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