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