open_disk.c revision 135145
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 */
9
10#include <sys/cdefs.h>
11__FBSDID("$FreeBSD: head/lib/libdisk/open_disk.c 135145 2004-09-13 11:28:54Z le $");
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <fcntl.h>
17#include <string.h>
18#include <inttypes.h>
19#include <err.h>
20#include <sys/sysctl.h>
21#include <sys/stdint.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <sys/ioctl.h>
25#include <sys/disklabel.h>
26#include <sys/gpt.h>
27#include <paths.h>
28#include "libdisk.h"
29
30#include <ctype.h>
31#include <errno.h>
32#include <assert.h>
33
34#ifdef DEBUG
35#define	DPRINT(x)	warn x
36#define	DPRINTX(x)	warnx x
37#else
38#define	DPRINT(x)
39#define	DPRINTX(x)
40#endif
41
42struct disk *
43Int_Open_Disk(const char *name, char *conftxt)
44{
45	struct disk *d;
46	int i;
47	char *p, *q, *r, *a, *b, *n, *t, *sn;
48	daddr_t o, len, off;
49	u_int l, s, ty, sc, hd, alt;
50	daddr_t lo[10];
51
52	for (p = conftxt; p != NULL && *p; p = strchr(p, '\n')) {
53		if (*p == '\n')
54			p++;
55		a = strsep(&p, " ");
56		if (strcmp(a, "0"))
57			continue;
58
59		a = strsep(&p, " ");
60		if (strcmp(a, "DISK"))
61			continue;
62
63		a = strsep(&p, " ");
64		if (strcmp(a, name))
65			continue;
66		break;
67	}
68
69	q = strchr(p, '\n');
70	if (q != NULL)
71		*q++ = '\0';
72
73	d = (struct disk *)calloc(sizeof *d, 1);
74	if(d == NULL)
75		return NULL;
76
77	d->name = strdup(name);
78
79	a = strsep(&p, " ");	/* length in bytes */
80	len = strtoimax(a, &r, 0);
81	if (*r) {
82		printf("BARF %d <%d>\n", __LINE__, *r);
83		exit (0);
84	}
85
86	a = strsep(&p, " ");	/* sectorsize */
87	s = strtoul(a, &r, 0);
88	if (*r) {
89		printf("BARF %d <%d>\n", __LINE__, *r);
90		exit (0);
91	}
92
93	if (s == 0)
94		return (NULL);
95	d->sector_size = s;
96	len /= s;	/* media size in number of sectors. */
97
98	if (Add_Chunk(d, 0, len, name, whole, 0, 0, "-")) {
99		DPRINT(("Failed to add 'whole' chunk"));
100	}
101
102	for (;;) {
103		a = strsep(&p, " ");
104		if (a == NULL)
105			break;
106		b = strsep(&p, " ");
107		o = strtoimax(b, &r, 0);
108		if (*r) {
109			printf("BARF %d <%d>\n", __LINE__, *r);
110			exit (0);
111		}
112		if (!strcmp(a, "hd"))
113			d->bios_hd = o;
114		else if (!strcmp(a, "sc"))
115			d->bios_sect = o;
116		else
117			printf("HUH ? <%s> <%s>\n", a, b);
118	}
119
120	/*
121	 * Calculate the number of cylinders this disk must have. If we have
122	 * an obvious insanity, we set the number of cylinders to zero.
123	 */
124	o = d->bios_hd * d->bios_sect;
125	d->bios_cyl = (o != 0) ? len / o : 0;
126
127	p = q;
128	lo[0] = 0;
129
130	for (; p != NULL && *p; p = q) {
131		if (sn)
132			sn = NULL;
133		q = strchr(p, '\n');
134		if (q != NULL)
135			*q++ = '\0';
136		a = strsep(&p, " ");	/* Index */
137		if (!strcmp(a, "0"))
138			break;
139		l = strtoimax(a, &r, 0);
140		if (*r) {
141			printf("BARF %d <%d>\n", __LINE__, *r);
142			exit (0);
143		}
144		t = strsep(&p, " ");	/* Type {SUN, BSD, MBR, PC98, GPT} */
145		n = strsep(&p, " ");	/* name */
146		a = strsep(&p, " ");	/* len */
147		len = strtoimax(a, &r, 0);
148		if (*r) {
149			printf("BARF %d <%d>\n", __LINE__, *r);
150			exit (0);
151		}
152		a = strsep(&p, " ");	/* secsize */
153		s = strtoimax(a, &r, 0);
154		if (*r) {
155			printf("BARF %d <%d>\n", __LINE__, *r);
156			exit (0);
157		}
158		for (;;) {
159			a = strsep(&p, " ");
160			if (a == NULL)
161				break;
162			/* XXX: Slice name may include a space. */
163			if (!strcmp(a, "sn")) {
164				sn = p;
165				break;
166			}
167			b = strsep(&p, " ");
168			o = strtoimax(b, &r, 0);
169			/* APPLE have ty as a string */
170			if ((*r) && strcmp(t, "APPLE")) {
171				printf("BARF %d <%d>\n", __LINE__, *r);
172				exit (0);
173			}
174			if (!strcmp(a, "o"))
175				off = o;
176			else if (!strcmp(a, "i"))
177				i = o;
178			else if (!strcmp(a, "ty"))
179				ty = o;
180			else if (!strcmp(a, "sc"))
181				sc = o;
182			else if (!strcmp(a, "hd"))
183				hd = o;
184			else if (!strcmp(a, "alt"))
185				alt = o;
186		}
187
188		/* PLATFORM POLICY BEGIN ----------------------------------- */
189		if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2)
190			continue;
191		if (platform == p_sparc64 && !strcmp(t, "SUN") &&
192		    d->chunks->part->part == NULL) {
193			d->bios_hd = hd;
194			d->bios_sect = sc;
195			o = d->chunks->size / (hd * sc);
196			o *= (hd * sc);
197			o -= alt * hd * sc;
198			if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
199				DPRINT(("Failed to add 'freebsd' chunk"));
200			}
201		}
202		if (platform == p_alpha && !strcmp(t, "BSD") &&
203		    d->chunks->part->part == NULL) {
204			if (Add_Chunk(d, 0, d->chunks->size, name, freebsd,
205				      0, 0, "-")) {
206				DPRINT(("Failed to add 'freebsd' chunk"));
207			}
208		}
209		if (!strcmp(t, "BSD") && i == RAW_PART)
210			continue;
211		/* PLATFORM POLICY END ------------------------------------- */
212
213		off /= s;
214		len /= s;
215		off += lo[l - 1];
216		lo[l] = off;
217		if (!strcmp(t, "SUN"))
218			i = Add_Chunk(d, off, len, n, part, 0, 0, 0);
219		else if (!strncmp(t, "MBR", 3)) {
220			switch (ty) {
221			case 0xa5:
222				i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0);
223				break;
224			case 0x01:
225			case 0x04:
226			case 0x06:
227			case 0x0b:
228			case 0x0c:
229			case 0x0e:
230				i = Add_Chunk(d, off, len, n, fat, ty, 0, 0);
231				break;
232			case 0xef:	/* EFI */
233				i = Add_Chunk(d, off, len, n, efi, ty, 0, 0);
234				break;
235			default:
236				i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0);
237				break;
238			}
239		} else if (!strcmp(t, "BSD"))
240			i = Add_Chunk(d, off, len, n, part, ty, 0, 0);
241		else if (!strcmp(t, "PC98")) {
242			switch (ty & 0x7f) {
243			case 0x14:
244				i = Add_Chunk(d, off, len, n, freebsd, ty, 0,
245					      sn);
246				break;
247			case 0x20:
248			case 0x21:
249			case 0x22:
250			case 0x23:
251			case 0x24:
252				i = Add_Chunk(d, off, len, n, fat, ty, 0, sn);
253				break;
254			default:
255				i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn);
256				break;
257			}
258		} else if (!strcmp(t, "GPT"))
259			i = Add_Chunk(d, off, len, n, ty, 0, 0, 0);
260		else if (!strcmp(t, "BDE"))
261			; /* nothing */
262		else if (!strcmp(t, "CCD"))
263			; /* nothing */
264		else if (!strcmp(t, "APPLE"))
265			i = Add_Chunk(d, off, len, n, apple, 0, 0, sn);
266		else if (!strcmp(t, "STRIPE"))
267			; /* nothing */
268		else if (strstr(t, "VINUM") != NULL)
269			; /* nothing */
270		else {
271			printf("BARF %d\n", __LINE__);
272			exit(0);
273		}
274	}
275	/* PLATFORM POLICY BEGIN ------------------------------------- */
276	/* We have a chance to do things on a blank disk here */
277	if (platform == p_sparc64 && d->chunks->part->part == NULL) {
278		hd = d->bios_hd;
279		sc = d->bios_sect;
280		o = d->chunks->size / (hd * sc);
281		o *= (hd * sc);
282		o -= 2 * hd * sc;
283		if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
284			DPRINT(("Failed to add 'freebsd' chunk"));
285		}
286	}
287	/* PLATFORM POLICY END --------------------------------------- */
288
289	return (d);
290	i = 0;
291}
292