diff --git a/usr.sbin/boot0cfg/boot0cfg.c b/usr.sbin/boot0cfg/boot0cfg.c index 1da269225310..77244367f537 100644 --- a/usr.sbin/boot0cfg/boot0cfg.c +++ b/usr.sbin/boot0cfg/boot0cfg.c @@ -73,6 +73,9 @@ static const char fmt0[] = "# flag start chs type" static const char fmt1[] = "%d 0x%02x %4u:%3u:%2u 0x%02x" " %4u:%3u:%2u %10u %10u\n"; +static int read_mbr(const char *, u_int8_t **, int); +static void write_mbr(const char *, int, u_int8_t *, int); +static void display_mbr(u_int8_t *); static int boot0version(const u_int8_t *); static int boot0bs(const u_int8_t *); static void stropt(const char *, int *, int *); @@ -86,18 +89,13 @@ static void usage(void); int main(int argc, char *argv[]) { - u_int8_t buf[MBRSIZE]; - u_int8_t *boot0 = buf; - int version; - int boot0_size = sizeof(buf); - struct dos_partition part[4]; - struct stat sb; + u_int8_t *mbr, *boot0; + int boot0_size, mbr_size; const char *bpath, *fpath, *disk; - ssize_t n; int B_flag, v_flag, o_flag; int d_arg, m_arg, t_arg; int o_and, o_or; - int fd, fd1, up, c, i; + int up, c; bpath = "/boot/boot0"; fpath = NULL; @@ -141,41 +139,34 @@ main(int argc, char *argv[]) usage(); disk = mkrdev(*argv); up = B_flag || d_arg != -1 || m_arg != -1 || o_flag || t_arg != -1; - if ((fd = open(disk, up ? O_RDWR : O_RDONLY)) == -1) - err(1, "%s", disk); - if ((n = read(fd, buf, MBRSIZE)) == -1) - err(1, "%s", disk); - if (n != MBRSIZE) - errx(1, "%s: short read", disk); - if (cv2(buf + OFF_MAGIC) != 0xaa55) - errx(1, "%s: bad magic", disk); - if (!B_flag && !boot0bs(buf)) - errx(1, "%s: unknown or incompatible boot code", disk); - if (fpath) { - if ((fd1 = open(fpath, O_WRONLY | O_CREAT | O_TRUNC, - 0666)) == -1 || - (n = write(fd1, buf, MBRSIZE)) == -1 || close(fd1)) - err(1, "%s", fpath); - if (n != MBRSIZE) - errx(1, "%s: short write", fpath); - } - memcpy(part, buf + OFF_PTBL, sizeof(part)); + + /* open the disk and read in the existing mbr */ + mbr_size = read_mbr(disk, &mbr, !B_flag); + + /* save the existing MBR if we are asked to do so */ + if (fpath) + write_mbr(fpath, O_CREAT | O_TRUNC, mbr, mbr_size); + + /* + * If we are installing the boot loader, read it from disk and copy the + * slice table over from the existing MBR. If not, then point boot0 + * back at the MBR we just read in. After this, boot0 is the data to + * write back to disk if we are going to do a write. + */ if (B_flag) { - if ((fd1 = open(bpath, O_RDONLY)) == -1 || - fstat(fd1, &sb) == -1) - err(1, "%s", bpath); - if ((boot0 = malloc(boot0_size = sb.st_size)) == NULL) - errx(1, "%s: unable to allocate read buffer", bpath); - if ((n = read(fd1, boot0, boot0_size)) == -1 || close(fd1)) - err(1, "%s", bpath); - if (n != boot0_size) - errx(1, "%s: short read", bpath); - if (!boot0bs(boot0)) - errx(1, "%s: unknown or incompatible boot code", bpath); - memcpy(boot0 + OFF_PTBL, part, sizeof(part)); + boot0_size = read_mbr(bpath, &boot0, 1); + memcpy(boot0 + OFF_PTBL, mbr + OFF_PTBL, + sizeof(struct dos_partition) * NDOSPART); + } else { + boot0 = mbr; + boot0_size = mbr_size; } + + /* set the drive */ if (d_arg != -1) boot0[OFF_DRIVE] = d_arg; + + /* set various flags */ if (m_arg != -1) { boot0[OFF_FLAGS] &= 0xf0; boot0[OFF_FLAGS] |= m_arg; @@ -184,49 +175,118 @@ main(int argc, char *argv[]) boot0[OFF_FLAGS] &= o_and; boot0[OFF_FLAGS] |= o_or; } + + /* set the timeout */ if (t_arg != -1) mk2(boot0 + OFF_TICKS, t_arg); - if (up) { - if (lseek(fd, 0, SEEK_SET) == -1 || - (n = write(fd, boot0, boot0_size)) == -1 || close(fd)) - err(1, "%s", disk); - if (n != boot0_size) - errx(1, "%s: short write", disk); - } - if (v_flag) { - printf(fmt0); - for (i = 0; i < 4; i++) - if (part[i].dp_typ) { - printf(fmt1, - 1 + i, - part[i].dp_flag, - part[i].dp_scyl + ((part[i].dp_ssect & 0xc0) << 2), - part[i].dp_shd, - part[i].dp_ssect & 0x3f, - part[i].dp_typ, - part[i].dp_ecyl + ((part[i].dp_esect & 0xc0) << 2), - part[i].dp_ehd, - part[i].dp_esect & 0x3f, - part[i].dp_start, - part[i].dp_size); - } - printf("\n"); - version = boot0version(boot0); - printf("version=%d.%d drive=0x%x mask=0x%x ticks=%u\noptions=", - version >> 8, version & 0xff, boot0[OFF_DRIVE], - boot0[OFF_FLAGS] & 0xf, cv2(boot0 + OFF_TICKS)); - for (i = 0; i < nopt; i++) { - if (i) - printf(","); - if (!(boot0[OFF_FLAGS] & 1 << (7 - i)) ^ opttbl[i].def) - printf("no"); - printf("%s", opttbl[i].tok); - } - printf("\n"); - } + + /* write the MBR back to disk */ + if (up) + write_mbr(disk, 0, boot0, boot0_size); + + /* display the MBR */ + if (v_flag) + display_mbr(boot0); + + /* clean up */ + if (mbr != boot0) + free(boot0); + free(mbr); + return 0; } +/* + * Read in the MBR of the disk. If it is boot0, then use the version to + * read in all of it if necessary. Use pointers to return a malloc'd + * buffer containing the MBR and then return its size. + */ +static int +read_mbr(const char *disk, u_int8_t **mbr, int check_version) +{ + u_int8_t buf[MBRSIZE]; + int mbr_size, fd; + ssize_t n; + + if ((fd = open(disk, O_RDONLY)) == -1) + err(1, "%s", disk); + if ((n = read(fd, buf, MBRSIZE)) == -1) + err(1, "%s", disk); + if (n != MBRSIZE) + errx(1, "%s: short read", disk); + if (cv2(buf + OFF_MAGIC) != 0xaa55) + errx(1, "%s: bad magic", disk); + + if (!boot0bs(buf)) { + if (check_version) + errx(1, "%s: unknown or incompatible boot code", disk); + } else if (boot0version(buf) == 0x101) { + mbr_size = 1024; + if ((*mbr = malloc(mbr_size)) == NULL) + errx(1, "%s: unable to allocate read buffer", disk); + if (lseek(fd, 0, SEEK_SET) == -1 || + (n = read(fd, *mbr, mbr_size)) == -1) + err(1, "%s", disk); + if (n != mbr_size) + errx(1, "%s: short read", disk); + return (mbr_size); + } + *mbr = malloc(sizeof(buf)); + memcpy(*mbr, buf, sizeof(buf)); + + return sizeof(buf); +} + +/* + * Write out the mbr to the specified file. + */ +static void +write_mbr(const char *fname, int flags, u_int8_t *mbr, int mbr_size) +{ + int fd; + ssize_t n; + + if ((fd = open(fname, O_WRONLY | flags, 0666)) == -1 || + (n = write(fd, mbr, mbr_size)) == -1 || close(fd)) + err(1, "%s", fname); + if (n != mbr_size) + errx(1, "%s: short write", fname); +} + +/* + * Outputs an informative dump of the data in the MBR to stdout. + */ +static void +display_mbr(u_int8_t *mbr) +{ + struct dos_partition *part; + int i, version; + + part = (struct dos_partition *)(mbr + DOSPARTOFF); + printf(fmt0); + for (i = 0; i < NDOSPART; i++) + if (part[i].dp_typ) + printf(fmt1, 1 + i, part[i].dp_flag, + part[i].dp_scyl + ((part[i].dp_ssect & 0xc0) << 2), + part[i].dp_shd, part[i].dp_ssect & 0x3f, part[i].dp_typ, + part[i].dp_ecyl + ((part[i].dp_esect & 0xc0) << 2), + part[i].dp_ehd, part[i].dp_esect & 0x3f, part[i].dp_start, + part[i].dp_size); + printf("\n"); + version = boot0version(mbr); + printf("version=%d.%d drive=0x%x mask=0x%x ticks=%u\noptions=", + version >> 8, version & 0xff, mbr[OFF_DRIVE], + mbr[OFF_FLAGS] & 0xf, cv2(mbr + OFF_TICKS)); + for (i = 0; i < nopt; i++) { + if (i) + printf(","); + if (!(mbr[OFF_FLAGS] & 1 << (7 - i)) ^ opttbl[i].def) + printf("no"); + printf("%s", opttbl[i].tok); + } + printf("\n"); +} + /* * Return the boot0 version with the minor revision in the low byte, and * the major revision in the next higher byte. @@ -265,10 +325,8 @@ boot0bs(const u_int8_t *bs) int i; for (i = 0; i < sizeof(ident) / sizeof(ident[0]); i++) - if (memcmp(bs + ident[i].off, ident[i].key, ident[i].len)) { - printf("bah, failed id%d\n", i); + if (memcmp(bs + ident[i].off, ident[i].key, ident[i].len)) return 0; - } return 1; }; @@ -310,14 +368,11 @@ static char * mkrdev(const char *fname) { char buf[MAXPATHLEN]; - struct stat sb; char *s; s = (char *)fname; if (!strchr(fname, '/')) { - snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname); - if (stat(buf, &sb)) - snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); + snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); if (!(s = strdup(buf))) err(1, NULL); }