fix-attach-directories-code-to-properly-use-vgetpartition-20011011
[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     struct DiskPartition *dp;
1633     int i, j=0, k;
1634
1635     strcpy(namehead, "/vicep"); /*7 including null terminator*/
1636
1637     /* Only report attached partitions */
1638     for(i = 0 ; i < VOLMAXPARTS; i++){
1639         if (i < 26) {
1640             namehead[6] = i + 'a';
1641             namehead[7] = '\0';
1642         } else {
1643             k = i - 26;
1644             namehead[6] = 'a' + (k/26);
1645             namehead[7] = 'a' + (k%26);
1646             namehead[8] = '\0';
1647         }
1648         dp = VGetPartition(namehead, 0);
1649         if (dp)
1650             partList.partId[j++] = i;
1651     }
1652     pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1653     memcpy((char *)pEntries->partEntries_val, (char *)&partList, j * sizeof(int));
1654     pEntries->partEntries_len = j;
1655     return 0;
1656
1657 }
1658
1659 /*extract the volume id from string vname. Its of the form " V0*<id>.vol  "*/
1660 afs_int32 ExtractVolId(vname)
1661 char vname[];
1662 {
1663     int i;
1664     char name[VOLSER_MAXVOLNAME +1];
1665
1666     strcpy(name,vname);
1667     i = 0;
1668     while(name[i] == 'V' || name[i] == '0')
1669         i++;
1670     
1671     name[11] = '\0';    /* smash the "." */
1672     return(atol(&name[i]));
1673 }
1674
1675 /*return the name of the next volume header in the directory associated with dirp and dp.
1676 *the volume id is  returned in volid, and volume header name is returned in volname*/
1677 GetNextVol(DIR *dirp, char *volname, afs_int32 *volid)
1678 {  
1679     struct dirent *dp;
1680
1681     dp = readdir(dirp);/*read next entry in the directory */
1682     if(dp){
1683         
1684         if((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)){
1685             *volid = ExtractVolId(dp->d_name);
1686             strcpy(volname,dp->d_name);
1687             return 0;/*return the name of the file representing a volume */
1688         }
1689         else {
1690             strcpy(volname,"");
1691             return 0;/*volname doesnot represent a volume*/
1692         }
1693     }
1694     else {strcpy(volname,"EOD"); return 0;/*end of directory */}
1695     
1696 }
1697
1698 /*return the header information about the <volid> */
1699 afs_int32 SAFSVolListOneVolume (acid, partid, volumeId, volumeInfo)
1700 struct rx_call *acid;
1701 afs_int32 volumeId, partid;
1702 volEntries *volumeInfo;
1703 {
1704   afs_int32 code;
1705
1706   code = VolListOneVolume (acid, partid, volumeId, volumeInfo);
1707   osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
1708   return code;
1709 }
1710
1711 afs_int32 VolListOneVolume (acid, partid, volumeId, volumeInfo)
1712 struct rx_call *acid;
1713 afs_int32 volumeId, partid;
1714 volEntries *volumeInfo;
1715 {   volintInfo *pntr;
1716     register struct Volume *tv;
1717     struct DiskPartition *partP;
1718     struct volser_trans *ttc;
1719     char pname[9], volname[20];
1720     afs_int32 error = 0;
1721     DIR *dirp;
1722     afs_int32 volid;
1723     int found = 0;
1724     unsigned int now;
1725
1726     volumeInfo->volEntries_val = (volintInfo *) malloc( sizeof(volintInfo));
1727     pntr = volumeInfo->volEntries_val;
1728     volumeInfo->volEntries_len = 1;
1729     if(GetPartName(partid, pname)) return VOLSERILLEGAL_PARTITION;
1730     if (!(partP = VGetPartition(pname, 0))) return VOLSERILLEGAL_PARTITION;
1731     dirp = opendir(VPartitionPath(partP));
1732     if(dirp == NULL) return VOLSERILLEGAL_PARTITION;
1733     strcpy(volname,"");
1734     ttc = (struct volser_trans *) 0;    
1735     tv = (Volume *) 0;                  /* volume not attached */
1736
1737     while(strcmp(volname,"EOD") && !found){/*while there are more volumes in the partition */
1738
1739         if(!strcmp(volname,"")) {/* its not a volume, fetch next file */
1740             GetNextVol(dirp, volname, &volid);
1741             continue; /*back to while loop */
1742         }
1743         
1744         if(volid == volumeId) { /*copy other things too */
1745             found = 1;
1746             IOMGR_Poll(); /*make sure that the client doesnot time out*/
1747             ttc = NewTrans(volid,partid);
1748             if(!ttc){
1749                 pntr->status = VBUSY;
1750                 pntr->volid = volid;
1751                 goto drop;
1752             }
1753             tv = VAttachVolumeByName(&error, pname, volname,V_READONLY);
1754             if(error) {
1755                 pntr->status = 0; /*things are messed up */
1756                 strcpy(pntr->name,volname);
1757                 pntr->volid = volid;
1758                 Log("1 Volser: ListVolumes: Could not attach volume %u (%s:%s), error=%d\n",volid,pname,volname,error);
1759                 goto drop;
1760             }
1761             if(tv->header->diskstuff.destroyMe == DESTROY_ME) {
1762                 /*this volume will be salvaged */
1763                 pntr->status = 0;
1764                 strcpy(pntr->name,volname);
1765                 pntr->volid = volid;
1766                 Log("1 Volser: ListVolumes: Volume %u (%s) will be destroyed on next salvage\n",volid,volname);
1767                 goto drop;
1768             }
1769
1770             if(tv->header->diskstuff.needsSalvaged){
1771                 /*this volume will be salvaged */
1772                 pntr->status = 0;
1773                 strcpy(pntr->name,volname);
1774                 pntr->volid = volid;
1775                 Log("1 Volser: ListVolumes: Volume %u (%s) needs to be salvaged\n",volid,volname);
1776                 goto drop;
1777             }
1778
1779             /*read in the relevant info */
1780             pntr->status = VOK ; /*its ok */
1781             pntr->volid = tv->header->diskstuff.id;
1782             strcpy(pntr->name,tv->header->diskstuff.name);
1783             pntr->type = tv->header->diskstuff.type; /*if ro volume*/
1784             pntr->cloneID = tv->header->diskstuff.cloneId; /*if rw volume*/
1785             pntr->backupID = tv->header->diskstuff.backupId;
1786             pntr->parentID = tv->header->diskstuff.parentId;
1787             pntr->copyDate = tv->header->diskstuff.copyDate;
1788             pntr->inUse = tv->header->diskstuff.inUse;
1789             pntr->size = tv->header->diskstuff.diskused;
1790             pntr->needsSalvaged = tv->header->diskstuff.needsSalvaged;
1791             pntr->destroyMe = tv->header->diskstuff.destroyMe;
1792             pntr->maxquota = tv->header->diskstuff.maxquota;
1793             pntr->filecount = tv->header->diskstuff.filecount;
1794             now = FT_ApproxTime();
1795             if (now - tv->header->diskstuff.dayUseDate > OneDay)
1796                  pntr->dayUse = 0;
1797             else
1798                  pntr->dayUse = tv->header->diskstuff.dayUse;
1799             pntr->creationDate = tv->header->diskstuff.creationDate;
1800             pntr->accessDate = tv->header->diskstuff.accessDate;
1801             pntr->updateDate = tv->header->diskstuff.updateDate;
1802             pntr->backupDate = tv->header->diskstuff.backupDate;
1803             pntr->spare0 = tv->header->diskstuff.minquota;
1804             pntr->spare1 = (long) tv->header->diskstuff.weekUse[0] + (long) tv->header->diskstuff.weekUse[1] +
1805                 (long) tv->header->diskstuff.weekUse[2] + (long) tv->header->diskstuff.weekUse[3] +
1806                 (long) tv->header->diskstuff.weekUse[4] + (long) tv->header->diskstuff.weekUse[5] +
1807                 (long) tv->header->diskstuff.weekUse[6];
1808             pntr->flags = pntr->spare2 = pntr->spare3 = (long) 0;
1809             VDetachVolume(&error,tv);/*free the volume */
1810             tv = (Volume *) 0;
1811             if(error) {
1812                 pntr->status = 0; /*things are messed up */
1813                 strcpy(pntr->name,volname);
1814                 Log("1 Volser: ListVolumes: Could not detach volume %s\n",volname);
1815                 goto drop;
1816             }
1817         }
1818         GetNextVol(dirp, volname, &volid);
1819     }
1820     drop:
1821         if (tv) {
1822             VDetachVolume(&error, tv);
1823             tv = (Volume *) 0;
1824         }
1825         if(ttc) {
1826             DeleteTrans(ttc);
1827             ttc = (struct volser_trans *) 0;
1828         }
1829         
1830     closedir(dirp);
1831     if(found)return 0 ;
1832     else return ENODEV;
1833 }
1834
1835 /*------------------------------------------------------------------------
1836  * EXPORTED SAFSVolXListOneVolume
1837  *
1838  * Description:
1839  *      Returns extended info on volume a_volID on partition a_partID.
1840  *
1841  * Arguments:
1842  *      a_rxCidP       : Pointer to the Rx call we're performing.
1843  *      a_partID       : Partition for which we want the extended list.
1844  *      a_volID        : Volume ID we wish to know about.
1845  *      a_volumeXInfoP : Ptr to the extended info blob.
1846  *
1847  * Returns:
1848  *      0                       Successful operation
1849  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
1850  *
1851  * Environment:
1852  *      Nothing interesting.
1853  *
1854  * Side Effects:
1855  *      As advertised.
1856  *------------------------------------------------------------------------*/
1857
1858 afs_int32 SAFSVolXListOneVolume (a_rxCidP, a_partID, a_volID, a_volumeXInfoP)
1859     struct rx_call *a_rxCidP;
1860     afs_int32 a_partID;
1861     afs_int32 a_volID;
1862     volXEntries *a_volumeXInfoP;
1863 {
1864   afs_int32 code;
1865
1866   code = VolXListOneVolume (a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
1867   osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
1868   return code;
1869 }
1870
1871 afs_int32 VolXListOneVolume (a_rxCidP, a_partID, a_volID, a_volumeXInfoP)
1872     struct rx_call *a_rxCidP;
1873     afs_int32 a_partID;
1874     afs_int32 a_volID;
1875     volXEntries *a_volumeXInfoP;
1876
1877 { /*SAFSVolXListOneVolume*/
1878
1879     volintXInfo *xInfoP;                  /*Ptr to the extended vol info*/
1880     register struct Volume *tv;           /*Volume ptr*/
1881     struct volser_trans *ttc;             /*Volume transaction ptr*/
1882     struct DiskPartition *partP;          /*Ptr to partition */
1883     char pname[9], volname[20];           /*Partition, volume names*/
1884     afs_int32 error;                      /*Error code*/
1885     afs_int32 code;                               /*Return code*/
1886     DIR *dirp;                            /*Partition directory ptr*/
1887     afs_int32 currVolID;                          /*Current volume ID*/
1888     int found = 0;                        /*Did we find the volume we need?*/
1889     struct VolumeDiskData *volDiskDataP;  /*Ptr to on-disk volume data*/
1890     int numStatBytes;                     /*Num stat bytes to copy per volume*/
1891     unsigned int now;
1892
1893     /*
1894      * Set up our pointers for action, marking our structure to hold exactly
1895      * one entry.  Also, assume we'll fail in our quest.
1896      */
1897     a_volumeXInfoP->volXEntries_val = (volintXInfo *) malloc(sizeof(volintXInfo));
1898     xInfoP = a_volumeXInfoP->volXEntries_val;
1899     a_volumeXInfoP->volXEntries_len = 1;
1900     code = ENODEV;
1901
1902     /*
1903      * If the partition name we've been given is bad, bogue out.
1904      */
1905     if (GetPartName(a_partID, pname))
1906         return(VOLSERILLEGAL_PARTITION);
1907
1908     /*
1909      * Open the directory representing the given AFS parttion.  If we can't
1910      * do that, we lose.
1911      */
1912     if (!(partP = VGetPartition(pname, 0))) return VOLSERILLEGAL_PARTITION;
1913     dirp = opendir(VPartitionPath(partP));
1914     if (dirp == NULL)
1915         return(VOLSERILLEGAL_PARTITION);
1916
1917     /*
1918      * Sweep through the partition directory, looking for the desired entry.
1919      * First, of course, figure out how many stat bytes to copy out of each
1920      * volume.
1921      */
1922     numStatBytes = 4*((2*VOLINT_STATS_NUM_RWINFO_FIELDS) +
1923                       (4*VOLINT_STATS_NUM_TIME_FIELDS));
1924     strcpy(volname, "");
1925     ttc = (struct volser_trans *)0;     /*No transaction yet*/
1926     tv = (Volume *)0;                   /*Volume not yet attached*/
1927
1928     while (strcmp(volname,"EOD") && !found) {
1929         /*
1930          * If this is not a volume, move on to the next entry in the
1931          * partition's directory.
1932          */
1933         if (!strcmp(volname,"")) {
1934             GetNextVol(dirp, volname, &currVolID);
1935             continue;
1936         }
1937         
1938         if (currVolID == a_volID) {
1939             /*
1940              * We found the volume entry we're interested.  Pull out the
1941              * extended information, remembering to poll (so that the client
1942              * doesn't time out) and to set up a transaction on the volume.
1943              */
1944             found = 1;
1945             IOMGR_Poll();
1946             ttc = NewTrans(currVolID, a_partID);
1947             if (!ttc) {
1948                 /*
1949                  * Couldn't get a transaction on this volume; let our caller
1950                  * know it's busy.
1951                  */
1952                 xInfoP->status = VBUSY;
1953                 xInfoP->volid = currVolID;
1954                 goto drop;
1955             }
1956
1957             /*
1958              * Attach the volume, give up on the volume if we can't.
1959              */
1960             tv = VAttachVolumeByName(&error, pname, volname, V_READONLY);
1961             if (error) {
1962                 xInfoP->status = 0; /*things are messed up */
1963                 strcpy(xInfoP->name, volname);
1964                 xInfoP->volid = currVolID;
1965                 Log("1 Volser: XListOneVolume: Could not attach volume %u\n",
1966                     currVolID);
1967                 goto drop;
1968             }
1969
1970             /*
1971              * Also bag out on this volume if it's been marked as needing a
1972              * salvage or to-be-destroyed.
1973              */
1974             volDiskDataP = &(tv->header->diskstuff);
1975             if (volDiskDataP->destroyMe == DESTROY_ME) {
1976                 xInfoP->status = 0;
1977                 strcpy(xInfoP->name, volname);
1978                 xInfoP->volid = currVolID;
1979                 Log("1 Volser: XListOneVolume: Volume %u will be destroyed on next salvage\n", currVolID);
1980                 goto drop;
1981             }
1982
1983             if (volDiskDataP->needsSalvaged) {
1984                 xInfoP->status = 0;
1985                 strcpy(xInfoP->name, volname);
1986                 xInfoP->volid = currVolID;
1987                 Log("1 Volser: XListOneVolume: Volume %u needs to be salvaged\n",
1988                     currVolID);
1989                 goto drop;
1990             }
1991
1992             /*
1993              * Pull out the desired info and stuff it into the area we'll be
1994              * returning to our caller.
1995              */
1996             strcpy(xInfoP->name,volDiskDataP->name);
1997             xInfoP->volid        = volDiskDataP->id;
1998             xInfoP->type         = volDiskDataP->type;
1999             xInfoP->backupID     = volDiskDataP->backupId;
2000             xInfoP->parentID     = volDiskDataP->parentId;
2001             xInfoP->cloneID      = volDiskDataP->cloneId;
2002             xInfoP->status       = VOK;
2003             xInfoP->copyDate     = volDiskDataP->copyDate;
2004             xInfoP->inUse        = volDiskDataP->inUse;
2005             xInfoP->creationDate = volDiskDataP->creationDate;
2006             xInfoP->accessDate   = volDiskDataP->accessDate;
2007             xInfoP->updateDate   = volDiskDataP->updateDate;
2008             xInfoP->backupDate   = volDiskDataP->backupDate;
2009             now = FT_ApproxTime();
2010             if (now - volDiskDataP->dayUseDate > OneDay)
2011                xInfoP->dayUse    = 0;
2012             else
2013                xInfoP->dayUse    = volDiskDataP->dayUse;
2014             xInfoP->filecount    = volDiskDataP->filecount;
2015             xInfoP->maxquota     = volDiskDataP->maxquota;
2016             xInfoP->size         = volDiskDataP->diskused;
2017
2018             /*
2019              * Copy out the stat fields in a single operation.
2020              */
2021             memcpy((char *)&(xInfoP->stat_reads[0]), (char *)&(volDiskDataP->stat_reads[0]), numStatBytes);
2022
2023             /*
2024              * We're done copying.  Detach the volume and iterate (at this
2025              * point, since we found our volume, we'll then drop out of the
2026              * loop).
2027              */
2028             VDetachVolume(&error, tv);
2029             tv = (Volume *)0;
2030             if (error) {
2031                 xInfoP->status = 0;
2032                 strcpy(xInfoP->name, volname);
2033                 Log("1 Volser: XListOneVolumes Couldn't detach volume %s\n",
2034                     volname);
2035                 goto drop;
2036             }
2037
2038             /*
2039              * At this point, we're golden.
2040              */
2041             code = 0;
2042         } /*Found desired volume*/
2043         GetNextVol(dirp, volname, &currVolID);
2044     }
2045
2046     /*
2047      * Drop the transaction we have for this volume.
2048      */
2049     drop:
2050         if (tv) {
2051             VDetachVolume(&error, tv);
2052             tv = (Volume *)0;
2053         }
2054         if (ttc) {
2055             DeleteTrans(ttc);
2056             ttc = (struct volser_trans *)0;
2057         }
2058
2059     /*
2060      * Clean up before going to dinner: close the partition directory,
2061      * return the proper value.
2062      */
2063     closedir(dirp);
2064     return(code);
2065
2066 } /*SAFSVolXListOneVolume*/
2067
2068 /*returns all the volumes on partition partid. If flags = 1 then all the 
2069 * relevant info about the volumes  is also returned */
2070 afs_int32 SAFSVolListVolumes (acid, partid, flags, volumeInfo)
2071 struct rx_call *acid;
2072 afs_int32 flags, partid;
2073 volEntries *volumeInfo;
2074 {
2075   afs_int32 code;
2076
2077   code = VolListVolumes (acid, partid, flags, volumeInfo);
2078   osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2079   return code;
2080 }
2081
2082 afs_int32 VolListVolumes (acid, partid, flags, volumeInfo)
2083 struct rx_call *acid;
2084 afs_int32 flags, partid;
2085 volEntries *volumeInfo;
2086 {   volintInfo *pntr;
2087     register struct Volume *tv;
2088     struct DiskPartition *partP;
2089     struct volser_trans *ttc;
2090     afs_int32 allocSize = 1000;/*to be changed to a larger figure */
2091     char pname[9], volname[20];
2092     afs_int32 error = 0;
2093     DIR *dirp;
2094     afs_int32 volid;
2095     unsigned int now;
2096
2097     volumeInfo->volEntries_val = (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2098     pntr = volumeInfo->volEntries_val;
2099     volumeInfo->volEntries_len = 0;
2100     if(GetPartName(partid, pname)) return VOLSERILLEGAL_PARTITION;
2101     if (!(partP = VGetPartition(pname, 0))) return VOLSERILLEGAL_PARTITION;
2102     dirp = opendir(VPartitionPath(partP));
2103     if(dirp == NULL) return VOLSERILLEGAL_PARTITION;
2104     strcpy(volname,"");
2105     while(strcmp(volname,"EOD")){/*while there are more partitions in the partition */
2106         ttc = (struct volser_trans *) 0;        /* new one for each pass */
2107         tv = (Volume *) 0;                      /* volume not attached */
2108
2109         if(!strcmp(volname,"")) {/* its not a volume, fetch next file */
2110             GetNextVol(dirp, volname, &volid);
2111             continue; /*back to while loop */
2112         }
2113         
2114         if(flags) { /*copy other things too */
2115             IOMGR_Poll(); /*make sure that the client doesnot time out*/
2116             ttc = NewTrans(volid,partid);
2117             if(!ttc){
2118                 pntr->status = VBUSY;
2119                 pntr->volid = volid;
2120                 goto drop;
2121             }
2122             tv = VAttachVolumeByName(&error, pname, volname,V_READONLY);
2123             if(error) {
2124                 pntr->status = 0; /*things are messed up */
2125                 strcpy(pntr->name,volname);
2126                 pntr->volid = volid;
2127                 Log("1 Volser: ListVolumes: Could not attach volume %u (%s) error=%d\n",volid,volname,error);
2128                 goto drop;
2129             }
2130             if(tv->header->diskstuff.needsSalvaged){
2131                 /*this volume will be salvaged */
2132                 pntr->status = 0;
2133                 strcpy(pntr->name,volname);
2134                 pntr->volid = volid;
2135                 Log("1 Volser: ListVolumes: Volume %u (%s) needs to be salvaged\n",volid, volname);
2136                 goto drop;
2137             }
2138
2139             if(tv->header->diskstuff.destroyMe == DESTROY_ME) {
2140                 /*this volume will be salvaged */
2141                 goto drop2;
2142             }
2143             /*read in the relevant info */
2144             pntr->status = VOK ; /*its ok */
2145             pntr->volid = tv->header->diskstuff.id;
2146             strcpy(pntr->name,tv->header->diskstuff.name);
2147             pntr->type = tv->header->diskstuff.type; /*if ro volume*/
2148             pntr->cloneID = tv->header->diskstuff.cloneId; /*if rw volume*/
2149             pntr->backupID = tv->header->diskstuff.backupId;
2150             pntr->parentID = tv->header->diskstuff.parentId;
2151             pntr->copyDate = tv->header->diskstuff.copyDate;
2152             pntr->inUse = tv->header->diskstuff.inUse;
2153             pntr->size = tv->header->diskstuff.diskused;
2154             pntr->needsSalvaged = tv->header->diskstuff.needsSalvaged;
2155             pntr->maxquota = tv->header->diskstuff.maxquota;
2156             pntr->filecount = tv->header->diskstuff.filecount;
2157             now = FT_ApproxTime();
2158             if (now - tv->header->diskstuff.dayUseDate > OneDay)
2159                  pntr->dayUse = 0;
2160             else
2161                  pntr->dayUse = tv->header->diskstuff.dayUse;
2162             pntr->creationDate = tv->header->diskstuff.creationDate;
2163             pntr->accessDate = tv->header->diskstuff.accessDate;
2164             pntr->updateDate = tv->header->diskstuff.updateDate;
2165             pntr->backupDate = tv->header->diskstuff.backupDate;
2166             pntr->spare0 = tv->header->diskstuff.minquota;
2167             pntr->spare1 = (long) tv->header->diskstuff.weekUse[0] + (long) tv->header->diskstuff.weekUse[1] +
2168                 (long) tv->header->diskstuff.weekUse[2] + (long) tv->header->diskstuff.weekUse[3] +
2169                 (long) tv->header->diskstuff.weekUse[4] + (long) tv->header->diskstuff.weekUse[5] +
2170                 (long) tv->header->diskstuff.weekUse[6];
2171             pntr->flags = pntr->spare2 = pntr->spare3 = (long) 0;
2172             VDetachVolume(&error,tv);/*free the volume */
2173             tv = (Volume *) 0;
2174             if(error) {
2175                 pntr->status = 0; /*things are messed up */
2176                 strcpy(pntr->name,volname);
2177                 Log("1 Volser: ListVolumes: Could not detach volume %s\n",volname);
2178                 goto drop;
2179             }
2180         }else{
2181             pntr->volid = volid;
2182             /*just volids are needed*/
2183         }
2184
2185       drop:
2186         if(ttc) {
2187             DeleteTrans(ttc);
2188             ttc = (struct volser_trans *) 0;
2189         }
2190         pntr++;
2191         volumeInfo->volEntries_len += 1;
2192         if((allocSize - volumeInfo->volEntries_len) < 5) {
2193             /*running out of space, allocate more space */
2194             allocSize = (allocSize *3)/2;
2195             pntr = (volintInfo *) realloc((char *) volumeInfo->volEntries_val,
2196                                           allocSize * sizeof(volintInfo));
2197             if(pntr == NULL) {
2198                 if (tv) {
2199                     VDetachVolume(&error, tv);
2200                     tv = (Volume *) 0;
2201                 }
2202                 if(ttc) {
2203                     DeleteTrans(ttc);
2204                     ttc = (struct volser_trans *) 0;
2205                 }
2206                 closedir(dirp);
2207                 return VOLSERNO_MEMORY;
2208             }
2209             volumeInfo->volEntries_val = pntr; /* point to new block */
2210             /* set pntr to the right position */
2211             pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2212             
2213         }
2214         
2215       drop2:
2216         if (tv) {
2217             VDetachVolume(&error, tv);
2218             tv = (Volume *) 0;
2219         }
2220         if(ttc) {
2221             DeleteTrans(ttc);
2222             ttc = (struct volser_trans *) 0;
2223         }
2224         GetNextVol(dirp, volname, &volid);
2225         
2226     }
2227     closedir(dirp);
2228     if (ttc)
2229         DeleteTrans(ttc);
2230     
2231     return 0 ;
2232 }
2233
2234 /*------------------------------------------------------------------------
2235  * EXPORTED SAFSVolXListVolumes
2236  *
2237  * Description:
2238  *      Returns all the volumes on partition a_partID.  If a_flags
2239  *      is set to 1, then all the relevant extended volume information
2240  *      is also returned.
2241  *
2242  * Arguments:
2243  *      a_rxCidP       : Pointer to the Rx call we're performing.
2244  *      a_partID       : Partition for which we want the extended list.
2245  *      a_flags        : Various flags.
2246  *      a_volumeXInfoP : Ptr to the extended info blob.
2247  *
2248  * Returns:
2249  *      0                       Successful operation
2250  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2251  *      VOLSERNO_MEMORY         if we ran out of memory allocating
2252  *                              our return blob
2253  *
2254  * Environment:
2255  *      Nothing interesting.
2256  *
2257  * Side Effects:
2258  *      As advertised.
2259  *------------------------------------------------------------------------*/
2260
2261 afs_int32 SAFSVolXListVolumes (a_rxCidP, a_partID, a_flags, a_volumeXInfoP)
2262     struct rx_call *a_rxCidP;
2263     afs_int32 a_partID;
2264     afs_int32 a_flags;
2265     volXEntries *a_volumeXInfoP;
2266 {
2267   afs_int32 code;
2268
2269   code = VolXListVolumes (a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2270   osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2271   return code;
2272 }
2273
2274 afs_int32 VolXListVolumes (a_rxCidP, a_partID, a_flags, a_volumeXInfoP)
2275     struct rx_call *a_rxCidP;
2276     afs_int32 a_partID;
2277     afs_int32 a_flags;
2278     volXEntries *a_volumeXInfoP;
2279
2280 { /*SAFSVolXListVolumes*/
2281
2282     volintXInfo *xInfoP;                  /*Ptr to the extended vol info*/
2283     register struct Volume *tv;           /*Volume ptr*/
2284     struct DiskPartition *partP;          /*Ptr to partition*/
2285     struct volser_trans *ttc;             /*Volume transaction ptr*/
2286     afs_int32 allocSize = 1000;           /*To be changed to a larger figure */
2287     char pname[9], volname[20];           /*Partition, volume names*/
2288     afs_int32 error = 0;                          /*Return code*/
2289     DIR *dirp;                            /*Partition directory ptr*/
2290     afs_int32 volid;                              /*Current volume ID*/
2291     struct VolumeDiskData *volDiskDataP;  /*Ptr to on-disk volume data*/
2292     int numStatBytes;                     /*Num stat bytes to copy per volume*/
2293     unsigned int now;
2294
2295     /*
2296      * Allocate a large array of extended volume info structures, then
2297      * set it up for action.
2298      */
2299     a_volumeXInfoP->volXEntries_val =
2300         (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2301     xInfoP = a_volumeXInfoP->volXEntries_val;
2302     a_volumeXInfoP->volXEntries_len = 0;
2303
2304     /*
2305      * If the partition name we've been given is bad, bogue out.
2306      */
2307     if (GetPartName(a_partID, pname))
2308         return(VOLSERILLEGAL_PARTITION);
2309
2310     /*
2311      * Open the directory representing the given AFS parttion.  If we can't
2312      * do that, we lose.
2313      */
2314     if (!(partP = VGetPartition(pname, 0))) return VOLSERILLEGAL_PARTITION;
2315     dirp = opendir(VPartitionPath(partP));
2316     if (dirp == NULL)
2317         return (VOLSERILLEGAL_PARTITION);
2318
2319     /*
2320      * Sweep through the partition directory, acting on each entry.  First,
2321      * of course, figure out how many stat bytes to copy out of each volume.
2322      */
2323     numStatBytes = 4*((2*VOLINT_STATS_NUM_RWINFO_FIELDS) +
2324                       (4*VOLINT_STATS_NUM_TIME_FIELDS));
2325     strcpy(volname,"");
2326     while (strcmp(volname, "EOD")) {
2327         ttc = (struct volser_trans *)0; /*New one for each pass*/
2328         tv = (Volume *)0;               /*Volume not yet attached*/
2329
2330         /*
2331          * If this is not a volume, move on to the next entry in the
2332          * partition's directory.
2333          */
2334         if(!strcmp(volname,"")) {
2335             GetNextVol(dirp, volname, &volid);
2336             continue;
2337         }
2338
2339         if (a_flags) {
2340             /*
2341              * Full info about the volume desired.  Poll to make sure the
2342              * client doesn't time out, then start up a new transaction.
2343              */
2344             IOMGR_Poll();
2345             ttc = NewTrans(volid,a_partID);
2346             if (!ttc) {
2347                 /*
2348                  * Couldn't get a transaction on this volume; let our caller
2349                  * know it's busy.
2350                  */
2351                 xInfoP->status = VBUSY;
2352                 xInfoP->volid = volid;
2353                 goto drop;
2354             }
2355
2356             /*
2357              * Attach the volume, give up on this volume if we can't.
2358              */
2359             tv = VAttachVolumeByName(&error, pname, volname, V_READONLY);
2360             if (error) {
2361                 xInfoP->status = 0; /*things are messed up */
2362                 strcpy(xInfoP->name, volname);
2363                 xInfoP->volid = volid;
2364                 Log("1 Volser: XListVolumes: Could not attach volume %u\n",
2365                     volid);
2366                 goto drop;
2367             }
2368
2369             /*
2370              * Also bag out on this volume if it's been marked as needing a
2371              * salvage or to-be-destroyed.
2372              */
2373             volDiskDataP = &(tv->header->diskstuff);
2374             if (volDiskDataP->needsSalvaged) {
2375                 xInfoP->status = 0;
2376                 strcpy(xInfoP->name, volname);
2377                 xInfoP->volid = volid;
2378                 Log("1 Volser: XListVolumes: Volume %u needs to be salvaged\n",
2379                     volid);
2380                 goto drop;
2381             }
2382
2383             if (volDiskDataP->destroyMe == DESTROY_ME)
2384                 goto drop2;
2385
2386             /*
2387              * Pull out the desired info and stuff it into the area we'll be
2388              * returning to our caller.
2389              */
2390             strcpy(xInfoP->name,volDiskDataP->name);
2391             xInfoP->volid        = volDiskDataP->id;
2392             xInfoP->type         = volDiskDataP->type;
2393             xInfoP->backupID     = volDiskDataP->backupId;
2394             xInfoP->parentID     = volDiskDataP->parentId;
2395             xInfoP->cloneID      = volDiskDataP->cloneId;
2396             xInfoP->status       = VOK;
2397             xInfoP->copyDate     = volDiskDataP->copyDate;
2398             xInfoP->inUse        = volDiskDataP->inUse;
2399             xInfoP->creationDate = volDiskDataP->creationDate;
2400             xInfoP->accessDate   = volDiskDataP->accessDate;
2401             xInfoP->updateDate   = volDiskDataP->updateDate;
2402             xInfoP->backupDate   = volDiskDataP->backupDate;
2403             now = FT_ApproxTime();
2404             if (now - volDiskDataP->dayUseDate > OneDay)
2405                xInfoP->dayUse    = 0;
2406             else
2407                xInfoP->dayUse    = volDiskDataP->dayUse;
2408             xInfoP->filecount    = volDiskDataP->filecount;
2409             xInfoP->maxquota     = volDiskDataP->maxquota;
2410             xInfoP->size         = volDiskDataP->diskused;
2411
2412             /*
2413              * Copy out the stat fields in a single operation.
2414              */
2415             memcpy((char *)&(xInfoP->stat_reads[0]), (char *)&(volDiskDataP->stat_reads[0]), numStatBytes);
2416
2417             /*
2418              * We're done copying.  Detach the volume and iterate.
2419              */
2420             VDetachVolume(&error, tv);
2421             tv = (Volume *) 0;
2422             if (error) {
2423                 xInfoP->status = 0;
2424                 strcpy(xInfoP->name, volname);
2425                 Log("1 Volser: XListVolumes: Could not detach volume %s\n",
2426                     volname);
2427                 goto drop;
2428             }
2429         } /*Full contents desired*/
2430         else
2431             /*
2432              * Just volume IDs are needed.
2433              */
2434             xInfoP->volid = volid;
2435
2436       drop:
2437         /*
2438          * Drop the transaction we have for this volume.
2439          */
2440         if(ttc) {
2441             DeleteTrans(ttc);
2442             ttc = (struct volser_trans *) 0;
2443         }
2444
2445         /*
2446          * Bump the pointer in the data area we're building, along with
2447          * the count of the number of entries it contains.
2448          */
2449         xInfoP++;
2450         (a_volumeXInfoP->volXEntries_len)++;
2451         if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2452             /*
2453              * We're running out of space in the area we've built.  Grow it.
2454              */
2455             allocSize = (allocSize * 3)/2;
2456             xInfoP = (volintXInfo *)
2457                 realloc((char *) a_volumeXInfoP->volXEntries_val,
2458                         (allocSize * sizeof(volintXInfo)));
2459             if (xInfoP == NULL) {
2460                 /*
2461                  * Bummer, no memory. Bag it, tell our caller what went wrong.
2462                  */
2463                 if (tv) {
2464                     VDetachVolume(&error, tv);
2465                     tv = (Volume *) 0;
2466                 }
2467                 if (ttc) {
2468                     DeleteTrans(ttc);
2469                     ttc = (struct volser_trans *) 0;
2470                 }
2471                 closedir(dirp);
2472                 return(VOLSERNO_MEMORY);
2473             }
2474
2475             /*
2476              * Memory reallocation worked.  Correct our pointers so they
2477              * now point to the new block and the current open position within
2478              * the new block.
2479              */
2480             a_volumeXInfoP->volXEntries_val = xInfoP;
2481             xInfoP = a_volumeXInfoP->volXEntries_val +
2482                      a_volumeXInfoP->volXEntries_len;
2483         } /*Need more space*/
2484
2485       drop2:
2486         /*
2487          * Detach our current volume and the transaction on it, then move on
2488          * to the next volume in the partition directory.
2489          */
2490         if (tv) {
2491             VDetachVolume(&error, tv);
2492             tv = (Volume *) 0;
2493         }
2494         if (ttc) {
2495             DeleteTrans(ttc);
2496             ttc = (struct volser_trans *) 0;
2497         }
2498         GetNextVol(dirp, volname, &volid);
2499     } /*Sweep through the partition directory*/
2500
2501     /*
2502      * We've examined all entries in the partition directory.  Close it,
2503      * delete our transaction (if any), and go home happy.
2504      */
2505     closedir(dirp);
2506     if (ttc)
2507         DeleteTrans(ttc);
2508     return(0);
2509
2510 } /*SAFSVolXListVolumes*/
2511
2512 /*this call is used to monitor the status of volser for debugging purposes.
2513  *information about all the active transactions is returned in transInfo*/
2514 afs_int32 SAFSVolMonitor (acid,transInfo)
2515   struct rx_call *acid;
2516   transDebugEntries *transInfo;
2517 {
2518   afs_int32 code;
2519
2520   code = VolMonitor (acid,transInfo);
2521   osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2522   return code;
2523 }
2524
2525 afs_int32 VolMonitor (acid,transInfo)
2526      struct rx_call *acid;
2527      transDebugEntries *transInfo;
2528 {
2529     transDebugInfo *pntr;
2530     afs_int32 allocSize = 50;
2531     struct volser_trans *tt, *allTrans;
2532
2533     transInfo->transDebugEntries_val = (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2534     pntr = transInfo->transDebugEntries_val;
2535     transInfo->transDebugEntries_len = 0;
2536     allTrans = TransList();
2537     if(allTrans == (struct volser_trans *)0) return 0;/*no active transactions */
2538     for(tt=allTrans;tt;tt=tt->next){/*copy relevant info into pntr */
2539         pntr->tid = tt->tid;
2540         pntr->time = tt->time;
2541         pntr->creationTime = tt->creationTime;
2542         pntr->returnCode = tt->returnCode;
2543         pntr->volid = tt->volid;
2544         pntr->partition = tt->partition;
2545         pntr->iflags = tt->iflags;
2546         pntr->vflags = tt->vflags;
2547         pntr->tflags = tt->tflags;
2548         strcpy(pntr->lastProcName,tt->lastProcName);
2549         pntr->callValid = 0;
2550         if(tt->rxCallPtr) { /*record call related info */
2551             pntr->callValid = 1;
2552             pntr->readNext = tt->rxCallPtr->rnext;
2553             pntr->transmitNext = tt->rxCallPtr->tnext;
2554             pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2555             pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2556         }
2557         pntr++;
2558         transInfo->transDebugEntries_len += 1;
2559         if((allocSize - transInfo->transDebugEntries_len) < 5) {/*alloc some more space */
2560             allocSize = (allocSize *3)/2;
2561             pntr  = (transDebugInfo *) realloc((char *) transInfo->transDebugEntries_val,allocSize * sizeof(transDebugInfo));
2562             transInfo->transDebugEntries_val = pntr;
2563             pntr = transInfo->transDebugEntries_val + transInfo->transDebugEntries_len;
2564             /*set pntr to right position*/
2565         }
2566             
2567     }
2568     
2569     return 0;
2570 }
2571
2572 afs_int32 SAFSVolSetIdsTypes (acid,atid,name, type, pId, cloneId, backupId)
2573   struct rx_call *acid;
2574   afs_int32 type, pId, cloneId, backupId, atid;
2575   char name[];
2576 {
2577   afs_int32 code;
2578
2579   code = VolSetIdsTypes (acid,atid,name, type, pId, cloneId, backupId);
2580   osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, 
2581                                           AUD_STR,  name,
2582                                           AUD_STR,  type,
2583                                           AUD_LONG, pId,
2584                                           AUD_LONG, cloneId, 
2585                                           AUD_LONG, backupId, AUD_END);
2586   return code;
2587 }
2588
2589 afs_int32 VolSetIdsTypes (acid,atid,name, type, pId, cloneId, backupId)
2590      struct rx_call *acid;
2591      afs_int32 type, pId, cloneId, backupId, atid;
2592      char name[];
2593 {
2594     struct Volume *tv;
2595     afs_int32 error = 0;
2596     register struct volser_trans *tt; 
2597     char caller[MAXKTCNAMELEN];
2598
2599     if (strlen(name)>31) return VOLSERBADNAME;
2600     if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/
2601     /* find the trans */
2602     tt = FindTrans(atid);
2603     if (!tt) return ENOENT;
2604     if (tt->vflags & VTDeleted) {
2605         Log("1 Volser: VolSetIds: volume %u has been deleted \n",tt->volid);
2606         TRELE(tt);
2607         return ENOENT;
2608     }
2609     strcpy(tt->lastProcName,"SetIdsTypes");
2610     tt->rxCallPtr = acid;
2611     tv = tt->volume;
2612    
2613     V_type(tv) = type;
2614     V_backupId(tv) = backupId;
2615     V_cloneId(tv) = cloneId;
2616     V_parentId(tv) = pId;
2617     strcpy((&V_disk(tv))->name,name);
2618     VUpdateVolume(&error, tv);
2619     if (error) {
2620          Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2621          LogError(error);
2622         goto fail;
2623     }
2624     tt->rxCallPtr = (struct rx_call *)0;
2625     if(TRELE(tt) && !error) return VOLSERTRELE_ERROR;
2626     
2627     return error;
2628 fail:
2629     tt->rxCallPtr = (struct rx_call *)0;
2630     if(TRELE(tt) && !error) return VOLSERTRELE_ERROR;
2631     return error;
2632 }
2633
2634 afs_int32 SAFSVolSetDate (acid,atid,cdate)
2635      struct rx_call *acid;
2636      afs_int32 atid, cdate;
2637 {
2638   afs_int32 code;
2639
2640   code = VolSetDate (acid,atid,cdate);
2641   osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate, AUD_END);
2642   return code;
2643 }
2644
2645 afs_int32 VolSetDate (acid,atid,cdate)
2646      struct rx_call *acid;
2647      afs_int32 atid, cdate;
2648 {
2649     struct Volume *tv;
2650     afs_int32 error = 0;
2651     register struct volser_trans *tt; 
2652     char caller[MAXKTCNAMELEN];
2653
2654     if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/
2655     /* find the trans */
2656     tt = FindTrans(atid);
2657     if (!tt) return ENOENT;
2658     if (tt->vflags & VTDeleted) {
2659         Log("1 Volser: VolSetDate: volume %u has been deleted \n",tt->volid);
2660         TRELE(tt);
2661         return ENOENT;
2662     }
2663     strcpy(tt->lastProcName,"SetDate");
2664     tt->rxCallPtr = acid;
2665     tv = tt->volume;
2666    
2667     V_creationDate(tv) = cdate;   
2668     VUpdateVolume(&error, tv);
2669     if (error) {
2670          Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2671          LogError(error);
2672         goto fail;
2673     }
2674     tt->rxCallPtr = (struct rx_call *)0;
2675     if(TRELE(tt) && !error) return VOLSERTRELE_ERROR;
2676     
2677     return error;
2678 fail:
2679     tt->rxCallPtr = (struct rx_call *)0;
2680     if(TRELE(tt) && !error) return VOLSERTRELE_ERROR;
2681     return error;
2682 }
2683
2684 /* GetPartName - map partid (a decimal number) into pname (a string)
2685  * Since for NT we actually want to return the drive name, we map through the
2686  * partition struct.
2687  */
2688 static int GetPartName(afs_int32 partid, char *pname)
2689 {   
2690     if (partid < 0)
2691         return -1;
2692     if(partid < 26) {
2693         strcpy(pname,"/vicep");
2694         pname[6] = 'a' + partid;
2695         pname[7] = '\0';
2696         return 0;
2697     } else if (partid < VOLMAXPARTS) {
2698         strcpy(pname,"/vicep");
2699         partid -= 26;
2700         pname[6] = 'a' + (partid / 26);
2701         pname[7] = 'a' + (partid % 26);
2702         pname[8] = '\0';
2703         return 0;
2704     }
2705     else return -1;
2706 }