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