diff --git a/lib/libdisk/Makefile b/lib/libdisk/Makefile index f3c560b9d2e0..762c904d9ac9 100644 --- a/lib/libdisk/Makefile +++ b/lib/libdisk/Makefile @@ -1,8 +1,15 @@ # $FreeBSD$ +.if ${MACHINE_ARCH} == "ia64" +_open_disk= open_ia64_disk.c +.else +_change = change.c +_open_disk= open_disk.c +.endif + LIB= disk -SRCS= blocks.c chunk.c disk.c change.c \ - create_chunk.c rules.c write_disk.c write_${MACHINE}_disk.c +SRCS= blocks.c ${_change} chunk.c create_chunk.c disk.c ${_open_disk} \ + rules.c write_disk.c write_${MACHINE}_disk.c INCS= libdisk.h WARNS= 2 diff --git a/lib/libdisk/create_chunk.c b/lib/libdisk/create_chunk.c index d8e35e8ce232..fb3daecd2dd6 100644 --- a/lib/libdisk/create_chunk.c +++ b/lib/libdisk/create_chunk.c @@ -140,7 +140,7 @@ Fixup_Names(struct disk *d) struct chunk *c1, *c2; #if defined(__i386__) || defined(__ia64__) || defined(__amd64__) struct chunk *c3; - int j; + int j, max; #endif c1 = d->chunks; @@ -153,8 +153,14 @@ Fixup_Names(struct disk *d) c2->oname = malloc(12); if (!c2->oname) return -1; - for (j = 1; j <= NDOSPART; j++) { - sprintf(c2->oname, "%ss%d", c1->name, j); +#ifdef __ia64__ + max = d->gpt_size; +#else + max = NDOSPART; +#endif + for (j = 1; j <= max; j++) { + sprintf(c2->oname, "%s%c%d", c1->name, + (c1->type == whole) ? 'p' : 's', j); for (c3 = c1->part; c3; c3 = c3->next) if (c3 != c2 && !strcmp(c3->name, c2->oname)) goto match; @@ -188,9 +194,10 @@ 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; - + +#ifndef __ia64__ if (!(flags & CHUNK_FORCE_ALL)) { + u_long l; #ifdef PC98 /* Never use the first cylinder */ if (!offset) { @@ -209,6 +216,7 @@ Create_Chunk(struct disk *d, u_long offset, u_long size, chunk_e type, l = (offset+size) % (d->bios_sect * d->bios_hd); size -= l; } +#endif i = Add_Chunk(d, offset, size, "X", type, subtype, flags, sname); Fixup_Names(d); diff --git a/lib/libdisk/disk.c b/lib/libdisk/disk.c index 6690fba90e8f..42eea97d0736 100644 --- a/lib/libdisk/disk.c +++ b/lib/libdisk/disk.c @@ -33,14 +33,6 @@ __FBSDID("$FreeBSD$"); #include #include -#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 @@ -81,303 +73,32 @@ chunk_name(chunk_e type) } }; -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; + char *conftxt; 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]; + int error; error = sysctlbyname("kern.geom.conftxt", NULL, &txtsize, NULL, 0); if (error) { warn("kern.geom.conftxt sysctl not available, giving up!"); return (NULL); } - conftxt = (char *) malloc(txtsize+1); + conftxt = malloc(txtsize+1); if (conftxt == NULL) { - DPRINT(("cannot malloc memory for conftxt")); + warn("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")); + warn("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 if (!strcmp(t, "CCD")) - ; /* 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; + return Int_Open_Disk(name, conftxt); } void @@ -385,10 +106,8 @@ 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 + +#ifndef __ia64__ printf(" bios_geom=%lu/%lu/%lu = %lu\n", d->bios_cyl, d->bios_hd, d->bios_sect, d->bios_cyl * d->bios_hd * d->bios_sect); @@ -401,11 +120,14 @@ Debug_Disk(struct disk *d) #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 +#else /* __ia64__ */ + printf(" media size=%lu, sector size=%lu\n", d->media_size, + d->sector_size); +#endif + Debug_Chunk(d->chunks); } diff --git a/lib/libdisk/libdisk.h b/lib/libdisk/libdisk.h index cc6b2fdc5a51..ac97d898b791 100644 --- a/lib/libdisk/libdisk.h +++ b/lib/libdisk/libdisk.h @@ -51,6 +51,7 @@ typedef enum { } chunk_e; __BEGIN_DECLS +#ifndef __ia64__ struct disk { char *name; u_long bios_cyl; @@ -62,20 +63,27 @@ struct disk { 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 */ }; +#else /* !__ia64__ */ +struct disk { + char *name; + struct chunk *chunks; + u_long media_size; + u_long sector_size; + u_long lba_start; + u_long lba_end; + u_int gpt_size; /* Number of entries */ +}; +#endif struct chunk { struct chunk *next; @@ -123,11 +131,13 @@ struct chunk { #define CHUNK_FORCE_ALL 0x0040 #define CHUNK_AUTO_SIZE 0x0080 #define CHUNK_NEWFS 0x0100 +#define CHUNK_HAS_INDEX 0x0200 +#define CHUNK_ITOF(i) ((i & 0xFFFF) << 16) +#define CHUNK_FTOI(f) ((f >> 16) & 0xFFFF) #define DELCHUNK_NORMAL 0x0000 #define DELCHUNK_RECOVER 0x0001 - const char *chunk_name(chunk_e); const char * @@ -259,6 +269,7 @@ ShowChunkFlags(struct chunk *); */ struct disklabel; + void Fill_Disklabel(struct disklabel *, const struct disk *, const struct chunk *); void Debug_Chunk(struct chunk *); @@ -269,7 +280,7 @@ int Add_Chunk(struct disk *, long, u_long, const char *, chunk_e, int, u_long, 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 *); +struct disk *Int_Open_Disk(const char *, char *); int Fixup_Names(struct disk *); int MakeDevChunk(const struct chunk *, const char *); __END_DECLS diff --git a/lib/libdisk/open_disk.c b/lib/libdisk/open_disk.c new file mode 100644 index 000000000000..99abba500eeb --- /dev/null +++ b/lib/libdisk/open_disk.c @@ -0,0 +1,278 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libdisk.h" + +#include +#include +#include + +#ifdef DEBUG +#define DPRINT(x) warn x +#define DPRINTX(x) warnx x +#else +#define DPRINT(x) +#define DPRINTX(x) +#endif + +struct disk * +Int_Open_Disk(const char *name, char *conftxt) +{ + struct disk *d; + int i; + char *p, *q, *r, *a, *b, *n, *t, *sn; + off_t o, len, off; + u_int l, s, ty, sc, hd, alt; + off_t lo[10]; + + for (p = conftxt; p != NULL && *p; p = strchr(p, '\n')) { + if (*p == '\n') + p++; + a = strsep(&p, " "); + if (strcmp(a, "0")) + continue; + + a = strsep(&p, " "); + if (strcmp(a, "DISK")) + continue; + + a = strsep(&p, " "); + if (strcmp(a, name)) + continue; + break; + } + + q = strchr(p, '\n'); + if (q != NULL) + *q++ = '\0'; + + d = (struct disk *)calloc(sizeof *d, 1); + if(d == NULL) + return NULL; + + d->name = strdup(name); + + a = strsep(&p, " "); /* length in bytes */ + len = strtoimax(a, &r, 0); + if (*r) { + printf("BARF %d <%d>\n", __LINE__, *r); + exit (0); + } + + a = strsep(&p, " "); /* sectorsize */ + s = strtoul(a, &r, 0); + if (*r) { + printf("BARF %d <%d>\n", __LINE__, *r); + exit (0); + } + + if (s == 0) + return (NULL); + d->sector_size = s; + len /= s; /* media size in number of sectors. */ + + if (Add_Chunk(d, 0, len, name, whole, 0, 0, "-")) + DPRINT(("Failed to add 'whole' chunk")); + + for (;;) { + a = strsep(&p, " "); + if (a == NULL) + break; + b = strsep(&p, " "); + o = 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) { + printf("BARF %d <%d>\n", __LINE__, *r); + exit (0); + } + if (!strcmp(a, "o")) + off = o; + else if (!strcmp(a, "i")) + i = o; + else if (!strcmp(a, "ty")) + ty = o; + else if (!strcmp(a, "sc")) + sc = o; + else if (!strcmp(a, "hd")) + hd = o; + else if (!strcmp(a, "alt")) + alt = o; + } + + /* PLATFORM POLICY BEGIN ----------------------------------- */ + if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2) + continue; + if (platform == p_sparc64 && !strcmp(t, "SUN") && + d->chunks->part->part == NULL) { + d->bios_hd = hd; + d->bios_sect = sc; + o = d->chunks->size / (hd * sc); + o *= (hd * sc); + o -= alt * hd * sc; + if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) + DPRINT(("Failed to add 'freebsd' chunk")); + } + if (platform == p_alpha && !strcmp(t, "BSD") && + d->chunks->part->part == NULL) { + if (Add_Chunk(d, 0, d->chunks->size, name, freebsd, + 0, 0, "-")) + DPRINT(("Failed to add 'freebsd' chunk")); + } + if (!strcmp(t, "BSD") && i == RAW_PART) + continue; + /* PLATFORM POLICY END ------------------------------------- */ + + off /= s; + len /= s; + off += lo[l - 1]; + lo[l] = off; + if (!strcmp(t, "SUN")) + i = Add_Chunk(d, off, len, n, part, 0, 0, 0); + else if (!strncmp(t, "MBR", 3)) { + switch (ty) { + case 0xa5: + i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0); + break; + case 0x01: + case 0x04: + case 0x06: + case 0x0b: + case 0x0c: + case 0x0e: + i = Add_Chunk(d, off, len, n, fat, ty, 0, 0); + break; + case 0xef: /* EFI */ + i = Add_Chunk(d, off, len, n, efi, ty, 0, 0); + break; + default: + i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0); + break; + } + } else if (!strcmp(t, "BSD")) + i = Add_Chunk(d, off, len, n, part, ty, 0, 0); + else if (!strcmp(t, "PC98")) { + switch (ty & 0x7f) { + case 0x14: + i = Add_Chunk(d, off, len, n, freebsd, ty, 0, + sn); + break; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + i = Add_Chunk(d, off, len, n, fat, ty, 0, sn); + break; + default: + i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn); + break; + } + } else if (!strcmp(t, "GPT")) + i = Add_Chunk(d, off, len, n, ty, 0, 0, 0); + else if (!strcmp(t, "BDE")) + ; /* nothing */ + else if (!strcmp(t, "CCD")) + ; /* 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; +} diff --git a/lib/libdisk/open_ia64_disk.c b/lib/libdisk/open_ia64_disk.c new file mode 100644 index 000000000000..019bf36b9f8a --- /dev/null +++ b/lib/libdisk/open_ia64_disk.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2003 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libdisk.h" + +static uuid_t _efi = GPT_ENT_TYPE_EFI; +static uuid_t _mbr = GPT_ENT_TYPE_MBR; +static uuid_t _fbsd = GPT_ENT_TYPE_FREEBSD; +static uuid_t _swap = GPT_ENT_TYPE_FREEBSD_SWAP; +static uuid_t _ufs = GPT_ENT_TYPE_FREEBSD_UFS; + +static struct disk * +parse_disk(char *conftxt, const char *name) +{ + char devname[64]; + struct disk *disk; + struct dos_partition *part; + struct gpt_hdr *gpt; + char *buffer, *p, *q; + int fd, i; + + disk = (struct disk *)calloc(sizeof *disk, 1); + if (disk == NULL) + return (NULL); + + disk->name = strdup(name); + p = strsep(&conftxt, " "); /* media size */ + disk->media_size = strtoimax(p, &q, 0); + if (*q) + goto fail; + + p = strsep(&conftxt, " "); /* sector size */ + disk->sector_size = strtoul(p, &q, 0); + if (*q) + goto fail; + + if (disk->sector_size == 0) + disk->sector_size = 512; + + if (disk->media_size % disk->sector_size) + goto fail; + + /* + * We need to read the disk to get GPT specific information. + */ + + snprintf(devname, sizeof(devname), "%s%s", _PATH_DEV, name); + fd = open(devname, O_RDONLY); + if (fd == -1) + goto fail; + buffer = malloc(2 * disk->sector_size); + if (buffer == NULL) { + close (fd); + goto fail; + } + if (read(fd, buffer, 2 * disk->sector_size) == -1) { + free(buffer); + close(fd); + goto fail; + } + close(fd); + + gpt = (struct gpt_hdr *)(buffer + disk->sector_size); + if (memcmp(gpt->hdr_sig, GPT_HDR_SIG, sizeof(gpt->hdr_sig))) { + /* + * No GPT present. Check if the MBR is empty (if present) + * or is a PMBR before declaring this disk as empty. If + * the MBR isn't empty, bail out. Let's not risk nuking a + * disk. + */ + if (*(u_short *)(buffer + DOSMAGICOFFSET) == DOSMAGIC) { + for (i = 0; i < 4; i++) { + part = (struct dos_partition *) + (buffer + DOSPARTOFF + i * DOSPARTSIZE); + if (part->dp_typ != 0 && + part->dp_typ != DOSPTYP_PMBR) + break; + } + if (i < 4) { + free(buffer); + goto fail; + } + } + disk->gpt_size = 128; + disk->lba_start = (disk->gpt_size * sizeof(struct gpt_ent)) / + disk->sector_size + 2; + disk->lba_end = (disk->media_size * disk->sector_size) - + disk->lba_start + 1; + } else { + disk->lba_start = gpt->hdr_lba_start; + disk->lba_end = gpt->hdr_lba_end; + disk->gpt_size = gpt->hdr_entries; + } + free(buffer); + Add_Chunk(disk, disk->lba_start, disk->lba_end - disk->lba_start + 1, + name, whole, 0, 0, "-"); + return (disk); + +fail: + free(disk->name); + free(disk); + return (NULL); +} + +struct disk * +Int_Open_Disk(const char *name, char *conftxt) +{ + struct chunk chunk; + uuid_t uuid; + struct disk *disk; + char *p, *q, *r, *s, *sd, *type; + u_long i; + uint32_t status; + + p = conftxt; + while (p != NULL && *p != 0) { + q = strsep(&p, " "); + if (strcmp(q, "0") == 0) { + q = strsep(&p, " "); + if (strcmp(q, "DISK") == 0) { + q = strsep(&p, " "); + if (strcmp(q, name) == 0) + break; + } + } + p = strchr(p, '\n'); + if (p != NULL && *p == '\n') + p++; + conftxt = p; + } + if (p == NULL || *p == 0) + return (NULL); + + conftxt = strchr(p, '\n'); + if (conftxt != NULL) + *conftxt++ = '\0'; + + disk = parse_disk(p, name); + if (disk == NULL) + return (NULL); + + while (conftxt != NULL && *conftxt != 0) { + p = conftxt; + conftxt = strchr(p, '\n'); + if (conftxt != NULL) + *conftxt++ = '\0'; + + sd = strsep(&p, " "); /* depth */ + if (strcmp(sd, "0") == 0) + break; + + type = strsep(&p, " "); /* type */ + chunk.name = strsep(&p, " "); /* name */ + q = strsep(&p, " "); /* length */ + i = strtoimax(q, &r, 0); + if (*r) + abort(); + chunk.end = i / disk->sector_size; + q = strsep(&p, " "); /* sector size */ + + for (;;) { + q = strsep(&p, " "); + if (q == NULL) + break; + r = strsep(&p, " "); + i = strtoimax(r, &s, 0); + if (*s) { + uuid_from_string(r, &uuid, &status); + if (status != uuid_s_ok) + abort(); + } else + status = uuid_s_invalid_string_uuid; + if (!strcmp(q, "o")) + chunk.offset = i / disk->sector_size; + else if (!strcmp(q, "i")) + chunk.flags = CHUNK_ITOF(i) | CHUNK_HAS_INDEX; + else if (!strcmp(q, "ty")) + chunk.subtype = i; + } + + if (strncmp(type, "MBR", 3) == 0) { + switch (chunk.subtype) { + case 0xa5: + chunk.type = freebsd; + break; + case 0x01: + case 0x04: + case 0x06: + case 0x0b: + case 0x0c: + case 0x0e: + chunk.type = fat; + break; + case 0xef: /* EFI */ + chunk.type = efi; + break; + default: + chunk.type = mbr; + break; + } + } else if (strcmp(type, "BSD") == 0) { + chunk.type = part; + } else if (strcmp(type, "GPT") == 0) { + chunk.subtype = 0; + if (status != uuid_s_ok) + abort(); + if (uuid_is_nil(&uuid, NULL)) + chunk.type = unused; + else if (uuid_equal(&uuid, &_efi, NULL)) + chunk.type = efi; + else if (uuid_equal(&uuid, &_mbr, NULL)) + chunk.type = unknown; + else if (uuid_equal(&uuid, &_fbsd, NULL)) { + chunk.type = freebsd; + chunk.subtype = 0xa5; + } else if (uuid_equal(&uuid, &_swap, NULL)) { + chunk.type = part; + chunk.subtype = FS_SWAP; + } else if (uuid_equal(&uuid, &_ufs, NULL)) { + chunk.type = part; + chunk.subtype = FS_BSDFFS; + } else + chunk.type = unknown; + } else + abort(); + + Add_Chunk(disk, chunk.offset, chunk.end, chunk.name, + chunk.type, chunk.subtype, chunk.flags, 0); + } + + return (disk); +}