diff options
Diffstat (limited to 'lib/libdisk')
-rw-r--r-- | lib/libdisk/Makefile | 34 | ||||
-rw-r--r-- | lib/libdisk/blocks.c | 50 | ||||
-rw-r--r-- | lib/libdisk/change.c | 109 | ||||
-rw-r--r-- | lib/libdisk/chunk.c | 559 | ||||
-rw-r--r-- | lib/libdisk/create_chunk.c | 263 | ||||
-rw-r--r-- | lib/libdisk/disk.c | 678 | ||||
-rw-r--r-- | lib/libdisk/libdisk.3 | 331 | ||||
-rw-r--r-- | lib/libdisk/libdisk.h | 349 | ||||
-rw-r--r-- | lib/libdisk/rules.c | 280 | ||||
-rw-r--r-- | lib/libdisk/tst01.c | 321 | ||||
-rw-r--r-- | lib/libdisk/write_alpha_disk.c | 85 | ||||
-rw-r--r-- | lib/libdisk/write_amd64_disk.c | 197 | ||||
-rw-r--r-- | lib/libdisk/write_disk.c | 74 | ||||
-rw-r--r-- | lib/libdisk/write_i386_disk.c | 197 | ||||
-rw-r--r-- | lib/libdisk/write_ia64_disk.c | 178 | ||||
-rw-r--r-- | lib/libdisk/write_pc98_disk.c | 172 | ||||
-rw-r--r-- | lib/libdisk/write_sparc64_disk.c | 106 |
17 files changed, 3983 insertions, 0 deletions
diff --git a/lib/libdisk/Makefile b/lib/libdisk/Makefile new file mode 100644 index 0000000..f3c560b --- /dev/null +++ b/lib/libdisk/Makefile @@ -0,0 +1,34 @@ +# $FreeBSD$ + +LIB= disk +SRCS= blocks.c chunk.c disk.c change.c \ + create_chunk.c rules.c write_disk.c write_${MACHINE}_disk.c +INCS= libdisk.h + +WARNS= 2 + +CFLAGS+= -I${.CURDIR}/../../sys/geom + +.if ${MACHINE} == "pc98" +CFLAGS+= -DPC98 +.endif + +CLEANFILES+= tmp.c tst01 tst01.o +NOPROFILE= yes +NOPIC= yes + +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..fa12ad9 --- /dev/null +++ b/lib/libdisk/change.c @@ -0,0 +1,109 @@ +/* + * ---------------------------------------------------------------------------- + * "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; + if (disk->bios_hd > 16) + 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... */ +#ifdef PC98 + /* Assume standard SCSI parameter */ + 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); +} + +void +All_FreeBSD(struct disk *d, int force_all) +{ + struct chunk *c; + int type; + +#ifdef PC98 + type = 0x494; +#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..e41796b --- /dev/null +++ b/lib/libdisk/chunk.c @@ -0,0 +1,559 @@ +/* + * ---------------------------------------------------------------------------- + * "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 <sys/types.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, u_long offset, u_long 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; + 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, u_long offset, u_long 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) { + 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, long offset, u_long size, const char *name, + chunk_e type, int subtype, u_long flags, const char *sname) +{ + struct chunk *c1, *c2, ct; + u_long 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 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; + 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(' '); + printf("%p %8ld %8lu %8lu %-8s %-16s %-8s 0x%02x %s", + c1, c1->offset, c1->size, 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; + u_long 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); + 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..d8e35e8 --- /dev/null +++ b/lib/libdisk/create_chunk.c @@ -0,0 +1,263 @@ +/* + * ---------------------------------------------------------------------------- + * "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" + +struct chunk *New_Chunk(void); + +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 + +int +Fixup_Names(struct disk *d) +{ + struct chunk *c1, *c2; +#if defined(__i386__) || defined(__ia64__) || defined(__amd64__) + struct chunk *c3; + int j; +#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; + for (j = 1; j <= NDOSPART; j++) { + sprintf(c2->oname, "%ss%d", c1->name, j); + 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); +#ifndef PC98 + else if (c2->type == extended) + Fixup_Extended_Names(c2); +#endif + } + return 0; +} + +int +Create_Chunk(struct disk *d, u_long offset, u_long size, chunk_e type, + int subtype, u_long flags, const char *sname) +{ + int i; + u_long l; + + if (!(flags & CHUNK_FORCE_ALL)) { +#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; + } + + 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, u_long size, + chunk_e type, int subtype, u_long flags) +{ + int i; + struct chunk *c1; + long offset; + + if (!parent) + parent = d->chunks; + + if (parent->type == freebsd && 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..c750c2b --- /dev/null +++ b/lib/libdisk/disk.c @@ -0,0 +1,678 @@ +/* + * ---------------------------------------------------------------------------- + * "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> + +#ifdef DEBUG +#define DPRINT(x) warn x +#define DPRINTX(x) warnx x +#else +#define DPRINT(x) +#define DPRINTX(x) +#endif + +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 +#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"); + default: return ("??"); + } +}; + +static chunk_e +uuid_type(uuid_t *uuid) +{ + 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 uuid_t _vinum = GPT_ENT_TYPE_FREEBSD_VINUM; + + if (uuid_is_nil(uuid, NULL)) + return (unused); + if (uuid_equal(uuid, &_efi, NULL)) + return (efi); + if (uuid_equal(uuid, &_mbr, NULL)) + return (mbr); + if (uuid_equal(uuid, &_fbsd, NULL)) + return (freebsd); + if (uuid_equal(uuid, &_swap, NULL)) + return (part); + if (uuid_equal(uuid, &_ufs, NULL)) + return (part); + if (uuid_equal(uuid, &_vinum, NULL)) + return (part); + return (spare); +} + +struct disk * +Open_Disk(const char *name) +{ + + return Int_Open_Disk(name); +} + +struct disk * +Int_Open_Disk(const char *name) +{ + uuid_t uuid; + char *conftxt = NULL; + struct disk *d; + size_t txtsize; + int error, i; + char *p, *q, *r, *a, *b, *n, *t, *sn; + off_t o, len, off; + u_int l, s, ty, sc, hd, alt; + off_t lo[10]; + + error = sysctlbyname("kern.geom.conftxt", NULL, &txtsize, NULL, 0); + if (error) { + warn("kern.geom.conftxt sysctl not available, giving up!"); + return (NULL); + } + conftxt = (char *) malloc(txtsize+1); + if (conftxt == NULL) { + DPRINT(("cannot malloc memory for conftxt")); + return (NULL); + } + error = sysctlbyname("kern.geom.conftxt", conftxt, &txtsize, NULL, 0); + if (error) { + DPRINT(("error reading kern.geom.conftxt from the system")); + free(conftxt); + return (NULL); + } + conftxt[txtsize] = '\0'; /* in case kernel bug is still there */ + + 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 = strtoul(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 cyclinders 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) { + 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); + if (*r) { + uint32_t status; + + uuid_from_string(b, &uuid, &status); + if (status != uuid_s_ok) { + printf("BARF %d <%d>\n", __LINE__, *r); + exit (0); + } + o = uuid_type(&uuid); + } + 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, ty, 0, 0, 0); + else if (!strcmp(t, "BDE")) + ; /* nothing */ + else { + printf("BARF %d\n", __LINE__); + exit(0); + } + } + /* 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; +} + +void +Debug_Disk(struct disk *d) +{ + + printf("Debug_Disk(%s)", d->name); +#if 0 + printf(" real_geom=%lu/%lu/%lu", + d->real_cyl, d->real_hd, d->real_sect); +#endif + 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); +#elif defined(__ia64__) + printf("\n"); +#else +/* Should be: error "Debug_Disk: unknown arch"; */ +#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) +{ + char *str1 = *(char**)a; + char *str2 = *(char**)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; + } + + 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) { + 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; +} + +#ifdef PC98 +const char * +slice_type_name( int type, int subtype ) +{ + + switch (type) { + case whole: + return "whole"; + case fat: + return "fat"; + case freebsd: + switch (subtype) { + case 0xc494: return "freebsd"; + default: return "unknown"; + } + case unused: + return "unused"; + default: + return "unknown"; + } +} +#else /* PC98 */ +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 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 166: return "OpenBSD FFS"; /* 0xA6 */ + case 169: return "NetBSD FFS"; /* 0xA9 */ + case 182: return "OpenBSD"; /* dedicated */ + case 183: return "bsd/os"; + case 184: return "bsd/os swap"; + case 238: return "EFI GPT"; + case 239: return "EFI Sys. Part."; + default: return "unknown"; + } + case fat: + return "fat"; + case freebsd: + switch (subtype) { + case 165: return "freebsd"; + default: return "unknown"; + } + case extended: + return "extended"; + case part: + return "part"; + case efi: + return "efi"; + case unused: + return "unused"; + default: + return "unknown"; + } +} +#endif /* PC98 */ diff --git a/lib/libdisk/libdisk.3 b/lib/libdisk/libdisk.3 new file mode 100644 index 0000000..6d088b3 --- /dev/null +++ b/lib/libdisk/libdisk.3 @@ -0,0 +1,331 @@ +.\" +.\" 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 March 15, 1996 +.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" "u_long offset" "u_long size" "chunk_e type" "int subtype" "u_long flags" +.Ft void +.Fn All_FreeBSD "struct disk *d" "int force_all" +.Ft char * +.Fn CheckRules "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 "struct disk *d" +.Ft int +.Fn Cyl_Aligned "struct disk *d" "u_long offset" +.Ft u_long +.Fn Next_Cyl_Aligned "struct disk *d" "u_long offset" +.Ft u_long +.Fn Prev_Cyl_Aligned "struct disk *d" "u_long offset" +.Ft int +.Fn Track_Aligned "struct disk *d" "u_long offset" +.Ft u_long +.Fn Next_Track_Aligned "struct disk *d" "u_long offset" +.Ft u_long +.Fn Prev_Track_Aligned "struct disk *d" "u_long offset" +.Ft struct chunk * +.Fn Create_Chunk_DWIM "struct disk *d" "struct chunk *parent" "u_long 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 +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; + long offset; + u_long size; + u_long 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 flag +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 +checks if +.Ql offset +is aligned on a 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 isn't 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..c988adc --- /dev/null +++ b/lib/libdisk/libdisk.h @@ -0,0 +1,349 @@ +/* +* ---------------------------------------------------------------------------- +* "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 +}; +extern const enum platform platform; + +typedef enum { + whole, + unknown, + + sun, + pc98, + mbr, + gpt, + + efi, + fat, + freebsd, + extended, + part, + spare, + unused +} chunk_e; + +__BEGIN_DECLS +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 +#if !defined(__ia64__) + u_char *bootmgr; + size_t bootmgr_size; +#endif +#endif +#if !defined(__ia64__) + u_char *boot1; +#endif +#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 */ +}; + +struct chunk { + struct chunk *next; + struct chunk *part; + struct disk *disk; + long offset; + u_long size; + u_long 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 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 *, u_long, u_long, 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 *, u_long, u_long, 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 */ + +u_long +Next_Cyl_Aligned(const struct disk *, u_long); +/* Round offset up to next cylinder according to the bios-geometry */ + +u_long +Prev_Cyl_Aligned(const struct disk *, u_long); +/* Round offset down to previous cylinder according to the bios-geometry */ + +int +Track_Aligned(const struct disk *, u_long); +/* Check if offset is aligned on a track according to the bios geometry */ + +u_long +Next_Track_Aligned(const struct disk *, u_long); +/* Round offset up to next track according to the bios-geometry */ + +u_long +Prev_Track_Aligned(const struct disk *, u_long); +/* Check if offset is aligned on a track according to the bios geometry */ + +struct chunk * +Create_Chunk_DWIM(struct disk *, struct chunk *, u_long, 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 *); +void Free_Chunk(struct chunk *); +struct chunk *Clone_Chunk(const struct chunk *); +int Add_Chunk(struct disk *, long, u_long, 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 *); +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/rules.c b/lib/libdisk/rules.c new file mode 100644 index 0000000..30e24a7 --- /dev/null +++ b/lib/libdisk/rules.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 <string.h> +#include <sys/types.h> +#include <sys/disklabel.h> +#ifdef PC98 +#include <sys/diskpc98.h> +#else +#include <sys/diskmbr.h> +#endif +#include "libdisk.h" + +int +Track_Aligned(const struct disk *d, u_long offset) +{ + + if (!d->bios_sect) + return 1; + if (offset % d->bios_sect) + return 0; + return 1; +} + +u_long +Prev_Track_Aligned(const struct disk *d, u_long offset) +{ + + if (!d->bios_sect) + return offset; + return (offset / d->bios_sect) * d->bios_sect; +} + +u_long +Next_Track_Aligned(const struct disk *d, u_long offset) +{ + + if (!d->bios_sect) + return offset; + return Prev_Track_Aligned(d, offset + d->bios_sect-1); +} + +static int +Cyl_Aligned(const struct disk *d, u_long offset) +{ + + if (!d->bios_sect || !d->bios_hd) + return 1; + if (offset % (d->bios_sect * d->bios_hd)) + return 0; + return 1; +} + +u_long +Prev_Cyl_Aligned(const struct disk *d, u_long offset) +{ + + if (!d->bios_sect || !d->bios_hd) + return offset; + return (offset / (d->bios_sect*d->bios_hd)) * d->bios_sect * d->bios_hd; +} + +u_long +Next_Cyl_Aligned(const struct disk *d, u_long offset) +{ + + if (!d->bios_sect || !d->bios_hd) + return offset; + return Prev_Cyl_Aligned(d,offset + (d->bios_sect * d->bios_hd) - 1); +} + +/* + * Rule#0: + * Chunks of type 'whole' can have max NDOSPART children. + * Only one of them can have the "active" flag + */ +static void +Rule_000(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' [%ld..%ld] does not start" + " on a cylinder boundary\n", +#else + "chunk '%s' [%ld..%ld] does not start" + " on a track boundary\n", +#endif + c1->name, c1->offset, c1->end); + if ((c->type == whole || c->end == c1->end) + || Cyl_Aligned(d, c1->end + 1)) + ; + else + sprintf(msg + strlen(msg), + "chunk '%s' [%ld..%ld] does not end" + " on a cylinder boundary\n", + c1->name, c1->offset, c1->end); + } +} + +/* + * Rule#2: + * Max one 'fat' as child of 'whole' + */ +static void +Rule_002(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(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(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..b260635 --- /dev/null +++ b/lib/libdisk/tst01.c @@ -0,0 +1,321 @@ +/* + * ---------------------------------------------------------------------------- + * "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; + } + 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; + } + 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_alpha_disk.c b/lib/libdisk/write_alpha_disk.c new file mode 100644 index 0000000..1e76c7c --- /dev/null +++ b/lib/libdisk/write_alpha_disk.c @@ -0,0 +1,85 @@ +/* + * ---------------------------------------------------------------------------- + * "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" + +/* + * 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 + */ +int +Write_Disk(const struct disk *d1) +{ + u_char buf[BBSIZE]; + char device[64]; + struct chunk *c1; + struct disklabel *dl; + void *p; + uint64_t *lp, sum; + int fd, i; + + strcpy(device, _PATH_DEV); + strcat(device, d1->name); + + fd = open(device, O_RDWR); + if (fd < 0) + return (1); + + c1 = d1->chunks->part; + if (!strcmp(c1->name, "X") || c1->type != freebsd) { + close (fd); + return (0); + } + + for (i = 0; i < BBSIZE/512; i++) { + p = read_block(fd, i + c1->offset, 512); + memcpy(buf + 512 * i, p, 512); + free(p); + } + if (d1->boot1) + memcpy(buf + 512, d1->boot1, BBSIZE - 512); + + dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET); + Fill_Disklabel(dl, d1, c1); + + /* + * Tell SRM where the bootstrap is. + */ + lp = (uint64_t *)buf; + lp[60] = (BBSIZE - 512) / 512; /* Length */ + lp[61] = 1; /* Start */ + lp[62] = 0; /* Flags */ + + /* + * Generate the bootblock checksum for the SRM console. + */ + sum = 0; + for (i = 0; i < 63; i++) + sum += lp[i]; + lp[63] = sum; + + for (i = 0; i < BBSIZE / 512; i++) + write_block(fd, i + c1->offset, buf + 512 * i, 512); + close(fd); + + return (0); +} diff --git a/lib/libdisk/write_amd64_disk.c b/lib/libdisk/write_amd64_disk.c new file mode 100644 index 0000000..f409ae4 --- /dev/null +++ b/lib/libdisk/write_amd64_disk.c @@ -0,0 +1,197 @@ +/* + * ---------------------------------------------------------------------------- + * "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++) { + p = read_block(fd, i + c1->offset, 512); + 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); + mbr = read_block(fd, 0, d1->sector_size); + 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; + + mbr = read_block(fd, 0, d1->sector_size); + 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_disk.c b/lib/libdisk/write_disk.c new file mode 100644 index 0000000..8c2aa54 --- /dev/null +++ b/lib/libdisk/write_disk.c @@ -0,0 +1,74 @@ +/* + * ---------------------------------------------------------------------------- + * "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; + dl->d_ncylinders = new->bios_cyl; + dl->d_ntracks = new->bios_hd; + dl->d_nsectors = new->bios_sect; + 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..f409ae4 --- /dev/null +++ b/lib/libdisk/write_i386_disk.c @@ -0,0 +1,197 @@ +/* + * ---------------------------------------------------------------------------- + * "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++) { + p = read_block(fd, i + c1->offset, 512); + 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); + mbr = read_block(fd, 0, d1->sector_size); + 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; + + mbr = read_block(fd, 0, d1->sector_size); + 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_ia64_disk.c b/lib/libdisk/write_ia64_disk.c new file mode 100644 index 0000000..33113e1 --- /dev/null +++ b/lib/libdisk/write_ia64_disk.c @@ -0,0 +1,178 @@ +/* + * ---------------------------------------------------------------------------- + * "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++) { + p = read_block(fd, i + c1->offset, 512); + if (p == NULL) + return (1); + memcpy(buf + 512 * i, p, 512); + free(p); + } + + dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET); + Fill_Disklabel(dl, new, c1); + + for (i = 0; i < BBSIZE / 512; i++) { + if (write_block(fd, i + c1->offset, buf + 512 * i, 512) != 0) + return (1); + } + + 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; +} + +int +Write_Disk(const struct disk *d1) +{ + struct chunk *c1; + char device[64]; + u_char *mbr; + struct dos_partition *dp, work[NDOSPART]; + int s[4]; + int fd, i, j, ret; + + strcpy(device, _PATH_DEV); + strcat(device, d1->name); + + fd = open(device, O_RDWR); + if (fd < 0) + return (1); + + memset(s, 0, sizeof(s)); + mbr = read_block(fd, 0, 512); + if (mbr == NULL) + goto fail; + dp = (struct dos_partition *)(mbr + DOSPARTOFF); + memcpy(work, dp, sizeof(work)); + dp = work; + free(mbr); + + ret = 0; + for (c1 = d1->chunks->part; c1; c1 = c1->next) { + if (c1->type == unused || !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 = 1024 * d1->bios_sect * d1->bios_hd; + if (i == 0 || c1->offset >= i) { + /* Start */ + dp[j].dp_ssect = 0xff; + dp[j].dp_shd = 0xff; + dp[j].dp_scyl = 0xff; + + /* End */ + dp[j].dp_esect = 0xff; + dp[j].dp_ehd = 0xff; + dp[j].dp_ecyl = 0xff; + } else { + /* Start */ + i = c1->offset; + 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; + + /* End */ + 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; + dp[j].dp_ecyl = i; + i -= dp[j].dp_ecyl; + dp[j].dp_esect |= i >> 2; + } +#ifdef DEBUG + printf("S:%lu = (%x/%x/%x) E:%lu = (%x/%x/%x)\n", c1->offset, + dp[j].dp_scyl, dp[j].dp_shd, dp[j].dp_ssect, 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; + } + + for (i = 0; i < NDOSPART; i++) { + if (!s[i]) + memset(dp + i, 0, sizeof(*dp)); + } + + mbr = read_block(fd, 0, d1->sector_size); + if (mbr == NULL) + goto fail; + memcpy(mbr + DOSPARTOFF, dp, sizeof(*dp) * NDOSPART); + mbr[512-2] = 0x55; + mbr[512-1] = 0xaa; + ret += write_block(fd, 0, mbr, 512); + free(mbr); + if (ret != 0) + goto fail; + + close(fd); + return (0); + + fail: + close(fd); + return (1); +} diff --git a/lib/libdisk/write_pc98_disk.c b/lib/libdisk/write_pc98_disk.c new file mode 100644 index 0000000..c6bb687 --- /dev/null +++ b/lib/libdisk/write_pc98_disk.c @@ -0,0 +1,172 @@ +/* + * ---------------------------------------------------------------------------- + * "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++) { + p = read_block(fd, i + c1->offset, 512); + 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 *mbr; + 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); + mbr = read_block(fd, 1, d1->sector_size); + dp = (struct pc98_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 > 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); + + mbr = read_block(fd, 1, d1->sector_size); + memcpy(mbr + 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, mbr, 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_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; +} |