summaryrefslogtreecommitdiffstats
path: root/usr.sbin/boot0cfg/boot0cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/boot0cfg/boot0cfg.c')
-rw-r--r--usr.sbin/boot0cfg/boot0cfg.c221
1 files changed, 138 insertions, 83 deletions
diff --git a/usr.sbin/boot0cfg/boot0cfg.c b/usr.sbin/boot0cfg/boot0cfg.c
index 1da2692..7724436 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,47 +175,116 @@ 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);
+
+ /* 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);
}
- 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");
+ *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);
}
- return 0;
+ printf("\n");
}
/*
@@ -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);
}
OpenPOWER on IntegriCloud