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