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