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); }
/* * 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; }
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); }
/* * 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; }