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