diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2013-10-01 20:32:31 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2013-10-01 20:32:31 +0000 |
commit | be79627b74c57d7e684667b5f79e3a1e0c70a899 (patch) | |
tree | 88b5f89beb8e3f07c87ac3fac93d1568179f660b /sys/arch/aviion | |
parent | 89792c68f54e47e46ddaa2996cfe21fa597cb763 (diff) |
Add the simple vdm/vdit dumper I wrote 3 years ago. Turn it into something
a bit worthwhile (yet crude), and give it the ability to initialize the boot
area, instead of having installboot do it - we will need the boot area set up
before attempting to invoke disklabel on the root disk.
Diffstat (limited to 'sys/arch/aviion')
-rw-r--r-- | sys/arch/aviion/stand/Makefile | 4 | ||||
-rw-r--r-- | sys/arch/aviion/stand/installboot/installboot.c | 46 | ||||
-rw-r--r-- | sys/arch/aviion/stand/vdmtool/Makefile | 16 | ||||
-rw-r--r-- | sys/arch/aviion/stand/vdmtool/vdmtool.8 | 51 | ||||
-rw-r--r-- | sys/arch/aviion/stand/vdmtool/vdmtool.c | 641 |
5 files changed, 712 insertions, 46 deletions
diff --git a/sys/arch/aviion/stand/Makefile b/sys/arch/aviion/stand/Makefile index 2fc4fcacf31..f0aff770184 100644 --- a/sys/arch/aviion/stand/Makefile +++ b/sys/arch/aviion/stand/Makefile @@ -1,6 +1,6 @@ -# $OpenBSD: Makefile,v 1.4 2013/09/29 17:51:34 miod Exp $ +# $OpenBSD: Makefile,v 1.5 2013/10/01 20:32:29 miod Exp $ -SUBDIR= a2coff installboot +SUBDIR= a2coff installboot vdmtool .if ${MACHINE} == "aviion" SUBDIR+= libprom libsa libz diff --git a/sys/arch/aviion/stand/installboot/installboot.c b/sys/arch/aviion/stand/installboot/installboot.c index 2b165150a7e..a6fba2d789f 100644 --- a/sys/arch/aviion/stand/installboot/installboot.c +++ b/sys/arch/aviion/stand/installboot/installboot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: installboot.c,v 1.2 2013/09/29 21:30:49 jmc Exp $ */ +/* $OpenBSD: installboot.c,v 1.3 2013/10/01 20:32:30 miod Exp $ */ /* * Copyright (c) 2013 Miodrag Vallat. @@ -31,7 +31,6 @@ char *boot, *dev; void analyze_label_sector(uint8_t *, struct vdm_label **, struct vdm_boot_info **); -void initialize_boot_area(int); void read_sector(int, uint32_t, void *); void usage(void); void write_sector(int, uint32_t, void *); @@ -90,32 +89,17 @@ main(int argc, char *argv[]) /* * Figure out the boot area span. - * If there is no VDM boot area, set up one. */ read_sector(devfd, VDM_LABEL_SECTOR, buf); analyze_label_sector(buf, &dl, &bi); - if (bi == NULL) { - if (verbose) - printf("no boot area found\n"); - if (nowrite) - return 0; - if (verbose) - printf("creating boot area\n"); - initialize_boot_area(devfd); - - read_sector(devfd, VDM_LABEL_SECTOR, buf); - analyze_label_sector(buf, &dl, &bi); - } - if (bi != NULL) { if (verbose) printf("boot area: sectors %u-%u\n", bi->boot_start, bi->boot_start + bi->boot_size - 1); } else { - /* should not happen */ - return 1; + errx(1, "no boot area found on %s", dev); } /* @@ -196,29 +180,3 @@ analyze_label_sector(uint8_t *sector, struct vdm_label **dl, *dl = l; *dbi = bi; } - -/* - * Build a minimal VDM label and boot area. - * Allows you to shoot yourself in the foot, badly. - */ -void -initialize_boot_area(int fd) -{ - struct vdm_label dl; - struct vdm_boot_info bi; - - memset(buf, 0, sizeof buf); - memset(&dl, 0, sizeof dl); - memset(&bi, 0, sizeof bi); - - dl.signature = htobe32(VDM_LABEL_SIGNATURE); - bi.signature = htobe32(VDM_LABEL_SIGNATURE); - bi.boot_start = htobe32(LABELSECTOR + 1); - bi.boot_size = htobe32(VDM_BOOT_DEFAULT_SIZE); - bi.version = htobe32(VDM_BOOT_INFO_VERSION); - - memcpy(buf + VDM_LABEL_OFFSET_ALT, &dl, sizeof dl); - memcpy(buf + VDM_BLOCK_SIZE - sizeof bi, &bi, sizeof bi); - - write_sector(fd, VDM_LABEL_SECTOR, buf); -} diff --git a/sys/arch/aviion/stand/vdmtool/Makefile b/sys/arch/aviion/stand/vdmtool/Makefile new file mode 100644 index 00000000000..38a67c43af8 --- /dev/null +++ b/sys/arch/aviion/stand/vdmtool/Makefile @@ -0,0 +1,16 @@ +# $OpenBSD: Makefile,v 1.1 2013/10/01 20:32:30 miod Exp $ + +MAN= vdmtool.8 +MANSUBDIR= aviion + +.if ${MACHINE} == "aviion" +PROG= vdmtool +BINDIR= /usr/mdec +DPADD= ${LIBUTIL} +LDADD= -lutil +LDSTATIC= -static +.else +NOPROG= +.endif + +.include <bsd.prog.mk> diff --git a/sys/arch/aviion/stand/vdmtool/vdmtool.8 b/sys/arch/aviion/stand/vdmtool/vdmtool.8 new file mode 100644 index 00000000000..d7ba7c0b905 --- /dev/null +++ b/sys/arch/aviion/stand/vdmtool/vdmtool.8 @@ -0,0 +1,51 @@ +.\" $OpenBSD: vdmtool.8,v 1.1 2013/10/01 20:32:30 miod Exp $ +.\" +.\" Copyright (c) 2013 Miodrag Vallat. +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: October 1 2013 $ +.Dt VDMTOOL 8 aviion +.Os +.Sh NAME +.Nm vdmtool +.Nd display or initialize DG/UX disk volume information +.Sh SYNOPSIS +.Nm vdmtool +.Op Fl iv +.Ar rawdev +.Sh DESCRIPTION +.Nm vdmtool +displays +.\" rather crude +information about the DG/UX volume information found on a disk. +It may also be used to setup a "boot area" on a new disk, to turn it into +a bootable device. +.Pp +The options are as follows: +.Bl -tag -width rawdev +.It Fl i +Do not display volume information, but initialize a "boot area" instead. +This will overwrite the first sector of the disk with a valid boot area +descriptor, which declares the first 251KB of the disk as a boot area. +.It Fl v +Be more verbose, printing out VDIT sector information, as well as any +unparsed byte in the VDIT structures. +.It Ar rawdev +The name of the raw disk device to operate upon. +It may be abbreviated into a form recognizable by +.Xr opendev 3 . +.El +.Sh SEE ALSO +.Xr disklabel 8 , +.Xr installboot 8 diff --git a/sys/arch/aviion/stand/vdmtool/vdmtool.c b/sys/arch/aviion/stand/vdmtool/vdmtool.c new file mode 100644 index 00000000000..899a8c76454 --- /dev/null +++ b/sys/arch/aviion/stand/vdmtool/vdmtool.c @@ -0,0 +1,641 @@ +/* $OpenBSD: vdmtool.c,v 1.1 2013/10/01 20:32:30 miod Exp $ */ + +/* + * Copyright (c) 2013 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <unistd.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <util.h> +#include <sys/disklabel.h> + +void initialize(int); +void report(int); +void usage(void); + +int verbose; + +#define VDM_BLOCK_SIZE 0x200 + +void +usage() +{ + fprintf(stderr, "usage: vdmtool [-i] [-v] <device>\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int c; + int fd; + int iflag = 0; + int exitcode = 0; + char *realpath; + + while ((c = getopt(argc, argv, "iqv")) != -1) { + switch (c) { + case 'i': + iflag = 1; + break; + case 'v': + verbose = 1; + break; + default: + usage(); + } + } + + if (argc - optind != 1) + usage(); + + fd = opendev(argv[optind], iflag ? O_RDWR : O_RDONLY, OPENDEV_PART, + &realpath); + if (fd < 0) + err(1, "open(%s)", realpath); + + if (iflag) + initialize(fd); + else + report(fd); + + close(fd); + exit(exitcode); +} + +void +read_sector(int fd, uint32_t secno, void *buf) +{ + if (lseek(fd, (off_t)secno * VDM_BLOCK_SIZE, SEEK_SET) == -1) + err(1, "lseek"); + + if (read(fd, buf, VDM_BLOCK_SIZE) != VDM_BLOCK_SIZE) + err(1, "read(%d,%08x)", fd, secno); +} + +void +write_sector(int fd, uint32_t secno, void *buf) +{ + if (lseek(fd, (off_t)secno * VDM_BLOCK_SIZE, SEEK_SET) == -1) + err(1, "lseek"); + + if (write(fd, buf, VDM_BLOCK_SIZE) != VDM_BLOCK_SIZE) + err(1, "write(%d,%08x)", fd, secno); +} + +void +analyze_label_sector(uint8_t *sector, struct vdm_label **dl, + struct vdm_boot_info **dbi) +{ + struct vdm_label *l; + struct vdm_boot_info *bi; + + l = (struct vdm_label *)(sector + VDM_LABEL_OFFSET); + if (betoh32(l->signature) != VDM_LABEL_SIGNATURE) { + l = (struct vdm_label *)(sector + VDM_LABEL_OFFSET_ALT); + if (betoh32(l->signature) != VDM_LABEL_SIGNATURE) + l = NULL; + } + + if (l != NULL) { + bi = (struct vdm_boot_info *) + (sector + VDM_BLOCK_SIZE - sizeof *bi); + if (betoh32(bi->signature) != VDM_LABEL_SIGNATURE) + bi = NULL; + } else + bi = NULL; + + *dl = l; + *dbi = bi; +} + +uint32_t +get_vdit_size(int fd, uint32_t secno) +{ + uint8_t sector[VDM_BLOCK_SIZE]; + struct vdit_block_header *hdr; + uint32_t cursize = 0; + int kind = VDIT_BLOCK_HEAD_BE; + + for (;;) { + read_sector(fd, secno, sector); + hdr = (struct vdit_block_header *)sector; + if (VDM_ID_KIND(&hdr->id) != kind) { + printf("unexpected VDIT block kind " + "on sector %08x: %02x\n", + secno, VDM_ID_KIND(&hdr->id)); + return 0; + } + + if (verbose) + printf("sector %08x: vdit frag type %02x, length %04x, " + "next frag at %08x\n", + secno, VDM_ID_KIND(&hdr->id), + betoh16(hdr->chunksz), secno); + + cursize += betoh16(hdr->chunksz); + if (betoh32(hdr->nextblk) == VDM_NO_BLK_NUMBER) + break; + + secno = betoh32(hdr->nextblk); + kind = VDIT_PORTION_HEADER_BLOCK; + } + + return cursize; +} + +vdit_id_t subdriver_vdmphys_id; +vdit_id_t subdriver_vdmpart_id; +vdit_id_t subdriver_vdmaggr_id; +vdit_id_t subdriver_vdmremap_id; + +void +register_subdriver(uint8_t *buf) +{ + struct vdit_subdriver_entry entry; + vdit_id_t id, *regid; + + memcpy(&entry, buf, sizeof entry); + entry.version = betoh16(entry.version); + memcpy(&id, &entry.subdriver_id, sizeof id); + id = betoh32(id); + + if (strcmp(entry.name, VDM_SUBDRIVER_VDMPHYS) == 0) + regid = &subdriver_vdmphys_id; + else if (strcmp(entry.name, VDM_SUBDRIVER_VDMPART) == 0) + regid = &subdriver_vdmpart_id; + else if (strcmp(entry.name, VDM_SUBDRIVER_VDMAGGR) == 0) + regid = &subdriver_vdmaggr_id; + else if (strcmp(entry.name, VDM_SUBDRIVER_VDMREMAP) == 0) + regid = &subdriver_vdmremap_id; + else + regid = NULL; + + if (regid != NULL) { + if (*regid != 0) + printf("WARNING: subdriver \"%s\" overriden\n", + entry.name); + *regid = id; + } +} + +void +print_vdit_instance_id(struct vdit_instance_id *buf, const char *descr) +{ + struct vdit_instance_id instance; + + memcpy(&instance, buf, sizeof instance); + instance.generation_timestamp = betoh32(instance.generation_timestamp); + instance.system_id = betoh32(instance.system_id); + if (instance.generation_timestamp != 0 || instance.system_id != 0 || + verbose) + printf("%s id %08x:%08x", + descr, instance.generation_timestamp, instance.system_id); +} + +uint32_t +print_vdit_boot_info(uint8_t *buf, uint32_t size) +{ + struct vdit_boot_info_entry entry; + + if (size < sizeof entry) { + printf("\tTRUNCATED ENTRY (%02x bytes, expected %02zx)\n", + size, sizeof entry); + return 0; + } + + memcpy(&entry, buf, sizeof entry); + entry.version = betoh16(entry.version); + printf("\tboot info: version %02x", entry.version); + print_vdit_instance_id(&entry.default_swap, " default swap"); + print_vdit_instance_id(&entry.default_root, " default root"); + printf("\n"); + + return size - sizeof entry; +} + +uint32_t +print_vdit_subdriver_info(uint8_t *buf, uint32_t size) +{ + struct vdit_subdriver_entry entry; + vdit_id_t id; + + if (size < sizeof entry) { + printf("\tTRUNCATED ENTRY (%02x bytes, expected %02zx)\n", + size, sizeof entry); + return 0; + } + + memcpy(&entry, buf, sizeof entry); + entry.version = betoh16(entry.version); + printf("\tsubdriver: version %02x", entry.version); + memcpy(&id, &entry.subdriver_id, sizeof id); + id = betoh32(id); + printf(" id %08x name \"%s\"\n", id, entry.name); + + return size - sizeof entry; +} + +uint32_t +print_vdmphys_instance(uint8_t *buf, uint32_t size) +{ + struct vdit_vdmphys_instance entry; + + if (size < sizeof entry) { + printf("\tTRUNCATED ENTRY (%02x bytes, expected %02zx)\n", + size, sizeof entry); + return 0; + } + + memcpy(&entry, buf, sizeof entry); + entry.version = betoh16(entry.version); + entry.mode = betoh16(entry.mode); + printf("\tvdmphys: version %02x mode %02x\n", + entry.version, entry.mode); + + return size - sizeof entry; +} + +uint32_t +print_vdmpart_instance(uint8_t *buf, uint32_t size) +{ + struct vdit_vdmpart_instance entry; + + if (size < sizeof entry) { + printf("\tTRUNCATED ENTRY (%02x bytes, expected %02zx)\n", + size, sizeof entry); + return 0; + } + + memcpy(&entry, buf, sizeof entry); + entry.version = betoh16(entry.version); + entry.start_blkno = betoh32(entry.start_blkno); + entry.size = betoh32(entry.size); + printf("\tvdmpart: version %02x", entry.version); + print_vdit_instance_id(&entry.child_instance, " child"); + printf("\n"); + printf("\t\tstarting block %08x size %08x", + entry.start_blkno, entry.size); + print_vdit_instance_id(&entry.remap_instance, " remap"); + printf("\n"); + + return size - sizeof entry; +} + +uint32_t +print_vdmaggr_instance(uint8_t *buf, uint32_t size) +{ + struct vdit_vdmaggr_instance entry; + struct vdit_instance_id *aggr; + uint32_t aggrsize; + uint stripe; + + if (size < sizeof entry) { + printf("\tTRUNCATED ENTRY (%02x bytes, expected %02zx)\n", + size, sizeof entry); + return 0; + } + + memcpy(&entry, buf, sizeof entry); + entry.version = betoh16(entry.version); + entry.aggr_count = betoh16(entry.aggr_count); + entry.stripe_size = betoh32(entry.stripe_size); + printf("\tvdmaggr: version %02x count %02x stripe size %08x\n", + entry.version, entry.aggr_count, entry.stripe_size); + + aggrsize = entry.aggr_count * sizeof(struct vdit_instance_id) + + sizeof entry; + if (size < aggrsize) { + printf("\tTRUNCATED ENTRY (%02x bytes, expected %02x)\n", + size, aggrsize); + return 0; + } + + aggr = (struct vdit_instance_id *)(buf + sizeof entry); + for (stripe = 0; stripe < entry.aggr_count; stripe++) { + printf("\t\tstripe %u", stripe); + print_vdit_instance_id(aggr++, ""); + printf("\n"); + } + + return size - aggrsize; +} + +uint32_t +print_vdmremap_instance(uint8_t *buf, uint32_t size) +{ + struct vdit_vdmremap_instance entry; + + if (size < sizeof entry) { + printf("\tTRUNCATED ENTRY (%02x bytes, expected %02zx)\n", + size, sizeof entry); + return 0; + } + + memcpy(&entry, buf, sizeof entry); + entry.version = betoh16(entry.version); + printf("\tvdmremap: version %02x", entry.version); + print_vdit_instance_id(&entry.primary_remap_table, + " primary remap table"); + printf("\n"); + print_vdit_instance_id(&entry.secondary_remap_table, + "\t\tsecondary remap table"); + printf("\n"); + print_vdit_instance_id(&entry.remap_area, "\t\tremap area"); + printf("\n"); + + return size - sizeof entry; +} + +uint32_t +print_vdit_instance_info(uint8_t *buf, uint32_t size) +{ + struct vdit_instance_entry entry; + vdit_id_t id; + + if (size < sizeof entry) { + printf("\tTRUNCATED ENTRY (%02x bytes, expected %02zx)\n", + size, sizeof entry); + return 0; + } + + memcpy(&entry, buf, sizeof entry); + entry.version = betoh16(entry.version); + printf("\tinstance: version %02x name \"%s\"\n", + entry.version, entry.name); + memcpy(&id, &entry.subdriver_id, sizeof id); + id = betoh32(id); + printf("\t\tsubdriver id %08x", id); + print_vdit_instance_id(&entry.instance_id, ""); + printf(" export %d\n", entry.exported); + + if (id == subdriver_vdmphys_id) + return print_vdmphys_instance(buf, size); + if (id == subdriver_vdmpart_id) + return print_vdmpart_instance(buf, size); + if (id == subdriver_vdmaggr_id) + return print_vdmaggr_instance(buf, size); + if (id == subdriver_vdmremap_id) + return print_vdmremap_instance(buf, size); + + return size - sizeof entry; +} + +uint8_t * +print_vdit_entry(uint8_t *buf) +{ + struct vdit_entry_header hdr; + uint32_t remaining, cnt; + uint8_t *rembuf; + + memcpy(&hdr, buf, sizeof hdr); + hdr.type = betoh16(hdr.type); + hdr.size = betoh16(hdr.size); + + printf("vdit entry: type %02x size %02x\n", hdr.type, hdr.size); + if (hdr.type == VDIT_ENTRY_SENTINEL) + return NULL; + + remaining = hdr.size - sizeof hdr; + + switch (hdr.type) { + case VDIT_ENTRY_UNUSED: + remaining = 0; /* don't print anything */ + break; + case VDIT_ENTRY_BOOT_INFO: + remaining = print_vdit_boot_info(buf + sizeof hdr, remaining); + break; + case VDIT_ENTRY_SUBDRIVER_INFO: + register_subdriver(buf + sizeof hdr); + remaining = print_vdit_subdriver_info(buf + sizeof hdr, + remaining); + break; + case VDIT_ENTRY_INSTANCE: + remaining = print_vdit_instance_info(buf + sizeof hdr, + remaining); + break; + } + + if (remaining == 4) { + /* timestamp */ + remaining -= 4; + } + + if (remaining != 0 && verbose) { + printf("\t%02x bytes unparsed", remaining); + rembuf = buf + hdr.size - remaining; + cnt = 0; + while (remaining-- != 0) { + if (cnt % 16 == 0) + printf("\n "); + printf("%02x ", *rembuf++); + cnt++; + } + printf("\n"); + } + + return buf + hdr.size; +} + +uint8_t * +append_vdit_sector(uint32_t secno, uint8_t *buf, uint8_t *sector, int kind) +{ + struct vdit_block_header *hdr; + + hdr = (struct vdit_block_header *)sector; + if (VDM_ID_KIND(&hdr->id) != kind) { + printf("unexpected block kind on sector %08x: %02x\n", + secno, VDM_ID_KIND(&hdr->id)); + return NULL; + } + +#ifdef DEBUG + printf("sector %08x: vdit block %08x\n", + secno, VDM_ID_BLKNO(&hdr->id)); +#endif + + memcpy(buf, sector + sizeof *hdr, VDM_BLOCK_SIZE - (sizeof *hdr)); + return buf + VDM_BLOCK_SIZE - (sizeof *hdr); +} + +uint8_t * +append_vdit_portion(int fd, uint32_t secno, uint8_t *buf, uint8_t *sector, + int kind) +{ + struct vdit_block_header *hdr; + u_int chunksz; + + hdr = (struct vdit_block_header *)sector; + if (VDM_ID_KIND(&hdr->id) != kind) { + printf("unexpected block kind on sector %08x: %02x\n", + secno, VDM_ID_KIND(&hdr->id)); + return NULL; + } + + /* store first sector of the portion */ + chunksz = betoh16(hdr->chunksz); + buf = append_vdit_sector(secno, buf, sector, kind); + chunksz--; + secno++; + + /* do the others */ + while (chunksz-- != 0) { + read_sector(fd, secno, sector); + buf = append_vdit_sector(secno, buf, sector, VDIT_BLOCK); + if (buf == NULL) + return NULL; + secno++; + } + + return buf; +} + +uint8_t * +read_vdit(int fd, uint32_t secno, size_t *vditsize) +{ + uint8_t sector[VDM_BLOCK_SIZE]; + struct vdit_block_header hdr; + uint32_t vdit_size; + uint8_t *buf, *curbuf; + int first = 1; + + vdit_size = get_vdit_size(fd, secno); +#ifdef DEBUG + printf("vdit size: %02x sectors\n", vdit_size); +#endif + + buf = (uint8_t *)malloc(VDM_BLOCK_SIZE * vdit_size); + if (buf == NULL) + err(1, "malloc"); + memset(buf, 0, VDM_BLOCK_SIZE * vdit_size); + + curbuf = buf; + for (;;) { + /* read first sector of portion */ + read_sector(fd, secno, sector); + memcpy(&hdr, sector, sizeof hdr); + + curbuf = append_vdit_portion(fd, secno, curbuf, sector, + first ? VDIT_BLOCK_HEAD_BE : VDIT_PORTION_HEADER_BLOCK); + if (curbuf == NULL) { + free(buf); + return NULL; + } + first = 0; + + if (hdr.nextblk == VDM_NO_BLK_NUMBER) + break; + + secno = betoh32(hdr.nextblk); + } + + if (verbose) + printf("vdit final size: 0x%zx bytes\n", curbuf - buf); + + *vditsize = curbuf - buf; + return buf; +} + +void +report(int fd) +{ + uint8_t *vdit, *vdit2, *tmpvdit; + size_t vditsize, vditsize2; + struct vdm_label *dl; + struct vdm_boot_info *bi; + struct disklabel *lp; + uint8_t sector[VDM_BLOCK_SIZE]; + struct vdit_block_header *hdr; + + read_sector(fd, VDM_LABEL_SECTOR, sector); + analyze_label_sector(sector, &dl, &bi); + + if (dl == NULL) + return; + + printf("label version %04x\n", betoh16(dl->version)); + + if (bi != NULL) + printf("disk boot info: start %08x size %08x version %08x\n", + betoh32(bi->boot_start), + betoh32(bi->boot_size), betoh32(bi->version)); + + read_sector(fd, VDIT_SECTOR, sector); + hdr = (struct vdit_block_header *)sector; + if (VDM_ID_KIND(&hdr->id) != VDIT_BLOCK_HEAD_BE) { + lp = (struct disklabel *)(sector + LABELOFFSET); + if (lp->d_magic == DISKMAGIC && lp->d_magic2 == DISKMAGIC) { + if (verbose) + printf("no VDIT but a native OpenBSD label\n"); + return; + } + errx(3, "unexpected block kind on sector %08x: %02x", + 1, VDM_ID_KIND(&hdr->id)); + } + + vdit = read_vdit(fd, 1, &vditsize); + if (vdit != NULL) { + tmpvdit = vdit; + while (tmpvdit != NULL) + tmpvdit = print_vdit_entry(tmpvdit); + + vdit2 = read_vdit(fd, betoh32(hdr->secondary_vdit), &vditsize2); + if (vdit2 == NULL) + printf("can't read backup VDIT\n"); + else { + if (vditsize2 < vditsize) { + printf("WARNING: backup VDIT is smaller " + "than main VDIT!\n"); + vditsize = vditsize2; + } + if (memcmp(vdit, vdit2, vditsize) != 0) + printf("VDIT and backup VDIT differ!\n"); + free(vdit2); + } + + free(vdit); + } +} + +/* + * Build a minimal VDM label and boot area. + * Allows you to shoot yourself in the foot, badly. + */ +void +initialize(int fd) +{ + uint8_t sector[VDM_BLOCK_SIZE]; + struct vdm_label dl; + struct vdm_boot_info bi; + + memset(sector, 0, sizeof sector); + memset(&dl, 0, sizeof dl); + memset(&bi, 0, sizeof bi); + + dl.signature = htobe32(VDM_LABEL_SIGNATURE); + bi.signature = htobe32(VDM_LABEL_SIGNATURE); + bi.boot_start = htobe32(8); + bi.boot_size = htobe32(VDM_BOOT_DEFAULT_SIZE); + bi.version = htobe32(VDM_BOOT_INFO_VERSION); + + memcpy(sector + VDM_LABEL_OFFSET_ALT, &dl, sizeof dl); + memcpy(sector + VDM_BLOCK_SIZE - sizeof bi, &bi, sizeof bi); + + write_sector(fd, VDM_LABEL_SECTOR, sector); +} |