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