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