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