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