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