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