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