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