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