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