Use calloc, rather than malloc/memset
[openafs.git] / src / volser / volprocs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  *
9  * Portions Copyright (c) 2007-2008 Sine Nomine Associates
10  */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15 #include <roken.h>
16
17 #include <rx/xdr.h>
18 #include <rx/rx.h>
19 #include <rx/rxkad.h>
20 #include <afs/afsint.h>
21 #include <afs/prs_fs.h>
22 #include <afs/nfs.h>
23 #include <lwp.h>
24 #include <lock.h>
25 #include <afs/cellconfig.h>
26 #include <afs/keys.h>
27 #include <ubik.h>
28 #include <afs/ihandle.h>
29 #ifdef AFS_NT40_ENV
30 #include <afs/ntops.h>
31 #endif
32 #include <afs/vnode.h>
33 #include <afs/volume.h>
34 #include <afs/volume_inline.h>
35 #include <afs/partition.h>
36 #include "vol.h"
37 #include <afs/daemon_com.h>
38 #include <afs/fssync.h>
39 #include <afs/acl.h>
40 #include "afs/audit.h"
41 #include <afs/dir.h>
42 #include <afs/afsutil.h>
43 #include <afs/com_err.h>
44 #include <afs/vol_prototypes.h>
45 #include <afs/errors.h>
46
47 #include "volser.h"
48 #include "voltrans_inline.h"
49 #include "volint.h"
50
51 #include "volser_internal.h"
52 #include "physio.h"
53 #include "dumpstuff.h"
54
55 extern int DoLogging;
56 extern struct afsconf_dir *tdir;
57 extern int DoPreserveVolumeStats;
58
59 extern void LogError(afs_int32 errcode);
60
61 /* Forward declarations */
62 static int GetPartName(afs_int32 partid, char *pname);
63
64 #define OneDay (24*60*60)
65
66 #ifdef AFS_NT40_ENV
67 #define ENOTCONN 134
68 #endif
69
70 afs_int32 localTid = 1;
71
72 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
73                                   struct diskPartition64 *);
74 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
75 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
76                                  afs_int32, afs_uint32, afs_uint32 *,
77                                  afs_int32 *);
78 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
79 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
80                           afs_int32, char *, afs_uint32 *);
81 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
82 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
83                                 afs_int32, afs_int32 *);
84 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
85                                  afs_int32 *);
86 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
87 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
88 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
89                             struct destServer *destination, afs_int32,
90                             struct restoreCookie *cookie);
91 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
92 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
93                             struct restoreCookie *);
94 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
95 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
96 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
97                               struct volser_status *);
98 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
99 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
100 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
101 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
102 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
103                                   volEntries *);
104 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
105                                    volXEntries *);
106 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
107                                 volEntries *);
108 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
109                                 volXEntries *);
110 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
111 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
112                                 afs_int32, afs_uint32, afs_uint32,
113                                 afs_uint32);
114 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
115
116 /**
117  * Return the host address of the caller as a string.
118  *
119  * @param[in]  acid    incoming rx call
120  * @param[out] buffer  buffer to be filled with the addess string
121  *
122  * @return address as formatted by inet_ntoa
123  */
124 static_inline char *
125 callerAddress(struct rx_call *acid, char *buffer)
126 {
127     afs_uint32 ip = rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid)));
128     return afs_inet_ntoa_r(ip, buffer);
129 }
130
131 /* this call unlocks all of the partition locks we've set */
132 int
133 VPFullUnlock_r(void)
134 {
135     struct DiskPartition64 *tp;
136     for (tp = DiskPartitionList; tp; tp = tp->next) {
137         if (tp->lock_fd != INVALID_FD) {
138             OS_CLOSE(tp->lock_fd);
139             tp->lock_fd = INVALID_FD;
140         }
141     }
142     return 0;
143 }
144
145 int
146 VPFullUnlock(void)
147 {
148     int code;
149     VOL_LOCK;
150     code = VPFullUnlock_r();
151     VOL_UNLOCK;
152     return code;
153 }
154
155 /* get partition id from a name */
156 afs_int32
157 PartitionID(char *aname)
158 {
159     char tc;
160     int code = 0;
161     char ascii[3];
162
163     tc = *aname;
164     if (tc == 0)
165         return -1;              /* unknown */
166
167     /* otherwise check for vicepa or /vicepa, or just plain "a" */
168     ascii[2] = 0;
169     if (!strncmp(aname, "/vicep", 6)) {
170         strncpy(ascii, aname + 6, 2);
171     } else
172         return -1;              /* bad partition name */
173     /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
174      * from 0.  Do the appropriate conversion */
175     if (ascii[1] == 0) {
176         /* one char name, 0..25 */
177         if (ascii[0] < 'a' || ascii[0] > 'z')
178             return -1;          /* wrongo */
179         return ascii[0] - 'a';
180     } else {
181         /* two char name, 26 .. <whatever> */
182         if (ascii[0] < 'a' || ascii[0] > 'z')
183             return -1;          /* wrongo */
184         if (ascii[1] < 'a' || ascii[1] > 'z')
185             return -1;          /* just as bad */
186         code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
187         if (code > VOLMAXPARTS)
188             return -1;
189         return code;
190     }
191 }
192
193 static int
194 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
195 {
196     if (asize < 18)
197         return -1;
198     /* It's better using the Generic VFORMAT since otherwise we have to make changes to too many places... The 14 char limitation in names hits us again in AIX; print in field of 9 digits (still 10 for the rest), right justified with 0 padding */
199     snprintf(aname, asize, VFORMAT, (unsigned long)avol);
200     return 0;
201 }
202
203 static int
204 ConvertPartition(int apartno, char *aname, int asize)
205 {
206     if (asize < 10)
207         return E2BIG;
208     if (apartno < 0)
209         return EINVAL;
210     strcpy(aname, "/vicep");
211     if (apartno < 26) {
212         aname[6] = 'a' + apartno;
213         aname[7] = 0;
214     } else {
215         apartno -= 26;
216         aname[6] = 'a' + (apartno / 26);
217         aname[7] = 'a' + (apartno % 26);
218         aname[8] = 0;
219     }
220     return 0;
221 }
222
223 #ifdef AFS_DEMAND_ATTACH_FS
224 /* normally we should use the regular salvaging functions from the volume
225  * package, but this is a special case where we have a volume ID, but no
226  * volume structure to give the volume package */
227 static void
228 SalvageUnknownVolume(VolumeId volid, char *part)
229 {
230     afs_int32 code;
231
232     Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
233         afs_printable_uint32_lu(volid), part);
234
235     code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
236                        FSYNC_SALVAGE, NULL);
237     if (code) {
238         Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
239             afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
240             part);
241     }
242 }
243 #endif /* AFS_DEMAND_ATTACH_FS */
244
245 static struct Volume *
246 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
247 {
248     struct Volume *vp;
249
250     *ec = 0;
251     vp = VAttachVolumeByName(ec, partition, name, mode);
252
253 #ifdef AFS_DEMAND_ATTACH_FS
254     {
255         int i;
256         /*
257          * The fileserver will take care of keeping track of how many
258          * demand-salvages have been performed, and will force the volume to
259          * ERROR if we've done too many. The limit on This loop is just a
260          * failsafe to prevent trying to salvage forever. We want to attempt
261          * attachment at least SALVAGE_COUNT_MAX times, since we want to
262          * avoid prematurely exiting this loop, if we can.
263          */
264         for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
265             sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
266             vp = VAttachVolumeByName(ec, partition, name, mode);
267         }
268
269         if (*ec == VSALVAGING) {
270             *ec = VSALVAGE;
271         }
272     }
273 #endif /* AFS_DEMAND_ATTACH_FS */
274
275     return vp;
276 }
277
278 static struct Volume *
279 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
280 {
281     struct Volume *vp;
282
283     *ec = 0;
284     vp = VAttachVolume(ec, avolid, amode);
285
286 #ifdef AFS_DEMAND_ATTACH_FS
287     {
288         int i;
289         /* see comment above in VAttachVolumeByName_retry */
290         for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
291             sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
292             vp = VAttachVolume(ec, avolid, amode);
293         }
294
295         if (*ec == VSALVAGING) {
296             *ec = VSALVAGE;
297         }
298     }
299 #endif /* AFS_DEMAND_ATTACH_FS */
300
301     return vp;
302 }
303
304 /* the only attach function that takes a partition is "...ByName", so we use it */
305 static struct Volume *
306 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
307 {
308     char pbuf[30], vbuf[20];
309
310     if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
311         *error = EINVAL;
312         return NULL;
313     }
314     if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
315         *error = EINVAL;
316         return NULL;
317     }
318
319     return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
320 }
321
322 /* Adapted from the file server; create a root directory for this volume */
323 static Error
324 ViceCreateRoot(Volume *vp)
325 {
326     DirHandle dir;
327     struct acl_accessList *ACL;
328     AFSFid did;
329     Inode inodeNumber, AFS_UNUSED nearInode;
330     struct VnodeDiskObject *vnode;
331     struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
332     IHandle_t *h;
333     FdHandle_t *fdP;
334     afs_fsize_t length;
335     ssize_t nBytes;
336
337     vnode = calloc(1, SIZEOF_LARGEDISKVNODE);
338     if (!vnode)
339         return ENOMEM;
340
341     V_pref(vp, nearInode);
342     inodeNumber =
343         IH_CREATE(V_linkHandle(vp), V_device(vp),
344                   VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
345                   1, 1, 0);
346     if (!VALID_INO(inodeNumber)) {
347         Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
348         free(vnode);
349         return EIO;
350     }
351
352     SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
353     did.Volume = V_id(vp);
354     did.Vnode = (VnodeId) 1;
355     did.Unique = 1;
356
357     osi_Assert(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
358     DFlush();                   /* flush all modified dir buffers out */
359     DZap(&dir);                 /* Remove all buffers for this dir */
360     length = afs_dir_Length(&dir);      /* Remember size of this directory */
361
362     FidZap(&dir);               /* Done with the dir handle obtained via SetSalvageDirHandle() */
363
364     /* build a single entry ACL that gives all rights to system:administrators */
365     /* this section of code assumes that access list format is not going to
366      * change
367      */
368     ACL = VVnodeDiskACL(vnode);
369     ACL->size = sizeof(struct acl_accessList);
370     ACL->version = ACL_ACLVERSION;
371     ACL->total = 1;
372     ACL->positive = 1;
373     ACL->negative = 0;
374     ACL->entries[0].id = -204;  /* this assumes System:administrators is group -204 */
375     ACL->entries[0].rights =
376         PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
377         | PRSFS_LOCK | PRSFS_ADMINISTER;
378
379     vnode->type = vDirectory;
380     vnode->cloned = 0;
381     vnode->modeBits = 0777;
382     vnode->linkCount = 2;
383     VNDISK_SET_LEN(vnode, length);
384     vnode->uniquifier = 1;
385     V_uniquifier(vp) = vnode->uniquifier + 1;
386     vnode->dataVersion = 1;
387     VNDISK_SET_INO(vnode, inodeNumber);
388     vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
389     vnode->author = 0;
390     vnode->owner = 0;
391     vnode->parent = 0;
392     vnode->vnodeMagic = vcp->magic;
393
394     IH_INIT(h, vp->device, V_parentId(vp),
395             vp->vnodeIndex[vLarge].handle->ih_ino);
396     fdP = IH_OPEN(h);
397     osi_Assert(fdP != NULL);
398     nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
399     osi_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
400     FDH_REALLYCLOSE(fdP);
401     IH_RELEASE(h);
402     VNDISK_GET_LEN(length, vnode);
403     V_diskused(vp) = nBlocks(length);
404
405     free(vnode);
406     return 0;
407 }
408
409 afs_int32
410 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
411                      *partition)
412 {
413     afs_int32 code;
414     struct diskPartition64 *dp = (struct diskPartition64 *)
415         malloc(sizeof(struct diskPartition64));
416
417     code = VolPartitionInfo(acid, pname, dp);
418     if (!code) {
419         strncpy(partition->name, dp->name, 32);
420         strncpy(partition->devName, dp->devName, 32);
421         partition->lock_fd = dp->lock_fd;
422         partition->free=RoundInt64ToInt32(dp->free);
423         partition->minFree=RoundInt64ToInt32(dp->minFree);
424     }
425     free(dp);
426     osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
427     return code;
428 }
429
430 afs_int32
431 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
432                      *partition)
433 {
434     afs_int32 code;
435
436     code = VolPartitionInfo(acid, pname, partition);
437     osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
438     return code;
439 }
440
441 afs_int32
442 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
443                  *partition)
444 {
445     struct DiskPartition64 *dp;
446
447 /*
448     if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
449 */
450     VResetDiskUsage();
451     dp = VGetPartition(pname, 0);
452     if (dp) {
453         strncpy(partition->name, dp->name, 32);
454         strncpy(partition->devName, dp->devName, 32);
455         partition->lock_fd = (int)dp->lock_fd;
456         partition->free = dp->free;
457         partition->minFree = dp->totalUsable;
458         return 0;
459     } else
460         return VOLSERILLEGAL_PARTITION;
461 }
462
463 /* obliterate a volume completely, and slowly. */
464 afs_int32
465 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
466 {
467     afs_int32 code;
468
469     code = VolNukeVolume(acid, apartID, avolID);
470     osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
471     return code;
472 }
473
474 static afs_int32
475 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
476 {
477     char partName[50];
478     afs_int32 error;
479     Error verror;
480     afs_int32 code;
481     struct Volume *tvp;
482     char caller[MAXKTCNAMELEN];
483
484     /* check for access */
485     if (!afsconf_SuperUser(tdir, acid, caller))
486         return VOLSERBAD_ACCESS;
487     if (DoLogging) {
488         char buffer[16];
489         Log("%s on %s is executing VolNukeVolume %u\n", caller,
490             callerAddress(acid, buffer), avolID);
491     }
492
493     if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
494         return VOLSERNOVOL;
495     /* we first try to attach the volume in update mode, so that the file
496      * server doesn't try to use it (and abort) while (or after) we delete it.
497      * If we don't get the volume, that's fine, too.  We just won't put it back.
498      */
499     tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
500     code = nuke(partName, avolID);
501     if (tvp)
502         VDetachVolume(&verror, tvp);
503     return code;
504 }
505
506 /* create a new volume, with name aname, on the specified partition (1..n)
507  * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
508  * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
509  * for the volume id (useful for things like volume restore).
510  * Return the new volume id in *avolid.
511  */
512 afs_int32
513 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
514                     afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
515                     afs_int32 *atrans)
516 {
517     afs_int32 code;
518
519     code =
520         VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
521     osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
522                *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
523                AUD_END);
524     return code;
525 }
526
527 static afs_int32
528 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
529                     afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
530                     afs_int32 *atrans)
531 {
532     Error error;
533     Volume *vp;
534     Error junk;         /* discardable error code */
535     afs_uint32 volumeID;
536     afs_int32 doCreateRoot = 1;
537     struct volser_trans *tt;
538     char ppath[30];
539     char caller[MAXKTCNAMELEN];
540
541     if (strlen(aname) > 31)
542         return VOLSERBADNAME;
543     if (!afsconf_SuperUser(tdir, acid, caller))
544         return VOLSERBAD_ACCESS;
545     if (DoLogging) {
546         char buffer[16];
547         Log("%s on %s is executing CreateVolume '%s'\n", caller,
548             callerAddress(acid, buffer), aname);
549     }
550     if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
551         return error;           /*a standard unix error */
552     if (atype != readwriteVolume && atype != readonlyVolume
553         && atype != backupVolume)
554         return EINVAL;
555     if ((volumeID = *avolid) == 0) {
556
557         Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
558         return E2BIG;
559
560     }
561     if ((aparent == volumeID) && (atype == readwriteVolume)) {
562         doCreateRoot = 0;
563     }
564     if (aparent == 0)
565         aparent = volumeID;
566     tt = NewTrans(volumeID, apart);
567     if (!tt) {
568         Log("1 createvolume: failed to create trans\n");
569         return VOLSERVOLBUSY;   /* volume already busy! */
570     }
571     vp = VCreateVolume(&error, ppath, volumeID, aparent);
572     if (error) {
573 #ifdef AFS_DEMAND_ATTACH_FS
574         if (error != VVOLEXISTS && error != EXDEV) {
575             SalvageUnknownVolume(volumeID, ppath);
576         }
577 #endif
578         Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
579         LogError(error);
580         DeleteTrans(tt, 1);
581         return EIO;
582     }
583     V_uniquifier(vp) = 1;
584     V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
585     V_inService(vp) = V_blessed(vp) = 1;
586     V_type(vp) = atype;
587     AssignVolumeName(&V_disk(vp), aname, 0);
588     if (doCreateRoot) {
589         error = ViceCreateRoot(vp);
590         if (error) {
591             Log("1 Volser: CreateVolume: Unable to create volume root dir; "
592                 "error code %u\n", (unsigned)error);
593             DeleteTrans(tt, 1);
594             V_needsSalvaged(vp) = 1;
595             VDetachVolume(&junk, vp);
596             return EIO;
597         }
598     }
599     V_destroyMe(vp) = DESTROY_ME;
600     V_inService(vp) = 0;
601     V_maxquota(vp) = 5000;      /* set a quota of 5000 at init time */
602     VUpdateVolume(&error, vp);
603     if (error) {
604         Log("1 Volser: create UpdateVolume failed, code %d\n", error);
605         LogError(error);
606         DeleteTrans(tt, 1);
607         VDetachVolume(&junk, vp);       /* rather return the real error code */
608         return error;
609     }
610     VTRANS_OBJ_LOCK(tt);
611     tt->volume = vp;
612     *atrans = tt->tid;
613     TSetRxCall_r(tt, acid, "CreateVolume");
614     VTRANS_OBJ_UNLOCK(tt);
615     Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
616     TClearRxCall(tt);
617     if (TRELE(tt))
618         return VOLSERTRELE_ERROR;
619     return 0;
620 }
621
622 /* delete the volume associated with this transaction */
623 afs_int32
624 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
625 {
626     afs_int32 code;
627
628     code = VolDeleteVolume(acid, atrans);
629     osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
630     return code;
631 }
632
633 static afs_int32
634 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
635 {
636     struct volser_trans *tt;
637     Error error;
638     char caller[MAXKTCNAMELEN];
639
640     if (!afsconf_SuperUser(tdir, acid, caller))
641         return VOLSERBAD_ACCESS;
642     tt = FindTrans(atrans);
643     if (!tt)
644         return ENOENT;
645     if (tt->vflags & VTDeleted) {
646         Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
647         TRELE(tt);
648         return ENOENT;
649     }
650     if (DoLogging) {
651         char buffer[16];
652         Log("%s on %s is executing Delete Volume %u\n", caller,
653             callerAddress(acid, buffer), tt->volid);
654     }
655     TSetRxCall(tt, acid, "DeleteVolume");
656     VPurgeVolume(&error, tt->volume);   /* don't check error code, it is not set! */
657     V_destroyMe(tt->volume) = DESTROY_ME;
658     if (tt->volume->needsPutBack) {
659         tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
660     }
661     VTRANS_OBJ_LOCK(tt);
662     tt->vflags |= VTDeleted;    /* so we know not to do anything else to it */
663     TClearRxCall_r(tt);
664     VTRANS_OBJ_UNLOCK(tt);
665     if (TRELE(tt))
666         return VOLSERTRELE_ERROR;
667
668     Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
669     return 0;                   /* vpurgevolume doesn't set an error code */
670 }
671
672 /* make a clone of the volume associated with atrans, possibly giving it a new
673  * number (allocate a new number if *newNumber==0, otherwise use *newNumber
674  * for the clone's id).  The new clone is given the name newName.  Finally,
675  * due to efficiency considerations, if purgeId is non-zero, we purge that
676  * volume when doing the clone operation.  This may be useful when making
677  * new backup volumes, for instance since the net result of a clone and a
678  * purge generally leaves many inode ref counts the same, while doing them
679  * separately would result in far more iincs and idecs being peformed
680  * (and they are slow operations).
681  */
682 /* for efficiency reasons, sometimes faster to piggyback a purge here */
683 afs_int32
684 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
685              afs_int32 newType, char *newName, afs_uint32 *newNumber)
686 {
687     afs_int32 code;
688
689     code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
690     osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
691                AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
692                AUD_END);
693     return code;
694 }
695
696 static afs_int32
697 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
698              afs_int32 newType, char *newName, afs_uint32 *newNumber)
699 {
700     afs_uint32 newId;
701     struct Volume *originalvp, *purgevp, *newvp;
702     Error error, code;
703     struct volser_trans *tt, *ttc;
704     char caller[MAXKTCNAMELEN];
705 #ifdef AFS_DEMAND_ATTACH_FS
706     struct Volume *salv_vp = NULL;
707 #endif
708
709     if (strlen(newName) > 31)
710         return VOLSERBADNAME;
711     if (!afsconf_SuperUser(tdir, acid, caller))
712         return VOLSERBAD_ACCESS;        /*not a super user */
713     if (DoLogging) {
714         char buffer[16];
715         Log("%s on %s is executing Clone Volume new name=%s\n", caller,
716             callerAddress(acid, buffer), newName);
717     }
718     error = 0;
719     originalvp = (Volume *) 0;
720     purgevp = (Volume *) 0;
721     newvp = (Volume *) 0;
722     tt = ttc = (struct volser_trans *)0;
723
724     if (!newNumber || !*newNumber) {
725         Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
726         goto fail;
727     }
728     newId = *newNumber;
729
730     tt = FindTrans(atrans);
731     if (!tt)
732         return ENOENT;
733     if (tt->vflags & VTDeleted) {
734         Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
735         TRELE(tt);
736         return ENOENT;
737     }
738     ttc = NewTrans(newId, tt->partition);
739     if (!ttc) {                 /* someone is messing with the clone already */
740         TRELE(tt);
741         return VOLSERVOLBUSY;
742     }
743     TSetRxCall(tt, acid, "Clone");
744
745
746     if (purgeId) {
747         purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
748         if (error) {
749             Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
750             goto fail;
751         }
752     } else {
753         purgevp = NULL;
754     }
755     originalvp = tt->volume;
756     if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
757         Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
758             V_id(originalvp));
759         error = VOFFLINE;
760         goto fail;
761     }
762     if (purgevp) {
763         if (originalvp->device != purgevp->device) {
764             Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
765             error = EXDEV;
766             goto fail;
767         }
768         if (V_type(purgevp) != readonlyVolume) {
769             Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
770             error = EINVAL;
771             goto fail;
772         }
773         if (V_parentId(originalvp) != V_parentId(purgevp)) {
774             Log("1 Volser: Clone: Volume %u and volume %u were not originally cloned from the same parent; aborted\n", purgeId, tt->volid);
775             error = EXDEV;
776             goto fail;
777         }
778     }
779
780     error = 0;
781 #ifdef AFS_DEMAND_ATTACH_FS
782     salv_vp = originalvp;
783 #endif
784
785     if (purgeId == newId) {
786         newvp = purgevp;
787     } else {
788         newvp =
789             VCreateVolume(&error, originalvp->partition->name, newId,
790                           V_parentId(originalvp));
791         if (error) {
792             Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
793             newvp = (Volume *) 0;
794             goto fail;
795         }
796     }
797     if (newType == readonlyVolume)
798         V_cloneId(originalvp) = newId;
799     Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
800         newId);
801     if (purgevp)
802         Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
803     CloneVolume(&error, originalvp, newvp, purgevp);
804     purgevp = NULL;             /* clone releases it, maybe even if error */
805     if (error) {
806         Log("1 Volser: Clone: clone operation failed with code %u\n", error);
807         LogError(error);
808         goto fail;
809     }
810     if (newType == readonlyVolume) {
811         AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
812         V_type(newvp) = readonlyVolume;
813     } else if (newType == backupVolume) {
814         AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
815         V_type(newvp) = backupVolume;
816         V_backupId(originalvp) = newId;
817     }
818     strcpy(newvp->header->diskstuff.name, newName);
819     V_creationDate(newvp) = V_copyDate(newvp);
820     ClearVolumeStats(&V_disk(newvp));
821     V_destroyMe(newvp) = DESTROY_ME;
822     V_inService(newvp) = 0;
823     if (newType == backupVolume) {
824         V_backupDate(originalvp) = V_copyDate(newvp);
825         V_backupDate(newvp) = V_copyDate(newvp);
826     }
827     V_inUse(newvp) = 0;
828     VUpdateVolume(&error, newvp);
829     if (error) {
830         Log("1 Volser: Clone: VUpdate failed code %u\n", error);
831         LogError(error);
832         goto fail;
833     }
834     VDetachVolume(&error, newvp);       /* allow file server to get it's hands on it */
835     newvp = NULL;
836     VUpdateVolume(&error, originalvp);
837     if (error) {
838         Log("1 Volser: Clone: original update %u\n", error);
839         LogError(error);
840         goto fail;
841     }
842     TClearRxCall(tt);
843 #ifdef AFS_DEMAND_ATTACH_FS
844     salv_vp = NULL;
845 #endif
846     if (TRELE(tt)) {
847         tt = (struct volser_trans *)0;
848         error = VOLSERTRELE_ERROR;
849         goto fail;
850     }
851     DeleteTrans(ttc, 1);
852     return 0;
853
854   fail:
855     if (purgevp)
856         VDetachVolume(&code, purgevp);
857     if (newvp)
858         VDetachVolume(&code, newvp);
859     if (tt) {
860         TClearRxCall(tt);
861         TRELE(tt);
862     }
863     if (ttc)
864         DeleteTrans(ttc, 1);
865 #ifdef AFS_DEMAND_ATTACH_FS
866     if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
867         V_needsSalvaged(salv_vp) = 1;
868     }
869 #endif /* AFS_DEMAND_ATTACH_FS */
870     return error;
871 }
872
873 /* reclone this volume into the specified id */
874 afs_int32
875 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
876 {
877     afs_int32 code;
878
879     code = VolReClone(acid, atrans, cloneId);
880     osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
881                cloneId, AUD_END);
882     return code;
883 }
884
885 static afs_int32
886 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
887 {
888     struct Volume *originalvp, *clonevp;
889     Error error, code;
890     afs_int32 newType;
891     struct volser_trans *tt, *ttc;
892     char caller[MAXKTCNAMELEN];
893     VolumeDiskData saved_header;
894
895     /*not a super user */
896     if (!afsconf_SuperUser(tdir, acid, caller))
897         return VOLSERBAD_ACCESS;
898     if (DoLogging) {
899         char buffer[16];
900         Log("%s on %s is executing Reclone Volume %u\n", caller,
901             callerAddress(acid, buffer), cloneId);
902     }
903     error = 0;
904     clonevp = originalvp = (Volume *) 0;
905     tt = (struct volser_trans *)0;
906
907     tt = FindTrans(atrans);
908     if (!tt)
909         return ENOENT;
910     if (tt->vflags & VTDeleted) {
911         Log("1 Volser: VolReClone: volume %u has been deleted \n", 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 %d is offline and cannot be cloned\n",
925             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 %d\n", 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 %u and %u are on different devices\n",
940             tt->volid, cloneId);
941         error = EXDEV;
942         goto fail;
943     }
944     if (V_parentId(originalvp) != V_parentId(clonevp)) {
945         Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, 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 %u to volume %u\n", tt->volid,
956         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, afs_uint32 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, afs_uint32 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, afs_uint32 *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 %u has been deleted \n",
1153             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 %u has been deleted \n",
1197             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     /* initialize things */
1268     tcon = (struct rx_connection *)0;
1269     tt = (struct volser_trans *)0;
1270
1271     /* find the local transaction */
1272     tt = FindTrans(fromTrans);
1273     if (!tt)
1274         return ENOENT;
1275     if (tt->vflags & VTDeleted) {
1276         Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1277         TRELE(tt);
1278         return ENOENT;
1279     }
1280     vp = tt->volume;
1281     TSetRxCall(tt, NULL, "Forward");
1282
1283     /* get auth info for the this connection (uses afs from ticket file) */
1284     code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1285     if (code) {
1286         TRELE(tt);
1287         return code;
1288     }
1289
1290     /* make an rpc connection to the other server */
1291     tcon =
1292         rx_NewConnection(htonl(destination->destHost),
1293                          htons(destination->destPort), VOLSERVICE_ID,
1294                          securityObject, securityIndex);
1295     if (!tcon) {
1296         TClearRxCall(tt);
1297         TRELE(tt);
1298         return ENOTCONN;
1299     }
1300     tcall = rx_NewCall(tcon);
1301     TSetRxCall(tt, tcall, "Forward");
1302     /* start restore going.  fromdate == 0 --> doing an incremental dump/restore */
1303     code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1304     if (code) {
1305         goto fail;
1306     }
1307
1308     /* these next calls implictly call rx_Write when writing out data */
1309     code = DumpVolume(tcall, vp, fromDate, 0);  /* last field = don't dump all dirs */
1310     if (code)
1311         goto fail;
1312     EndAFSVolRestore(tcall);    /* probably doesn't do much */
1313     TClearRxCall(tt);
1314     code = rx_EndCall(tcall, 0);
1315     rx_DestroyConnection(tcon); /* done with the connection */
1316     tcon = NULL;
1317     if (code)
1318         goto fail;
1319     if (TRELE(tt))
1320         return VOLSERTRELE_ERROR;
1321
1322     return 0;
1323
1324   fail:
1325     if (tcon) {
1326         (void)rx_EndCall(tcall, 0);
1327         rx_DestroyConnection(tcon);
1328     }
1329     if (tt) {
1330         TClearRxCall(tt);
1331         TRELE(tt);
1332     }
1333     return code;
1334 }
1335
1336 /* Start a dump and send it to multiple places simultaneously.
1337  * If this returns an error (eg, return ENOENT), it means that
1338  * none of the releases worked.  If this returns 0, that means
1339  * that one or more of the releases worked, and the caller has
1340  * to examine the results array to see which one(s).
1341  * This will only do EITHER incremental or full, not both, so it's
1342  * the caller's responsibility to be sure that all the destinations
1343  * need just an incremental (and from the same time), if that's
1344  * what we're doing.
1345  */
1346 afs_int32
1347 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1348                        fromDate, manyDests *destinations, afs_int32 spare,
1349                        struct restoreCookie *cookie, manyResults *results)
1350 {
1351     afs_int32 securityIndex;
1352     struct rx_securityClass *securityObject;
1353     char caller[MAXKTCNAMELEN];
1354     struct volser_trans *tt;
1355     afs_int32 ec, code, *codes;
1356     struct rx_connection **tcons;
1357     struct rx_call **tcalls;
1358     struct Volume *vp;
1359     int i, is_incremental;
1360
1361     if (results) {
1362         memset(results, 0, sizeof(manyResults));
1363         i = results->manyResults_len = destinations->manyDests_len;
1364         results->manyResults_val = codes =
1365           (afs_int32 *) malloc(i * sizeof(afs_int32));
1366     }
1367     if (!results || !results->manyResults_val)
1368         return ENOMEM;
1369
1370     if (!afsconf_SuperUser(tdir, acid, caller))
1371         return VOLSERBAD_ACCESS;        /*not a super user */
1372     tt = FindTrans(fromTrans);
1373     if (!tt)
1374         return ENOENT;
1375     if (tt->vflags & VTDeleted) {
1376         Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1377         TRELE(tt);
1378         return ENOENT;
1379     }
1380     vp = tt->volume;
1381     TSetRxCall(tt, NULL, "ForwardMulti");
1382
1383     /* (fromDate == 0) ==> full dump */
1384     is_incremental = (fromDate ? 1 : 0);
1385
1386     tcons =
1387         (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1388     if (!tcons) {
1389         return ENOMEM;
1390     }
1391     tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1392     if (!tcalls) {
1393         free(tcons);
1394         return ENOMEM;
1395     }
1396
1397     /* get auth info for this connection (uses afs from ticket file) */
1398     code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1399     if (code) {
1400         goto fail;              /* in order to audit each failure */
1401     }
1402
1403     /* make connections to all the other servers */
1404     for (i = 0; i < destinations->manyDests_len; i++) {
1405         struct replica *dest = &(destinations->manyDests_val[i]);
1406         tcons[i] =
1407             rx_NewConnection(htonl(dest->server.destHost),
1408                              htons(dest->server.destPort), VOLSERVICE_ID,
1409                              securityObject, securityIndex);
1410         if (!tcons[i]) {
1411             codes[i] = ENOTCONN;
1412         } else {
1413             if (!(tcalls[i] = rx_NewCall(tcons[i])))
1414                 codes[i] = ENOTCONN;
1415             else {
1416                 codes[i] =
1417                     StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1418                                        cookie);
1419                 if (codes[i]) {
1420                     (void)rx_EndCall(tcalls[i], 0);
1421                     tcalls[i] = 0;
1422                     rx_DestroyConnection(tcons[i]);
1423                     tcons[i] = 0;
1424                 }
1425             }
1426         }
1427     }
1428
1429     /* these next calls implictly call rx_Write when writing out data */
1430     code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1431
1432
1433   fail:
1434     for (i--; i >= 0; i--) {
1435         struct replica *dest = &(destinations->manyDests_val[i]);
1436
1437         if (!code && tcalls[i] && !codes[i]) {
1438             EndAFSVolRestore(tcalls[i]);
1439         }
1440         if (tcalls[i]) {
1441             ec = rx_EndCall(tcalls[i], 0);
1442             if (!codes[i])
1443                 codes[i] = ec;
1444         }
1445         if (tcons[i]) {
1446             rx_DestroyConnection(tcons[i]);     /* done with the connection */
1447         }
1448
1449         osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1450                    fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1451                    dest->trans, AUD_END);
1452     }
1453     free(tcons);
1454     free(tcalls);
1455
1456     if (tt) {
1457         TClearRxCall(tt);
1458         if (TRELE(tt) && !code) /* return the first code if it's set */
1459             return VOLSERTRELE_ERROR;
1460     }
1461
1462     return code;
1463 }
1464
1465 afs_int32
1466 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1467 {
1468     afs_int32 code;
1469
1470     code = VolDump(acid, fromTrans, fromDate, 0);
1471     osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1472     return code;
1473 }
1474
1475 afs_int32
1476 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1477               afs_int32 flags)
1478 {
1479     afs_int32 code;
1480
1481     code = VolDump(acid, fromTrans, fromDate, flags);
1482     osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1483     return code;
1484 }
1485
1486 static afs_int32
1487 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1488         afs_int32 flags)
1489 {
1490     int code = 0;
1491     struct volser_trans *tt;
1492     char caller[MAXKTCNAMELEN];
1493
1494     if (!afsconf_SuperUser(tdir, acid, caller))
1495         return VOLSERBAD_ACCESS;        /*not a super user */
1496     tt = FindTrans(fromTrans);
1497     if (!tt)
1498         return ENOENT;
1499     if (tt->vflags & VTDeleted) {
1500         Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1501         TRELE(tt);
1502         return ENOENT;
1503     }
1504     TSetRxCall(tt, acid, "Dump");
1505     code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1506                       ? 0 : 1); /* squirt out the volume's data, too */
1507     if (code) {
1508         TClearRxCall(tt);
1509         TRELE(tt);
1510         return code;
1511     }
1512     TClearRxCall(tt);
1513
1514     if (TRELE(tt))
1515         return VOLSERTRELE_ERROR;
1516
1517     return 0;
1518 }
1519
1520 /*
1521  * Ha!  No more helper process!
1522  */
1523 afs_int32
1524 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1525                struct restoreCookie *cookie)
1526 {
1527     afs_int32 code;
1528
1529     code = VolRestore(acid, atrans, aflags, cookie);
1530     osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1531     return code;
1532 }
1533
1534 static afs_int32
1535 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1536            struct restoreCookie *cookie)
1537 {
1538     struct volser_trans *tt;
1539     afs_int32 code, tcode;
1540     char caller[MAXKTCNAMELEN];
1541
1542     if (!afsconf_SuperUser(tdir, acid, caller))
1543         return VOLSERBAD_ACCESS;        /*not a super user */
1544     tt = FindTrans(atrans);
1545     if (!tt)
1546         return ENOENT;
1547     if (tt->vflags & VTDeleted) {
1548         Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1549         TRELE(tt);
1550         return ENOENT;
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 %u has been deleted \n",
1618             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 %u has been deleted \n",
1659             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 = &tv->header->diskstuff;
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 %u has been deleted \n", 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 = &tv->header->diskstuff;
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 = (char *)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 %u has been deleted \n", 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 = &tv->header->diskstuff;
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 = (char *)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                      afs_uint32 parentId, afs_uint32 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 = (afs_int32 *) malloc(j * sizeof(int));
1895         if (!pEntries->partEntries_val)
1896             return ENOMEM;
1897         memcpy((char *)pEntries->partEntries_val, (char *)&partList,
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 /*return the name of the next volume header in the directory associated with dirp and dp.
1909 *the volume id is  returned in volid, and volume header name is returned in volname*/
1910 int
1911 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1912 {
1913     struct dirent *dp;
1914
1915     dp = readdir(dirp);         /*read next entry in the directory */
1916     if (dp) {
1917         if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1918             *volid = VolumeNumber(dp->d_name);
1919             strcpy(volname, dp->d_name);
1920             return 0;           /*return the name of the file representing a volume */
1921         } else {
1922             strcpy(volname, "");
1923             return 0;           /*volname doesnot represent a volume */
1924         }
1925     } else {
1926         strcpy(volname, "EOD");
1927         return 0;               /*end of directory */
1928     }
1929
1930 }
1931
1932 /**
1933  * volint vol info structure type.
1934  */
1935 typedef enum {
1936     VOLINT_INFO_TYPE_BASE,  /**< volintInfo type */
1937     VOLINT_INFO_TYPE_EXT    /**< volintXInfo type */
1938 } volint_info_type_t;
1939
1940 /**
1941  * handle to various on-wire vol info types.
1942  */
1943 typedef struct {
1944     volint_info_type_t volinfo_type;
1945     union {
1946         void * opaque;
1947         volintInfo * base;
1948         volintXInfo * ext;
1949     } volinfo_ptr;
1950 } volint_info_handle_t;
1951
1952 /**
1953  * store value to a field at the appropriate location in on-wire structure.
1954  */
1955 #define VOLINT_INFO_STORE(handle, name, val) \
1956     do { \
1957         if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1958             (handle)->volinfo_ptr.base->name = (val); \
1959         } else { \
1960             (handle)->volinfo_ptr.ext->name = (val); \
1961         } \
1962     } while(0)
1963
1964 /**
1965  * get pointer to appropriate offset of field in on-wire structure.
1966  */
1967 #define VOLINT_INFO_PTR(handle, name) \
1968     (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1969      &((handle)->volinfo_ptr.base->name) : \
1970      &((handle)->volinfo_ptr.ext->name))
1971
1972 /**
1973  * fill in appropriate type of on-wire volume metadata structure.
1974  *
1975  * @param vp      pointer to volume object
1976  * @param handle  pointer to wire format handle object
1977  *
1978  * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1979  * @pre handle object must have a valid pointer and enumeration value
1980  *
1981  * @note passing a NULL value for vp means that the fileserver doesn't
1982  *       know about this particular volume, thus implying it is offline.
1983  *
1984  * @return operation status
1985  *   @retval 0 success
1986  *   @retval 1 failure
1987  */
1988 static int
1989 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1990 {
1991     unsigned int numStatBytes, now;
1992     struct VolumeDiskData *hdr = &vp->header->diskstuff;
1993
1994     /*read in the relevant info */
1995     strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1996     VOLINT_INFO_STORE(handle, status, VOK);     /*its ok */
1997     VOLINT_INFO_STORE(handle, volid, hdr->id);
1998     VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1999     VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId);   /*if rw volume */
2000     VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2001     VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2002     VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2003     VOLINT_INFO_STORE(handle, size, hdr->diskused);
2004     VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2005     VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2006     now = FT_ApproxTime();
2007     if ((now - hdr->dayUseDate) > OneDay) {
2008         VOLINT_INFO_STORE(handle, dayUse, 0);
2009     } else {
2010         VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2011     }
2012     VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2013     VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2014     VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2015     VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2016
2017 #ifdef AFS_DEMAND_ATTACH_FS
2018     /*
2019      * for DAFS, we "lie" about volume state --
2020      * instead of returning the raw state from the disk header,
2021      * we compute state based upon the fileserver's internal
2022      * in-core state enumeration value reported to us via fssync,
2023      * along with the blessed and inService flags from the header.
2024      *   -- tkeiser 11/27/2007
2025      */
2026
2027     /* Conditions that offline status is based on:
2028                 volume is unattached state
2029                 volume state is in (one of several error states)
2030                 volume not in service
2031                 volume is not marked as blessed (not on hold)
2032                 volume in salvage req. state
2033                 volume needsSalvaged
2034                 next op would set volume offline
2035                 next op would not leave volume online (based on several conditions)
2036     */
2037     if (!vp ||
2038         (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2039         VIsErrorState(V_attachState(vp)) ||
2040         !hdr->inService ||
2041         !hdr->blessed ||
2042         (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2043         hdr->needsSalvaged ||
2044         (vp->pending_vol_op &&
2045                 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2046                 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2047         )
2048         ) {
2049         VOLINT_INFO_STORE(handle, inUse, 0);
2050     } else {
2051         VOLINT_INFO_STORE(handle, inUse, 1);
2052     }
2053 #else
2054     /* offline status based on program type, where != fileServer enum (1) is offline */
2055     if (hdr->inUse == fileServer) {
2056         VOLINT_INFO_STORE(handle, inUse, 1);
2057     } else {
2058         VOLINT_INFO_STORE(handle, inUse, 0);
2059     }
2060 #endif
2061
2062
2063     switch(handle->volinfo_type) {
2064         /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2065     case VOLINT_INFO_TYPE_BASE:
2066
2067 #ifdef AFS_DEMAND_ATTACH_FS
2068         /* see comment above where we set inUse bit */
2069         if (hdr->needsSalvaged ||
2070             (vp && VIsErrorState(V_attachState(vp)))) {
2071             handle->volinfo_ptr.base->needsSalvaged = 1;
2072         } else {
2073             handle->volinfo_ptr.base->needsSalvaged = 0;
2074         }
2075 #else
2076         handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2077 #endif
2078         handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2079         handle->volinfo_ptr.base->spare0 = hdr->minquota;
2080         handle->volinfo_ptr.base->spare1 =
2081             (long)hdr->weekUse[0] +
2082             (long)hdr->weekUse[1] +
2083             (long)hdr->weekUse[2] +
2084             (long)hdr->weekUse[3] +
2085             (long)hdr->weekUse[4] +
2086             (long)hdr->weekUse[5] +
2087             (long)hdr->weekUse[6];
2088         handle->volinfo_ptr.base->flags = 0;
2089         handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2090         handle->volinfo_ptr.base->spare3 = 0;
2091         break;
2092
2093
2094     case VOLINT_INFO_TYPE_EXT:
2095         numStatBytes =
2096             4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2097                  (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2098
2099         /*
2100          * Copy out the stat fields in a single operation.
2101          */
2102         if ((now - hdr->dayUseDate) > OneDay) {
2103             memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2104                    0, numStatBytes);
2105         } else {
2106             memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2107                    (char *)&(hdr->stat_reads[0]),
2108                    numStatBytes);
2109         }
2110         break;
2111     }
2112
2113     return 0;
2114 }
2115
2116 #ifdef AFS_DEMAND_ATTACH_FS
2117
2118 /**
2119  * get struct Volume out of the fileserver.
2120  *
2121  * @param[in] volumeId  volumeId for which we want state information
2122  * @param[in] pname     partition name string
2123  * @param[inout] vp     pointer to pointer to Volume object which
2124  *                      will be populated (see note)
2125  *
2126  * @return operation status
2127  *   @retval 0         success
2128  *   @retval non-zero  failure
2129  *
2130  * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2131  *
2132  * @internal
2133  */
2134 static int
2135 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2136 {
2137     int code;
2138     SYNC_response res;
2139
2140     res.hdr.response_len = sizeof(res.hdr);
2141     res.payload.buf = *vp;
2142     res.payload.len = sizeof(Volume);
2143
2144     code = FSYNC_VolOp(volumeId,
2145                        pname,
2146                        FSYNC_VOL_QUERY,
2147                        0,
2148                        &res);
2149
2150     if (code != SYNC_OK) {
2151         switch (res.hdr.reason) {
2152         case FSYNC_WRONG_PART:
2153         case FSYNC_UNKNOWN_VOLID:
2154             *vp = NULL;
2155             code = SYNC_OK;
2156             break;
2157         }
2158     }
2159
2160     return code;
2161 }
2162
2163 #endif
2164
2165 /**
2166  * mode of volume list operation.
2167  */
2168 typedef enum {
2169     VOL_INFO_LIST_SINGLE,   /**< performing a single volume list op */
2170     VOL_INFO_LIST_MULTIPLE  /**< performing a multi-volume list op */
2171 } vol_info_list_mode_t;
2172
2173 /**
2174  * abstract interface to populate wire-format volume metadata structures.
2175  *
2176  * @param[in]  partId    partition id
2177  * @param[in]  volumeId  volume id
2178  * @param[in]  pname     partition name
2179  * @param[in]  volname   volume file name
2180  * @param[in]  handle    handle to on-wire volume metadata object
2181  * @param[in]  mode      listing mode
2182  *
2183  * @return operation status
2184  *   @retval 0      success
2185  *   @retval -2     DESTROY_ME flag is set
2186  *   @retval -1     general failure; some data filled in
2187  *   @retval -3     couldn't create vtrans; some data filled in
2188  */
2189 static int
2190 GetVolInfo(afs_uint32 partId,
2191            afs_uint32 volumeId,
2192            char * pname,
2193            char * volname,
2194            volint_info_handle_t * handle,
2195            vol_info_list_mode_t mode)
2196 {
2197     int code = -1;
2198     Error error;
2199     struct volser_trans *ttc = NULL;
2200     struct Volume *fill_tv, *tv = NULL;
2201 #ifdef AFS_DEMAND_ATTACH_FS
2202     struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2203     SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2204     SYNC_response fs_res; /* Response handle for the pending_vol_op */
2205     FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2206
2207     /* Set up response handle for pending_vol_op */
2208     fs_res.hdr.response_len = sizeof(fs_res.hdr);
2209     fs_res.payload.buf = fs_res_buf;
2210     fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2211 #endif
2212
2213     ttc = NewTrans(volumeId, partId);
2214     if (!ttc) {
2215         code = -3;
2216         VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2217         VOLINT_INFO_STORE(handle, volid, volumeId);
2218         goto drop;
2219     }
2220
2221     /* Get volume from volserver */
2222     if (mode == VOL_INFO_LIST_MULTIPLE)
2223         tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2224     else
2225         tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2226     if (error) {
2227         Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2228             volumeId, pname, volname, error);
2229         goto drop;
2230     }
2231
2232     /*
2233      * please note that destroyMe and needsSalvaged checks used to be ordered
2234      * in the opposite manner for ListVolumes and XListVolumes.  I think it's
2235      * more correct to check destroyMe before needsSalvaged.
2236      *   -- tkeiser 11/28/2007
2237      */
2238
2239     if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2240         switch (mode) {
2241         case VOL_INFO_LIST_MULTIPLE:
2242             code = -2;
2243             goto drop;
2244
2245         case VOL_INFO_LIST_SINGLE:
2246             Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2247                 volumeId, pname, volname);
2248
2249         default:
2250             goto drop;
2251         }
2252     }
2253
2254     if (tv->header->diskstuff.needsSalvaged) {
2255         /*this volume will be salvaged */
2256         Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2257             volumeId, pname, volname);
2258     }
2259
2260 #ifdef AFS_DEMAND_ATTACH_FS
2261     /* If using DAFS, get volume from fsserver */
2262     if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2263
2264         goto drop;
2265     }
2266
2267     /* fs_tv is a shallow copy, must populate certain structures before passing along */
2268     if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2269         /* If we if the pending vol op */
2270         memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2271         fs_tv->pending_vol_op=&pending_vol_op_res;
2272     } else {
2273         fs_tv->pending_vol_op=NULL;
2274     }
2275
2276     /* populate the header from the volserver copy */
2277     fs_tv->header=tv->header;
2278
2279     /* When using DAFS, use the fs volume info, populated with required structures */
2280     fill_tv = fs_tv;
2281 #else
2282     /* When not using DAFS, just use the local volume info */
2283     fill_tv = tv;
2284 #endif
2285
2286     /* ok, we have all the data we need; fill in the on-wire struct */
2287     code = FillVolInfo(fill_tv, handle);
2288
2289  drop:
2290     if (code == -1) {
2291         VOLINT_INFO_STORE(handle, status, 0);
2292         strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2293         VOLINT_INFO_STORE(handle, volid, volumeId);
2294     }
2295     if (tv) {
2296         VDetachVolume(&error, tv);
2297         tv = NULL;
2298         if (error) {
2299             VOLINT_INFO_STORE(handle, status, 0);
2300             strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2301             Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2302                 volumeId, pname, volname);
2303         }
2304     }
2305     if (ttc) {
2306         DeleteTrans(ttc, 1);
2307         ttc = NULL;
2308     }
2309     return code;
2310 }
2311
2312
2313 /*return the header information about the <volid> */
2314 afs_int32
2315 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2316                      afs_uint32 volumeId, volEntries *volumeInfo)
2317 {
2318     afs_int32 code;
2319
2320     code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2321     osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2322     return code;
2323 }
2324
2325 static afs_int32
2326 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2327                  afs_uint32 volumeId, volEntries *volumeInfo)
2328 {
2329     struct DiskPartition64 *partP;
2330     char pname[9], volname[20];
2331     DIR *dirp;
2332     afs_uint32 volid;
2333     int found = 0;
2334     int code;
2335     volint_info_handle_t handle;
2336
2337     volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2338     if (!volumeInfo->volEntries_val)
2339         return ENOMEM;
2340
2341     volumeInfo->volEntries_len = 1;
2342     if (GetPartName(partid, pname))
2343         return VOLSERILLEGAL_PARTITION;
2344     if (!(partP = VGetPartition(pname, 0)))
2345         return VOLSERILLEGAL_PARTITION;
2346     dirp = opendir(VPartitionPath(partP));
2347     if (dirp == NULL)
2348         return VOLSERILLEGAL_PARTITION;
2349
2350     strcpy(volname, "");
2351
2352     while (strcmp(volname, "EOD") && !found) {  /*while there are more volumes in the partition */
2353
2354         if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
2355             GetNextVol(dirp, volname, &volid);
2356             continue;           /*back to while loop */
2357         }
2358
2359         if (volid == volumeId) {        /*copy other things too */
2360             found = 1;
2361             break;
2362         }
2363
2364         GetNextVol(dirp, volname, &volid);
2365     }
2366
2367     if (found) {
2368 #ifndef AFS_PTHREAD_ENV
2369         IOMGR_Poll();   /*make sure that the client does not time out */
2370 #endif
2371
2372         handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2373         handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2374
2375         code = GetVolInfo(partid,
2376                           volid,
2377                           pname,
2378                           volname,
2379                           &handle,
2380                           VOL_INFO_LIST_SINGLE);
2381     }
2382
2383     closedir(dirp);
2384     if (found)
2385         return code ? ENODEV: 0;
2386     else
2387         return ENODEV;
2388 }
2389
2390 /*------------------------------------------------------------------------
2391  * EXPORTED SAFSVolXListOneVolume
2392  *
2393  * Description:
2394  *      Returns extended info on volume a_volID on partition a_partID.
2395  *
2396  * Arguments:
2397  *      a_rxCidP       : Pointer to the Rx call we're performing.
2398  *      a_partID       : Partition for which we want the extended list.
2399  *      a_volID        : Volume ID we wish to know about.
2400  *      a_volumeXInfoP : Ptr to the extended info blob.
2401  *
2402  * Returns:
2403  *      0                       Successful operation
2404  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2405  *
2406  * Environment:
2407  *      Nothing interesting.
2408  *
2409  * Side Effects:
2410  *      As advertised.
2411  *------------------------------------------------------------------------*/
2412
2413 afs_int32
2414 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2415                       afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2416 {
2417     afs_int32 code;
2418
2419     code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2420     osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2421     return code;
2422 }
2423
2424 static afs_int32
2425 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2426                   afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2427 {                               /*SAFSVolXListOneVolume */
2428
2429     struct DiskPartition64 *partP;      /*Ptr to partition */
2430     char pname[9], volname[20]; /*Partition, volume names */
2431     DIR *dirp;                  /*Partition directory ptr */
2432     afs_uint32 currVolID;               /*Current volume ID */
2433     int found = 0;              /*Did we find the volume we need? */
2434     int code;
2435     volint_info_handle_t handle;
2436
2437     /*
2438      * Set up our pointers for action, marking our structure to hold exactly
2439      * one entry.  Also, assume we'll fail in our quest.
2440      */
2441     a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2442     if (!a_volumeXInfoP->volXEntries_val)
2443         return ENOMEM;
2444
2445     a_volumeXInfoP->volXEntries_len = 1;
2446     code = ENODEV;
2447
2448     /*
2449      * If the partition name we've been given is bad, bogue out.
2450      */
2451     if (GetPartName(a_partID, pname))
2452         return (VOLSERILLEGAL_PARTITION);
2453
2454     /*
2455      * Open the directory representing the given AFS parttion.  If we can't
2456      * do that, we lose.
2457      */
2458     if (!(partP = VGetPartition(pname, 0)))
2459         return VOLSERILLEGAL_PARTITION;
2460     dirp = opendir(VPartitionPath(partP));
2461     if (dirp == NULL)
2462         return (VOLSERILLEGAL_PARTITION);
2463
2464     strcpy(volname, "");
2465
2466     /*
2467      * Sweep through the partition directory, looking for the desired entry.
2468      * First, of course, figure out how many stat bytes to copy out of each
2469      * volume.
2470      */
2471     while (strcmp(volname, "EOD") && !found) {
2472         /*
2473          * If this is not a volume, move on to the next entry in the
2474          * partition's directory.
2475          */
2476         if (!strcmp(volname, "")) {
2477             GetNextVol(dirp, volname, &currVolID);
2478             continue;
2479         }
2480
2481         if (currVolID == a_volID) {
2482             /*
2483              * We found the volume entry we're interested.  Pull out the
2484              * extended information, remembering to poll (so that the client
2485              * doesn't time out) and to set up a transaction on the volume.
2486              */
2487             found = 1;
2488             break;
2489         }                       /*Found desired volume */
2490
2491         GetNextVol(dirp, volname, &currVolID);
2492     }
2493
2494     if (found) {
2495 #ifndef AFS_PTHREAD_ENV
2496         IOMGR_Poll();
2497 #endif
2498
2499         handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2500         handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2501
2502         code = GetVolInfo(a_partID,
2503                           a_volID,
2504                           pname,
2505                           volname,
2506                           &handle,
2507                           VOL_INFO_LIST_SINGLE);
2508
2509     }
2510
2511     /*
2512      * Clean up before going to dinner: close the partition directory,
2513      * return the proper value.
2514      */
2515     closedir(dirp);
2516     if (found)
2517         return code ? ENODEV: 0;
2518     else
2519         return ENODEV;
2520 }                               /*SAFSVolXListOneVolume */
2521
2522 /*returns all the volumes on partition partid. If flags = 1 then all the
2523 * relevant info about the volumes  is also returned */
2524 afs_int32
2525 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2526                    volEntries *volumeInfo)
2527 {
2528     afs_int32 code;
2529
2530     code = VolListVolumes(acid, partid, flags, volumeInfo);
2531     osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2532     return code;
2533 }
2534
2535 static afs_int32
2536 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2537                    volEntries *volumeInfo)
2538 {
2539     volintInfo *pntr;
2540     struct DiskPartition64 *partP;
2541     afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2542     char pname[9], volname[20];
2543     DIR *dirp;
2544     afs_uint32 volid;
2545     int code;
2546     volint_info_handle_t handle;
2547
2548     volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2549     if (!volumeInfo->volEntries_val)
2550         return ENOMEM;
2551
2552     pntr = volumeInfo->volEntries_val;
2553     volumeInfo->volEntries_len = 0;
2554     if (GetPartName(partid, pname))
2555         return VOLSERILLEGAL_PARTITION;
2556     if (!(partP = VGetPartition(pname, 0)))
2557         return VOLSERILLEGAL_PARTITION;
2558     dirp = opendir(VPartitionPath(partP));
2559     if (dirp == NULL)
2560         return VOLSERILLEGAL_PARTITION;
2561     strcpy(volname, "");
2562
2563     while (strcmp(volname, "EOD")) {    /*while there are more partitions in the partition */
2564
2565         if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
2566             GetNextVol(dirp, volname, &volid);
2567             continue;           /*back to while loop */
2568         }
2569
2570         if (flags) {            /*copy other things too */
2571 #ifndef AFS_PTHREAD_ENV
2572             IOMGR_Poll();       /*make sure that the client does not time out */
2573 #endif
2574
2575             handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2576             handle.volinfo_ptr.base = pntr;
2577
2578
2579             code = GetVolInfo(partid,
2580                               volid,
2581                               pname,
2582                               volname,
2583                               &handle,
2584                               VOL_INFO_LIST_MULTIPLE);
2585             if (code == -2) { /* DESTROY_ME flag set */
2586                 goto drop2;
2587             }
2588         } else {
2589             pntr->volid = volid;
2590             /*just volids are needed */
2591         }
2592
2593         pntr++;
2594         volumeInfo->volEntries_len += 1;
2595         if ((allocSize - volumeInfo->volEntries_len) < 5) {
2596             /*running out of space, allocate more space */
2597             allocSize = (allocSize * 3) / 2;
2598             pntr =
2599                 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2600                                        allocSize * sizeof(volintInfo));
2601             if (pntr == NULL) {
2602                 closedir(dirp);
2603                 return VOLSERNO_MEMORY;
2604             }
2605             volumeInfo->volEntries_val = pntr;  /* point to new block */
2606             /* set pntr to the right position */
2607             pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2608
2609         }
2610
2611       drop2:
2612         GetNextVol(dirp, volname, &volid);
2613
2614     }
2615
2616     closedir(dirp);
2617     return 0;
2618 }
2619
2620 /*------------------------------------------------------------------------
2621  * EXPORTED SAFSVolXListVolumes
2622  *
2623  * Description:
2624  *      Returns all the volumes on partition a_partID.  If a_flags
2625  *      is set to 1, then all the relevant extended volume information
2626  *      is also returned.
2627  *
2628  * Arguments:
2629  *      a_rxCidP       : Pointer to the Rx call we're performing.
2630  *      a_partID       : Partition for which we want the extended list.
2631  *      a_flags        : Various flags.
2632  *      a_volumeXInfoP : Ptr to the extended info blob.
2633  *
2634  * Returns:
2635  *      0                       Successful operation
2636  *      VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2637  *      VOLSERNO_MEMORY         if we ran out of memory allocating
2638  *                              our return blob
2639  *
2640  * Environment:
2641  *      Nothing interesting.
2642  *
2643  * Side Effects:
2644  *      As advertised.
2645  *------------------------------------------------------------------------*/
2646
2647 afs_int32
2648 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2649                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2650 {
2651     afs_int32 code;
2652
2653     code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2654     osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2655     return code;
2656 }
2657
2658 static afs_int32
2659 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2660                     afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2661 {                               /*SAFSVolXListVolumes */
2662
2663     volintXInfo *xInfoP;        /*Ptr to the extended vol info */
2664     struct DiskPartition64 *partP;      /*Ptr to partition */
2665     afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2666     char pname[9], volname[20]; /*Partition, volume names */
2667     DIR *dirp;                  /*Partition directory ptr */
2668     afs_uint32 volid;           /*Current volume ID */
2669     int code;
2670     volint_info_handle_t handle;
2671
2672     /*
2673      * Allocate a large array of extended volume info structures, then
2674      * set it up for action.
2675      */
2676     a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2677     if (!a_volumeXInfoP->volXEntries_val)
2678         return ENOMEM;
2679
2680     xInfoP = a_volumeXInfoP->volXEntries_val;
2681     a_volumeXInfoP->volXEntries_len = 0;
2682
2683     /*
2684      * If the partition name we've been given is bad, bogue out.
2685      */
2686     if (GetPartName(a_partID, pname))
2687         return (VOLSERILLEGAL_PARTITION);
2688
2689     /*
2690      * Open the directory representing the given AFS parttion.  If we can't
2691      * do that, we lose.
2692      */
2693     if (!(partP = VGetPartition(pname, 0)))
2694         return VOLSERILLEGAL_PARTITION;
2695     dirp = opendir(VPartitionPath(partP));
2696     if (dirp == NULL)
2697         return (VOLSERILLEGAL_PARTITION);
2698     strcpy(volname, "");
2699
2700     /*
2701      * Sweep through the partition directory, acting on each entry.  First,
2702      * of course, figure out how many stat bytes to copy out of each volume.
2703      */
2704     while (strcmp(volname, "EOD")) {
2705
2706         /*
2707          * If this is not a volume, move on to the next entry in the
2708          * partition's directory.
2709          */
2710         if (!strcmp(volname, "")) {
2711             GetNextVol(dirp, volname, &volid);
2712             continue;
2713         }
2714
2715         if (a_flags) {
2716             /*
2717              * Full info about the volume desired.  Poll to make sure the
2718              * client doesn't time out, then start up a new transaction.
2719              */
2720 #ifndef AFS_PTHREAD_ENV
2721             IOMGR_Poll();
2722 #endif
2723
2724             handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2725             handle.volinfo_ptr.ext = xInfoP;
2726
2727             code = GetVolInfo(a_partID,
2728                               volid,
2729                               pname,
2730                               volname,
2731                               &handle,
2732                               VOL_INFO_LIST_MULTIPLE);
2733             if (code == -2) { /* DESTROY_ME flag set */
2734                 goto drop2;
2735             }
2736         } else {
2737             /*
2738              * Just volume IDs are needed.
2739              */
2740             xInfoP->volid = volid;
2741         }
2742
2743         /*
2744          * Bump the pointer in the data area we're building, along with
2745          * the count of the number of entries it contains.
2746          */
2747         xInfoP++;
2748         (a_volumeXInfoP->volXEntries_len)++;
2749         if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2750             /*
2751              * We're running out of space in the area we've built.  Grow it.
2752              */
2753             allocSize = (allocSize * 3) / 2;
2754             xInfoP = (volintXInfo *)
2755                 realloc((char *)a_volumeXInfoP->volXEntries_val,
2756                         (allocSize * sizeof(volintXInfo)));
2757             if (xInfoP == NULL) {
2758                 /*
2759                  * Bummer, no memory. Bag it, tell our caller what went wrong.
2760                  */
2761                 closedir(dirp);
2762                 return (VOLSERNO_MEMORY);
2763             }
2764
2765             /*
2766              * Memory reallocation worked.  Correct our pointers so they
2767              * now point to the new block and the current open position within
2768              * the new block.
2769              */
2770             a_volumeXInfoP->volXEntries_val = xInfoP;
2771             xInfoP =
2772                 a_volumeXInfoP->volXEntries_val +
2773                 a_volumeXInfoP->volXEntries_len;
2774         }
2775
2776       drop2:
2777         GetNextVol(dirp, volname, &volid);
2778     }                           /*Sweep through the partition directory */
2779
2780     /*
2781      * We've examined all entries in the partition directory.  Close it,
2782      * delete our transaction (if any), and go home happy.
2783      */
2784     closedir(dirp);
2785     return (0);
2786
2787 }                               /*SAFSVolXListVolumes */
2788
2789 /*this call is used to monitor the status of volser for debugging purposes.
2790  *information about all the active transactions is returned in transInfo*/
2791 afs_int32
2792 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2793 {
2794     afs_int32 code;
2795
2796     code = VolMonitor(acid, transInfo);
2797     osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2798     return code;
2799 }
2800
2801 static afs_int32
2802 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2803 {
2804     transDebugInfo *pntr;
2805     afs_int32 allocSize = 50;
2806     struct volser_trans *tt, *nt, *allTrans;
2807
2808     transInfo->transDebugEntries_val =
2809         (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2810     if (!transInfo->transDebugEntries_val)
2811         return ENOMEM;
2812     pntr = transInfo->transDebugEntries_val;
2813     transInfo->transDebugEntries_len = 0;
2814
2815     VTRANS_LOCK;
2816     allTrans = TransList();
2817     if (allTrans == (struct volser_trans *)0)
2818         goto done;              /*no active transactions */
2819     for (tt = allTrans; tt; tt = nt) {  /*copy relevant info into pntr */
2820         nt = tt->next;
2821         VTRANS_OBJ_LOCK(tt);
2822         pntr->tid = tt->tid;
2823         pntr->time = tt->time;
2824         pntr->creationTime = tt->creationTime;
2825         pntr->returnCode = tt->returnCode;
2826         pntr->volid = tt->volid;
2827         pntr->partition = tt->partition;
2828         pntr->iflags = tt->iflags;
2829         pntr->vflags = tt->vflags;
2830         pntr->tflags = tt->tflags;
2831         strcpy(pntr->lastProcName, tt->lastProcName);
2832         pntr->callValid = 0;
2833         if (tt->rxCallPtr) {    /*record call related info */
2834             pntr->callValid = 1;
2835 #if 0
2836             pntr->readNext = tt->rxCallPtr->rnext;
2837             pntr->transmitNext = tt->rxCallPtr->tnext;
2838             pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2839             pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2840 #endif
2841         }
2842         VTRANS_OBJ_UNLOCK(tt);
2843         pntr++;
2844         transInfo->transDebugEntries_len += 1;
2845         if ((allocSize - transInfo->transDebugEntries_len) < 5) {       /*alloc some more space */
2846             allocSize = (allocSize * 3) / 2;
2847             pntr =
2848                 (transDebugInfo *) realloc((char *)transInfo->
2849                                            transDebugEntries_val,
2850                                            allocSize *
2851                                            sizeof(transDebugInfo));
2852             transInfo->transDebugEntries_val = pntr;
2853             pntr =
2854                 transInfo->transDebugEntries_val +
2855                 transInfo->transDebugEntries_len;
2856             /*set pntr to right position */
2857         }
2858
2859     }
2860 done:
2861     VTRANS_UNLOCK;
2862
2863     return 0;
2864 }
2865
2866 afs_int32
2867 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2868                    afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2869                    afs_uint32 backupId)
2870 {
2871     afs_int32 code;
2872
2873     code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2874     osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2875                AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2876                backupId, AUD_END);
2877     return code;
2878 }
2879
2880 static afs_int32
2881 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2882                afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2883                afs_uint32 backupId)
2884 {
2885     struct Volume *tv;
2886     Error error = 0;
2887     struct volser_trans *tt;
2888     char caller[MAXKTCNAMELEN];
2889
2890     if (strlen(name) > 31)
2891         return VOLSERBADNAME;
2892     if (!afsconf_SuperUser(tdir, acid, caller))
2893         return VOLSERBAD_ACCESS;        /*not a super user */
2894     /* find the trans */
2895     tt = FindTrans(atid);
2896     if (!tt)
2897         return ENOENT;
2898     if (tt->vflags & VTDeleted) {
2899         Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2900         TRELE(tt);
2901         return ENOENT;
2902     }
2903     TSetRxCall(tt, acid, "SetIdsTypes");
2904     tv = tt->volume;
2905
2906     V_type(tv) = type;
2907     V_backupId(tv) = backupId;
2908     V_cloneId(tv) = cloneId;
2909     V_parentId(tv) = pId;
2910     strcpy((&V_disk(tv))->name, name);
2911     VUpdateVolume(&error, tv);
2912     if (error) {
2913         Log("1 Volser: SetIdsTypes: 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 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2931 {
2932     afs_int32 code;
2933
2934     code = VolSetDate(acid, atid, cdate);
2935     osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2936                AUD_END);
2937     return code;
2938 }
2939
2940 static afs_int32
2941 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2942 {
2943     struct Volume *tv;
2944     Error error = 0;
2945     struct volser_trans *tt;
2946     char caller[MAXKTCNAMELEN];
2947
2948     if (!afsconf_SuperUser(tdir, acid, caller))
2949         return VOLSERBAD_ACCESS;        /*not a super user */
2950     /* find the trans */
2951     tt = FindTrans(atid);
2952     if (!tt)
2953         return ENOENT;
2954     if (tt->vflags & VTDeleted) {
2955         Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2956         TRELE(tt);
2957         return ENOENT;
2958     }
2959     TSetRxCall(tt, acid, "SetDate");
2960     tv = tt->volume;
2961
2962     V_creationDate(tv) = cdate;
2963     VUpdateVolume(&error, tv);
2964     if (error) {
2965         Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2966         LogError(error);
2967         goto fail;
2968     }
2969     TClearRxCall(tt);
2970     if (TRELE(tt) && !error)
2971         return VOLSERTRELE_ERROR;
2972
2973     return error;
2974   fail:
2975     TClearRxCall(tt);
2976     if (TRELE(tt) && !error)
2977         return VOLSERTRELE_ERROR;
2978     return error;
2979 }
2980
2981 afs_int32
2982 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2983                            afs_uint32 volumeId)
2984 {
2985 #ifdef AFS_NT40_ENV
2986     return EXDEV;
2987 #else
2988     char caller[MAXKTCNAMELEN];
2989     DIR *dirp;
2990     struct volser_trans *ttc;
2991     char pname[16], volname[20];
2992     struct DiskPartition64 *partP;
2993     afs_int32 ret = ENODEV;
2994     afs_uint32 volid;
2995
2996     if (!afsconf_SuperUser(tdir, acid, caller))
2997         return VOLSERBAD_ACCESS;        /*not a super user */
2998     if (GetPartName(partId, pname))
2999         return VOLSERILLEGAL_PARTITION;
3000     if (!(partP = VGetPartition(pname, 0)))
3001         return VOLSERILLEGAL_PARTITION;
3002     dirp = opendir(VPartitionPath(partP));
3003     if (dirp == NULL)
3004         return VOLSERILLEGAL_PARTITION;
3005     strcpy(volname, "");
3006     ttc = (struct volser_trans *)0;
3007
3008     while (strcmp(volname, "EOD")) {
3009         if (!strcmp(volname, "")) {     /* its not a volume, fetch next file */
3010             GetNextVol(dirp, volname, &volid);
3011             continue;           /*back to while loop */
3012         }
3013
3014         if (volid == volumeId) {        /*copy other things too */
3015 #ifndef AFS_PTHREAD_ENV
3016             IOMGR_Poll();       /*make sure that the client doesnot time out */
3017 #endif
3018             ttc = NewTrans(volumeId, partId);
3019             if (!ttc) {
3020                 return VOLSERVOLBUSY;
3021             }
3022 #ifdef AFS_NAMEI_ENV
3023             ret = namei_ConvertROtoRWvolume(pname, volumeId);
3024 #else
3025             ret = inode_ConvertROtoRWvolume(pname, volumeId);
3026 #endif
3027             break;
3028         }
3029         GetNextVol(dirp, volname, &volid);
3030     }
3031
3032     if (ttc) {
3033         DeleteTrans(ttc, 1);
3034         ttc = (struct volser_trans *)0;
3035     }
3036
3037     closedir(dirp);
3038     return ret;
3039 #endif
3040 }
3041
3042 afs_int32
3043 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3044                struct volintSize *size)
3045 {
3046     int code = 0;
3047     struct volser_trans *tt;
3048     char caller[MAXKTCNAMELEN];
3049
3050     if (!afsconf_SuperUser(tdir, acid, caller))
3051         return VOLSERBAD_ACCESS;        /*not a super user */
3052     tt = FindTrans(fromTrans);
3053     if (!tt)
3054         return ENOENT;
3055     if (tt->vflags & VTDeleted) {
3056         TRELE(tt);
3057         return ENOENT;
3058     }
3059     TSetRxCall(tt, acid, "GetSize");
3060     code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3061     TClearRxCall(tt);
3062     if (TRELE(tt))
3063         return VOLSERTRELE_ERROR;
3064
3065 /*    osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);  */
3066     return code;
3067 }
3068
3069 afs_int32
3070 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3071                    afs_uint32 where, afs_int32 verbose)
3072 {
3073 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3074     Error code, code2;
3075     Volume *vol=0, *newvol=0;
3076     struct volser_trans *tt = 0, *tt2 = 0;
3077     char caller[MAXKTCNAMELEN];
3078     char line[128];
3079
3080     if (!afsconf_SuperUser(tdir, acall, caller))
3081         return EPERM;
3082
3083     vol = VAttachVolume(&code, vid, V_VOLUPD);
3084     if (!vol) {
3085         if (!code)
3086             code = ENOENT;
3087         return code;
3088     }
3089     newvol = VAttachVolume(&code, new, V_VOLUPD);
3090     if (!newvol) {
3091         VDetachVolume(&code2, vol);
3092         if (!code)
3093             code = ENOENT;
3094         return code;
3095     }
3096     if (V_device(vol) != V_device(newvol)
3097         || V_uniquifier(newvol) != 2) {
3098         if (V_device(vol) != V_device(newvol)) {
3099             sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3100                     vid, new);
3101             rx_Write(acall, line, strlen(line));
3102         }
3103         if (V_uniquifier(newvol) != 2) {
3104             sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3105             rx_Write(acall, line, strlen(line));
3106         }
3107         line[0] = 0;
3108         rx_Write(acall, line, 1);
3109         VDetachVolume(&code2, vol);
3110         VDetachVolume(&code2, newvol);
3111         return EINVAL;
3112     }
3113     tt = NewTrans(vid, V_device(vol));
3114     if (!tt) {
3115         sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3116         rx_Write(acall, line, strlen(line));
3117         line[0] = 0;
3118         rx_Write(acall, line, 1);
3119         VDetachVolume(&code2, vol);
3120         VDetachVolume(&code2, newvol);
3121         return VOLSERVOLBUSY;
3122     }
3123     VTRANS_OBJ_LOCK(tt);
3124     tt->iflags = ITBusy;
3125     tt->vflags = 0;
3126     TSetRxCall_r(tt, NULL, "SplitVolume");
3127     VTRANS_OBJ_UNLOCK(tt);
3128
3129     tt2 = NewTrans(new, V_device(newvol));
3130     if (!tt2) {
3131         sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3132         rx_Write(acall, line, strlen(line));
3133         line[0] = 0;
3134         rx_Write(acall, line, 1);
3135         DeleteTrans(tt, 1);
3136         VDetachVolume(&code2, vol);
3137         VDetachVolume(&code2, newvol);
3138         return VOLSERVOLBUSY;
3139     }
3140     VTRANS_OBJ_LOCK(tt2);
3141     tt2->iflags = ITBusy;
3142     tt2->vflags = 0;
3143     TSetRxCall_r(tt2, NULL, "SplitVolume");
3144     VTRANS_OBJ_UNLOCK(tt2);
3145
3146     code = split_volume(acall, vol, newvol, where, verbose);
3147
3148     VDetachVolume(&code2, vol);
3149     DeleteTrans(tt, 1);
3150     VDetachVolume(&code2, newvol);
3151     DeleteTrans(tt2, 1);
3152     return code;
3153 #else
3154     return VOLSERBADOP;
3155 #endif
3156 }
3157
3158 /* GetPartName - map partid (a decimal number) into pname (a string)
3159  * Since for NT we actually want to return the drive name, we map through the
3160  * partition struct.
3161  */
3162 static int
3163 GetPartName(afs_int32 partid, char *pname)
3164 {
3165     if (partid < 0)
3166         return -1;
3167     if (partid < 26) {
3168         strcpy(pname, "/vicep");
3169         pname[6] = 'a' + partid;
3170         pname[7] = '\0';
3171         return 0;
3172     } else if (partid < VOLMAXPARTS) {
3173         strcpy(pname, "/vicep");
3174         partid -= 26;
3175         pname[6] = 'a' + (partid / 26);
3176         pname[7] = 'a' + (partid % 26);
3177         pname[8] = '\0';
3178         return 0;
3179     } else
3180         return -1;
3181 }