Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / volser / volprocs.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 *
9 * Portions Copyright (c) 2007-2008 Sine Nomine Associates
10 */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15 #include <roken.h>
16
17 #include <afs/opr.h>
18 #ifdef AFS_PTHREAD_ENV
19 # include <opr/lock.h>
20 #endif
21
22 #include <rx/rx.h>
23 #include <rx/rxkad.h>
24 #include <rx/rx_queue.h>
25 #include <afs/afsint.h>
26 #include <afs/prs_fs.h>
27 #include <afs/nfs.h>
28 #include <lwp.h>
29 #include <lock.h>
30 #include <afs/cellconfig.h>
31 #include <afs/keys.h>
32 #include <ubik.h>
33 #include <afs/ihandle.h>
34 #ifdef AFS_NT40_ENV
35 #include <afs/ntops.h>
36 #endif
37 #include <afs/vnode.h>
38 #include <afs/volume.h>
39 #include <afs/volume_inline.h>
40 #include <afs/partition.h>
41 #include "vol.h"
42 #include <afs/daemon_com.h>
43 #include <afs/fssync.h>
44 #include <afs/acl.h>
45 #include "afs/audit.h"
46 #include <afs/dir.h>
47 #include <afs/afsutil.h>
48 #include <afs/com_err.h>
49 #include <afs/vol_prototypes.h>
50 #include <afs/errors.h>
51
52 #include "volser.h"
53 #include "voltrans_inline.h"
54 #include "volint.h"
55
56 #include "volser_internal.h"
57 #include "physio.h"
58 #include "dumpstuff.h"
59
60 extern int DoLogging;
61 extern struct afsconf_dir *tdir;
62 extern int DoPreserveVolumeStats;
63 extern int restrictedQueryLevel;
64 extern enum vol_s2s_crypt doCrypt;
65
66 extern void LogError(afs_int32 errcode);
67
68 /* Forward declarations */
69 static int GetPartName(afs_int32 partid, char *pname);
70
71 #define OneDay (24*60*60)
72
73 #ifdef AFS_NT40_ENV
74 #define ENOTCONN 134
75 #endif
76
77 afs_int32 localTid = 1;
78
79 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
80 struct diskPartition64 *);
81 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
82 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
83 afs_int32, afs_uint32, afs_uint32 *,
84 afs_int32 *);
85 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
86 static afs_int32 VolClone(struct rx_call *, afs_int32, VolumeId,
87 afs_int32, char *, VolumeId *);
88 static afs_int32 VolReClone(struct rx_call *, afs_int32, VolumeId);
89 static afs_int32 VolTransCreate(struct rx_call *, VolumeId, afs_int32,
90 afs_int32, afs_int32 *);
91 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
92 afs_int32 *);
93 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
94 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
95 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
96 struct destServer *destination, afs_int32,
97 struct restoreCookie *cookie);
98 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
99 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
100 struct restoreCookie *);
101 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
102 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
103 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
104 struct volser_status *);
105 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
106 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
107 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
108 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
109 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, VolumeId,
110 volEntries *);
111 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, VolumeId,
112 volXEntries *);
113 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
114 volEntries *);
115 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
116 volXEntries *);
117 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
118 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
119 afs_int32, VolumeId, VolumeId,
120 VolumeId);
121 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
122
123 /**
124 * Return the host address of the caller as a string.
125 *
126 * @param[in] acid incoming rx call
127 * @param[out] buffer buffer to be filled with the addess string
128 *
129 * @return address as formatted by inet_ntoa
130 */
131 static_inline char *
132 callerAddress(struct rx_call *acid, char *buffer)
133 {
134 afs_uint32 ip = rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid)));
135 return afs_inet_ntoa_r(ip, buffer);
136 }
137
138 /* this call unlocks all of the partition locks we've set */
139 int
140 VPFullUnlock_r(void)
141 {
142 struct DiskPartition64 *tp;
143 for (tp = DiskPartitionList; tp; tp = tp->next) {
144 if (tp->lock_fd != INVALID_FD) {
145 OS_CLOSE(tp->lock_fd);
146 tp->lock_fd = INVALID_FD;
147 }
148 }
149 return 0;
150 }
151
152 int
153 VPFullUnlock(void)
154 {
155 int code;
156 VOL_LOCK;
157 code = VPFullUnlock_r();
158 VOL_UNLOCK;
159 return code;
160 }
161
162 /* get partition id from a name */
163 afs_int32
164 PartitionID(char *aname)
165 {
166 char tc;
167 int code = 0;
168 char ascii[3];
169
170 tc = *aname;
171 if (tc == 0)
172 return -1; /* unknown */
173
174 /* otherwise check for vicepa or /vicepa, or just plain "a" */
175 ascii[2] = 0;
176 if (!strncmp(aname, "/vicep", 6)) {
177 strncpy(ascii, aname + 6, 2);
178 } else
179 return -1; /* bad partition name */
180 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
181 * from 0. Do the appropriate conversion */
182 if (ascii[1] == 0) {
183 /* one char name, 0..25 */
184 if (ascii[0] < 'a' || ascii[0] > 'z')
185 return -1; /* wrongo */
186 return ascii[0] - 'a';
187 } else {
188 /* two char name, 26 .. <whatever> */
189 if (ascii[0] < 'a' || ascii[0] > 'z')
190 return -1; /* wrongo */
191 if (ascii[1] < 'a' || ascii[1] > 'z')
192 return -1; /* just as bad */
193 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
194 if (code > VOLMAXPARTS)
195 return -1;
196 return code;
197 }
198 }
199
200 static int
201 ConvertVolume(VolumeId avol, char *aname, afs_int32 asize)
202 {
203 if (asize < 18)
204 return -1;
205 /* It's better using the Generic VFORMAT since otherwise we have to make changes to too many places... The 14 char limitation in names hits us again in AIX; print in field of 9 digits (still 10 for the rest), right justified with 0 padding */
206 snprintf(aname, asize, VFORMAT, afs_printable_VolumeId_lu(avol));
207 return 0;
208 }
209
210 static int
211 ConvertPartition(int apartno, char *aname, int asize)
212 {
213 if (asize < 10)
214 return E2BIG;
215 if (apartno < 0)
216 return EINVAL;
217 strcpy(aname, "/vicep");
218 if (apartno < 26) {
219 aname[6] = 'a' + apartno;
220 aname[7] = 0;
221 } else {
222 apartno -= 26;
223 aname[6] = 'a' + (apartno / 26);
224 aname[7] = 'a' + (apartno % 26);
225 aname[8] = 0;
226 }
227 return 0;
228 }
229
230 #ifdef AFS_DEMAND_ATTACH_FS
231 /* normally we should use the regular salvaging functions from the volume
232 * package, but this is a special case where we have a volume ID, but no
233 * volume structure to give the volume package */
234 static void
235 SalvageUnknownVolume(VolumeId volid, char *part)
236 {
237 afs_int32 code;
238
239 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
240 afs_printable_uint32_lu(volid), part);
241
242 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
243 FSYNC_SALVAGE, NULL);
244 if (code) {
245 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
246 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
247 part);
248 }
249 }
250 #endif /* AFS_DEMAND_ATTACH_FS */
251
252 static struct Volume *
253 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
254 {
255 struct Volume *vp;
256
257 *ec = 0;
258 vp = VAttachVolumeByName(ec, partition, name, mode);
259
260 #ifdef AFS_DEMAND_ATTACH_FS
261 {
262 int i;
263 /*
264 * The fileserver will take care of keeping track of how many
265 * demand-salvages have been performed, and will force the volume to
266 * ERROR if we've done too many. The limit on This loop is just a
267 * failsafe to prevent trying to salvage forever. We want to attempt
268 * attachment at least SALVAGE_COUNT_MAX times, since we want to
269 * avoid prematurely exiting this loop, if we can.
270 */
271 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
272 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
273 vp = VAttachVolumeByName(ec, partition, name, mode);
274 }
275
276 if (*ec == VSALVAGING) {
277 *ec = VSALVAGE;
278 }
279 }
280 #endif /* AFS_DEMAND_ATTACH_FS */
281
282 return vp;
283 }
284
285 static struct Volume *
286 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
287 {
288 struct Volume *vp;
289
290 *ec = 0;
291 vp = VAttachVolume(ec, avolid, amode);
292
293 #ifdef AFS_DEMAND_ATTACH_FS
294 {
295 int i;
296 /* see comment above in VAttachVolumeByName_retry */
297 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
298 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
299 vp = VAttachVolume(ec, avolid, amode);
300 }
301
302 if (*ec == VSALVAGING) {
303 *ec = VSALVAGE;
304 }
305 }
306 #endif /* AFS_DEMAND_ATTACH_FS */
307
308 return vp;
309 }
310
311 /* the only attach function that takes a partition is "...ByName", so we use it */
312 static struct Volume *
313 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
314 {
315 char pbuf[30], vbuf[20];
316
317 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
318 *error = EINVAL;
319 return NULL;
320 }
321 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
322 *error = EINVAL;
323 return NULL;
324 }
325
326 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
327 }
328
329 /* Adapted from the file server; create a root directory for this volume */
330 static Error
331 ViceCreateRoot(Volume *vp)
332 {
333 DirHandle dir;
334 struct acl_accessList *ACL;
335 AFSFid did;
336 Inode inodeNumber, AFS_UNUSED nearInode;
337 struct VnodeDiskObject *vnode;
338 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
339 IHandle_t *h;
340 FdHandle_t *fdP;
341 afs_fsize_t length;
342 ssize_t nBytes;
343
344 vnode = calloc(1, SIZEOF_LARGEDISKVNODE);
345 if (!vnode)
346 return ENOMEM;
347
348 V_pref(vp, nearInode);
349 inodeNumber =
350 IH_CREATE(V_linkHandle(vp), V_device(vp),
351 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
352 1, 1, 0);
353 if (!VALID_INO(inodeNumber)) {
354 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
355 free(vnode);
356 return EIO;
357 }
358
359 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
360 did.Volume = V_id(vp);
361 did.Vnode = (VnodeId) 1;
362 did.Unique = 1;
363
364 opr_Verify(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
365 DFlush(); /* flush all modified dir buffers out */
366 DZap(&dir); /* Remove all buffers for this dir */
367 length = afs_dir_Length(&dir); /* Remember size of this directory */
368
369 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
370
371 /* build a single entry ACL that gives all rights to system:administrators */
372 /* this section of code assumes that access list format is not going to
373 * change
374 */
375 ACL = VVnodeDiskACL(vnode);
376 ACL->size = sizeof(struct acl_accessList);
377 ACL->version = ACL_ACLVERSION;
378 ACL->total = 1;
379 ACL->positive = 1;
380 ACL->negative = 0;
381 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
382 ACL->entries[0].rights =
383 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
384 | PRSFS_LOCK | PRSFS_ADMINISTER;
385
386 vnode->type = vDirectory;
387 vnode->cloned = 0;
388 vnode->modeBits = 0777;
389 vnode->linkCount = 2;
390 VNDISK_SET_LEN(vnode, length);
391 vnode->uniquifier = 1;
392 V_uniquifier(vp) = vnode->uniquifier + 1;
393 vnode->dataVersion = 1;
394 VNDISK_SET_INO(vnode, inodeNumber);
395 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
396 vnode->author = 0;
397 vnode->owner = 0;
398 vnode->parent = 0;
399 vnode->vnodeMagic = vcp->magic;
400
401 IH_INIT(h, vp->device, V_parentId(vp),
402 vp->vnodeIndex[vLarge].handle->ih_ino);
403 fdP = IH_OPEN(h);
404 opr_Assert(fdP != NULL);
405 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
406 opr_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
407 FDH_REALLYCLOSE(fdP);
408 IH_RELEASE(h);
409 VNDISK_GET_LEN(length, vnode);
410 V_diskused(vp) = nBlocks(length);
411
412 free(vnode);
413 return 0;
414 }
415
416 afs_int32
417 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
418 *partition)
419 {
420 afs_int32 code;
421 struct diskPartition64 *dp = malloc(sizeof(struct diskPartition64));
422
423 memset(partition, 0, sizeof(*partition));
424 code = VolPartitionInfo(acid, pname, dp);
425 if (!code) {
426 strncpy(partition->name, dp->name, 32);
427 strncpy(partition->devName, dp->devName, 32);
428 partition->lock_fd = dp->lock_fd;
429 partition->free=RoundInt64ToInt32(dp->free);
430 partition->minFree=RoundInt64ToInt32(dp->minFree);
431 }
432 free(dp);
433 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
434 return code;
435 }
436
437 afs_int32
438 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
439 *partition)
440 {
441 afs_int32 code;
442
443 memset(partition, 0, sizeof(*partition));
444 code = VolPartitionInfo(acid, pname, partition);
445 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
446 return code;
447 }
448
449 afs_int32
450 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
451 *partition)
452 {
453 struct DiskPartition64 *dp;
454
455 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
456 return VOLSERBAD_ACCESS;
457
458 VResetDiskUsage();
459 dp = VGetPartition(pname, 0);
460 if (dp) {
461 strncpy(partition->name, dp->name, 32);
462 strncpy(partition->devName, dp->devName, 32);
463 partition->lock_fd = (int)dp->lock_fd;
464 partition->free = dp->free;
465 partition->minFree = dp->totalUsable;
466 return 0;
467 } else
468 return VOLSERILLEGAL_PARTITION;
469 }
470
471 /* obliterate a volume completely, and slowly. */
472 afs_int32
473 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, VolumeId avolID)
474 {
475 afs_int32 code;
476
477 code = VolNukeVolume(acid, apartID, avolID);
478 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
479 return code;
480 }
481
482 static afs_int32
483 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
484 {
485 char partName[50];
486 afs_int32 error;
487 Error verror;
488 afs_int32 code;
489 struct Volume *tvp;
490 char caller[MAXKTCNAMELEN];
491
492 /* check for access */
493 if (!afsconf_SuperUser(tdir, acid, caller))
494 return VOLSERBAD_ACCESS;
495 if (DoLogging) {
496 char buffer[16];
497 Log("%s on %s is executing VolNukeVolume %u\n", caller,
498 callerAddress(acid, buffer), avolID);
499 }
500
501 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
502 return VOLSERNOVOL;
503 /* we first try to attach the volume in update mode, so that the file
504 * server doesn't try to use it (and abort) while (or after) we delete it.
505 * If we don't get the volume, that's fine, too. We just won't put it back.
506 */
507 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
508 code = nuke(partName, avolID);
509 if (tvp)
510 VDetachVolume(&verror, tvp);
511 return code;
512 }
513
514 /* create a new volume, with name aname, on the specified partition (1..n)
515 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
516 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
517 * for the volume id (useful for things like volume restore).
518 * Return the new volume id in *avolid.
519 */
520 afs_int32
521 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
522 afs_int32 atype, VolumeId aparent, VolumeId *avolid,
523 afs_int32 *atrans)
524 {
525 afs_int32 code;
526
527 code =
528 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
529 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
530 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
531 AUD_END);
532 return code;
533 }
534
535 static afs_int32
536 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
537 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
538 afs_int32 *atrans)
539 {
540 Error error;
541 Volume *vp;
542 Error junk; /* discardable error code */
543 afs_uint32 volumeID;
544 afs_int32 doCreateRoot = 1;
545 struct volser_trans *tt;
546 char ppath[30];
547 char caller[MAXKTCNAMELEN];
548
549 if (strlen(aname) > 31)
550 return VOLSERBADNAME;
551 if (!afsconf_SuperUser(tdir, acid, caller))
552 return VOLSERBAD_ACCESS;
553 if (DoLogging) {
554 char buffer[16];
555 Log("%s on %s is executing CreateVolume '%s'\n", caller,
556 callerAddress(acid, buffer), aname);
557 }
558 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
559 return error; /*a standard unix error */
560 if (atype != readwriteVolume && atype != readonlyVolume
561 && atype != backupVolume)
562 return EINVAL;
563 if ((volumeID = *avolid) == 0) {
564
565 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
566 return E2BIG;
567
568 }
569 if ((aparent == volumeID) && (atype == readwriteVolume)) {
570 doCreateRoot = 0;
571 }
572 if (aparent == 0)
573 aparent = volumeID;
574 tt = NewTrans(volumeID, apart);
575 if (!tt) {
576 Log("1 createvolume: failed to create trans\n");
577 return VOLSERVOLBUSY; /* volume already busy! */
578 }
579 vp = VCreateVolume(&error, ppath, volumeID, aparent);
580 if (error) {
581 #ifdef AFS_DEMAND_ATTACH_FS
582 if (error != VVOLEXISTS && error != EXDEV) {
583 SalvageUnknownVolume(volumeID, ppath);
584 }
585 #endif
586 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
587 LogError(error);
588 DeleteTrans(tt, 1);
589 return EIO;
590 }
591 V_uniquifier(vp) = 1;
592 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
593 V_inService(vp) = V_blessed(vp) = 1;
594 V_type(vp) = atype;
595 AssignVolumeName(&V_disk(vp), aname, 0);
596 if (doCreateRoot) {
597 error = ViceCreateRoot(vp);
598 if (error) {
599 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
600 "error code %u\n", (unsigned)error);
601 DeleteTrans(tt, 1);
602 V_needsSalvaged(vp) = 1;
603 VDetachVolume(&junk, vp);
604 return EIO;
605 }
606 }
607 V_destroyMe(vp) = DESTROY_ME;
608 V_inService(vp) = 0;
609 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
610 VUpdateVolume(&error, vp);
611 if (error) {
612 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
613 LogError(error);
614 DeleteTrans(tt, 1);
615 VDetachVolume(&junk, vp); /* rather return the real error code */
616 return error;
617 }
618 VTRANS_OBJ_LOCK(tt);
619 tt->volume = vp;
620 *atrans = tt->tid;
621 TSetRxCall_r(tt, acid, "CreateVolume");
622 VTRANS_OBJ_UNLOCK(tt);
623 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
624 TClearRxCall(tt);
625 if (TRELE(tt))
626 return VOLSERTRELE_ERROR;
627 return 0;
628 }
629
630 /* delete the volume associated with this transaction */
631 afs_int32
632 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
633 {
634 afs_int32 code;
635
636 code = VolDeleteVolume(acid, atrans);
637 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
638 return code;
639 }
640
641 static afs_int32
642 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
643 {
644 struct volser_trans *tt;
645 Error error;
646 char caller[MAXKTCNAMELEN];
647
648 if (!afsconf_SuperUser(tdir, acid, caller))
649 return VOLSERBAD_ACCESS;
650 tt = FindTrans(atrans);
651 if (!tt)
652 return ENOENT;
653 if (tt->vflags & VTDeleted) {
654 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " already deleted \n",
655 afs_printable_VolumeId_lu(tt->volid));
656 TRELE(tt);
657 return ENOENT;
658 }
659 if (DoLogging) {
660 char buffer[16];
661 Log("%s on %s is executing Delete Volume %" AFS_VOLID_FMT "\n", caller,
662 callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
663 }
664 TSetRxCall(tt, acid, "DeleteVolume");
665 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
666 V_destroyMe(tt->volume) = DESTROY_ME;
667 if (tt->volume->needsPutBack) {
668 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
669 }
670 VTRANS_OBJ_LOCK(tt);
671 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
672 TClearRxCall_r(tt);
673 VTRANS_OBJ_UNLOCK(tt);
674 if (TRELE(tt))
675 return VOLSERTRELE_ERROR;
676
677 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " deleted \n",
678 afs_printable_VolumeId_lu(tt->volid));
679 return 0; /* vpurgevolume doesn't set an error code */
680 }
681
682 /* make a clone of the volume associated with atrans, possibly giving it a new
683 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
684 * for the clone's id). The new clone is given the name newName. Finally,
685 * due to efficiency considerations, if purgeId is non-zero, we purge that
686 * volume when doing the clone operation. This may be useful when making
687 * new backup volumes, for instance since the net result of a clone and a
688 * purge generally leaves many inode ref counts the same, while doing them
689 * separately would result in far more iincs and idecs being peformed
690 * (and they are slow operations).
691 */
692 /* for efficiency reasons, sometimes faster to piggyback a purge here */
693 afs_int32
694 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
695 afs_int32 newType, char *newName, VolumeId *newNumber)
696 {
697 afs_int32 code;
698 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
699 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
700 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
701 AUD_END);
702 return code;
703 }
704
705 static afs_int32
706 VolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
707 afs_int32 newType, char *newName, VolumeId *newNumber)
708 {
709 VolumeId newId;
710 struct Volume *originalvp, *purgevp, *newvp;
711 Error error, code;
712 struct volser_trans *tt, *ttc;
713 char caller[MAXKTCNAMELEN];
714 #ifdef AFS_DEMAND_ATTACH_FS
715 struct Volume *salv_vp = NULL;
716 #endif
717
718 if (strlen(newName) > 31)
719 return VOLSERBADNAME;
720 if (!afsconf_SuperUser(tdir, acid, caller))
721 return VOLSERBAD_ACCESS; /*not a super user */
722 if (DoLogging) {
723 char buffer[16];
724 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
725 callerAddress(acid, buffer), newName);
726 }
727 error = 0;
728 purgevp = (Volume *) 0;
729 newvp = (Volume *) 0;
730 tt = ttc = (struct volser_trans *)0;
731
732 if (!newNumber || !*newNumber) {
733 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
734 goto fail;
735 }
736 newId = *newNumber;
737
738 tt = FindTrans(atrans);
739 if (!tt)
740 return ENOENT;
741 if (tt->vflags & VTDeleted) {
742 Log("1 Volser: Clone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
743 TRELE(tt);
744 return ENOENT;
745 }
746 ttc = NewTrans(newId, tt->partition);
747 if (!ttc) { /* someone is messing with the clone already */
748 TRELE(tt);
749 return VOLSERVOLBUSY;
750 }
751 TSetRxCall(tt, acid, "Clone");
752
753
754 if (purgeId) {
755 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
756 if (error) {
757 Log("1 Volser: Clone: Could not attach 'purge' volume %" AFS_VOLID_FMT "; clone aborted\n", afs_printable_VolumeId_lu(purgeId));
758 goto fail;
759 }
760 } else {
761 purgevp = NULL;
762 }
763 originalvp = tt->volume;
764 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
765 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
766 afs_printable_VolumeId_lu(V_id(originalvp)));
767 error = VOFFLINE;
768 goto fail;
769 }
770 if (purgevp) {
771 if (originalvp->device != purgevp->device) {
772 Log("1 Volser: Clone: Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are on different devices\n", afs_printable_VolumeId_lu(tt->volid), afs_printable_VolumeId_lu(purgeId));
773 error = EXDEV;
774 goto fail;
775 }
776 if (V_type(purgevp) != readonlyVolume) {
777 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
778 error = EINVAL;
779 goto fail;
780 }
781 if (V_parentId(originalvp) != V_parentId(purgevp)) {
782 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " and volume %" AFS_VOLID_FMT " were not originally cloned from the same parent; aborted\n", afs_printable_VolumeId_lu(purgeId), afs_printable_VolumeId_lu(tt->volid));
783 error = EXDEV;
784 goto fail;
785 }
786 }
787
788 error = 0;
789 #ifdef AFS_DEMAND_ATTACH_FS
790 salv_vp = originalvp;
791 #endif
792
793 if (purgeId == newId) {
794 newvp = purgevp;
795 } else {
796 newvp =
797 VCreateVolume(&error, originalvp->partition->name, newId,
798 V_parentId(originalvp));
799 if (error) {
800 Log("1 Volser: Clone: Couldn't create new volume %" AFS_VOLID_FMT " for parent %" AFS_VOLID_FMT "; clone aborted\n",
801 afs_printable_VolumeId_lu(newId), afs_printable_VolumeId_lu(V_parentId(originalvp)));
802 newvp = (Volume *) 0;
803 goto fail;
804 }
805 }
806 if (newType == readonlyVolume)
807 V_cloneId(originalvp) = newId;
808 Log("1 Volser: Clone: Cloning volume %" AFS_VOLID_FMT " to new volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
809 afs_printable_VolumeId_lu(newId));
810 if (purgevp)
811 Log("1 Volser: Clone: Purging old read only volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(purgeId));
812 CloneVolume(&error, originalvp, newvp, purgevp);
813 purgevp = NULL; /* clone releases it, maybe even if error */
814 if (error) {
815 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
816 LogError(error);
817 goto fail;
818 }
819 if (newType == readonlyVolume) {
820 V_type(newvp) = readonlyVolume;
821 } else if (newType == backupVolume) {
822 V_type(newvp) = backupVolume;
823 V_backupId(originalvp) = newId;
824 }
825 strcpy(V_name(newvp), newName);
826 V_creationDate(newvp) = V_copyDate(newvp);
827 ClearVolumeStats(&V_disk(newvp));
828 V_destroyMe(newvp) = DESTROY_ME;
829 V_inService(newvp) = 0;
830 if (newType == backupVolume) {
831 V_backupDate(originalvp) = V_copyDate(newvp);
832 V_backupDate(newvp) = V_copyDate(newvp);
833 }
834 V_inUse(newvp) = 0;
835 VUpdateVolume(&error, newvp);
836 if (error) {
837 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
838 LogError(error);
839 goto fail;
840 }
841 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
842 newvp = NULL;
843 VUpdateVolume(&error, originalvp);
844 if (error) {
845 Log("1 Volser: Clone: original update %u\n", error);
846 LogError(error);
847 goto fail;
848 }
849 TClearRxCall(tt);
850 #ifdef AFS_DEMAND_ATTACH_FS
851 salv_vp = NULL;
852 #endif
853
854 /* Clients could have callbacks to the clone ID */
855 FSYNC_VolOp(newId, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
856
857 if (TRELE(tt)) {
858 tt = (struct volser_trans *)0;
859 error = VOLSERTRELE_ERROR;
860 goto fail;
861 }
862 DeleteTrans(ttc, 1);
863 return 0;
864
865 fail:
866 if (purgevp)
867 VDetachVolume(&code, purgevp);
868 if (newvp)
869 VDetachVolume(&code, newvp);
870 if (tt) {
871 TClearRxCall(tt);
872 TRELE(tt);
873 }
874 if (ttc)
875 DeleteTrans(ttc, 1);
876 #ifdef AFS_DEMAND_ATTACH_FS
877 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
878 V_needsSalvaged(salv_vp) = 1;
879 }
880 #endif /* AFS_DEMAND_ATTACH_FS */
881 return error;
882 }
883
884 /* reclone this volume into the specified id */
885 afs_int32
886 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
887 {
888 afs_int32 code;
889
890 code = VolReClone(acid, atrans, cloneId);
891 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
892 cloneId, AUD_END);
893 return code;
894 }
895
896 static afs_int32
897 VolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
898 {
899 struct Volume *originalvp, *clonevp;
900 Error error, code;
901 afs_int32 newType;
902 struct volser_trans *tt, *ttc;
903 char caller[MAXKTCNAMELEN];
904 VolumeDiskData saved_header;
905
906 /*not a super user */
907 if (!afsconf_SuperUser(tdir, acid, caller))
908 return VOLSERBAD_ACCESS;
909 if (DoLogging) {
910 char buffer[16];
911 Log("%s on %s is executing Reclone Volume %" AFS_VOLID_FMT "\n", caller,
912 callerAddress(acid, buffer), afs_printable_VolumeId_lu(cloneId));
913 }
914 error = 0;
915 clonevp = originalvp = (Volume *) 0;
916
917 tt = FindTrans(atrans);
918 if (!tt)
919 return ENOENT;
920 if (tt->vflags & VTDeleted) {
921 Log("1 Volser: VolReClone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
922 TRELE(tt);
923 return ENOENT;
924 }
925 ttc = NewTrans(cloneId, tt->partition);
926 if (!ttc) { /* someone is messing with the clone already */
927 TRELE(tt);
928 return VOLSERVOLBUSY;
929 }
930 TSetRxCall(tt, acid, "ReClone");
931
932 originalvp = tt->volume;
933 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
934 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
935 afs_printable_VolumeId_lu(V_id(originalvp)));
936 error = VOFFLINE;
937 goto fail;
938 }
939
940 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
941 if (error) {
942 Log("1 Volser: can't attach clone %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(cloneId));
943 goto fail;
944 }
945
946 newType = V_type(clonevp); /* type of the new volume */
947
948 if (originalvp->device != clonevp->device) {
949 Log("1 Volser: Clone: Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are on different devices\n",
950 afs_printable_VolumeId_lu(tt->volid), afs_printable_VolumeId_lu(cloneId));
951 error = EXDEV;
952 goto fail;
953 }
954 if (V_parentId(originalvp) != V_parentId(clonevp)) {
955 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " was not originally cloned from volume %" AFS_VOLID_FMT "; aborted\n", afs_printable_VolumeId_lu(cloneId), afs_printable_VolumeId_lu(tt->volid));
956 error = EXDEV;
957 goto fail;
958 }
959
960 if (DoPreserveVolumeStats) {
961 CopyVolumeStats(&V_disk(clonevp), &saved_header);
962 }
963
964 error = 0;
965 Log("1 Volser: Clone: Recloning volume %" AFS_VOLID_FMT " to volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
966 afs_printable_VolumeId_lu(cloneId));
967 CloneVolume(&error, originalvp, clonevp, clonevp);
968 if (error) {
969 Log("1 Volser: Clone: reclone operation failed with code %d\n",
970 error);
971 LogError(error);
972 goto fail;
973 }
974
975 /* fix up volume name and type, CloneVolume just propagated RW's */
976 if (newType == readonlyVolume) {
977 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
978 V_type(clonevp) = readonlyVolume;
979 } else if (newType == backupVolume) {
980 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
981 V_type(clonevp) = backupVolume;
982 V_backupId(originalvp) = cloneId;
983 }
984 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
985
986 /* update the creationDate, since this represents the last cloning date
987 * for ROs. But do not update copyDate; let it stay so we can identify
988 * when the clone was first created. */
989 V_creationDate(clonevp) = time(0);
990 if (DoPreserveVolumeStats) {
991 CopyVolumeStats(&saved_header, &V_disk(clonevp));
992 } else {
993 ClearVolumeStats(&V_disk(clonevp));
994 }
995 V_destroyMe(clonevp) = 0;
996 V_inService(clonevp) = 0;
997 if (newType == backupVolume) {
998 V_backupDate(originalvp) = V_creationDate(clonevp);
999 V_backupDate(clonevp) = V_creationDate(clonevp);
1000 }
1001 V_inUse(clonevp) = 0;
1002 VUpdateVolume(&error, clonevp);
1003 if (error) {
1004 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
1005 LogError(error);
1006 goto fail;
1007 }
1008 /* VUpdateVolume succeeded. Mark it in service so there's no window
1009 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
1010 * specialStatus; this is a reclone and this volume started online
1011 */
1012 V_inService(clonevp) = 1;
1013 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
1014 clonevp = NULL;
1015 VUpdateVolume(&error, originalvp);
1016 if (error) {
1017 Log("1 Volser: Clone: original update %u\n", error);
1018 LogError(error);
1019 goto fail;
1020 }
1021 TClearRxCall(tt);
1022 if (TRELE(tt)) {
1023 tt = (struct volser_trans *)0;
1024 error = VOLSERTRELE_ERROR;
1025 goto fail;
1026 }
1027
1028 DeleteTrans(ttc, 1);
1029
1030 {
1031 struct DiskPartition64 *tpartp = originalvp->partition;
1032 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1033 }
1034 return 0;
1035
1036 fail:
1037 if (clonevp)
1038 VDetachVolume(&code, clonevp);
1039 if (tt) {
1040 TClearRxCall(tt);
1041 TRELE(tt);
1042 }
1043 if (ttc)
1044 DeleteTrans(ttc, 1);
1045 return error;
1046 }
1047
1048 /* create a new transaction, associated with volume and partition. Type of
1049 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1050 * See volser.h for definition of iflags (the constants are named IT*).
1051 */
1052 afs_int32
1053 SAFSVolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1054 afs_int32 iflags, afs_int32 *ttid)
1055 {
1056 afs_int32 code;
1057
1058 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1059 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1060 AUD_END);
1061 return code;
1062 }
1063
1064 static afs_int32
1065 VolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1066 afs_int32 iflags, afs_int32 *ttid)
1067 {
1068 struct volser_trans *tt;
1069 Volume *tv;
1070 afs_int32 error;
1071 Error code;
1072 afs_int32 mode;
1073 char caller[MAXKTCNAMELEN];
1074
1075 if (!afsconf_SuperUser(tdir, acid, caller))
1076 return VOLSERBAD_ACCESS; /*not a super user */
1077 if (iflags & ITCreate)
1078 mode = V_SECRETLY;
1079 else if (iflags & ITBusy)
1080 mode = V_CLONE;
1081 else if (iflags & ITReadOnly)
1082 mode = V_READONLY;
1083 else if (iflags & ITOffline)
1084 mode = V_VOLUPD;
1085 else {
1086 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1087 EINVAL);
1088 LogError(EINVAL);
1089 return EINVAL;
1090 }
1091 tt = NewTrans(volume, partition);
1092 if (!tt) {
1093 /* can't create a transaction? put the volume back */
1094 Log("1 transcreate: can't create transaction\n");
1095 return VOLSERVOLBUSY;
1096 }
1097 tv = XAttachVolume(&error, volume, partition, mode);
1098 if (error) {
1099 /* give up */
1100 if (tv)
1101 VDetachVolume(&code, tv);
1102 DeleteTrans(tt, 1);
1103 return error;
1104 }
1105 VTRANS_OBJ_LOCK(tt);
1106 tt->volume = tv;
1107 *ttid = tt->tid;
1108 tt->iflags = iflags;
1109 tt->vflags = 0;
1110 TSetRxCall_r(tt, NULL, "TransCreate");
1111 VTRANS_OBJ_UNLOCK(tt);
1112 if (TRELE(tt))
1113 return VOLSERTRELE_ERROR;
1114
1115 return 0;
1116 }
1117
1118 /* using aindex as a 0-based index, return the aindex'th volume on this server
1119 * Both the volume number and partition number (one-based) are returned.
1120 */
1121 afs_int32
1122 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, VolumeId *avolume,
1123 afs_int32 *apart)
1124 {
1125 afs_int32 code;
1126
1127 code = VolGetNthVolume(acid, aindex, avolume, apart);
1128 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1129 return code;
1130 }
1131
1132 static afs_int32
1133 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1134 afs_int32 *apart)
1135 {
1136 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1137 return VOLSERBAD_ACCESS;
1138
1139 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1140 return VOLSERNO_OP;
1141 }
1142
1143 /* return the volume flags (VT* constants in volser.h) associated with this
1144 * transaction.
1145 */
1146 afs_int32
1147 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1148 {
1149 afs_int32 code;
1150
1151 code = VolGetFlags(acid, atid, aflags);
1152 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1153 return code;
1154 }
1155
1156 static afs_int32
1157 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1158 {
1159 struct volser_trans *tt;
1160
1161 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1162 return VOLSERBAD_ACCESS;
1163
1164 tt = FindTrans(atid);
1165 if (!tt)
1166 return ENOENT;
1167 if (tt->vflags & VTDeleted) {
1168 Log("1 Volser: VolGetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1169 afs_printable_VolumeId_lu(tt->volid));
1170 TRELE(tt);
1171 return ENOENT;
1172 }
1173 TSetRxCall(tt, acid, "GetFlags");
1174 *aflags = tt->vflags;
1175 TClearRxCall(tt);
1176 if (TRELE(tt))
1177 return VOLSERTRELE_ERROR;
1178
1179 return 0;
1180 }
1181
1182 /* Change the volume flags (VT* constants in volser.h) associated with this
1183 * transaction. Effects take place immediately on volume, although volume
1184 * remains attached as usual by the transaction.
1185 */
1186 afs_int32
1187 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1188 {
1189 afs_int32 code;
1190
1191 code = VolSetFlags(acid, atid, aflags);
1192 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1193 AUD_END);
1194 return code;
1195 }
1196
1197 static afs_int32
1198 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1199 {
1200 struct volser_trans *tt;
1201 struct Volume *vp;
1202 Error error;
1203 char caller[MAXKTCNAMELEN];
1204
1205 if (!afsconf_SuperUser(tdir, acid, caller))
1206 return VOLSERBAD_ACCESS; /*not a super user */
1207 /* find the trans */
1208 tt = FindTrans(atid);
1209 if (!tt)
1210 return ENOENT;
1211 if (tt->vflags & VTDeleted) {
1212 Log("1 Volser: VolSetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1213 afs_printable_VolumeId_lu(tt->volid));
1214 TRELE(tt);
1215 return ENOENT;
1216 }
1217 TSetRxCall(tt, acid, "SetFlags");
1218 vp = tt->volume; /* pull volume out of transaction */
1219
1220 /* check if we're allowed to make any updates */
1221 if (tt->iflags & ITReadOnly) {
1222 TRELE(tt);
1223 return EROFS;
1224 }
1225
1226 /* handle delete-on-salvage flag */
1227 if (aflags & VTDeleteOnSalvage) {
1228 V_destroyMe(tt->volume) = DESTROY_ME;
1229 } else {
1230 V_destroyMe(tt->volume) = 0;
1231 }
1232
1233 if (aflags & VTOutOfService) {
1234 V_inService(vp) = 0;
1235 } else {
1236 V_inService(vp) = 1;
1237 }
1238 VUpdateVolume(&error, vp);
1239 VTRANS_OBJ_LOCK(tt);
1240 tt->vflags = aflags;
1241 TClearRxCall_r(tt);
1242 VTRANS_OBJ_UNLOCK(tt);
1243 if (TRELE(tt) && !error)
1244 return VOLSERTRELE_ERROR;
1245
1246 return error;
1247 }
1248
1249 /* dumpS the volume associated with a particular transaction from a particular
1250 * date. Send the dump to a different transaction (destTrans) on the server
1251 * specified by the destServer structure.
1252 */
1253 afs_int32
1254 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1255 struct destServer *destination, afs_int32 destTrans,
1256 struct restoreCookie *cookie)
1257 {
1258 afs_int32 code;
1259
1260 code =
1261 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1262 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1263 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1264 return code;
1265 }
1266
1267 static_inline afs_int32
1268 MakeClient(struct rx_call *acid, struct rx_securityClass **securityObject,
1269 afs_int32 *securityIndex)
1270 {
1271 rxkad_level enc_level = rxkad_clear;
1272 int docrypt;
1273 int code;
1274
1275 switch (doCrypt) {
1276 case VS2SC_ALWAYS:
1277 docrypt = 1;
1278 break;
1279 case VS2SC_INHERIT:
1280 rxkad_GetServerInfo(rx_ConnectionOf(acid), &enc_level, 0, 0, 0, 0, 0);
1281 docrypt = (enc_level == rxkad_crypt ? 1 : 0);
1282 break;
1283 case VS2SC_NEVER:
1284 docrypt = 0;
1285 break;
1286 default:
1287 opr_Assert(0 && "doCrypt corrupt?");
1288 }
1289 if (docrypt)
1290 code = afsconf_ClientAuthSecure(tdir, securityObject, securityIndex);
1291 else
1292 code = afsconf_ClientAuth(tdir, securityObject, securityIndex);
1293 return code;
1294 }
1295
1296 static afs_int32
1297 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1298 struct destServer *destination, afs_int32 destTrans,
1299 struct restoreCookie *cookie)
1300 {
1301 struct volser_trans *tt;
1302 afs_int32 code;
1303 struct rx_connection *tcon;
1304 struct rx_call *tcall;
1305 struct Volume *vp;
1306 struct rx_securityClass *securityObject;
1307 afs_int32 securityIndex;
1308 char caller[MAXKTCNAMELEN];
1309
1310 if (!afsconf_SuperUser(tdir, acid, caller))
1311 return VOLSERBAD_ACCESS; /*not a super user */
1312
1313 /* find the local transaction */
1314 tt = FindTrans(fromTrans);
1315 if (!tt)
1316 return ENOENT;
1317 if (tt->vflags & VTDeleted) {
1318 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1319 TRELE(tt);
1320 return ENOENT;
1321 }
1322 vp = tt->volume;
1323 TSetRxCall(tt, NULL, "Forward");
1324
1325 /* get auth info for the this connection (uses afs from ticket file) */
1326 code = MakeClient(acid, &securityObject, &securityIndex);
1327 if (code) {
1328 TRELE(tt);
1329 return code;
1330 }
1331
1332 /* make an rpc connection to the other server */
1333 tcon =
1334 rx_NewConnection(htonl(destination->destHost),
1335 htons(destination->destPort), VOLSERVICE_ID,
1336 securityObject, securityIndex);
1337
1338 RXS_Close(securityObject); /* will be freed after connection destroyed */
1339
1340 if (!tcon) {
1341 TClearRxCall(tt);
1342 TRELE(tt);
1343 return ENOTCONN;
1344 }
1345 tcall = rx_NewCall(tcon);
1346 TSetRxCall(tt, tcall, "Forward");
1347 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1348 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1349 if (code) {
1350 goto fail;
1351 }
1352
1353 /* these next calls implictly call rx_Write when writing out data */
1354 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1355 if (code)
1356 goto fail;
1357 EndAFSVolRestore(tcall); /* probably doesn't do much */
1358 TClearRxCall(tt);
1359 code = rx_EndCall(tcall, 0);
1360 rx_DestroyConnection(tcon); /* done with the connection */
1361 tcon = NULL;
1362 if (code)
1363 goto fail;
1364 if (TRELE(tt))
1365 return VOLSERTRELE_ERROR;
1366
1367 return 0;
1368
1369 fail:
1370 if (tcon) {
1371 (void)rx_EndCall(tcall, 0);
1372 rx_DestroyConnection(tcon);
1373 }
1374 if (tt) {
1375 TClearRxCall(tt);
1376 TRELE(tt);
1377 }
1378 return code;
1379 }
1380
1381 /* Start a dump and send it to multiple places simultaneously.
1382 * If this returns an error (eg, return ENOENT), it means that
1383 * none of the releases worked. If this returns 0, that means
1384 * that one or more of the releases worked, and the caller has
1385 * to examine the results array to see which one(s).
1386 * This will only do EITHER incremental or full, not both, so it's
1387 * the caller's responsibility to be sure that all the destinations
1388 * need just an incremental (and from the same time), if that's
1389 * what we're doing.
1390 */
1391 afs_int32
1392 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1393 fromDate, manyDests *destinations, afs_int32 spare,
1394 struct restoreCookie *cookie, manyResults *results)
1395 {
1396 afs_int32 securityIndex;
1397 struct rx_securityClass *securityObject;
1398 char caller[MAXKTCNAMELEN];
1399 struct volser_trans *tt;
1400 afs_int32 ec, code, *codes;
1401 struct rx_connection **tcons;
1402 struct rx_call **tcalls;
1403 struct Volume *vp;
1404 int i, is_incremental;
1405
1406 if (results) {
1407 memset(results, 0, sizeof(manyResults));
1408 i = results->manyResults_len = destinations->manyDests_len;
1409 results->manyResults_val = codes = malloc(i * sizeof(afs_int32));
1410 }
1411 if (!results || !results->manyResults_val)
1412 return ENOMEM;
1413
1414 if (!afsconf_SuperUser(tdir, acid, caller))
1415 return VOLSERBAD_ACCESS; /*not a super user */
1416 tt = FindTrans(fromTrans);
1417 if (!tt)
1418 return ENOENT;
1419 if (tt->vflags & VTDeleted) {
1420 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1421 TRELE(tt);
1422 return ENOENT;
1423 }
1424 vp = tt->volume;
1425 TSetRxCall(tt, NULL, "ForwardMulti");
1426
1427 /* (fromDate == 0) ==> full dump */
1428 is_incremental = (fromDate ? 1 : 0);
1429
1430 tcons = malloc(i * sizeof(struct rx_connection *));
1431 if (!tcons) {
1432 return ENOMEM;
1433 }
1434 tcalls = malloc(i * sizeof(struct rx_call *));
1435 if (!tcalls) {
1436 free(tcons);
1437 return ENOMEM;
1438 }
1439
1440 /* get auth info for this connection (uses afs from ticket file) */
1441 code = MakeClient(acid, &securityObject, &securityIndex);
1442 if (code) {
1443 goto fail; /* in order to audit each failure */
1444 }
1445
1446 /* make connections to all the other servers */
1447 for (i = 0; i < destinations->manyDests_len; i++) {
1448 struct replica *dest = &(destinations->manyDests_val[i]);
1449 tcons[i] =
1450 rx_NewConnection(htonl(dest->server.destHost),
1451 htons(dest->server.destPort), VOLSERVICE_ID,
1452 securityObject, securityIndex);
1453 if (!tcons[i]) {
1454 codes[i] = ENOTCONN;
1455 } else {
1456 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1457 codes[i] = ENOTCONN;
1458 else {
1459 codes[i] =
1460 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1461 cookie);
1462 if (codes[i]) {
1463 (void)rx_EndCall(tcalls[i], 0);
1464 tcalls[i] = 0;
1465 rx_DestroyConnection(tcons[i]);
1466 tcons[i] = 0;
1467 }
1468 }
1469 }
1470 }
1471
1472 /* Security object will be freed when all connections destroyed */
1473 RXS_Close(securityObject);
1474
1475 /* these next calls implictly call rx_Write when writing out data */
1476 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1477
1478
1479 fail:
1480 for (i--; i >= 0; i--) {
1481 struct replica *dest = &(destinations->manyDests_val[i]);
1482
1483 if (!code && tcalls[i] && !codes[i]) {
1484 EndAFSVolRestore(tcalls[i]);
1485 }
1486 if (tcalls[i]) {
1487 ec = rx_EndCall(tcalls[i], 0);
1488 if (!codes[i])
1489 codes[i] = ec;
1490 }
1491 if (tcons[i]) {
1492 rx_DestroyConnection(tcons[i]); /* done with the connection */
1493 }
1494
1495 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1496 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1497 dest->trans, AUD_END);
1498 }
1499 free(tcons);
1500 free(tcalls);
1501
1502 if (tt) {
1503 TClearRxCall(tt);
1504 if (TRELE(tt) && !code) /* return the first code if it's set */
1505 return VOLSERTRELE_ERROR;
1506 }
1507
1508 return code;
1509 }
1510
1511 afs_int32
1512 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1513 {
1514 afs_int32 code;
1515
1516 code = VolDump(acid, fromTrans, fromDate, 0);
1517 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1518 return code;
1519 }
1520
1521 afs_int32
1522 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1523 afs_int32 flags)
1524 {
1525 afs_int32 code;
1526
1527 code = VolDump(acid, fromTrans, fromDate, flags);
1528 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1529 return code;
1530 }
1531
1532 static afs_int32
1533 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1534 afs_int32 flags)
1535 {
1536 int code = 0;
1537 struct volser_trans *tt;
1538 char caller[MAXKTCNAMELEN];
1539
1540 if (!afsconf_SuperUser(tdir, acid, caller))
1541 return VOLSERBAD_ACCESS; /*not a super user */
1542 tt = FindTrans(fromTrans);
1543 if (!tt)
1544 return ENOENT;
1545 if (tt->vflags & VTDeleted) {
1546 Log("1 Volser: VolDump: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1547 TRELE(tt);
1548 return ENOENT;
1549 }
1550 TSetRxCall(tt, acid, "Dump");
1551 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1552 ? 0 : 1); /* squirt out the volume's data, too */
1553 if (code) {
1554 TClearRxCall(tt);
1555 TRELE(tt);
1556 return code;
1557 }
1558 TClearRxCall(tt);
1559
1560 if (TRELE(tt))
1561 return VOLSERTRELE_ERROR;
1562
1563 return 0;
1564 }
1565
1566 /*
1567 * Ha! No more helper process!
1568 */
1569 afs_int32
1570 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1571 struct restoreCookie *cookie)
1572 {
1573 afs_int32 code;
1574
1575 code = VolRestore(acid, atrans, aflags, cookie);
1576 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1577 return code;
1578 }
1579
1580 static afs_int32
1581 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1582 struct restoreCookie *cookie)
1583 {
1584 struct volser_trans *tt;
1585 afs_int32 code, tcode;
1586 char caller[MAXKTCNAMELEN];
1587
1588 if (!afsconf_SuperUser(tdir, acid, caller))
1589 return VOLSERBAD_ACCESS; /*not a super user */
1590 tt = FindTrans(atrans);
1591 if (!tt)
1592 return ENOENT;
1593 if (tt->vflags & VTDeleted) {
1594 Log("1 Volser: VolRestore: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1595 TRELE(tt);
1596 return ENOENT;
1597 }
1598 if (DoLogging) {
1599 char buffer[16];
1600 Log("%s on %s is executing Restore %" AFS_VOLID_FMT "\n", caller,
1601 callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
1602 }
1603 TSetRxCall(tt, acid, "Restore");
1604
1605 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1606
1607 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1608 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1609 TClearRxCall(tt);
1610 tcode = TRELE(tt);
1611
1612 return (code ? code : tcode);
1613 }
1614
1615 /* end a transaction, returning the transaction's final error code in rcode */
1616 afs_int32
1617 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1618 {
1619 afs_int32 code;
1620
1621 code = VolEndTrans(acid, destTrans, rcode);
1622 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1623 return code;
1624 }
1625
1626 static afs_int32
1627 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1628 {
1629 struct volser_trans *tt;
1630 char caller[MAXKTCNAMELEN];
1631
1632 if (!afsconf_SuperUser(tdir, acid, caller))
1633 return VOLSERBAD_ACCESS; /*not a super user */
1634 tt = FindTrans(destTrans);
1635 if (!tt) {
1636 return ENOENT;
1637 }
1638 *rcode = tt->returnCode;
1639 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1640
1641 return 0;
1642 }
1643
1644 afs_int32
1645 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1646 {
1647 afs_int32 code;
1648
1649 code = VolSetForwarding(acid, atid, anewsite);
1650 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1651 htonl(anewsite), AUD_END);
1652 return code;
1653 }
1654
1655 static afs_int32
1656 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1657 {
1658 struct volser_trans *tt;
1659 char caller[MAXKTCNAMELEN];
1660 char partName[16];
1661
1662 if (!afsconf_SuperUser(tdir, acid, caller))
1663 return VOLSERBAD_ACCESS; /*not a super user */
1664 tt = FindTrans(atid);
1665 if (!tt)
1666 return ENOENT;
1667 if (tt->vflags & VTDeleted) {
1668 Log("1 Volser: VolSetForwarding: volume %" AFS_VOLID_FMT " has been deleted \n",
1669 afs_printable_VolumeId_lu(tt->volid));
1670 TRELE(tt);
1671 return ENOENT;
1672 }
1673 TSetRxCall(tt, acid, "SetForwarding");
1674 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1675 partName[0] = '\0';
1676 }
1677 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1678 TClearRxCall(tt);
1679 if (TRELE(tt))
1680 return VOLSERTRELE_ERROR;
1681
1682 return 0;
1683 }
1684
1685 afs_int32
1686 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1687 struct volser_status *astatus)
1688 {
1689 afs_int32 code;
1690
1691 code = VolGetStatus(acid, atrans, astatus);
1692 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1693 return code;
1694 }
1695
1696 static afs_int32
1697 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1698 struct volser_status *astatus)
1699 {
1700 struct Volume *tv;
1701 struct VolumeDiskData *td;
1702 struct volser_trans *tt;
1703
1704 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1705 return VOLSERBAD_ACCESS;
1706
1707 tt = FindTrans(atrans);
1708 if (!tt)
1709 return ENOENT;
1710 if (tt->vflags & VTDeleted) {
1711 Log("1 Volser: VolGetStatus: volume %" AFS_VOLID_FMT " has been deleted \n",
1712 afs_printable_VolumeId_lu(tt->volid));
1713 TRELE(tt);
1714 return ENOENT;
1715 }
1716 TSetRxCall(tt, acid, "GetStatus");
1717 tv = tt->volume;
1718 if (!tv) {
1719 TClearRxCall(tt);
1720 TRELE(tt);
1721 return ENOENT;
1722 }
1723
1724 td = &(V_disk(tv));
1725 astatus->volID = td->id;
1726 astatus->nextUnique = td->uniquifier;
1727 astatus->type = td->type;
1728 astatus->parentID = td->parentId;
1729 astatus->cloneID = td->cloneId;
1730 astatus->backupID = td->backupId;
1731 astatus->restoredFromID = td->restoredFromId;
1732 astatus->maxQuota = td->maxquota;
1733 astatus->minQuota = td->minquota;
1734 astatus->owner = td->owner;
1735 astatus->creationDate = td->creationDate;
1736 astatus->accessDate = td->accessDate;
1737 astatus->updateDate = td->updateDate;
1738 astatus->expirationDate = td->expirationDate;
1739 astatus->backupDate = td->backupDate;
1740 astatus->copyDate = td->copyDate;
1741 TClearRxCall(tt);
1742 if (TRELE(tt))
1743 return VOLSERTRELE_ERROR;
1744
1745 return 0;
1746 }
1747
1748 afs_int32
1749 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1750 struct volintInfo *astatus)
1751 {
1752 afs_int32 code;
1753
1754 code = VolSetInfo(acid, atrans, astatus);
1755 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1756 return code;
1757 }
1758
1759 static afs_int32
1760 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1761 struct volintInfo *astatus)
1762 {
1763 struct Volume *tv;
1764 struct VolumeDiskData *td;
1765 struct volser_trans *tt;
1766 char caller[MAXKTCNAMELEN];
1767 Error error;
1768
1769 if (!afsconf_SuperUser(tdir, acid, caller))
1770 return VOLSERBAD_ACCESS; /*not a super user */
1771 tt = FindTrans(atrans);
1772 if (!tt)
1773 return ENOENT;
1774 if (tt->vflags & VTDeleted) {
1775 Log("1 Volser: VolSetInfo: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1776 TRELE(tt);
1777 return ENOENT;
1778 }
1779 TSetRxCall(tt, acid, "SetStatus");
1780 tv = tt->volume;
1781 if (!tv) {
1782 TClearRxCall(tt);
1783 TRELE(tt);
1784 return ENOENT;
1785 }
1786
1787 td = &(V_disk(tv));
1788 /*
1789 * Add more fields as necessary
1790 */
1791 if (astatus->maxquota != -1)
1792 td->maxquota = astatus->maxquota;
1793 if (astatus->dayUse != -1)
1794 td->dayUse = astatus->dayUse;
1795 if (astatus->creationDate != -1)
1796 td->creationDate = astatus->creationDate;
1797 if (astatus->updateDate != -1)
1798 td->updateDate = astatus->updateDate;
1799 if (astatus->spare2 != -1)
1800 td->volUpdateCounter = (unsigned int)astatus->spare2;
1801 VUpdateVolume(&error, tv);
1802 TClearRxCall(tt);
1803 if (TRELE(tt))
1804 return VOLSERTRELE_ERROR;
1805 return 0;
1806 }
1807
1808
1809 afs_int32
1810 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1811 {
1812 afs_int32 code;
1813
1814 code = VolGetName(acid, atrans, aname);
1815 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1816 return code;
1817 }
1818
1819 static afs_int32
1820 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1821 {
1822 struct Volume *tv;
1823 struct VolumeDiskData *td;
1824 struct volser_trans *tt;
1825 int len;
1826
1827 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1828 return VOLSERBAD_ACCESS;
1829
1830 /* We need to at least fill it in */
1831 *aname = malloc(1);
1832 if (!*aname)
1833 return ENOMEM;
1834 tt = FindTrans(atrans);
1835 if (!tt)
1836 return ENOENT;
1837 if (tt->vflags & VTDeleted) {
1838 Log("1 Volser: VolGetName: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1839 TRELE(tt);
1840 return ENOENT;
1841 }
1842 TSetRxCall(tt, acid, "GetName");
1843 tv = tt->volume;
1844 if (!tv) {
1845 TClearRxCall(tt);
1846 TRELE(tt);
1847 return ENOENT;
1848 }
1849
1850 td = &(V_disk(tv));
1851 len = strlen(td->name) + 1; /* don't forget the null */
1852 if (len >= SIZE) {
1853 TClearRxCall(tt);
1854 TRELE(tt);
1855 return E2BIG;
1856 }
1857 *aname = realloc(*aname, len);
1858 strcpy(*aname, td->name);
1859 TClearRxCall(tt);
1860 if (TRELE(tt))
1861 return VOLSERTRELE_ERROR;
1862
1863 return 0;
1864 }
1865
1866 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1867 * - a noop now !*/
1868 afs_int32
1869 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1870 VolumeId parentId, VolumeId cloneId)
1871 {
1872 return 0;
1873 }
1874
1875
1876 /*return a list of all partitions on the server. The non mounted
1877 *partitions are returned as -1 in the corresponding slot in partIds*/
1878 afs_int32
1879 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1880 {
1881 afs_int32 code;
1882
1883 code = VolListPartitions(acid, partIds);
1884 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1885 return code;
1886 }
1887
1888 static afs_int32
1889 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1890 {
1891 char namehead[9];
1892 int i;
1893
1894 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1895 return VOLSERBAD_ACCESS;
1896
1897 strcpy(namehead, "/vicep"); /*7 including null terminator */
1898
1899 /* Just return attached partitions. */
1900 namehead[7] = '\0';
1901 for (i = 0; i < 26; i++) {
1902 namehead[6] = i + 'a';
1903 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1904 }
1905
1906 return 0;
1907 }
1908
1909 /*return a list of all partitions on the server. The non mounted
1910 *partitions are returned as -1 in the corresponding slot in partIds*/
1911 afs_int32
1912 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1913 {
1914 afs_int32 code;
1915
1916 code = XVolListPartitions(acid, pEntries);
1917 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1918 return code;
1919 }
1920
1921 static afs_int32
1922 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1923 {
1924 char namehead[9];
1925 struct partList partList;
1926 struct DiskPartition64 *dp;
1927 int i, j = 0;
1928
1929 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1930 return VOLSERBAD_ACCESS;
1931
1932 strcpy(namehead, "/vicep"); /*7 including null terminator */
1933
1934 /* Only report attached partitions */
1935 for (i = 0; i < VOLMAXPARTS; i++) {
1936 #ifdef AFS_DEMAND_ATTACH_FS
1937 dp = VGetPartitionById(i, 0);
1938 #else
1939 if (i < 26) {
1940 namehead[6] = i + 'a';
1941 namehead[7] = '\0';
1942 } else {
1943 int k;
1944
1945 k = i - 26;
1946 namehead[6] = 'a' + (k / 26);
1947 namehead[7] = 'a' + (k % 26);
1948 namehead[8] = '\0';
1949 }
1950 dp = VGetPartition(namehead, 0);
1951 #endif
1952 if (dp)
1953 partList.partId[j++] = i;
1954 }
1955 if (j > 0) {
1956 pEntries->partEntries_val = malloc(j * sizeof(int));
1957 if (!pEntries->partEntries_val)
1958 return ENOMEM;
1959 memcpy(pEntries->partEntries_val, partList.partId,
1960 j * sizeof(int));
1961 pEntries->partEntries_len = j;
1962 } else {
1963 pEntries->partEntries_val = NULL;
1964 pEntries->partEntries_len = 0;
1965 }
1966 return 0;
1967
1968 }
1969
1970 /*
1971 * Scan a directory for possible volume headers.
1972 * in: DIR *dirp -- a directory handle from opendir()
1973 * out: char *volname -- set to name of directory entry
1974 * afs_uint32 *volid -- set to volume ID parsed from name
1975 * returns:
1976 * true if volname and volid have been set to valid values
1977 * false if we got to the end of the directory
1978 */
1979 static int
1980 GetNextVol(DIR *dirp, char *volname, VolumeId *volid)
1981 {
1982 struct dirent *dp;
1983
1984 while ((dp = readdir(dirp)) != NULL) {
1985 /* could be optimized on platforms with dp->d_namlen */
1986 if (dp->d_name[0] == 'V' && strlen(dp->d_name) == VHDRNAMELEN
1987 && strcmp(&(dp->d_name[VFORMATDIGITS + 1]), VHDREXT) == 0) {
1988 *volid = VolumeNumber(dp->d_name);
1989 strcpy(volname, dp->d_name);
1990 return 1;
1991 }
1992 }
1993 return 0;
1994 }
1995
1996 /**
1997 * volint vol info structure type.
1998 */
1999 typedef enum {
2000 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
2001 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
2002 } volint_info_type_t;
2003
2004 /**
2005 * handle to various on-wire vol info types.
2006 */
2007 typedef struct {
2008 volint_info_type_t volinfo_type;
2009 union {
2010 void * opaque;
2011 volintInfo * base;
2012 volintXInfo * ext;
2013 } volinfo_ptr;
2014 } volint_info_handle_t;
2015
2016 /**
2017 * store value to a field at the appropriate location in on-wire structure.
2018 */
2019 #define VOLINT_INFO_STORE(handle, name, val) \
2020 do { \
2021 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
2022 (handle)->volinfo_ptr.base->name = (val); \
2023 } else { \
2024 (handle)->volinfo_ptr.ext->name = (val); \
2025 } \
2026 } while(0)
2027
2028 /**
2029 * get pointer to appropriate offset of field in on-wire structure.
2030 */
2031 #define VOLINT_INFO_PTR(handle, name) \
2032 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
2033 &((handle)->volinfo_ptr.base->name) : \
2034 &((handle)->volinfo_ptr.ext->name))
2035
2036 /**
2037 * fill in appropriate type of on-wire volume metadata structure.
2038 *
2039 * @param vp pointer to volume object
2040 * @param handle pointer to wire format handle object
2041 *
2042 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
2043 * @pre handle object must have a valid pointer and enumeration value
2044 *
2045 * @note passing a NULL value for vp means that the fileserver doesn't
2046 * know about this particular volume, thus implying it is offline.
2047 *
2048 * @return operation status
2049 * @retval 0 success
2050 * @retval 1 failure
2051 */
2052 static int
2053 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
2054 {
2055 unsigned int numStatBytes, now;
2056 struct VolumeDiskData *hdr = &(V_disk(vp));
2057
2058 /*read in the relevant info */
2059 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2060 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
2061 VOLINT_INFO_STORE(handle, volid, hdr->id);
2062 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2063 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2064 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2065 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2066 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2067 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2068 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2069 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2070 now = FT_ApproxTime();
2071 if ((now - hdr->dayUseDate) > OneDay) {
2072 VOLINT_INFO_STORE(handle, dayUse, 0);
2073 } else {
2074 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2075 }
2076 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2077 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2078 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2079 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2080
2081 #ifdef AFS_DEMAND_ATTACH_FS
2082 /*
2083 * for DAFS, we "lie" about volume state --
2084 * instead of returning the raw state from the disk header,
2085 * we compute state based upon the fileserver's internal
2086 * in-core state enumeration value reported to us via fssync,
2087 * along with the blessed and inService flags from the header.
2088 * -- tkeiser 11/27/2007
2089 */
2090
2091 /* Conditions that offline status is based on:
2092 volume is unattached state
2093 volume state is in (one of several error states)
2094 volume not in service
2095 volume is not marked as blessed (not on hold)
2096 volume in salvage req. state
2097 volume needsSalvaged
2098 next op would set volume offline
2099 next op would not leave volume online (based on several conditions)
2100 */
2101 if (!vp ||
2102 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2103 VIsErrorState(V_attachState(vp)) ||
2104 !hdr->inService ||
2105 !hdr->blessed ||
2106 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2107 hdr->needsSalvaged ||
2108 (vp->pending_vol_op &&
2109 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2110 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2111 )
2112 ) {
2113 VOLINT_INFO_STORE(handle, inUse, 0);
2114 } else {
2115 VOLINT_INFO_STORE(handle, inUse, 1);
2116 }
2117 #else
2118 /* offline status based on program type, where != fileServer enum (1) is offline */
2119 if (hdr->inUse == fileServer) {
2120 VOLINT_INFO_STORE(handle, inUse, 1);
2121 } else {
2122 VOLINT_INFO_STORE(handle, inUse, 0);
2123 }
2124 #endif
2125
2126
2127 switch(handle->volinfo_type) {
2128 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2129 case VOLINT_INFO_TYPE_BASE:
2130
2131 #ifdef AFS_DEMAND_ATTACH_FS
2132 /* see comment above where we set inUse bit */
2133 if (hdr->needsSalvaged ||
2134 (vp && VIsErrorState(V_attachState(vp)))) {
2135 handle->volinfo_ptr.base->needsSalvaged = 1;
2136 } else {
2137 handle->volinfo_ptr.base->needsSalvaged = 0;
2138 }
2139 #else
2140 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2141 #endif
2142 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2143 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2144 handle->volinfo_ptr.base->spare1 =
2145 (long)hdr->weekUse[0] +
2146 (long)hdr->weekUse[1] +
2147 (long)hdr->weekUse[2] +
2148 (long)hdr->weekUse[3] +
2149 (long)hdr->weekUse[4] +
2150 (long)hdr->weekUse[5] +
2151 (long)hdr->weekUse[6];
2152 handle->volinfo_ptr.base->flags = 0;
2153 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2154 handle->volinfo_ptr.base->spare3 = 0;
2155 break;
2156
2157
2158 case VOLINT_INFO_TYPE_EXT:
2159 numStatBytes =
2160 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2161 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2162
2163 /*
2164 * Copy out the stat fields in a single operation.
2165 */
2166 if ((now - hdr->dayUseDate) > OneDay) {
2167 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2168 0, numStatBytes);
2169 } else {
2170 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2171 (char *)&(hdr->stat_reads[0]),
2172 numStatBytes);
2173 }
2174 break;
2175 }
2176
2177 return 0;
2178 }
2179
2180 #ifdef AFS_DEMAND_ATTACH_FS
2181
2182 /**
2183 * get struct Volume out of the fileserver.
2184 *
2185 * @param[in] volumeId volumeId for which we want state information
2186 * @param[in] pname partition name string
2187 * @param[inout] vp pointer to pointer to Volume object which
2188 * will be populated (see note)
2189 *
2190 * @return operation status
2191 * @retval 0 success
2192 * @retval non-zero failure
2193 *
2194 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2195 *
2196 * @internal
2197 */
2198 static int
2199 GetVolObject(VolumeId volumeId, char * pname, Volume ** vp)
2200 {
2201 int code;
2202 SYNC_response res;
2203
2204 res.hdr.response_len = sizeof(res.hdr);
2205 res.payload.buf = *vp;
2206 res.payload.len = sizeof(Volume);
2207
2208 code = FSYNC_VolOp(volumeId,
2209 pname,
2210 FSYNC_VOL_QUERY,
2211 0,
2212 &res);
2213
2214 if (code != SYNC_OK) {
2215 switch (res.hdr.reason) {
2216 case FSYNC_WRONG_PART:
2217 case FSYNC_UNKNOWN_VOLID:
2218 *vp = NULL;
2219 code = SYNC_OK;
2220 break;
2221 }
2222 }
2223
2224 return code;
2225 }
2226
2227 #endif
2228
2229 /**
2230 * mode of volume list operation.
2231 */
2232 typedef enum {
2233 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2234 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2235 } vol_info_list_mode_t;
2236
2237 /**
2238 * abstract interface to populate wire-format volume metadata structures.
2239 *
2240 * @param[in] partId partition id
2241 * @param[in] volumeId volume id
2242 * @param[in] pname partition name
2243 * @param[in] volname volume file name
2244 * @param[in] handle handle to on-wire volume metadata object
2245 * @param[in] mode listing mode
2246 *
2247 * @return operation status
2248 * @retval 0 success
2249 * @retval -2 DESTROY_ME flag is set
2250 * @retval -1 general failure; some data filled in
2251 * @retval -3 couldn't create vtrans; some data filled in
2252 */
2253 static int
2254 GetVolInfo(afs_uint32 partId,
2255 VolumeId volumeId,
2256 char * pname,
2257 char * volname,
2258 volint_info_handle_t * handle,
2259 vol_info_list_mode_t mode)
2260 {
2261 int code = -1;
2262 Error error;
2263 struct volser_trans *ttc = NULL;
2264 struct Volume *fill_tv, *tv = NULL;
2265 #ifdef AFS_DEMAND_ATTACH_FS
2266 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2267 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2268 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2269 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2270
2271 /* Set up response handle for pending_vol_op */
2272 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2273 fs_res.payload.buf = fs_res_buf;
2274 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2275 #endif
2276
2277 ttc = NewTrans(volumeId, partId);
2278 if (!ttc) {
2279 code = -3;
2280 VOLINT_INFO_STORE(handle, status, VBUSY);
2281 VOLINT_INFO_STORE(handle, volid, volumeId);
2282 goto drop;
2283 }
2284
2285 /* Get volume from volserver */
2286 if (mode == VOL_INFO_LIST_MULTIPLE)
2287 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2288 else {
2289 #ifdef AFS_DEMAND_ATTACH_FS
2290 int mode = V_PEEK;
2291 #else
2292 int mode = V_READONLY; /* informs the fileserver to update the volume headers. */
2293 #endif
2294 tv = VAttachVolumeByName_retry(&error, pname, volname, mode);
2295 }
2296
2297 if (error) {
2298 Log("1 Volser: GetVolInfo: Could not attach volume %" AFS_VOLID_FMT " (%s:%s) error=%d\n",
2299 afs_printable_VolumeId_lu(volumeId), pname, volname, error);
2300 goto drop;
2301 }
2302
2303 /*
2304 * please note that destroyMe and needsSalvaged checks used to be ordered
2305 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2306 * more correct to check destroyMe before needsSalvaged.
2307 * -- tkeiser 11/28/2007
2308 */
2309
2310 if (V_destroyMe(tv) == DESTROY_ME) {
2311 switch (mode) {
2312 case VOL_INFO_LIST_MULTIPLE:
2313 code = -2;
2314 goto drop;
2315
2316 case VOL_INFO_LIST_SINGLE:
2317 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) will be destroyed on next salvage\n",
2318 afs_printable_VolumeId_lu(volumeId), pname, volname);
2319
2320 default:
2321 goto drop;
2322 }
2323 }
2324
2325 if (V_needsSalvaged(tv)) {
2326 /*this volume will be salvaged */
2327 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) needs to be salvaged\n",
2328 afs_printable_VolumeId_lu(volumeId), pname, volname);
2329 }
2330
2331 #ifdef AFS_DEMAND_ATTACH_FS
2332 /* If using DAFS, get volume from fsserver */
2333 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2334
2335 goto drop;
2336 }
2337
2338 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2339 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2340 /* If we if the pending vol op */
2341 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2342 fs_tv->pending_vol_op=&pending_vol_op_res;
2343 } else {
2344 fs_tv->pending_vol_op=NULL;
2345 }
2346
2347 /* populate the header from the volserver copy */
2348 fs_tv->header=tv->header;
2349
2350 /* When using DAFS, use the fs volume info, populated with required structures */
2351 fill_tv = fs_tv;
2352 #else
2353 /* When not using DAFS, just use the local volume info */
2354 fill_tv = tv;
2355 #endif
2356
2357 /* ok, we have all the data we need; fill in the on-wire struct */
2358 code = FillVolInfo(fill_tv, handle);
2359
2360 drop:
2361 if (code == -1) {
2362 VOLINT_INFO_STORE(handle, status, 0);
2363 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2364 VOLINT_INFO_STORE(handle, volid, volumeId);
2365 }
2366 if (tv) {
2367 VDetachVolume(&error, tv);
2368 tv = NULL;
2369 if (error) {
2370 VOLINT_INFO_STORE(handle, status, 0);
2371 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2372 Log("1 Volser: GetVolInfo: Could not detach volume %" AFS_VOLID_FMT " (%s:%s)\n",
2373 afs_printable_VolumeId_lu(volumeId), pname, volname);
2374 }
2375 }
2376 if (ttc) {
2377 DeleteTrans(ttc, 1);
2378 ttc = NULL;
2379 }
2380 return code;
2381 }
2382
2383
2384 /*return the header information about the <volid> */
2385 afs_int32
2386 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2387 VolumeId volumeId, volEntries *volumeInfo)
2388 {
2389 afs_int32 code;
2390
2391 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2392 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2393 return code;
2394 }
2395
2396 static afs_int32
2397 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2398 VolumeId volumeId, volEntries *volumeInfo)
2399 {
2400 struct DiskPartition64 *partP;
2401 char pname[9], volname[20];
2402 DIR *dirp;
2403 VolumeId volid;
2404 int found = 0;
2405 volint_info_handle_t handle;
2406
2407 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2408 return VOLSERBAD_ACCESS;
2409
2410 volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2411 if (!volumeInfo->volEntries_val)
2412 return ENOMEM;
2413
2414 volumeInfo->volEntries_len = 1;
2415 if (GetPartName(partid, pname))
2416 return VOLSERILLEGAL_PARTITION;
2417 if (!(partP = VGetPartition(pname, 0)))
2418 return VOLSERILLEGAL_PARTITION;
2419 dirp = opendir(VPartitionPath(partP));
2420 if (dirp == NULL)
2421 return VOLSERILLEGAL_PARTITION;
2422
2423 while (GetNextVol(dirp, volname, &volid)) {
2424 if (volid == volumeId) { /*copy other things too */
2425 found = 1;
2426 break;
2427 }
2428 }
2429
2430 if (found) {
2431 #ifndef AFS_PTHREAD_ENV
2432 IOMGR_Poll(); /*make sure that the client does not time out */
2433 #endif
2434
2435 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2436 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2437
2438 /* The return code from GetVolInfo is ignored; there is no error from
2439 * it that results in the whole call being aborted. Any volume
2440 * attachment failures are reported in 'status' field in the
2441 * volumeInfo payload. */
2442 GetVolInfo(partid,
2443 volid,
2444 pname,
2445 volname,
2446 &handle,
2447 VOL_INFO_LIST_SINGLE);
2448 }
2449
2450 closedir(dirp);
2451 return (found) ? 0 : ENODEV;
2452 }
2453
2454 /*------------------------------------------------------------------------
2455 * EXPORTED SAFSVolXListOneVolume
2456 *
2457 * Description:
2458 * Returns extended info on volume a_volID on partition a_partID.
2459 *
2460 * Arguments:
2461 * a_rxCidP : Pointer to the Rx call we're performing.
2462 * a_partID : Partition for which we want the extended list.
2463 * a_volID : Volume ID we wish to know about.
2464 * a_volumeXInfoP : Ptr to the extended info blob.
2465 *
2466 * Returns:
2467 * 0 Successful operation
2468 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2469 *
2470 * Environment:
2471 * Nothing interesting.
2472 *
2473 * Side Effects:
2474 * As advertised.
2475 *------------------------------------------------------------------------*/
2476
2477 afs_int32
2478 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2479 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2480 {
2481 afs_int32 code;
2482
2483 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2484 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2485 return code;
2486 }
2487
2488 static afs_int32
2489 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2490 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2491 { /*SAFSVolXListOneVolume */
2492
2493 struct DiskPartition64 *partP; /*Ptr to partition */
2494 char pname[9], volname[20]; /*Partition, volume names */
2495 DIR *dirp; /*Partition directory ptr */
2496 VolumeId currVolID; /*Current volume ID */
2497 int found = 0; /*Did we find the volume we need? */
2498 volint_info_handle_t handle;
2499
2500 if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
2501 return VOLSERBAD_ACCESS;
2502
2503 /*
2504 * Set up our pointers for action, marking our structure to hold exactly
2505 * one entry. Also, assume we'll fail in our quest.
2506 */
2507 a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2508 if (!a_volumeXInfoP->volXEntries_val)
2509 return ENOMEM;
2510
2511 a_volumeXInfoP->volXEntries_len = 1;
2512
2513 /*
2514 * If the partition name we've been given is bad, bogue out.
2515 */
2516 if (GetPartName(a_partID, pname))
2517 return (VOLSERILLEGAL_PARTITION);
2518
2519 /*
2520 * Open the directory representing the given AFS parttion. If we can't
2521 * do that, we lose.
2522 */
2523 if (!(partP = VGetPartition(pname, 0)))
2524 return VOLSERILLEGAL_PARTITION;
2525 dirp = opendir(VPartitionPath(partP));
2526 if (dirp == NULL)
2527 return (VOLSERILLEGAL_PARTITION);
2528
2529
2530 /*
2531 * Sweep through the partition directory, looking for the desired entry.
2532 * First, of course, figure out how many stat bytes to copy out of each
2533 * volume.
2534 */
2535 while (GetNextVol(dirp, volname, &currVolID)) {
2536 if (currVolID == a_volID) {
2537 /*
2538 * We found the volume entry we're interested. Pull out the
2539 * extended information, remembering to poll (so that the client
2540 * doesn't time out) and to set up a transaction on the volume.
2541 */
2542 found = 1;
2543 break;
2544 } /*Found desired volume */
2545 }
2546
2547 if (found) {
2548 #ifndef AFS_PTHREAD_ENV
2549 IOMGR_Poll();
2550 #endif
2551
2552 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2553 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2554
2555 /* The return code from GetVolInfo is ignored; there is no error from
2556 * it that results in the whole call being aborted. Any volume
2557 * attachment failures are reported in 'status' field in the
2558 * volumeInfo payload. */
2559 GetVolInfo(a_partID,
2560 a_volID,
2561 pname,
2562 volname,
2563 &handle,
2564 VOL_INFO_LIST_SINGLE);
2565 }
2566
2567 /*
2568 * Clean up before going to dinner: close the partition directory,
2569 * return the proper value.
2570 */
2571 closedir(dirp);
2572 return (found) ? 0 : ENODEV;
2573 } /*SAFSVolXListOneVolume */
2574
2575 /*returns all the volumes on partition partid. If flags = 1 then all the
2576 * relevant info about the volumes is also returned */
2577 afs_int32
2578 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2579 volEntries *volumeInfo)
2580 {
2581 afs_int32 code;
2582
2583 code = VolListVolumes(acid, partid, flags, volumeInfo);
2584 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2585 return code;
2586 }
2587
2588 static afs_int32
2589 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2590 volEntries *volumeInfo)
2591 {
2592 volintInfo *pntr;
2593 struct DiskPartition64 *partP;
2594 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2595 char pname[9], volname[20];
2596 DIR *dirp;
2597 VolumeId volid;
2598 int code;
2599 volint_info_handle_t handle;
2600
2601 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2602 return VOLSERBAD_ACCESS;
2603
2604 volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2605 if (!volumeInfo->volEntries_val)
2606 return ENOMEM;
2607
2608 pntr = volumeInfo->volEntries_val;
2609 volumeInfo->volEntries_len = 0;
2610 if (GetPartName(partid, pname))
2611 return VOLSERILLEGAL_PARTITION;
2612 if (!(partP = VGetPartition(pname, 0)))
2613 return VOLSERILLEGAL_PARTITION;
2614 dirp = opendir(VPartitionPath(partP));
2615 if (dirp == NULL)
2616 return VOLSERILLEGAL_PARTITION;
2617
2618 while (GetNextVol(dirp, volname, &volid)) {
2619 if (flags) { /*copy other things too */
2620 #ifndef AFS_PTHREAD_ENV
2621 IOMGR_Poll(); /*make sure that the client does not time out */
2622 #endif
2623
2624 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2625 handle.volinfo_ptr.base = pntr;
2626
2627
2628 code = GetVolInfo(partid,
2629 volid,
2630 pname,
2631 volname,
2632 &handle,
2633 VOL_INFO_LIST_MULTIPLE);
2634 if (code == -2) /* DESTROY_ME flag set */
2635 continue;
2636 } else {
2637 pntr->volid = volid;
2638 /*just volids are needed */
2639 }
2640
2641 pntr++;
2642 volumeInfo->volEntries_len += 1;
2643 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2644 /*running out of space, allocate more space */
2645 allocSize = (allocSize * 3) / 2;
2646 pntr = realloc(volumeInfo->volEntries_val,
2647 allocSize * sizeof(volintInfo));
2648 if (pntr == NULL) {
2649 closedir(dirp);
2650 return VOLSERNO_MEMORY;
2651 }
2652 volumeInfo->volEntries_val = pntr; /* point to new block */
2653 /* set pntr to the right position */
2654 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2655 }
2656 }
2657
2658 closedir(dirp);
2659 return 0;
2660 }
2661
2662 /*------------------------------------------------------------------------
2663 * EXPORTED SAFSVolXListVolumes
2664 *
2665 * Description:
2666 * Returns all the volumes on partition a_partID. If a_flags
2667 * is set to 1, then all the relevant extended volume information
2668 * is also returned.
2669 *
2670 * Arguments:
2671 * a_rxCidP : Pointer to the Rx call we're performing.
2672 * a_partID : Partition for which we want the extended list.
2673 * a_flags : Various flags.
2674 * a_volumeXInfoP : Ptr to the extended info blob.
2675 *
2676 * Returns:
2677 * 0 Successful operation
2678 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2679 * VOLSERNO_MEMORY if we ran out of memory allocating
2680 * our return blob
2681 *
2682 * Environment:
2683 * Nothing interesting.
2684 *
2685 * Side Effects:
2686 * As advertised.
2687 *------------------------------------------------------------------------*/
2688
2689 afs_int32
2690 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2691 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2692 {
2693 afs_int32 code;
2694
2695 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2696 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2697 return code;
2698 }
2699
2700 static afs_int32
2701 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2702 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2703 { /*SAFSVolXListVolumes */
2704
2705 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2706 struct DiskPartition64 *partP; /*Ptr to partition */
2707 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2708 char pname[9], volname[20]; /*Partition, volume names */
2709 DIR *dirp; /*Partition directory ptr */
2710 VolumeId volid; /*Current volume ID */
2711 int code;
2712 volint_info_handle_t handle;
2713
2714 if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
2715 return VOLSERBAD_ACCESS;
2716
2717 /*
2718 * Allocate a large array of extended volume info structures, then
2719 * set it up for action.
2720 */
2721 a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2722 if (!a_volumeXInfoP->volXEntries_val)
2723 return ENOMEM;
2724
2725 xInfoP = a_volumeXInfoP->volXEntries_val;
2726 a_volumeXInfoP->volXEntries_len = 0;
2727
2728 /*
2729 * If the partition name we've been given is bad, bogue out.
2730 */
2731 if (GetPartName(a_partID, pname))
2732 return (VOLSERILLEGAL_PARTITION);
2733
2734 /*
2735 * Open the directory representing the given AFS parttion. If we can't
2736 * do that, we lose.
2737 */
2738 if (!(partP = VGetPartition(pname, 0)))
2739 return VOLSERILLEGAL_PARTITION;
2740 dirp = opendir(VPartitionPath(partP));
2741 if (dirp == NULL)
2742 return (VOLSERILLEGAL_PARTITION);
2743 while (GetNextVol(dirp, volname, &volid)) {
2744 if (a_flags) {
2745 /*
2746 * Full info about the volume desired. Poll to make sure the
2747 * client doesn't time out, then start up a new transaction.
2748 */
2749 #ifndef AFS_PTHREAD_ENV
2750 IOMGR_Poll();
2751 #endif
2752
2753 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2754 handle.volinfo_ptr.ext = xInfoP;
2755
2756 code = GetVolInfo(a_partID,
2757 volid,
2758 pname,
2759 volname,
2760 &handle,
2761 VOL_INFO_LIST_MULTIPLE);
2762 if (code == -2) /* DESTROY_ME flag set */
2763 continue;
2764 } else {
2765 /*
2766 * Just volume IDs are needed.
2767 */
2768 xInfoP->volid = volid;
2769 }
2770
2771 /*
2772 * Bump the pointer in the data area we're building, along with
2773 * the count of the number of entries it contains.
2774 */
2775 xInfoP++;
2776 (a_volumeXInfoP->volXEntries_len)++;
2777 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2778 /*
2779 * We're running out of space in the area we've built. Grow it.
2780 */
2781 allocSize = (allocSize * 3) / 2;
2782 xInfoP = (volintXInfo *)
2783 realloc((char *)a_volumeXInfoP->volXEntries_val,
2784 (allocSize * sizeof(volintXInfo)));
2785 if (xInfoP == NULL) {
2786 /*
2787 * Bummer, no memory. Bag it, tell our caller what went wrong.
2788 */
2789 closedir(dirp);
2790 return (VOLSERNO_MEMORY);
2791 }
2792
2793 /*
2794 * Memory reallocation worked. Correct our pointers so they
2795 * now point to the new block and the current open position within
2796 * the new block.
2797 */
2798 a_volumeXInfoP->volXEntries_val = xInfoP;
2799 xInfoP =
2800 a_volumeXInfoP->volXEntries_val +
2801 a_volumeXInfoP->volXEntries_len;
2802 }
2803 }
2804
2805 /*
2806 * We've examined all entries in the partition directory. Close it,
2807 * delete our transaction (if any), and go home happy.
2808 */
2809 closedir(dirp);
2810 return (0);
2811
2812 } /*SAFSVolXListVolumes */
2813
2814 /*this call is used to monitor the status of volser for debugging purposes.
2815 *information about all the active transactions is returned in transInfo*/
2816 afs_int32
2817 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2818 {
2819 afs_int32 code;
2820
2821 code = VolMonitor(acid, transInfo);
2822 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2823 return code;
2824 }
2825
2826 static afs_int32
2827 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2828 {
2829 transDebugInfo *pntr;
2830 afs_int32 allocSize = 50;
2831 struct volser_trans *tt, *nt, *allTrans;
2832
2833 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2834 return VOLSERBAD_ACCESS;
2835
2836 transInfo->transDebugEntries_val =
2837 malloc(allocSize * sizeof(transDebugInfo));
2838 if (!transInfo->transDebugEntries_val)
2839 return ENOMEM;
2840 pntr = transInfo->transDebugEntries_val;
2841 transInfo->transDebugEntries_len = 0;
2842
2843 VTRANS_LOCK;
2844 allTrans = TransList();
2845 if (allTrans == (struct volser_trans *)0)
2846 goto done; /*no active transactions */
2847 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2848 nt = tt->next;
2849 memset(pntr, 0, sizeof(*pntr));
2850 VTRANS_OBJ_LOCK(tt);
2851 pntr->tid = tt->tid;
2852 pntr->time = tt->time;
2853 pntr->creationTime = tt->creationTime;
2854 pntr->returnCode = tt->returnCode;
2855 pntr->volid = tt->volid;
2856 pntr->partition = tt->partition;
2857 pntr->iflags = tt->iflags;
2858 pntr->vflags = tt->vflags;
2859 pntr->tflags = tt->tflags;
2860 strcpy(pntr->lastProcName, tt->lastProcName);
2861 pntr->callValid = 0;
2862 if (tt->rxCallPtr) { /*record call related info */
2863 pntr->callValid = 1;
2864 rx_GetCallStatus(tt->rxCallPtr, &(pntr->readNext), &(pntr->transmitNext),
2865 &(pntr->lastSendTime), &(pntr->lastReceiveTime));
2866 }
2867 VTRANS_OBJ_UNLOCK(tt);
2868 pntr++;
2869 transInfo->transDebugEntries_len += 1;
2870 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2871 allocSize = (allocSize * 3) / 2;
2872 pntr = realloc(transInfo->transDebugEntries_val,
2873 allocSize * sizeof(transDebugInfo));
2874 transInfo->transDebugEntries_val = pntr;
2875 pntr =
2876 transInfo->transDebugEntries_val +
2877 transInfo->transDebugEntries_len;
2878 /*set pntr to right position */
2879 }
2880
2881 }
2882 done:
2883 VTRANS_UNLOCK;
2884
2885 return 0;
2886 }
2887
2888 afs_int32
2889 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2890 afs_int32 type, afs_uint32 pId, VolumeId cloneId,
2891 VolumeId backupId)
2892 {
2893 afs_int32 code;
2894
2895 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2896 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2897 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2898 backupId, AUD_END);
2899 return code;
2900 }
2901
2902 static afs_int32
2903 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2904 afs_int32 type, VolumeId pId, VolumeId cloneId,
2905 VolumeId backupId)
2906 {
2907 struct Volume *tv;
2908 Error error = 0;
2909 struct volser_trans *tt;
2910 char caller[MAXKTCNAMELEN];
2911
2912 if (strlen(name) > 31)
2913 return VOLSERBADNAME;
2914 if (!afsconf_SuperUser(tdir, acid, caller))
2915 return VOLSERBAD_ACCESS; /*not a super user */
2916 /* find the trans */
2917 tt = FindTrans(atid);
2918 if (!tt)
2919 return ENOENT;
2920 if (tt->vflags & VTDeleted) {
2921 Log("1 Volser: VolSetIds: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2922 TRELE(tt);
2923 return ENOENT;
2924 }
2925 TSetRxCall(tt, acid, "SetIdsTypes");
2926 tv = tt->volume;
2927
2928 V_type(tv) = type;
2929 V_backupId(tv) = backupId;
2930 V_cloneId(tv) = cloneId;
2931 V_parentId(tv) = pId;
2932 strcpy((&V_disk(tv))->name, name);
2933 VUpdateVolume(&error, tv);
2934 if (error) {
2935 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2936 LogError(error);
2937 goto fail;
2938 }
2939 TClearRxCall(tt);
2940 if (TRELE(tt) && !error)
2941 return VOLSERTRELE_ERROR;
2942
2943 return error;
2944 fail:
2945 TClearRxCall(tt);
2946 if (TRELE(tt) && !error)
2947 return VOLSERTRELE_ERROR;
2948 return error;
2949 }
2950
2951 afs_int32
2952 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2953 {
2954 afs_int32 code;
2955
2956 code = VolSetDate(acid, atid, cdate);
2957 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2958 AUD_END);
2959 return code;
2960 }
2961
2962 static afs_int32
2963 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2964 {
2965 struct Volume *tv;
2966 Error error = 0;
2967 struct volser_trans *tt;
2968 char caller[MAXKTCNAMELEN];
2969
2970 if (!afsconf_SuperUser(tdir, acid, caller))
2971 return VOLSERBAD_ACCESS; /*not a super user */
2972 /* find the trans */
2973 tt = FindTrans(atid);
2974 if (!tt)
2975 return ENOENT;
2976 if (tt->vflags & VTDeleted) {
2977 Log("1 Volser: VolSetDate: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2978 TRELE(tt);
2979 return ENOENT;
2980 }
2981 TSetRxCall(tt, acid, "SetDate");
2982 tv = tt->volume;
2983
2984 V_creationDate(tv) = cdate;
2985 VUpdateVolume(&error, tv);
2986 if (error) {
2987 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2988 LogError(error);
2989 goto fail;
2990 }
2991 TClearRxCall(tt);
2992 if (TRELE(tt) && !error)
2993 return VOLSERTRELE_ERROR;
2994
2995 return error;
2996 fail:
2997 TClearRxCall(tt);
2998 if (TRELE(tt) && !error)
2999 return VOLSERTRELE_ERROR;
3000 return error;
3001 }
3002
3003 afs_int32
3004 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
3005 VolumeId volumeId)
3006 {
3007 #ifdef AFS_NT40_ENV
3008 return EXDEV;
3009 #else
3010 char caller[MAXKTCNAMELEN];
3011 DIR *dirp;
3012 struct volser_trans *ttc;
3013 char pname[16], volname[20];
3014 struct DiskPartition64 *partP;
3015 afs_int32 ret = ENODEV;
3016 VolumeId volid;
3017
3018 if (!afsconf_SuperUser(tdir, acid, caller))
3019 return VOLSERBAD_ACCESS; /*not a super user */
3020 if (GetPartName(partId, pname))
3021 return VOLSERILLEGAL_PARTITION;
3022 if (!(partP = VGetPartition(pname, 0)))
3023 return VOLSERILLEGAL_PARTITION;
3024 dirp = opendir(VPartitionPath(partP));
3025 if (dirp == NULL)
3026 return VOLSERILLEGAL_PARTITION;
3027 ttc = (struct volser_trans *)0;
3028
3029 while (GetNextVol(dirp, volname, &volid)) {
3030 if (volid == volumeId) { /*copy other things too */
3031 #ifndef AFS_PTHREAD_ENV
3032 IOMGR_Poll(); /*make sure that the client doesnot time out */
3033 #endif
3034 ttc = NewTrans(volumeId, partId);
3035 if (!ttc) {
3036 return VOLSERVOLBUSY;
3037 }
3038 #ifdef AFS_NAMEI_ENV
3039 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3040 #else
3041 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3042 #endif
3043 break;
3044 }
3045 }
3046
3047 if (ttc)
3048 DeleteTrans(ttc, 1);
3049
3050 closedir(dirp);
3051 return ret;
3052 #endif
3053 }
3054
3055 afs_int32
3056 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3057 struct volintSize *size)
3058 {
3059 int code = 0;
3060 struct volser_trans *tt;
3061 char caller[MAXKTCNAMELEN];
3062
3063 if (!afsconf_SuperUser(tdir, acid, caller))
3064 return VOLSERBAD_ACCESS; /*not a super user */
3065 tt = FindTrans(fromTrans);
3066 if (!tt)
3067 return ENOENT;
3068 if (tt->vflags & VTDeleted) {
3069 TRELE(tt);
3070 return ENOENT;
3071 }
3072 TSetRxCall(tt, acid, "GetSize");
3073 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3074 TClearRxCall(tt);
3075 if (TRELE(tt))
3076 return VOLSERTRELE_ERROR;
3077
3078 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3079 return code;
3080 }
3081
3082 afs_int32
3083 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 ovid, afs_uint32 onew,
3084 afs_uint32 where, afs_int32 verbose)
3085 {
3086 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3087 Error code, code2;
3088 Volume *vol=0, *newvol=0;
3089 struct volser_trans *tt = 0, *tt2 = 0;
3090 char caller[MAXKTCNAMELEN];
3091 char line[128];
3092 VolumeId new = onew;
3093 VolumeId vid = ovid;
3094
3095 if (!afsconf_SuperUser(tdir, acall, caller))
3096 return EPERM;
3097
3098 vol = VAttachVolume(&code, vid, V_VOLUPD);
3099 if (!vol) {
3100 if (!code)
3101 code = ENOENT;
3102 return code;
3103 }
3104 newvol = VAttachVolume(&code, new, V_VOLUPD);
3105 if (!newvol) {
3106 VDetachVolume(&code2, vol);
3107 if (!code)
3108 code = ENOENT;
3109 return code;
3110 }
3111 if (V_device(vol) != V_device(newvol)
3112 || V_uniquifier(newvol) != 2) {
3113 if (V_device(vol) != V_device(newvol)) {
3114 sprintf(line, "Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are not in the same partition, aborted.\n",
3115 afs_printable_VolumeId_lu(vid),
3116 afs_printable_VolumeId_lu(new));
3117 rx_Write(acall, line, strlen(line));
3118 }
3119 if (V_uniquifier(newvol) != 2) {
3120 sprintf(line, "Volume %" AFS_VOLID_FMT " is not freshly created, aborted.\n",
3121 afs_printable_VolumeId_lu(new));
3122 rx_Write(acall, line, strlen(line));
3123 }
3124 line[0] = 0;
3125 rx_Write(acall, line, 1);
3126 VDetachVolume(&code2, vol);
3127 VDetachVolume(&code2, newvol);
3128 return EINVAL;
3129 }
3130 tt = NewTrans(vid, V_device(vol));
3131 if (!tt) {
3132 sprintf(line, "Couldn't create transaction for %" AFS_VOLID_FMT ", aborted.\n",
3133 afs_printable_VolumeId_lu(vid));
3134 rx_Write(acall, line, strlen(line));
3135 line[0] = 0;
3136 rx_Write(acall, line, 1);
3137 VDetachVolume(&code2, vol);
3138 VDetachVolume(&code2, newvol);
3139 return VOLSERVOLBUSY;
3140 }
3141 VTRANS_OBJ_LOCK(tt);
3142 tt->iflags = ITBusy;
3143 tt->vflags = 0;
3144 TSetRxCall_r(tt, NULL, "SplitVolume");
3145 VTRANS_OBJ_UNLOCK(tt);
3146
3147 tt2 = NewTrans(new, V_device(newvol));
3148 if (!tt2) {
3149 sprintf(line, "Couldn't create transaction for %" AFS_VOLID_FMT ", aborted.\n",
3150 afs_printable_VolumeId_lu(new));
3151 rx_Write(acall, line, strlen(line));
3152 line[0] = 0;
3153 rx_Write(acall, line, 1);
3154 DeleteTrans(tt, 1);
3155 VDetachVolume(&code2, vol);
3156 VDetachVolume(&code2, newvol);
3157 return VOLSERVOLBUSY;
3158 }
3159 VTRANS_OBJ_LOCK(tt2);
3160 tt2->iflags = ITBusy;
3161 tt2->vflags = 0;
3162 TSetRxCall_r(tt2, NULL, "SplitVolume");
3163 VTRANS_OBJ_UNLOCK(tt2);
3164
3165 code = split_volume(acall, vol, newvol, where, verbose);
3166
3167 VDetachVolume(&code2, vol);
3168 DeleteTrans(tt, 1);
3169 VDetachVolume(&code2, newvol);
3170 DeleteTrans(tt2, 1);
3171 return code;
3172 #else
3173 return VOLSERBADOP;
3174 #endif
3175 }
3176
3177 /* GetPartName - map partid (a decimal number) into pname (a string)
3178 * Since for NT we actually want to return the drive name, we map through the
3179 * partition struct.
3180 */
3181 static int
3182 GetPartName(afs_int32 partid, char *pname)
3183 {
3184 if (partid < 0)
3185 return -1;
3186 if (partid < 26) {
3187 strcpy(pname, "/vicep");
3188 pname[6] = 'a' + partid;
3189 pname[7] = '\0';
3190 return 0;
3191 } else if (partid < VOLMAXPARTS) {
3192 strcpy(pname, "/vicep");
3193 partid -= 26;
3194 pname[6] = 'a' + (partid / 26);
3195 pname[7] = 'a' + (partid % 26);
3196 pname[8] = '\0';
3197 return 0;
3198 } else
3199 return -1;
3200 }