4c01848ae78c4541fd409df7bb744dfcbf7b7bb2
[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     volint_info_handle_t handle;
2432
2433     /*
2434      * Set up our pointers for action, marking our structure to hold exactly
2435      * one entry.  Also, assume we'll fail in our quest.
2436      */
2437     a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2438     if (!a_volumeXInfoP->volXEntries_val)
2439         return ENOMEM;
2440
2441     a_volumeXInfoP->volXEntries_len = 1;
2442
2443     /*
2444      * If the partition name we've been given is bad, bogue out.
2445      */
2446     if (GetPartName(a_partID, pname))
2447         return (VOLSERILLEGAL_PARTITION);
2448
2449     /*
2450      * Open the directory representing the given AFS parttion.  If we can't
2451      * do that, we lose.
2452      */
2453     if (!(partP = VGetPartition(pname, 0)))
2454         return VOLSERILLEGAL_PARTITION;
2455     dirp = opendir(VPartitionPath(partP));
2456     if (dirp == NULL)
2457         return (VOLSERILLEGAL_PARTITION);
2458
2459
2460     /*
2461      * Sweep through the partition directory, looking for the desired entry.
2462      * First, of course, figure out how many stat bytes to copy out of each
2463      * volume.
2464      */
2465     while (GetNextVol(dirp, volname, &currVolID)) {
2466         if (currVolID == a_volID) {
2467             /*
2468              * We found the volume entry we're interested.  Pull out the
2469              * extended information, remembering to poll (so that the client
2470              * doesn't time out) and to set up a transaction on the volume.
2471              */
2472             found = 1;
2473             break;
2474         }                       /*Found desired volume */
2475     }
2476
2477     if (found) {
2478 #ifndef AFS_PTHREAD_ENV
2479         IOMGR_Poll();
2480 #endif
2481
2482         handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2483         handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2484
2485         /* The return code from GetVolInfo is ignored; there is no error from
2486          * it that results in the whole call being aborted. Any volume
2487          * attachment failures are reported in 'status' field in the
2488          * volumeInfo payload. */
2489         GetVolInfo(a_partID,
2490                    a_volID,
2491                    pname,
2492                    volname,
2493                    &handle,
2494                    VOL_INFO_LIST_SINGLE);
2495     }
2496
2497     /*
2498      * Clean up before going to dinner: close the partition directory,
2499      * return the proper value.
2500      */
2501     closedir(dirp);
2502     return (found) ? 0 : ENODEV;
2503 }                               /*SAFSVolXListOneVolume */
2504
2505 /*returns all the volumes on partition partid. If flags = 1 then all the
2506 * relevant info about the volumes  is also returned */
2507 afs_int32
2508 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2509                    volEntries *volumeInfo)
2510 {
2511     afs_int32 code;
2512
2513     code = VolListVolumes(acid, partid, flags, volumeInfo);
2514     osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2515     return code;
2516 }
2517
2518 static afs_int32
2519 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2520                    volEntries *volumeInfo)
2521 {
2522     volintInfo *pntr;
2523     struct DiskPartition64 *partP;
2524     afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2525     char pname[9], volname[20];
2526     DIR *dirp;
2527     VolumeId volid;
2528     int code;
2529     volint_info_handle_t handle;
2530
2531     volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2532     if (!volumeInfo->volEntries_val)
2533         return ENOMEM;
2534
2535     pntr = volumeInfo->volEntries_val;
2536     volumeInfo->volEntries_len = 0;
2537     if (GetPartName(partid, pname))
2538         return VOLSERILLEGAL_PARTITION;
2539     if (!(partP = VGetPartition(pname, 0)))
2540         return VOLSERILLEGAL_PARTITION;
2541     dirp = opendir(VPartitionPath(partP));
2542     if (dirp == NULL)
2543         return VOLSERILLEGAL_PARTITION;
2544
2545     while (GetNextVol(dirp, volname, &volid)) {
2546         if (flags) {            /*copy other things too */
2547 #ifndef AFS_PTHREAD_ENV
2548             IOMGR_Poll();       /*make sure that the client does not time out */
2549 #endif
2550
2551             handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2552             handle.volinfo_ptr.base = pntr;
2553
2554
2555             code = GetVolInfo(partid,
2556                               volid,
2557                               pname,
2558                               volname,
2559                               &handle,
2560                               VOL_INFO_LIST_MULTIPLE);
2561             if (code == -2)     /* DESTROY_ME flag set */
2562                 continue;
2563         } else {
2564             pntr->volid = volid;
2565             /*just volids are needed */
2566         }
2567
2568         pntr++;
2569         volumeInfo->volEntries_len += 1;
2570         if ((allocSize - volumeInfo->volEntries_len) < 5) {
2571             /*running out of space, allocate more space */
2572             allocSize = (allocSize * 3) / 2;
2573             pntr = realloc(volumeInfo->volEntries_val,
2574                            allocSize * sizeof(volintInfo));
2575             if (pntr == NULL) {
2576                 closedir(dirp);
2577                 return VOLSERNO_MEMORY;
2578             }
2579             volumeInfo->volEntries_val = pntr;  /* point to new block */
2580             /* set pntr to the right position */
2581             pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2582         }
2583     }
2584
2585     closedir(dirp);
2586     return 0;
2587 }
2588
2589 /*------------------------------------------------------------------------
2590  * EXPORTED SAFSVolXListVolumes
2591  *
2592  * Description:
2593  *      Returns all the volumes on partition a_partID.  If a_flags
2594  *      is set to 1, then all the relevant extended volume information
2595  *      is also returned.
2596  *
2597  * Arguments:
2598  *      a_rxCidP       : Pointer to the Rx call we're performing.
2599  *      a_partID       : Partition for which we want the extended list.
2600  *      a_flags        : Various flags.
2601  *      a_volumeXInfoP : Ptr to the extended info blob.
2602  *
2603  * Returns:
2604  *      0                       Successful operation
2605  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2606  *      VOLSERNO_MEMORY         if we ran out of memory allocating
2607  *                              our return blob
2608  *
2609  * Environment:
2610  *      Nothing interesting.
2611  *
2612  * Side Effects:
2613  *      As advertised.
2614  *------------------------------------------------------------------------*/
2615
2616 afs_int32
2617 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2618                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2619 {
2620     afs_int32 code;
2621
2622     code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2623     osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2624     return code;
2625 }
2626
2627 static afs_int32
2628 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2629                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2630 {                               /*SAFSVolXListVolumes */
2631
2632     volintXInfo *xInfoP;        /*Ptr to the extended vol info */
2633     struct DiskPartition64 *partP;      /*Ptr to partition */
2634     afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2635     char pname[9], volname[20]; /*Partition, volume names */
2636     DIR *dirp;                  /*Partition directory ptr */
2637     VolumeId volid;             /*Current volume ID */
2638     int code;
2639     volint_info_handle_t handle;
2640
2641     /*
2642      * Allocate a large array of extended volume info structures, then
2643      * set it up for action.
2644      */
2645     a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2646     if (!a_volumeXInfoP->volXEntries_val)
2647         return ENOMEM;
2648
2649     xInfoP = a_volumeXInfoP->volXEntries_val;
2650     a_volumeXInfoP->volXEntries_len = 0;
2651
2652     /*
2653      * If the partition name we've been given is bad, bogue out.
2654      */
2655     if (GetPartName(a_partID, pname))
2656         return (VOLSERILLEGAL_PARTITION);
2657
2658     /*
2659      * Open the directory representing the given AFS parttion.  If we can't
2660      * do that, we lose.
2661      */
2662     if (!(partP = VGetPartition(pname, 0)))
2663         return VOLSERILLEGAL_PARTITION;
2664     dirp = opendir(VPartitionPath(partP));
2665     if (dirp == NULL)
2666         return (VOLSERILLEGAL_PARTITION);
2667     while (GetNextVol(dirp, volname, &volid)) {
2668         if (a_flags) {
2669             /*
2670              * Full info about the volume desired.  Poll to make sure the
2671              * client doesn't time out, then start up a new transaction.
2672              */
2673 #ifndef AFS_PTHREAD_ENV
2674             IOMGR_Poll();
2675 #endif
2676
2677             handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2678             handle.volinfo_ptr.ext = xInfoP;
2679
2680             code = GetVolInfo(a_partID,
2681                               volid,
2682                               pname,
2683                               volname,
2684                               &handle,
2685                               VOL_INFO_LIST_MULTIPLE);
2686             if (code == -2)     /* DESTROY_ME flag set */
2687                 continue;
2688         } else {
2689             /*
2690              * Just volume IDs are needed.
2691              */
2692             xInfoP->volid = volid;
2693         }
2694
2695         /*
2696          * Bump the pointer in the data area we're building, along with
2697          * the count of the number of entries it contains.
2698          */
2699         xInfoP++;
2700         (a_volumeXInfoP->volXEntries_len)++;
2701         if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2702             /*
2703              * We're running out of space in the area we've built.  Grow it.
2704              */
2705             allocSize = (allocSize * 3) / 2;
2706             xInfoP = (volintXInfo *)
2707                 realloc((char *)a_volumeXInfoP->volXEntries_val,
2708                         (allocSize * sizeof(volintXInfo)));
2709             if (xInfoP == NULL) {
2710                 /*
2711                  * Bummer, no memory. Bag it, tell our caller what went wrong.
2712                  */
2713                 closedir(dirp);
2714                 return (VOLSERNO_MEMORY);
2715             }
2716
2717             /*
2718              * Memory reallocation worked.  Correct our pointers so they
2719              * now point to the new block and the current open position within
2720              * the new block.
2721              */
2722             a_volumeXInfoP->volXEntries_val = xInfoP;
2723             xInfoP =
2724                 a_volumeXInfoP->volXEntries_val +
2725                 a_volumeXInfoP->volXEntries_len;
2726         }
2727     }
2728
2729     /*
2730      * We've examined all entries in the partition directory.  Close it,
2731      * delete our transaction (if any), and go home happy.
2732      */
2733     closedir(dirp);
2734     return (0);
2735
2736 }                               /*SAFSVolXListVolumes */
2737
2738 /*this call is used to monitor the status of volser for debugging purposes.
2739  *information about all the active transactions is returned in transInfo*/
2740 afs_int32
2741 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2742 {
2743     afs_int32 code;
2744
2745     code = VolMonitor(acid, transInfo);
2746     osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2747     return code;
2748 }
2749
2750 static afs_int32
2751 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2752 {
2753     transDebugInfo *pntr;
2754     afs_int32 allocSize = 50;
2755     struct volser_trans *tt, *nt, *allTrans;
2756
2757     transInfo->transDebugEntries_val =
2758         malloc(allocSize * sizeof(transDebugInfo));
2759     if (!transInfo->transDebugEntries_val)
2760         return ENOMEM;
2761     pntr = transInfo->transDebugEntries_val;
2762     transInfo->transDebugEntries_len = 0;
2763
2764     VTRANS_LOCK;
2765     allTrans = TransList();
2766     if (allTrans == (struct volser_trans *)0)
2767         goto done;              /*no active transactions */
2768     for (tt = allTrans; tt; tt = nt) {  /*copy relevant info into pntr */
2769         nt = tt->next;
2770         VTRANS_OBJ_LOCK(tt);
2771         pntr->tid = tt->tid;
2772         pntr->time = tt->time;
2773         pntr->creationTime = tt->creationTime;
2774         pntr->returnCode = tt->returnCode;
2775         pntr->volid = tt->volid;
2776         pntr->partition = tt->partition;
2777         pntr->iflags = tt->iflags;
2778         pntr->vflags = tt->vflags;
2779         pntr->tflags = tt->tflags;
2780         strcpy(pntr->lastProcName, tt->lastProcName);
2781         pntr->callValid = 0;
2782         if (tt->rxCallPtr) {    /*record call related info */
2783             pntr->callValid = 1;
2784 #if 0
2785             pntr->readNext = tt->rxCallPtr->rnext;
2786             pntr->transmitNext = tt->rxCallPtr->tnext;
2787             pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2788             pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2789 #endif
2790         }
2791         VTRANS_OBJ_UNLOCK(tt);
2792         pntr++;
2793         transInfo->transDebugEntries_len += 1;
2794         if ((allocSize - transInfo->transDebugEntries_len) < 5) {       /*alloc some more space */
2795             allocSize = (allocSize * 3) / 2;
2796             pntr = realloc(transInfo->transDebugEntries_val,
2797                            allocSize * sizeof(transDebugInfo));
2798             transInfo->transDebugEntries_val = pntr;
2799             pntr =
2800                 transInfo->transDebugEntries_val +
2801                 transInfo->transDebugEntries_len;
2802             /*set pntr to right position */
2803         }
2804
2805     }
2806 done:
2807     VTRANS_UNLOCK;
2808
2809     return 0;
2810 }
2811
2812 afs_int32
2813 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2814                    afs_int32 type, afs_uint32 pId, VolumeId cloneId,
2815                    VolumeId backupId)
2816 {
2817     afs_int32 code;
2818
2819     code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2820     osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2821                AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2822                backupId, AUD_END);
2823     return code;
2824 }
2825
2826 static afs_int32
2827 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2828                afs_int32 type, VolumeId pId, VolumeId cloneId,
2829                VolumeId backupId)
2830 {
2831     struct Volume *tv;
2832     Error error = 0;
2833     struct volser_trans *tt;
2834     char caller[MAXKTCNAMELEN];
2835
2836     if (strlen(name) > 31)
2837         return VOLSERBADNAME;
2838     if (!afsconf_SuperUser(tdir, acid, caller))
2839         return VOLSERBAD_ACCESS;        /*not a super user */
2840     /* find the trans */
2841     tt = FindTrans(atid);
2842     if (!tt)
2843         return ENOENT;
2844     if (tt->vflags & VTDeleted) {
2845         Log("1 Volser: VolSetIds: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2846         TRELE(tt);
2847         return ENOENT;
2848     }
2849     TSetRxCall(tt, acid, "SetIdsTypes");
2850     tv = tt->volume;
2851
2852     V_type(tv) = type;
2853     V_backupId(tv) = backupId;
2854     V_cloneId(tv) = cloneId;
2855     V_parentId(tv) = pId;
2856     strcpy((&V_disk(tv))->name, name);
2857     VUpdateVolume(&error, tv);
2858     if (error) {
2859         Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2860         LogError(error);
2861         goto fail;
2862     }
2863     TClearRxCall(tt);
2864     if (TRELE(tt) && !error)
2865         return VOLSERTRELE_ERROR;
2866
2867     return error;
2868   fail:
2869     TClearRxCall(tt);
2870     if (TRELE(tt) && !error)
2871         return VOLSERTRELE_ERROR;
2872     return error;
2873 }
2874
2875 afs_int32
2876 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2877 {
2878     afs_int32 code;
2879
2880     code = VolSetDate(acid, atid, cdate);
2881     osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2882                AUD_END);
2883     return code;
2884 }
2885
2886 static afs_int32
2887 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2888 {
2889     struct Volume *tv;
2890     Error error = 0;
2891     struct volser_trans *tt;
2892     char caller[MAXKTCNAMELEN];
2893
2894     if (!afsconf_SuperUser(tdir, acid, caller))
2895         return VOLSERBAD_ACCESS;        /*not a super user */
2896     /* find the trans */
2897     tt = FindTrans(atid);
2898     if (!tt)
2899         return ENOENT;
2900     if (tt->vflags & VTDeleted) {
2901         Log("1 Volser: VolSetDate: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2902         TRELE(tt);
2903         return ENOENT;
2904     }
2905     TSetRxCall(tt, acid, "SetDate");
2906     tv = tt->volume;
2907
2908     V_creationDate(tv) = cdate;
2909     VUpdateVolume(&error, tv);
2910     if (error) {
2911         Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2912         LogError(error);
2913         goto fail;
2914     }
2915     TClearRxCall(tt);
2916     if (TRELE(tt) && !error)
2917         return VOLSERTRELE_ERROR;
2918
2919     return error;
2920   fail:
2921     TClearRxCall(tt);
2922     if (TRELE(tt) && !error)
2923         return VOLSERTRELE_ERROR;
2924     return error;
2925 }
2926
2927 afs_int32
2928 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2929                            VolumeId volumeId)
2930 {
2931 #ifdef AFS_NT40_ENV
2932     return EXDEV;
2933 #else
2934     char caller[MAXKTCNAMELEN];
2935     DIR *dirp;
2936     struct volser_trans *ttc;
2937     char pname[16], volname[20];
2938     struct DiskPartition64 *partP;
2939     afs_int32 ret = ENODEV;
2940     VolumeId volid;
2941
2942     if (!afsconf_SuperUser(tdir, acid, caller))
2943         return VOLSERBAD_ACCESS;        /*not a super user */
2944     if (GetPartName(partId, pname))
2945         return VOLSERILLEGAL_PARTITION;
2946     if (!(partP = VGetPartition(pname, 0)))
2947         return VOLSERILLEGAL_PARTITION;
2948     dirp = opendir(VPartitionPath(partP));
2949     if (dirp == NULL)
2950         return VOLSERILLEGAL_PARTITION;
2951     ttc = (struct volser_trans *)0;
2952
2953     while (GetNextVol(dirp, volname, &volid)) {
2954         if (volid == volumeId) {        /*copy other things too */
2955 #ifndef AFS_PTHREAD_ENV
2956             IOMGR_Poll();       /*make sure that the client doesnot time out */
2957 #endif
2958             ttc = NewTrans(volumeId, partId);
2959             if (!ttc) {
2960                 return VOLSERVOLBUSY;
2961             }
2962 #ifdef AFS_NAMEI_ENV
2963             ret = namei_ConvertROtoRWvolume(pname, volumeId);
2964 #else
2965             ret = inode_ConvertROtoRWvolume(pname, volumeId);
2966 #endif
2967             break;
2968         }
2969     }
2970
2971     if (ttc)
2972         DeleteTrans(ttc, 1);
2973
2974     closedir(dirp);
2975     return ret;
2976 #endif
2977 }
2978
2979 afs_int32
2980 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
2981                struct volintSize *size)
2982 {
2983     int code = 0;
2984     struct volser_trans *tt;
2985     char caller[MAXKTCNAMELEN];
2986
2987     if (!afsconf_SuperUser(tdir, acid, caller))
2988         return VOLSERBAD_ACCESS;        /*not a super user */
2989     tt = FindTrans(fromTrans);
2990     if (!tt)
2991         return ENOENT;
2992     if (tt->vflags & VTDeleted) {
2993         TRELE(tt);
2994         return ENOENT;
2995     }
2996     TSetRxCall(tt, acid, "GetSize");
2997     code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
2998     TClearRxCall(tt);
2999     if (TRELE(tt))
3000         return VOLSERTRELE_ERROR;
3001
3002 /*    osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);  */
3003     return code;
3004 }
3005
3006 afs_int32
3007 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3008                    afs_uint32 where, afs_int32 verbose)
3009 {
3010 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3011     Error code, code2;
3012     Volume *vol=0, *newvol=0;
3013     struct volser_trans *tt = 0, *tt2 = 0;
3014     char caller[MAXKTCNAMELEN];
3015     char line[128];
3016
3017     if (!afsconf_SuperUser(tdir, acall, caller))
3018         return EPERM;
3019
3020     vol = VAttachVolume(&code, vid, V_VOLUPD);
3021     if (!vol) {
3022         if (!code)
3023             code = ENOENT;
3024         return code;
3025     }
3026     newvol = VAttachVolume(&code, new, V_VOLUPD);
3027     if (!newvol) {
3028         VDetachVolume(&code2, vol);
3029         if (!code)
3030             code = ENOENT;
3031         return code;
3032     }
3033     if (V_device(vol) != V_device(newvol)
3034         || V_uniquifier(newvol) != 2) {
3035         if (V_device(vol) != V_device(newvol)) {
3036             sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3037                     vid, new);
3038             rx_Write(acall, line, strlen(line));
3039         }
3040         if (V_uniquifier(newvol) != 2) {
3041             sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3042             rx_Write(acall, line, strlen(line));
3043         }
3044         line[0] = 0;
3045         rx_Write(acall, line, 1);
3046         VDetachVolume(&code2, vol);
3047         VDetachVolume(&code2, newvol);
3048         return EINVAL;
3049     }
3050     tt = NewTrans(vid, V_device(vol));
3051     if (!tt) {
3052         sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3053         rx_Write(acall, line, strlen(line));
3054         line[0] = 0;
3055         rx_Write(acall, line, 1);
3056         VDetachVolume(&code2, vol);
3057         VDetachVolume(&code2, newvol);
3058         return VOLSERVOLBUSY;
3059     }
3060     VTRANS_OBJ_LOCK(tt);
3061     tt->iflags = ITBusy;
3062     tt->vflags = 0;
3063     TSetRxCall_r(tt, NULL, "SplitVolume");
3064     VTRANS_OBJ_UNLOCK(tt);
3065
3066     tt2 = NewTrans(new, V_device(newvol));
3067     if (!tt2) {
3068         sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3069         rx_Write(acall, line, strlen(line));
3070         line[0] = 0;
3071         rx_Write(acall, line, 1);
3072         DeleteTrans(tt, 1);
3073         VDetachVolume(&code2, vol);
3074         VDetachVolume(&code2, newvol);
3075         return VOLSERVOLBUSY;
3076     }
3077     VTRANS_OBJ_LOCK(tt2);
3078     tt2->iflags = ITBusy;
3079     tt2->vflags = 0;
3080     TSetRxCall_r(tt2, NULL, "SplitVolume");
3081     VTRANS_OBJ_UNLOCK(tt2);
3082
3083     code = split_volume(acall, vol, newvol, where, verbose);
3084
3085     VDetachVolume(&code2, vol);
3086     DeleteTrans(tt, 1);
3087     VDetachVolume(&code2, newvol);
3088     DeleteTrans(tt2, 1);
3089     return code;
3090 #else
3091     return VOLSERBADOP;
3092 #endif
3093 }
3094
3095 /* GetPartName - map partid (a decimal number) into pname (a string)
3096  * Since for NT we actually want to return the drive name, we map through the
3097  * partition struct.
3098  */
3099 static int
3100 GetPartName(afs_int32 partid, char *pname)
3101 {
3102     if (partid < 0)
3103         return -1;
3104     if (partid < 26) {
3105         strcpy(pname, "/vicep");
3106         pname[6] = 'a' + partid;
3107         pname[7] = '\0';
3108         return 0;
3109     } else if (partid < VOLMAXPARTS) {
3110         strcpy(pname, "/vicep");
3111         partid -= 26;
3112         pname[6] = 'a' + (partid / 26);
3113         pname[7] = 'a' + (partid % 26);
3114         pname[8] = '\0';
3115         return 0;
3116     } else
3117         return -1;
3118 }