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