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