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