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