diff options
Diffstat (limited to 'lib/libdisk/open_disk.c')
| -rw-r--r-- | lib/libdisk/open_disk.c | 308 | 
1 files changed, 308 insertions, 0 deletions
diff --git a/lib/libdisk/open_disk.c b/lib/libdisk/open_disk.c new file mode 100644 index 000000000000..6ffe88d61a4e --- /dev/null +++ b/lib/libdisk/open_disk.c @@ -0,0 +1,308 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <inttypes.h> +#include <err.h> +#include <sys/sysctl.h> +#include <sys/stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/disklabel.h> +#include <sys/gpt.h> +#include <paths.h> +#include "libdisk.h" + +#include <ctype.h> +#include <errno.h> +#include <assert.h> + +#ifdef DEBUG +#define	DPRINT(x)	warn x +#define	DPRINTX(x)	warnx x +#else +#define	DPRINT(x) +#define	DPRINTX(x) +#endif + +struct disk * +Int_Open_Disk(const char *name, char *conftxt) +{ +	struct disk *d; +	int i, line = 1; +	char *p, *q, *r, *a, *b, *n, *t, *sn; +	daddr_t o, len, off; +	u_int l, s, ty, sc, hd, alt; +	daddr_t lo[10]; + +	/* +	 * Locate the disk (by name) in our sysctl output +	 */ +	for (p = conftxt; p != NULL && *p; p = strchr(p, '\n'), line++) { +		if (*p == '\n') +			p++; +		a = strsep(&p, " "); +		/* Skip anything not with index 0 */ +		if (strcmp(a, "0")) +			continue; + +		/* Skip anything not a disk */ +		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("libdisk: Int_Open_Disk(%s): can't parse length in line %d (r='%s')\n", +			name, line, r); +		return NULL; +	} + +	a = strsep(&p, " ");	/* sectorsize */ +	s = strtoul(a, &r, 0); +	if (*r) { +		printf("libdisk: Int_Open_Disk(%s): can't parse sector size in line %d (r='%s')\n", +			name, line, r); +		return NULL; +	} + +	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")); +	} + +	/* Try to parse any fields after the sector size in the DISK entry line */ +	for (;;) { +		a = strsep(&p, " "); +		if (a == NULL) +			break; +		b = strsep(&p, " "); +		o = strtoimax(b, &r, 0); +		if (*r) { +			printf("libdisk: Int_Open_Disk(%s): can't parse parameter '%s' in line %d (r='%s')\n", +				name, a, line, r); +			return NULL; +		} +		if (!strcmp(a, "hd")) +			d->bios_hd = o; +		else if (!strcmp(a, "sc")) +			d->bios_sect = o; +		else +			printf("libdisk: Int_Open_Disk(%s): unknown parameter '%s' with value '%s' in line %d, ignored\n", +				name, a, b, line); +	} + +	/* +	 * Calculate the number of cylinders this disk must have. If we have +	 * an obvious insanity, we set the number of cylinders to zero. +	 */ +	o = d->bios_hd * d->bios_sect; +	d->bios_cyl = (o != 0) ? len / o : 0; + +	p = q; line++; /* p is now the start of the line _after_ the DISK entry */ +	lo[0] = 0; + +	for (; p != NULL && *p; p = q, line++) { +		sn = NULL; +		q = strchr(p, '\n'); +		if (q != NULL) +			*q++ = '\0'; +		a = strsep(&p, " ");	/* Index */ +		/* +		 * If we find index 0 again, this means we've encountered another disk, so it's safe to assume this disk +		 * has been processed. +		 */ +		if (!strcmp(a, "0")) +			break; +		l = strtoimax(a, &r, 0); +		if (*r) { +			printf("libdisk: Int_Open_Disk(%s): can't parse depth '%s' in line %d (r='%s')\n", +				name, a, line, r); +			return NULL; + +		} +		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("libdisk: Int_Open_Disk(%s): can't parse length '%s' in line %d (r='%s')\n", +				name, a, line, r); +			continue; +		} +		a = strsep(&p, " ");	/* secsize */ +		s = strtoimax(a, &r, 0); +		if (*r) { +			printf("libdisk: Int_Open_Disk(%s): can't parse sector size '%s' in line %d (r='%s')\n", +				name, a, line, r); +			continue; +		} +		for (;;) { +			a = strsep(&p, " "); +			if (a == NULL) +				break; +			/* XXX: Slice name may include a space. */ +			if (!strcmp(a, "sn")) { +				sn = p; +				break; +			} +			b = strsep(&p, " "); +			o = strtoimax(b, &r, 0); +			/* APPLE have ty as a string */ +			if ((*r) && strcmp(t, "APPLE") && +			    strcmp(t, "GPT") && strcmp(t, "PART")) { +				printf("libdisk: Int_Open_Disk(%s): can't parse parameter '%s' in line %d (r='%s')\n", +					name, a, line, r); +				break; +			} +			if (!strcmp(a, "o")) +				off = o; +			else if (!strcmp(a, "i")) +				i = (!strcmp(t, "PART")) ? o - 1 : 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; +			else if (!strcmp(a, "xs")) +				t = b; +			else if (!strcmp(a, "xt")) { +				if (*r) +					sn = b; +				else +					ty = o; +			} +		} + +		/* PLATFORM POLICY BEGIN ----------------------------------- */ +		if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2) +			continue; +		if (platform == p_sparc64 && !strcmp(t, "SUN") && +		    d->chunks->part->part == NULL) { +			d->bios_hd = hd; +			d->bios_sect = sc; +			o = d->chunks->size / (hd * sc); +			o *= (hd * sc); +			o -= alt * hd * sc; +			if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) { +				DPRINT(("Failed to add 'freebsd' chunk")); +			} +		} +		if (platform == p_alpha && !strcmp(t, "BSD") && +		    d->chunks->part->part == NULL) { +			if (Add_Chunk(d, 0, d->chunks->size, name, freebsd, +				      0, 0, "-")) { +				DPRINT(("Failed to add 'freebsd' chunk")); +			} +		} +		if (!strcmp(t, "BSD") && i == RAW_PART) +			continue; +		/* PLATFORM POLICY END ------------------------------------- */ + +		off /= s; +		len /= s; +		off += lo[l - 1]; +		lo[l] = off; +		if (!strcmp(t, "SUN")) +			i = Add_Chunk(d, off, len, n, part, 0, 0, 0); +		else if (!strncmp(t, "MBR", 3)) { +			switch (ty) { +			case 0xa5: +				i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0); +				break; +			case 0x01: +			case 0x04: +			case 0x06: +			case 0x0b: +			case 0x0c: +			case 0x0e: +				i = Add_Chunk(d, off, len, n, fat, ty, 0, 0); +				break; +			case 0xef:	/* EFI */ +				i = Add_Chunk(d, off, len, n, efi, ty, 0, 0); +				break; +			default: +				i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0); +				break; +			} +		} else if (!strcmp(t, "BSD")) +			i = Add_Chunk(d, off, len, n, part, ty, 0, 0); +		else if (!strcmp(t, "PC98")) { +			switch (ty & 0x7f) { +			case 0x14: +				i = Add_Chunk(d, off, len, n, freebsd, ty, 0, +					      sn); +				break; +			case 0x20: +			case 0x21: +			case 0x22: +			case 0x23: +			case 0x24: +				i = Add_Chunk(d, off, len, n, fat, ty, 0, sn); +				break; +			default: +				i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn); +				break; +			} +		} else if (!strcmp(t, "GPT")) +			i = Add_Chunk(d, off, len, n, gpt, 0, 0, b); +		else if (!strcmp(t, "APPLE")) +			i = Add_Chunk(d, off, len, n, apple, 0, 0, sn); +		else +			; /* Ignore unknown classes. */ +	} +	/* PLATFORM POLICY BEGIN ------------------------------------- */ +	/* We have a chance to do things on a blank disk here */ +	if (platform == p_sparc64 && d->chunks->part->part == NULL) { +		hd = d->bios_hd; +		sc = d->bios_sect; +		o = d->chunks->size / (hd * sc); +		o *= (hd * sc); +		o -= 2 * hd * sc; +		if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) { +			DPRINT(("Failed to add 'freebsd' chunk")); +		} +	} +	/* PLATFORM POLICY END --------------------------------------- */ + +	return (d); +	i = 0; +}  | 
