summaryrefslogtreecommitdiffstats
path: root/lib/libdisk
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libdisk')
-rw-r--r--lib/libdisk/Makefile47
-rw-r--r--lib/libdisk/blocks.c50
-rw-r--r--lib/libdisk/change.c132
-rw-r--r--lib/libdisk/chunk.c595
-rw-r--r--lib/libdisk/create_chunk.c296
-rw-r--r--lib/libdisk/disk.c400
-rw-r--r--lib/libdisk/libdisk.3345
-rw-r--r--lib/libdisk/libdisk.h364
-rw-r--r--lib/libdisk/open_disk.c280
-rw-r--r--lib/libdisk/open_ia64_disk.c273
-rw-r--r--lib/libdisk/rules.c296
-rw-r--r--lib/libdisk/tst01.c323
-rw-r--r--lib/libdisk/write_amd64_disk.c204
-rw-r--r--lib/libdisk/write_arm_disk.c47
-rw-r--r--lib/libdisk/write_disk.c76
-rw-r--r--lib/libdisk/write_i386_disk.c204
-rw-r--r--lib/libdisk/write_ia64_disk.c423
-rw-r--r--lib/libdisk/write_pc98_disk.c179
-rw-r--r--lib/libdisk/write_powerpc_disk.c64
-rw-r--r--lib/libdisk/write_sparc64_disk.c106
20 files changed, 4704 insertions, 0 deletions
diff --git a/lib/libdisk/Makefile b/lib/libdisk/Makefile
new file mode 100644
index 0000000..763170d
--- /dev/null
+++ b/lib/libdisk/Makefile
@@ -0,0 +1,47 @@
+# $FreeBSD$
+
+.if ${MACHINE_ARCH} == "ia64"
+_open_disk= open_ia64_disk.c
+.else
+_change = change.c
+_open_disk= open_disk.c
+.endif
+
+LIB= disk
+SRCS= blocks.c ${_change} chunk.c create_chunk.c disk.c ${_open_disk} \
+ rules.c write_disk.c
+.if ${MACHINE} == "sun4v"
+SRCS+= write_sparc64_disk.c
+.else
+SRCS+= write_${MACHINE}_disk.c
+.endif
+
+INCS= libdisk.h
+
+WARNS?= 2
+
+CFLAGS+= -I${.CURDIR}/../../sys/geom
+
+.if ${MACHINE} == "pc98"
+CFLAGS+= -DPC98
+.endif
+
+CLEANFILES+= tmp.c tst01 tst01.o
+NO_PROFILE=
+NO_PIC=
+
+MAN= libdisk.3
+
+.include <bsd.lib.mk>
+
+tst01: tst01.o libdisk.a
+ cc ${CFLAGS} -static tst01.o -o tst01 libdisk.a
+
+ad0: all install tst01
+ ./tst01 ad0
+
+da0: all install tst01
+ ./tst01 da0
+
+da1: all install tst01
+ ./tst01 da1
diff --git a/lib/libdisk/blocks.c b/lib/libdisk/blocks.c
new file mode 100644
index 0000000..313c5cc
--- /dev/null
+++ b/lib/libdisk/blocks.c
@@ -0,0 +1,50 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libdisk.h"
+
+void *
+read_block(int fd, daddr_t block, u_long sector_size)
+{
+ void *foo;
+ int i;
+
+ foo = malloc(sector_size);
+ if (foo == NULL)
+ return (NULL);
+ if (-1 == lseek(fd, (off_t)block * sector_size, SEEK_SET)) {
+ free (foo);
+ return (NULL);
+ }
+ i = read(fd, foo, sector_size);
+ if ((int)sector_size != i) {
+ free (foo);
+ return (NULL);
+ }
+ return foo;
+}
+
+int
+write_block(int fd, daddr_t block, const void *foo, u_long sector_size)
+{
+ int i;
+
+ if (-1 == lseek(fd, (off_t)block * sector_size, SEEK_SET))
+ return (-1);
+ i = write(fd, foo, sector_size);
+ if ((int)sector_size != i)
+ return (-1);
+ return 0;
+}
diff --git a/lib/libdisk/change.c b/lib/libdisk/change.c
new file mode 100644
index 0000000..7b63561
--- /dev/null
+++ b/lib/libdisk/change.c
@@ -0,0 +1,132 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include "libdisk.h"
+
+void
+Set_Bios_Geom(struct disk *disk, u_long cyl, u_long hd, u_long sect)
+{
+
+ disk->bios_cyl = cyl;
+ disk->bios_hd = hd;
+ disk->bios_sect = sect;
+}
+
+void
+Sanitize_Bios_Geom(struct disk *disk)
+{
+ int sane;
+
+ sane = 1;
+
+#ifdef PC98
+ if (disk->bios_cyl >= 65536)
+#else
+ if (disk->bios_cyl > 1024)
+#endif
+ sane = 0;
+#ifdef PC98
+ if (disk->bios_hd >= 256)
+#else
+ if (disk->bios_hd > 16)
+#endif
+ sane = 0;
+#ifdef PC98
+ if (disk->bios_sect >= 256)
+#else
+ if (disk->bios_sect > 63)
+#endif
+ sane = 0;
+ if (disk->bios_cyl * disk->bios_hd * disk->bios_sect !=
+ disk->chunks->size)
+ sane = 0;
+ if (sane)
+ return;
+
+ /* First try something that IDE can handle */
+ disk->bios_sect = 63;
+ disk->bios_hd = 16;
+ disk->bios_cyl = disk->chunks->size /
+ (disk->bios_sect * disk->bios_hd);
+
+#ifdef PC98
+ if (disk->bios_cyl < 65536)
+#else
+ if (disk->bios_cyl < 1024)
+#endif
+ return;
+
+ /* Hmm, try harder... */
+ /* Assume standard SCSI parameter */
+#ifdef PC98
+ disk->bios_sect = 128;
+ disk->bios_hd = 8;
+#else
+ disk->bios_hd = 255;
+#endif
+ disk->bios_cyl = disk->chunks->size /
+ (disk->bios_sect * disk->bios_hd);
+
+#ifdef PC98
+ if (disk->bios_cyl < 65536)
+ return;
+
+ /* Assume UIDE-133/98-A Challenger BIOS 0.9821C parameter */
+ disk->bios_sect = 255;
+ disk->bios_hd = 16;
+ disk->bios_cyl = disk->chunks->size /
+ (disk->bios_sect * disk->bios_hd);
+
+ if (disk->bios_cyl < 65536)
+ return;
+
+ /* BIG-na-Drive? */
+ disk->bios_hd = 255;
+ disk->bios_cyl = disk->chunks->size /
+ (disk->bios_sect * disk->bios_hd);
+#endif
+}
+
+void
+All_FreeBSD(struct disk *d, int force_all)
+{
+ struct chunk *c;
+ int type;
+
+#ifdef PC98
+ type = 0xc494;
+#else
+ type = 0xa5;
+#endif
+
+again:
+ for (c = d->chunks->part; c; c = c->next)
+ if (c->type != unused) {
+ Delete_Chunk(d, c);
+ goto again;
+ }
+ c = d->chunks;
+ if (force_all) {
+ Sanitize_Bios_Geom(d);
+ Create_Chunk(d, c->offset, c->size, freebsd, type,
+ CHUNK_FORCE_ALL, "FreeBSD");
+ } else {
+ Create_Chunk(d, c->offset, c->size, freebsd, type, 0,
+ "FreeBSD");
+ }
+}
diff --git a/lib/libdisk/chunk.c b/lib/libdisk/chunk.c
new file mode 100644
index 0000000..fb43ef5
--- /dev/null
+++ b/lib/libdisk/chunk.c
@@ -0,0 +1,595 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <err.h>
+#include "libdisk.h"
+
+struct chunk *
+New_Chunk(void)
+{
+ struct chunk *c;
+
+ c = malloc(sizeof *c);
+ if (c != NULL)
+ memset(c, 0, sizeof *c);
+ return (c);
+}
+
+/* Is c2 completely inside c1 ? */
+
+static int
+Chunk_Inside(const struct chunk *c1, const struct chunk *c2)
+{
+ /* if c1 ends before c2 do */
+ if (c1->end < c2->end)
+ return 0;
+ /* if c1 starts after c2 do */
+ if (c1->offset > c2->offset)
+ return 0;
+ return 1;
+}
+
+static struct chunk *
+Find_Mother_Chunk(struct chunk *chunks, daddr_t offset, daddr_t end,
+ chunk_e type)
+{
+ struct chunk *c1, *c2, ct;
+
+ ct.offset = offset;
+ ct.end = end;
+ switch (type) {
+ case whole:
+ if (Chunk_Inside(chunks, &ct))
+ return chunks;
+ case extended:
+ for (c1 = chunks->part; c1; c1 = c1->next) {
+ if (c1->type != type)
+ continue;
+ if (Chunk_Inside(c1, &ct))
+ return c1;
+ }
+ return 0;
+ case freebsd:
+ for (c1 = chunks->part; c1; c1 = c1->next) {
+ if (c1->type == type)
+ if (Chunk_Inside(c1, &ct))
+ return c1;
+ if (c1->type != extended)
+ continue;
+ for (c2 = c1->part; c2; c2 = c2->next)
+ if (c2->type == type && Chunk_Inside(c2, &ct))
+ return c2;
+ }
+ return 0;
+#ifdef __powerpc__
+ case apple:
+ for (c1 = chunks->part; c1; c1 = c1->next) {
+ if (c1->type == type)
+ if (Chunk_Inside(c1, &ct))
+ return c1;
+ }
+ return 0;
+#endif
+ default:
+ warn("Unsupported mother type in Find_Mother_Chunk");
+ return 0;
+ }
+}
+
+void
+Free_Chunk(struct chunk *c1)
+{
+ if(c1 == NULL)
+ return;
+ if(c1->private_data && c1->private_free)
+ (*c1->private_free)(c1->private_data);
+ if(c1->part != NULL)
+ Free_Chunk(c1->part);
+ if(c1->next != NULL)
+ Free_Chunk(c1->next);
+ if (c1->name != NULL)
+ free(c1->name);
+ if (c1->sname != NULL)
+ free(c1->sname);
+ free(c1);
+}
+
+struct chunk *
+Clone_Chunk(const struct chunk *c1)
+{
+ struct chunk *c2;
+
+ if(!c1)
+ return NULL;
+ c2 = New_Chunk();
+ if (c2 == NULL)
+ return NULL;
+ *c2 = *c1;
+ if (c1->private_data && c1->private_clone)
+ c2->private_data = c2->private_clone(c2->private_data);
+ c2->name = strdup(c2->name);
+ if (c2->sname != NULL)
+ c2->sname = strdup(c2->sname);
+ c2->next = Clone_Chunk(c2->next);
+ c2->part = Clone_Chunk(c2->part);
+ return c2;
+}
+
+int
+Insert_Chunk(struct chunk *c2, daddr_t offset, daddr_t size, const char *name,
+ chunk_e type, int subtype, u_long flags, const char *sname)
+{
+ struct chunk *ct,*cs;
+
+ /* We will only insert into empty spaces */
+ if (c2->type != unused)
+ return __LINE__;
+
+ ct = New_Chunk();
+ if (ct == NULL)
+ return __LINE__;
+ ct->disk = c2->disk;
+ ct->offset = offset;
+ ct->size = size;
+ ct->end = offset + size - 1;
+ ct->type = type;
+ if (sname != NULL)
+ ct->sname = strdup(sname);
+ ct->name = strdup(name);
+ ct->subtype = subtype;
+ ct->flags = flags;
+
+ if (!Chunk_Inside(c2, ct)) {
+ Free_Chunk(ct);
+ return __LINE__;
+ }
+
+ if ((type == freebsd || type == extended || type == apple)) {
+ cs = New_Chunk();
+ if (cs == NULL)
+ return __LINE__;
+ cs->disk = c2->disk;
+ cs->offset = offset;
+ cs->size = size;
+ cs->end = offset + size - 1;
+ cs->type = unused;
+ if (sname != NULL)
+ cs->sname = strdup(sname);
+ cs->name = strdup("-");
+ ct->part = cs;
+ }
+
+ /* Make a new chunk for any trailing unused space */
+ if (c2->end > ct->end) {
+ cs = New_Chunk();
+ if (cs == NULL)
+ return __LINE__;
+ *cs = *c2;
+ cs->disk = c2->disk;
+ cs->offset = ct->end + 1;
+ cs->size = c2->end - ct->end;
+ if (c2->sname != NULL)
+ cs->sname = strdup(c2->sname);
+ if (c2->name)
+ cs->name = strdup(c2->name);
+ c2->next = cs;
+ c2->size -= c2->end - ct->end;
+ c2->end = ct->end;
+ }
+ /* If no leading unused space just occupy the old chunk */
+ if (c2->offset == ct->offset) {
+ c2->sname = ct->sname;
+ c2->name = ct->name;
+ c2->type = ct->type;
+ c2->part = ct->part;
+ c2->subtype = ct->subtype;
+ c2->flags = ct->flags;
+ ct->sname = NULL;
+ ct->name = NULL;
+ ct->part = 0;
+ Free_Chunk(ct);
+ return 0;
+ }
+ /* else insert new chunk and adjust old one */
+ c2->end = ct->offset - 1;
+ c2->size -= ct->size;
+ ct->next = c2->next;
+ c2->next = ct;
+ return 0;
+}
+
+int
+Add_Chunk(struct disk *d, daddr_t offset, daddr_t size, const char *name,
+ chunk_e type, int subtype, u_long flags, const char *sname)
+{
+ struct chunk *c1, *c2, ct;
+ daddr_t end = offset + size - 1;
+ ct.offset = offset;
+ ct.end = end;
+ ct.size = size;
+
+ if (type == whole) {
+ d->chunks = c1 = New_Chunk();
+ if (c1 == NULL)
+ return __LINE__;
+ c2 = c1->part = New_Chunk();
+ if (c2 == NULL)
+ return __LINE__;
+ c2->disk = c1->disk = d;
+ c2->offset = c1->offset = offset;
+ c2->size = c1->size = size;
+ c2->end = c1->end = end;
+ c1->sname = strdup(sname);
+ c2->sname = strdup("-");
+ c1->name = strdup(name);
+ c2->name = strdup("-");
+ c1->type = type;
+ c2->type = unused;
+ c1->flags = flags;
+ c1->subtype = subtype;
+ return 0;
+ }
+
+ c1 = 0;
+ /* PLATFORM POLICY BEGIN ------------------------------------- */
+ switch(platform) {
+ case p_i386:
+ case p_amd64:
+ switch (type) {
+ case fat:
+ case gpt:
+ case mbr:
+ case extended:
+ case freebsd:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd);
+ break;
+ default:
+ return(-1);
+ }
+ break;
+ case p_ia64:
+ switch (type) {
+ case freebsd:
+ subtype = 0xa5;
+ /* FALL THROUGH */
+ case fat:
+ case efi:
+ case mbr:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end,
+ freebsd);
+ if (!c1)
+ c1 = Find_Mother_Chunk(d->chunks, offset, end,
+ whole);
+ break;
+ default:
+ return (-1);
+ }
+ break;
+ case p_pc98:
+ switch (type) {
+ case fat:
+ case pc98:
+ case freebsd:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd);
+ break;
+ default:
+ return(-1);
+ }
+ break;
+ case p_sparc64:
+ case p_alpha:
+ switch (type) {
+ case freebsd:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, freebsd);
+ break;
+ default:
+ return(-1);
+ }
+ break;
+ case p_ppc:
+ switch (type) {
+ case apple:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, offset, end, apple);
+ break;
+ default:
+ return (-1);
+ }
+ break;
+ default:
+ return (-1);
+ }
+ /* PLATFORM POLICY END ---------------------------------------- */
+
+ if(!c1)
+ return __LINE__;
+ for(c2 = c1->part; c2; c2 = c2->next) {
+ if (c2->type != unused)
+ continue;
+ if(!Chunk_Inside(c2, &ct))
+ continue;
+/* PLATFORM POLICY BEGIN ------------------------------------- */
+ if (platform == p_sparc64) {
+ offset = Prev_Cyl_Aligned(d, offset);
+ size = Next_Cyl_Aligned(d, size);
+ } else if (platform == p_i386 || platform == p_pc98 ||
+ platform == p_amd64) {
+ if (type != freebsd)
+ break;
+ if (!(flags & CHUNK_ALIGN))
+ break;
+ if (offset == d->chunks->offset &&
+ end == d->chunks->end)
+ break;
+
+ /* Round down to prev cylinder */
+ offset = Prev_Cyl_Aligned(d,offset);
+ /* Stay inside the parent */
+ if (offset < c2->offset)
+ offset = c2->offset;
+ /* Round up to next cylinder */
+ offset = Next_Cyl_Aligned(d, offset);
+ /* Keep one track clear in front of parent */
+ if (offset == c1->offset)
+ offset = Next_Track_Aligned(d, offset + 1);
+ /* Work on the (end+1) */
+ size += offset;
+ /* Round up to cylinder */
+ size = Next_Cyl_Aligned(d, size);
+ /* Stay inside parent */
+ if ((size-1) > c2->end)
+ size = c2->end + 1;
+ /* Round down to cylinder */
+ size = Prev_Cyl_Aligned(d, size);
+
+ /* Convert back to size */
+ size -= offset;
+ }
+ break;
+
+/* PLATFORM POLICY END ------------------------------------- */
+ }
+ if (c2 == NULL)
+ return (__LINE__);
+ return Insert_Chunk(c2, offset, size, name, type, subtype, flags,
+ sname);
+}
+
+char *
+ShowChunkFlags(struct chunk *c)
+{
+ static char ret[10];
+ int i = 0;
+
+ if (c->flags & CHUNK_ACTIVE)
+ ret[i++] = 'A';
+ if (c->flags & CHUNK_ALIGN)
+ ret[i++] = '=';
+ if (c->flags & CHUNK_IS_ROOT)
+ ret[i++] = 'R';
+ ret[i++] = '\0';
+
+ return ret;
+}
+
+static void
+Print_Chunk(struct chunk *c1, int offset)
+{
+ int i;
+
+ if (!c1)
+ return;
+ for (i = 0; i < offset - 2; i++)
+ putchar(' ');
+ for (; i < offset; i++)
+ putchar('-');
+ putchar('>');
+ for (; i < 10; i++)
+ putchar(' ');
+#ifndef __ia64__
+ printf("%p ", c1);
+#endif
+ printf("%8jd %8jd %8jd %-8s %-16s %-8s 0x%02x %s",
+ (intmax_t)c1->offset, (intmax_t)c1->size, (intmax_t)c1->end,
+ c1->name, c1->sname, chunk_name(c1->type), c1->subtype,
+ ShowChunkFlags(c1));
+ putchar('\n');
+ Print_Chunk(c1->part, offset + 2);
+ Print_Chunk(c1->next, offset);
+}
+
+void
+Debug_Chunk(struct chunk *c1)
+{
+
+ Print_Chunk(c1, 2);
+}
+
+int
+Delete_Chunk(struct disk *d, struct chunk *c)
+{
+
+ return (Delete_Chunk2(d, c, 0));
+}
+
+int
+Delete_Chunk2(struct disk *d, struct chunk *c, int rflags)
+{
+ struct chunk *c1, *c2, *c3;
+ daddr_t offset = c->offset;
+
+ switch (c->type) {
+ case whole:
+ case unused:
+ return 1;
+ case extended:
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, whole);
+ break;
+ case part:
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, freebsd);
+#ifdef __ia64__
+ if (c1 == NULL)
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end,
+ whole);
+#endif
+#ifdef __powerpc__
+ if (c1 == NULL)
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end,
+ apple);
+#endif
+ break;
+ default:
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end, extended);
+ if (c1 == NULL)
+ c1 = Find_Mother_Chunk(d->chunks, c->offset, c->end,
+ whole);
+ break;
+ }
+ if (c1 == NULL)
+ return 1;
+ for (c2 = c1->part; c2; c2 = c2->next) {
+ if (c2 == c) {
+ c2->type = unused;
+ c2->subtype = 0;
+ c2->flags = 0;
+ if (c2->sname != NULL)
+ free(c2->sname);
+ c2->sname = strdup("-");
+ free(c2->name);
+ c2->name = strdup("-");
+ Free_Chunk(c2->part);
+ c2->part =0;
+ goto scan;
+ }
+ }
+ return 1;
+scan:
+ /*
+ * Collapse multiple unused elements together, and attempt
+ * to extend the previous chunk into the freed chunk.
+ *
+ * We only extend non-unused elements which are marked
+ * for newfs (we can't extend working filesystems), and
+ * only if we are called with DELCHUNK_RECOVER.
+ */
+ for (c2 = c1->part; c2; c2 = c2->next) {
+ if (c2->type != unused) {
+ if (c2->offset + c2->size != offset ||
+ (rflags & DELCHUNK_RECOVER) == 0 ||
+ (c2->flags & CHUNK_NEWFS) == 0) {
+ continue;
+ }
+ /* else extend into free area */
+ }
+ if (!c2->next)
+ continue;
+ if (c2->next->type != unused)
+ continue;
+ c3 = c2->next;
+ c2->size += c3->size;
+ c2->end = c3->end;
+ c2->next = c3->next;
+ c3->next = 0;
+ Free_Chunk(c3);
+ goto scan;
+ }
+ Fixup_Names(d);
+ return 0;
+}
+
+#if 0
+int
+Collapse_Chunk(struct disk *d, struct chunk *c1)
+{
+ struct chunk *c2, *c3;
+
+ if (c1->next && Collapse_Chunk(d, c1->next))
+ return 1;
+
+ if (c1->type == unused && c1->next && c1->next->type == unused) {
+ c3 = c1->next;
+ c1->size += c3->size;
+ c1->end = c3->end;
+ c1->next = c3->next;
+ c3->next = 0;
+ Free_Chunk(c3);
+ return 1;
+ }
+ c3 = c1->part;
+ if (!c3)
+ return 0;
+ if (Collapse_Chunk(d, c1->part))
+ return 1;
+
+ if (c1->type == whole)
+ return 0;
+
+ if (c3->type == unused && c3->size == c1->size) {
+ Delete_Chunk(d, c1);
+ return 1;
+ }
+ if (c3->type == unused) {
+ c2 = New_Chunk();
+ if (c2 == NULL)
+ barfout(1, "malloc failed");
+ *c2 = *c1;
+ c1->next = c2;
+ c1->disk = d;
+ c1->sname = strdup("-");
+ c1->name = strdup("-");
+ c1->part = 0;
+ c1->type = unused;
+ c1->flags = 0;
+ c1->subtype = 0;
+ c1->size = c3->size;
+ c1->end = c3->end;
+ c2->offset += c1->size;
+ c2->size -= c1->size;
+ c2->part = c3->next;
+ c3->next = 0;
+ Free_Chunk(c3);
+ return 1;
+ }
+ for (c2 = c3; c2->next; c2 = c2->next)
+ c3 = c2;
+ if (c2 && c2->type == unused) {
+ c3->next = 0;
+ c2->next = c1->next;
+ c1->next = c2;
+ c1->size -= c2->size;
+ c1->end -= c2->size;
+ return 1;
+ }
+
+ return 0;
+}
+#endif
diff --git a/lib/libdisk/create_chunk.c b/lib/libdisk/create_chunk.c
new file mode 100644
index 0000000..7f1453e
--- /dev/null
+++ b/lib/libdisk/create_chunk.c
@@ -0,0 +1,296 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <sys/param.h>
+#include <sys/disklabel.h>
+#ifdef PC98
+#include <sys/diskpc98.h>
+#else
+#include <sys/diskmbr.h>
+#endif
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include "libdisk.h"
+
+static int
+Fixup_FreeBSD_Names(struct chunk *c)
+{
+ struct chunk *c1, *c3;
+ uint j;
+
+ if (!strcmp(c->name, "X"))
+ return 0;
+
+ /* reset all names to "X" */
+ for (c1 = c->part; c1; c1 = c1->next) {
+ c1->oname = c1->name;
+ c1->name = malloc(12);
+ if (!c1->name)
+ return -1;
+ strcpy(c1->name,"X");
+ }
+
+ /* Allocate the first swap-partition we find */
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ if (c1->subtype != FS_SWAP)
+ continue;
+ sprintf(c1->name, "%s%c", c->name, SWAP_PART + 'a');
+ break;
+ }
+
+ /* Allocate the first root-partition we find */
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ if (!(c1->flags & CHUNK_IS_ROOT))
+ continue;
+ sprintf(c1->name, "%s%c", c->name, 0 + 'a');
+ break;
+ }
+
+ /* Try to give them the same as they had before */
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (strcmp(c1->name, "X"))
+ continue;
+ for (c3 = c->part; c3 ; c3 = c3->next)
+ if (c1 != c3 && !strcmp(c3->name, c1->oname))
+ goto newname;
+ strcpy(c1->name, c1->oname);
+ newname:
+ ;
+ }
+
+ /* Allocate the rest sequentially */
+ for (c1 = c->part; c1; c1 = c1->next) {
+ const char order[] = "defghab";
+
+ if (c1->type == unused)
+ continue;
+ if (strcmp("X", c1->name))
+ continue;
+
+ for (j = 0; j < strlen(order); j++) {
+ sprintf(c1->name, "%s%c", c->name, order[j]);
+ for (c3 = c->part; c3 ; c3 = c3->next)
+ if (c1 != c3 && !strcmp(c3->name, c1->name))
+ goto match;
+ break;
+ match:
+ strcpy(c1->name, "X");
+ continue;
+ }
+ }
+ for (c1 = c->part; c1; c1 = c1->next) {
+ free(c1->oname);
+ c1->oname = 0;
+ }
+ return 0;
+}
+
+#ifndef PC98
+static int
+Fixup_Extended_Names(struct chunk *c)
+{
+ struct chunk *c1;
+ int j = 5;
+
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ free(c1->name);
+ c1->name = malloc(12);
+ if (!c1->name)
+ return -1;
+ sprintf(c1->name, "%ss%d", c->disk->chunks->name, j++);
+ if (c1->type == freebsd)
+ if (Fixup_FreeBSD_Names(c1) != 0)
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+#ifdef __powerpc__
+static int
+Fixup_Apple_Names(struct chunk *c)
+{
+ struct chunk *c1;
+
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ free(c1->name);
+ c1->name = strdup(c->name);
+ if (!c1->name)
+ return (-1);
+ }
+ return 0;
+}
+#endif
+
+int
+Fixup_Names(struct disk *d)
+{
+ struct chunk *c1, *c2;
+#if defined(__i386__) || defined(__ia64__) || defined(__amd64__)
+ struct chunk *c3;
+ int j, max;
+#endif
+
+ c1 = d->chunks;
+ for (c2 = c1->part; c2 ; c2 = c2->next) {
+ if (c2->type == unused)
+ continue;
+ if (strcmp(c2->name, "X"))
+ continue;
+#if defined(__i386__) || defined(__ia64__) || defined(__amd64__)
+ c2->oname = malloc(12);
+ if (!c2->oname)
+ return -1;
+#ifdef __ia64__
+ max = d->gpt_size;
+#else
+ max = NDOSPART;
+#endif
+ for (j = 1; j <= max; j++) {
+#ifdef __ia64__
+ sprintf(c2->oname, "%s%c%d", c1->name,
+ (c1->type == whole) ? 'p' : 's', j);
+#else
+ sprintf(c2->oname, "%ss%d", c1->name, j);
+#endif
+ for (c3 = c1->part; c3; c3 = c3->next)
+ if (c3 != c2 && !strcmp(c3->name, c2->oname))
+ goto match;
+ free(c2->name);
+ c2->name = c2->oname;
+ c2->oname = 0;
+ break;
+ match:
+ continue;
+ }
+ if (c2->oname)
+ free(c2->oname);
+#else
+ free(c2->name);
+ c2->name = strdup(c1->name);
+#endif /*__i386__*/
+ }
+ for (c2 = c1->part; c2; c2 = c2->next) {
+ if (c2->type == freebsd)
+ Fixup_FreeBSD_Names(c2);
+#ifdef __powerpc__
+ else if (c2->type == apple)
+ Fixup_Apple_Names(c2);
+#endif
+#ifndef PC98
+ else if (c2->type == extended)
+ Fixup_Extended_Names(c2);
+#endif
+ }
+ return 0;
+}
+
+int
+Create_Chunk(struct disk *d, daddr_t offset, daddr_t size, chunk_e type,
+ int subtype, u_long flags, const char *sname)
+{
+ int i;
+
+#ifndef __ia64__
+ if (!(flags & CHUNK_FORCE_ALL)) {
+ daddr_t l;
+#ifdef PC98
+ /* Never use the first cylinder */
+ if (!offset) {
+ offset += (d->bios_sect * d->bios_hd);
+ size -= (d->bios_sect * d->bios_hd);
+ }
+#else
+ /* Never use the first track */
+ if (!offset) {
+ offset += d->bios_sect;
+ size -= d->bios_sect;
+ }
+#endif /* PC98 */
+
+ /* Always end on cylinder boundary */
+ l = (offset + size) % (d->bios_sect * d->bios_hd);
+ size -= l;
+ }
+#endif
+
+ i = Add_Chunk(d, offset, size, "X", type, subtype, flags, sname);
+ Fixup_Names(d);
+ return i;
+}
+
+struct chunk *
+Create_Chunk_DWIM(struct disk *d, struct chunk *parent, daddr_t size,
+ chunk_e type, int subtype, u_long flags)
+{
+ int i;
+ struct chunk *c1;
+ daddr_t offset;
+
+ if (!parent)
+ parent = d->chunks;
+
+ if ((parent->type == freebsd && type == part && parent->part == NULL)
+ || (parent->type == apple && type == part && parent->part == NULL)) {
+ c1 = New_Chunk();
+ if (c1 == NULL)
+ return (NULL);
+ c1->disk = parent->disk;
+ c1->offset = parent->offset;
+ c1->size = parent->size;
+ c1->end = parent->offset + parent->size - 1;
+ c1->type = unused;
+ if (parent->sname != NULL)
+ c1->sname = strdup(parent->sname);
+ c1->name = strdup("-");
+ parent->part = c1;
+ }
+
+ for (c1 = parent->part; c1; c1 = c1->next) {
+ if (c1->type != unused)
+ continue;
+ if (c1->size < size)
+ continue;
+ offset = c1->offset;
+ goto found;
+ }
+ return 0;
+found:
+ i = Add_Chunk(d, offset, size, "X", type, subtype, flags, "-");
+ if (i)
+ return 0;
+ Fixup_Names(d);
+ for (c1 = parent->part; c1; c1 = c1->next)
+ if (c1->offset == offset)
+ return c1;
+ /* barfout(1, "Serious internal trouble"); */
+ return 0;
+}
diff --git a/lib/libdisk/disk.c b/lib/libdisk/disk.c
new file mode 100644
index 0000000..68be4ee
--- /dev/null
+++ b/lib/libdisk/disk.c
@@ -0,0 +1,400 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <inttypes.h>
+#include <err.h>
+#include <sys/sysctl.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/uuid.h>
+#include <sys/gpt.h>
+#include <paths.h>
+#include "libdisk.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#include <uuid.h>
+
+const enum platform platform =
+#if defined (P_DEBUG)
+ P_DEBUG
+#elif defined (PC98)
+ p_pc98
+#elif defined(__i386__)
+ p_i386
+#elif defined(__alpha__)
+ p_alpha
+#elif defined(__sparc64__)
+ p_sparc64
+#elif defined(__ia64__)
+ p_ia64
+#elif defined(__ppc__)
+ p_ppc
+#elif defined(__amd64__)
+ p_amd64
+#elif defined(__arm__)
+ p_arm
+#else
+ IHAVENOIDEA
+#endif
+ ;
+
+const char *
+chunk_name(chunk_e type)
+{
+ switch(type) {
+ case unused: return ("unused");
+ case mbr: return ("mbr");
+ case part: return ("part");
+ case gpt: return ("gpt");
+ case pc98: return ("pc98");
+ case sun: return ("sun");
+ case freebsd: return ("freebsd");
+ case fat: return ("fat");
+ case spare: return ("spare");
+ case efi: return ("efi");
+ case apple: return ("apple");
+ default: return ("??");
+ }
+}
+
+struct disk *
+Open_Disk(const char *name)
+{
+ struct disk *d;
+ char *conftxt;
+ size_t txtsize;
+ int error;
+
+ error = sysctlbyname("kern.geom.conftxt", NULL, &txtsize, NULL, 0);
+ if (error) {
+ warn("kern.geom.conftxt sysctl not available, giving up!");
+ return (NULL);
+ }
+ conftxt = malloc(txtsize+1);
+ if (conftxt == NULL) {
+ warn("cannot malloc memory for conftxt");
+ return (NULL);
+ }
+ error = sysctlbyname("kern.geom.conftxt", conftxt, &txtsize, NULL, 0);
+ if (error) {
+ warn("error reading kern.geom.conftxt from the system");
+ free(conftxt);
+ return (NULL);
+ }
+ conftxt[txtsize] = '\0'; /* in case kernel bug is still there */
+ d = Int_Open_Disk(name, conftxt);
+ free(conftxt);
+
+ return (d);
+}
+
+void
+Debug_Disk(struct disk *d)
+{
+
+ printf("Debug_Disk(%s)", d->name);
+
+#ifndef __ia64__
+ printf(" bios_geom=%lu/%lu/%lu = %lu\n",
+ d->bios_cyl, d->bios_hd, d->bios_sect,
+ d->bios_cyl * d->bios_hd * d->bios_sect);
+#if defined(PC98)
+ printf(" boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n",
+ d->boot1, d->boot2, d->bootipl, d->bootmenu);
+#elif defined(__i386__) || defined(__amd64__)
+ printf(" boot1=%p, boot2=%p, bootmgr=%p\n",
+ d->boot1, d->boot2, d->bootmgr);
+#elif defined(__alpha__)
+ printf(" boot1=%p, bootmgr=%p\n",
+ d->boot1, d->bootmgr);
+#else
+/* Should be: error "Debug_Disk: unknown arch"; */
+#endif
+#else /* __ia64__ */
+ printf(" media size=%lu, sector size=%lu\n", d->media_size,
+ d->sector_size);
+#endif
+
+ Debug_Chunk(d->chunks);
+}
+
+void
+Free_Disk(struct disk *d)
+{
+ if (d->chunks)
+ Free_Chunk(d->chunks);
+ if (d->name)
+ free(d->name);
+#ifdef PC98
+ if (d->bootipl)
+ free(d->bootipl);
+ if (d->bootmenu)
+ free(d->bootmenu);
+#else
+#if !defined(__ia64__)
+ if (d->bootmgr)
+ free(d->bootmgr);
+#endif
+#endif
+#if !defined(__ia64__)
+ if (d->boot1)
+ free(d->boot1);
+#endif
+#if defined(__i386__) || defined(__amd64__)
+ if (d->boot2)
+ free(d->boot2);
+#endif
+ free(d);
+}
+
+#if 0
+void
+Collapse_Disk(struct disk *d)
+{
+
+ while (Collapse_Chunk(d, d->chunks))
+ ;
+}
+#endif
+
+static int
+qstrcmp(const void* a, const void* b)
+{
+ const char *str1 = *(char* const*)a;
+ const char *str2 = *(char* const*)b;
+
+ return strcmp(str1, str2);
+}
+
+char **
+Disk_Names()
+{
+ int disk_cnt;
+ static char **disks;
+ int error;
+ size_t listsize;
+ char *disklist;
+
+ error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
+ if (error) {
+ warn("kern.disks sysctl not available");
+ return NULL;
+ }
+
+ if (listsize == 0)
+ return (NULL);
+
+ disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
+ if (disks == NULL)
+ return NULL;
+ disklist = (char *)malloc(listsize + 1);
+ if (disklist == NULL) {
+ free(disks);
+ return NULL;
+ }
+ memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
+ memset(disklist, 0, listsize + 1);
+ error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
+ if (error || disklist[0] == 0) {
+ free(disklist);
+ free(disks);
+ return NULL;
+ }
+ for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) {
+ disks[disk_cnt] = strsep(&disklist, " ");
+ if (disks[disk_cnt] == NULL)
+ break;
+ }
+ qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
+ return disks;
+}
+
+#ifdef PC98
+void
+Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size,
+ const u_char *bootmenu, const size_t bootmenu_size)
+#else
+void
+Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
+#endif
+{
+#if !defined(__ia64__)
+#ifdef PC98
+ if (d->sector_size == 0)
+ return;
+ if (bootipl_size % d->sector_size != 0)
+ return;
+ if (d->bootipl)
+ free(d->bootipl);
+ if (!bootipl) {
+ d->bootipl = NULL;
+ } else {
+ d->bootipl_size = bootipl_size;
+ d->bootipl = malloc(bootipl_size);
+ if (!d->bootipl)
+ return;
+ memcpy(d->bootipl, bootipl, bootipl_size);
+ }
+
+ if (bootmenu_size % d->sector_size != 0)
+ return;
+ if (d->bootmenu)
+ free(d->bootmenu);
+ if (!bootmenu) {
+ d->bootmenu = NULL;
+ } else {
+ d->bootmenu_size = bootmenu_size;
+ d->bootmenu = malloc(bootmenu_size);
+ if (!d->bootmenu)
+ return;
+ memcpy(d->bootmenu, bootmenu, bootmenu_size);
+ }
+#else
+ if (d->sector_size == 0)
+ return;
+ if (s % d->sector_size != 0)
+ return;
+ if (d->bootmgr)
+ free(d->bootmgr);
+ if (!b) {
+ d->bootmgr = NULL;
+ } else {
+ d->bootmgr_size = s;
+ d->bootmgr = malloc(s);
+ if (!d->bootmgr)
+ return;
+ memcpy(d->bootmgr, b, s);
+ }
+#endif
+#endif
+}
+
+int
+Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
+{
+#if defined(__i386__) || defined(__amd64__)
+ if (d->boot1)
+ free(d->boot1);
+ d->boot1 = malloc(512);
+ if (!d->boot1)
+ return -1;
+ memcpy(d->boot1, b1, 512);
+ if (d->boot2)
+ free(d->boot2);
+ d->boot2 = malloc(15 * 512);
+ if (!d->boot2)
+ return -1;
+ memcpy(d->boot2, b2, 15 * 512);
+#elif defined(__alpha__)
+ if (d->boot1)
+ free(d->boot1);
+ d->boot1 = malloc(15 * 512);
+ if (!d->boot1)
+ return -1;
+ memcpy(d->boot1, b1, 15 * 512);
+#elif defined(__sparc64__)
+ if (d->boot1 != NULL)
+ free(d->boot1);
+ d->boot1 = malloc(16 * 512);
+ if (d->boot1 == NULL)
+ return (-1);
+ memcpy(d->boot1, b1, 16 * 512);
+#elif defined(__ia64__)
+ /* nothing */
+#else
+/* Should be: #error "Set_Boot_Blocks: unknown arch"; */
+#endif
+ return 0;
+}
+
+const char *
+slice_type_name( int type, int subtype )
+{
+
+ switch (type) {
+ case whole:
+ return "whole";
+ case mbr:
+ switch (subtype) {
+ case 1: return "fat (12-bit)";
+ case 2: return "XENIX /";
+ case 3: return "XENIX /usr";
+ case 4: return "fat (16-bit,<=32Mb)";
+ case 5: return "extended DOS";
+ case 6: return "fat (16-bit,>32Mb)";
+ case 7: return "NTFS/HPFS/QNX";
+ case 8: return "AIX bootable";
+ case 9: return "AIX data";
+ case 10: return "OS/2 bootmgr";
+ case 11: return "fat (32-bit)";
+ case 12: return "fat (32-bit,LBA)";
+ case 14: return "fat (16-bit,>32Mb,LBA)";
+ case 15: return "extended DOS, LBA";
+ case 18: return "Compaq Diagnostic";
+ case 57: return "Plan 9";
+ case 77: return "QNX 4.X";
+ case 78: return "QNX 4.X 2nd part";
+ case 79: return "QNX 4.X 3rd part";
+ case 84: return "OnTrack diskmgr";
+ case 100: return "Netware 2.x";
+ case 101: return "Netware 3.x";
+ case 115: return "SCO UnixWare";
+ case 128: return "Minix 1.1";
+ case 129: return "Minix 1.5";
+ case 130: return "linux_swap";
+ case 131: return "ext2fs";
+ case 133: return "linux extended";
+ case 166: return "OpenBSD FFS"; /* 0xA6 */
+ case 168: return "Mac OS-X";
+ case 169: return "NetBSD FFS"; /* 0xA9 */
+ case 171: return "Mac OS-X Boot";
+ case 182: return "OpenBSD"; /* dedicated */
+ case 183: return "bsd/os";
+ case 184: return "bsd/os swap";
+ case 191: return "Solaris (new)";
+ case 238: return "EFI GPT";
+ case 239: return "EFI Sys. Part.";
+ default: return "unknown";
+ }
+ case fat:
+ return "fat";
+ case freebsd:
+ switch (subtype) {
+#ifdef PC98
+ case 0xc494: return "freebsd";
+#else
+ case 165: return "freebsd";
+#endif
+ default: return "unknown";
+ }
+ case extended:
+ return "extended";
+ case part:
+ return "part";
+ case efi:
+ return "efi";
+ case unused:
+ return "unused";
+ default:
+ return "unknown";
+ }
+}
diff --git a/lib/libdisk/libdisk.3 b/lib/libdisk/libdisk.3
new file mode 100644
index 0000000..43e7ba1
--- /dev/null
+++ b/lib/libdisk/libdisk.3
@@ -0,0 +1,345 @@
+.\"
+.\" Copyright (c) 1996 Joerg Wunsch
+.\"
+.\" All rights reserved.
+.\"
+.\" This program is free software.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\" "
+.Dd January 30, 2006
+.Dt LIBDISK 3
+.Os
+.Sh NAME
+.Nm Open_Disk ,
+.Nm Free_Disk ,
+.Nm Debug_Disk ,
+.Nm Set_Bios_Geom ,
+.Nm Delete_Chunk ,
+.Nm Collapse_Disk ,
+.Nm Collapse_Chunk ,
+.Nm Create_Chunk ,
+.Nm All_FreeBSD ,
+.Nm CheckRules ,
+.Nm Disk_Names ,
+.Nm Set_Boot_Mgr ,
+.Nm Set_Boot_Blocks ,
+.Nm Write_Disk ,
+.Nm Cyl_Aligned ,
+.Nm Next_Cyl_Aligned ,
+.Nm Prev_Cyl_Aligned ,
+.Nm Track_Aligned ,
+.Nm Next_Track_Aligned ,
+.Nm Prev_Track_Aligned ,
+.Nm Create_Chunk_DWIM ,
+.Nm MakeDev ,
+.Nm MakeDevDisk ,
+.Nm ShowChunkFlags ,
+.Nm chunk_name ,
+.Nm slice_type_name
+.Nd library interface to slice and partition labels
+.Sh LIBRARY
+.Lb libdisk
+.Sh SYNOPSIS
+.In sys/types.h
+.In libdisk.h
+.Pp
+.Ft struct disk *
+.Fn Open_Disk "const char *devname"
+.Ft void
+.Fn Free_Disk "struct disk *disk"
+.Ft void
+.Fn Debug_Disk "struct disk *disk"
+.Ft void
+.Fn Set_Bios_Geom "struct disk *disk" "u_long cyl" "u_long heads" "u_long sects"
+.Ft int
+.Fn Delete_Chunk "struct disk *disk" "struct chunk *"
+.Ft void
+.Fn Collapse_Disk "struct disk *disk"
+.Ft int
+.Fn Collapse_Chunk "struct disk *disk" "struct chunk *chunk"
+.Ft int
+.Fn Create_Chunk "struct disk *disk" "daddr_t offset" "daddr_t size" "chunk_e type" "int subtype" "u_long flags" "const char *sname"
+.Ft void
+.Fn All_FreeBSD "struct disk *d" "int force_all"
+.Ft char *
+.Fn CheckRules "const struct disk *"
+.Ft char **
+.Fn Disk_Names "void"
+.Ft void
+.Fn Set_Boot_Mgr "struct disk *d" "const u_char *bootmgr" "const size_t bootmgr_size"
+.Ft int
+.Fn Set_Boot_Blocks "struct disk *d" "const u_char *boot1" "const u_char *boot2"
+.Ft int
+.Fn Write_Disk "const struct disk *d"
+.Ft int
+.Fn Cyl_Aligned "struct disk *d" "daddr_t offset"
+.Ft daddr_t
+.Fn Next_Cyl_Aligned "const struct disk *d" "daddr_t offset"
+.Ft daddr_t
+.Fn Prev_Cyl_Aligned "const struct disk *d" "daddr_t offset"
+.Ft int
+.Fn Track_Aligned "const struct disk *d" "daddr_t offset"
+.Ft daddr_t
+.Fn Next_Track_Aligned "const struct disk *d" "daddr_t offset"
+.Ft daddr_t
+.Fn Prev_Track_Aligned "const struct disk *d" "daddr_t offset"
+.Ft struct chunk *
+.Fn Create_Chunk_DWIM "struct disk *d" "struct chunk *parent" "daddr_t size" "chunk_e type" "int subtype" "u_long flags"
+.Ft int
+.Fn MakeDev "struct chunk *c" "const char *path"
+.Ft int
+.Fn MakeDevDisk "struct disk *d" "const char *path"
+.Ft char *
+.Fn ShowChunkFlags "struct chunk *c"
+.Ft const char *
+.Fn chunk_name "chunk_e type"
+.Ft const char *
+.Fn slice_type_name "int type" "int subtype"
+.Sh DESCRIPTION
+.Bf Sy
+.Nm libdisk
+is just for the use of
+.Xr sysinstall 8 .
+You should consider using
+.Xr libgeom 3
+instead.
+.Ef
+.Pp
+The
+.Nm libdisk
+library provides an interface to the low-level disk slice and partition labels.
+Most functions operate with arguments of the types
+.Ql struct disk ,
+or
+.Ql struct chunk .
+.Pp
+While both types are mostly opaque to the programmer, the internal
+structure is mentioned below for the sake of completeness.
+.Bd -literal -offset indent
+struct disk {
+ char *name;
+ u_long flags;
+ u_long bios_cyl;
+ u_long bios_hd;
+ u_long bios_sect;
+ u_char *bootmgr;
+ u_char *boot1;
+ u_char *boot2;
+ struct chunk *chunks;
+ u_long sector_size;
+};
+.Ed
+The only flag value by now is
+.Ql DISK_ON_TRACK ,
+meaning that this disk is handled by the On-Track Disk Manager.
+.Pp
+.Bd -literal -offset indent
+struct chunk {
+ struct chunk *next;
+ struct chunk *part;
+ struct disk *disk;
+ daddr_t offset;
+ daddr_t size;
+ daddr_t end;
+ char *name;
+ char *oname;
+ chunk_e type;
+ int subtype;
+ u_long flags;
+ void (*private_free)(void*);
+ void *(*private_clone)(void*);
+ void *private_data;
+};
+.Ed
+The
+.Ql type
+field can be one of the following values:
+.Ql whole, unknown, fat, freebsd, extended, part, unused .
+.Pp
+These are the valid
+.Ql flags
+values for a
+.Ql struct chunk .
+.Bl -tag -offset indent -width CHUNK_BSD_COMPATXX
+.It CHUNK_PAST_1024
+This chunk cannot be booted from because it extends past cylinder 1024.
+.It CHUNK_BSD_COMPAT
+This chunk is in the
+.Bx Ns -compatibility ,
+and has a short name too, i.e.\&
+.Ql wd0s4f -> wd0f .
+.It CHUNK_ALIGN
+This chunk should be aligned.
+.It CHUNK_IS_ROOT
+This
+.Ql part
+is a rootfs, allocate partition
+.Sq a .
+.It CHUNK_ACTIVE
+This is the active slice in the MBR.
+.It CHUNK_FORCE_ALL
+Force a dedicated disk for
+.Fx ,
+bypassing all BIOS geometry considerations.
+.El
+.Pp
+The
+.Ql private_data ,
+.Ql private_free ,
+and
+.Ql private_clone
+fields are for data private to the application, and the management
+thereof.
+If the functions are not provided, no storage management is
+done, cloning will just copy the pointer and freeing will just forget
+it.
+.Pp
+.Fn Open_Disk
+will open the named disk, and return populated tree.
+.Pp
+.Fn Free_Disk
+frees a tree made with
+.Fn Open_Disk
+or
+.Fn Clone_Disk .
+.Pp
+.Fn Debug_Disk
+prints the content of the tree to
+.Dv stdout .
+.Pp
+.Fn Set_Bios_Geom
+sets the geometry the bios uses.
+.Pp
+.Fn Delete_Chunk
+frees a chunk of disk_space.
+.Pp
+.Fn Collapse_Disk
+and
+.Fn Collapse_Chunk
+are experimental, do not use.
+.Pp
+.Fn Create_Chunk
+creates a chunk with the specified parameters.
+.Pp
+.Fn All_FreeBSD
+makes one
+.Fx
+chunk covering the entire disk; if
+.Ql force_all
+is set, bypass all BIOS geometry considerations.
+.Pp
+.Fn CheckRules
+returns
+.Ql char*
+to warnings about broken design rules in this disklayout.
+.Pp
+.Fn Disk_Names
+returns
+.Ql char**
+with all disk's names (wd0, wd1 ...).
+You must free each pointer, as
+well as the array by hand.
+.Pp
+.Fn Set_Boot_Mgr
+sets this boot-manager for use on this disk.
+Gets written when
+.Fn Write_Disk
+is called.
+.Pp
+.Fn Set_Boot_Blocks
+sets the boot-blocks for use on this disk.
+Gets written when
+.Fn Write_Disk
+is called.
+.Pp
+.Fn Write_Disk
+writes all the MBRs, disklabels, bootblocks and boot managers.
+.Pp
+.Fn Cyl_Aligned
+checks if
+.Ql offset
+is aligned on a cylinder according to the BIOS geometry.
+.Pp
+.Fn Next_Cyl_Aligned
+rounds
+.Ql offset
+up to next cylinder according to the BIOS geometry.
+.Pp
+.Fn Prev_Cyl_Aligned
+rounds
+.Ql offset
+down to previous cylinder according to the BIOS geometry.
+.Pp
+.Fn Track_Aligned
+checks if
+.Ql offset
+is aligned on a track according to the BIOS geometry.
+.Pp
+.Fn Next_Track_Aligned
+rounds
+.Ql offset
+up to next track according to the BIOS geometry.
+.Pp
+.Fn Prev_Track_Aligned
+rounds
+.Ql offset
+up to previous track according to the BIOS geometry.
+.Pp
+.Fn Create_Chunk_DWIM
+creates a partition inside the given parent of the given size, and
+returns a pointer to it.
+The first unused chunk big enough is used.
+.Pp
+.Fn MakeDev
+makes the device nodes for this chunk.
+.Pp
+.Fn MakeDevDisk
+makes the device nodes for all chunks on this disk.
+.Pp
+.Fn ShowChunkFlags
+returns a string to show flags.
+.Pp
+The
+.Fn chunk_name
+function takes the enumerated chunk type and returns its name.
+.Fn chunk_name
+replaces the old external array
+.Va chunk_n .
+.Pp
+.Fn slice_type_name
+returns the name strings associated with the specified
+.Ql type .
+.Ql subtype .
+If
+.Fn slice_type_name
+returns "unknown" for slices it is not familiar with.
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libdisk
+library was written by
+.An Poul-Henning Kamp .
+.Pp
+This manual page was written by
+.An J\(:org Wunsch .
diff --git a/lib/libdisk/libdisk.h b/lib/libdisk/libdisk.h
new file mode 100644
index 0000000..0a161cc
--- /dev/null
+++ b/lib/libdisk/libdisk.h
@@ -0,0 +1,364 @@
+/*
+* ----------------------------------------------------------------------------
+* "THE BEER-WARE LICENSE" (Revision 42):
+* <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+* can do whatever you want with this stuff. If we meet some day, and you think
+* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+* ----------------------------------------------------------------------------
+*
+* $FreeBSD$
+*
+*/
+
+/* #define DEBUG 1 */
+/* You can define a particular architecture here if you are debugging. */
+/* #define P_DEBUG p_sparc64 */
+
+#define MAX_NO_DISKS 32
+/* Max # of disks Disk_Names() will return */
+
+#define MAX_SEC_SIZE 2048 /* maximum sector size that is supported */
+#define MIN_SEC_SIZE 512 /* the sector size to end sensing at */
+
+enum platform {
+ p_any, /* for debugging ! */
+ p_alpha,
+ p_i386,
+ p_pc98,
+ p_sparc64,
+ p_ia64,
+ p_ppc,
+ p_amd64,
+ p_arm
+};
+extern const enum platform platform;
+
+typedef enum {
+ whole,
+ unknown,
+
+ sun,
+ pc98,
+ mbr,
+ gpt,
+
+ efi,
+ fat,
+ freebsd,
+ extended,
+ part,
+ spare,
+ unused,
+
+ apple
+} chunk_e;
+
+__BEGIN_DECLS
+#ifndef __ia64__
+struct disk {
+ char *name;
+ u_long bios_cyl;
+ u_long bios_hd;
+ u_long bios_sect;
+#ifdef PC98
+ u_char *bootipl;
+ size_t bootipl_size;
+ u_char *bootmenu;
+ size_t bootmenu_size;
+#else
+ u_char *bootmgr;
+ size_t bootmgr_size;
+#endif
+ u_char *boot1;
+#if defined(__i386__) || defined(__amd64__) /* the i386 needs extra help... */
+ u_char *boot2;
+#endif
+ struct chunk *chunks;
+ u_long sector_size; /* media sector size, a power of 2 */
+};
+#else /* !__ia64__ */
+struct disk {
+ char *name;
+ struct chunk *chunks;
+ u_long media_size;
+ u_long sector_size;
+ u_long lba_start;
+ u_long lba_end;
+ u_int gpt_size; /* Number of entries */
+};
+#endif
+
+struct chunk {
+ struct chunk *next;
+ struct chunk *part;
+ struct disk *disk;
+ daddr_t offset;
+ daddr_t size;
+ daddr_t end;
+ char *sname; /* PC98 field */
+ char *name;
+ char *oname;
+ /* Used during Fixup_Names() to avoid renaming more than
+ * absolutely needed.
+ */
+ chunk_e type;
+ int subtype;
+ u_long flags;
+ void (*private_free)(void*);
+ void *(*private_clone)(void*);
+ void *private_data;
+ /* For data private to the application, and the management
+ * thereof. If the functions are not provided, no storage
+ * management is done, Cloning will just copy the pointer
+ * and freeing will just forget it.
+ */
+};
+
+/*
+ * flags:
+ *
+ * ALIGN - This chunk should be aligned
+ * IS_ROOT - This 'part' is a rootfs, allocate 'a'
+ * ACTIVE - This is the active slice in the MBR
+ * FORCE_ALL - Force a dedicated disk for FreeBSD, bypassing
+ * all BIOS geometry considerations
+ * AUTO_SIZE - This chunk was auto-sized and can fill-out a
+ * following chunk if the following chunk is deleted.
+ * NEWFS - newfs pending, used to enable auto-resizing on
+ * delete (along with AUTO_SIZE).
+ */
+
+#define CHUNK_ALIGN 0x0008
+#define CHUNK_IS_ROOT 0x0010
+#define CHUNK_ACTIVE 0x0020
+#define CHUNK_FORCE_ALL 0x0040
+#define CHUNK_AUTO_SIZE 0x0080
+#define CHUNK_NEWFS 0x0100
+#define CHUNK_HAS_INDEX 0x0200
+#define CHUNK_ITOF(i) ((i & 0xFFFF) << 16)
+#define CHUNK_FTOI(f) ((f >> 16) & 0xFFFF)
+
+#define DELCHUNK_NORMAL 0x0000
+#define DELCHUNK_RECOVER 0x0001
+
+const char *chunk_name(chunk_e);
+
+const char *
+slice_type_name(int, int);
+/* "chunk_n" for subtypes too */
+
+struct disk *
+Open_Disk(const char *);
+/* Will open the named disk, and return populated tree. */
+
+void
+Free_Disk(struct disk *);
+/* Free a tree made with Open_Disk() or Clone_Disk() */
+
+void
+Debug_Disk(struct disk *);
+/* Print the content of the tree to stdout */
+
+void
+Set_Bios_Geom(struct disk *, u_long, u_long, u_long);
+/* Set the geometry the bios uses. */
+
+void
+Sanitize_Bios_Geom(struct disk *);
+/* Set the bios geometry to something sane */
+
+int
+Insert_Chunk(struct chunk *, daddr_t, daddr_t, const char *, chunk_e, int,
+ u_long, const char *);
+
+int
+Delete_Chunk2(struct disk *, struct chunk *, int);
+/* Free a chunk of disk_space modified by the passed flags. */
+
+int
+Delete_Chunk(struct disk *, struct chunk *);
+/* Free a chunk of disk_space */
+
+void
+Collapse_Disk(struct disk *);
+/* Experimental, do not use. */
+
+int
+Collapse_Chunk(struct disk *, struct chunk *);
+/* Experimental, do not use. */
+
+int
+Create_Chunk(struct disk *, daddr_t, daddr_t, chunk_e, int, u_long, const char *);
+/* Create a chunk with the specified paramters */
+
+void
+All_FreeBSD(struct disk *, int);
+/*
+ * Make one FreeBSD chunk covering the entire disk;
+ * if force_all is set, bypass all BIOS geometry
+ * considerations.
+ */
+
+char *
+CheckRules(const struct disk *);
+/* Return char* to warnings about broken design rules in this disklayout */
+
+char **
+Disk_Names(void);
+/*
+ * Return char** with all disk's names (wd0, wd1 ...). You must free
+ * each pointer, as well as the array by hand
+ */
+
+#ifdef PC98
+void
+Set_Boot_Mgr(struct disk *, const u_char *, const size_t, const u_char *,
+ const size_t);
+#else
+void
+Set_Boot_Mgr(struct disk *, const u_char *, const size_t);
+#endif
+/*
+ * Use this boot-manager on this disk. Gets written when Write_Disk()
+ * is called
+ */
+
+int
+Set_Boot_Blocks(struct disk *, const u_char *, const u_char *);
+/*
+ * Use these boot-blocks on this disk. Gets written when Write_Disk()
+ * is called. Returns nonzero upon failure.
+ */
+
+int
+Write_Disk(const struct disk *);
+/* Write all the MBRs, disklabels, bootblocks and boot managers */
+
+daddr_t
+Next_Cyl_Aligned(const struct disk *, daddr_t);
+/* Round offset up to next cylinder according to the bios-geometry */
+
+daddr_t
+Prev_Cyl_Aligned(const struct disk *, daddr_t);
+/* Round offset down to previous cylinder according to the bios-geometry */
+
+int
+Track_Aligned(const struct disk *, daddr_t);
+/* Check if offset is aligned on a track according to the bios geometry */
+
+daddr_t
+Next_Track_Aligned(const struct disk *, daddr_t);
+/* Round offset up to next track according to the bios-geometry */
+
+daddr_t
+Prev_Track_Aligned(const struct disk *, daddr_t);
+/* Check if offset is aligned on a track according to the bios geometry */
+
+struct chunk *
+Create_Chunk_DWIM(struct disk *, struct chunk *, daddr_t, chunk_e, int,
+ u_long);
+/*
+ * This one creates a partition inside the given parent of the given
+ * size, and returns a pointer to it. The first unused chunk big
+ * enough is used.
+ */
+
+char *
+ShowChunkFlags(struct chunk *);
+/* Return string to show flags. */
+
+/*
+ * Implementation details >>> DO NOT USE <<<
+ */
+
+struct disklabel;
+
+void Fill_Disklabel(struct disklabel *, const struct disk *,
+ const struct chunk *);
+void Debug_Chunk(struct chunk *);
+struct chunk *New_Chunk(void);
+void Free_Chunk(struct chunk *);
+struct chunk *Clone_Chunk(const struct chunk *);
+int Add_Chunk(struct disk *, daddr_t, daddr_t, const char *, chunk_e, int,
+ u_long, const char *);
+void *read_block(int, daddr_t, u_long);
+int write_block(int, daddr_t, const void *, u_long);
+struct disklabel *read_disklabel(int, daddr_t, u_long);
+struct disk *Int_Open_Disk(const char *, char *);
+int Fixup_Names(struct disk *);
+int MakeDevChunk(const struct chunk *, const char *);
+__END_DECLS
+
+#define dprintf printf
+
+/* TODO
+ *
+ * Need an error string mechanism from the functions instead of warn()
+ *
+ * Make sure only FreeBSD start at offset==0
+ *
+ * Collapse must align.
+ *
+ * Make Write_Disk(struct disk*)
+ *
+ * Consider booting from OnTrack'ed disks.
+ *
+ * Get Bios-geom, ST506 & OnTrack from driver (or otherwise)
+ *
+ * Make Create_DWIM().
+ *
+ * Make Is_Unchanged(struct disk *d1, struct chunk *c1)
+ *
+ * don't rename slices unless we have to
+ *
+ *Sample output from tst01:
+ *
+ * Debug_Disk(wd0) flags=0 bios_geom=0/0/0
+ * >> 0x3d040 0 1411200 1411199 wd0 0 whole 0 0
+ * >>>> 0x3d080 0 960120 960119 wd0s1 3 freebsd 0 8
+ * >>>>>> 0x3d100 0 40960 40959 wd0s1a 5 part 0 0
+ * >>>>>> 0x3d180 40960 131072 172031 wd0s1b 5 part 0 0
+ * >>>>>> 0x3d1c0 172032 409600 581631 wd0s1e 5 part 0 0
+ * >>>>>> 0x3d200 581632 378488 960119 wd0s1f 5 part 0 0
+ * >>>> 0x3d140 960120 5670 965789 wd0s2 4 extended 0 8
+ * >>>>>> 0x3d2c0 960120 63 960182 - 6 unused 0 0
+ * >>>>>> 0x3d0c0 960183 5607 965789 wd0s5 2 fat 0 8
+ * >>>> 0x3d280 965790 1890 967679 wd0s3 1 foo -2 8
+ * >>>> 0x3d300 967680 443520 1411199 wd0s4 3 freebsd 0 8
+ * >>>>>> 0x3d340 967680 443520 1411199 wd0s4a 5 part 0 0
+ *
+ * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
+ * level chunkptr start size end name type subtype flags
+ *
+ * Underlying data structure:
+ *
+ * Legend:
+ * <struct chunk> --> part
+ * |
+ * v next
+ *
+ * <wd0> --> <wd0s1> --> <wd0s1a>
+ * | |
+ * | v
+ * | <wd0s1b>
+ * | |
+ * | v
+ * | <wd0s1e>
+ * | |
+ * | v
+ * | <wd0s1f>
+ * |
+ * v
+ * <wd0s2> --> <unused>
+ * | |
+ * | v
+ * | <wd0s5>
+ * |
+ * v
+ * <wd0s3>
+ * |
+ * v
+ * <wd0s4> --> <wd0s4a>
+ *
+ *
+ */
diff --git a/lib/libdisk/open_disk.c b/lib/libdisk/open_disk.c
new file mode 100644
index 0000000..7450652
--- /dev/null
+++ b/lib/libdisk/open_disk.c
@@ -0,0 +1,280 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <inttypes.h>
+#include <err.h>
+#include <sys/sysctl.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/gpt.h>
+#include <paths.h>
+#include "libdisk.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifdef DEBUG
+#define DPRINT(x) warn x
+#define DPRINTX(x) warnx x
+#else
+#define DPRINT(x)
+#define DPRINTX(x)
+#endif
+
+struct disk *
+Int_Open_Disk(const char *name, char *conftxt)
+{
+ struct disk *d;
+ int i;
+ char *p, *q, *r, *a, *b, *n, *t, *sn;
+ daddr_t o, len, off;
+ u_int l, s, ty, sc, hd, alt;
+ daddr_t lo[10];
+
+ for (p = conftxt; p != NULL && *p; p = strchr(p, '\n')) {
+ if (*p == '\n')
+ p++;
+ a = strsep(&p, " ");
+ if (strcmp(a, "0"))
+ continue;
+
+ a = strsep(&p, " ");
+ if (strcmp(a, "DISK"))
+ continue;
+
+ a = strsep(&p, " ");
+ if (strcmp(a, name))
+ continue;
+ break;
+ }
+
+ q = strchr(p, '\n');
+ if (q != NULL)
+ *q++ = '\0';
+
+ d = (struct disk *)calloc(sizeof *d, 1);
+ if(d == NULL)
+ return NULL;
+
+ d->name = strdup(name);
+
+ a = strsep(&p, " "); /* length in bytes */
+ len = strtoimax(a, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+
+ a = strsep(&p, " "); /* sectorsize */
+ s = strtoul(a, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+
+ if (s == 0)
+ return (NULL);
+ d->sector_size = s;
+ len /= s; /* media size in number of sectors. */
+
+ if (Add_Chunk(d, 0, len, name, whole, 0, 0, "-")) {
+ DPRINT(("Failed to add 'whole' chunk"));
+ }
+
+ for (;;) {
+ a = strsep(&p, " ");
+ if (a == NULL)
+ break;
+ b = strsep(&p, " ");
+ o = strtoimax(b, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+ if (!strcmp(a, "hd"))
+ d->bios_hd = o;
+ else if (!strcmp(a, "sc"))
+ d->bios_sect = o;
+ else
+ printf("HUH ? <%s> <%s>\n", a, b);
+ }
+
+ /*
+ * Calculate the number of cylinders this disk must have. If we have
+ * an obvious insanity, we set the number of cylinders to zero.
+ */
+ o = d->bios_hd * d->bios_sect;
+ d->bios_cyl = (o != 0) ? len / o : 0;
+
+ p = q;
+ lo[0] = 0;
+
+ for (; p != NULL && *p; p = q) {
+ sn = NULL;
+ q = strchr(p, '\n');
+ if (q != NULL)
+ *q++ = '\0';
+ a = strsep(&p, " "); /* Index */
+ if (!strcmp(a, "0"))
+ break;
+ l = strtoimax(a, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+ t = strsep(&p, " "); /* Type {SUN, BSD, MBR, PC98, GPT} */
+ n = strsep(&p, " "); /* name */
+ a = strsep(&p, " "); /* len */
+ len = strtoimax(a, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+ a = strsep(&p, " "); /* secsize */
+ s = strtoimax(a, &r, 0);
+ if (*r) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+ for (;;) {
+ a = strsep(&p, " ");
+ if (a == NULL)
+ break;
+ /* XXX: Slice name may include a space. */
+ if (!strcmp(a, "sn")) {
+ sn = p;
+ break;
+ }
+ b = strsep(&p, " ");
+ o = strtoimax(b, &r, 0);
+ /* APPLE have ty as a string */
+ if ((*r) && (strcmp(t, "APPLE") && strcmp(t, "GPT"))) {
+ printf("BARF %d <%d>\n", __LINE__, *r);
+ exit (0);
+ }
+ if (!strcmp(a, "o"))
+ off = o;
+ else if (!strcmp(a, "i"))
+ i = o;
+ else if (!strcmp(a, "ty"))
+ ty = o;
+ else if (!strcmp(a, "sc"))
+ sc = o;
+ else if (!strcmp(a, "hd"))
+ hd = o;
+ else if (!strcmp(a, "alt"))
+ alt = o;
+ }
+
+ /* PLATFORM POLICY BEGIN ----------------------------------- */
+ if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2)
+ continue;
+ if (platform == p_sparc64 && !strcmp(t, "SUN") &&
+ d->chunks->part->part == NULL) {
+ d->bios_hd = hd;
+ d->bios_sect = sc;
+ o = d->chunks->size / (hd * sc);
+ o *= (hd * sc);
+ o -= alt * hd * sc;
+ if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
+ DPRINT(("Failed to add 'freebsd' chunk"));
+ }
+ }
+ if (platform == p_alpha && !strcmp(t, "BSD") &&
+ d->chunks->part->part == NULL) {
+ if (Add_Chunk(d, 0, d->chunks->size, name, freebsd,
+ 0, 0, "-")) {
+ DPRINT(("Failed to add 'freebsd' chunk"));
+ }
+ }
+ if (!strcmp(t, "BSD") && i == RAW_PART)
+ continue;
+ /* PLATFORM POLICY END ------------------------------------- */
+
+ off /= s;
+ len /= s;
+ off += lo[l - 1];
+ lo[l] = off;
+ if (!strcmp(t, "SUN"))
+ i = Add_Chunk(d, off, len, n, part, 0, 0, 0);
+ else if (!strncmp(t, "MBR", 3)) {
+ switch (ty) {
+ case 0xa5:
+ i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0);
+ break;
+ case 0x01:
+ case 0x04:
+ case 0x06:
+ case 0x0b:
+ case 0x0c:
+ case 0x0e:
+ i = Add_Chunk(d, off, len, n, fat, ty, 0, 0);
+ break;
+ case 0xef: /* EFI */
+ i = Add_Chunk(d, off, len, n, efi, ty, 0, 0);
+ break;
+ default:
+ i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0);
+ break;
+ }
+ } else if (!strcmp(t, "BSD"))
+ i = Add_Chunk(d, off, len, n, part, ty, 0, 0);
+ else if (!strcmp(t, "PC98")) {
+ switch (ty & 0x7f) {
+ case 0x14:
+ i = Add_Chunk(d, off, len, n, freebsd, ty, 0,
+ sn);
+ break;
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ i = Add_Chunk(d, off, len, n, fat, ty, 0, sn);
+ break;
+ default:
+ i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn);
+ break;
+ }
+ } else if (!strcmp(t, "GPT"))
+ i = Add_Chunk(d, off, len, n, gpt, 0, 0, b);
+ else if (!strcmp(t, "APPLE"))
+ i = Add_Chunk(d, off, len, n, apple, 0, 0, sn);
+ else
+ ; /* Ignore unknown classes. */
+ }
+ /* PLATFORM POLICY BEGIN ------------------------------------- */
+ /* We have a chance to do things on a blank disk here */
+ if (platform == p_sparc64 && d->chunks->part->part == NULL) {
+ hd = d->bios_hd;
+ sc = d->bios_sect;
+ o = d->chunks->size / (hd * sc);
+ o *= (hd * sc);
+ o -= 2 * hd * sc;
+ if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
+ DPRINT(("Failed to add 'freebsd' chunk"));
+ }
+ }
+ /* PLATFORM POLICY END --------------------------------------- */
+
+ return (d);
+ i = 0;
+}
diff --git a/lib/libdisk/open_ia64_disk.c b/lib/libdisk/open_ia64_disk.c
new file mode 100644
index 0000000..8fc9f64
--- /dev/null
+++ b/lib/libdisk/open_ia64_disk.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/disklabel.h>
+#include <sys/diskmbr.h>
+#include <sys/gpt.h>
+#include <sys/uuid.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <uuid.h>
+
+#include "libdisk.h"
+
+static uuid_t _efi = GPT_ENT_TYPE_EFI;
+static uuid_t _mbr = GPT_ENT_TYPE_MBR;
+static uuid_t _fbsd = GPT_ENT_TYPE_FREEBSD;
+static uuid_t _swap = GPT_ENT_TYPE_FREEBSD_SWAP;
+static uuid_t _ufs = GPT_ENT_TYPE_FREEBSD_UFS;
+
+static struct disk *
+parse_disk(char *conftxt, const char *name)
+{
+ char devname[64];
+ struct disk *disk;
+ struct dos_partition *part;
+ struct gpt_hdr *gpt;
+ char *buffer, *p, *q;
+ int fd, i;
+
+ disk = (struct disk *)calloc(sizeof *disk, 1);
+ if (disk == NULL)
+ return (NULL);
+
+ disk->name = strdup(name);
+ p = strsep(&conftxt, " "); /* media size */
+ disk->media_size = strtoimax(p, &q, 0);
+ if (*q)
+ goto fail;
+
+ p = strsep(&conftxt, " "); /* sector size */
+ disk->sector_size = strtoul(p, &q, 0);
+ if (*q)
+ goto fail;
+
+ if (disk->sector_size == 0)
+ disk->sector_size = 512;
+
+ if (disk->media_size % disk->sector_size)
+ goto fail;
+
+ /*
+ * We need to read the disk to get GPT specific information.
+ */
+
+ snprintf(devname, sizeof(devname), "%s%s", _PATH_DEV, name);
+ fd = open(devname, O_RDONLY);
+ if (fd == -1)
+ goto fail;
+ buffer = malloc(2 * disk->sector_size);
+ if (buffer == NULL) {
+ close (fd);
+ goto fail;
+ }
+ if (read(fd, buffer, 2 * disk->sector_size) == -1) {
+ free(buffer);
+ close(fd);
+ goto fail;
+ }
+ close(fd);
+
+ gpt = (struct gpt_hdr *)(buffer + disk->sector_size);
+ if (memcmp(gpt->hdr_sig, GPT_HDR_SIG, sizeof(gpt->hdr_sig))) {
+ /*
+ * No GPT present. Check if the MBR is empty (if present)
+ * or is a PMBR before declaring this disk as empty. If
+ * the MBR isn't empty, bail out. Let's not risk nuking a
+ * disk.
+ */
+ if (*(u_short *)(buffer + DOSMAGICOFFSET) == DOSMAGIC) {
+ for (i = 0; i < 4; i++) {
+ part = (struct dos_partition *)
+ (buffer + DOSPARTOFF + i * DOSPARTSIZE);
+ if (part->dp_typ != 0 &&
+ part->dp_typ != DOSPTYP_PMBR)
+ break;
+ }
+ if (i < 4) {
+ free(buffer);
+ goto fail;
+ }
+ }
+ disk->gpt_size = 128;
+ disk->lba_start = (disk->gpt_size * sizeof(struct gpt_ent)) /
+ disk->sector_size + 2;
+ disk->lba_end = (disk->media_size / disk->sector_size) -
+ disk->lba_start;
+ } else {
+ disk->lba_start = gpt->hdr_lba_start;
+ disk->lba_end = gpt->hdr_lba_end;
+ disk->gpt_size = gpt->hdr_entries;
+ }
+ free(buffer);
+ Add_Chunk(disk, disk->lba_start, disk->lba_end - disk->lba_start + 1,
+ name, whole, 0, 0, "-");
+ return (disk);
+
+fail:
+ free(disk->name);
+ free(disk);
+ return (NULL);
+}
+
+struct disk *
+Int_Open_Disk(const char *name, char *conftxt)
+{
+ struct chunk chunk;
+ uuid_t uuid;
+ struct disk *disk;
+ char *p, *q, *r, *s, *sd, *type;
+ u_long i;
+ uint32_t status;
+
+ p = conftxt;
+ while (p != NULL && *p != 0) {
+ q = strsep(&p, " ");
+ if (strcmp(q, "0") == 0) {
+ q = strsep(&p, " ");
+ if (strcmp(q, "DISK") == 0) {
+ q = strsep(&p, " ");
+ if (strcmp(q, name) == 0)
+ break;
+ }
+ }
+ p = strchr(p, '\n');
+ if (p != NULL && *p == '\n')
+ p++;
+ conftxt = p;
+ }
+ if (p == NULL || *p == 0)
+ return (NULL);
+
+ conftxt = strchr(p, '\n');
+ if (conftxt != NULL)
+ *conftxt++ = '\0';
+
+ disk = parse_disk(p, name);
+ if (disk == NULL)
+ return (NULL);
+
+ while (conftxt != NULL && *conftxt != 0) {
+ p = conftxt;
+ conftxt = strchr(p, '\n');
+ if (conftxt != NULL)
+ *conftxt++ = '\0';
+
+ sd = strsep(&p, " "); /* depth */
+ if (strcmp(sd, "0") == 0)
+ break;
+
+ type = strsep(&p, " "); /* type */
+ chunk.name = strsep(&p, " "); /* name */
+ q = strsep(&p, " "); /* length */
+ i = strtoimax(q, &r, 0);
+ if (*r)
+ abort();
+ chunk.end = i / disk->sector_size;
+ q = strsep(&p, " "); /* sector size */
+
+ for (;;) {
+ q = strsep(&p, " ");
+ if (q == NULL)
+ break;
+ r = strsep(&p, " ");
+ i = strtoimax(r, &s, 0);
+ if (*s) {
+ uuid_from_string(r, &uuid, &status);
+ if (status != uuid_s_ok)
+ abort();
+ } else
+ status = uuid_s_invalid_string_uuid;
+ if (!strcmp(q, "o"))
+ chunk.offset = i / disk->sector_size;
+ else if (!strcmp(q, "i"))
+ chunk.flags = CHUNK_ITOF(i) | CHUNK_HAS_INDEX;
+ else if (!strcmp(q, "ty"))
+ chunk.subtype = i;
+ }
+
+ if (strncmp(type, "MBR", 3) == 0) {
+ switch (chunk.subtype) {
+ case 0xa5:
+ chunk.type = freebsd;
+ break;
+ case 0x01:
+ case 0x04:
+ case 0x06:
+ case 0x0b:
+ case 0x0c:
+ case 0x0e:
+ chunk.type = fat;
+ break;
+ case 0xef: /* EFI */
+ chunk.type = efi;
+ break;
+ default:
+ chunk.type = mbr;
+ break;
+ }
+ } else if (strcmp(type, "BSD") == 0) {
+ chunk.type = part;
+ } else if (strcmp(type, "GPT") == 0) {
+ chunk.subtype = 0;
+ if (status != uuid_s_ok)
+ abort();
+ if (uuid_is_nil(&uuid, NULL))
+ chunk.type = unused;
+ else if (uuid_equal(&uuid, &_efi, NULL))
+ chunk.type = efi;
+ else if (uuid_equal(&uuid, &_mbr, NULL))
+ chunk.type = mbr;
+ else if (uuid_equal(&uuid, &_fbsd, NULL)) {
+ chunk.type = freebsd;
+ chunk.subtype = 0xa5;
+ } else if (uuid_equal(&uuid, &_swap, NULL)) {
+ chunk.type = part;
+ chunk.subtype = FS_SWAP;
+ } else if (uuid_equal(&uuid, &_ufs, NULL)) {
+ chunk.type = part;
+ chunk.subtype = FS_BSDFFS;
+ } else
+ chunk.type = part;
+ } else
+ abort();
+
+ Add_Chunk(disk, chunk.offset, chunk.end, chunk.name,
+ chunk.type, chunk.subtype, chunk.flags, 0);
+ }
+
+ return (disk);
+}
diff --git a/lib/libdisk/rules.c b/lib/libdisk/rules.c
new file mode 100644
index 0000000..1f12f4c
--- /dev/null
+++ b/lib/libdisk/rules.c
@@ -0,0 +1,296 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stdint.h>
+#include <sys/disklabel.h>
+#ifdef PC98
+#include <sys/diskpc98.h>
+#else
+#include <sys/diskmbr.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "libdisk.h"
+
+int
+Track_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect)
+ return 1;
+ if (offset % d->bios_sect)
+ return 0;
+#endif /* __ia64__ */
+ return 1;
+}
+
+daddr_t
+Prev_Track_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect)
+ return offset;
+ return (offset / d->bios_sect) * d->bios_sect;
+#else
+ return 1;
+#endif
+}
+
+daddr_t
+Next_Track_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect)
+ return offset;
+ return Prev_Track_Aligned(d, offset + d->bios_sect-1);
+#else
+ return 1;
+#endif
+}
+
+static int
+Cyl_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect || !d->bios_hd)
+ return 1;
+ if (offset % (d->bios_sect * d->bios_hd))
+ return 0;
+#endif
+ return 1;
+}
+
+daddr_t
+Prev_Cyl_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect || !d->bios_hd)
+ return offset;
+ return (offset / (d->bios_sect * d->bios_hd)) * d->bios_sect *
+ d->bios_hd;
+#else
+ return 1;
+#endif
+}
+
+daddr_t
+Next_Cyl_Aligned(const struct disk *d, daddr_t offset)
+{
+#ifndef __ia64__
+ if (!d->bios_sect || !d->bios_hd)
+ return offset;
+ return Prev_Cyl_Aligned(d,offset + (d->bios_sect * d->bios_hd) - 1);
+#else
+ return 1;
+#endif
+}
+
+/*
+ * Rule#0:
+ * Chunks of type 'whole' can have max NDOSPART children.
+ * Only one of them can have the "active" flag
+ */
+static void
+Rule_000(__unused const struct disk *d, const struct chunk *c, char *msg)
+{
+#ifdef PC98
+ int i = 0;
+#else
+ int i = 0, j = 0;
+#endif
+ struct chunk *c1;
+
+ if (c->type != whole)
+ return;
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type != unused)
+ continue;
+#ifndef PC98
+ if (c1->flags & CHUNK_ACTIVE)
+ j++;
+#endif
+ i++;
+ }
+ if (i > NDOSPART)
+ sprintf(msg + strlen(msg),
+ "%d is too many children of the 'whole' chunk."
+ " Max is %d\n", i, NDOSPART);
+#ifndef PC98
+ if (j > 1)
+ sprintf(msg + strlen(msg),
+ "Too many active children of 'whole'");
+#endif
+}
+
+/*
+ * Rule#1:
+ * All children of 'whole' and 'extended' must be track-aligned.
+ * Exception: the end can be unaligned if it matches the end of 'whole'
+ */
+static void
+Rule_001(const struct disk *d, const struct chunk *c, char *msg)
+{
+ struct chunk *c1;
+
+ if (c->type != whole && c->type != extended)
+ return;
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ c1->flags |= CHUNK_ALIGN;
+#ifdef PC98
+ if (!Cyl_Aligned(d, c1->offset))
+#else
+ if (!Track_Aligned(d, c1->offset))
+#endif
+ sprintf(msg + strlen(msg),
+#ifdef PC98
+ "chunk '%s' [%jd..%jd] does not start"
+ " on a cylinder boundary\n",
+#else
+ "chunk '%s' [%jd..%jd] does not start"
+ " on a track boundary\n",
+#endif
+ c1->name, (intmax_t)c1->offset, (intmax_t)c1->end);
+ if ((c->type == whole || c->end == c1->end)
+ || Cyl_Aligned(d, c1->end + 1))
+ ;
+ else
+ sprintf(msg + strlen(msg),
+ "chunk '%s' [%jd..%jd] does not end"
+ " on a cylinder boundary\n",
+ c1->name, (intmax_t)c1->offset, (intmax_t)c1->end);
+ }
+}
+
+/*
+ * Rule#2:
+ * Max one 'fat' as child of 'whole'
+ */
+static void
+Rule_002(__unused const struct disk *d, const struct chunk *c, char *msg)
+{
+ int i;
+ struct chunk *c1;
+
+ if (c->type != whole)
+ return;
+ for (i = 0, c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type != fat)
+ continue;
+ i++;
+ }
+ if (i > 1) {
+ sprintf(msg + strlen(msg),
+ "Max one 'fat' allowed as child of 'whole'\n");
+ }
+}
+
+/*
+ * Rule#3:
+ * Max one extended as child of 'whole'
+ */
+static void
+Rule_003(__unused const struct disk *d, const struct chunk *c, char *msg)
+{
+ int i;
+ struct chunk *c1;
+
+ if (c->type != whole)
+ return;
+ for (i = 0, c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type != extended)
+ continue;
+ i++;
+ }
+ if (i > 1) {
+ sprintf(msg + strlen(msg),
+ "Max one 'extended' allowed as child of 'whole'\n");
+ }
+}
+
+/*
+ * Rule#4:
+ * Max seven 'part' as children of 'freebsd'
+ * Max one CHUNK_IS_ROOT child per 'freebsd'
+ */
+static void
+Rule_004(__unused const struct disk *d, const struct chunk *c, char *msg)
+{
+ int i = 0, k = 0;
+ struct chunk *c1;
+
+ if (c->type != freebsd)
+ return;
+
+ for (c1 = c->part; c1; c1 = c1->next) {
+ if (c1->type != part)
+ continue;
+ if (c1->flags & CHUNK_IS_ROOT)
+ k++;
+ i++;
+ }
+ if (i > 7) {
+ sprintf(msg + strlen(msg),
+ "Max seven partitions per freebsd slice\n");
+ }
+ if (k > 1) {
+ sprintf(msg + strlen(msg),
+ "Max one root partition child per freebsd slice\n");
+ }
+}
+
+static void
+Check_Chunk(const struct disk *d, const struct chunk *c, char *msg)
+{
+
+ switch (platform) {
+ case p_i386:
+ case p_amd64:
+ Rule_000(d, c, msg);
+ Rule_001(d, c, msg);
+ Rule_002(d, c, msg);
+ Rule_003(d, c, msg);
+ Rule_004(d, c, msg);
+ if (c->part)
+ Check_Chunk(d, c->part, msg);
+ if (c->next)
+ Check_Chunk(d, c->next, msg);
+ break;
+ case p_pc98:
+ Rule_000(d, c, msg);
+ Rule_001(d, c, msg);
+ Rule_004(d, c, msg);
+ if (c->part)
+ Check_Chunk(d, c->part, msg);
+ if (c->next)
+ Check_Chunk(d, c->next, msg);
+ break;
+ default:
+ break;
+ }
+}
+
+char *
+CheckRules(const struct disk *d)
+{
+ char msg[BUFSIZ];
+
+ *msg = '\0';
+ Check_Chunk(d, d->chunks, msg);
+ if (*msg)
+ return strdup(msg);
+ return 0;
+}
diff --git a/lib/libdisk/tst01.c b/lib/libdisk/tst01.c
new file mode 100644
index 0000000..7bb7579
--- /dev/null
+++ b/lib/libdisk/tst01.c
@@ -0,0 +1,323 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+#ifdef READLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+#endif
+#include <sys/types.h>
+#include <paths.h>
+#include "libdisk.h"
+
+#ifndef PC98
+u_char mbrboot[] = {
+250,51,192,142,208,188,0,124,139,244,80,7,80,31,251,252,191,0,6,185,0,1,
+242,165,234,29,6,0,0,190,190,7,179,4,128,60,128,116,14,128,60,0,117,28,
+131,198,16,254,203,117,239,205,24,139,20,139,76,2,139,238,131,198,16,254,
+203,116,26,128,60,0,116,244,190,139,6,172,60,0,116,11,86,187,7,0,180,14,
+205,16,94,235,240,235,254,191,5,0,187,0,124,184,1,2,87,205,19,95,115,12,
+51,192,205,19,79,117,237,190,163,6,235,211,190,194,6,191,254,125,129,61,
+85,170,117,199,139,245,234,0,124,0,0,73,110,118,97,108,105,100,32,112,97,
+114,116,105,116,105,111,110,32,116,97,98,108,101,0,69,114,114,111,114,32,
+108,111,97,100,105,110,103,32,111,112,101,114,97,116,105,110,103,32,115,
+121,115,116,101,109,0,77,105,115,115,105,110,103,32,111,112,101,114,97,
+116,105,110,103,32,115,121,115,116,101,109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,
+1,1,0,4,15,63,60,63,0,0,0,241,239,0,0,0,0,1,61,5,15,63,243,48,240,0,0,144,
+208,2,0,0,0,1,244,165,15,63,170,192,192,3,0,144,208,2,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,85,170
+};
+
+u_char bteasy17[] = {
+51,192,142,192,142,216,142,208,188,0,124,252,139,244,191,0,6,185,0,1,242,
+165,234,96,6,0,0,139,213,88,162,72,7,60,53,116,28,180,16,246,228,5,174,
+4,150,246,68,4,255,116,62,198,4,128,232,218,0,138,116,1,139,76,2,235,8,
+232,207,0,185,1,0,50,209,187,0,124,184,1,2,205,19,114,30,129,191,254,1,
+85,170,117,22,234,0,124,0,0,128,250,129,116,2,178,128,139,234,66,128,242,
+179,136,22,58,7,191,190,7,185,4,0,198,6,45,7,49,50,246,136,45,138,69,4,
+60,0,116,35,60,5,116,31,254,198,190,42,7,232,113,0,190,72,7,70,70,139,28,
+10,255,116,5,50,125,4,117,243,141,183,114,7,232,90,0,131,199,16,254,6,45,
+7,226,203,128,62,117,4,2,116,11,190,59,7,10,246,117,10,205,24,235,172,190,
+42,7,232,57,0,232,54,0,50,228,205,26,139,218,131,195,96,180,1,205,22,180,
+0,117,11,205,26,59,211,114,242,160,72,7,235,10,205,22,138,196,60,28,116,
+243,4,246,60,49,114,214,60,53,119,210,80,190,40,7,187,27,6,83,252,172,80,
+36,127,180,14,205,16,88,168,128,116,242,195,86,184,1,3,187,0,6,185,1,0,
+50,246,205,19,94,198,6,72,7,63,195,13,138,13,10,70,48,32,46,32,46,32,46,
+160,100,105,115,107,32,49,13,10,10,68,101,102,97,117,108,116,58,32,70,63,
+160,0,1,0,4,0,6,3,7,7,10,10,99,14,100,14,101,20,128,20,129,25,130,30,147,
+36,165,39,159,43,117,47,82,47,219,50,64,55,242,61,0,100,111,243,72,80,70,
+211,79,115,178,85,110,105,248,78,111,118,101,108,236,77,105,110,105,248,
+76,105,110,117,248,65,109,111,101,98,225,66,83,196,66,83,68,233,80,67,73,
+216,67,80,205,86,101,110,105,248,68,111,115,115,101,227,63,191,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,85,170
+};
+#endif
+
+int
+scan_block(int fd, daddr_t block)
+{
+ u_char foo[512];
+
+ if (-1 == lseek(fd, (off_t)block * 512, SEEK_SET))
+ err(1, "lseek");
+ if (512 != read(fd, foo, 512))
+ return 1;
+ return 0;
+}
+
+void
+Scan_Disk(struct disk *d)
+{
+ char device[64];
+ u_long l;
+ int i, j, fd;
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d->name);
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ warn("open(%s) failed", device);
+ return;
+ }
+ for (i = -1, l = 0; ; l++) {
+ j = scan_block(fd, l);
+ if (j != i) {
+ if (i == -1) {
+ printf("%c: %lu.",j ? 'B' : 'G', l);
+ fflush(stdout);
+ } else if (i == 0) {
+ printf(".%lu\nB: %lu.", l - 1, l);
+ fflush(stdout);
+ } else {
+ printf(".%lu\nG: %lu.", l - 1, l);
+ fflush(stdout);
+ }
+ i = j;
+ }
+ }
+ close(fd);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct disk *d,*db;
+ char myprompt[BUFSIZ];
+#ifndef READLINE
+ char input[BUFSIZ];
+#endif
+ char *p,*q = 0;
+ char **cp, *cmds[200];
+ int ncmd, i;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage:\n\t%s diskname\n", argv[0]);
+ exit(1);
+ }
+ d = Open_Disk(argv[1]);
+ if (!d)
+ err(1, "Couldn't open disk %s", argv[1]);
+
+ sprintf(myprompt, "%s %s> ", argv[0], argv[1]);
+ while (1) {
+ printf("--==##==--\n");
+ p = CheckRules(d);
+ Debug_Disk(d);
+ if (p) {
+ printf("%s",p);
+ free(p);
+ }
+#ifdef READLINE
+ if (q)
+ free(q);
+ q = p = readline(myprompt);
+#else
+ printf("%s", myprompt);
+ fflush(stdout);
+ q = p = fgets(input, sizeof(input), stdin);
+#endif
+ if(!p)
+ break;
+ for (cp = cmds; (*cp = strsep(&p, " \t\n")) != NULL;)
+ if (**cp != '\0')
+ cp++;
+ ncmd = cp - cmds;
+ if (!ncmd)
+ continue;
+ if (!strcasecmp(*cmds, "quit"))
+ break;
+ if (!strcasecmp(*cmds, "exit"))
+ break;
+ if (!strcasecmp(*cmds, "q"))
+ break;
+ if (!strcasecmp(*cmds, "x"))
+ break;
+ if (!strcasecmp(*cmds, "dwim") && ncmd == 6) {
+ printf("dwim = %p\n",
+ Create_Chunk_DWIM(d,
+ (struct chunk *)strtol(cmds[1], 0, 0),
+ strtol(cmds[2], 0, 0),
+ strtol(cmds[3], 0, 0),
+ strtol(cmds[4], 0, 0),
+ strtol(cmds[5], 0, 0)));
+ continue;
+ }
+ if (!strcasecmp(*cmds, "delete") && ncmd == 2) {
+ printf("delete = %d\n",
+ Delete_Chunk(d,
+ (struct chunk *)strtol(cmds[1], 0, 0)));
+ continue;
+ }
+#ifndef __ia64__
+ if (!strcasecmp(*cmds, "allfreebsd")) {
+ All_FreeBSD(d, 0);
+ continue;
+ }
+ if (!strcasecmp(*cmds, "dedicate")) {
+ All_FreeBSD(d, 1);
+ continue;
+ }
+ if (!strcasecmp(*cmds, "sanitize")) {
+ Sanitize_Bios_Geom(d);
+ continue;
+ }
+ if (!strcasecmp(*cmds, "bios") && ncmd == 4) {
+ Set_Bios_Geom(d, strtol(cmds[1], 0, 0),
+ strtol(cmds[2], 0, 0),
+ strtol(cmds[3], 0, 0));
+ continue;
+ }
+#endif
+ if (!strcasecmp(*cmds, "list")) {
+ cp = Disk_Names();
+ printf("Disks:");
+ for (i = 0; cp[i]; i++) {
+ printf(" %s", cp[i]);
+ free(cp[i]);
+ }
+ free(cp);
+ continue;
+ }
+#ifdef PC98
+ if (!strcasecmp(*cmds, "create") && ncmd == 7) {
+#else
+ if (!strcasecmp(*cmds,"create") && ncmd == 6) {
+#endif
+
+ printf("Create=%d\n",
+ Create_Chunk(d,
+ strtol(cmds[1], 0, 0),
+ strtol(cmds[2], 0, 0),
+ strtol(cmds[3], 0, 0),
+ strtol(cmds[4], 0, 0),
+#ifdef PC98
+ strtol(cmds[5], 0, 0), cmds[6]));
+#else
+ strtol(cmds[5], 0, 0), NULL));
+#endif
+ continue;
+ }
+ if (!strcasecmp(*cmds,"read")) {
+ db = d;
+ if (ncmd > 1)
+ d = Open_Disk(cmds[1]);
+ else
+ d = Open_Disk(argv[1]);
+ if (d)
+ Free_Disk(db);
+ else
+ d = db;
+ continue;
+ }
+ if (!strcasecmp(*cmds,"scan")) {
+ Scan_Disk(d);
+ continue;
+ }
+#ifndef PC98
+ if (!strcasecmp(*cmds,"bteasy")) {
+ Set_Boot_Mgr(d, bteasy17, sizeof (bteasy17));
+ continue;
+ }
+ if (!strcasecmp(*cmds, "mbr")) {
+ Set_Boot_Mgr(d, mbrboot, sizeof (mbrboot));
+ continue;
+ }
+#endif
+#if 0 /* XXX boot1 undefined, fix me */
+ if (!strcasecmp(*cmds, "boot")) {
+ Set_Boot_Blocks(d, boot1, boot2);
+ continue;
+ }
+#endif
+ if (!strcasecmp(*cmds, "write")) {
+ printf("Write=%d\n",
+ Write_Disk(d));
+ Free_Disk(d);
+ d = Open_Disk(argv[1]);
+ continue;
+ }
+ if (strcasecmp(*cmds, "help"))
+ printf("\007ERROR\n");
+ printf("CMDS:\n");
+ printf("\tallfreebsd\n");
+ printf("\tdedicate\n");
+ printf("\tbios cyl hd sect\n");
+ printf("\tboot\n");
+#ifndef PC98
+ printf("\tbteasy17\n");
+#endif
+#if 0
+ printf("\tcollapse [pointer]\n");
+#endif
+#ifdef PC98
+ printf("\tcreate offset size enum subtype flags name\n");
+#else
+ printf("\tcreate offset size enum subtype flags\n");
+#endif
+ printf("\t\tsubtype(part): swap=1, ffs=7\n");
+ printf("\tdelete pointer\n");
+ printf("\tlist\n");
+#ifndef PC98
+ printf("\tmbr\n");
+#endif
+#if 0
+ printf("\tphys cyl hd sect\n");
+#endif
+ printf("\tquit\n");
+ printf("\tread [disk]\n");
+ printf("\tscan\n");
+ printf("\twrite\n");
+ printf("\nENUM:\n\t");
+#if 0
+ for (i = 0; chunk_n[i]; i++)
+ printf("%d = %s%s", i, chunk_n[i],
+ i == 4 ? "\n\t" : " ");
+#endif
+ printf("\n");
+
+ }
+ exit (0);
+}
diff --git a/lib/libdisk/write_amd64_disk.c b/lib/libdisk/write_amd64_disk.c
new file mode 100644
index 0000000..9899258
--- /dev/null
+++ b/lib/libdisk/write_amd64_disk.c
@@ -0,0 +1,204 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/disklabel.h>
+#include <sys/diskmbr.h>
+#include <paths.h>
+#include "libdisk.h"
+
+/*
+ * XXX: A lot of hardcoded 512s probably should be foo->sector_size;
+ * I'm not sure which, so I leave it like it worked before. --schweikh
+ */
+static int
+Write_FreeBSD(int fd, const struct disk *new, const struct chunk *c1)
+{
+ struct disklabel *dl;
+ int i;
+ void *p;
+ u_char buf[BBSIZE];
+
+ for (i = 0; i < BBSIZE/512; i++) {
+ if (!(p = read_block(fd, i + c1->offset, 512)))
+ return (1);
+ memcpy(buf + 512 * i, p, 512);
+ free(p);
+ }
+ if (new->boot1)
+ memcpy(buf, new->boot1, 512);
+
+ if (new->boot2)
+ memcpy(buf + 512, new->boot2, BBSIZE - 512);
+
+ dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
+ Fill_Disklabel(dl, new, c1);
+
+ for (i = 0; i < BBSIZE / 512; i++)
+ write_block(fd, i + c1->offset, buf + 512 * i, 512);
+
+ return 0;
+}
+
+static void
+Write_Int32(u_int32_t *p, u_int32_t v)
+{
+ u_int8_t *bp = (u_int8_t *)p;
+
+ bp[0] = (v >> 0) & 0xff;
+ bp[1] = (v >> 8) & 0xff;
+ bp[2] = (v >> 16) & 0xff;
+ bp[3] = (v >> 24) & 0xff;
+}
+
+/*
+ * Special install-time configuration for the i386 boot0 boot manager.
+ */
+static void
+Cfg_Boot_Mgr(u_char *mbr, int edd)
+{
+
+ if (mbr[0x1b0] == 0x66 && mbr[0x1b1] == 0xbb) {
+ if (edd)
+ mbr[0x1bb] |= 0x80; /* Packet mode on */
+ else
+ mbr[0x1bb] &= 0x7f; /* Packet mode off */
+ }
+}
+
+int
+Write_Disk(const struct disk *d1)
+{
+ int fd, j;
+ uint i;
+ struct chunk *c1;
+ int ret = 0;
+ char device[64];
+ u_char *mbr;
+ struct dos_partition *dp,work[NDOSPART];
+ int s[4];
+ int need_edd = 0; /* Need EDD (packet interface) */
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d1->name);
+
+ fd = open(device, O_RDWR);
+ if (fd < 0)
+ return 1;
+
+ memset(s, 0, sizeof s);
+ if (!(mbr = read_block(fd, 0, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ dp = (struct dos_partition *)(mbr + DOSPARTOFF);
+ memcpy(work, dp, sizeof work);
+ dp = work;
+ free(mbr);
+ for (c1 = d1->chunks->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ if (!strcmp(c1->name, "X"))
+ continue;
+ j = c1->name[strlen(d1->name) + 1] - '1';
+ if (j < 0 || j > 3)
+ continue;
+ s[j]++;
+ if (c1->type == freebsd)
+ ret += Write_FreeBSD(fd, d1, c1);
+
+ Write_Int32(&dp[j].dp_start, c1->offset);
+ Write_Int32(&dp[j].dp_size, c1->size);
+
+ i = c1->offset;
+ if (i >= 1024 * d1->bios_sect * d1->bios_hd) {
+ dp[j].dp_ssect = 0xff;
+ dp[j].dp_shd = 0xff;
+ dp[j].dp_scyl = 0xff;
+ need_edd++;
+ } else {
+ dp[j].dp_ssect = i % d1->bios_sect;
+ i -= dp[j].dp_ssect++;
+ i /= d1->bios_sect;
+ dp[j].dp_shd = i % d1->bios_hd;
+ i -= dp[j].dp_shd;
+ i /= d1->bios_hd;
+ dp[j].dp_scyl = i;
+ i -= dp[j].dp_scyl;
+ dp[j].dp_ssect |= i >> 2;
+ }
+#ifdef DEBUG
+ printf("S:%lu = (%x/%x/%x)", c1->offset,
+ dp[j].dp_scyl, dp[j].dp_shd, dp[j].dp_ssect);
+#endif
+
+ i = c1->end;
+ dp[j].dp_esect = i % d1->bios_sect;
+ i -= dp[j].dp_esect++;
+ i /= d1->bios_sect;
+ dp[j].dp_ehd = i % d1->bios_hd;
+ i -= dp[j].dp_ehd;
+ i /= d1->bios_hd;
+ if (i > 1023)
+ i = 1023;
+ dp[j].dp_ecyl = i;
+ i -= dp[j].dp_ecyl;
+ dp[j].dp_esect |= i >> 2;
+#ifdef DEBUG
+ printf(" E:%lu = (%x/%x/%x)\n", c1->end,
+ dp[j].dp_ecyl, dp[j].dp_ehd, dp[j].dp_esect);
+#endif
+
+ dp[j].dp_typ = c1->subtype;
+ if (c1->flags & CHUNK_ACTIVE)
+ dp[j].dp_flag = 0x80;
+ else
+ dp[j].dp_flag = 0;
+ }
+ j = 0;
+ for (i = 0; i < NDOSPART; i++) {
+ if (!s[i])
+ memset(dp + i, 0, sizeof *dp);
+ if (dp[i].dp_flag)
+ j++;
+ }
+ if (!j)
+ for(i = 0; i < NDOSPART; i++)
+ if (dp[i].dp_typ == 0xa5)
+ dp[i].dp_flag = 0x80;
+
+ if (!(mbr = read_block(fd, 0, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ if (d1->bootmgr) {
+ memcpy(mbr, d1->bootmgr, DOSPARTOFF);
+ Cfg_Boot_Mgr(mbr, need_edd);
+ }
+ memcpy(mbr + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
+ mbr[512-2] = 0x55;
+ mbr[512-1] = 0xaa;
+ write_block(fd, 0, mbr, d1->sector_size);
+ if (d1->bootmgr && d1->bootmgr_size > d1->sector_size)
+ for (i = 1; i * d1->sector_size <= d1->bootmgr_size; i++)
+ write_block(fd, i, &d1->bootmgr[i * d1->sector_size],
+ d1->sector_size);
+
+ close(fd);
+ return 0;
+}
diff --git a/lib/libdisk/write_arm_disk.c b/lib/libdisk/write_arm_disk.c
new file mode 100644
index 0000000..5dbb0ad
--- /dev/null
+++ b/lib/libdisk/write_arm_disk.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2006 Olivier Houchard
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <paths.h>
+#include "libdisk.h"
+
+int
+Write_Disk(const struct disk *d1)
+{
+ return (0);
+}
diff --git a/lib/libdisk/write_disk.c b/lib/libdisk/write_disk.c
new file mode 100644
index 0000000..024981b
--- /dev/null
+++ b/lib/libdisk/write_disk.c
@@ -0,0 +1,76 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <paths.h>
+#include "libdisk.h"
+
+void
+Fill_Disklabel(struct disklabel *dl, const struct disk *new,
+ const struct chunk *c1)
+{
+ struct chunk *c2;
+ int j;
+
+ memset(dl, 0, sizeof *dl);
+
+ for (c2 = c1->part; c2; c2 = c2->next) {
+ if (c2->type == unused)
+ continue;
+ if (!strcmp(c2->name, "X"))
+ continue;
+ j = c2->name[strlen(c2->name) - 1] - 'a';
+ if (j < 0 || j >= MAXPARTITIONS || j == RAW_PART)
+ continue;
+ dl->d_partitions[j].p_size = c2->size;
+ dl->d_partitions[j].p_offset = c2->offset;
+ dl->d_partitions[j].p_fstype = c2->subtype;
+ }
+
+ dl->d_bbsize = BBSIZE;
+ /*
+ * Add in defaults for superblock size, interleave, and rpms
+ */
+ dl->d_sbsize = 0;
+
+ strcpy(dl->d_typename, c1->name);
+
+ dl->d_secsize = 512;
+ dl->d_secperunit = new->chunks->size;
+#ifndef __ia64__
+ dl->d_ncylinders = new->bios_cyl;
+ dl->d_ntracks = new->bios_hd;
+ dl->d_nsectors = new->bios_sect;
+#endif
+ dl->d_secpercyl = dl->d_ntracks * dl->d_nsectors;
+
+ dl->d_npartitions = MAXPARTITIONS;
+
+ dl->d_type = new->name[0] == 's' || new->name[0] == 'd' ||
+ new->name[0] == 'o' ? DTYPE_SCSI : DTYPE_ESDI;
+ dl->d_partitions[RAW_PART].p_size = c1->size;
+ dl->d_partitions[RAW_PART].p_offset = c1->offset;
+ dl->d_rpm = 3600;
+ dl->d_interleave = 1;
+
+ dl->d_magic = DISKMAGIC;
+ dl->d_magic2 = DISKMAGIC;
+ dl->d_checksum = dkcksum(dl);
+}
diff --git a/lib/libdisk/write_i386_disk.c b/lib/libdisk/write_i386_disk.c
new file mode 100644
index 0000000..15317d3
--- /dev/null
+++ b/lib/libdisk/write_i386_disk.c
@@ -0,0 +1,204 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/disklabel.h>
+#include <sys/diskmbr.h>
+#include <paths.h>
+#include "libdisk.h"
+
+/*
+ * XXX: A lot of hardcoded 512s probably should be foo->sector_size;
+ * I'm not sure which, so I leave it like it worked before. --schweikh
+ */
+static int
+Write_FreeBSD(int fd, const struct disk *new, const struct chunk *c1)
+{
+ struct disklabel *dl;
+ int i;
+ void *p;
+ u_char buf[BBSIZE];
+
+ for (i = 0; i < BBSIZE/512; i++) {
+ if (!(p = read_block(fd, i + c1->offset, 512)))
+ return (1);
+ memcpy(buf + 512 * i, p, 512);
+ free(p);
+ }
+ if (new->boot1)
+ memcpy(buf, new->boot1, 512);
+
+ if (new->boot2)
+ memcpy(buf + 512, new->boot2, BBSIZE - 512);
+
+ dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
+ Fill_Disklabel(dl, new, c1);
+
+ for (i = 0; i < BBSIZE / 512; i++)
+ write_block(fd, i + c1->offset, buf + 512 * i, 512);
+
+ return 0;
+}
+
+static void
+Write_Int32(u_int32_t *p, u_int32_t v)
+{
+ u_int8_t *bp = (u_int8_t *)p;
+
+ bp[0] = (v >> 0) & 0xff;
+ bp[1] = (v >> 8) & 0xff;
+ bp[2] = (v >> 16) & 0xff;
+ bp[3] = (v >> 24) & 0xff;
+}
+
+/*
+ * Special install-time configuration for the i386 boot0 boot manager.
+ */
+static void
+Cfg_Boot_Mgr(u_char *mbrblk, int edd)
+{
+
+ if (mbrblk[0x1b0] == 0x66 && mbrblk[0x1b1] == 0xbb) {
+ if (edd)
+ mbrblk[0x1bb] |= 0x80; /* Packet mode on */
+ else
+ mbrblk[0x1bb] &= 0x7f; /* Packet mode off */
+ }
+}
+
+int
+Write_Disk(const struct disk *d1)
+{
+ int fd, j;
+ uint i;
+ struct chunk *c1;
+ int ret = 0;
+ char device[64];
+ u_char *mbrblk;
+ struct dos_partition *dp,work[NDOSPART];
+ int s[4];
+ int need_edd = 0; /* Need EDD (packet interface) */
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d1->name);
+
+ fd = open(device, O_RDWR);
+ if (fd < 0)
+ return 1;
+
+ memset(s, 0, sizeof s);
+ if (!(mbrblk = read_block(fd, 0, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ dp = (struct dos_partition *)(mbrblk + DOSPARTOFF);
+ memcpy(work, dp, sizeof work);
+ dp = work;
+ free(mbrblk);
+ for (c1 = d1->chunks->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ if (!strcmp(c1->name, "X"))
+ continue;
+ j = c1->name[strlen(d1->name) + 1] - '1';
+ if (j < 0 || j > 3)
+ continue;
+ s[j]++;
+ if (c1->type == freebsd)
+ ret += Write_FreeBSD(fd, d1, c1);
+
+ Write_Int32(&dp[j].dp_start, c1->offset);
+ Write_Int32(&dp[j].dp_size, c1->size);
+
+ i = c1->offset;
+ if (i >= 1024 * d1->bios_sect * d1->bios_hd) {
+ dp[j].dp_ssect = 0xff;
+ dp[j].dp_shd = 0xff;
+ dp[j].dp_scyl = 0xff;
+ need_edd++;
+ } else {
+ dp[j].dp_ssect = i % d1->bios_sect;
+ i -= dp[j].dp_ssect++;
+ i /= d1->bios_sect;
+ dp[j].dp_shd = i % d1->bios_hd;
+ i -= dp[j].dp_shd;
+ i /= d1->bios_hd;
+ dp[j].dp_scyl = i;
+ i -= dp[j].dp_scyl;
+ dp[j].dp_ssect |= i >> 2;
+ }
+#ifdef DEBUG
+ printf("S:%lu = (%x/%x/%x)", c1->offset,
+ dp[j].dp_scyl, dp[j].dp_shd, dp[j].dp_ssect);
+#endif
+
+ i = c1->end;
+ dp[j].dp_esect = i % d1->bios_sect;
+ i -= dp[j].dp_esect++;
+ i /= d1->bios_sect;
+ dp[j].dp_ehd = i % d1->bios_hd;
+ i -= dp[j].dp_ehd;
+ i /= d1->bios_hd;
+ if (i > 1023)
+ i = 1023;
+ dp[j].dp_ecyl = i;
+ i -= dp[j].dp_ecyl;
+ dp[j].dp_esect |= i >> 2;
+#ifdef DEBUG
+ printf(" E:%lu = (%x/%x/%x)\n", c1->end,
+ dp[j].dp_ecyl, dp[j].dp_ehd, dp[j].dp_esect);
+#endif
+
+ dp[j].dp_typ = c1->subtype;
+ if (c1->flags & CHUNK_ACTIVE)
+ dp[j].dp_flag = 0x80;
+ else
+ dp[j].dp_flag = 0;
+ }
+ j = 0;
+ for (i = 0; i < NDOSPART; i++) {
+ if (!s[i])
+ memset(dp + i, 0, sizeof *dp);
+ if (dp[i].dp_flag)
+ j++;
+ }
+ if (!j)
+ for(i = 0; i < NDOSPART; i++)
+ if (dp[i].dp_typ == 0xa5)
+ dp[i].dp_flag = 0x80;
+
+ if (!(mbrblk = read_block(fd, 0, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ if (d1->bootmgr) {
+ memcpy(mbrblk, d1->bootmgr, DOSPARTOFF);
+ Cfg_Boot_Mgr(mbrblk, need_edd);
+ }
+ memcpy(mbrblk + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
+ mbrblk[512-2] = 0x55;
+ mbrblk[512-1] = 0xaa;
+ write_block(fd, 0, mbrblk, d1->sector_size);
+ if (d1->bootmgr && d1->bootmgr_size > d1->sector_size)
+ for (i = 1; i * d1->sector_size <= d1->bootmgr_size; i++)
+ write_block(fd, i, &d1->bootmgr[i * d1->sector_size],
+ d1->sector_size);
+
+ close(fd);
+ return 0;
+}
diff --git a/lib/libdisk/write_ia64_disk.c b/lib/libdisk/write_ia64_disk.c
new file mode 100644
index 0000000..6a57322
--- /dev/null
+++ b/lib/libdisk/write_ia64_disk.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2003 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * CRC32 code derived from work by Gary S. Brown.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/disklabel.h>
+#include <sys/diskmbr.h>
+#include <sys/gpt.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <uuid.h>
+
+#include "libdisk.h"
+
+static uuid_t _efi = GPT_ENT_TYPE_EFI;
+static uuid_t _fbsd = GPT_ENT_TYPE_FREEBSD;
+static uuid_t _swap = GPT_ENT_TYPE_FREEBSD_SWAP;
+static uuid_t _ufs = GPT_ENT_TYPE_FREEBSD_UFS;
+
+static uint32_t crc32_tab[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+static uint32_t
+crc32(const void *buf, size_t size)
+{
+ const uint8_t *p;
+ uint32_t crc;
+
+ p = buf;
+ crc = ~0U;
+
+ while (size--)
+ crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+
+ return (crc ^ ~0U);
+}
+
+static int
+write_pmbr(int fd, const struct disk *disk)
+{
+ struct dos_partition dp;
+ char *buffer;
+ u_long nsects;
+ int error;
+
+ error = 0;
+ nsects = disk->media_size / disk->sector_size;
+ nsects--; /* The GPT starts at LBA 1 */
+
+ buffer = calloc(disk->sector_size, 1);
+ if (buffer == NULL)
+ return (ENOMEM);
+ buffer[DOSMAGICOFFSET] = DOSMAGIC & 0xff;
+ buffer[DOSMAGICOFFSET + 1] = DOSMAGIC >> 8;
+
+ dp.dp_flag = 0;
+ dp.dp_shd = dp.dp_ssect = dp.dp_scyl = 0xff;
+ dp.dp_typ = DOSPTYP_PMBR;
+ dp.dp_ehd = dp.dp_esect = dp.dp_ecyl = 0xff;
+ dp.dp_start = 1;
+ dp.dp_size = (nsects > 0xffffffffu) ? ~0u : nsects;
+ memcpy(buffer + DOSPARTOFF, &dp, DOSPARTSIZE);
+
+ if (lseek(fd, 0L, SEEK_SET) != 0L ||
+ write(fd, buffer, disk->sector_size) != disk->sector_size)
+ error = (errno) ? errno : EAGAIN;
+
+ free(buffer);
+ return (error);
+}
+
+static int
+read_gpt(int fd, const struct disk *disk, struct gpt_hdr *hdr,
+ struct gpt_ent *tbl)
+{
+ char *buffer;
+ off_t off;
+ size_t nsects, sz;
+ int error, i;
+
+ error = 0;
+ nsects = disk->gpt_size * sizeof(struct gpt_ent) / disk->sector_size;
+ nsects++;
+ sz = nsects * disk->sector_size;
+ buffer = malloc(sz);
+ if (buffer == NULL)
+ return (ENOMEM);
+
+ if (lseek(fd, disk->sector_size, SEEK_SET) != disk->sector_size ||
+ read(fd, buffer, disk->sector_size) != disk->sector_size) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ if (memcmp(buffer, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0) {
+ /*
+ * No GPT on disk. Create one out of thin air.
+ */
+ bzero(&hdr[0], sizeof(struct gpt_hdr));
+ memcpy(hdr[0].hdr_sig, GPT_HDR_SIG, sizeof(hdr[0].hdr_sig));
+ hdr[0].hdr_revision = GPT_HDR_REVISION;
+ hdr[0].hdr_size = offsetof(struct gpt_hdr, padding);
+ hdr[0].hdr_lba_self = 1;
+ hdr[0].hdr_lba_alt = disk->media_size / disk->sector_size - 1L;
+ hdr[0].hdr_lba_start = disk->lba_start;
+ hdr[0].hdr_lba_end = disk->lba_end;
+ uuid_create(&hdr[0].hdr_uuid, NULL);
+ hdr[0].hdr_lba_table = 2;
+ hdr[0].hdr_entries = disk->gpt_size;
+ hdr[0].hdr_entsz = sizeof(struct gpt_ent);
+ hdr[1] = hdr[0];
+ hdr[1].hdr_lba_self = hdr[0].hdr_lba_alt;
+ hdr[1].hdr_lba_alt = hdr[0].hdr_lba_self;
+ hdr[1].hdr_lba_table = disk->lba_end + 1;
+
+ for (i = 0; i < disk->gpt_size; i++) {
+ bzero(&tbl[i], sizeof(struct gpt_ent));
+ uuid_create(&tbl[i].ent_uuid, NULL);
+ }
+
+ goto bail;
+ }
+
+ /*
+ * We have a GPT on disk. Read it.
+ */
+ memcpy(&hdr[0], buffer, sizeof(struct gpt_hdr));
+ off = hdr->hdr_lba_table * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ read(fd, buffer, sz) != sz) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ memcpy(tbl, buffer, sizeof(struct gpt_ent) * disk->gpt_size);
+ off = hdr->hdr_lba_alt * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ read(fd, buffer, disk->sector_size) != disk->sector_size) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ memcpy(&hdr[1], buffer, sizeof(struct gpt_hdr));
+
+bail:
+ free(buffer);
+ return (error);
+}
+
+static int
+update_gpt(int fd, const struct disk *disk, struct gpt_hdr *hdr,
+ struct gpt_ent *tbl)
+{
+ struct gpt_ent *save;
+ char *buffer;
+ struct chunk *c;
+ off_t off;
+ size_t bufsz;
+ int error, idx, sav;
+
+ error = 0;
+
+ /*
+ * Save the entries of those chunks that have an index. They are
+ * the ones that exist on disk already.
+ */
+ sav = 0;
+ for (c = disk->chunks->part; c != NULL; c = c->next) {
+ if ((c->flags & CHUNK_HAS_INDEX))
+ sav++;
+ }
+ if (sav > 0) {
+ save = malloc(sav * sizeof(struct gpt_ent));
+ if (save == NULL)
+ abort();
+ sav = 0;
+ for (c = disk->chunks->part; c != NULL; c = c->next) {
+ if ((c->flags & CHUNK_HAS_INDEX)) {
+ idx = CHUNK_FTOI(c->flags);
+ save[sav] = tbl[idx];
+ c->flags ^= CHUNK_ITOF(idx);
+ c->flags |= CHUNK_ITOF(sav);
+ sav++;
+ }
+ }
+ } else
+ save = NULL;
+
+ /*
+ * Clear the table entries.
+ */
+ for (idx = 0; idx < disk->gpt_size; idx++) {
+ uuid_create_nil(&tbl[idx].ent_type, NULL);
+ tbl[idx].ent_lba_start = 0;
+ tbl[idx].ent_lba_end = 0;
+ tbl[idx].ent_attr = 0;
+ bzero(tbl[idx].ent_name, sizeof(tbl[idx].ent_name));
+ }
+
+ /*
+ * Repopulate the table from the chunks, possibly using saved
+ * information.
+ */
+ idx = 0;
+ for (c = disk->chunks->part; c != NULL; c = c->next) {
+ if (!(c->flags & CHUNK_HAS_INDEX)) {
+ switch (c->type) {
+ case freebsd:
+ tbl[idx].ent_type = _fbsd;
+ break;
+ case efi:
+ tbl[idx].ent_type = _efi;
+ break;
+ case part:
+ switch (c->subtype) {
+ case FS_SWAP:
+ tbl[idx].ent_type = _swap;
+ break;
+ case FS_BSDFFS:
+ tbl[idx].ent_type = _ufs;
+ break;
+ default:
+ return (EINVAL);
+ }
+ break;
+ default:
+ return (EINVAL);
+ }
+ } else {
+ sav = CHUNK_FTOI(c->flags);
+ tbl[idx].ent_type = save[sav].ent_type;
+ memcpy(tbl[idx].ent_name, save[sav].ent_name,
+ sizeof(tbl[idx].ent_name));
+ }
+ tbl[idx].ent_lba_start = c->offset;
+ tbl[idx].ent_lba_end = c->end;
+
+ idx++;
+ if (idx == disk->gpt_size)
+ return (ENOSPC);
+ }
+ if (save != NULL)
+ free(save);
+
+ hdr[0].hdr_crc_table = crc32(tbl,
+ disk->gpt_size * sizeof(struct gpt_ent));
+ hdr[0].hdr_crc_self = 0;
+ hdr[0].hdr_crc_self = crc32(&hdr[0], hdr[0].hdr_size);
+
+ hdr[1].hdr_crc_table = hdr[0].hdr_crc_table;
+ hdr[1].hdr_crc_self = 0;
+ hdr[1].hdr_crc_self = crc32(&hdr[1], hdr[1].hdr_size);
+
+ /*
+ * Write the new GPT back to the disk.
+ */
+ bufsz = disk->gpt_size * sizeof(struct gpt_ent);
+ if (bufsz == 0 || bufsz % disk->sector_size)
+ bufsz += disk->sector_size;
+ bufsz = (bufsz / disk->sector_size) * disk->sector_size;
+ buffer = calloc(1, bufsz);
+
+ memcpy(buffer, &hdr[0], sizeof(struct gpt_hdr));
+ off = hdr[0].hdr_lba_self * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ write(fd, buffer, disk->sector_size) != disk->sector_size) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ memcpy(buffer, &hdr[1], sizeof(struct gpt_hdr));
+ off = hdr[1].hdr_lba_self * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ write(fd, buffer, disk->sector_size) != disk->sector_size) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ memcpy(buffer, tbl, disk->gpt_size * sizeof(struct gpt_ent));
+ off = hdr[0].hdr_lba_table * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ write(fd, buffer, bufsz) != bufsz) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+ off = hdr[1].hdr_lba_table * disk->sector_size;
+ if (lseek(fd, off, SEEK_SET) != off ||
+ write(fd, buffer, bufsz) != bufsz) {
+ error = (errno) ? errno : EAGAIN;
+ goto bail;
+ }
+
+bail:
+ free(buffer);
+ return (error);
+}
+
+int
+Write_Disk(const struct disk *disk)
+{
+ char devname[64];
+ struct gpt_hdr *hdr;
+ struct gpt_ent *tbl;
+ int error, fd;
+
+ hdr = malloc(sizeof(struct gpt_hdr) * 2);
+ if (hdr == NULL)
+ return (ENOMEM);
+ tbl = malloc(sizeof(struct gpt_ent) * disk->gpt_size);
+ if (tbl == NULL) {
+ free(hdr);
+ return (ENOMEM);
+ }
+
+ snprintf(devname, sizeof(devname), "%s%s", _PATH_DEV, disk->name);
+ fd = open(devname, O_RDWR);
+ if (fd == -1) {
+ free(tbl);
+ free(hdr);
+ return (errno);
+ }
+
+ /*
+ * We can always write the PMBR, because we reject disks that do not
+ * have a PMBR and are not virgin.
+ */
+ error = write_pmbr(fd, disk);
+ if (error)
+ goto bail;
+
+ /*
+ * Read the existing GPT from disk or otherwise create one out of
+ * thin air. This way we can preserve the UUIDs and the entry names
+ * when updating it.
+ */
+ error = read_gpt(fd, disk, hdr, tbl);
+ if (error)
+ goto bail;
+
+ /*
+ * Update and write the in-memory copy of the GPT.
+ */
+ error = update_gpt(fd, disk, hdr, tbl);
+
+bail:
+ close(fd);
+ free(tbl);
+ free(hdr);
+ return (error);
+}
diff --git a/lib/libdisk/write_pc98_disk.c b/lib/libdisk/write_pc98_disk.c
new file mode 100644
index 0000000..8f2a45d
--- /dev/null
+++ b/lib/libdisk/write_pc98_disk.c
@@ -0,0 +1,179 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/diskpc98.h>
+#include <paths.h>
+#include "libdisk.h"
+
+/*
+ * XXX: A lot of hardcoded 512s probably should be foo->sector_size;
+ * I'm not sure which, so I leave it like it worked before. --schweikh
+ */
+static int
+Write_FreeBSD(int fd, const struct disk *new, const struct chunk *c1)
+{
+ struct disklabel *dl;
+ int i;
+ void *p;
+ u_char buf[BBSIZE];
+
+ for (i = 0; i < BBSIZE / 512; i++) {
+ if (!(p = read_block(fd, i + c1->offset, 512)))
+ return (1);
+ memcpy(buf + 512 * i, p, 512);
+ free(p);
+ }
+ if (new->boot1)
+ memcpy(buf, new->boot1, 512);
+
+ if (new->boot2)
+ memcpy(buf + 512, new->boot2, BBSIZE - 512);
+
+ dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
+ Fill_Disklabel(dl, new, c1);
+
+ for (i = 0; i < BBSIZE / 512; i++)
+ write_block(fd, i + c1->offset, buf + 512 * i, 512);
+
+ return 0;
+}
+
+
+int
+Write_Disk(const struct disk *d1)
+{
+ int fd, i, j;
+ struct chunk *c1;
+ int ret = 0;
+ char device[64];
+ u_char *mbrblk;
+ struct pc98_partition *dp, work[NDOSPART];
+ int s[7];
+ int PC98_EntireDisk = 0;
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d1->name);
+
+ /* XXX - for entire FreeBSD(98) */
+ for (c1 = d1->chunks->part; c1; c1 = c1->next) {
+ if ((c1->type == freebsd) || (c1->offset == 0))
+ device[9] = 0;
+ }
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+#ifdef DEBUG
+ warn("open(%s) failed", device);
+#endif
+ return 1;
+ }
+
+ memset(s, 0, sizeof s);
+ if (!(mbrblk = read_block(fd, 1, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ dp = (struct pc98_partition *)(mbrblk + DOSPARTOFF);
+ memcpy(work, dp, sizeof work);
+ dp = work;
+ free(mbrblk);
+ for (c1 = d1->chunks->part; c1; c1 = c1->next) {
+ if (c1->type == unused)
+ continue;
+ if (!strcmp(c1->name, "X"))
+ continue;
+ j = c1->name[strlen(d1->name) + 1] - '1';
+ if (j < 0 || j > 7)
+ continue;
+ s[j]++;
+ if (c1->type == freebsd)
+ ret += Write_FreeBSD(fd, d1, c1);
+
+ i = c1->offset;
+ dp[j].dp_ssect = dp[j].dp_ipl_sct = i % d1->bios_sect;
+ i -= dp[j].dp_ssect;
+ i /= d1->bios_sect;
+ dp[j].dp_shd = dp[j].dp_ipl_head = i % d1->bios_hd;
+ i -= dp[j].dp_shd;
+ i /= d1->bios_hd;
+ dp[j].dp_scyl = dp[j].dp_ipl_cyl = i;
+#ifdef DEBUG
+ printf("S:%lu = (%x/%x/%x)", c1->offset,
+ dp[j].dp_scyl, dp[j].dp_shd, dp[j].dp_ssect);
+#endif
+
+ i = c1->end;
+#if 1
+ dp[j].dp_esect = dp[j].dp_ehd = 0;
+ dp[j].dp_ecyl = i / (d1->bios_sect * d1->bios_hd);
+#else
+ dp[j].dp_esect = i % d1->bios_sect;
+ i -= dp[j].dp_esect;
+ i /= d1->bios_sect;
+ dp[j].dp_ehd = i % d1->bios_hd;
+ i -= dp[j].dp_ehd;
+ i /= d1->bios_hd;
+ dp[j].dp_ecyl = i;
+#endif
+#ifdef DEBUG
+ printf(" E:%lu = (%x/%x/%x)\n", c1->end,
+ dp[j].dp_ecyl, dp[j].dp_ehd, dp[j].dp_esect);
+#endif
+
+ dp[j].dp_mid = c1->subtype & 0xff;
+ dp[j].dp_sid = c1->subtype >> 8;
+ if (c1->flags & CHUNK_ACTIVE)
+ dp[j].dp_mid |= 0x80;
+
+ strncpy(dp[j].dp_name, c1->sname, 16);
+ }
+ j = 0;
+ for (i = 0; i < NDOSPART; i++) {
+ if (!s[i])
+ memset(dp + i, 0, sizeof *dp);
+ }
+
+ if (d1->bootipl)
+ write_block(fd, 0, d1->bootipl, d1->sector_size);
+
+ if (!(mbrblk = read_block(fd, 1, d1->sector_size))) {
+ close (fd);
+ return (1);
+ }
+ memcpy(mbrblk + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
+ /* XXX - for entire FreeBSD(98) */
+ for (c1 = d1->chunks->part; c1; c1 = c1->next)
+ if (((c1->type == freebsd) || (c1->type == fat))
+ && (c1->offset == 0))
+ PC98_EntireDisk = 1;
+ if (PC98_EntireDisk == 0)
+ write_block(fd, 1, mbrblk, d1->sector_size);
+
+ if (d1->bootmenu)
+ for (i = 0; i * d1->sector_size < d1->bootmenu_size; i++)
+ write_block(fd, 2 + i,
+ &d1->bootmenu[i * d1->sector_size],
+ d1->sector_size);
+
+ close(fd);
+ return 0;
+}
diff --git a/lib/libdisk/write_powerpc_disk.c b/lib/libdisk/write_powerpc_disk.c
new file mode 100644
index 0000000..ec955e2
--- /dev/null
+++ b/lib/libdisk/write_powerpc_disk.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2004 Suleiman Souhlal.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <paths.h>
+#include "libdisk.h"
+
+int
+Write_Disk(const struct disk *d1)
+{
+ /*
+ * We don't have to write any label, so we only check that we can
+ * open the disk.
+ */
+ int fd;
+ char device[64];
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d1->name);
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ close(fd);
+ return 1;
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/lib/libdisk/write_sparc64_disk.c b/lib/libdisk/write_sparc64_disk.c
new file mode 100644
index 0000000..9832b0d
--- /dev/null
+++ b/lib/libdisk/write_sparc64_disk.c
@@ -0,0 +1,106 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <err.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/sun_disklabel.h>
+#include <paths.h>
+#include <errno.h>
+#include "libdisk.h"
+
+#include "geom_sunlabel_enc.c"
+
+int
+Write_Disk(const struct disk *d1)
+{
+ struct sun_disklabel *sl;
+ struct chunk *c, *c1, *c2;
+ int i;
+ char *p;
+ u_long secpercyl;
+ char device[64];
+ u_char buf[SUN_SIZE];
+ int fd;
+
+ strcpy(device, _PATH_DEV);
+ strcat(device, d1->name);
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ warn("open(%s) failed", device);
+ return (1);
+ }
+
+ sl = calloc(sizeof *sl, 1);
+ c = d1->chunks;
+ c2 = c->part;
+ secpercyl = d1->bios_sect * d1->bios_hd;
+ sl->sl_pcylinders = c->size / secpercyl;
+ sl->sl_ncylinders = c2->size / secpercyl;
+ sl->sl_acylinders = sl->sl_pcylinders - sl->sl_ncylinders;
+ sl->sl_magic = SUN_DKMAGIC;
+ sl->sl_nsectors = d1->bios_sect;
+ sl->sl_ntracks = d1->bios_hd;
+ if (c->size > 4999 * 1024 * 2) {
+ sprintf(sl->sl_text, "FreeBSD%luG cyl %u alt %u hd %u sec %u",
+ (c->size + 1024 * 1024) / (2 * 1024 * 1024),
+ sl->sl_ncylinders, sl->sl_acylinders,
+ sl->sl_ntracks, sl->sl_nsectors);
+ } else {
+ sprintf(sl->sl_text, "FreeBSD%luM cyl %u alt %u hd %u sec %u",
+ (c->size + 1024) / (2 * 1024),
+ sl->sl_ncylinders, sl->sl_acylinders,
+ sl->sl_ntracks, sl->sl_nsectors);
+ }
+ sl->sl_interleave = 1;
+ sl->sl_sparespercyl = 0;
+ sl->sl_rpm = 3600;
+
+ for (c1 = c2->part; c1 != NULL; c1 = c1->next) {
+ p = c1->name;
+ p += strlen(p);
+ p--;
+ if (*p < 'a')
+ continue;
+ i = *p - 'a';
+ if (i >= SUN_NPART)
+ continue;
+ sl->sl_part[i].sdkp_cyloffset = c1->offset / secpercyl;
+ sl->sl_part[i].sdkp_nsectors = c1->size;
+ for (i = 1; i < 16; i++) {
+ write_block(fd, c1->offset + i, d1->boot1 + (i * 512),
+ 512);
+ }
+ }
+
+ /*
+ * We need to fill in the "RAW" partition as well. Emperical data
+ * seems to indicate that this covers the "obviously" visible part
+ * of the disk, ie: sl->sl_ncylinders.
+ */
+ sl->sl_part[SUN_RAWPART].sdkp_cyloffset = 0;
+ sl->sl_part[SUN_RAWPART].sdkp_nsectors = sl->sl_ncylinders * secpercyl;
+
+ memset(buf, 0, sizeof buf);
+ sunlabel_enc(buf, sl);
+ write_block(fd, 0, buf, sizeof buf);
+
+ close(fd);
+ return 0;
+}
OpenPOWER on IntegriCloud