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