/* * Copyright 2000, International Business Machines Corporation and others. * All Rights Reserved. * * This software has been released under the terms of the IBM Public * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ #include #include RCSID("$Header$"); #include #include #include #ifdef AFS_NT40_ENV #include #include #else #include #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef AFS_NT40_ENV #include #endif #include #include #include #include "vol.h" #include #include #include "afs/audit.h" #include "volser.h" #include "volint.h" extern int DoLogging; extern struct volser_trans *FindTrans(), *NewTrans(),*TransList(); extern struct rx_securityClass *rxnull_NewServerSecurityObject(); extern struct rx_service *rx_NewService(); extern struct rx_securityClass *rxnull_NewClientSecurityObject(); extern struct afsconf_dir *tdir; extern char *volutil_PartitionName(); /* Forward declarations */ static int GetPartName(afs_int32 partid, char *pname); #define OneDay (24*60*60) #ifdef AFS_NT40_ENV #define ENOTCONN 134 #endif afs_int32 localTid=1; afs_int32 VolPartitionInfo(), VolNukeVolume(), VolCreateVolume(), VolDeleteVolume(), VolClone(); afs_int32 VolReClone(), VolTransCreate(), VolGetNthVolume(), VolGetFlags(), VolForward(), VolDump(); afs_int32 VolForwardMultiple(); afs_int32 VolRestore(), VolEndTrans(), VolSetForwarding(), VolGetStatus(), VolSetInfo(), VolGetName(); afs_int32 VolSignalRestore(), VolListPartitions(), VolListOneVolume(), VolXListOneVolume(), VolXListVolumes(); afs_int32 VolListVolumes(), XVolListPartitions(), VolMonitor(), VolSetIdsTypes(), VolSetDate(), VolSetFlags(); /* this call unlocks all of the partition locks we've set */ VPFullUnlock() { register struct DiskPartition *tp; for(tp = DiskPartitionList; tp; tp = tp->next) { if (tp->lock_fd != -1) { close(tp->lock_fd); /* releases flock held on this partition */ tp->lock_fd = -1; } } return 0; } /* get partition id from a name */ afs_int32 PartitionID(aname) char *aname; { register char tc; register int code = 0; char ascii[3]; tc = *aname; if (tc == 0) return -1; /* unknown */ /* otherwise check for vicepa or /vicepa, or just plain "a" */ ascii[2] = 0; if (!strncmp(aname, "/vicep", 6)) { strncpy(ascii, aname+6, 2); } else return -1; /* bad partition name */ /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered from 0. Do the appropriate conversion */ if (ascii[1] == 0) { /* one char name, 0..25 */ if (ascii[0] < 'a' || ascii[0] > 'z') return -1; /* wrongo */ return ascii[0] - 'a'; } else { /* two char name, 26 .. */ if (ascii[0] < 'a' || ascii[0] > 'z') return -1; /* wrongo */ if (ascii[1] < 'a' || ascii[1] > 'z') return -1; /* just as bad */ code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26; if (code > VOLMAXPARTS) return -1; return code; } } static int ConvertVolume(avol, aname, asize) afs_int32 avol; char *aname; afs_int32 asize; { if (asize < 18) return -1; /* 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 */ sprintf(aname, VFORMAT, avol); return 0; } static int ConvertPartition(apartno, aname, asize) int apartno; char *aname; int asize; { if (asize < 10) return E2BIG; if (apartno < 0) return EINVAL; strcpy(aname, "/vicep"); if (apartno < 26) { aname[6] = 'a'+apartno; aname[7] = 0; } else { apartno -= 26; aname[6] = 'a' + (apartno / 26); aname[7] = 'a' + (apartno % 26); aname[8] = 0; } return 0; } /* the only attach function that takes a partition is "...ByName", so we use it */ struct Volume *XAttachVolume(error, avolid, apartid, amode) afs_int32 *error; afs_int32 avolid; afs_int32 apartid; int amode; { char pbuf[30], vbuf[20]; register struct Volume *tv; if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) { *error = EINVAL; return (struct Volume *) 0; } if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) { *error = EINVAL; return (struct Volume *) 0; } tv = VAttachVolumeByName(error, pbuf, vbuf, amode); return tv; } /* Adapted from the file server; create a root directory for this volume */ static ViceCreateRoot(vp) Volume * vp; { DirHandle dir; struct acl_accessList * ACL; ViceFid did; Inode inodeNumber, nearInode; char buf[SIZEOF_LARGEDISKVNODE]; struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf; struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge]; IHandle_t *h; FdHandle_t *fdP; int code; int length; memset(vnode, 0, SIZEOF_LARGEDISKVNODE); V_pref(vp, nearInode); inodeNumber = IH_CREATE(V_linkHandle(vp), V_device(vp), VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp), 1, 1, 0); assert(VALID_INO(inodeNumber)); SetSalvageDirHandle(&dir, V_id(vp), vp->device, inodeNumber); did.Volume = V_id(vp); did.Vnode = (VnodeId)1; did.Unique = 1; assert(!(MakeDir(&dir, &did, &did))); DFlush(); /* flush all modified dir buffers out */ DZap(&dir); /* Remove all buffers for this dir */ length = Length(&dir); /* Remember size of this directory */ FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */ /* build a single entry ACL that gives all rights to system:administrators */ /* this section of code assumes that access list format is not going to * change */ ACL = VVnodeDiskACL(vnode); ACL->size = sizeof(struct acl_accessList); ACL->version = ACL_ACLVERSION; ACL->total = 1; ACL->positive = 1; ACL->negative = 0; ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */ ACL->entries[0].rights = PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE | PRSFS_LOCK | PRSFS_ADMINISTER; vnode->type = vDirectory; vnode->cloned = 0; vnode->modeBits = 0777; vnode->linkCount = 2; vnode->length = length; vnode->uniquifier = 1; V_uniquifier(vp) = vnode->uniquifier+1; vnode->dataVersion = 1; VNDISK_SET_INO(vnode, inodeNumber); vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp); vnode->author = 0; vnode->owner = 0; vnode->parent = 0; vnode->vnodeMagic = vcp->magic; IH_INIT(h, vp->device, V_parentId(vp), vp->vnodeIndex[vLarge].handle->ih_ino); fdP = IH_OPEN(h); assert(fdP != NULL); code = FDH_SEEK(fdP, vnodeIndexOffset(vcp, 1), SEEK_SET); assert(code >= 0); code = FDH_WRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE); assert(code == SIZEOF_LARGEDISKVNODE); FDH_REALLYCLOSE(fdP); IH_RELEASE(h); V_diskused(vp) = nBlocks(vnode->length); return 1; } afs_int32 SAFSVolPartitionInfo (acid,pname,partition) struct rx_call *acid; char *pname; struct diskPartition *partition; { afs_int32 code; code = VolPartitionInfo (acid,pname,partition); osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END); return code; } afs_int32 VolPartitionInfo (acid,pname,partition) struct rx_call *acid; char *pname; struct diskPartition *partition; { register struct DiskPartition *dp; /* if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS; */ VResetDiskUsage(); dp = VGetPartition(pname, 0); if(dp) { strncpy(partition->name,dp->name,32); strncpy(partition->devName,dp->devName,32); partition->lock_fd = dp->lock_fd ; partition->free = dp->free; partition->minFree = dp->totalUsable; return 0; } else return VOLSERILLEGAL_PARTITION; } /* obliterate a volume completely, and slowly. */ afs_int32 SAFSVolNukeVolume (acid, apartID, avolID) struct rx_call *acid; afs_int32 apartID, avolID; { afs_int32 code; code = VolNukeVolume (acid, apartID, avolID); osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END); return code; } afs_int32 VolNukeVolume (acid, apartID, avolID) struct rx_call *acid; afs_int32 apartID, avolID; { register char *tp; char partName[50]; afs_int32 error; register afs_int32 code; struct Volume *tvp; char caller[MAXKTCNAMELEN]; /* check for access */ if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS; if (DoLogging) Log("%s is executing VolNukeVolume %u\n", caller, avolID); tp = volutil_PartitionName(apartID); if (!tp) return VOLSERNOVOL; strcpy(partName, tp); /* remember it for later */ /* we first try to attach the volume in update mode, so that the file * server doesn't try to use it (and abort) while (or after) we delete it. * If we don't get the volume, that's fine, too. We just won't put it back. */ tvp = XAttachVolume(&error, avolID, apartID, V_UPDATE); code = nuke(partName, avolID); if (tvp) VDetachVolume(&error, tvp); return code; } /* create a new volume, with name aname, on the specified partition (1..n) * and of type atype (readwriteVolume, readonlyVolume, backupVolume). * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid * for the volume id (useful for things like volume restore). * Return the new volume id in *avolid. */ afs_int32 SAFSVolCreateVolume (acid, apart, aname, atype, aparent, avolid, atrans) struct rx_call *acid; afs_int32 apart; afs_int32 atype; char *aname; afs_int32 aparent; afs_int32 *atrans; afs_int32 *avolid; { afs_int32 code; code = VolCreateVolume (acid, apart, aname, atype, aparent, avolid, atrans); osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG, *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent, AUD_END); return code; } afs_int32 VolCreateVolume (acid, apart, aname, atype, aparent, avolid, atrans) struct rx_call *acid; afs_int32 apart; afs_int32 atype; char *aname; afs_int32 aparent; afs_int32 *atrans; afs_int32 *avolid; { afs_int32 error; register Volume *vp; afs_int32 junk; /* discardable error code */ register afs_int32 volumeID, doCreateRoot=1; register struct volser_trans *tt; char ppath[30]; char caller[MAXKTCNAMELEN]; if (strlen(aname) > 31) return VOLSERBADNAME; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS; if (DoLogging) Log("%s is executing CreateVolume '%s'\n", caller, aname); if (error = ConvertPartition(apart, ppath, sizeof(ppath))) return error;/*a standard unix error*/ if (atype != readwriteVolume && atype != readonlyVolume && atype != backupVolume) return EINVAL; if ((volumeID = *avolid) == 0) { Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n",aname); return E2BIG; } if ((aparent == volumeID) && (atype == readwriteVolume)) { doCreateRoot = 0; } if (aparent == 0) aparent = volumeID; tt = NewTrans(volumeID, apart); if (!tt) { Log("1 createvolume: failed to create trans\n"); return VOLSERVOLBUSY; /* volume already busy! */ } vp = VCreateVolume(&error, ppath, volumeID, aparent); if (error) { Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n",error); LogError(error); DeleteTrans(tt); return EIO; } V_uniquifier(vp) = 1; V_creationDate(vp) = V_copyDate(vp); V_inService(vp) = V_blessed(vp) = 1; V_type(vp) = atype; AssignVolumeName(&V_disk(vp), aname, 0); if (doCreateRoot) ViceCreateRoot(vp); V_destroyMe(vp) = DESTROY_ME; V_inService(vp) = 0; V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */ VUpdateVolume(&error, vp); if (error) { Log("1 Volser: create UpdateVolume failed, code %d\n", error); LogError(error); DeleteTrans(tt); VDetachVolume(&junk, vp); /* rather return the real error code */ return error; } tt->volume = vp; *atrans = tt->tid; strcpy(tt->lastProcName,"CreateVolume"); tt->rxCallPtr = acid; Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname); tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt)) return VOLSERTRELE_ERROR; return 0; } /* delete the volume associated with this transaction */ afs_int32 SAFSVolDeleteVolume (acid, atrans) afs_int32 atrans; struct rx_call *acid; { afs_int32 code; code = VolDeleteVolume (acid, atrans); osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END); return code; } afs_int32 VolDeleteVolume (acid, atrans) afs_int32 atrans; struct rx_call *acid; { register struct volser_trans *tt; afs_int32 error; char caller[MAXKTCNAMELEN]; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS; tt = FindTrans(atrans); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: Delete: volume %u already deleted \n",tt->volid); TRELE(tt); return ENOENT; } if (DoLogging) Log("%s is executing Delete Volume %u\n", caller, tt->volid); strcpy(tt->lastProcName,"DeleteVolume"); tt->rxCallPtr = acid; VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */ tt->vflags |= VTDeleted; /* so we know not to do anything else to it */ tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt)) return VOLSERTRELE_ERROR; Log("1 Volser: Delete: volume %u deleted \n",tt->volid); return 0; /* vpurgevolume doesn't set an error code */ } /* make a clone of the volume associated with atrans, possibly giving it a new * number (allocate a new number if *newNumber==0, otherwise use *newNumber * for the clone's id). The new clone is given the name newName. Finally, due to * efficiency considerations, if purgeId is non-zero, we purge that volume when doing * the clone operation. This may be useful when making new backup volumes, for instance * since the net result of a clone and a purge generally leaves many inode ref counts * the same, while doing them separately would result in far more iincs and idecs being * peformed (and they are slow operations). */ afs_int32 SAFSVolClone (acid, atrans, purgeId, newType, newName, newNumber) struct rx_call *acid; afs_int32 atrans; afs_int32 newType; afs_int32 *newNumber; afs_int32 purgeId; /* for efficiency reasons, sometimes faster to piggyback a purge here */ char *newName; { afs_int32 code; code = VolClone (acid, atrans, purgeId, newType, newName, newNumber); osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId, AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber, AUD_END); return code; } afs_int32 VolClone (acid, atrans, purgeId, newType, newName, newNumber) struct rx_call *acid; afs_int32 atrans; afs_int32 newType; afs_int32 *newNumber; afs_int32 purgeId; /* for efficiency reasons, sometimes faster to piggyback a purge here */ char *newName; { VolumeId newId; register struct Volume *originalvp, *purgevp, *newvp; Error error, code; register struct volser_trans *tt,*ttc; char caller[MAXKTCNAMELEN]; if (strlen(newName)>31) return VOLSERBADNAME; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ if (DoLogging) Log("%s is executing Clone Volume new name=%s\n", caller, newName); error = 0; originalvp = (Volume *) 0; purgevp = (Volume *) 0; newvp = (Volume *) 0; tt = ttc = (struct volser_trans *) 0; if (!newNumber || !*newNumber) { Log("1 Volser: Clone: missing volume number for the clone; aborted\n"); goto fail; } newId = *newNumber; if (newType != readonlyVolume && newType != backupVolume) return EINVAL; tt = FindTrans(atrans); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: Clone: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } ttc = NewTrans(newId,tt->partition); if (!ttc) { /* someone is messing with the clone already */ TRELE(tt); return VBUSY; } strcpy(tt->lastProcName,"Clone"); tt->rxCallPtr = acid; if (purgeId) { purgevp = VAttachVolume(&error, purgeId, V_UPDATE); if (error) { Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId); goto fail; } } else { purgevp = (struct Volume *) 0; } originalvp = tt->volume; if ((V_type(originalvp) == backupVolume) || (V_type(originalvp) == readonlyVolume)){ Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n"); error = EROFS; goto fail; } if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) { Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n", V_id(originalvp)); error = VOFFLINE; goto fail; } if (purgevp) { if (originalvp->device != purgevp->device) { Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId); error = EXDEV; goto fail; } if (V_type(purgevp) != readonlyVolume) { Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n"); error = EINVAL; goto fail; } if (V_type(originalvp) == readonlyVolume && V_parentId(originalvp) != V_parentId(purgevp)) { Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId); error = EXDEV; goto fail; } if (V_type(originalvp) == readwriteVolume && tt->volid != V_parentId(purgevp)) { Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid); error = EXDEV; goto fail; } } error = 0; newvp = VCreateVolume(&error, originalvp->partition->name, newId, V_parentId(originalvp)); if (error) { Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n"); newvp = (Volume *) 0; goto fail; } if (newType == readonlyVolume) V_cloneId(originalvp) = newId; Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid, newId); if (purgevp) Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId); CloneVolume(&error, originalvp, newvp, purgevp); purgevp = (struct Volume *) 0; /* clone releases it, maybe even if error */ if (error) { Log("1 Volser: Clone: clone operation failed with code %d\n", error); LogError(error); goto fail; } if (newType == readonlyVolume) { AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly"); V_type(newvp) = readonlyVolume; } else if (newType == backupVolume) { AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup"); V_type(newvp) = backupVolume; V_backupId(originalvp) = newId; } strcpy(newvp->header->diskstuff.name,newName); V_creationDate(newvp) = V_copyDate(newvp); ClearVolumeStats(&V_disk(newvp)); V_destroyMe(newvp) = DESTROY_ME; V_inService(newvp) = 0; if (newType == backupVolume) { V_backupDate(originalvp) = V_copyDate(newvp); V_backupDate(newvp) = V_copyDate(newvp); } V_inUse(newvp) = 0; VUpdateVolume(&error, newvp); if (error) { Log("1 Volser: Clone: VUpdate failed code %d\n", error); LogError(error); goto fail; } VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */ newvp = (struct Volume *) 0; VUpdateVolume(&error, originalvp); if (error) { Log("1 Volser: Clone: original update %d\n", error); LogError(error); goto fail; } tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt)){ tt = (struct volser_trans *) 0; error = VOLSERTRELE_ERROR; goto fail; } DeleteTrans(ttc); return 0; fail: if (purgevp) VDetachVolume(&code, purgevp); if (newvp) VDetachVolume(&code, newvp); if (tt) { tt->rxCallPtr = (struct rx_call *)0; TRELE(tt); } if(ttc) DeleteTrans(ttc); return error; } /* reclone this volume into the specified id */ afs_int32 SAFSVolReClone (acid, atrans, cloneId) struct rx_call *acid; afs_int32 atrans; afs_int32 cloneId; { afs_int32 code; code = VolReClone (acid, atrans, cloneId); osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG, cloneId, AUD_END); return code; } afs_int32 VolReClone (acid, atrans, cloneId) struct rx_call *acid; afs_int32 atrans; afs_int32 cloneId; { register struct Volume *originalvp, *clonevp; Error error, code; afs_int32 newType; register struct volser_trans *tt,*ttc; char caller[MAXKTCNAMELEN]; /*not a super user*/ if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS; if (DoLogging) Log("%s is executing Reclone Volume %u\n", caller, cloneId); error = 0; clonevp = originalvp = (Volume *) 0; tt = (struct volser_trans *) 0; tt = FindTrans(atrans); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolReClone: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } ttc = NewTrans(cloneId, tt->partition); if (!ttc){ /* someone is messing with the clone already */ TRELE(tt); return VBUSY; } strcpy(tt->lastProcName,"ReClone"); tt->rxCallPtr = acid; originalvp = tt->volume; if ((V_type(originalvp) == backupVolume) || (V_type(originalvp) == readonlyVolume)){ Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n"); error = EROFS; goto fail; } if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) { Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n", V_id(originalvp)); error = VOFFLINE; goto fail; } clonevp = VAttachVolume(&error, cloneId, V_UPDATE); if (error) { Log("1 Volser: can't attach clone %d\n", cloneId); goto fail; } newType = V_type(clonevp); /* type of the new volume */ if (originalvp->device != clonevp->device) { Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, cloneId); error = EXDEV; goto fail; } if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) { Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n"); error = EINVAL; goto fail; } if (V_type(originalvp) == readonlyVolume && V_parentId(originalvp) != V_parentId(clonevp)) { Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId); error = EXDEV; goto fail; } if (V_type(originalvp) == readwriteVolume && tt->volid != V_parentId(clonevp)) { Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid); error = EXDEV; goto fail; } error = 0; Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid, cloneId); CloneVolume(&error, originalvp, clonevp, clonevp); if (error) { Log("1 Volser: Clone: reclone operation failed with code %d\n", error); LogError(error); goto fail; } /* fix up volume name and type, CloneVolume just propagated RW's */ if (newType == readonlyVolume) { AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly"); V_type(clonevp) = readonlyVolume; } else if (newType == backupVolume) { AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup"); V_type(clonevp) = backupVolume; V_backupId(originalvp) = cloneId; } /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */ /* pretend recloned volume is a totally new instance */ V_copyDate(clonevp) = time(0); V_creationDate(clonevp) = V_copyDate(clonevp); ClearVolumeStats(&V_disk(clonevp)); V_destroyMe(clonevp) = 0; V_inService(clonevp) = 0; if (newType == backupVolume) { V_backupDate(originalvp) = V_copyDate(clonevp); V_backupDate(clonevp) = V_copyDate(clonevp); } V_inUse(clonevp) = 0; VUpdateVolume(&error, clonevp); if (error) { Log("1 Volser: Clone: VUpdate failed code %d\n", error); LogError(error); goto fail; } VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */ clonevp = (struct Volume *) 0; VUpdateVolume(&error, originalvp); if (error) { Log("1 Volser: Clone: original update %d\n", error); LogError(error); goto fail; } tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt)){ tt = (struct volser_trans *) 0; error = VOLSERTRELE_ERROR; goto fail; } DeleteTrans(ttc); { struct DiskPartition *tpartp = originalvp->partition; FSYNC_askfs(cloneId, tpartp->name, FSYNC_RESTOREVOLUME, 0); } return 0; fail: if (clonevp) VDetachVolume(&code, clonevp); if (tt) { tt->rxCallPtr = (struct rx_call *)0; TRELE(tt); } if(ttc) DeleteTrans(ttc); return error; } /* create a new transaction, associated with volume and partition. Type of * volume transaction is spec'd by iflags. New trans id is returned in ttid. * See volser.h for definition of iflags (the constants are named IT*). */ afs_int32 SAFSVolTransCreate (acid, volume, partition, iflags, ttid) struct rx_call *acid; afs_int32 volume; afs_int32 partition; afs_int32 iflags; afs_int32 *ttid; { afs_int32 code; code = VolTransCreate (acid, volume, partition, iflags, ttid); osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume, AUD_END); return code; } afs_int32 VolTransCreate (acid, volume, partition, iflags, ttid) struct rx_call *acid; afs_int32 volume; afs_int32 partition; afs_int32 iflags; afs_int32 *ttid; { register struct volser_trans *tt; register Volume *tv; afs_int32 error, code; afs_int32 mode; char caller[MAXKTCNAMELEN]; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ if (iflags & ITCreate) mode = V_SECRETLY; else if (iflags & ITBusy) mode = V_CLONE; else if (iflags & ITReadOnly) mode = V_READONLY; else if (iflags & ITOffline) mode = V_UPDATE; else { Log("1 Volser: TransCreate: Could not create trans, error %u\n",EINVAL); LogError(EINVAL); return EINVAL; } tt = NewTrans(volume, partition); if (!tt) { /* can't create a transaction? put the volume back */ Log("1 transcreate: can't create transaction\n"); return VOLSERVOLBUSY; } tv = XAttachVolume(&error, volume, partition, mode); if (error) { /* give up */ if (tv) VDetachVolume(&code, tv); DeleteTrans(tt); return error; } tt->volume = tv; *ttid = tt->tid; tt->iflags = iflags; tt->vflags = 0; strcpy(tt->lastProcName,"TransCreate"); if(TRELE(tt)) return VOLSERTRELE_ERROR; return 0; } /* using aindex as a 0-based index, return the aindex'th volume on this server * Both the volume number and partition number (one-based) are returned. */ afs_int32 SAFSVolGetNthVolume (acid, aindex, avolume, apart) struct rx_call *acid; afs_int32 aindex; afs_int32 *avolume; afs_int32 *apart; { afs_int32 code; code = VolGetNthVolume (acid, aindex, avolume, apart); osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END); return code; } afs_int32 VolGetNthVolume (acid, aindex, avolume, apart) struct rx_call *acid; afs_int32 aindex; afs_int32 *avolume; afs_int32 *apart; { Log("1 Volser: GetNthVolume: Not yet implemented\n"); return VOLSERNO_OP; } /* return the volume flags (VT* constants in volser.h) associated with this * transaction. */ afs_int32 SAFSVolGetFlags (acid, atid, aflags) struct rx_call *acid; afs_int32 atid; afs_int32 *aflags; { afs_int32 code; code = VolGetFlags (acid, atid, aflags); osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END); return code; } afs_int32 VolGetFlags (acid, atid, aflags) struct rx_call *acid; afs_int32 atid; afs_int32 *aflags; { register struct volser_trans *tt; tt = FindTrans(atid); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolGetFlags: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } strcpy(tt->lastProcName,"GetFlags"); tt->rxCallPtr = acid; *aflags = tt->vflags; tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt)) return VOLSERTRELE_ERROR; return 0; } /* Change the volume flags (VT* constants in volser.h) associated with this * transaction. Effects take place immediately on volume, although volume * remains attached as usual by the transaction. */ afs_int32 SAFSVolSetFlags (acid, atid, aflags) struct rx_call *acid; afs_int32 atid; afs_int32 aflags; { afs_int32 code; code = VolSetFlags (acid, atid, aflags); osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags, AUD_END); return code; } afs_int32 VolSetFlags (acid, atid, aflags) struct rx_call *acid; afs_int32 atid; afs_int32 aflags; { register struct volser_trans *tt; register struct Volume *vp; afs_int32 error; char caller[MAXKTCNAMELEN]; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ /* find the trans */ tt = FindTrans(atid); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolSetFlags: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } strcpy(tt->lastProcName,"SetFlags"); tt->rxCallPtr = acid; vp = tt->volume; /* pull volume out of transaction */ /* check if we're allowed to make any updates */ if (tt->iflags & ITReadOnly) { TRELE(tt); return EROFS; } /* handle delete-on-salvage flag */ if (aflags & VTDeleteOnSalvage) { V_destroyMe(tt->volume) = DESTROY_ME; } else { V_destroyMe(tt->volume) = 0; } if (aflags & VTOutOfService) { V_inService(vp) = 0; } else { V_inService(vp) = 1; } VUpdateVolume(&error, vp); tt->vflags = aflags; tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt) && !error) return VOLSERTRELE_ERROR; return error; } /* dumpS the volume associated with a particular transaction from a particular * date. Send the dump to a different transaction (destTrans) on the server * specified by the destServer structure. */ afs_int32 SAFSVolForward (acid, fromTrans, fromDate, destination, destTrans,cookie) struct rx_call *acid; afs_int32 fromTrans; afs_int32 fromDate; struct destServer *destination; struct restoreCookie *cookie; afs_int32 destTrans; { afs_int32 code; code = VolForward (acid, fromTrans, fromDate, destination, destTrans,cookie); osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST, destination->destHost, AUD_LONG, destTrans, AUD_END); return code; } afs_int32 VolForward (acid, fromTrans, fromDate, destination, destTrans,cookie) struct rx_call *acid; afs_int32 fromTrans; afs_int32 fromDate; struct destServer *destination; struct restoreCookie *cookie; afs_int32 destTrans; { register struct volser_trans *tt; register afs_int32 code; register struct rx_connection *tcon; struct rx_call *tcall; register struct Volume *vp; struct rx_securityClass *securityObject; afs_int32 securityIndex; char caller[MAXKTCNAMELEN]; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ /* initialize things */ tcon = (struct rx_connection *) 0; tt = (struct volser_trans *) 0; /* find the local transaction */ tt = FindTrans(fromTrans); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolForward: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } vp = tt->volume; strcpy(tt->lastProcName,"Forward"); /* get auth info for the this connection (uses afs from ticket file) */ code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex); if (code) { TRELE(tt); return code; } /* make an rpc connection to the other server */ tcon = rx_NewConnection(htonl(destination->destHost), htons(destination->destPort),VOLSERVICE_ID, securityObject, securityIndex); if (!tcon) { tt->rxCallPtr = (struct rx_call *)0; TRELE(tt); return ENOTCONN; } tcall = rx_NewCall(tcon); tt->rxCallPtr = tcall; /* start restore going. fromdate == 0 --> doing an incremental dump/restore */ code = StartAFSVolRestore(tcall, destTrans, (fromDate? 1 : 0),cookie); if (code) { goto fail; } /* these next calls implictly call rx_Write when writing out data */ code = DumpVolume(tcall, vp, fromDate, 0);/* last field = don't dump all dirs */ if (code) goto fail; EndAFSVolRestore(tcall); /* probably doesn't do much */ tt->rxCallPtr = (struct rx_call *)0; code = rx_EndCall(tcall, 0); rx_DestroyConnection(tcon); /* done with the connection */ tcon = NULL; if (code) goto fail; if(TRELE(tt)) return VOLSERTRELE_ERROR; return 0; fail: if (tcon) { rx_EndCall(tcall,0); rx_DestroyConnection(tcon); } if (tt){ tt->rxCallPtr = (struct rx_call *)0; TRELE(tt); } return code; } /* Start a dump and send it to multiple places simultaneously. * If this returns an error (eg, return ENOENT), it means that * none of the releases worked. If this returns 0, that means * that one or more of the releases worked, and the caller has * to examine the results array to see which one(s). * This will only do EITHER incremental or full, not both, so it's * the caller's responsibility to be sure that all the destinations * need just an incremental (and from the same time), if that's * what we're doing. */ afs_int32 SAFSVolForwardMultiple (acid, fromTrans, fromDate, destinations, spare, cookie, results) struct rx_call *acid; afs_int32 fromTrans; afs_int32 fromDate; afs_int32 spare; manyDests *destinations; struct restoreCookie *cookie; manyResults *results; { afs_int32 securityIndex; struct rx_securityClass *securityObject; char caller[MAXKTCNAMELEN]; struct volser_trans *tt; afs_int32 ec, code, *codes; struct rx_connection **tcons; struct rx_call **tcalls; struct Volume *vp; int i, nconns, is_incremental; if (results) memset(results, 0, sizeof(manyResults)); if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ tt = FindTrans(fromTrans); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolForward: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } vp = tt->volume; strcpy(tt->lastProcName, "ForwardMulti"); /* (fromDate == 0) ==> incremental dump */ is_incremental = (fromDate ? 1 : 0); i= results->manyResults_len = destinations->manyDests_len; results->manyResults_val = codes = (afs_int32 *)malloc(i * sizeof(afs_int32)); tcons = (struct rx_connection **) malloc (i*sizeof (struct rx_connection *)); tcalls = (struct rx_call **) malloc (i*sizeof (struct rx_call *)); /* get auth info for this connection (uses afs from ticket file) */ code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex); if (code) { goto fail; /* in order to audit each failure */ } /* make connections to all the other servers */ for (i=0; i < destinations->manyDests_len; i++) { struct replica *dest = &(destinations->manyDests_val[i]); tcons[i] = rx_NewConnection(htonl(dest->server.destHost), htons(dest->server.destPort), VOLSERVICE_ID, securityObject, securityIndex); if (!tcons[i]) { codes[i] = ENOTCONN; } else { if (!(tcalls[i] = rx_NewCall(tcons[i]))) codes[i]=ENOTCONN; else { codes[i] = StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,cookie); if (codes[i]) { rx_EndCall (tcalls[i],0); tcalls[i] = 0; rx_DestroyConnection(tcons[i]); tcons[i] = 0; } } } } /* these next calls implictly call rx_Write when writing out data */ code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes); fail: for (i--; i >=0 ; i--) { struct replica *dest = &(destinations->manyDests_val[i]); if (!code && tcalls[i] && !codes[i]) { EndAFSVolRestore(tcalls[i]); } if (tcalls[i]) { ec = rx_EndCall(tcalls[i], 0); if (!codes[i]) codes[i] = ec; } if (tcons[i]) { rx_DestroyConnection(tcons[i]); /* done with the connection */ } osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG, fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG, dest->trans, AUD_END); } free (tcons); free (tcalls); if (tt) { tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt) && !code) /* return the first code if it's set */ return VOLSERTRELE_ERROR; } return code; } afs_int32 SAFSVolDump (acid, fromTrans, fromDate) struct rx_call *acid; afs_int32 fromTrans; afs_int32 fromDate; { afs_int32 code; code = VolDump (acid, fromTrans, fromDate); osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); return code; } afs_int32 VolDump (acid, fromTrans, fromDate) struct rx_call *acid; afs_int32 fromTrans; afs_int32 fromDate; { int code = 0; register struct volser_trans *tt; char caller[MAXKTCNAMELEN]; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ tt = FindTrans(fromTrans); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolDump: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } strcpy(tt->lastProcName,"Dump"); tt->rxCallPtr = acid; code = DumpVolume(acid, tt->volume, fromDate, 1); /* squirt out the volume's data, too */ if(code){tt->rxCallPtr = (struct rx_call *)0; TRELE(tt); return code;} tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt)) return VOLSERTRELE_ERROR; return 0; } /* * Ha! No more helper process! */ afs_int32 SAFSVolRestore (acid, atrans, aflags,cookie) struct rx_call *acid; afs_int32 aflags; afs_int32 atrans; struct restoreCookie *cookie; { afs_int32 code; code = VolRestore (acid, atrans, aflags,cookie); osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END); return code; } afs_int32 VolRestore (acid, atrans, aflags,cookie) struct rx_call *acid; int aflags; afs_int32 atrans; struct restoreCookie *cookie; { register struct volser_trans *tt; register afs_int32 code,tcode; char caller[MAXKTCNAMELEN]; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ tt = FindTrans(atrans); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolRestore: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } strcpy(tt->lastProcName,"Restore"); tt->rxCallPtr = acid; code = RestoreVolume(acid, tt->volume, (aflags & 1),cookie); /* last is incrementalp */ FSYNC_askfs(tt->volid, (char *) 0, FSYNC_RESTOREVOLUME, 0l);/*break call backs on the restored volume */ tt->rxCallPtr = (struct rx_call *)0; tcode = TRELE(tt); return (code? code : tcode); } /* end a transaction, returning the transaction's final error code in rcode */ afs_int32 SAFSVolEndTrans (acid, destTrans, rcode) struct rx_call *acid; afs_int32 destTrans; afs_int32 *rcode; { afs_int32 code; code = VolEndTrans (acid, destTrans, rcode); osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END); return code; } afs_int32 VolEndTrans (acid, destTrans, rcode) struct rx_call *acid; afs_int32 destTrans; afs_int32 *rcode; { register struct volser_trans *tt; char caller[MAXKTCNAMELEN]; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ tt = FindTrans(destTrans); if (!tt) {return ENOENT;} *rcode = tt->returnCode; DeleteTrans(tt); /* this does an implicit TRELE */ return 0; } afs_int32 SAFSVolSetForwarding (acid, atid, anewsite) struct rx_call *acid; afs_int32 atid; afs_int32 anewsite; { afs_int32 code; code = VolSetForwarding (acid, atid, anewsite); osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST, anewsite, AUD_END); return code; } afs_int32 VolSetForwarding (acid, atid, anewsite) struct rx_call *acid; afs_int32 atid; afs_int32 anewsite; { register struct volser_trans *tt; char caller[MAXKTCNAMELEN]; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ tt = FindTrans(atid); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } strcpy(tt->lastProcName,"SetForwarding"); tt->rxCallPtr = acid; FSYNC_askfs(tt->volid, (char *) 0, FSYNC_MOVEVOLUME, anewsite); tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt)) return VOLSERTRELE_ERROR; return 0; } afs_int32 SAFSVolGetStatus (acid, atrans, astatus) struct rx_call *acid; afs_int32 atrans; register struct volser_status *astatus; { afs_int32 code; code = VolGetStatus (acid, atrans, astatus); osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END); return code; } afs_int32 VolGetStatus (acid, atrans, astatus) struct rx_call *acid; afs_int32 atrans; register struct volser_status *astatus; { register struct Volume *tv; register struct VolumeDiskData *td; struct volser_trans *tt; tt = FindTrans(atrans); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolGetStatus: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } strcpy(tt->lastProcName,"GetStatus"); tt->rxCallPtr = acid; tv = tt->volume; if (!tv) { tt->rxCallPtr = (struct rx_call *)0; TRELE(tt); return ENOENT; } td = &tv->header->diskstuff; astatus->volID = td->id; astatus->nextUnique = td->uniquifier; astatus->type = td->type; astatus->parentID = td->parentId; astatus->cloneID = td->cloneId; astatus->backupID = td->backupId; astatus->restoredFromID = td->restoredFromId; astatus->maxQuota = td->maxquota; astatus->minQuota = td->minquota; astatus->owner = td->owner; astatus->creationDate = td->creationDate; astatus->accessDate = td->accessDate; astatus->updateDate = td->updateDate; astatus->expirationDate = td->expirationDate; astatus->backupDate = td->backupDate; astatus->copyDate = td->copyDate; tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt)) return VOLSERTRELE_ERROR; return 0; } afs_int32 SAFSVolSetInfo (acid, atrans, astatus) struct rx_call *acid; afs_int32 atrans; register struct volintInfo *astatus; { afs_int32 code; code = VolSetInfo (acid, atrans, astatus); osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END); return code; } afs_int32 VolSetInfo (acid, atrans, astatus) struct rx_call *acid; afs_int32 atrans; register struct volintInfo *astatus; { register struct Volume *tv; register struct VolumeDiskData *td; struct volser_trans *tt; char caller[MAXKTCNAMELEN]; afs_int32 error; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ tt = FindTrans(atrans); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolSetInfo: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } strcpy(tt->lastProcName,"SetStatus"); tt->rxCallPtr = acid; tv = tt->volume; if (!tv) { tt->rxCallPtr = (struct rx_call *)0; TRELE(tt); return ENOENT; } td = &tv->header->diskstuff; /* * Add more fields as necessary */ if (astatus->maxquota != -1) td->maxquota = astatus->maxquota; if (astatus->dayUse != -1) td->dayUse = astatus->dayUse; VUpdateVolume(&error, tv); tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt)) return VOLSERTRELE_ERROR; return 0; } afs_int32 SAFSVolGetName (acid, atrans, aname) struct rx_call *acid; afs_int32 atrans; char **aname; { afs_int32 code; code = VolGetName (acid, atrans, aname); osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END); return code; } afs_int32 VolGetName (acid, atrans, aname) struct rx_call *acid; afs_int32 atrans; char **aname; { register struct Volume *tv; register struct VolumeDiskData *td; struct volser_trans *tt; register int len; *aname = (char *)0; tt = FindTrans(atrans); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolGetName: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } strcpy(tt->lastProcName,"GetName"); tt->rxCallPtr = acid; tv = tt->volume; if (!tv) { tt->rxCallPtr = (struct rx_call *)0; TRELE(tt); return ENOENT; } td = &tv->header->diskstuff; len = strlen(td->name)+1; /* don't forget the null */ if (len >= SIZE) { tt->rxCallPtr = (struct rx_call *)0; TRELE(tt); return E2BIG; } *aname = (char *)malloc(len); strcpy(*aname, td->name); tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt)) return VOLSERTRELE_ERROR; return 0; } /*this is a handshake to indicate that the next call will be SAFSVolRestore * - a noop now !*/ afs_int32 SAFSVolSignalRestore (acid, volname, volType, parentId, cloneId) struct rx_call *acid; char volname[]; afs_int32 parentId, cloneId; int volType; { return 0; } /*return a list of all partitions on the server. The non mounted *partitions are returned as -1 in the corresponding slot in partIds*/ afs_int32 SAFSVolListPartitions (acid, partIds) struct rx_call *acid; struct pIDs *partIds; { afs_int32 code; code = VolListPartitions (acid, partIds); osi_auditU(acid, VS_ListParEvent, code, AUD_END); return code; } afs_int32 VolListPartitions (acid, partIds) struct rx_call *acid; struct pIDs *partIds; { char namehead[9]; int code; char i; strcpy(namehead, "/vicep"); /*7 including null terminator*/ /* Just return attached partitions. */ namehead[7] = '\0'; for (i=0; i<26; i++) { namehead[6] = i + 'a'; if (VGetPartition(namehead, 0)) partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1; } return 0; } /*return a list of all partitions on the server. The non mounted *partitions are returned as -1 in the corresponding slot in partIds*/ afs_int32 SAFSVolXListPartitions (acid, pEntries) struct rx_call *acid; struct partEntries *pEntries; { afs_int32 code; code = XVolListPartitions (acid, pEntries); osi_auditU(acid, VS_ListParEvent, code, AUD_END); return code; } afs_int32 XVolListPartitions (acid, pEntries) struct rx_call *acid; struct partEntries *pEntries; { struct stat rbuf, pbuf; char namehead[9]; struct partList partList; struct DiskPartition *dp; int i, j=0, k; strcpy(namehead, "/vicep"); /*7 including null terminator*/ /* Only report attached partitions */ for(i = 0 ; i < VOLMAXPARTS; i++){ if (i < 26) { namehead[6] = i + 'a'; namehead[7] = '\0'; } else { k = i - 26; namehead[6] = 'a' + (k/26); namehead[7] = 'a' + (k%26); namehead[8] = '\0'; } dp = VGetPartition(namehead, 0); if (dp) partList.partId[j++] = i; } pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int)); memcpy((char *)pEntries->partEntries_val, (char *)&partList, j * sizeof(int)); pEntries->partEntries_len = j; return 0; } /*extract the volume id from string vname. Its of the form " V0*.vol "*/ afs_int32 ExtractVolId(vname) char vname[]; { int i; char name[VOLSER_MAXVOLNAME +1]; strcpy(name,vname); i = 0; while(name[i] == 'V' || name[i] == '0') i++; name[11] = '\0'; /* smash the "." */ return(atol(&name[i])); } /*return the name of the next volume header in the directory associated with dirp and dp. *the volume id is returned in volid, and volume header name is returned in volname*/ GetNextVol(DIR *dirp, char *volname, afs_int32 *volid) { struct dirent *dp; dp = readdir(dirp);/*read next entry in the directory */ if(dp){ if((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)){ *volid = ExtractVolId(dp->d_name); strcpy(volname,dp->d_name); return 0;/*return the name of the file representing a volume */ } else { strcpy(volname,""); return 0;/*volname doesnot represent a volume*/ } } else {strcpy(volname,"EOD"); return 0;/*end of directory */} } /*return the header information about the */ afs_int32 SAFSVolListOneVolume (acid, partid, volumeId, volumeInfo) struct rx_call *acid; afs_int32 volumeId, partid; volEntries *volumeInfo; { afs_int32 code; code = VolListOneVolume (acid, partid, volumeId, volumeInfo); osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END); return code; } afs_int32 VolListOneVolume (acid, partid, volumeId, volumeInfo) struct rx_call *acid; afs_int32 volumeId, partid; volEntries *volumeInfo; { volintInfo *pntr; register struct Volume *tv; struct DiskPartition *partP; struct volser_trans *ttc; char pname[9], volname[20]; afs_int32 error = 0; DIR *dirp; afs_int32 volid; int found = 0; unsigned int now; volumeInfo->volEntries_val = (volintInfo *) malloc( sizeof(volintInfo)); pntr = volumeInfo->volEntries_val; volumeInfo->volEntries_len = 1; if(GetPartName(partid, pname)) return VOLSERILLEGAL_PARTITION; if (!(partP = VGetPartition(pname, 0))) return VOLSERILLEGAL_PARTITION; dirp = opendir(VPartitionPath(partP)); if(dirp == NULL) return VOLSERILLEGAL_PARTITION; strcpy(volname,""); ttc = (struct volser_trans *) 0; tv = (Volume *) 0; /* volume not attached */ while(strcmp(volname,"EOD") && !found){/*while there are more volumes in the partition */ if(!strcmp(volname,"")) {/* its not a volume, fetch next file */ GetNextVol(dirp, volname, &volid); continue; /*back to while loop */ } if(volid == volumeId) { /*copy other things too */ found = 1; IOMGR_Poll(); /*make sure that the client doesnot time out*/ ttc = NewTrans(volid,partid); if(!ttc){ pntr->status = VBUSY; pntr->volid = volid; goto drop; } tv = VAttachVolumeByName(&error, pname, volname,V_READONLY); if(error) { pntr->status = 0; /*things are messed up */ strcpy(pntr->name,volname); pntr->volid = volid; Log("1 Volser: ListVolumes: Could not attach volume %u (%s:%s), error=%d\n",volid,pname,volname,error); goto drop; } if(tv->header->diskstuff.destroyMe == DESTROY_ME) { /*this volume will be salvaged */ pntr->status = 0; strcpy(pntr->name,volname); pntr->volid = volid; Log("1 Volser: ListVolumes: Volume %u (%s) will be destroyed on next salvage\n",volid,volname); goto drop; } if(tv->header->diskstuff.needsSalvaged){ /*this volume will be salvaged */ pntr->status = 0; strcpy(pntr->name,volname); pntr->volid = volid; Log("1 Volser: ListVolumes: Volume %u (%s) needs to be salvaged\n",volid,volname); goto drop; } /*read in the relevant info */ pntr->status = VOK ; /*its ok */ pntr->volid = tv->header->diskstuff.id; strcpy(pntr->name,tv->header->diskstuff.name); pntr->type = tv->header->diskstuff.type; /*if ro volume*/ pntr->cloneID = tv->header->diskstuff.cloneId; /*if rw volume*/ pntr->backupID = tv->header->diskstuff.backupId; pntr->parentID = tv->header->diskstuff.parentId; pntr->copyDate = tv->header->diskstuff.copyDate; pntr->inUse = tv->header->diskstuff.inUse; pntr->size = tv->header->diskstuff.diskused; pntr->needsSalvaged = tv->header->diskstuff.needsSalvaged; pntr->destroyMe = tv->header->diskstuff.destroyMe; pntr->maxquota = tv->header->diskstuff.maxquota; pntr->filecount = tv->header->diskstuff.filecount; now = FT_ApproxTime(); if (now - tv->header->diskstuff.dayUseDate > OneDay) pntr->dayUse = 0; else pntr->dayUse = tv->header->diskstuff.dayUse; pntr->creationDate = tv->header->diskstuff.creationDate; pntr->accessDate = tv->header->diskstuff.accessDate; pntr->updateDate = tv->header->diskstuff.updateDate; pntr->backupDate = tv->header->diskstuff.backupDate; pntr->spare0 = tv->header->diskstuff.minquota; pntr->spare1 = (long) tv->header->diskstuff.weekUse[0] + (long) tv->header->diskstuff.weekUse[1] + (long) tv->header->diskstuff.weekUse[2] + (long) tv->header->diskstuff.weekUse[3] + (long) tv->header->diskstuff.weekUse[4] + (long) tv->header->diskstuff.weekUse[5] + (long) tv->header->diskstuff.weekUse[6]; pntr->flags = pntr->spare2 = pntr->spare3 = (long) 0; VDetachVolume(&error,tv);/*free the volume */ tv = (Volume *) 0; if(error) { pntr->status = 0; /*things are messed up */ strcpy(pntr->name,volname); Log("1 Volser: ListVolumes: Could not detach volume %s\n",volname); goto drop; } } GetNextVol(dirp, volname, &volid); } drop: if (tv) { VDetachVolume(&error, tv); tv = (Volume *) 0; } if(ttc) { DeleteTrans(ttc); ttc = (struct volser_trans *) 0; } closedir(dirp); if(found)return 0 ; else return ENODEV; } /*------------------------------------------------------------------------ * EXPORTED SAFSVolXListOneVolume * * Description: * Returns extended info on volume a_volID on partition a_partID. * * Arguments: * a_rxCidP : Pointer to the Rx call we're performing. * a_partID : Partition for which we want the extended list. * a_volID : Volume ID we wish to know about. * a_volumeXInfoP : Ptr to the extended info blob. * * Returns: * 0 Successful operation * VOLSERILLEGAL_PARTITION if we got a bogus partition ID * * Environment: * Nothing interesting. * * Side Effects: * As advertised. *------------------------------------------------------------------------*/ afs_int32 SAFSVolXListOneVolume (a_rxCidP, a_partID, a_volID, a_volumeXInfoP) struct rx_call *a_rxCidP; afs_int32 a_partID; afs_int32 a_volID; volXEntries *a_volumeXInfoP; { afs_int32 code; code = VolXListOneVolume (a_rxCidP, a_partID, a_volID, a_volumeXInfoP); osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END); return code; } afs_int32 VolXListOneVolume (a_rxCidP, a_partID, a_volID, a_volumeXInfoP) struct rx_call *a_rxCidP; afs_int32 a_partID; afs_int32 a_volID; volXEntries *a_volumeXInfoP; { /*SAFSVolXListOneVolume*/ volintXInfo *xInfoP; /*Ptr to the extended vol info*/ register struct Volume *tv; /*Volume ptr*/ struct volser_trans *ttc; /*Volume transaction ptr*/ struct DiskPartition *partP; /*Ptr to partition */ char pname[9], volname[20]; /*Partition, volume names*/ afs_int32 error; /*Error code*/ afs_int32 code; /*Return code*/ DIR *dirp; /*Partition directory ptr*/ afs_int32 currVolID; /*Current volume ID*/ int found = 0; /*Did we find the volume we need?*/ struct VolumeDiskData *volDiskDataP; /*Ptr to on-disk volume data*/ int numStatBytes; /*Num stat bytes to copy per volume*/ unsigned int now; /* * Set up our pointers for action, marking our structure to hold exactly * one entry. Also, assume we'll fail in our quest. */ a_volumeXInfoP->volXEntries_val = (volintXInfo *) malloc(sizeof(volintXInfo)); xInfoP = a_volumeXInfoP->volXEntries_val; a_volumeXInfoP->volXEntries_len = 1; code = ENODEV; /* * If the partition name we've been given is bad, bogue out. */ if (GetPartName(a_partID, pname)) return(VOLSERILLEGAL_PARTITION); /* * Open the directory representing the given AFS parttion. If we can't * do that, we lose. */ if (!(partP = VGetPartition(pname, 0))) return VOLSERILLEGAL_PARTITION; dirp = opendir(VPartitionPath(partP)); if (dirp == NULL) return(VOLSERILLEGAL_PARTITION); /* * Sweep through the partition directory, looking for the desired entry. * First, of course, figure out how many stat bytes to copy out of each * volume. */ numStatBytes = 4*((2*VOLINT_STATS_NUM_RWINFO_FIELDS) + (4*VOLINT_STATS_NUM_TIME_FIELDS)); strcpy(volname, ""); ttc = (struct volser_trans *)0; /*No transaction yet*/ tv = (Volume *)0; /*Volume not yet attached*/ while (strcmp(volname,"EOD") && !found) { /* * If this is not a volume, move on to the next entry in the * partition's directory. */ if (!strcmp(volname,"")) { GetNextVol(dirp, volname, &currVolID); continue; } if (currVolID == a_volID) { /* * We found the volume entry we're interested. Pull out the * extended information, remembering to poll (so that the client * doesn't time out) and to set up a transaction on the volume. */ found = 1; IOMGR_Poll(); ttc = NewTrans(currVolID, a_partID); if (!ttc) { /* * Couldn't get a transaction on this volume; let our caller * know it's busy. */ xInfoP->status = VBUSY; xInfoP->volid = currVolID; goto drop; } /* * Attach the volume, give up on the volume if we can't. */ tv = VAttachVolumeByName(&error, pname, volname, V_READONLY); if (error) { xInfoP->status = 0; /*things are messed up */ strcpy(xInfoP->name, volname); xInfoP->volid = currVolID; Log("1 Volser: XListOneVolume: Could not attach volume %u\n", currVolID); goto drop; } /* * Also bag out on this volume if it's been marked as needing a * salvage or to-be-destroyed. */ volDiskDataP = &(tv->header->diskstuff); if (volDiskDataP->destroyMe == DESTROY_ME) { xInfoP->status = 0; strcpy(xInfoP->name, volname); xInfoP->volid = currVolID; Log("1 Volser: XListOneVolume: Volume %u will be destroyed on next salvage\n", currVolID); goto drop; } if (volDiskDataP->needsSalvaged) { xInfoP->status = 0; strcpy(xInfoP->name, volname); xInfoP->volid = currVolID; Log("1 Volser: XListOneVolume: Volume %u needs to be salvaged\n", currVolID); goto drop; } /* * Pull out the desired info and stuff it into the area we'll be * returning to our caller. */ strcpy(xInfoP->name,volDiskDataP->name); xInfoP->volid = volDiskDataP->id; xInfoP->type = volDiskDataP->type; xInfoP->backupID = volDiskDataP->backupId; xInfoP->parentID = volDiskDataP->parentId; xInfoP->cloneID = volDiskDataP->cloneId; xInfoP->status = VOK; xInfoP->copyDate = volDiskDataP->copyDate; xInfoP->inUse = volDiskDataP->inUse; xInfoP->creationDate = volDiskDataP->creationDate; xInfoP->accessDate = volDiskDataP->accessDate; xInfoP->updateDate = volDiskDataP->updateDate; xInfoP->backupDate = volDiskDataP->backupDate; now = FT_ApproxTime(); if (now - volDiskDataP->dayUseDate > OneDay) xInfoP->dayUse = 0; else xInfoP->dayUse = volDiskDataP->dayUse; xInfoP->filecount = volDiskDataP->filecount; xInfoP->maxquota = volDiskDataP->maxquota; xInfoP->size = volDiskDataP->diskused; /* * Copy out the stat fields in a single operation. */ memcpy((char *)&(xInfoP->stat_reads[0]), (char *)&(volDiskDataP->stat_reads[0]), numStatBytes); /* * We're done copying. Detach the volume and iterate (at this * point, since we found our volume, we'll then drop out of the * loop). */ VDetachVolume(&error, tv); tv = (Volume *)0; if (error) { xInfoP->status = 0; strcpy(xInfoP->name, volname); Log("1 Volser: XListOneVolumes Couldn't detach volume %s\n", volname); goto drop; } /* * At this point, we're golden. */ code = 0; } /*Found desired volume*/ GetNextVol(dirp, volname, &currVolID); } /* * Drop the transaction we have for this volume. */ drop: if (tv) { VDetachVolume(&error, tv); tv = (Volume *)0; } if (ttc) { DeleteTrans(ttc); ttc = (struct volser_trans *)0; } /* * Clean up before going to dinner: close the partition directory, * return the proper value. */ closedir(dirp); return(code); } /*SAFSVolXListOneVolume*/ /*returns all the volumes on partition partid. If flags = 1 then all the * relevant info about the volumes is also returned */ afs_int32 SAFSVolListVolumes (acid, partid, flags, volumeInfo) struct rx_call *acid; afs_int32 flags, partid; volEntries *volumeInfo; { afs_int32 code; code = VolListVolumes (acid, partid, flags, volumeInfo); osi_auditU(acid, VS_ListVolEvent, code, AUD_END); return code; } afs_int32 VolListVolumes (acid, partid, flags, volumeInfo) struct rx_call *acid; afs_int32 flags, partid; volEntries *volumeInfo; { volintInfo *pntr; register struct Volume *tv; struct DiskPartition *partP; struct volser_trans *ttc; afs_int32 allocSize = 1000;/*to be changed to a larger figure */ char pname[9], volname[20]; afs_int32 error = 0; DIR *dirp; afs_int32 volid; unsigned int now; volumeInfo->volEntries_val = (volintInfo *) malloc(allocSize * sizeof(volintInfo)); pntr = volumeInfo->volEntries_val; volumeInfo->volEntries_len = 0; if(GetPartName(partid, pname)) return VOLSERILLEGAL_PARTITION; if (!(partP = VGetPartition(pname, 0))) return VOLSERILLEGAL_PARTITION; dirp = opendir(VPartitionPath(partP)); if(dirp == NULL) return VOLSERILLEGAL_PARTITION; strcpy(volname,""); while(strcmp(volname,"EOD")){/*while there are more partitions in the partition */ ttc = (struct volser_trans *) 0; /* new one for each pass */ tv = (Volume *) 0; /* volume not attached */ if(!strcmp(volname,"")) {/* its not a volume, fetch next file */ GetNextVol(dirp, volname, &volid); continue; /*back to while loop */ } if(flags) { /*copy other things too */ IOMGR_Poll(); /*make sure that the client doesnot time out*/ ttc = NewTrans(volid,partid); if(!ttc){ pntr->status = VBUSY; pntr->volid = volid; goto drop; } tv = VAttachVolumeByName(&error, pname, volname,V_READONLY); if(error) { pntr->status = 0; /*things are messed up */ strcpy(pntr->name,volname); pntr->volid = volid; Log("1 Volser: ListVolumes: Could not attach volume %u (%s) error=%d\n",volid,volname,error); goto drop; } if(tv->header->diskstuff.needsSalvaged){ /*this volume will be salvaged */ pntr->status = 0; strcpy(pntr->name,volname); pntr->volid = volid; Log("1 Volser: ListVolumes: Volume %u (%s) needs to be salvaged\n",volid, volname); goto drop; } if(tv->header->diskstuff.destroyMe == DESTROY_ME) { /*this volume will be salvaged */ goto drop2; } /*read in the relevant info */ pntr->status = VOK ; /*its ok */ pntr->volid = tv->header->diskstuff.id; strcpy(pntr->name,tv->header->diskstuff.name); pntr->type = tv->header->diskstuff.type; /*if ro volume*/ pntr->cloneID = tv->header->diskstuff.cloneId; /*if rw volume*/ pntr->backupID = tv->header->diskstuff.backupId; pntr->parentID = tv->header->diskstuff.parentId; pntr->copyDate = tv->header->diskstuff.copyDate; pntr->inUse = tv->header->diskstuff.inUse; pntr->size = tv->header->diskstuff.diskused; pntr->needsSalvaged = tv->header->diskstuff.needsSalvaged; pntr->maxquota = tv->header->diskstuff.maxquota; pntr->filecount = tv->header->diskstuff.filecount; now = FT_ApproxTime(); if (now - tv->header->diskstuff.dayUseDate > OneDay) pntr->dayUse = 0; else pntr->dayUse = tv->header->diskstuff.dayUse; pntr->creationDate = tv->header->diskstuff.creationDate; pntr->accessDate = tv->header->diskstuff.accessDate; pntr->updateDate = tv->header->diskstuff.updateDate; pntr->backupDate = tv->header->diskstuff.backupDate; pntr->spare0 = tv->header->diskstuff.minquota; pntr->spare1 = (long) tv->header->diskstuff.weekUse[0] + (long) tv->header->diskstuff.weekUse[1] + (long) tv->header->diskstuff.weekUse[2] + (long) tv->header->diskstuff.weekUse[3] + (long) tv->header->diskstuff.weekUse[4] + (long) tv->header->diskstuff.weekUse[5] + (long) tv->header->diskstuff.weekUse[6]; pntr->flags = pntr->spare2 = pntr->spare3 = (long) 0; VDetachVolume(&error,tv);/*free the volume */ tv = (Volume *) 0; if(error) { pntr->status = 0; /*things are messed up */ strcpy(pntr->name,volname); Log("1 Volser: ListVolumes: Could not detach volume %s\n",volname); goto drop; } }else{ pntr->volid = volid; /*just volids are needed*/ } drop: if(ttc) { DeleteTrans(ttc); ttc = (struct volser_trans *) 0; } pntr++; volumeInfo->volEntries_len += 1; if((allocSize - volumeInfo->volEntries_len) < 5) { /*running out of space, allocate more space */ allocSize = (allocSize *3)/2; pntr = (volintInfo *) realloc((char *) volumeInfo->volEntries_val, allocSize * sizeof(volintInfo)); if(pntr == NULL) { if (tv) { VDetachVolume(&error, tv); tv = (Volume *) 0; } if(ttc) { DeleteTrans(ttc); ttc = (struct volser_trans *) 0; } closedir(dirp); return VOLSERNO_MEMORY; } volumeInfo->volEntries_val = pntr; /* point to new block */ /* set pntr to the right position */ pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len; } drop2: if (tv) { VDetachVolume(&error, tv); tv = (Volume *) 0; } if(ttc) { DeleteTrans(ttc); ttc = (struct volser_trans *) 0; } GetNextVol(dirp, volname, &volid); } closedir(dirp); if (ttc) DeleteTrans(ttc); return 0 ; } /*------------------------------------------------------------------------ * EXPORTED SAFSVolXListVolumes * * Description: * Returns all the volumes on partition a_partID. If a_flags * is set to 1, then all the relevant extended volume information * is also returned. * * Arguments: * a_rxCidP : Pointer to the Rx call we're performing. * a_partID : Partition for which we want the extended list. * a_flags : Various flags. * a_volumeXInfoP : Ptr to the extended info blob. * * Returns: * 0 Successful operation * VOLSERILLEGAL_PARTITION if we got a bogus partition ID * VOLSERNO_MEMORY if we ran out of memory allocating * our return blob * * Environment: * Nothing interesting. * * Side Effects: * As advertised. *------------------------------------------------------------------------*/ afs_int32 SAFSVolXListVolumes (a_rxCidP, a_partID, a_flags, a_volumeXInfoP) struct rx_call *a_rxCidP; afs_int32 a_partID; afs_int32 a_flags; volXEntries *a_volumeXInfoP; { afs_int32 code; code = VolXListVolumes (a_rxCidP, a_partID, a_flags, a_volumeXInfoP); osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END); return code; } afs_int32 VolXListVolumes (a_rxCidP, a_partID, a_flags, a_volumeXInfoP) struct rx_call *a_rxCidP; afs_int32 a_partID; afs_int32 a_flags; volXEntries *a_volumeXInfoP; { /*SAFSVolXListVolumes*/ volintXInfo *xInfoP; /*Ptr to the extended vol info*/ register struct Volume *tv; /*Volume ptr*/ struct DiskPartition *partP; /*Ptr to partition*/ struct volser_trans *ttc; /*Volume transaction ptr*/ afs_int32 allocSize = 1000; /*To be changed to a larger figure */ char pname[9], volname[20]; /*Partition, volume names*/ afs_int32 error = 0; /*Return code*/ DIR *dirp; /*Partition directory ptr*/ afs_int32 volid; /*Current volume ID*/ struct VolumeDiskData *volDiskDataP; /*Ptr to on-disk volume data*/ int numStatBytes; /*Num stat bytes to copy per volume*/ unsigned int now; /* * Allocate a large array of extended volume info structures, then * set it up for action. */ a_volumeXInfoP->volXEntries_val = (volintXInfo *) malloc(allocSize * sizeof(volintXInfo)); xInfoP = a_volumeXInfoP->volXEntries_val; a_volumeXInfoP->volXEntries_len = 0; /* * If the partition name we've been given is bad, bogue out. */ if (GetPartName(a_partID, pname)) return(VOLSERILLEGAL_PARTITION); /* * Open the directory representing the given AFS parttion. If we can't * do that, we lose. */ if (!(partP = VGetPartition(pname, 0))) return VOLSERILLEGAL_PARTITION; dirp = opendir(VPartitionPath(partP)); if (dirp == NULL) return (VOLSERILLEGAL_PARTITION); /* * Sweep through the partition directory, acting on each entry. First, * of course, figure out how many stat bytes to copy out of each volume. */ numStatBytes = 4*((2*VOLINT_STATS_NUM_RWINFO_FIELDS) + (4*VOLINT_STATS_NUM_TIME_FIELDS)); strcpy(volname,""); while (strcmp(volname, "EOD")) { ttc = (struct volser_trans *)0; /*New one for each pass*/ tv = (Volume *)0; /*Volume not yet attached*/ /* * If this is not a volume, move on to the next entry in the * partition's directory. */ if(!strcmp(volname,"")) { GetNextVol(dirp, volname, &volid); continue; } if (a_flags) { /* * Full info about the volume desired. Poll to make sure the * client doesn't time out, then start up a new transaction. */ IOMGR_Poll(); ttc = NewTrans(volid,a_partID); if (!ttc) { /* * Couldn't get a transaction on this volume; let our caller * know it's busy. */ xInfoP->status = VBUSY; xInfoP->volid = volid; goto drop; } /* * Attach the volume, give up on this volume if we can't. */ tv = VAttachVolumeByName(&error, pname, volname, V_READONLY); if (error) { xInfoP->status = 0; /*things are messed up */ strcpy(xInfoP->name, volname); xInfoP->volid = volid; Log("1 Volser: XListVolumes: Could not attach volume %u\n", volid); goto drop; } /* * Also bag out on this volume if it's been marked as needing a * salvage or to-be-destroyed. */ volDiskDataP = &(tv->header->diskstuff); if (volDiskDataP->needsSalvaged) { xInfoP->status = 0; strcpy(xInfoP->name, volname); xInfoP->volid = volid; Log("1 Volser: XListVolumes: Volume %u needs to be salvaged\n", volid); goto drop; } if (volDiskDataP->destroyMe == DESTROY_ME) goto drop2; /* * Pull out the desired info and stuff it into the area we'll be * returning to our caller. */ strcpy(xInfoP->name,volDiskDataP->name); xInfoP->volid = volDiskDataP->id; xInfoP->type = volDiskDataP->type; xInfoP->backupID = volDiskDataP->backupId; xInfoP->parentID = volDiskDataP->parentId; xInfoP->cloneID = volDiskDataP->cloneId; xInfoP->status = VOK; xInfoP->copyDate = volDiskDataP->copyDate; xInfoP->inUse = volDiskDataP->inUse; xInfoP->creationDate = volDiskDataP->creationDate; xInfoP->accessDate = volDiskDataP->accessDate; xInfoP->updateDate = volDiskDataP->updateDate; xInfoP->backupDate = volDiskDataP->backupDate; now = FT_ApproxTime(); if (now - volDiskDataP->dayUseDate > OneDay) xInfoP->dayUse = 0; else xInfoP->dayUse = volDiskDataP->dayUse; xInfoP->filecount = volDiskDataP->filecount; xInfoP->maxquota = volDiskDataP->maxquota; xInfoP->size = volDiskDataP->diskused; /* * Copy out the stat fields in a single operation. */ memcpy((char *)&(xInfoP->stat_reads[0]), (char *)&(volDiskDataP->stat_reads[0]), numStatBytes); /* * We're done copying. Detach the volume and iterate. */ VDetachVolume(&error, tv); tv = (Volume *) 0; if (error) { xInfoP->status = 0; strcpy(xInfoP->name, volname); Log("1 Volser: XListVolumes: Could not detach volume %s\n", volname); goto drop; } } /*Full contents desired*/ else /* * Just volume IDs are needed. */ xInfoP->volid = volid; drop: /* * Drop the transaction we have for this volume. */ if(ttc) { DeleteTrans(ttc); ttc = (struct volser_trans *) 0; } /* * Bump the pointer in the data area we're building, along with * the count of the number of entries it contains. */ xInfoP++; (a_volumeXInfoP->volXEntries_len)++; if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) { /* * We're running out of space in the area we've built. Grow it. */ allocSize = (allocSize * 3)/2; xInfoP = (volintXInfo *) realloc((char *) a_volumeXInfoP->volXEntries_val, (allocSize * sizeof(volintXInfo))); if (xInfoP == NULL) { /* * Bummer, no memory. Bag it, tell our caller what went wrong. */ if (tv) { VDetachVolume(&error, tv); tv = (Volume *) 0; } if (ttc) { DeleteTrans(ttc); ttc = (struct volser_trans *) 0; } closedir(dirp); return(VOLSERNO_MEMORY); } /* * Memory reallocation worked. Correct our pointers so they * now point to the new block and the current open position within * the new block. */ a_volumeXInfoP->volXEntries_val = xInfoP; xInfoP = a_volumeXInfoP->volXEntries_val + a_volumeXInfoP->volXEntries_len; } /*Need more space*/ drop2: /* * Detach our current volume and the transaction on it, then move on * to the next volume in the partition directory. */ if (tv) { VDetachVolume(&error, tv); tv = (Volume *) 0; } if (ttc) { DeleteTrans(ttc); ttc = (struct volser_trans *) 0; } GetNextVol(dirp, volname, &volid); } /*Sweep through the partition directory*/ /* * We've examined all entries in the partition directory. Close it, * delete our transaction (if any), and go home happy. */ closedir(dirp); if (ttc) DeleteTrans(ttc); return(0); } /*SAFSVolXListVolumes*/ /*this call is used to monitor the status of volser for debugging purposes. *information about all the active transactions is returned in transInfo*/ afs_int32 SAFSVolMonitor (acid,transInfo) struct rx_call *acid; transDebugEntries *transInfo; { afs_int32 code; code = VolMonitor (acid,transInfo); osi_auditU(acid, VS_MonitorEvent, code, AUD_END); return code; } afs_int32 VolMonitor (acid,transInfo) struct rx_call *acid; transDebugEntries *transInfo; { transDebugInfo *pntr; afs_int32 allocSize = 50; struct volser_trans *tt, *allTrans; transInfo->transDebugEntries_val = (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo)); pntr = transInfo->transDebugEntries_val; transInfo->transDebugEntries_len = 0; allTrans = TransList(); if(allTrans == (struct volser_trans *)0) return 0;/*no active transactions */ for(tt=allTrans;tt;tt=tt->next){/*copy relevant info into pntr */ pntr->tid = tt->tid; pntr->time = tt->time; pntr->creationTime = tt->creationTime; pntr->returnCode = tt->returnCode; pntr->volid = tt->volid; pntr->partition = tt->partition; pntr->iflags = tt->iflags; pntr->vflags = tt->vflags; pntr->tflags = tt->tflags; strcpy(pntr->lastProcName,tt->lastProcName); pntr->callValid = 0; if(tt->rxCallPtr) { /*record call related info */ pntr->callValid = 1; pntr->readNext = tt->rxCallPtr->rnext; pntr->transmitNext = tt->rxCallPtr->tnext; pntr->lastSendTime = tt->rxCallPtr->lastSendTime; pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime; } pntr++; transInfo->transDebugEntries_len += 1; if((allocSize - transInfo->transDebugEntries_len) < 5) {/*alloc some more space */ allocSize = (allocSize *3)/2; pntr = (transDebugInfo *) realloc((char *) transInfo->transDebugEntries_val,allocSize * sizeof(transDebugInfo)); transInfo->transDebugEntries_val = pntr; pntr = transInfo->transDebugEntries_val + transInfo->transDebugEntries_len; /*set pntr to right position*/ } } return 0; } afs_int32 SAFSVolSetIdsTypes (acid,atid,name, type, pId, cloneId, backupId) struct rx_call *acid; afs_int32 type, pId, cloneId, backupId, atid; char name[]; { afs_int32 code; code = VolSetIdsTypes (acid,atid,name, type, pId, cloneId, backupId); osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name, AUD_STR, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG, backupId, AUD_END); return code; } afs_int32 VolSetIdsTypes (acid,atid,name, type, pId, cloneId, backupId) struct rx_call *acid; afs_int32 type, pId, cloneId, backupId, atid; char name[]; { struct Volume *tv; afs_int32 error = 0; register struct volser_trans *tt; char caller[MAXKTCNAMELEN]; if (strlen(name)>31) return VOLSERBADNAME; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ /* find the trans */ tt = FindTrans(atid); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolSetIds: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } strcpy(tt->lastProcName,"SetIdsTypes"); tt->rxCallPtr = acid; tv = tt->volume; V_type(tv) = type; V_backupId(tv) = backupId; V_cloneId(tv) = cloneId; V_parentId(tv) = pId; strcpy((&V_disk(tv))->name,name); VUpdateVolume(&error, tv); if (error) { Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error); LogError(error); goto fail; } tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt) && !error) return VOLSERTRELE_ERROR; return error; fail: tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt) && !error) return VOLSERTRELE_ERROR; return error; } afs_int32 SAFSVolSetDate (acid,atid,cdate) struct rx_call *acid; afs_int32 atid, cdate; { afs_int32 code; code = VolSetDate (acid,atid,cdate); osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate, AUD_END); return code; } afs_int32 VolSetDate (acid,atid,cdate) struct rx_call *acid; afs_int32 atid, cdate; { struct Volume *tv; afs_int32 error = 0; register struct volser_trans *tt; char caller[MAXKTCNAMELEN]; if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super user*/ /* find the trans */ tt = FindTrans(atid); if (!tt) return ENOENT; if (tt->vflags & VTDeleted) { Log("1 Volser: VolSetDate: volume %u has been deleted \n",tt->volid); TRELE(tt); return ENOENT; } strcpy(tt->lastProcName,"SetDate"); tt->rxCallPtr = acid; tv = tt->volume; V_creationDate(tv) = cdate; VUpdateVolume(&error, tv); if (error) { Log("1 Volser: SetDate: VUpdate failed code %d\n", error); LogError(error); goto fail; } tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt) && !error) return VOLSERTRELE_ERROR; return error; fail: tt->rxCallPtr = (struct rx_call *)0; if(TRELE(tt) && !error) return VOLSERTRELE_ERROR; return error; } /* GetPartName - map partid (a decimal number) into pname (a string) * Since for NT we actually want to return the drive name, we map through the * partition struct. */ static int GetPartName(afs_int32 partid, char *pname) { if (partid < 0) return -1; if(partid < 26) { strcpy(pname,"/vicep"); pname[6] = 'a' + partid; pname[7] = '\0'; return 0; } else if (partid < VOLMAXPARTS) { strcpy(pname,"/vicep"); partid -= 26; pname[6] = 'a' + (partid / 26); pname[7] = 'a' + (partid % 26); pname[8] = '\0'; return 0; } else return -1; }