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