예제 #1
0
void
sr_installpbr(int devfd, int vol, int disk)
{
	struct bioc_disk bd;
	struct disklabel dl;
	struct partition *pp;
	uint32_t poffset;
	char *realdiskdev;
	char part;
	int diskfd;
	int rv;

	/* Get device name for this disk/chunk. */
	memset(&bd, 0, sizeof(bd));
	bd.bd_volid = vol;
	bd.bd_diskid = disk;
	rv = ioctl(devfd, BIOCDISK, &bd);
	if (rv == -1)
		err(1, "BIOCDISK");

	/* Check disk status. */
	if (bd.bd_status != BIOC_SDONLINE && bd.bd_status != BIOC_SDREBUILD) {
		fprintf(stderr, "softraid chunk %u not online - skipping...\n",
		    disk);
		return;	
	}

	if (strlen(bd.bd_vendor) < 1)
		errx(1, "invalid disk name");
	part = bd.bd_vendor[strlen(bd.bd_vendor) - 1];
	if (part < 'a' || part >= 'a' + MAXPARTITIONS)
		errx(1, "invalid partition %c\n", part);
	bd.bd_vendor[strlen(bd.bd_vendor) - 1] = '\0';

	/* Open this device and check its disklabel. */
	if ((diskfd = opendev(bd.bd_vendor, (nowrite? O_RDONLY:O_RDWR),
	    OPENDEV_PART, &realdiskdev)) < 0)
		err(1, "open: %s", realdiskdev);

	/* Get and check disklabel. */
	if (ioctl(diskfd, DIOCGDINFO, &dl) != 0)
		err(1, "disklabel: %s", realdev);
	if (dl.d_magic != DISKMAGIC)
		err(1, "bad disklabel magic=0x%08x", dl.d_magic);

	/* Warn on unknown disklabel types. */
	if (dl.d_type == 0)
		warnx("disklabel type unknown");

	/* Determine poffset and set symbol value. */
	pp = &dl.d_partitions[part - 'a'];
	if (pp->p_offseth != 0)
		errx(1, "partition offset too high");
	poffset = pp->p_offset; 		/* Offset of RAID partition. */
	poffset += SR_BOOT_LOADER_OFFSET;	/* SR boot loader area. */
	sym_set_value(pbr_symbols, "_p_offset", poffset);

	if (verbose)
		fprintf(stderr, "%s%c: installing boot blocks on %s, "
		    "part offset %u\n", bd.bd_vendor, part, realdiskdev,
		    poffset);

	/* Write boot blocks to device. */
	write_bootblocks(diskfd, &dl);

	close(diskfd);
}
예제 #2
0
/*
 * Read information about /boot's inode, then put this and filesystem
 * parameters from the superblock into pbr_symbols.
 */
static int
getbootparams(char *boot, int devfd, struct disklabel *dl)
{
	int		fd;
	struct stat	statbuf, sb;
	struct statfs	statfsbuf;
	struct partition *pp;
	struct fs	*fs;
	char		*buf;
	u_int		blk, *ap;
	struct ufs1_dinode	*ip1;
	struct ufs2_dinode	*ip2;
	int		ndb;
	int		mib[3];
	size_t		size;
	dev_t		dev;
	int		skew;

	/*
	 * Open 2nd-level boot program and record enough details about
	 * where it is on the filesystem represented by `devfd'
	 * (inode block, offset within that block, and various filesystem
	 * parameters essentially taken from the superblock) for biosboot
	 * to be able to load it later.
	 */

	/* Make sure the (probably new) boot file is on disk. */
	sync(); sleep(1);

	if ((fd = open(boot, O_RDONLY)) < 0)
		err(1, "open: %s", boot);

	if (fstatfs(fd, &statfsbuf) != 0)
		err(1, "statfs: %s", boot);

	if (strncmp(statfsbuf.f_fstypename, "ffs", MFSNAMELEN) &&
	    strncmp(statfsbuf.f_fstypename, "ufs", MFSNAMELEN) )
		errx(1, "%s: not on an FFS filesystem", boot);

#if 0
	if (read(fd, &eh, sizeof(eh)) != sizeof(eh))
		errx(1, "read: %s", boot);

	if (!IS_ELF(eh)) {
		errx(1, "%s: bad magic: 0x%02x%02x%02x%02x",
		    boot,
		    eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1],
		    eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]);
	}
#endif

	if (fsync(fd) != 0)
		err(1, "fsync: %s", boot);

	if (fstat(fd, &statbuf) != 0)
		err(1, "fstat: %s", boot);

	if (fstat(devfd, &sb) != 0)
		err(1, "fstat: %s", realdev);

	/* Check devices. */
	mib[0] = CTL_MACHDEP;
	mib[1] = CPU_CHR2BLK;
	mib[2] = sb.st_rdev;
	size = sizeof(dev);
	if (sysctl(mib, 3, &dev, &size, NULL, 0) >= 0) {
		if (statbuf.st_dev / MAXPARTITIONS != dev / MAXPARTITIONS)
			errx(1, "cross-device install");
	}

	pp = &dl->d_partitions[DISKPART(statbuf.st_dev)];
	close(fd);

	sbread(devfd, DL_SECTOBLK(dl, DL_GETPOFFSET(pp)), &fs);

	/* Read inode. */
	if ((buf = malloc(fs->fs_bsize)) == NULL)
		err(1, NULL);

	blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));

	/*
	 * Have the inode.  Figure out how many filesystem blocks (not disk
	 * sectors) there are for biosboot to load.
	 */
	devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset) + blk,
	    fs->fs_bsize, "inode");
	if (fs->fs_magic == FS_UFS2_MAGIC) {
		ip2 = (struct ufs2_dinode *)(buf) +
		    ino_to_fsbo(fs, statbuf.st_ino);
		ndb = howmany(ip2->di_size, fs->fs_bsize);
		ap = (u_int *)ip2->di_db;
		skew = sizeof(u_int32_t);
	} else {
		ip1 = (struct ufs1_dinode *)(buf) +
		    ino_to_fsbo(fs, statbuf.st_ino);
		ndb = howmany(ip1->di_size, fs->fs_bsize);
		ap = (u_int *)ip1->di_db;
		skew = 0;
	}
	if (ndb <= 0)
		errx(1, "No blocks to load");

	/*
	 * Now set the values that will need to go into biosboot
	 * (the partition boot record, a.k.a. the PBR).
	 */
	sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16));
	sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / 
	    dl->d_secsize));

	/*
	 * fs_fsbtodb is the shift to convert fs_fsize to DEV_BSIZE. The
	 * ino_to_fsba() return value is the number of fs_fsize units.
	 * Calculate the shift to convert fs_fsize into physical sectors,
	 * which are added to p_offset to get the sector address BIOS
	 * will use.
	 *
	 * N.B.: ASSUMES fs_fsize is a power of 2 of d_secsize.
	 */
	sym_set_value(pbr_symbols, "_fsbtodb",
	    ffs(fs->fs_fsize / dl->d_secsize) - 1);

	if (pp->p_offseth != 0)
		errx(1, "partition offset too high");
	sym_set_value(pbr_symbols, "_p_offset", pp->p_offset);
	sym_set_value(pbr_symbols, "_inodeblk",
	    ino_to_fsba(fs, statbuf.st_ino));
	sym_set_value(pbr_symbols, "_inodedbl",
	    ((((char *)ap) - buf) + INODEOFF));
	sym_set_value(pbr_symbols, "_nblocks", ndb);
	sym_set_value(pbr_symbols, "_blkskew", skew);

	if (verbose) {
		fprintf(stderr, "%s is %d blocks x %d bytes\n",
		    boot, ndb, fs->fs_bsize);
		fprintf(stderr, "fs block shift %u; part offset %llu; "
		    "inode block %lld, offset %u\n",
		    ffs(fs->fs_fsize / dl->d_secsize) - 1,
		    DL_GETPOFFSET(pp), ino_to_fsba(fs, statbuf.st_ino),
		    (unsigned int)((((char *)ap) - buf) + INODEOFF));
		fprintf(stderr, "expecting %d-bit fs blocks (skew %d)\n",
		    skew ? 64 : 32, skew);
	}

	return 0;
}
예제 #3
0
void
sr_installboot(int devfd)
{
	struct bioc_installboot bb;
	struct stat sb;
	struct ufs1_dinode *ino_p;
	uint32_t bootsize, inodeblk, inodedbl;
	uint16_t bsize = SR_FS_BLOCKSIZE;
	uint16_t nblocks;
	uint8_t bshift = 5;		/* fragsize == blocksize */
	int fd, i, rv;
	u_char *p;

	/*
	 * Install boot loader into softraid boot loader storage area.
	 *
	 * In order to allow us to reuse the existing biosboot we construct
	 * a fake FFS filesystem with a single inode, which points to the
	 * boot loader.
	 */

	nblocks = howmany(SR_BOOT_LOADER_SIZE, SR_FS_BLOCKSIZE / DEV_BSIZE);
	inodeblk = nblocks - 1;
	bootsize = nblocks * SR_FS_BLOCKSIZE;

	p = malloc(bootsize);
	if (p == NULL)
		err(1, NULL);
	
	memset(p, 0, bootsize);
	fd = open(boot, O_RDONLY, 0);
	if (fd == -1)
		err(1, NULL);

	if (fstat(fd, &sb) == -1)
		err(1, NULL);

	nblocks = howmany(sb.st_blocks, SR_FS_BLOCKSIZE / DEV_BSIZE);
	if (sb.st_blocks * S_BLKSIZE > bootsize - sizeof(struct ufs1_dinode))
		errx(1, "boot code will not fit");

	/* We only need to fill the direct block array. */
	ino_p = (struct ufs1_dinode *)&p[bootsize - sizeof(struct ufs1_dinode)];

	ino_p->di_mode = sb.st_mode;
	ino_p->di_nlink = 1;
	ino_p->di_inumber = 0xfeebfaab;
	ino_p->di_size = read(fd, p, sb.st_blocks * S_BLKSIZE);
	ino_p->di_blocks = nblocks;
	for (i = 0; i < nblocks; i++)
		ino_p->di_db[i] = i;

	inodedbl = ((u_char*)&ino_p->di_db[0] -
	    &p[bootsize - SR_FS_BLOCKSIZE]) + INODEOFF;

	bb.bb_bootldr = p;
	bb.bb_bootldr_size = bootsize;
	bb.bb_bootblk = "XXX";
	bb.bb_bootblk_size = sizeof("XXX");
	strncpy(bb.bb_dev, dev, sizeof(bb.bb_dev));
	if (!nowrite) {
		if (verbose)
			fprintf(stderr, "%s: installing boot loader on "
			    "softraid volume\n", dev);
		rv = ioctl(devfd, BIOCINSTALLBOOT, &bb);
		if (rv != 0)
			errx(1, "softraid installboot failed");
	}

	/*
	 * Set the values that will need to go into biosboot
	 * (the partition boot record, a.k.a. the PBR).
	 */
	sym_set_value(pbr_symbols, "_fs_bsize_p", (bsize / 16));
	sym_set_value(pbr_symbols, "_fs_bsize_s", (bsize / 512));
	sym_set_value(pbr_symbols, "_fsbtodb", bshift);
	sym_set_value(pbr_symbols, "_inodeblk", inodeblk);
	sym_set_value(pbr_symbols, "_inodedbl", inodedbl);
	sym_set_value(pbr_symbols, "_nblocks", nblocks);
	sym_set_value(pbr_symbols, "_blkskew", 0);

	if (verbose)
		fprintf(stderr, "%s is %d blocks x %d bytes\n",
		    boot, nblocks, bsize);

	close(fd);
}
예제 #4
0
/*
 * Read information about /boot's inode, then put this and filesystem
 * parameters from the superblock into pbr_symbols.
 */
static int
getbootparams(char *boot, int devfd, struct disklabel *dl)
{
	int		fd;
	struct stat	statbuf, sb;
	struct statfs	statfsbuf;
	struct partition *pl;
	struct fs	*fs;
	char		*buf;
	daddr_t		blk, *ap;
	struct ufs1_dinode	*ip;
	int		ndb;
	int		mib[3];
	size_t		size;
	dev_t		dev;

	/*
	 * Open 2nd-level boot program and record enough details about
	 * where it is on the filesystem represented by `devfd'
	 * (inode block, offset within that block, and various filesystem
	 * parameters essentially taken from the superblock) for biosboot
	 * to be able to load it later.
	 */

	/* Make sure the (probably new) boot file is on disk. */
	sync(); sleep(1);

	if ((fd = open(boot, O_RDONLY)) < 0)
		err(1, "open: %s", boot);

	if (fstatfs(fd, &statfsbuf) != 0)
		err(1, "statfs: %s", boot);

	if (strncmp(statfsbuf.f_fstypename, "ffs", MFSNAMELEN) &&
	    strncmp(statfsbuf.f_fstypename, "ufs", MFSNAMELEN) )
		errx(1, "%s: not on an FFS filesystem", boot);

#if 0
	if (read(fd, &eh, sizeof(eh)) != sizeof(eh))
		errx(1, "read: %s", boot);

	if (!IS_ELF(eh)) {
		errx(1, "%s: bad magic: 0x%02x%02x%02x%02x",
		    boot,
		    eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1],
		    eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]);
	}
#endif

	if (fsync(fd) != 0)
		err(1, "fsync: %s", boot);

	if (fstat(fd, &statbuf) != 0)
		err(1, "fstat: %s", boot);

	if (fstat(devfd, &sb) != 0)
		err(1, "fstat: %s", realdev);

	/* Check devices. */
	mib[0] = CTL_MACHDEP;
	mib[1] = CPU_CHR2BLK;
	mib[2] = sb.st_rdev;
	size = sizeof(dev);
	if (sysctl(mib, 3, &dev, &size, NULL, 0) >= 0) {
		if (statbuf.st_dev / MAXPARTITIONS != dev / MAXPARTITIONS)
			errx(1, "cross-device install");
	}

	pl = &dl->d_partitions[DISKPART(statbuf.st_dev)];
	close(fd);

	/* Read superblock. */
	devread(devfd, sblock, pl->p_offset + SBLOCK, SBSIZE, "superblock");
	fs = (struct fs *)sblock;

	/* Sanity-check super-block. */
	if (fs->fs_magic != FS_MAGIC)
		errx(1, "Bad magic number in superblock");
	if (fs->fs_inopb <= 0)
		err(1, "Bad inopb=%d in superblock", fs->fs_inopb);

	/* Read inode. */
	if ((buf = malloc(fs->fs_bsize)) == NULL)
		err(1, NULL);

	blk = fsbtodb(fs, ino_to_fsba(fs, statbuf.st_ino));

	devread(devfd, buf, pl->p_offset + blk, fs->fs_bsize, "inode");
	ip = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, statbuf.st_ino);

	/*
	 * Have the inode.  Figure out how many filesystem blocks (not disk
	 * sectors) there are for biosboot to load.
	 */
	ndb = howmany(ip->di_size, fs->fs_bsize);
	if (ndb <= 0)
		errx(1, "No blocks to load");

	/*
	 * Now set the values that will need to go into biosboot
	 * (the partition boot record, a.k.a. the PBR).
	 */
	sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16));
	sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / 512));
	sym_set_value(pbr_symbols, "_fsbtodb", fs->fs_fsbtodb);
	sym_set_value(pbr_symbols, "_p_offset", pl->p_offset);
	sym_set_value(pbr_symbols, "_inodeblk",
	    ino_to_fsba(fs, statbuf.st_ino));
	ap = ip->di_db;
	sym_set_value(pbr_symbols, "_inodedbl",
	    ((((char *)ap) - buf) + INODEOFF));
	sym_set_value(pbr_symbols, "_nblocks", ndb);

	if (verbose) {
		fprintf(stderr, "%s is %d blocks x %d bytes\n",
		    boot, ndb, fs->fs_bsize);
		fprintf(stderr, "fs block shift %u; part offset %u; "
		    "inode block %u, offset %ld\n",
		    fs->fs_fsbtodb, pl->p_offset,
		    ino_to_fsba(fs, statbuf.st_ino),
		    ((((char *)ap) - buf) + INODEOFF));
	}

	return 0;
}