open_disk.c revision 171734
165793Smsmith/*
265793Smsmith * ----------------------------------------------------------------------------
381150Sscottl * "THE BEER-WARE LICENSE" (Revision 42):
465793Smsmith * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
581082Sscottl * can do whatever you want with this stuff. If we meet some day, and you think
665793Smsmith * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
765793Smsmith * ----------------------------------------------------------------------------
865793Smsmith */
965793Smsmith
1065793Smsmith#include <sys/cdefs.h>
1165793Smsmith__FBSDID("$FreeBSD: head/lib/libdisk/open_disk.c 171734 2007-08-05 16:55:40Z rink $");
1265793Smsmith
1365793Smsmith#include <stdio.h>
1465793Smsmith#include <stdlib.h>
1565793Smsmith#include <unistd.h>
1665793Smsmith#include <fcntl.h>
1765793Smsmith#include <string.h>
1865793Smsmith#include <inttypes.h>
1965793Smsmith#include <err.h>
2065793Smsmith#include <sys/sysctl.h>
2165793Smsmith#include <sys/stdint.h>
2265793Smsmith#include <sys/types.h>
2365793Smsmith#include <sys/stat.h>
2465793Smsmith#include <sys/ioctl.h>
2565793Smsmith#include <sys/disklabel.h>
2665793Smsmith#include <sys/gpt.h>
2765793Smsmith#include <paths.h>
2865793Smsmith#include "libdisk.h"
2965793Smsmith
3065793Smsmith#include <ctype.h>
3165793Smsmith#include <errno.h>
3265793Smsmith#include <assert.h>
3365793Smsmith
3465793Smsmith#ifdef DEBUG
3565793Smsmith#define	DPRINT(x)	warn x
3665793Smsmith#define	DPRINTX(x)	warnx x
3765793Smsmith#else
3865793Smsmith#define	DPRINT(x)
3983114Sscottl#define	DPRINTX(x)
4065793Smsmith#endif
4165793Smsmith
4265793Smsmithstruct disk *
4365793SmsmithInt_Open_Disk(const char *name, char *conftxt)
4465793Smsmith{
4583114Sscottl	struct disk *d;
4665793Smsmith	int i, line = 1;
4765793Smsmith	char *p, *q, *r, *a, *b, *n, *t, *sn;
4865793Smsmith	daddr_t o, len, off;
4965793Smsmith	u_int l, s, ty, sc, hd, alt;
5065793Smsmith	daddr_t lo[10];
5165793Smsmith
5265793Smsmith	/*
5365793Smsmith	 * Locate the disk (by name) in our sysctl output
5465793Smsmith	 */
5565793Smsmith	for (p = conftxt; p != NULL && *p; p = strchr(p, '\n'), line++) {
5681082Sscottl		if (*p == '\n')
5781082Sscottl			p++;
5881082Sscottl		a = strsep(&p, " ");
5981082Sscottl		/* Skip anything not with index 0 */
6081082Sscottl		if (strcmp(a, "0"))
6181082Sscottl			continue;
6281082Sscottl
6381082Sscottl		/* Skip anything not a disk */
6481082Sscottl		a = strsep(&p, " ");
6581082Sscottl		if (strcmp(a, "DISK"))
6681082Sscottl			continue;
6781082Sscottl
6881082Sscottl		a = strsep(&p, " ");
6981082Sscottl		if (strcmp(a, name))
7081082Sscottl			continue;
7181082Sscottl		break;
7265793Smsmith	}
7365793Smsmith
7465793Smsmith	q = strchr(p, '\n');
7565793Smsmith	if (q != NULL)
7665793Smsmith		*q++ = '\0';
7765793Smsmith
7865793Smsmith	d = (struct disk *)calloc(sizeof *d, 1);
7965793Smsmith	if(d == NULL)
8065793Smsmith		return NULL;
8165793Smsmith
8265793Smsmith	d->name = strdup(name);
8365793Smsmith
8465793Smsmith	a = strsep(&p, " ");	/* length in bytes */
8583114Sscottl	len = strtoimax(a, &r, 0);
8683114Sscottl	if (*r) {
87103870Salfred		printf("libdisk: Int_Open_Disk(%s): can't parse length in line %d (r='%s')\n",
8865793Smsmith			name, line, r);
8965793Smsmith		return NULL;
9065793Smsmith	}
9165793Smsmith
9265793Smsmith	a = strsep(&p, " ");	/* sectorsize */
9365793Smsmith	s = strtoul(a, &r, 0);
9465793Smsmith	if (*r) {
9565793Smsmith		printf("libdisk: Int_Open_Disk(%s): can't parse sector size in line %d (r='%s')\n",
9665793Smsmith			name, line, r);
9783114Sscottl		return NULL;
9883114Sscottl	}
9965793Smsmith
10083114Sscottl	if (s == 0)
10183114Sscottl		return (NULL);
10283114Sscottl	d->sector_size = s;
10383114Sscottl	len /= s;	/* media size in number of sectors. */
10483114Sscottl
10583114Sscottl	if (Add_Chunk(d, 0, len, name, whole, 0, 0, "-")) {
10683114Sscottl		DPRINT(("Failed to add 'whole' chunk"));
10783114Sscottl	}
10883114Sscottl
109103870Salfred	/* Try to parse any fields after the sector size in the DISK entry line */
11065793Smsmith	for (;;) {
11165793Smsmith		a = strsep(&p, " ");
11265793Smsmith		if (a == NULL)
11365793Smsmith			break;
11465793Smsmith		b = strsep(&p, " ");
11565793Smsmith		o = strtoimax(b, &r, 0);
11665793Smsmith		if (*r) {
11765793Smsmith			printf("libdisk: Int_Open_Disk(%s): can't parse parameter '%s' in line %d (r='%s')\n",
11865793Smsmith				name, a, line, r);
11965793Smsmith			return NULL;
12065793Smsmith		}
12165793Smsmith		if (!strcmp(a, "hd"))
12265793Smsmith			d->bios_hd = o;
12365793Smsmith		else if (!strcmp(a, "sc"))
12465793Smsmith			d->bios_sect = o;
12565793Smsmith		else
12665793Smsmith			printf("libdisk: Int_Open_Disk(%s): unknown parameter '%s' with value '%s' in line %d, ignored\n",
12765793Smsmith				name, a, b, line);
12865793Smsmith	}
12965793Smsmith
13065793Smsmith	/*
131109088Sscottl	 * Calculate the number of cylinders this disk must have. If we have
132109088Sscottl	 * an obvious insanity, we set the number of cylinders to zero.
133103870Salfred	 */
13465793Smsmith	o = d->bios_hd * d->bios_sect;
13565793Smsmith	d->bios_cyl = (o != 0) ? len / o : 0;
13665793Smsmith
13765793Smsmith	p = q; line++; /* p is now the start of the line _after_ the DISK entry */
13865793Smsmith	lo[0] = 0;
13965793Smsmith
14083114Sscottl	for (; p != NULL && *p; p = q, line++) {
14183114Sscottl		sn = NULL;
14283114Sscottl		q = strchr(p, '\n');
14383114Sscottl		if (q != NULL)
14483114Sscottl			*q++ = '\0';
14583114Sscottl		a = strsep(&p, " ");	/* Index */
14683114Sscottl		/*
14783114Sscottl		 * If we find index 0 again, this means we've encountered another disk, so it's safe to assume this disk
14883114Sscottl		 * has been processed.
14983114Sscottl		 */
15083114Sscottl		if (!strcmp(a, "0"))
15183114Sscottl			break;
15283114Sscottl		l = strtoimax(a, &r, 0);
15383114Sscottl		if (*r) {
15483114Sscottl			printf("libdisk: Int_Open_Disk(%s): can't parse depth '%s' in line %d (r='%s')\n",
15583114Sscottl				name, a, line, r);
156103870Salfred			return NULL;
15765793Smsmith
15865793Smsmith		}
15965793Smsmith		t = strsep(&p, " ");	/* Type {SUN, BSD, MBR, PC98, GPT} */
16065793Smsmith		n = strsep(&p, " ");	/* name */
16183114Sscottl		a = strsep(&p, " ");	/* len */
16283114Sscottl		len = strtoimax(a, &r, 0);
163103870Salfred		if (*r) {
16465793Smsmith			printf("libdisk: Int_Open_Disk(%s): can't parse length '%s' in line %d (r='%s')\n",
16565793Smsmith				name, a, line, r);
16665793Smsmith			continue;
16765793Smsmith		}
16865793Smsmith		a = strsep(&p, " ");	/* secsize */
16983114Sscottl		s = strtoimax(a, &r, 0);
17083114Sscottl		if (*r) {
17165793Smsmith			printf("libdisk: Int_Open_Disk(%s): can't parse sector size '%s' in line %d (r='%s')\n",
17283114Sscottl				name, a, line, r);
17383114Sscottl			continue;
17483114Sscottl		}
17583114Sscottl		for (;;) {
17683114Sscottl			a = strsep(&p, " ");
17783114Sscottl			if (a == NULL)
17883114Sscottl				break;
17983114Sscottl			/* XXX: Slice name may include a space. */
18083114Sscottl			if (!strcmp(a, "sn")) {
18183114Sscottl				sn = p;
18283114Sscottl				break;
18383114Sscottl			}
18483114Sscottl			b = strsep(&p, " ");
18583114Sscottl			o = strtoimax(b, &r, 0);
18683114Sscottl			/* APPLE have ty as a string */
18783114Sscottl			if ((*r) && (strcmp(t, "APPLE") && strcmp(t, "GPT"))) {
18883114Sscottl				printf("libdisk: Int_Open_Disk(%s): can't parse parameter '%s' in line %d (r='%s')\n",
18983114Sscottl					name, a, line, r);
19083114Sscottl				break;
19183114Sscottl			}
19283114Sscottl			if (!strcmp(a, "o"))
19365793Smsmith				off = o;
19483114Sscottl			else if (!strcmp(a, "i"))
19583114Sscottl				i = o;
19683114Sscottl			else if (!strcmp(a, "ty"))
19783114Sscottl				ty = o;
19883114Sscottl			else if (!strcmp(a, "sc"))
19965793Smsmith				sc = o;
20083114Sscottl			else if (!strcmp(a, "hd"))
20183114Sscottl				hd = o;
20283114Sscottl			else if (!strcmp(a, "alt"))
203151086Sscottl				alt = o;
20465793Smsmith		}
20583114Sscottl
20683114Sscottl		/* PLATFORM POLICY BEGIN ----------------------------------- */
20765793Smsmith		if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2)
20883114Sscottl			continue;
20983114Sscottl		if (platform == p_sparc64 && !strcmp(t, "SUN") &&
210151086Sscottl		    d->chunks->part->part == NULL) {
211151086Sscottl			d->bios_hd = hd;
212151086Sscottl			d->bios_sect = sc;
213151086Sscottl			o = d->chunks->size / (hd * sc);
21465793Smsmith			o *= (hd * sc);
21583114Sscottl			o -= alt * hd * sc;
21683114Sscottl			if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
21783114Sscottl				DPRINT(("Failed to add 'freebsd' chunk"));
21883114Sscottl			}
21983114Sscottl		}
22083114Sscottl		if (platform == p_alpha && !strcmp(t, "BSD") &&
22183114Sscottl		    d->chunks->part->part == NULL) {
222151086Sscottl			if (Add_Chunk(d, 0, d->chunks->size, name, freebsd,
223206534Semaste				      0, 0, "-")) {
224151086Sscottl				DPRINT(("Failed to add 'freebsd' chunk"));
225151086Sscottl			}
226206534Semaste		}
227206534Semaste		if (!strcmp(t, "BSD") && i == RAW_PART)
228206534Semaste			continue;
229151086Sscottl		/* PLATFORM POLICY END ------------------------------------- */
230151086Sscottl
231151086Sscottl		off /= s;
232151086Sscottl		len /= s;
233151086Sscottl		off += lo[l - 1];
234151086Sscottl		lo[l] = off;
235206534Semaste		if (!strcmp(t, "SUN"))
236206534Semaste			i = Add_Chunk(d, off, len, n, part, 0, 0, 0);
23765793Smsmith		else if (!strncmp(t, "MBR", 3)) {
23865793Smsmith			switch (ty) {
23965793Smsmith			case 0xa5:
24065793Smsmith				i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0);
24165793Smsmith				break;
24265793Smsmith			case 0x01:
24365793Smsmith			case 0x04:
24465793Smsmith			case 0x06:
24565793Smsmith			case 0x0b:
24665793Smsmith			case 0x0c:
24765793Smsmith			case 0x0e:
24865793Smsmith				i = Add_Chunk(d, off, len, n, fat, ty, 0, 0);
24981082Sscottl				break;
25081082Sscottl			case 0xef:	/* EFI */
25181082Sscottl				i = Add_Chunk(d, off, len, n, efi, ty, 0, 0);
25281082Sscottl				break;
25381082Sscottl			default:
25481082Sscottl				i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0);
25581082Sscottl				break;
25681082Sscottl			}
25781082Sscottl		} else if (!strcmp(t, "BSD"))
25881082Sscottl			i = Add_Chunk(d, off, len, n, part, ty, 0, 0);
25981082Sscottl		else if (!strcmp(t, "PC98")) {
26081082Sscottl			switch (ty & 0x7f) {
26181082Sscottl			case 0x14:
26281082Sscottl				i = Add_Chunk(d, off, len, n, freebsd, ty, 0,
26381082Sscottl					      sn);
26481082Sscottl				break;
26581082Sscottl			case 0x20:
26681082Sscottl			case 0x21:
26781082Sscottl			case 0x22:
26881082Sscottl			case 0x23:
26981082Sscottl			case 0x24:
27081082Sscottl				i = Add_Chunk(d, off, len, n, fat, ty, 0, sn);
27165793Smsmith				break;
27265793Smsmith			default:
27365793Smsmith				i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn);
27465793Smsmith				break;
27565793Smsmith			}
27665793Smsmith		} else if (!strcmp(t, "GPT"))
27765793Smsmith			i = Add_Chunk(d, off, len, n, gpt, 0, 0, b);
27865793Smsmith		else if (!strcmp(t, "APPLE"))
27965793Smsmith			i = Add_Chunk(d, off, len, n, apple, 0, 0, sn);
28065793Smsmith		else
28165793Smsmith			; /* Ignore unknown classes. */
28265793Smsmith	}
28365793Smsmith	/* PLATFORM POLICY BEGIN ------------------------------------- */
28465793Smsmith	/* We have a chance to do things on a blank disk here */
28565793Smsmith	if (platform == p_sparc64 && d->chunks->part->part == NULL) {
286206534Semaste		hd = d->bios_hd;
28765793Smsmith		sc = d->bios_sect;
28865793Smsmith		o = d->chunks->size / (hd * sc);
28965793Smsmith		o *= (hd * sc);
29083114Sscottl		o -= 2 * hd * sc;
291109088Sscottl		if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
292151086Sscottl			DPRINT(("Failed to add 'freebsd' chunk"));
29383114Sscottl		}
294109088Sscottl	}
29583114Sscottl	/* PLATFORM POLICY END --------------------------------------- */
29683114Sscottl
29783114Sscottl	return (d);
29883114Sscottl	i = 0;
299109088Sscottl}
30083114Sscottl