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