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