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