build: compile_et rules for parallel make
[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     if (DoLogging) {
1551         char buffer[16];
1552         Log("%s on %s is executing Restore %" AFS_VOLID_FMT "\n", caller,
1553             callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
1554     }
1555     TSetRxCall(tt, acid, "Restore");
1556
1557     DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1558
1559     code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie);       /* last is incrementalp */
1560     FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1561     TClearRxCall(tt);
1562     tcode = TRELE(tt);
1563
1564     return (code ? code : tcode);
1565 }
1566
1567 /* end a transaction, returning the transaction's final error code in rcode */
1568 afs_int32
1569 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1570 {
1571     afs_int32 code;
1572
1573     code = VolEndTrans(acid, destTrans, rcode);
1574     osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1575     return code;
1576 }
1577
1578 static afs_int32
1579 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1580 {
1581     struct volser_trans *tt;
1582     char caller[MAXKTCNAMELEN];
1583
1584     if (!afsconf_SuperUser(tdir, acid, caller))
1585         return VOLSERBAD_ACCESS;        /*not a super user */
1586     tt = FindTrans(destTrans);
1587     if (!tt) {
1588         return ENOENT;
1589     }
1590     *rcode = tt->returnCode;
1591     DeleteTrans(tt, 1);         /* this does an implicit TRELE */
1592
1593     return 0;
1594 }
1595
1596 afs_int32
1597 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1598 {
1599     afs_int32 code;
1600
1601     code = VolSetForwarding(acid, atid, anewsite);
1602     osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1603                htonl(anewsite), AUD_END);
1604     return code;
1605 }
1606
1607 static afs_int32
1608 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1609 {
1610     struct volser_trans *tt;
1611     char caller[MAXKTCNAMELEN];
1612     char partName[16];
1613
1614     if (!afsconf_SuperUser(tdir, acid, caller))
1615         return VOLSERBAD_ACCESS;        /*not a super user */
1616     tt = FindTrans(atid);
1617     if (!tt)
1618         return ENOENT;
1619     if (tt->vflags & VTDeleted) {
1620         Log("1 Volser: VolSetForwarding: volume %" AFS_VOLID_FMT " has been deleted \n",
1621             afs_printable_VolumeId_lu(tt->volid));
1622         TRELE(tt);
1623         return ENOENT;
1624     }
1625     TSetRxCall(tt, acid, "SetForwarding");
1626     if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1627         partName[0] = '\0';
1628     }
1629     FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1630     TClearRxCall(tt);
1631     if (TRELE(tt))
1632         return VOLSERTRELE_ERROR;
1633
1634     return 0;
1635 }
1636
1637 afs_int32
1638 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1639                  struct volser_status *astatus)
1640 {
1641     afs_int32 code;
1642
1643     code = VolGetStatus(acid, atrans, astatus);
1644     osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1645     return code;
1646 }
1647
1648 static afs_int32
1649 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1650              struct volser_status *astatus)
1651 {
1652     struct Volume *tv;
1653     struct VolumeDiskData *td;
1654     struct volser_trans *tt;
1655
1656
1657     tt = FindTrans(atrans);
1658     if (!tt)
1659         return ENOENT;
1660     if (tt->vflags & VTDeleted) {
1661         Log("1 Volser: VolGetStatus: volume %" AFS_VOLID_FMT " has been deleted \n",
1662             afs_printable_VolumeId_lu(tt->volid));
1663         TRELE(tt);
1664         return ENOENT;
1665     }
1666     TSetRxCall(tt, acid, "GetStatus");
1667     tv = tt->volume;
1668     if (!tv) {
1669         TClearRxCall(tt);
1670         TRELE(tt);
1671         return ENOENT;
1672     }
1673
1674     td = &(V_disk(tv));
1675     astatus->volID = td->id;
1676     astatus->nextUnique = td->uniquifier;
1677     astatus->type = td->type;
1678     astatus->parentID = td->parentId;
1679     astatus->cloneID = td->cloneId;
1680     astatus->backupID = td->backupId;
1681     astatus->restoredFromID = td->restoredFromId;
1682     astatus->maxQuota = td->maxquota;
1683     astatus->minQuota = td->minquota;
1684     astatus->owner = td->owner;
1685     astatus->creationDate = td->creationDate;
1686     astatus->accessDate = td->accessDate;
1687     astatus->updateDate = td->updateDate;
1688     astatus->expirationDate = td->expirationDate;
1689     astatus->backupDate = td->backupDate;
1690     astatus->copyDate = td->copyDate;
1691     TClearRxCall(tt);
1692     if (TRELE(tt))
1693         return VOLSERTRELE_ERROR;
1694
1695     return 0;
1696 }
1697
1698 afs_int32
1699 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1700                struct volintInfo *astatus)
1701 {
1702     afs_int32 code;
1703
1704     code = VolSetInfo(acid, atrans, astatus);
1705     osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1706     return code;
1707 }
1708
1709 static afs_int32
1710 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1711                struct volintInfo *astatus)
1712 {
1713     struct Volume *tv;
1714     struct VolumeDiskData *td;
1715     struct volser_trans *tt;
1716     char caller[MAXKTCNAMELEN];
1717     Error error;
1718
1719     if (!afsconf_SuperUser(tdir, acid, caller))
1720         return VOLSERBAD_ACCESS;        /*not a super user */
1721     tt = FindTrans(atrans);
1722     if (!tt)
1723         return ENOENT;
1724     if (tt->vflags & VTDeleted) {
1725         Log("1 Volser: VolSetInfo: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1726         TRELE(tt);
1727         return ENOENT;
1728     }
1729     TSetRxCall(tt, acid, "SetStatus");
1730     tv = tt->volume;
1731     if (!tv) {
1732         TClearRxCall(tt);
1733         TRELE(tt);
1734         return ENOENT;
1735     }
1736
1737     td = &(V_disk(tv));
1738     /*
1739      * Add more fields as necessary
1740      */
1741     if (astatus->maxquota != -1)
1742         td->maxquota = astatus->maxquota;
1743     if (astatus->dayUse != -1)
1744         td->dayUse = astatus->dayUse;
1745     if (astatus->creationDate != -1)
1746         td->creationDate = astatus->creationDate;
1747     if (astatus->updateDate != -1)
1748         td->updateDate = astatus->updateDate;
1749     if (astatus->spare2 != -1)
1750         td->volUpdateCounter = (unsigned int)astatus->spare2;
1751     VUpdateVolume(&error, tv);
1752     TClearRxCall(tt);
1753     if (TRELE(tt))
1754         return VOLSERTRELE_ERROR;
1755     return 0;
1756 }
1757
1758
1759 afs_int32
1760 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1761 {
1762     afs_int32 code;
1763
1764     code = VolGetName(acid, atrans, aname);
1765     osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1766     return code;
1767 }
1768
1769 static afs_int32
1770 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1771 {
1772     struct Volume *tv;
1773     struct VolumeDiskData *td;
1774     struct volser_trans *tt;
1775     int len;
1776
1777     /* We need to at least fill it in */
1778     *aname = malloc(1);
1779     if (!*aname)
1780         return ENOMEM;
1781     tt = FindTrans(atrans);
1782     if (!tt)
1783         return ENOENT;
1784     if (tt->vflags & VTDeleted) {
1785         Log("1 Volser: VolGetName: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1786         TRELE(tt);
1787         return ENOENT;
1788     }
1789     TSetRxCall(tt, acid, "GetName");
1790     tv = tt->volume;
1791     if (!tv) {
1792         TClearRxCall(tt);
1793         TRELE(tt);
1794         return ENOENT;
1795     }
1796
1797     td = &(V_disk(tv));
1798     len = strlen(td->name) + 1; /* don't forget the null */
1799     if (len >= SIZE) {
1800         TClearRxCall(tt);
1801         TRELE(tt);
1802         return E2BIG;
1803     }
1804     *aname = realloc(*aname, len);
1805     strcpy(*aname, td->name);
1806     TClearRxCall(tt);
1807     if (TRELE(tt))
1808         return VOLSERTRELE_ERROR;
1809
1810     return 0;
1811 }
1812
1813 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1814  * - a noop now !*/
1815 afs_int32
1816 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1817                      VolumeId parentId, VolumeId cloneId)
1818 {
1819     return 0;
1820 }
1821
1822
1823 /*return a list of all partitions on the server. The non mounted
1824  *partitions are returned as -1 in the corresponding slot in partIds*/
1825 afs_int32
1826 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1827 {
1828     afs_int32 code;
1829
1830     code = VolListPartitions(acid, partIds);
1831     osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1832     return code;
1833 }
1834
1835 static afs_int32
1836 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1837 {
1838     char namehead[9];
1839     int i;
1840
1841     strcpy(namehead, "/vicep"); /*7 including null terminator */
1842
1843     /* Just return attached partitions. */
1844     namehead[7] = '\0';
1845     for (i = 0; i < 26; i++) {
1846         namehead[6] = i + 'a';
1847         partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1848     }
1849
1850     return 0;
1851 }
1852
1853 /*return a list of all partitions on the server. The non mounted
1854  *partitions are returned as -1 in the corresponding slot in partIds*/
1855 afs_int32
1856 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1857 {
1858     afs_int32 code;
1859
1860     code = XVolListPartitions(acid, pEntries);
1861     osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1862     return code;
1863 }
1864
1865 static afs_int32
1866 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1867 {
1868     char namehead[9];
1869     struct partList partList;
1870     struct DiskPartition64 *dp;
1871     int i, j = 0;
1872
1873     strcpy(namehead, "/vicep"); /*7 including null terminator */
1874
1875     /* Only report attached partitions */
1876     for (i = 0; i < VOLMAXPARTS; i++) {
1877 #ifdef AFS_DEMAND_ATTACH_FS
1878         dp = VGetPartitionById(i, 0);
1879 #else
1880         if (i < 26) {
1881             namehead[6] = i + 'a';
1882             namehead[7] = '\0';
1883         } else {
1884             int k;
1885
1886             k = i - 26;
1887             namehead[6] = 'a' + (k / 26);
1888             namehead[7] = 'a' + (k % 26);
1889             namehead[8] = '\0';
1890         }
1891         dp = VGetPartition(namehead, 0);
1892 #endif
1893         if (dp)
1894             partList.partId[j++] = i;
1895     }
1896     if (j > 0) {
1897         pEntries->partEntries_val = malloc(j * sizeof(int));
1898         if (!pEntries->partEntries_val)
1899             return ENOMEM;
1900         memcpy(pEntries->partEntries_val, partList.partId,
1901                 j * sizeof(int));
1902         pEntries->partEntries_len = j;
1903     } else {
1904         pEntries->partEntries_val = NULL;
1905         pEntries->partEntries_len = 0;
1906     }
1907     return 0;
1908
1909 }
1910
1911 /*
1912  * Scan a directory for possible volume headers.
1913  * in: DIR *dirp                -- a directory handle from opendir()
1914  * out: char *volname           -- set to name of directory entry
1915  *      afs_uint32 *volid       -- set to volume ID parsed from name
1916  * returns:
1917  *  true if volname and volid have been set to valid values
1918  *  false if we got to the end of the directory
1919  */
1920 static int
1921 GetNextVol(DIR *dirp, char *volname, VolumeId *volid)
1922 {
1923     struct dirent *dp;
1924
1925     while ((dp = readdir(dirp)) != NULL) {
1926         /* could be optimized on platforms with dp->d_namlen */
1927         if (dp->d_name[0] == 'V' && strlen(dp->d_name) == VHDRNAMELEN
1928                 && strcmp(&(dp->d_name[VFORMATDIGITS + 1]), VHDREXT) == 0) {
1929             *volid = VolumeNumber(dp->d_name);
1930             strcpy(volname, dp->d_name);
1931             return 1;
1932         }
1933     }
1934     return 0;
1935 }
1936
1937 /**
1938  * volint vol info structure type.
1939  */
1940 typedef enum {
1941     VOLINT_INFO_TYPE_BASE,  /**< volintInfo type */
1942     VOLINT_INFO_TYPE_EXT    /**< volintXInfo type */
1943 } volint_info_type_t;
1944
1945 /**
1946  * handle to various on-wire vol info types.
1947  */
1948 typedef struct {
1949     volint_info_type_t volinfo_type;
1950     union {
1951         void * opaque;
1952         volintInfo * base;
1953         volintXInfo * ext;
1954     } volinfo_ptr;
1955 } volint_info_handle_t;
1956
1957 /**
1958  * store value to a field at the appropriate location in on-wire structure.
1959  */
1960 #define VOLINT_INFO_STORE(handle, name, val) \
1961     do { \
1962         if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1963             (handle)->volinfo_ptr.base->name = (val); \
1964         } else { \
1965             (handle)->volinfo_ptr.ext->name = (val); \
1966         } \
1967     } while(0)
1968
1969 /**
1970  * get pointer to appropriate offset of field in on-wire structure.
1971  */
1972 #define VOLINT_INFO_PTR(handle, name) \
1973     (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1974      &((handle)->volinfo_ptr.base->name) : \
1975      &((handle)->volinfo_ptr.ext->name))
1976
1977 /**
1978  * fill in appropriate type of on-wire volume metadata structure.
1979  *
1980  * @param vp      pointer to volume object
1981  * @param handle  pointer to wire format handle object
1982  *
1983  * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1984  * @pre handle object must have a valid pointer and enumeration value
1985  *
1986  * @note passing a NULL value for vp means that the fileserver doesn't
1987  *       know about this particular volume, thus implying it is offline.
1988  *
1989  * @return operation status
1990  *   @retval 0 success
1991  *   @retval 1 failure
1992  */
1993 static int
1994 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1995 {
1996     unsigned int numStatBytes, now;
1997     struct VolumeDiskData *hdr = &(V_disk(vp));
1998
1999     /*read in the relevant info */
2000     strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2001     VOLINT_INFO_STORE(handle, status, VOK);     /*its ok */
2002     VOLINT_INFO_STORE(handle, volid, hdr->id);
2003     VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2004     VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId);   /*if rw volume */
2005     VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2006     VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2007     VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2008     VOLINT_INFO_STORE(handle, size, hdr->diskused);
2009     VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2010     VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2011     now = FT_ApproxTime();
2012     if ((now - hdr->dayUseDate) > OneDay) {
2013         VOLINT_INFO_STORE(handle, dayUse, 0);
2014     } else {
2015         VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2016     }
2017     VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2018     VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2019     VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2020     VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2021
2022 #ifdef AFS_DEMAND_ATTACH_FS
2023     /*
2024      * for DAFS, we "lie" about volume state --
2025      * instead of returning the raw state from the disk header,
2026      * we compute state based upon the fileserver's internal
2027      * in-core state enumeration value reported to us via fssync,
2028      * along with the blessed and inService flags from the header.
2029      *   -- tkeiser 11/27/2007
2030      */
2031
2032     /* Conditions that offline status is based on:
2033                 volume is unattached state
2034                 volume state is in (one of several error states)
2035                 volume not in service
2036                 volume is not marked as blessed (not on hold)
2037                 volume in salvage req. state
2038                 volume needsSalvaged
2039                 next op would set volume offline
2040                 next op would not leave volume online (based on several conditions)
2041     */
2042     if (!vp ||
2043         (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2044         VIsErrorState(V_attachState(vp)) ||
2045         !hdr->inService ||
2046         !hdr->blessed ||
2047         (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2048         hdr->needsSalvaged ||
2049         (vp->pending_vol_op &&
2050                 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2051                 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2052         )
2053         ) {
2054         VOLINT_INFO_STORE(handle, inUse, 0);
2055     } else {
2056         VOLINT_INFO_STORE(handle, inUse, 1);
2057     }
2058 #else
2059     /* offline status based on program type, where != fileServer enum (1) is offline */
2060     if (hdr->inUse == fileServer) {
2061         VOLINT_INFO_STORE(handle, inUse, 1);
2062     } else {
2063         VOLINT_INFO_STORE(handle, inUse, 0);
2064     }
2065 #endif
2066
2067
2068     switch(handle->volinfo_type) {
2069         /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2070     case VOLINT_INFO_TYPE_BASE:
2071
2072 #ifdef AFS_DEMAND_ATTACH_FS
2073         /* see comment above where we set inUse bit */
2074         if (hdr->needsSalvaged ||
2075             (vp && VIsErrorState(V_attachState(vp)))) {
2076             handle->volinfo_ptr.base->needsSalvaged = 1;
2077         } else {
2078             handle->volinfo_ptr.base->needsSalvaged = 0;
2079         }
2080 #else
2081         handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2082 #endif
2083         handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2084         handle->volinfo_ptr.base->spare0 = hdr->minquota;
2085         handle->volinfo_ptr.base->spare1 =
2086             (long)hdr->weekUse[0] +
2087             (long)hdr->weekUse[1] +
2088             (long)hdr->weekUse[2] +
2089             (long)hdr->weekUse[3] +
2090             (long)hdr->weekUse[4] +
2091             (long)hdr->weekUse[5] +
2092             (long)hdr->weekUse[6];
2093         handle->volinfo_ptr.base->flags = 0;
2094         handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2095         handle->volinfo_ptr.base->spare3 = 0;
2096         break;
2097
2098
2099     case VOLINT_INFO_TYPE_EXT:
2100         numStatBytes =
2101             4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2102                  (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2103
2104         /*
2105          * Copy out the stat fields in a single operation.
2106          */
2107         if ((now - hdr->dayUseDate) > OneDay) {
2108             memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2109                    0, numStatBytes);
2110         } else {
2111             memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2112                    (char *)&(hdr->stat_reads[0]),
2113                    numStatBytes);
2114         }
2115         break;
2116     }
2117
2118     return 0;
2119 }
2120
2121 #ifdef AFS_DEMAND_ATTACH_FS
2122
2123 /**
2124  * get struct Volume out of the fileserver.
2125  *
2126  * @param[in] volumeId  volumeId for which we want state information
2127  * @param[in] pname     partition name string
2128  * @param[inout] vp     pointer to pointer to Volume object which
2129  *                      will be populated (see note)
2130  *
2131  * @return operation status
2132  *   @retval 0         success
2133  *   @retval non-zero  failure
2134  *
2135  * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2136  *
2137  * @internal
2138  */
2139 static int
2140 GetVolObject(VolumeId volumeId, char * pname, Volume ** vp)
2141 {
2142     int code;
2143     SYNC_response res;
2144
2145     res.hdr.response_len = sizeof(res.hdr);
2146     res.payload.buf = *vp;
2147     res.payload.len = sizeof(Volume);
2148
2149     code = FSYNC_VolOp(volumeId,
2150                        pname,
2151                        FSYNC_VOL_QUERY,
2152                        0,
2153                        &res);
2154
2155     if (code != SYNC_OK) {
2156         switch (res.hdr.reason) {
2157         case FSYNC_WRONG_PART:
2158         case FSYNC_UNKNOWN_VOLID:
2159             *vp = NULL;
2160             code = SYNC_OK;
2161             break;
2162         }
2163     }
2164
2165     return code;
2166 }
2167
2168 #endif
2169
2170 /**
2171  * mode of volume list operation.
2172  */
2173 typedef enum {
2174     VOL_INFO_LIST_SINGLE,   /**< performing a single volume list op */
2175     VOL_INFO_LIST_MULTIPLE  /**< performing a multi-volume list op */
2176 } vol_info_list_mode_t;
2177
2178 /**
2179  * abstract interface to populate wire-format volume metadata structures.
2180  *
2181  * @param[in]  partId    partition id
2182  * @param[in]  volumeId  volume id
2183  * @param[in]  pname     partition name
2184  * @param[in]  volname   volume file name
2185  * @param[in]  handle    handle to on-wire volume metadata object
2186  * @param[in]  mode      listing mode
2187  *
2188  * @return operation status
2189  *   @retval 0      success
2190  *   @retval -2     DESTROY_ME flag is set
2191  *   @retval -1     general failure; some data filled in
2192  *   @retval -3     couldn't create vtrans; some data filled in
2193  */
2194 static int
2195 GetVolInfo(afs_uint32 partId,
2196            VolumeId volumeId,
2197            char * pname,
2198            char * volname,
2199            volint_info_handle_t * handle,
2200            vol_info_list_mode_t mode)
2201 {
2202     int code = -1;
2203     Error error;
2204     struct volser_trans *ttc = NULL;
2205     struct Volume *fill_tv, *tv = NULL;
2206 #ifdef AFS_DEMAND_ATTACH_FS
2207     struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2208     SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2209     SYNC_response fs_res; /* Response handle for the pending_vol_op */
2210     FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2211
2212     /* Set up response handle for pending_vol_op */
2213     fs_res.hdr.response_len = sizeof(fs_res.hdr);
2214     fs_res.payload.buf = fs_res_buf;
2215     fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2216 #endif
2217
2218     ttc = NewTrans(volumeId, partId);
2219     if (!ttc) {
2220         code = -3;
2221         VOLINT_INFO_STORE(handle, status, VBUSY);
2222         VOLINT_INFO_STORE(handle, volid, volumeId);
2223         goto drop;
2224     }
2225
2226     /* Get volume from volserver */
2227     if (mode == VOL_INFO_LIST_MULTIPLE)
2228         tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2229     else {
2230 #ifdef AFS_DEMAND_ATTACH_FS
2231         int mode = V_PEEK;
2232 #else
2233         int mode = V_READONLY;   /* informs the fileserver to update the volume headers. */
2234 #endif
2235         tv = VAttachVolumeByName_retry(&error, pname, volname, mode);
2236     }
2237
2238     if (error) {
2239         Log("1 Volser: GetVolInfo: Could not attach volume %" AFS_VOLID_FMT " (%s:%s) error=%d\n",
2240             afs_printable_VolumeId_lu(volumeId), pname, volname, error);
2241         goto drop;
2242     }
2243
2244     /*
2245      * please note that destroyMe and needsSalvaged checks used to be ordered
2246      * in the opposite manner for ListVolumes and XListVolumes.  I think it's
2247      * more correct to check destroyMe before needsSalvaged.
2248      *   -- tkeiser 11/28/2007
2249      */
2250
2251     if (V_destroyMe(tv) == DESTROY_ME) {
2252         switch (mode) {
2253         case VOL_INFO_LIST_MULTIPLE:
2254             code = -2;
2255             goto drop;
2256
2257         case VOL_INFO_LIST_SINGLE:
2258             Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) will be destroyed on next salvage\n",
2259                 afs_printable_VolumeId_lu(volumeId), pname, volname);
2260
2261         default:
2262             goto drop;
2263         }
2264     }
2265
2266     if (V_needsSalvaged(tv)) {
2267         /*this volume will be salvaged */
2268         Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) needs to be salvaged\n",
2269             afs_printable_VolumeId_lu(volumeId), pname, volname);
2270     }
2271
2272 #ifdef AFS_DEMAND_ATTACH_FS
2273     /* If using DAFS, get volume from fsserver */
2274     if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2275
2276         goto drop;
2277     }
2278
2279     /* fs_tv is a shallow copy, must populate certain structures before passing along */
2280     if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2281         /* If we if the pending vol op */
2282         memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2283         fs_tv->pending_vol_op=&pending_vol_op_res;
2284     } else {
2285         fs_tv->pending_vol_op=NULL;
2286     }
2287
2288     /* populate the header from the volserver copy */
2289     fs_tv->header=tv->header;
2290
2291     /* When using DAFS, use the fs volume info, populated with required structures */
2292     fill_tv = fs_tv;
2293 #else
2294     /* When not using DAFS, just use the local volume info */
2295     fill_tv = tv;
2296 #endif
2297
2298     /* ok, we have all the data we need; fill in the on-wire struct */
2299     code = FillVolInfo(fill_tv, handle);
2300
2301  drop:
2302     if (code == -1) {
2303         VOLINT_INFO_STORE(handle, status, 0);
2304         strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2305         VOLINT_INFO_STORE(handle, volid, volumeId);
2306     }
2307     if (tv) {
2308         VDetachVolume(&error, tv);
2309         tv = NULL;
2310         if (error) {
2311             VOLINT_INFO_STORE(handle, status, 0);
2312             strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2313             Log("1 Volser: GetVolInfo: Could not detach volume %" AFS_VOLID_FMT " (%s:%s)\n",
2314                 afs_printable_VolumeId_lu(volumeId), pname, volname);
2315         }
2316     }
2317     if (ttc) {
2318         DeleteTrans(ttc, 1);
2319         ttc = NULL;
2320     }
2321     return code;
2322 }
2323
2324
2325 /*return the header information about the <volid> */
2326 afs_int32
2327 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2328                      VolumeId volumeId, volEntries *volumeInfo)
2329 {
2330     afs_int32 code;
2331
2332     code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2333     osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2334     return code;
2335 }
2336
2337 static afs_int32
2338 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2339                  VolumeId volumeId, volEntries *volumeInfo)
2340 {
2341     struct DiskPartition64 *partP;
2342     char pname[9], volname[20];
2343     DIR *dirp;
2344     VolumeId volid;
2345     int found = 0;
2346     volint_info_handle_t handle;
2347
2348     volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2349     if (!volumeInfo->volEntries_val)
2350         return ENOMEM;
2351
2352     volumeInfo->volEntries_len = 1;
2353     if (GetPartName(partid, pname))
2354         return VOLSERILLEGAL_PARTITION;
2355     if (!(partP = VGetPartition(pname, 0)))
2356         return VOLSERILLEGAL_PARTITION;
2357     dirp = opendir(VPartitionPath(partP));
2358     if (dirp == NULL)
2359         return VOLSERILLEGAL_PARTITION;
2360
2361     while (GetNextVol(dirp, volname, &volid)) {
2362         if (volid == volumeId) {        /*copy other things too */
2363             found = 1;
2364             break;
2365         }
2366     }
2367
2368     if (found) {
2369 #ifndef AFS_PTHREAD_ENV
2370         IOMGR_Poll();   /*make sure that the client does not time out */
2371 #endif
2372
2373         handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2374         handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2375
2376         /* The return code from GetVolInfo is ignored; there is no error from
2377          * it that results in the whole call being aborted. Any volume
2378          * attachment failures are reported in 'status' field in the
2379          * volumeInfo payload. */
2380         GetVolInfo(partid,
2381                    volid,
2382                    pname,
2383                    volname,
2384                    &handle,
2385                    VOL_INFO_LIST_SINGLE);
2386     }
2387
2388     closedir(dirp);
2389     return (found) ? 0 : ENODEV;
2390 }
2391
2392 /*------------------------------------------------------------------------
2393  * EXPORTED SAFSVolXListOneVolume
2394  *
2395  * Description:
2396  *      Returns extended info on volume a_volID on partition a_partID.
2397  *
2398  * Arguments:
2399  *      a_rxCidP       : Pointer to the Rx call we're performing.
2400  *      a_partID       : Partition for which we want the extended list.
2401  *      a_volID        : Volume ID we wish to know about.
2402  *      a_volumeXInfoP : Ptr to the extended info blob.
2403  *
2404  * Returns:
2405  *      0                       Successful operation
2406  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2407  *
2408  * Environment:
2409  *      Nothing interesting.
2410  *
2411  * Side Effects:
2412  *      As advertised.
2413  *------------------------------------------------------------------------*/
2414
2415 afs_int32
2416 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2417                       VolumeId a_volID, volXEntries *a_volumeXInfoP)
2418 {
2419     afs_int32 code;
2420
2421     code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2422     osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2423     return code;
2424 }
2425
2426 static afs_int32
2427 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2428                   VolumeId a_volID, volXEntries *a_volumeXInfoP)
2429 {                               /*SAFSVolXListOneVolume */
2430
2431     struct DiskPartition64 *partP;      /*Ptr to partition */
2432     char pname[9], volname[20]; /*Partition, volume names */
2433     DIR *dirp;                  /*Partition directory ptr */
2434     VolumeId currVolID;         /*Current volume ID */
2435     int found = 0;              /*Did we find the volume we need? */
2436     volint_info_handle_t handle;
2437
2438     /*
2439      * Set up our pointers for action, marking our structure to hold exactly
2440      * one entry.  Also, assume we'll fail in our quest.
2441      */
2442     a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2443     if (!a_volumeXInfoP->volXEntries_val)
2444         return ENOMEM;
2445
2446     a_volumeXInfoP->volXEntries_len = 1;
2447
2448     /*
2449      * If the partition name we've been given is bad, bogue out.
2450      */
2451     if (GetPartName(a_partID, pname))
2452         return (VOLSERILLEGAL_PARTITION);
2453
2454     /*
2455      * Open the directory representing the given AFS parttion.  If we can't
2456      * do that, we lose.
2457      */
2458     if (!(partP = VGetPartition(pname, 0)))
2459         return VOLSERILLEGAL_PARTITION;
2460     dirp = opendir(VPartitionPath(partP));
2461     if (dirp == NULL)
2462         return (VOLSERILLEGAL_PARTITION);
2463
2464
2465     /*
2466      * Sweep through the partition directory, looking for the desired entry.
2467      * First, of course, figure out how many stat bytes to copy out of each
2468      * volume.
2469      */
2470     while (GetNextVol(dirp, volname, &currVolID)) {
2471         if (currVolID == a_volID) {
2472             /*
2473              * We found the volume entry we're interested.  Pull out the
2474              * extended information, remembering to poll (so that the client
2475              * doesn't time out) and to set up a transaction on the volume.
2476              */
2477             found = 1;
2478             break;
2479         }                       /*Found desired volume */
2480     }
2481
2482     if (found) {
2483 #ifndef AFS_PTHREAD_ENV
2484         IOMGR_Poll();
2485 #endif
2486
2487         handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2488         handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2489
2490         /* The return code from GetVolInfo is ignored; there is no error from
2491          * it that results in the whole call being aborted. Any volume
2492          * attachment failures are reported in 'status' field in the
2493          * volumeInfo payload. */
2494         GetVolInfo(a_partID,
2495                    a_volID,
2496                    pname,
2497                    volname,
2498                    &handle,
2499                    VOL_INFO_LIST_SINGLE);
2500     }
2501
2502     /*
2503      * Clean up before going to dinner: close the partition directory,
2504      * return the proper value.
2505      */
2506     closedir(dirp);
2507     return (found) ? 0 : ENODEV;
2508 }                               /*SAFSVolXListOneVolume */
2509
2510 /*returns all the volumes on partition partid. If flags = 1 then all the
2511 * relevant info about the volumes  is also returned */
2512 afs_int32
2513 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2514                    volEntries *volumeInfo)
2515 {
2516     afs_int32 code;
2517
2518     code = VolListVolumes(acid, partid, flags, volumeInfo);
2519     osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2520     return code;
2521 }
2522
2523 static afs_int32
2524 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2525                    volEntries *volumeInfo)
2526 {
2527     volintInfo *pntr;
2528     struct DiskPartition64 *partP;
2529     afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2530     char pname[9], volname[20];
2531     DIR *dirp;
2532     VolumeId volid;
2533     int code;
2534     volint_info_handle_t handle;
2535
2536     volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2537     if (!volumeInfo->volEntries_val)
2538         return ENOMEM;
2539
2540     pntr = volumeInfo->volEntries_val;
2541     volumeInfo->volEntries_len = 0;
2542     if (GetPartName(partid, pname))
2543         return VOLSERILLEGAL_PARTITION;
2544     if (!(partP = VGetPartition(pname, 0)))
2545         return VOLSERILLEGAL_PARTITION;
2546     dirp = opendir(VPartitionPath(partP));
2547     if (dirp == NULL)
2548         return VOLSERILLEGAL_PARTITION;
2549
2550     while (GetNextVol(dirp, volname, &volid)) {
2551         if (flags) {            /*copy other things too */
2552 #ifndef AFS_PTHREAD_ENV
2553             IOMGR_Poll();       /*make sure that the client does not time out */
2554 #endif
2555
2556             handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2557             handle.volinfo_ptr.base = pntr;
2558
2559
2560             code = GetVolInfo(partid,
2561                               volid,
2562                               pname,
2563                               volname,
2564                               &handle,
2565                               VOL_INFO_LIST_MULTIPLE);
2566             if (code == -2)     /* DESTROY_ME flag set */
2567                 continue;
2568         } else {
2569             pntr->volid = volid;
2570             /*just volids are needed */
2571         }
2572
2573         pntr++;
2574         volumeInfo->volEntries_len += 1;
2575         if ((allocSize - volumeInfo->volEntries_len) < 5) {
2576             /*running out of space, allocate more space */
2577             allocSize = (allocSize * 3) / 2;
2578             pntr = realloc(volumeInfo->volEntries_val,
2579                            allocSize * sizeof(volintInfo));
2580             if (pntr == NULL) {
2581                 closedir(dirp);
2582                 return VOLSERNO_MEMORY;
2583             }
2584             volumeInfo->volEntries_val = pntr;  /* point to new block */
2585             /* set pntr to the right position */
2586             pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2587         }
2588     }
2589
2590     closedir(dirp);
2591     return 0;
2592 }
2593
2594 /*------------------------------------------------------------------------
2595  * EXPORTED SAFSVolXListVolumes
2596  *
2597  * Description:
2598  *      Returns all the volumes on partition a_partID.  If a_flags
2599  *      is set to 1, then all the relevant extended volume information
2600  *      is also returned.
2601  *
2602  * Arguments:
2603  *      a_rxCidP       : Pointer to the Rx call we're performing.
2604  *      a_partID       : Partition for which we want the extended list.
2605  *      a_flags        : Various flags.
2606  *      a_volumeXInfoP : Ptr to the extended info blob.
2607  *
2608  * Returns:
2609  *      0                       Successful operation
2610  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2611  *      VOLSERNO_MEMORY         if we ran out of memory allocating
2612  *                              our return blob
2613  *
2614  * Environment:
2615  *      Nothing interesting.
2616  *
2617  * Side Effects:
2618  *      As advertised.
2619  *------------------------------------------------------------------------*/
2620
2621 afs_int32
2622 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2623                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2624 {
2625     afs_int32 code;
2626
2627     code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2628     osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2629     return code;
2630 }
2631
2632 static afs_int32
2633 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2634                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2635 {                               /*SAFSVolXListVolumes */
2636
2637     volintXInfo *xInfoP;        /*Ptr to the extended vol info */
2638     struct DiskPartition64 *partP;      /*Ptr to partition */
2639     afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2640     char pname[9], volname[20]; /*Partition, volume names */
2641     DIR *dirp;                  /*Partition directory ptr */
2642     VolumeId volid;             /*Current volume ID */
2643     int code;
2644     volint_info_handle_t handle;
2645
2646     /*
2647      * Allocate a large array of extended volume info structures, then
2648      * set it up for action.
2649      */
2650     a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2651     if (!a_volumeXInfoP->volXEntries_val)
2652         return ENOMEM;
2653
2654     xInfoP = a_volumeXInfoP->volXEntries_val;
2655     a_volumeXInfoP->volXEntries_len = 0;
2656
2657     /*
2658      * If the partition name we've been given is bad, bogue out.
2659      */
2660     if (GetPartName(a_partID, pname))
2661         return (VOLSERILLEGAL_PARTITION);
2662
2663     /*
2664      * Open the directory representing the given AFS parttion.  If we can't
2665      * do that, we lose.
2666      */
2667     if (!(partP = VGetPartition(pname, 0)))
2668         return VOLSERILLEGAL_PARTITION;
2669     dirp = opendir(VPartitionPath(partP));
2670     if (dirp == NULL)
2671         return (VOLSERILLEGAL_PARTITION);
2672     while (GetNextVol(dirp, volname, &volid)) {
2673         if (a_flags) {
2674             /*
2675              * Full info about the volume desired.  Poll to make sure the
2676              * client doesn't time out, then start up a new transaction.
2677              */
2678 #ifndef AFS_PTHREAD_ENV
2679             IOMGR_Poll();
2680 #endif
2681
2682             handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2683             handle.volinfo_ptr.ext = xInfoP;
2684
2685             code = GetVolInfo(a_partID,
2686                               volid,
2687                               pname,
2688                               volname,
2689                               &handle,
2690                               VOL_INFO_LIST_MULTIPLE);
2691             if (code == -2)     /* DESTROY_ME flag set */
2692                 continue;
2693         } else {
2694             /*
2695              * Just volume IDs are needed.
2696              */
2697             xInfoP->volid = volid;
2698         }
2699
2700         /*
2701          * Bump the pointer in the data area we're building, along with
2702          * the count of the number of entries it contains.
2703          */
2704         xInfoP++;
2705         (a_volumeXInfoP->volXEntries_len)++;
2706         if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2707             /*
2708              * We're running out of space in the area we've built.  Grow it.
2709              */
2710             allocSize = (allocSize * 3) / 2;
2711             xInfoP = (volintXInfo *)
2712                 realloc((char *)a_volumeXInfoP->volXEntries_val,
2713                         (allocSize * sizeof(volintXInfo)));
2714             if (xInfoP == NULL) {
2715                 /*
2716                  * Bummer, no memory. Bag it, tell our caller what went wrong.
2717                  */
2718                 closedir(dirp);
2719                 return (VOLSERNO_MEMORY);
2720             }
2721
2722             /*
2723              * Memory reallocation worked.  Correct our pointers so they
2724              * now point to the new block and the current open position within
2725              * the new block.
2726              */
2727             a_volumeXInfoP->volXEntries_val = xInfoP;
2728             xInfoP =
2729                 a_volumeXInfoP->volXEntries_val +
2730                 a_volumeXInfoP->volXEntries_len;
2731         }
2732     }
2733
2734     /*
2735      * We've examined all entries in the partition directory.  Close it,
2736      * delete our transaction (if any), and go home happy.
2737      */
2738     closedir(dirp);
2739     return (0);
2740
2741 }                               /*SAFSVolXListVolumes */
2742
2743 /*this call is used to monitor the status of volser for debugging purposes.
2744  *information about all the active transactions is returned in transInfo*/
2745 afs_int32
2746 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2747 {
2748     afs_int32 code;
2749
2750     code = VolMonitor(acid, transInfo);
2751     osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2752     return code;
2753 }
2754
2755 static afs_int32
2756 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2757 {
2758     transDebugInfo *pntr;
2759     afs_int32 allocSize = 50;
2760     struct volser_trans *tt, *nt, *allTrans;
2761
2762     transInfo->transDebugEntries_val =
2763         malloc(allocSize * sizeof(transDebugInfo));
2764     if (!transInfo->transDebugEntries_val)
2765         return ENOMEM;
2766     pntr = transInfo->transDebugEntries_val;
2767     transInfo->transDebugEntries_len = 0;
2768
2769     VTRANS_LOCK;
2770     allTrans = TransList();
2771     if (allTrans == (struct volser_trans *)0)
2772         goto done;              /*no active transactions */
2773     for (tt = allTrans; tt; tt = nt) {  /*copy relevant info into pntr */
2774         nt = tt->next;
2775         VTRANS_OBJ_LOCK(tt);
2776         pntr->tid = tt->tid;
2777         pntr->time = tt->time;
2778         pntr->creationTime = tt->creationTime;
2779         pntr->returnCode = tt->returnCode;
2780         pntr->volid = tt->volid;
2781         pntr->partition = tt->partition;
2782         pntr->iflags = tt->iflags;
2783         pntr->vflags = tt->vflags;
2784         pntr->tflags = tt->tflags;
2785         strcpy(pntr->lastProcName, tt->lastProcName);
2786         pntr->callValid = 0;
2787         if (tt->rxCallPtr) {    /*record call related info */
2788             pntr->callValid = 1;
2789 #if 0
2790             pntr->readNext = tt->rxCallPtr->rnext;
2791             pntr->transmitNext = tt->rxCallPtr->tnext;
2792             pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2793             pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2794 #endif
2795         }
2796         VTRANS_OBJ_UNLOCK(tt);
2797         pntr++;
2798         transInfo->transDebugEntries_len += 1;
2799         if ((allocSize - transInfo->transDebugEntries_len) < 5) {       /*alloc some more space */
2800             allocSize = (allocSize * 3) / 2;
2801             pntr = realloc(transInfo->transDebugEntries_val,
2802                            allocSize * sizeof(transDebugInfo));
2803             transInfo->transDebugEntries_val = pntr;
2804             pntr =
2805                 transInfo->transDebugEntries_val +
2806                 transInfo->transDebugEntries_len;
2807             /*set pntr to right position */
2808         }
2809
2810     }
2811 done:
2812     VTRANS_UNLOCK;
2813
2814     return 0;
2815 }
2816
2817 afs_int32
2818 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2819                    afs_int32 type, afs_uint32 pId, VolumeId cloneId,
2820                    VolumeId backupId)
2821 {
2822     afs_int32 code;
2823
2824     code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2825     osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2826                AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2827                backupId, AUD_END);
2828     return code;
2829 }
2830
2831 static afs_int32
2832 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2833                afs_int32 type, VolumeId pId, VolumeId cloneId,
2834                VolumeId backupId)
2835 {
2836     struct Volume *tv;
2837     Error error = 0;
2838     struct volser_trans *tt;
2839     char caller[MAXKTCNAMELEN];
2840
2841     if (strlen(name) > 31)
2842         return VOLSERBADNAME;
2843     if (!afsconf_SuperUser(tdir, acid, caller))
2844         return VOLSERBAD_ACCESS;        /*not a super user */
2845     /* find the trans */
2846     tt = FindTrans(atid);
2847     if (!tt)
2848         return ENOENT;
2849     if (tt->vflags & VTDeleted) {
2850         Log("1 Volser: VolSetIds: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2851         TRELE(tt);
2852         return ENOENT;
2853     }
2854     TSetRxCall(tt, acid, "SetIdsTypes");
2855     tv = tt->volume;
2856
2857     V_type(tv) = type;
2858     V_backupId(tv) = backupId;
2859     V_cloneId(tv) = cloneId;
2860     V_parentId(tv) = pId;
2861     strcpy((&V_disk(tv))->name, name);
2862     VUpdateVolume(&error, tv);
2863     if (error) {
2864         Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2865         LogError(error);
2866         goto fail;
2867     }
2868     TClearRxCall(tt);
2869     if (TRELE(tt) && !error)
2870         return VOLSERTRELE_ERROR;
2871
2872     return error;
2873   fail:
2874     TClearRxCall(tt);
2875     if (TRELE(tt) && !error)
2876         return VOLSERTRELE_ERROR;
2877     return error;
2878 }
2879
2880 afs_int32
2881 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2882 {
2883     afs_int32 code;
2884
2885     code = VolSetDate(acid, atid, cdate);
2886     osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2887                AUD_END);
2888     return code;
2889 }
2890
2891 static afs_int32
2892 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2893 {
2894     struct Volume *tv;
2895     Error error = 0;
2896     struct volser_trans *tt;
2897     char caller[MAXKTCNAMELEN];
2898
2899     if (!afsconf_SuperUser(tdir, acid, caller))
2900         return VOLSERBAD_ACCESS;        /*not a super user */
2901     /* find the trans */
2902     tt = FindTrans(atid);
2903     if (!tt)
2904         return ENOENT;
2905     if (tt->vflags & VTDeleted) {
2906         Log("1 Volser: VolSetDate: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2907         TRELE(tt);
2908         return ENOENT;
2909     }
2910     TSetRxCall(tt, acid, "SetDate");
2911     tv = tt->volume;
2912
2913     V_creationDate(tv) = cdate;
2914     VUpdateVolume(&error, tv);
2915     if (error) {
2916         Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2917         LogError(error);
2918         goto fail;
2919     }
2920     TClearRxCall(tt);
2921     if (TRELE(tt) && !error)
2922         return VOLSERTRELE_ERROR;
2923
2924     return error;
2925   fail:
2926     TClearRxCall(tt);
2927     if (TRELE(tt) && !error)
2928         return VOLSERTRELE_ERROR;
2929     return error;
2930 }
2931
2932 afs_int32
2933 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2934                            VolumeId volumeId)
2935 {
2936 #ifdef AFS_NT40_ENV
2937     return EXDEV;
2938 #else
2939     char caller[MAXKTCNAMELEN];
2940     DIR *dirp;
2941     struct volser_trans *ttc;
2942     char pname[16], volname[20];
2943     struct DiskPartition64 *partP;
2944     afs_int32 ret = ENODEV;
2945     VolumeId volid;
2946
2947     if (!afsconf_SuperUser(tdir, acid, caller))
2948         return VOLSERBAD_ACCESS;        /*not a super user */
2949     if (GetPartName(partId, pname))
2950         return VOLSERILLEGAL_PARTITION;
2951     if (!(partP = VGetPartition(pname, 0)))
2952         return VOLSERILLEGAL_PARTITION;
2953     dirp = opendir(VPartitionPath(partP));
2954     if (dirp == NULL)
2955         return VOLSERILLEGAL_PARTITION;
2956     ttc = (struct volser_trans *)0;
2957
2958     while (GetNextVol(dirp, volname, &volid)) {
2959         if (volid == volumeId) {        /*copy other things too */
2960 #ifndef AFS_PTHREAD_ENV
2961             IOMGR_Poll();       /*make sure that the client doesnot time out */
2962 #endif
2963             ttc = NewTrans(volumeId, partId);
2964             if (!ttc) {
2965                 return VOLSERVOLBUSY;
2966             }
2967 #ifdef AFS_NAMEI_ENV
2968             ret = namei_ConvertROtoRWvolume(pname, volumeId);
2969 #else
2970             ret = inode_ConvertROtoRWvolume(pname, volumeId);
2971 #endif
2972             break;
2973         }
2974     }
2975
2976     if (ttc)
2977         DeleteTrans(ttc, 1);
2978
2979     closedir(dirp);
2980     return ret;
2981 #endif
2982 }
2983
2984 afs_int32
2985 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
2986                struct volintSize *size)
2987 {
2988     int code = 0;
2989     struct volser_trans *tt;
2990     char caller[MAXKTCNAMELEN];
2991
2992     if (!afsconf_SuperUser(tdir, acid, caller))
2993         return VOLSERBAD_ACCESS;        /*not a super user */
2994     tt = FindTrans(fromTrans);
2995     if (!tt)
2996         return ENOENT;
2997     if (tt->vflags & VTDeleted) {
2998         TRELE(tt);
2999         return ENOENT;
3000     }
3001     TSetRxCall(tt, acid, "GetSize");
3002     code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3003     TClearRxCall(tt);
3004     if (TRELE(tt))
3005         return VOLSERTRELE_ERROR;
3006
3007 /*    osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);  */
3008     return code;
3009 }
3010
3011 afs_int32
3012 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3013                    afs_uint32 where, afs_int32 verbose)
3014 {
3015 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3016     Error code, code2;
3017     Volume *vol=0, *newvol=0;
3018     struct volser_trans *tt = 0, *tt2 = 0;
3019     char caller[MAXKTCNAMELEN];
3020     char line[128];
3021
3022     if (!afsconf_SuperUser(tdir, acall, caller))
3023         return EPERM;
3024
3025     vol = VAttachVolume(&code, vid, V_VOLUPD);
3026     if (!vol) {
3027         if (!code)
3028             code = ENOENT;
3029         return code;
3030     }
3031     newvol = VAttachVolume(&code, new, V_VOLUPD);
3032     if (!newvol) {
3033         VDetachVolume(&code2, vol);
3034         if (!code)
3035             code = ENOENT;
3036         return code;
3037     }
3038     if (V_device(vol) != V_device(newvol)
3039         || V_uniquifier(newvol) != 2) {
3040         if (V_device(vol) != V_device(newvol)) {
3041             sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3042                     vid, new);
3043             rx_Write(acall, line, strlen(line));
3044         }
3045         if (V_uniquifier(newvol) != 2) {
3046             sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3047             rx_Write(acall, line, strlen(line));
3048         }
3049         line[0] = 0;
3050         rx_Write(acall, line, 1);
3051         VDetachVolume(&code2, vol);
3052         VDetachVolume(&code2, newvol);
3053         return EINVAL;
3054     }
3055     tt = NewTrans(vid, V_device(vol));
3056     if (!tt) {
3057         sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3058         rx_Write(acall, line, strlen(line));
3059         line[0] = 0;
3060         rx_Write(acall, line, 1);
3061         VDetachVolume(&code2, vol);
3062         VDetachVolume(&code2, newvol);
3063         return VOLSERVOLBUSY;
3064     }
3065     VTRANS_OBJ_LOCK(tt);
3066     tt->iflags = ITBusy;
3067     tt->vflags = 0;
3068     TSetRxCall_r(tt, NULL, "SplitVolume");
3069     VTRANS_OBJ_UNLOCK(tt);
3070
3071     tt2 = NewTrans(new, V_device(newvol));
3072     if (!tt2) {
3073         sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3074         rx_Write(acall, line, strlen(line));
3075         line[0] = 0;
3076         rx_Write(acall, line, 1);
3077         DeleteTrans(tt, 1);
3078         VDetachVolume(&code2, vol);
3079         VDetachVolume(&code2, newvol);
3080         return VOLSERVOLBUSY;
3081     }
3082     VTRANS_OBJ_LOCK(tt2);
3083     tt2->iflags = ITBusy;
3084     tt2->vflags = 0;
3085     TSetRxCall_r(tt2, NULL, "SplitVolume");
3086     VTRANS_OBJ_UNLOCK(tt2);
3087
3088     code = split_volume(acall, vol, newvol, where, verbose);
3089
3090     VDetachVolume(&code2, vol);
3091     DeleteTrans(tt, 1);
3092     VDetachVolume(&code2, newvol);
3093     DeleteTrans(tt2, 1);
3094     return code;
3095 #else
3096     return VOLSERBADOP;
3097 #endif
3098 }
3099
3100 /* GetPartName - map partid (a decimal number) into pname (a string)
3101  * Since for NT we actually want to return the drive name, we map through the
3102  * partition struct.
3103  */
3104 static int
3105 GetPartName(afs_int32 partid, char *pname)
3106 {
3107     if (partid < 0)
3108         return -1;
3109     if (partid < 26) {
3110         strcpy(pname, "/vicep");
3111         pname[6] = 'a' + partid;
3112         pname[7] = '\0';
3113         return 0;
3114     } else if (partid < VOLMAXPARTS) {
3115         strcpy(pname, "/vicep");
3116         partid -= 26;
3117         pname[6] = 'a' + (partid / 26);
3118         pname[7] = 'a' + (partid % 26);
3119         pname[8] = '\0';
3120         return 0;
3121     } else
3122         return -1;
3123 }