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