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