diff options
Diffstat (limited to 'lib/libdisk')
-rw-r--r-- | lib/libdisk/Makefile | 47 | ||||
-rw-r--r-- | lib/libdisk/blocks.c | 50 | ||||
-rw-r--r-- | lib/libdisk/change.c | 132 | ||||
-rw-r--r-- | lib/libdisk/chunk.c | 595 | ||||
-rw-r--r-- | lib/libdisk/create_chunk.c | 296 | ||||
-rw-r--r-- | lib/libdisk/disk.c | 400 | ||||
-rw-r--r-- | lib/libdisk/libdisk.3 | 345 | ||||
-rw-r--r-- | lib/libdisk/libdisk.h | 364 | ||||
-rw-r--r-- | lib/libdisk/open_disk.c | 280 | ||||
-rw-r--r-- | lib/libdisk/open_ia64_disk.c | 273 | ||||
-rw-r--r-- | lib/libdisk/rules.c | 296 | ||||
-rw-r--r-- | lib/libdisk/tst01.c | 323 | ||||
-rw-r--r-- | lib/libdisk/write_amd64_disk.c | 204 | ||||
-rw-r--r-- | lib/libdisk/write_arm_disk.c | 47 | ||||
-rw-r--r-- | lib/libdisk/write_disk.c | 76 | ||||
-rw-r--r-- | lib/libdisk/write_i386_disk.c | 204 | ||||
-rw-r--r-- | lib/libdisk/write_ia64_disk.c | 423 | ||||
-rw-r--r-- | lib/libdisk/write_pc98_disk.c | 179 | ||||
-rw-r--r-- | lib/libdisk/write_powerpc_disk.c | 64 | ||||
-rw-r--r-- | lib/libdisk/write_sparc64_disk.c | 106 |
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; +} |