/* No lock needed. Only the volserver will call this, and only one transaction * can have a given volume (volid/partition pair) in use at a time */ void VPurgeVolume(Error * ec, Volume * vp) { struct DiskPartition64 *tpartp = vp->partition; char purgePath[MAXPATHLEN]; /* so VCheckDetach doesn't try to update the volume header and * dump spurious errors into the logs */ V_inUse(vp) = 0; /* N.B. it's important here to use the partition pointed to by the * volume header. This routine can, under some circumstances, be called * when two volumes with the same id exist on different partitions. */ (void)afs_snprintf(purgePath, sizeof purgePath, "%s/%s", VPartitionPath(vp->partition), VolumeExternalName(V_id(vp))); PurgeIndex_r(vp, vLarge); PurgeIndex_r(vp, vSmall); PurgeHeader_r(vp); unlink(purgePath); /* * Call the fileserver to break all call backs for that volume */ FSYNC_VolOp(V_id(vp), tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL); }
/** * read an existing volume disk header. * * @param[in] volid volume id * @param[in] dp disk partition object * @param[out] hdr volume disk header or NULL * * @note if hdr is NULL, this is essentially an existence test for the vol * header * * @return operation status * @retval 0 success * @retval -1 volume header doesn't exist * @retval EIO failed to read volume header * * @internal */ afs_int32 VReadVolumeDiskHeader(VolumeId volid, struct DiskPartition64 * dp, VolumeDiskHeader_t * hdr) { afs_int32 code = 0; int fd; char path[MAXPATHLEN]; (void)afs_snprintf(path, sizeof(path), "%s/" VFORMAT, VPartitionPath(dp), afs_printable_uint32_lu(volid)); fd = open(path, O_RDONLY); if (fd < 0) { Log("VReadVolumeDiskHeader: Couldn't open header for volume %lu (errno %d).\n", afs_printable_uint32_lu(volid), errno); code = -1; } else if (hdr && read(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) { Log("VReadVolumeDiskHeader: Couldn't read header for volume %lu.\n", afs_printable_uint32_lu(volid)); code = EIO; } if (fd >= 0) { close(fd); } return code; }
static int SalvageLogCleanup(int pid) { int pidlog, len; char fn[AFSDIR_PATH_MAX]; static char buf[LOG_XFER_BUF_SIZE]; afs_snprintf(fn, sizeof(fn), "%s.%d", AFSDIR_SERVER_SLVGLOG_FILEPATH, pid); pidlog = open(fn, O_RDONLY); unlink(fn); if (pidlog < 0) return 1; len = read(pidlog, buf, LOG_XFER_BUF_SIZE); while (len) { fwrite(buf, len, 1, logFile); len = read(pidlog, buf, LOG_XFER_BUF_SIZE); } close(pidlog); return 0; }
static void VInitPartition_r(char *path, char *devname, Device dev) { struct DiskPartition64 *dp, *op; dp = (struct DiskPartition64 *)malloc(sizeof(struct DiskPartition64)); /* Add it to the end, to preserve order when we print statistics */ for (op = DiskPartitionList; op; op = op->next) { if (!op->next) break; } if (op) op->next = dp; else DiskPartitionList = dp; dp->next = 0; dp->name = (char *)malloc(strlen(path) + 1); strncpy(dp->name, path, strlen(path) + 1); dp->index = volutil_GetPartitionID(path); #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV) /* Create a lockfile for the partition, of the form /vicepa/Lock/vicepa */ dp->devName = (char *)malloc(2 * strlen(path) + 6); strcpy(dp->devName, path); strcat(dp->devName, "/"); strcat(dp->devName, "Lock"); mkdir(dp->devName, 0700); strcat(dp->devName, path); close(afs_open(dp->devName, O_RDWR | O_CREAT, 0600)); dp->device = dp->index; #else dp->devName = (char *)malloc(strlen(devname) + 1); strncpy(dp->devName, devname, strlen(devname) + 1); dp->device = dev; #endif dp->lock_fd = INVALID_FD; dp->flags = 0; dp->f_files = 1; /* just a default value */ #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV) if (programType == fileServer) (void)namei_ViceREADME(VPartitionPath(dp)); #endif VSetPartitionDiskUsage_r(dp); #ifdef AFS_DEMAND_ATTACH_FS AddPartitionToTable_r(dp); queue_Init(&dp->vol_list.head); assert(pthread_cond_init(&dp->vol_list.cv, NULL) == 0); dp->vol_list.len = 0; dp->vol_list.busy = 0; { char lockpath[MAXPATHLEN+1]; afs_snprintf(lockpath, MAXPATHLEN, "%s/" AFS_PARTLOCK_FILE, dp->name); lockpath[MAXPATHLEN] = '\0'; VLockFileInit(&dp->headerLockFile, lockpath); } VDiskLockInit(&dp->headerLock, &dp->headerLockFile, 1); #endif /* AFS_DEMAND_ATTACH_FS */ }
/** * destroy a volume disk header. * * @param[in] dp disk partition object * @param[in] volid volume id * @param[in] parent parent's volume id, 0 if unknown * * @return operation status * @retval 0 success * * @note if parent is 0, the parent volume ID will be looked up from the * fileserver * * @note for non-DAFS, parent is currently ignored */ afs_int32 VDestroyVolumeDiskHeader(struct DiskPartition64 * dp, VolumeId volid, VolumeId parent) { afs_int32 code = 0; char path[MAXPATHLEN]; #ifdef AFS_DEMAND_ATTACH_FS SYNC_response res; #endif /* AFS_DEMAND_ATTACH_FS */ (void)afs_snprintf(path, sizeof(path), "%s/" VFORMAT, VPartitionPath(dp), afs_printable_uint32_lu(volid)); code = unlink(path); if (code) { Log("VDestroyVolumeDiskHeader: Couldn't unlink disk header, error = %d\n", errno); goto done; } #ifdef AFS_DEMAND_ATTACH_FS memset(&res, 0, sizeof(res)); if (!parent) { FSSYNC_VGQry_response_t q_res; code = FSYNC_VGCQuery(dp->name, volid, &q_res, &res); if (code) { Log("VDestroyVolumeDiskHeader: FSYNC_VGCQuery(%s, %lu) failed " "with code %ld, reason %ld\n", dp->name, afs_printable_uint32_lu(volid), afs_printable_int32_ld(code), afs_printable_int32_ld(res.hdr.reason)); goto done; } parent = q_res.rw; } code = FSYNC_VGCDel(dp->name, parent, volid, FSYNC_WHATEVER, &res); if (code) { Log("VDestroyVolumeDiskHeader: FSYNC_VGCDel(%s, %lu, %lu) failed " "with code %ld reason %ld\n", dp->name, afs_printable_uint32_lu(parent), afs_printable_uint32_lu(volid), afs_printable_int32_ld(code), afs_printable_int32_ld(res.hdr.reason)); } #endif /* AFS_DEMAND_ATTACH_FS */ done: return code; }
char * date(time_t date) { #define MAX_DATE_RESULT 100 static char results[8][MAX_DATE_RESULT]; static int next; struct tm *tm = localtime(&date); char buf[32]; (void)strftime(buf, 32, "%Y/%m/%d.%H:%M:%S", tm); /* NT does not have %T */ (void)afs_snprintf(results[next = (next + 1) & 7], MAX_DATE_RESULT, "%lu (%s)", (unsigned long)date, buf); return results[next]; }
static int fs_stateCreateDump(struct fs_dump_state * state) { int fd, ret = 0; char savedump[MAXPATHLEN]; struct afs_stat status; afs_snprintf(savedump, sizeof(savedump), "%s.old", state->fn); if (afs_stat(state->fn, &status) == 0) { renamefile(state->fn, savedump); } if (((fd = afs_open(state->fn, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1) || (afs_fstat(fd, &status) == -1)) { ViceLog(0, ("fs_stateCreateDump: failed to create state dump file '%s'\n", state->fn)); ret = 1; goto done; } state->fd = fd; state->mode = FS_STATE_DUMP_MODE; memset(state->hdr, 0, sizeof(struct fs_state_header)); fs_stateIncEOF(state, sizeof(struct fs_state_header)); #ifdef FS_STATE_USE_MMAP if (fs_stateSizeFile(state)) { ViceLog(0, ("fs_stateCreateDump: failed to resize state dump file '%s'\n", state->fn)); ret = 1; goto done; } if (fs_stateMapFile(state)) { ViceLog(0, ("fs_stateCreateDump: failed to memory map state dump file '%s'\n", state->fn)); ret = 1; goto done; } #endif ret = fs_stateInvalidateDump(state); done: return ret; }
/** * write an existing volume disk header. * * @param[in] hdr volume disk header * @param[in] dp disk partition object * @param[in] cr assert if O_CREAT | O_EXCL should be passed to open() * * @return operation status * @retval 0 success * @retval -1 volume header doesn't exist * @retval EIO failed to write volume header * * @internal */ static afs_int32 _VWriteVolumeDiskHeader(VolumeDiskHeader_t * hdr, struct DiskPartition64 * dp, int flags) { afs_int32 code = 0; int fd; char path[MAXPATHLEN]; #ifdef AFS_DEMAND_ATTACH_FS /* prevent racing with VGC scanners reading the vol header while we are * writing it */ code = VPartHeaderLock(dp, READ_LOCK); if (code) { return EIO; } #endif /* AFS_DEMAND_ATTACH_FS */ flags |= O_RDWR; (void)afs_snprintf(path, sizeof(path), "%s/" VFORMAT, VPartitionPath(dp), afs_printable_uint32_lu(hdr->id)); fd = open(path, flags, 0644); if (fd < 0) { code = errno; Log("_VWriteVolumeDiskHeader: Couldn't open header for volume %lu, " "error = %d\n", afs_printable_uint32_lu(hdr->id), errno); } else if (write(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) { Log("_VWriteVolumeDiskHeader: Couldn't write header for volume %lu, " "error = %d\n", afs_printable_uint32_lu(hdr->id), errno); code = EIO; } if (fd >= 0) { if (close(fd) != 0) { Log("_VWriteVolumeDiskHeader: Error closing header for volume " "%lu, errno %d\n", afs_printable_uint32_lu(hdr->id), errno); } } #ifdef AFS_DEMAND_ATTACH_FS VPartHeaderUnlock(dp, READ_LOCK); #endif /* AFS_DEMAND_ATTACH_FS */ return code; }
void vFSLog(const char *format, va_list args) { time_t currenttime; char *timeStamp; char tbuffer[1024]; char *info; size_t len; int num; currenttime = time(0); timeStamp = afs_ctime(¤ttime, tbuffer, sizeof(tbuffer)); timeStamp[24] = ' '; /* ts[24] is the newline, 25 is the null */ info = &timeStamp[25]; if (mrafsStyleLogs || threadIdLogs) { num = (*threadNumProgram) (); if (num > -1) { (void)afs_snprintf(info, (sizeof tbuffer) - strlen(tbuffer), "[%d] ", num); info += strlen(info); } } (void)afs_vsnprintf(info, (sizeof tbuffer) - strlen(tbuffer), format, args); len = strlen(tbuffer); LOCK_SERVERLOG(); #ifndef AFS_NT40_ENV if (serverLogSyslog) { syslog(LOG_INFO, "%s", info); } else #endif if (serverLogFD > 0) (void)write(serverLogFD, tbuffer, len); UNLOCK_SERVERLOG(); #if !defined(AFS_PTHREAD_ENV) && !defined(AFS_NT40_ENV) if (!serverLogSyslog) { fflush(stdout); fflush(stderr); /* in case they're sharing the same FD */ } #endif } /*vFSLog */
void HandleVolume(struct DiskPartition64 *dp, char *name, char *filename, int fromtime) { struct VolumeHeader header; struct VolumeDiskHeader diskHeader; struct afs_stat status, stat; register int fd; Volume *vp; IHandle_t *ih; char headerName[1024]; afs_int32 n; (void)afs_snprintf(headerName, sizeof headerName, "%s/%s", VPartitionPath(dp), name); if ((fd = afs_open(headerName, O_RDONLY)) == -1 || afs_fstat(fd, &status) == -1) { fprintf(stderr, "Cannot read volume header %s\n", name); close(fd); exit(1); } n = read(fd, &diskHeader, sizeof(diskHeader)); if (n != sizeof(diskHeader) || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) { fprintf(stderr, "Error reading volume header %s\n", name); exit(1); } if (diskHeader.stamp.version != VOLUMEHEADERVERSION) { fprintf(stderr, "Volume %s, version number is incorrect; volume needs salvage\n", name); exit(1); } DiskToVolumeHeader(&header, &diskHeader); close(fd); vp = AttachVolume(dp, name, &header); if (!vp) { fprintf(stderr, "Error attaching volume header %s\n", name); exit(1); } DoMyVolDump(vp, dp, filename, fromtime); }
static int DoSalvageVolume(struct SalvageQueueNode * node, int slot) { char childLog[AFSDIR_PATH_MAX]; struct DiskPartition64 * partP; /* do not allow further forking inside salvager */ canfork = 0; /* do not attempt to close parent's logFile handle as * another thread may have held the lock on the FILE * structure when fork was called! */ afs_snprintf(childLog, sizeof(childLog), "%s.%d", AFSDIR_SERVER_SLVGLOG_FILEPATH, getpid()); logFile = afs_fopen(childLog, "a"); if (!logFile) { /* still nothing, use stdout */ logFile = stdout; ShowLog = 0; } if (node->command.sop.parent <= 0) { Log("salvageServer: invalid volume id specified; salvage aborted\n"); return 1; } partP = VGetPartition(node->command.sop.partName, 0); if (!partP) { Log("salvageServer: Unknown or unmounted partition %s; salvage aborted\n", node->command.sop.partName); return 1; } /* obtain a shared salvage lock in the child worker, so if the * salvageserver restarts (and we continue), we will still hold a lock and * prevent standalone salvagers from interfering */ ObtainSharedSalvageLock(); /* Salvage individual volume; don't notify fs */ SalvageFileSys1(partP, node->command.sop.parent); fclose(logFile); return 0; }
int OpenLog(const char *fileName) { /* * This function should allow various libraries that inconsistently * use stdout/stderr to all go to the same place */ int tempfd, isfifo = 0; char oldName[MAXPATHLEN]; struct timeval Start; struct tm *TimeFields; char FileName[MAXPATHLEN]; #ifndef AFS_NT40_ENV struct stat statbuf; if (serverLogSyslog) { openlog(serverLogSyslogTag, LOG_PID, serverLogSyslogFacility); return (0); } /* Support named pipes as logs by not rotating them */ if ((lstat(fileName, &statbuf) == 0) && (S_ISFIFO(statbuf.st_mode))) { isfifo = 1; } #endif if (mrafsStyleLogs) { time_t t; TM_GetTimeOfDay(&Start, 0); t = Start.tv_sec; TimeFields = localtime(&t); if (fileName) { if (strncmp(fileName, (char *)&ourName, strlen(fileName))) strcpy((char *)&ourName, (char *)fileName); } afs_snprintf(FileName, MAXPATHLEN, "%s.%d%02d%02d%02d%02d%02d", ourName, TimeFields->tm_year + 1900, TimeFields->tm_mon + 1, TimeFields->tm_mday, TimeFields->tm_hour, TimeFields->tm_min, TimeFields->tm_sec); if (!isfifo) renamefile(fileName, FileName); /* don't check error code */ tempfd = open(fileName, O_WRONLY | O_TRUNC | O_CREAT | (isfifo?O_NONBLOCK:0), 0666); } else { strcpy(oldName, fileName); strcat(oldName, ".old"); /* don't check error */ if (!isfifo) renamefile(fileName, oldName); tempfd = open(fileName, O_WRONLY | O_TRUNC | O_CREAT | (isfifo?O_NONBLOCK:0), 0666); } if (tempfd < 0) { printf("Unable to open log file %s\n", fileName); return -1; } /* redirect stdout and stderr so random printf's don't write to data */ (void)freopen(fileName, "a", stdout); (void)freopen(fileName, "a", stderr); #ifdef HAVE_SETVBUF #ifdef SETVBUF_REVERSED setvbuf(stderr, _IONBF, NULL, 0); #else setvbuf(stderr, NULL, _IONBF, 0); #endif #else setbuf(stderr, NULL); #endif #if defined(AFS_PTHREAD_ENV) assert(pthread_mutex_init(&serverLogMutex, NULL) == 0); #endif /* AFS_PTHREAD_ENV */ serverLogFD = tempfd; return 0; } /*OpenLog */
Volume * VCreateVolume_r(Error * ec, char *partname, VolId volumeId, VolId parentId) { /* Should be the same as volumeId if there is * no parent */ VolumeDiskData vol; int i, rc; char headerName[VMAXPATHLEN], volumePath[VMAXPATHLEN]; Device device; struct DiskPartition64 *partition; struct VolumeDiskHeader diskHeader; IHandle_t *handle; FdHandle_t *fdP; Inode nearInode = 0; char *part, *name; struct stat st; # ifdef AFS_DEMAND_ATTACH_FS int locktype = 0; # endif /* AFS_DEMAND_ATTACH_FS */ *ec = 0; memset(&vol, 0, sizeof(vol)); vol.id = volumeId; vol.parentId = parentId; vol.copyDate = time(0); /* The only date which really means when this * @i(instance) of this volume was created. * Creation date does not mean this */ /* Initialize handle for error case below. */ handle = NULL; /* Verify that the parition is valid before writing to it. */ if (!(partition = VGetPartition_r(partname, 0))) { Log("VCreateVolume: partition %s is not in service.\n", partname); *ec = VNOVOL; return NULL; } #if defined(NEARINODE_HINT) nearInodeHash(volumeId, nearInode); nearInode %= partition->f_files; #endif VGetVolumePath(ec, vol.id, &part, &name); if (*ec == VNOVOL || !strcmp(partition->name, part)) { /* this case is ok */ } else { /* return EXDEV if it's a clone to an alternate partition * otherwise assume it's a move */ if (vol.parentId != vol.id) { *ec = EXDEV; return NULL; } } *ec = 0; # ifdef AFS_DEMAND_ATTACH_FS /* volume doesn't exist yet, but we must lock it to try to prevent something * else from reading it when we're e.g. half way through creating it (or * something tries to create the same volume at the same time) */ locktype = VVolLockType(V_VOLUPD, 1); rc = VLockVolumeByIdNB(volumeId, partition, locktype); if (rc) { Log("VCreateVolume: vol %lu already locked by someone else\n", afs_printable_uint32_lu(volumeId)); *ec = VNOVOL; return NULL; } # else /* AFS_DEMAND_ATTACH_FS */ VLockPartition_r(partname); # endif /* !AFS_DEMAND_ATTACH_FS */ memset(&tempHeader, 0, sizeof(tempHeader)); tempHeader.stamp.magic = VOLUMEHEADERMAGIC; tempHeader.stamp.version = VOLUMEHEADERVERSION; tempHeader.id = vol.id; tempHeader.parent = vol.parentId; vol.stamp.magic = VOLUMEINFOMAGIC; vol.stamp.version = VOLUMEINFOVERSION; vol.destroyMe = DESTROY_ME; (void)afs_snprintf(headerName, sizeof headerName, VFORMAT, afs_printable_uint32_lu(vol.id)); (void)afs_snprintf(volumePath, sizeof volumePath, "%s/%s", VPartitionPath(partition), headerName); rc = stat(volumePath, &st); if (rc == 0 || errno != ENOENT) { if (rc == 0) { Log("VCreateVolume: Header file %s already exists!\n", volumePath); *ec = VVOLEXISTS; } else { Log("VCreateVolume: Error %d trying to stat header file %s\n", errno, volumePath); *ec = VNOVOL; } goto bad_noheader; } device = partition->device; for (i = 0; i < nFILES; i++) { register struct stuff *p = &stuff[i]; if (p->obsolete) continue; #ifdef AFS_NAMEI_ENV *(p->inode) = IH_CREATE(NULL, device, VPartitionPath(partition), nearInode, (p->inodeType == VI_LINKTABLE) ? vol.parentId : vol.id, INODESPECIAL, p->inodeType, vol.parentId); if (!(VALID_INO(*(p->inode)))) { if (errno == EEXIST) { /* Increment the reference count instead. */ IHandle_t *lh; int code; #ifdef AFS_NT40_ENV *(p->inode) = nt_MakeSpecIno(VI_LINKTABLE); #else *(p->inode) = namei_MakeSpecIno(vol.parentId, VI_LINKTABLE); #endif IH_INIT(lh, device, parentId, *(p->inode)); fdP = IH_OPEN(lh); if (fdP == NULL) { IH_RELEASE(lh); goto bad; } code = IH_INC(lh, *(p->inode), parentId); FDH_REALLYCLOSE(fdP); IH_RELEASE(lh); if (code < 0) goto bad; continue; } } #else *(p->inode) = IH_CREATE(NULL, device, VPartitionPath(partition), nearInode, vol.id, INODESPECIAL, p->inodeType, vol.parentId); #endif if (!VALID_INO(*(p->inode))) { Log("VCreateVolume: Problem creating %s file associated with volume header %s\n", p->description, volumePath); bad: if (handle) IH_RELEASE(handle); RemoveInodes(device, vol.id); if (!*ec) { *ec = VNOVOL; } VDestroyVolumeDiskHeader(partition, volumeId, parentId); bad_noheader: # ifdef AFS_DEMAND_ATTACH_FS if (locktype) { VUnlockVolumeById(volumeId, partition); } # endif /* AFS_DEMAND_ATTACH_FS */ return NULL; } IH_INIT(handle, device, vol.parentId, *(p->inode)); fdP = IH_OPEN(handle); if (fdP == NULL) { Log("VCreateVolume: Problem iopen inode %s (err=%d)\n", PrintInode(NULL, *(p->inode)), errno); goto bad; } if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) { Log("VCreateVolume: Problem lseek inode %s (err=%d)\n", PrintInode(NULL, *(p->inode)), errno); FDH_REALLYCLOSE(fdP); goto bad; } if (FDH_WRITE(fdP, (char *)&p->stamp, sizeof(p->stamp)) != sizeof(p->stamp)) { Log("VCreateVolume: Problem writing to inode %s (err=%d)\n", PrintInode(NULL, *(p->inode)), errno); FDH_REALLYCLOSE(fdP); goto bad; } FDH_REALLYCLOSE(fdP); IH_RELEASE(handle); nearInode = *(p->inode); } IH_INIT(handle, device, vol.parentId, tempHeader.volumeInfo); fdP = IH_OPEN(handle); if (fdP == NULL) { Log("VCreateVolume: Problem iopen inode %s (err=%d)\n", PrintInode(NULL, tempHeader.volumeInfo), errno); goto bad; } if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) { Log("VCreateVolume: Problem lseek inode %s (err=%d)\n", PrintInode(NULL, tempHeader.volumeInfo), errno); FDH_REALLYCLOSE(fdP); goto bad; } if (FDH_WRITE(fdP, (char *)&vol, sizeof(vol)) != sizeof(vol)) { Log("VCreateVolume: Problem writing to inode %s (err=%d)\n", PrintInode(NULL, tempHeader.volumeInfo), errno); FDH_REALLYCLOSE(fdP); goto bad; } FDH_CLOSE(fdP); IH_RELEASE(handle); VolumeHeaderToDisk(&diskHeader, &tempHeader); rc = VCreateVolumeDiskHeader(&diskHeader, partition); if (rc) { Log("VCreateVolume: Error %d trying to write volume header for " "volume %u on partition %s; volume not created\n", rc, vol.id, VPartitionPath(partition)); if (rc == EEXIST) { *ec = VVOLEXISTS; } goto bad; } # ifdef AFS_DEMAND_ATTACH_FS if (locktype) { VUnlockVolumeById(volumeId, partition); } # endif /* AFS_DEMAND_ATTACH_FS */ return (VAttachVolumeByName_r(ec, partname, headerName, V_SECRETLY)); }
static int handleit(struct cmd_syndesc *as, void *arock) { register struct cmd_item *ti; int err = 0; int volumeId = 0; char *partName = 0; char *fileName = NULL; struct DiskPartition64 *partP = NULL; char name1[128]; char tmpPartName[20]; int fromtime = 0; afs_int32 code; #ifndef AFS_NT40_ENV #if 0 if (geteuid() != 0) { fprintf(stderr, "voldump must be run as root; sorry\n"); exit(1); } #endif #endif if ((ti = as->parms[0].items)) partName = ti->data; if ((ti = as->parms[1].items)) volumeId = atoi(ti->data); if ((ti = as->parms[2].items)) fileName = ti->data; if ((ti = as->parms[3].items)) verbose = 1; if (as->parms[4].items && strcmp(as->parms[4].items->data, "0")) { code = ktime_DateToInt32(as->parms[4].items->data, &fromtime); if (code) { fprintf(STDERR, "failed to parse date '%s' (error=%d))\n", as->parms[4].items->data, code); return code; } } DInit(10); err = VAttachPartitions(); if (err) { fprintf(stderr, "%d partitions had errors during attach.\n", err); } if (partName) { if (strlen(partName) == 1) { if (partName[0] >= 'a' && partName[0] <= 'z') { strcpy(tmpPartName, "/vicepa"); tmpPartName[6] = partName[0]; partP = VGetPartition(tmpPartName, 0); } } else { partP = VGetPartition(partName, 0); } if (!partP) { fprintf(stderr, "%s is not an AFS partition name on this server.\n", partName); exit(1); } } if (!volumeId) { fprintf(stderr, "Must specify volume id!\n"); exit(1); } if (!partP) { fprintf(stderr, "must specify vice partition.\n"); exit(1); } (void)afs_snprintf(name1, sizeof name1, VFORMAT, (unsigned long)volumeId); HandleVolume(partP, name1, fileName, fromtime); return 0; }
afs_int32 SDISK_SendFile(struct rx_call *rxcall, afs_int32 file, afs_int32 index, afs_int32 length, struct ubik_version *avers) { afs_int32 code; struct ubik_dbase *dbase = NULL; char tbuffer[1024]; afs_int32 offset; struct ubik_version tversion; int tlen; struct rx_peer *tpeer; struct rx_connection *tconn; afs_uint32 otherHost = 0; char hoststr[16]; #ifndef OLD_URECOVERY char pbuffer[1028]; int fd = -1; afs_int32 epoch = 0; afs_int32 pass; #endif /* send the file back to the requester */ pbuffer[0] = '\0'; dbase = ubik_dbase[index]; if (!dbase) { code = ENOENT; goto failed; } if ((code = ubik_CheckAuth(rxcall))) { DBHOLD(dbase); goto failed; } /* next, we do a sanity check to see if the guy sending us the database is * the guy we think is the sync site. It turns out that we might not have * decided yet that someone's the sync site, but they could have enough * votes from others to be sync site anyway, and could send us the database * in advance of getting our votes. This is fine, what we're really trying * to check is that some authenticated bogon isn't sending a random database * into another configuration. This could happen on a bad configuration * screwup. Thus, we only object if we're sure we know who the sync site * is, and it ain't the guy talking to us. */ offset = uvote_GetSyncSite(); tconn = rx_ConnectionOf(rxcall); tpeer = rx_PeerOf(tconn); otherHost = ubikGetPrimaryInterfaceAddr(rx_HostOf(tpeer)); if (offset && offset != otherHost) { /* we *know* this is the wrong guy */ code = USYNC; goto failed; } DBHOLD(dbase); /* abort any active trans that may scribble over the database */ urecovery_AbortAll(dbase); ubik_print("Ubik: Synchronize %s with server %s\n", dbase->pathName, afs_inet_ntoa_r(otherHost, hoststr)); offset = 0; #ifdef OLD_URECOVERY (*dbase->truncate) (dbase, file, 0); /* truncate first */ tversion.counter = 0; #else epoch = #endif tversion.epoch = 0; /* start off by labelling in-transit db as invalid */ (*dbase->setlabel) (dbase, file, &tversion); /* setlabel does sync */ #ifndef OLD_URECOVERY afs_snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP", dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); fd = open(pbuffer, O_CREAT | O_RDWR | O_TRUNC, 0600); if (fd < 0) { code = errno; goto failed; } code = lseek(fd, HDRSIZE, 0); if (code != HDRSIZE) { close(fd); goto failed; } pass = 0; #endif memcpy(&ubik_dbase[index]->version, &tversion, sizeof(struct ubik_version)); while (length > 0) { tlen = (length > sizeof(tbuffer) ? sizeof(tbuffer) : length); #if !defined(OLD_URECOVERY) && !defined(AFS_PTHREAD_ENV) if (pass % 4 == 0) IOMGR_Poll(); #endif code = rx_Read(rxcall, tbuffer, tlen); if (code != tlen) { ubik_dprint("Rx-read length error=%d\n", code); code = BULK_ERROR; close(fd); goto failed; } #ifdef OLD_URECOVERY code = (*dbase->write) (dbase, file, tbuffer, offset, tlen); #else code = write(fd, tbuffer, tlen); pass++; #endif if (code != tlen) { ubik_dprint("write failed error=%d\n", code); code = UIOERROR; close(fd); goto failed; } offset += tlen; length -= tlen; } #ifndef OLD_URECOVERY code = close(fd); if (code) goto failed; #endif /* sync data first, then write label and resync (resync done by setlabel call). * This way, good label is only on good database. */ #ifdef OLD_URECOVERY (*dbase->sync) (dbase, file); #else afs_snprintf(tbuffer, sizeof(tbuffer), "%s.DB%s%d", dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); #ifdef AFS_NT40_ENV afs_snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD", dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); code = unlink(pbuffer); if (!code) code = rename(tbuffer, pbuffer); afs_snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP", dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); #endif if (!code) code = rename(pbuffer, tbuffer); if (!code) { (*dbase->open) (dbase, file); #endif code = (*dbase->setlabel) (dbase, file, avers); #ifndef OLD_URECOVERY } #ifdef AFS_NT40_ENV afs_snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD", dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); unlink(pbuffer); #endif #endif memcpy(&dbase->version, avers, sizeof(struct ubik_version)); udisk_Invalidate(dbase, file); /* new dbase, flush disk buffers */ #ifdef AFS_PTHREAD_ENV assert(pthread_cond_broadcast(&dbase->version_cond) == 0); #else LWP_NoYieldSignal(&dbase->version); #endif failed: if (code) { #ifndef OLD_URECOVERY if (pbuffer[0] != '\0') unlink(pbuffer); /* Failed to sync. Allow reads again for now. */ if (dbase != NULL) { tversion.epoch = epoch; (*dbase->setlabel) (dbase, file, &tversion); } #endif ubik_print ("Ubik: Synchronize database %s with server %s failed (error = %d)\n", ubik_dbase[index]->pathName, afs_inet_ntoa_r(otherHost, hoststr), code); } else { ubik_print("Ubik: Synchronize database %s completed\n", dbase->pathName); } DBRELE(dbase); return code; }
/** * Thread to look for SalvageLog.$pid files that are not from our child * worker salvagers, and notify SalvageLogCleanupThread to clean them * up. This can happen if we restart during salvages, or the * salvageserver crashes or something. * * @param arg unused * * @return always NULL */ static void * SalvageLogScanningThread(void * arg) { struct rx_queue log_watch_queue; queue_Init(&log_watch_queue); { DIR *dp; struct dirent *dirp; char prefix[AFSDIR_PATH_MAX]; size_t prefix_len; afs_snprintf(prefix, sizeof(prefix), "%s.", AFSDIR_SLVGLOG_FILE); prefix_len = strlen(prefix); dp = opendir(AFSDIR_LOGS_DIR); assert(dp); while ((dirp = readdir(dp)) != NULL) { pid_t pid; struct log_cleanup_node *cleanup; int i; if (strncmp(dirp->d_name, prefix, prefix_len) != 0) { /* not a salvage logfile; skip */ continue; } errno = 0; pid = strtol(dirp->d_name + prefix_len, NULL, 10); if (errno != 0) { /* file is SalvageLog.<something> but <something> isn't * a pid, so skip */ continue; } VOL_LOCK; for (i = 0; i < Parallel; ++i) { if (pid == child_slot[i]) { break; } } VOL_UNLOCK; if (i < Parallel) { /* this pid is one of our children, so the reaper thread * will take care of it; skip */ continue; } cleanup = (struct log_cleanup_node *) malloc(sizeof(struct log_cleanup_node)); cleanup->pid = pid; queue_Append(&log_watch_queue, cleanup); } closedir(dp); } ScanLogs(&log_watch_queue); while (queue_IsNotEmpty(&log_watch_queue)) { sleep(SALVAGE_SCAN_POLL_INTERVAL); ScanLogs(&log_watch_queue); } return NULL; }
/*! * \brief Main interaction loop for the recovery manager * * The recovery light-weight process only runs when you're the * synchronization site. It performs the following tasks, if and only * if the prerequisite tasks have been performed successfully (it * keeps track of which ones have been performed in its bit map, * \p urecovery_state). * * First, it is responsible for probing that all servers are up. This * is the only operation that must be performed even if this is not * yet the sync site, since otherwise this site may not notice that * enough other machines are running to even elect this guy to be the * sync site. * * After that, the recovery process does nothing until the beacon and * voting modules manage to get this site elected sync site. * * After becoming sync site, recovery first attempts to find the best * database available in the network (it must do this in order to * ensure finding the latest committed data). After finding the right * database, it must fetch this dbase to the sync site. * * After fetching the dbase, it relabels it with a new version number, * to ensure that everyone recognizes this dbase as the most recent * dbase. * * One the dbase has been relabelled, this machine can start handling * requests. However, the recovery module still has one more task: * propagating the dbase out to everyone who is up in the network. */ void * urecovery_Interact(void *dummy) { afs_int32 code, tcode; struct ubik_server *bestServer = NULL; struct ubik_server *ts; int dbok, doingRPC, now; afs_int32 lastProbeTime, lastDBVCheck; /* if we're the sync site, the best db version we've found yet */ static struct ubik_version bestDBVersion; struct ubik_version tversion; struct timeval tv; int length, tlen, offset, file, nbytes; struct rx_call *rxcall; char tbuffer[1024]; struct ubik_stat ubikstat; struct in_addr inAddr; char hoststr[16]; #ifndef OLD_URECOVERY char pbuffer[1028]; int flen, fd = -1; afs_int32 pass; #endif /* otherwise, begin interaction */ urecovery_state = 0; lastProbeTime = 0; lastDBVCheck = 0; while (1) { /* Run through this loop every 4 seconds */ tv.tv_sec = 4; tv.tv_usec = 0; #ifdef AFS_PTHREAD_ENV select(0, 0, 0, 0, &tv); #else IOMGR_Select(0, 0, 0, 0, &tv); #endif ubik_dprint("recovery running in state %x\n", urecovery_state); /* Every 30 seconds, check all the down servers and mark them * as up if they respond. When a server comes up or found to * not be current, then re-find the the best database and * propogate it. */ if ((now = FT_ApproxTime()) > 30 + lastProbeTime) { for (ts = ubik_servers, doingRPC = 0; ts; ts = ts->next) { if (!ts->up) { doingRPC = 1; code = DoProbe(ts); if (code == 0) { ts->up = 1; urecovery_state &= ~UBIK_RECFOUNDDB; } } else if (!ts->currentDB) { urecovery_state &= ~UBIK_RECFOUNDDB; } } if (doingRPC) now = FT_ApproxTime(); lastProbeTime = now; } /* Mark whether we are the sync site */ if (!ubeacon_AmSyncSite()) { urecovery_state &= ~UBIK_RECSYNCSITE; continue; /* nothing to do */ } urecovery_state |= UBIK_RECSYNCSITE; /* If a server has just come up or if we have not found the * most current database, then go find the most current db. */ if (!(urecovery_state & UBIK_RECFOUNDDB)) { bestServer = (struct ubik_server *)0; bestDBVersion.epoch = 0; bestDBVersion.counter = 0; for (ts = ubik_servers; ts; ts = ts->next) { if (!ts->up) continue; /* don't bother with these guys */ if (ts->isClone) continue; code = DISK_GetVersion(ts->disk_rxcid, &ts->version); if (code == 0) { /* perhaps this is the best version */ if (vcmp(ts->version, bestDBVersion) > 0) { /* new best version */ bestDBVersion = ts->version; bestServer = ts; } } } /* take into consideration our version. Remember if we, * the sync site, have the best version. Also note that * we may need to send the best version out. */ if (vcmp(ubik_dbase->version, bestDBVersion) >= 0) { bestDBVersion = ubik_dbase->version; bestServer = (struct ubik_server *)0; urecovery_state |= UBIK_RECHAVEDB; } else { /* Clear the flag only when we know we have to retrieve * the db. Because urecovery_AllBetter() looks at it. */ urecovery_state &= ~UBIK_RECHAVEDB; } lastDBVCheck = FT_ApproxTime(); urecovery_state |= UBIK_RECFOUNDDB; urecovery_state &= ~UBIK_RECSENTDB; } #if defined(UBIK_PAUSE) /* it's not possible for UBIK_RECFOUNDDB not to be set here. * However, we might have lost UBIK_RECSYNCSITE, and that * IS important. */ if (!(urecovery_state & UBIK_RECSYNCSITE)) continue; /* lost sync */ #else if (!(urecovery_state & UBIK_RECFOUNDDB)) continue; /* not ready */ #endif /* UBIK_PAUSE */ /* If we, the sync site, do not have the best db version, then * go and get it from the server that does. */ if ((urecovery_state & UBIK_RECHAVEDB) || !bestServer) { urecovery_state |= UBIK_RECHAVEDB; } else { /* we don't have the best version; we should fetch it. */ DBHOLD(ubik_dbase); urecovery_AbortAll(ubik_dbase); /* Rx code to do the Bulk fetch */ file = 0; offset = 0; rxcall = rx_NewCall(bestServer->disk_rxcid); ubik_print("Ubik: Synchronize database with server %s\n", afs_inet_ntoa_r(bestServer->addr[0], hoststr)); code = StartDISK_GetFile(rxcall, file); if (code) { ubik_dprint("StartDiskGetFile failed=%d\n", code); goto FetchEndCall; } nbytes = rx_Read(rxcall, (char *)&length, sizeof(afs_int32)); length = ntohl(length); if (nbytes != sizeof(afs_int32)) { ubik_dprint("Rx-read length error=%d\n", code = BULK_ERROR); code = EIO; goto FetchEndCall; } #ifdef OLD_URECOVERY /* Truncate the file first */ code = (*ubik_dbase->truncate) (ubik_dbase, file, 0); if (code) { ubik_dprint("truncate io error=%d\n", code); goto FetchEndCall; } tversion.counter = 0; #endif /* give invalid label during file transit */ tversion.epoch = 0; code = (*ubik_dbase->setlabel) (ubik_dbase, file, &tversion); if (code) { ubik_dprint("setlabel io error=%d\n", code); goto FetchEndCall; } #ifndef OLD_URECOVERY flen = length; afs_snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); fd = open(pbuffer, O_CREAT | O_RDWR | O_TRUNC, 0600); if (fd < 0) { code = errno; goto FetchEndCall; } code = lseek(fd, HDRSIZE, 0); if (code != HDRSIZE) { close(fd); goto FetchEndCall; } #endif pass = 0; while (length > 0) { tlen = (length > sizeof(tbuffer) ? sizeof(tbuffer) : length); #ifndef AFS_PTHREAD_ENV if (pass % 4 == 0) IOMGR_Poll(); #endif nbytes = rx_Read(rxcall, tbuffer, tlen); if (nbytes != tlen) { ubik_dprint("Rx-read bulk error=%d\n", code = BULK_ERROR); code = EIO; close(fd); goto FetchEndCall; } #ifdef OLD_URECOVERY nbytes = (*ubik_dbase->write) (ubik_dbase, file, tbuffer, offset, tlen); #else nbytes = write(fd, tbuffer, tlen); pass++; #endif if (nbytes != tlen) { code = UIOERROR; close(fd); goto FetchEndCall; } offset += tlen; length -= tlen; } #ifndef OLD_URECOVERY code = close(fd); if (code) goto FetchEndCall; #endif code = EndDISK_GetFile(rxcall, &tversion); FetchEndCall: tcode = rx_EndCall(rxcall, code); if (!code) code = tcode; if (!code) { /* we got a new file, set up its header */ urecovery_state |= UBIK_RECHAVEDB; memcpy(&ubik_dbase->version, &tversion, sizeof(struct ubik_version)); #ifdef OLD_URECOVERY (*ubik_dbase->sync) (ubik_dbase, 0); /* get data out first */ #else afs_snprintf(tbuffer, sizeof(tbuffer), "%s.DB%s%d", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); #ifdef AFS_NT40_ENV afs_snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); code = unlink(pbuffer); if (!code) code = rename(tbuffer, pbuffer); afs_snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.TMP", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); #endif if (!code) code = rename(pbuffer, tbuffer); if (!code) { (*ubik_dbase->open) (ubik_dbase, 0); #endif /* after data is good, sync disk with correct label */ code = (*ubik_dbase->setlabel) (ubik_dbase, 0, &ubik_dbase->version); #ifndef OLD_URECOVERY } #ifdef AFS_NT40_ENV afs_snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d.OLD", ubik_dbase->pathName, (file<0)?"SYS":"", (file<0)?-file:file); unlink(pbuffer); #endif #endif } if (code) { #ifndef OLD_URECOVERY unlink(pbuffer); /* * We will effectively invalidate the old data forever now. * Unclear if we *should* but we do. */ #endif ubik_dbase->version.epoch = 0; ubik_dbase->version.counter = 0; ubik_print("Ubik: Synchronize database failed (error = %d)\n", code); } else { ubik_print("Ubik: Synchronize database completed\n"); urecovery_state |= UBIK_RECHAVEDB; } udisk_Invalidate(ubik_dbase, 0); /* data has changed */ #ifdef AFS_PTHREAD_ENV assert(pthread_cond_broadcast(&ubik_dbase->version_cond) == 0); #else LWP_NoYieldSignal(&ubik_dbase->version); #endif DBRELE(ubik_dbase); } #if defined(UBIK_PAUSE) if (!(urecovery_state & UBIK_RECSYNCSITE)) continue; /* lost sync */ #endif /* UBIK_PAUSE */ if (!(urecovery_state & UBIK_RECHAVEDB)) continue; /* not ready */ /* If the database was newly initialized, then when we establish quorum, write * a new label. This allows urecovery_AllBetter() to allow access for reads. * Setting it to 2 also allows another site to come along with a newer * database and overwrite this one. */ if (ubik_dbase->version.epoch == 1) { DBHOLD(ubik_dbase); urecovery_AbortAll(ubik_dbase); ubik_epochTime = 2; ubik_dbase->version.epoch = ubik_epochTime; ubik_dbase->version.counter = 1; code = (*ubik_dbase->setlabel) (ubik_dbase, 0, &ubik_dbase->version); udisk_Invalidate(ubik_dbase, 0); /* data may have changed */ #ifdef AFS_PTHREAD_ENV assert(pthread_cond_broadcast(&ubik_dbase->version_cond) == 0); #else LWP_NoYieldSignal(&ubik_dbase->version); #endif DBRELE(ubik_dbase); } /* Check the other sites and send the database to them if they * do not have the current db. */ if (!(urecovery_state & UBIK_RECSENTDB)) { /* now propagate out new version to everyone else */ dbok = 1; /* start off assuming they all worked */ DBHOLD(ubik_dbase); /* * Check if a write transaction is in progress. We can't send the * db when a write is in progress here because the db would be * obsolete as soon as it goes there. Also, ops after the begin * trans would reach the recepient and wouldn't find a transaction * pending there. Frankly, I don't think it's possible to get past * the write-lock above if there is a write transaction in progress, * but then, it won't hurt to check, will it? */ if (ubik_dbase->flags & DBWRITING) { struct timeval tv; int safety = 0; tv.tv_sec = 0; tv.tv_usec = 50000; while ((ubik_dbase->flags & DBWRITING) && (safety < 500)) { DBRELE(ubik_dbase); /* sleep for a little while */ #ifdef AFS_PTHREAD_ENV select(0, 0, 0, 0, &tv); #else IOMGR_Select(0, 0, 0, 0, &tv); #endif tv.tv_usec += 10000; safety++; DBHOLD(ubik_dbase); } } for (ts = ubik_servers; ts; ts = ts->next) { inAddr.s_addr = ts->addr[0]; if (!ts->up) { ubik_dprint("recovery cannot send version to %s\n", afs_inet_ntoa_r(inAddr.s_addr, hoststr)); dbok = 0; continue; } ubik_dprint("recovery sending version to %s\n", afs_inet_ntoa_r(inAddr.s_addr, hoststr)); if (vcmp(ts->version, ubik_dbase->version) != 0) { ubik_dprint("recovery stating local database\n"); /* Rx code to do the Bulk Store */ code = (*ubik_dbase->stat) (ubik_dbase, 0, &ubikstat); if (!code) { length = ubikstat.size; file = offset = 0; rxcall = rx_NewCall(ts->disk_rxcid); code = StartDISK_SendFile(rxcall, file, length, &ubik_dbase->version); if (code) { ubik_dprint("StartDiskSendFile failed=%d\n", code); goto StoreEndCall; } while (length > 0) { tlen = (length > sizeof(tbuffer) ? sizeof(tbuffer) : length); nbytes = (*ubik_dbase->read) (ubik_dbase, file, tbuffer, offset, tlen); if (nbytes != tlen) { ubik_dprint("Local disk read error=%d\n", code = UIOERROR); goto StoreEndCall; } nbytes = rx_Write(rxcall, tbuffer, tlen); if (nbytes != tlen) { ubik_dprint("Rx-write bulk error=%d\n", code = BULK_ERROR); goto StoreEndCall; } offset += tlen; length -= tlen; } code = EndDISK_SendFile(rxcall); StoreEndCall: code = rx_EndCall(rxcall, code); } if (code == 0) { /* we set a new file, process its header */ ts->version = ubik_dbase->version; ts->currentDB = 1; } else dbok = 0; } else { /* mark file up to date */ ts->currentDB = 1; } } DBRELE(ubik_dbase); if (dbok) urecovery_state |= UBIK_RECSENTDB; } } return NULL; }
/*! * \warning Beware, when using this function, of the header in front of most files. */ static int uphys_open(struct ubik_dbase *adbase, afs_int32 afid) { int fd; static int initd; int i; struct fdcache *tfd; struct fdcache *bestfd; /* initialize package */ if (!initd) { initd = 1; tfd = fdcache; for (i = 0; i < MAXFDCACHE; tfd++, i++) { tfd->fd = -1; /* invalid value */ tfd->fileID = -10000; /* invalid value */ tfd->refCount = 0; } } /* scan file descr cache */ for (tfd = fdcache, i = 0; i < MAXFDCACHE; i++, tfd++) { if (afid == tfd->fileID && tfd->refCount == 0) { /* don't use open fd */ lseek(tfd->fd, 0, 0); /* reset ptr just like open would have */ tfd->refCount++; return tfd->fd; } } /* not found, open it and try to enter in cache */ afs_snprintf(pbuffer, sizeof(pbuffer), "%s.DB%s%d", adbase->pathName, (afid<0)?"SYS":"", (afid<0)?-afid:afid); fd = open(pbuffer, O_CREAT | O_RDWR, 0600); if (fd < 0) { /* try opening read-only */ fd = open(pbuffer, O_RDONLY, 0); if (fd < 0) return fd; } /* enter it in the cache */ tfd = fdcache; bestfd = NULL; for (i = 0; i < MAXFDCACHE; i++, tfd++) { /* look for empty slot */ if (tfd->fd == -1) { bestfd = tfd; break; } } if (!bestfd) { /* look for reclaimable slot */ tfd = fdcache; for (i = 0; i < MAXFDCACHE; i++, tfd++) { if (tfd->refCount == 0) { bestfd = tfd; break; } } } if (bestfd) { /* found a usable slot */ tfd = bestfd; if (tfd->fd >= 0) close(tfd->fd); tfd->fd = fd; tfd->refCount = 1; /* us */ tfd->fileID = afid; } /* finally, we're done */ return fd; }
static int handleit(struct cmd_syndesc *as, void *arock) { struct cmd_item *ti; int err = 0; afs_uint32 volumeId = 0; char *partName = 0; struct DiskPartition64 *partP = NULL; #ifndef AFS_NT40_ENV if (geteuid() != 0) { printf("vol-info must be run as root; sorry\n"); exit(1); } #endif if (as->parms[0].items) online = 1; else online = 0; if (as->parms[1].items) DumpVnodes = 1; else DumpVnodes = 0; if (as->parms[2].items) DumpDate = 1; else DumpDate = 0; if (as->parms[3].items) DumpInodeNumber = 1; else DumpInodeNumber = 0; if (as->parms[4].items) InodeTimes = 1; else InodeTimes = 0; if ((ti = as->parms[5].items)) partName = ti->data; if ((ti = as->parms[6].items)) volumeId = strtoul(ti->data, NULL, 10); if (as->parms[7].items) dheader = 1; else dheader = 0; if (as->parms[8].items) { dsizeOnly = 1; dheader = 1; DumpVnodes = 1; } else dsizeOnly = 0; if (as->parms[9].items) { fixheader = 1; } else fixheader = 0; if (as->parms[10].items) { saveinodes = 1; dheader = 1; DumpVnodes = 1; } else saveinodes = 0; if (as->parms[11].items) { orphaned = 1; DumpVnodes = 1; } else #if defined(AFS_NAMEI_ENV) if (as->parms[12].items) { PrintFileNames = 1; DumpVnodes = 1; } else #endif orphaned = 0; DInit(10); err = VAttachPartitions(); if (err) { printf("%d partitions had errors during attach.\n", err); } if (partName) { partP = VGetPartition(partName, 0); if (!partP) { printf("%s is not an AFS partition name on this server.\n", partName); exit(1); } } if (!volumeId) { if (!partP) { HandleAllPart(); } else { HandlePart(partP); } } else { char name1[128]; if (!partP) { partP = FindCurrentPartition(); if (!partP) { printf("Current partition is not a vice partition.\n"); exit(1); } } (void)afs_snprintf(name1, sizeof name1, VFORMAT, afs_printable_uint32_lu(volumeId)); if (dsizeOnly && !saveinodes) printf ("Volume-Id\t Volsize Auxsize Inodesize AVolsize SizeDiff (VolName)\n"); HandleVolume(partP, name1); } return 0; }
void HandleVolume(struct DiskPartition64 *dp, char *name) { struct VolumeHeader header; struct VolumeDiskHeader diskHeader; struct afs_stat status, stat; int fd; Volume *vp; IHandle_t *ih; char headerName[1024]; if (online) { printf("volinfo: -online not supported\n"); exit(1); } else { afs_int32 n; (void)afs_snprintf(headerName, sizeof headerName, "%s/%s", VPartitionPath(dp), name); if ((fd = afs_open(headerName, O_RDONLY)) == -1 || afs_fstat(fd, &status) == -1) { printf("Volinfo: Cannot read volume header %s\n", name); close(fd); exit(1); } n = read(fd, &diskHeader, sizeof(diskHeader)); if (n != sizeof(diskHeader) || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) { printf("Volinfo: Error reading volume header %s\n", name); exit(1); } if (diskHeader.stamp.version != VOLUMEHEADERVERSION) { printf ("Volinfo: Volume %s, version number is incorrect; volume needs salvage\n", name); exit(1); } DiskToVolumeHeader(&header, &diskHeader); if (dheader) { FdHandle_t *fdP; afs_sfsize_t size = 0; afs_sfsize_t code; if (afs_fstat(fd, &stat) == -1) { perror("stat"); exit(1); } if (!dsizeOnly && !saveinodes) { size = stat.st_size; printf("Volume header (size = %d):\n", (int)size); printf("\tstamp\t= 0x%x\n", header.stamp.version); printf("\tVolId\t= %u\n", header.id); } IH_INIT(ih, dp->device, header.parent, header.volumeInfo); fdP = IH_OPEN(ih); if (fdP == NULL) { perror("opening volume info"); exit(1); } code = FDH_SIZE(fdP); if (code == -1) { perror("fstat"); exit(1); } FDH_REALLYCLOSE(fdP); IH_RELEASE(ih); size += code; if (!dsizeOnly && !saveinodes) { printf("\tparent\t= %u\n", header.parent); printf("\tInfo inode\t= %s (size = %d)\n", PrintInode(NULL, header.volumeInfo), (int)code); } IH_INIT(ih, dp->device, header.parent, header.smallVnodeIndex); fdP = IH_OPEN(ih); if (fdP == NULL) { perror("opening small vnode index"); exit(1); } code = FDH_SIZE(fdP); if (code == -1) { perror("fstat"); exit(1); } FDH_REALLYCLOSE(fdP); IH_RELEASE(ih); size += code; if (!dsizeOnly && !saveinodes) { printf("\tSmall inode\t= %s (size = %d)\n", PrintInode(NULL, header.smallVnodeIndex), (int)code); } IH_INIT(ih, dp->device, header.parent, header.largeVnodeIndex); fdP = IH_OPEN(ih); if (fdP == NULL) { perror("opening large vnode index"); exit(1); } code = FDH_SIZE(fdP); if (code == -1) { perror("fstat"); exit(1); } FDH_REALLYCLOSE(fdP); IH_RELEASE(ih); size += code; if (!dsizeOnly && !saveinodes) { printf("\tLarge inode\t= %s (size = %d)\n", PrintInode(NULL, header.largeVnodeIndex), (int)code); #ifndef AFS_NT40_ENV printf("Total aux volume size = %d\n\n", (int)size); #endif } #ifdef AFS_NAMEI_ENV IH_INIT(ih, dp->device, header.parent, header.linkTable); fdP = IH_OPEN(ih); if (fdP == NULL) { perror("opening link table index"); exit(1); } code = FDH_SIZE(fdP); if (code == -1) { perror("fstat"); exit(1); } FDH_REALLYCLOSE(fdP); IH_RELEASE(ih); size += code; if (!dsizeOnly && !saveinodes) { printf("\tLink inode\t= %s (size = %d)\n", PrintInode(NULL, header.linkTable), (int)code); printf("Total aux volume size = %d\n\n", (int)size); } #endif Vauxsize = size; Vauxsize_k = size / 1024; } close(fd); vp = AttachVolume(dp, name, &header); if (!vp) { printf("Volinfo: Error attaching volume header %s\n", name); return; } } PrintHeader(vp); if (DumpVnodes) { if (!dsizeOnly && !saveinodes) printf("\nLarge vnodes (directories)\n"); PrintVnodes(vp, vLarge); if (!dsizeOnly && !saveinodes) { printf("\nSmall vnodes(files, symbolic links)\n"); fflush(stdout); } if (saveinodes) printf("Saving all volume files to current directory ...\n"); PrintVnodes(vp, vSmall); } if (dsizeOnly) { totvolsize = Vauxsize_k + Vvnodesize_k; if (saveinodes) printf ("Volume-Id\t Volsize Auxsize Inodesize AVolsize SizeDiff (VolName)\n"); printf("%u\t%9d%9d%10d%10d%9d\t%24s\n", V_id(vp), Vdiskused, Vauxsize_k, Vvnodesize_k, totvolsize, totvolsize - Vdiskused, V_name(vp)); } free(vp->header); free(vp); }
static int CommandProc(struct cmd_syndesc *a_as, void *arock) { int i; long code = 0; long upos; long gpos = 0; struct prentry uentry, gentry; struct ubik_hdr *uh; char *dfile = 0; const char *pbase = AFSDIR_SERVER_PRDB_FILEPATH; char *pfile = NULL; char pbuffer[1028]; struct cmd_parmdesc *tparm; tparm = a_as->parms; if (tparm[0].items) { wflag++; } if (tparm[1].items) { flags |= DO_USR; } if (tparm[2].items) { flags |= DO_GRP; } if (tparm[3].items) { flags |= (DO_GRP | DO_MEM); } if (tparm[4].items) { nflag++; } if (tparm[5].items) { flags |= DO_SYS; } if (tparm[6].items) { flags |= DO_OTR; } if (tparm[7].items) { pfile = tparm[7].items->data; } if (tparm[8].items) { dfile = tparm[8].items->data; } if (pfile == NULL) { afs_snprintf(pbuffer, sizeof(pbuffer), "%s.DB0", pbase); pfile = pbuffer; } if ((dbase_fd = open(pfile, (wflag ? O_RDWR : O_RDONLY) | O_CREAT, 0600)) < 0) { fprintf(stderr, "pt_util: cannot open %s: %s\n", pfile, strerror(errno)); exit(1); } if (read(dbase_fd, buffer, HDRSIZE) < 0) { fprintf(stderr, "pt_util: error reading %s: %s\n", pfile, strerror(errno)); exit(1); } if (dfile) { if ((dfp = fopen(dfile, wflag ? "r" : "w")) == 0) { fprintf(stderr, "pt_util: error opening %s: %s\n", dfile, strerror(errno)); exit(1); } } else dfp = (wflag ? stdin : stdout); uh = (struct ubik_hdr *)buffer; if (ntohl(uh->magic) != UBIK_MAGIC) fprintf(stderr, "pt_util: %s: Bad UBIK_MAGIC. Is %x should be %x\n", pfile, ntohl(uh->magic), UBIK_MAGIC); memcpy(&uv, &uh->version, sizeof(struct ubik_version)); if (wflag && ntohl(uv.epoch) == 0 && ntohl(uv.counter) == 0) { uv.epoch = htonl(2); /* a ubik version of 0 or 1 has special meaning */ memcpy(&uh->version, &uv, sizeof(struct ubik_version)); lseek(dbase_fd, 0, SEEK_SET); if (write(dbase_fd, buffer, HDRSIZE) < 0) { fprintf(stderr, "pt_util: error writing ubik version to %s: %s\n", pfile, strerror(errno)); exit(1); } } /* Now that any writeback is done, swap these */ uv.epoch = ntohl(uv.epoch); uv.counter = ntohl(uv.counter); fprintf(stderr, "Ubik Version is: %d.%d\n", uv.epoch, uv.counter); if (read(dbase_fd, &prh, sizeof(struct prheader)) < 0) { fprintf(stderr, "pt_util: error reading %s: %s\n", pfile, strerror(errno)); exit(1); } Initdb(); initialize_PT_error_table(); if (wflag) { struct usr_list *u; while (fgets(buffer, sizeof(buffer), dfp)) { int id, oid, cid, flags, quota, uid; char name[PR_MAXNAMELEN], mem[PR_MAXNAMELEN]; if (isspace(*buffer)) { sscanf(buffer, "%s %d", mem, &uid); for (u = usr_head; u; u = u->next) if (u->uid && u->uid == uid) break; if (u) { /* Add user - deferred because it is probably foreign */ u->uid = 0; if (FindByID(0, uid)) code = PRIDEXIST; else { if (!code && (flags & (PRGRP | PRQUOTA)) == (PRGRP | PRQUOTA)) { gentry.ngroups++; code = pr_WriteEntry(0, 0, gpos, &gentry); if (code) fprintf(stderr, "Error setting group count on %s: %s\n", name, afs_error_message(code)); } code = CreateEntry(0, u->name, &uid, 1 /*idflag */ , 1 /*gflag */ , SYSADMINID /*oid */ , SYSADMINID /*cid */ ); } if (code) fprintf(stderr, "Error while creating %s: %s\n", u->name, afs_error_message(code)); continue; } /* Add user to group */ if (id == ANYUSERID || id == AUTHUSERID || uid == ANONYMOUSID) { code = PRPERM; } else if ((upos = FindByID(0, uid)) && (gpos = FindByID(0, id))) { code = pr_ReadEntry(0, 0, upos, &uentry); if (!code) code = pr_ReadEntry(0, 0, gpos, &gentry); if (!code) code = AddToEntry(0, &gentry, gpos, uid); if (!code) code = AddToEntry(0, &uentry, upos, id); } else code = PRNOENT; if (code) fprintf(stderr, "Error while adding %s to %s: %s\n", mem, name, afs_error_message(code)); } else { sscanf(buffer, "%s %d/%d %d %d %d", name, &flags, "a, &id, &oid, &cid); if (FindByID(0, id)) code = PRIDEXIST; else code = CreateEntry(0, name, &id, 1 /*idflag */ , flags & PRGRP, oid, cid); if (code == PRBADNAM) { u = (struct usr_list *)malloc(sizeof(struct usr_list)); u->next = usr_head; u->uid = id; strcpy(u->name, name); usr_head = u; } else if (code) { fprintf(stderr, "Error while creating %s: %s\n", name, afs_error_message(code)); } else if ((flags & PRACCESS) || (flags & (PRGRP | PRQUOTA)) == (PRGRP | PRQUOTA)) { gpos = FindByID(0, id); code = pr_ReadEntry(0, 0, gpos, &gentry); if (!code) { gentry.flags = flags; gentry.ngroups = quota; code = pr_WriteEntry(0, 0, gpos, &gentry); } if (code) fprintf(stderr, "Error while setting flags on %s: %s\n", name, afs_error_message(code)); } } } for (u = usr_head; u; u = u->next) if (u->uid) fprintf(stderr, "Error while creating %s: %s\n", u->name, afs_error_message(PRBADNAM)); } else { for (i = 0; i < HASHSIZE; i++) { upos = nflag ? ntohl(prh.nameHash[i]) : ntohl(prh.idHash[i]); while (upos) { long newpos; newpos = display_entry(upos); if (newpos == upos) { fprintf(stderr, "pt_util: hash error in %s chain %d\n", nflag ? "name":"id", i); exit(1); } else upos = newpos; } } if (flags & DO_GRP) display_groups(); } lseek(dbase_fd, 0, L_SET); /* rewind to beginning of file */ if (read(dbase_fd, buffer, HDRSIZE) < 0) { fprintf(stderr, "pt_util: error reading %s: %s\n", pfile, strerror(errno)); exit(1); } uh = (struct ubik_hdr *)buffer; uh->version.epoch = ntohl(uh->version.epoch); uh->version.counter = ntohl(uh->version.counter); if ((uh->version.epoch != uv.epoch) || (uh->version.counter != uv.counter)) { fprintf(stderr, "pt_util: Ubik Version number changed during execution.\n"); fprintf(stderr, "Old Version = %d.%d, new version = %d.%d\n", uv.epoch, uv.counter, uh->version.epoch, uh->version.counter); } close(dbase_fd); exit(0); }