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