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