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