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