c9ad3d482f158bf7e19fff4bfcb8c3ae9cdbd95d
[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[VFORMATDIGITS + 1]), 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 #ifdef AFS_DEMAND_ATTACH_FS
2230         int mode = V_PEEK;
2231 #else
2232         int mode = V_READONLY;   /* informs the fileserver to update the volume headers. */
2233 #endif
2234         tv = VAttachVolumeByName_retry(&error, pname, volname, mode);
2235     }
2236
2237     if (error) {
2238         Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2239             volumeId, pname, volname, error);
2240         goto drop;
2241     }
2242
2243     /*
2244      * please note that destroyMe and needsSalvaged checks used to be ordered
2245      * in the opposite manner for ListVolumes and XListVolumes.  I think it's
2246      * more correct to check destroyMe before needsSalvaged.
2247      *   -- tkeiser 11/28/2007
2248      */
2249
2250     if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2251         switch (mode) {
2252         case VOL_INFO_LIST_MULTIPLE:
2253             code = -2;
2254             goto drop;
2255
2256         case VOL_INFO_LIST_SINGLE:
2257             Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2258                 volumeId, pname, volname);
2259
2260         default:
2261             goto drop;
2262         }
2263     }
2264
2265     if (tv->header->diskstuff.needsSalvaged) {
2266         /*this volume will be salvaged */
2267         Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2268             volumeId, pname, volname);
2269     }
2270
2271 #ifdef AFS_DEMAND_ATTACH_FS
2272     /* If using DAFS, get volume from fsserver */
2273     if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2274
2275         goto drop;
2276     }
2277
2278     /* fs_tv is a shallow copy, must populate certain structures before passing along */
2279     if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2280         /* If we if the pending vol op */
2281         memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2282         fs_tv->pending_vol_op=&pending_vol_op_res;
2283     } else {
2284         fs_tv->pending_vol_op=NULL;
2285     }
2286
2287     /* populate the header from the volserver copy */
2288     fs_tv->header=tv->header;
2289
2290     /* When using DAFS, use the fs volume info, populated with required structures */
2291     fill_tv = fs_tv;
2292 #else
2293     /* When not using DAFS, just use the local volume info */
2294     fill_tv = tv;
2295 #endif
2296
2297     /* ok, we have all the data we need; fill in the on-wire struct */
2298     code = FillVolInfo(fill_tv, handle);
2299
2300  drop:
2301     if (code == -1) {
2302         VOLINT_INFO_STORE(handle, status, 0);
2303         strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2304         VOLINT_INFO_STORE(handle, volid, volumeId);
2305     }
2306     if (tv) {
2307         VDetachVolume(&error, tv);
2308         tv = NULL;
2309         if (error) {
2310             VOLINT_INFO_STORE(handle, status, 0);
2311             strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2312             Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2313                 volumeId, pname, volname);
2314         }
2315     }
2316     if (ttc) {
2317         DeleteTrans(ttc, 1);
2318         ttc = NULL;
2319     }
2320     return code;
2321 }
2322
2323
2324 /*return the header information about the <volid> */
2325 afs_int32
2326 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2327                      afs_uint32 volumeId, volEntries *volumeInfo)
2328 {
2329     afs_int32 code;
2330
2331     code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2332     osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2333     return code;
2334 }
2335
2336 static afs_int32
2337 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2338                  afs_uint32 volumeId, volEntries *volumeInfo)
2339 {
2340     struct DiskPartition64 *partP;
2341     char pname[9], volname[20];
2342     DIR *dirp;
2343     afs_uint32 volid;
2344     int found = 0;
2345     int code;
2346     volint_info_handle_t handle;
2347
2348     volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2349     if (!volumeInfo->volEntries_val)
2350         return ENOMEM;
2351
2352     volumeInfo->volEntries_len = 1;
2353     if (GetPartName(partid, pname))
2354         return VOLSERILLEGAL_PARTITION;
2355     if (!(partP = VGetPartition(pname, 0)))
2356         return VOLSERILLEGAL_PARTITION;
2357     dirp = opendir(VPartitionPath(partP));
2358     if (dirp == NULL)
2359         return VOLSERILLEGAL_PARTITION;
2360
2361     while (GetNextVol(dirp, volname, &volid)) {
2362         if (volid == volumeId) {        /*copy other things too */
2363             found = 1;
2364             break;
2365         }
2366     }
2367
2368     if (found) {
2369 #ifndef AFS_PTHREAD_ENV
2370         IOMGR_Poll();   /*make sure that the client does not time out */
2371 #endif
2372
2373         handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2374         handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2375
2376         code = GetVolInfo(partid,
2377                           volid,
2378                           pname,
2379                           volname,
2380                           &handle,
2381                           VOL_INFO_LIST_SINGLE);
2382     }
2383
2384     closedir(dirp);
2385     if (found)
2386         return code ? ENODEV: 0;
2387     else
2388         return ENODEV;
2389 }
2390
2391 /*------------------------------------------------------------------------
2392  * EXPORTED SAFSVolXListOneVolume
2393  *
2394  * Description:
2395  *      Returns extended info on volume a_volID on partition a_partID.
2396  *
2397  * Arguments:
2398  *      a_rxCidP       : Pointer to the Rx call we're performing.
2399  *      a_partID       : Partition for which we want the extended list.
2400  *      a_volID        : Volume ID we wish to know about.
2401  *      a_volumeXInfoP : Ptr to the extended info blob.
2402  *
2403  * Returns:
2404  *      0                       Successful operation
2405  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2406  *
2407  * Environment:
2408  *      Nothing interesting.
2409  *
2410  * Side Effects:
2411  *      As advertised.
2412  *------------------------------------------------------------------------*/
2413
2414 afs_int32
2415 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2416                       afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2417 {
2418     afs_int32 code;
2419
2420     code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2421     osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2422     return code;
2423 }
2424
2425 static afs_int32
2426 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2427                   afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2428 {                               /*SAFSVolXListOneVolume */
2429
2430     struct DiskPartition64 *partP;      /*Ptr to partition */
2431     char pname[9], volname[20]; /*Partition, volume names */
2432     DIR *dirp;                  /*Partition directory ptr */
2433     afs_uint32 currVolID;               /*Current volume ID */
2434     int found = 0;              /*Did we find the volume we need? */
2435     int code;
2436     volint_info_handle_t handle;
2437
2438     /*
2439      * Set up our pointers for action, marking our structure to hold exactly
2440      * one entry.  Also, assume we'll fail in our quest.
2441      */
2442     a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2443     if (!a_volumeXInfoP->volXEntries_val)
2444         return ENOMEM;
2445
2446     a_volumeXInfoP->volXEntries_len = 1;
2447     code = ENODEV;
2448
2449     /*
2450      * If the partition name we've been given is bad, bogue out.
2451      */
2452     if (GetPartName(a_partID, pname))
2453         return (VOLSERILLEGAL_PARTITION);
2454
2455     /*
2456      * Open the directory representing the given AFS parttion.  If we can't
2457      * do that, we lose.
2458      */
2459     if (!(partP = VGetPartition(pname, 0)))
2460         return VOLSERILLEGAL_PARTITION;
2461     dirp = opendir(VPartitionPath(partP));
2462     if (dirp == NULL)
2463         return (VOLSERILLEGAL_PARTITION);
2464
2465
2466     /*
2467      * Sweep through the partition directory, looking for the desired entry.
2468      * First, of course, figure out how many stat bytes to copy out of each
2469      * volume.
2470      */
2471     while (GetNextVol(dirp, volname, &currVolID)) {
2472         if (currVolID == a_volID) {
2473             /*
2474              * We found the volume entry we're interested.  Pull out the
2475              * extended information, remembering to poll (so that the client
2476              * doesn't time out) and to set up a transaction on the volume.
2477              */
2478             found = 1;
2479             break;
2480         }                       /*Found desired volume */
2481     }
2482
2483     if (found) {
2484 #ifndef AFS_PTHREAD_ENV
2485         IOMGR_Poll();
2486 #endif
2487
2488         handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2489         handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2490
2491         code = GetVolInfo(a_partID,
2492                           a_volID,
2493                           pname,
2494                           volname,
2495                           &handle,
2496                           VOL_INFO_LIST_SINGLE);
2497
2498     }
2499
2500     /*
2501      * Clean up before going to dinner: close the partition directory,
2502      * return the proper value.
2503      */
2504     closedir(dirp);
2505     if (found)
2506         return code ? ENODEV: 0;
2507     else
2508         return ENODEV;
2509 }                               /*SAFSVolXListOneVolume */
2510
2511 /*returns all the volumes on partition partid. If flags = 1 then all the
2512 * relevant info about the volumes  is also returned */
2513 afs_int32
2514 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2515                    volEntries *volumeInfo)
2516 {
2517     afs_int32 code;
2518
2519     code = VolListVolumes(acid, partid, flags, volumeInfo);
2520     osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2521     return code;
2522 }
2523
2524 static afs_int32
2525 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2526                    volEntries *volumeInfo)
2527 {
2528     volintInfo *pntr;
2529     struct DiskPartition64 *partP;
2530     afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2531     char pname[9], volname[20];
2532     DIR *dirp;
2533     afs_uint32 volid;
2534     int code;
2535     volint_info_handle_t handle;
2536
2537     volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2538     if (!volumeInfo->volEntries_val)
2539         return ENOMEM;
2540
2541     pntr = volumeInfo->volEntries_val;
2542     volumeInfo->volEntries_len = 0;
2543     if (GetPartName(partid, pname))
2544         return VOLSERILLEGAL_PARTITION;
2545     if (!(partP = VGetPartition(pname, 0)))
2546         return VOLSERILLEGAL_PARTITION;
2547     dirp = opendir(VPartitionPath(partP));
2548     if (dirp == NULL)
2549         return VOLSERILLEGAL_PARTITION;
2550
2551     while (GetNextVol(dirp, volname, &volid)) {
2552         if (flags) {            /*copy other things too */
2553 #ifndef AFS_PTHREAD_ENV
2554             IOMGR_Poll();       /*make sure that the client does not time out */
2555 #endif
2556
2557             handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2558             handle.volinfo_ptr.base = pntr;
2559
2560
2561             code = GetVolInfo(partid,
2562                               volid,
2563                               pname,
2564                               volname,
2565                               &handle,
2566                               VOL_INFO_LIST_MULTIPLE);
2567             if (code == -2)     /* DESTROY_ME flag set */
2568                 continue;
2569         } else {
2570             pntr->volid = volid;
2571             /*just volids are needed */
2572         }
2573
2574         pntr++;
2575         volumeInfo->volEntries_len += 1;
2576         if ((allocSize - volumeInfo->volEntries_len) < 5) {
2577             /*running out of space, allocate more space */
2578             allocSize = (allocSize * 3) / 2;
2579             pntr = realloc(volumeInfo->volEntries_val,
2580                            allocSize * sizeof(volintInfo));
2581             if (pntr == NULL) {
2582                 closedir(dirp);
2583                 return VOLSERNO_MEMORY;
2584             }
2585             volumeInfo->volEntries_val = pntr;  /* point to new block */
2586             /* set pntr to the right position */
2587             pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2588         }
2589     }
2590
2591     closedir(dirp);
2592     return 0;
2593 }
2594
2595 /*------------------------------------------------------------------------
2596  * EXPORTED SAFSVolXListVolumes
2597  *
2598  * Description:
2599  *      Returns all the volumes on partition a_partID.  If a_flags
2600  *      is set to 1, then all the relevant extended volume information
2601  *      is also returned.
2602  *
2603  * Arguments:
2604  *      a_rxCidP       : Pointer to the Rx call we're performing.
2605  *      a_partID       : Partition for which we want the extended list.
2606  *      a_flags        : Various flags.
2607  *      a_volumeXInfoP : Ptr to the extended info blob.
2608  *
2609  * Returns:
2610  *      0                       Successful operation
2611  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2612  *      VOLSERNO_MEMORY         if we ran out of memory allocating
2613  *                              our return blob
2614  *
2615  * Environment:
2616  *      Nothing interesting.
2617  *
2618  * Side Effects:
2619  *      As advertised.
2620  *------------------------------------------------------------------------*/
2621
2622 afs_int32
2623 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2624                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2625 {
2626     afs_int32 code;
2627
2628     code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2629     osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2630     return code;
2631 }
2632
2633 static afs_int32
2634 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2635                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2636 {                               /*SAFSVolXListVolumes */
2637
2638     volintXInfo *xInfoP;        /*Ptr to the extended vol info */
2639     struct DiskPartition64 *partP;      /*Ptr to partition */
2640     afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2641     char pname[9], volname[20]; /*Partition, volume names */
2642     DIR *dirp;                  /*Partition directory ptr */
2643     afs_uint32 volid;           /*Current volume ID */
2644     int code;
2645     volint_info_handle_t handle;
2646
2647     /*
2648      * Allocate a large array of extended volume info structures, then
2649      * set it up for action.
2650      */
2651     a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2652     if (!a_volumeXInfoP->volXEntries_val)
2653         return ENOMEM;
2654
2655     xInfoP = a_volumeXInfoP->volXEntries_val;
2656     a_volumeXInfoP->volXEntries_len = 0;
2657
2658     /*
2659      * If the partition name we've been given is bad, bogue out.
2660      */
2661     if (GetPartName(a_partID, pname))
2662         return (VOLSERILLEGAL_PARTITION);
2663
2664     /*
2665      * Open the directory representing the given AFS parttion.  If we can't
2666      * do that, we lose.
2667      */
2668     if (!(partP = VGetPartition(pname, 0)))
2669         return VOLSERILLEGAL_PARTITION;
2670     dirp = opendir(VPartitionPath(partP));
2671     if (dirp == NULL)
2672         return (VOLSERILLEGAL_PARTITION);
2673     while (GetNextVol(dirp, volname, &volid)) {
2674         if (a_flags) {
2675             /*
2676              * Full info about the volume desired.  Poll to make sure the
2677              * client doesn't time out, then start up a new transaction.
2678              */
2679 #ifndef AFS_PTHREAD_ENV
2680             IOMGR_Poll();
2681 #endif
2682
2683             handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2684             handle.volinfo_ptr.ext = xInfoP;
2685
2686             code = GetVolInfo(a_partID,
2687                               volid,
2688                               pname,
2689                               volname,
2690                               &handle,
2691                               VOL_INFO_LIST_MULTIPLE);
2692             if (code == -2)     /* DESTROY_ME flag set */
2693                 continue;
2694         } else {
2695             /*
2696              * Just volume IDs are needed.
2697              */
2698             xInfoP->volid = volid;
2699         }
2700
2701         /*
2702          * Bump the pointer in the data area we're building, along with
2703          * the count of the number of entries it contains.
2704          */
2705         xInfoP++;
2706         (a_volumeXInfoP->volXEntries_len)++;
2707         if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2708             /*
2709              * We're running out of space in the area we've built.  Grow it.
2710              */
2711             allocSize = (allocSize * 3) / 2;
2712             xInfoP = (volintXInfo *)
2713                 realloc((char *)a_volumeXInfoP->volXEntries_val,
2714                         (allocSize * sizeof(volintXInfo)));
2715             if (xInfoP == NULL) {
2716                 /*
2717                  * Bummer, no memory. Bag it, tell our caller what went wrong.
2718                  */
2719                 closedir(dirp);
2720                 return (VOLSERNO_MEMORY);
2721             }
2722
2723             /*
2724              * Memory reallocation worked.  Correct our pointers so they
2725              * now point to the new block and the current open position within
2726              * the new block.
2727              */
2728             a_volumeXInfoP->volXEntries_val = xInfoP;
2729             xInfoP =
2730                 a_volumeXInfoP->volXEntries_val +
2731                 a_volumeXInfoP->volXEntries_len;
2732         }
2733     }
2734
2735     /*
2736      * We've examined all entries in the partition directory.  Close it,
2737      * delete our transaction (if any), and go home happy.
2738      */
2739     closedir(dirp);
2740     return (0);
2741
2742 }                               /*SAFSVolXListVolumes */
2743
2744 /*this call is used to monitor the status of volser for debugging purposes.
2745  *information about all the active transactions is returned in transInfo*/
2746 afs_int32
2747 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2748 {
2749     afs_int32 code;
2750
2751     code = VolMonitor(acid, transInfo);
2752     osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2753     return code;
2754 }
2755
2756 static afs_int32
2757 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2758 {
2759     transDebugInfo *pntr;
2760     afs_int32 allocSize = 50;
2761     struct volser_trans *tt, *nt, *allTrans;
2762
2763     transInfo->transDebugEntries_val =
2764         malloc(allocSize * sizeof(transDebugInfo));
2765     if (!transInfo->transDebugEntries_val)
2766         return ENOMEM;
2767     pntr = transInfo->transDebugEntries_val;
2768     transInfo->transDebugEntries_len = 0;
2769
2770     VTRANS_LOCK;
2771     allTrans = TransList();
2772     if (allTrans == (struct volser_trans *)0)
2773         goto done;              /*no active transactions */
2774     for (tt = allTrans; tt; tt = nt) {  /*copy relevant info into pntr */
2775         nt = tt->next;
2776         VTRANS_OBJ_LOCK(tt);
2777         pntr->tid = tt->tid;
2778         pntr->time = tt->time;
2779         pntr->creationTime = tt->creationTime;
2780         pntr->returnCode = tt->returnCode;
2781         pntr->volid = tt->volid;
2782         pntr->partition = tt->partition;
2783         pntr->iflags = tt->iflags;
2784         pntr->vflags = tt->vflags;
2785         pntr->tflags = tt->tflags;
2786         strcpy(pntr->lastProcName, tt->lastProcName);
2787         pntr->callValid = 0;
2788         if (tt->rxCallPtr) {    /*record call related info */
2789             pntr->callValid = 1;
2790 #if 0
2791             pntr->readNext = tt->rxCallPtr->rnext;
2792             pntr->transmitNext = tt->rxCallPtr->tnext;
2793             pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2794             pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2795 #endif
2796         }
2797         VTRANS_OBJ_UNLOCK(tt);
2798         pntr++;
2799         transInfo->transDebugEntries_len += 1;
2800         if ((allocSize - transInfo->transDebugEntries_len) < 5) {       /*alloc some more space */
2801             allocSize = (allocSize * 3) / 2;
2802             pntr = realloc(transInfo->transDebugEntries_val,
2803                            allocSize * sizeof(transDebugInfo));
2804             transInfo->transDebugEntries_val = pntr;
2805             pntr =
2806                 transInfo->transDebugEntries_val +
2807                 transInfo->transDebugEntries_len;
2808             /*set pntr to right position */
2809         }
2810
2811     }
2812 done:
2813     VTRANS_UNLOCK;
2814
2815     return 0;
2816 }
2817
2818 afs_int32
2819 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2820                    afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2821                    afs_uint32 backupId)
2822 {
2823     afs_int32 code;
2824
2825     code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2826     osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2827                AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2828                backupId, AUD_END);
2829     return code;
2830 }
2831
2832 static afs_int32
2833 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2834                afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2835                afs_uint32 backupId)
2836 {
2837     struct Volume *tv;
2838     Error error = 0;
2839     struct volser_trans *tt;
2840     char caller[MAXKTCNAMELEN];
2841
2842     if (strlen(name) > 31)
2843         return VOLSERBADNAME;
2844     if (!afsconf_SuperUser(tdir, acid, caller))
2845         return VOLSERBAD_ACCESS;        /*not a super user */
2846     /* find the trans */
2847     tt = FindTrans(atid);
2848     if (!tt)
2849         return ENOENT;
2850     if (tt->vflags & VTDeleted) {
2851         Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2852         TRELE(tt);
2853         return ENOENT;
2854     }
2855     TSetRxCall(tt, acid, "SetIdsTypes");
2856     tv = tt->volume;
2857
2858     V_type(tv) = type;
2859     V_backupId(tv) = backupId;
2860     V_cloneId(tv) = cloneId;
2861     V_parentId(tv) = pId;
2862     strcpy((&V_disk(tv))->name, name);
2863     VUpdateVolume(&error, tv);
2864     if (error) {
2865         Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2866         LogError(error);
2867         goto fail;
2868     }
2869     TClearRxCall(tt);
2870     if (TRELE(tt) && !error)
2871         return VOLSERTRELE_ERROR;
2872
2873     return error;
2874   fail:
2875     TClearRxCall(tt);
2876     if (TRELE(tt) && !error)
2877         return VOLSERTRELE_ERROR;
2878     return error;
2879 }
2880
2881 afs_int32
2882 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2883 {
2884     afs_int32 code;
2885
2886     code = VolSetDate(acid, atid, cdate);
2887     osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2888                AUD_END);
2889     return code;
2890 }
2891
2892 static afs_int32
2893 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2894 {
2895     struct Volume *tv;
2896     Error error = 0;
2897     struct volser_trans *tt;
2898     char caller[MAXKTCNAMELEN];
2899
2900     if (!afsconf_SuperUser(tdir, acid, caller))
2901         return VOLSERBAD_ACCESS;        /*not a super user */
2902     /* find the trans */
2903     tt = FindTrans(atid);
2904     if (!tt)
2905         return ENOENT;
2906     if (tt->vflags & VTDeleted) {
2907         Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2908         TRELE(tt);
2909         return ENOENT;
2910     }
2911     TSetRxCall(tt, acid, "SetDate");
2912     tv = tt->volume;
2913
2914     V_creationDate(tv) = cdate;
2915     VUpdateVolume(&error, tv);
2916     if (error) {
2917         Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2918         LogError(error);
2919         goto fail;
2920     }
2921     TClearRxCall(tt);
2922     if (TRELE(tt) && !error)
2923         return VOLSERTRELE_ERROR;
2924
2925     return error;
2926   fail:
2927     TClearRxCall(tt);
2928     if (TRELE(tt) && !error)
2929         return VOLSERTRELE_ERROR;
2930     return error;
2931 }
2932
2933 afs_int32
2934 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2935                            afs_uint32 volumeId)
2936 {
2937 #ifdef AFS_NT40_ENV
2938     return EXDEV;
2939 #else
2940     char caller[MAXKTCNAMELEN];
2941     DIR *dirp;
2942     struct volser_trans *ttc;
2943     char pname[16], volname[20];
2944     struct DiskPartition64 *partP;
2945     afs_int32 ret = ENODEV;
2946     afs_uint32 volid;
2947
2948     if (!afsconf_SuperUser(tdir, acid, caller))
2949         return VOLSERBAD_ACCESS;        /*not a super user */
2950     if (GetPartName(partId, pname))
2951         return VOLSERILLEGAL_PARTITION;
2952     if (!(partP = VGetPartition(pname, 0)))
2953         return VOLSERILLEGAL_PARTITION;
2954     dirp = opendir(VPartitionPath(partP));
2955     if (dirp == NULL)
2956         return VOLSERILLEGAL_PARTITION;
2957     ttc = (struct volser_trans *)0;
2958
2959     while (GetNextVol(dirp, volname, &volid)) {
2960         if (volid == volumeId) {        /*copy other things too */
2961 #ifndef AFS_PTHREAD_ENV
2962             IOMGR_Poll();       /*make sure that the client doesnot time out */
2963 #endif
2964             ttc = NewTrans(volumeId, partId);
2965             if (!ttc) {
2966                 return VOLSERVOLBUSY;
2967             }
2968 #ifdef AFS_NAMEI_ENV
2969             ret = namei_ConvertROtoRWvolume(pname, volumeId);
2970 #else
2971             ret = inode_ConvertROtoRWvolume(pname, volumeId);
2972 #endif
2973             break;
2974         }
2975     }
2976
2977     if (ttc) {
2978         DeleteTrans(ttc, 1);
2979         ttc = (struct volser_trans *)0;
2980     }
2981
2982     closedir(dirp);
2983     return ret;
2984 #endif
2985 }
2986
2987 afs_int32
2988 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
2989                struct volintSize *size)
2990 {
2991     int code = 0;
2992     struct volser_trans *tt;
2993     char caller[MAXKTCNAMELEN];
2994
2995     if (!afsconf_SuperUser(tdir, acid, caller))
2996         return VOLSERBAD_ACCESS;        /*not a super user */
2997     tt = FindTrans(fromTrans);
2998     if (!tt)
2999         return ENOENT;
3000     if (tt->vflags & VTDeleted) {
3001         TRELE(tt);
3002         return ENOENT;
3003     }
3004     TSetRxCall(tt, acid, "GetSize");
3005     code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3006     TClearRxCall(tt);
3007     if (TRELE(tt))
3008         return VOLSERTRELE_ERROR;
3009
3010 /*    osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);  */
3011     return code;
3012 }
3013
3014 afs_int32
3015 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3016                    afs_uint32 where, afs_int32 verbose)
3017 {
3018 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3019     Error code, code2;
3020     Volume *vol=0, *newvol=0;
3021     struct volser_trans *tt = 0, *tt2 = 0;
3022     char caller[MAXKTCNAMELEN];
3023     char line[128];
3024
3025     if (!afsconf_SuperUser(tdir, acall, caller))
3026         return EPERM;
3027
3028     vol = VAttachVolume(&code, vid, V_VOLUPD);
3029     if (!vol) {
3030         if (!code)
3031             code = ENOENT;
3032         return code;
3033     }
3034     newvol = VAttachVolume(&code, new, V_VOLUPD);
3035     if (!newvol) {
3036         VDetachVolume(&code2, vol);
3037         if (!code)
3038             code = ENOENT;
3039         return code;
3040     }
3041     if (V_device(vol) != V_device(newvol)
3042         || V_uniquifier(newvol) != 2) {
3043         if (V_device(vol) != V_device(newvol)) {
3044             sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3045                     vid, new);
3046             rx_Write(acall, line, strlen(line));
3047         }
3048         if (V_uniquifier(newvol) != 2) {
3049             sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3050             rx_Write(acall, line, strlen(line));
3051         }
3052         line[0] = 0;
3053         rx_Write(acall, line, 1);
3054         VDetachVolume(&code2, vol);
3055         VDetachVolume(&code2, newvol);
3056         return EINVAL;
3057     }
3058     tt = NewTrans(vid, V_device(vol));
3059     if (!tt) {
3060         sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3061         rx_Write(acall, line, strlen(line));
3062         line[0] = 0;
3063         rx_Write(acall, line, 1);
3064         VDetachVolume(&code2, vol);
3065         VDetachVolume(&code2, newvol);
3066         return VOLSERVOLBUSY;
3067     }
3068     VTRANS_OBJ_LOCK(tt);
3069     tt->iflags = ITBusy;
3070     tt->vflags = 0;
3071     TSetRxCall_r(tt, NULL, "SplitVolume");
3072     VTRANS_OBJ_UNLOCK(tt);
3073
3074     tt2 = NewTrans(new, V_device(newvol));
3075     if (!tt2) {
3076         sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3077         rx_Write(acall, line, strlen(line));
3078         line[0] = 0;
3079         rx_Write(acall, line, 1);
3080         DeleteTrans(tt, 1);
3081         VDetachVolume(&code2, vol);
3082         VDetachVolume(&code2, newvol);
3083         return VOLSERVOLBUSY;
3084     }
3085     VTRANS_OBJ_LOCK(tt2);
3086     tt2->iflags = ITBusy;
3087     tt2->vflags = 0;
3088     TSetRxCall_r(tt2, NULL, "SplitVolume");
3089     VTRANS_OBJ_UNLOCK(tt2);
3090
3091     code = split_volume(acall, vol, newvol, where, verbose);
3092
3093     VDetachVolume(&code2, vol);
3094     DeleteTrans(tt, 1);
3095     VDetachVolume(&code2, newvol);
3096     DeleteTrans(tt2, 1);
3097     return code;
3098 #else
3099     return VOLSERBADOP;
3100 #endif
3101 }
3102
3103 /* GetPartName - map partid (a decimal number) into pname (a string)
3104  * Since for NT we actually want to return the drive name, we map through the
3105  * partition struct.
3106  */
3107 static int
3108 GetPartName(afs_int32 partid, char *pname)
3109 {
3110     if (partid < 0)
3111         return -1;
3112     if (partid < 26) {
3113         strcpy(pname, "/vicep");
3114         pname[6] = 'a' + partid;
3115         pname[7] = '\0';
3116         return 0;
3117     } else if (partid < VOLMAXPARTS) {
3118         strcpy(pname, "/vicep");
3119         partid -= 26;
3120         pname[6] = 'a' + (partid / 26);
3121         pname[7] = 'a' + (partid % 26);
3122         pname[8] = '\0';
3123         return 0;
3124     } else
3125         return -1;
3126 }