Exemple #1
0
/* 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);
}
Exemple #2
0
/**
 * 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;
}
Exemple #3
0
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;
}
Exemple #4
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 */
}
Exemple #5
0
/**
 * 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;
}
Exemple #6
0
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;
}
Exemple #8
0
/**
 * 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;
}
Exemple #9
0
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(&currenttime, 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 */
Exemple #10
0
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);
}
Exemple #11
0
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;
}
Exemple #12
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 */
Exemple #13
0
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));
}
Exemple #14
0
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;
}
Exemple #15
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;
}
Exemple #16
0
/**
 * 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;
}
Exemple #17
0
/*!
 * \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;
}
Exemple #18
0
/*!
 * \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;
}
Exemple #19
0
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;
}
Exemple #20
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);
}
Exemple #21
0
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, &quota, &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);
}