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