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