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