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