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