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