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