open_disk.c revision 143306
1273929Sjmmv/*
2240116Smarcel * ----------------------------------------------------------------------------
3240116Smarcel * "THE BEER-WARE LICENSE" (Revision 42):
4240116Smarcel * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5240116Smarcel * can do whatever you want with this stuff. If we meet some day, and you think
6240116Smarcel * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7240116Smarcel * ----------------------------------------------------------------------------
8240116Smarcel */
9240116Smarcel
10240116Smarcel#include <sys/cdefs.h>
11240116Smarcel__FBSDID("$FreeBSD: head/lib/libdisk/open_disk.c 143306 2005-03-08 21:46:18Z stefanf $");
12240116Smarcel
13240116Smarcel#include <stdio.h>
14240116Smarcel#include <stdlib.h>
15240116Smarcel#include <unistd.h>
16240116Smarcel#include <fcntl.h>
17240116Smarcel#include <string.h>
18240116Smarcel#include <inttypes.h>
19240116Smarcel#include <err.h>
20240116Smarcel#include <sys/sysctl.h>
21240116Smarcel#include <sys/stdint.h>
22240116Smarcel#include <sys/types.h>
23240116Smarcel#include <sys/stat.h>
24273929Sjmmv#include <sys/ioctl.h>
25240116Smarcel#include <sys/disklabel.h>
26240116Smarcel#include <sys/gpt.h>
27240116Smarcel#include <paths.h>
28240116Smarcel#include "libdisk.h"
29240116Smarcel
30240116Smarcel#include <ctype.h>
31240116Smarcel#include <errno.h>
32240116Smarcel#include <assert.h>
33240116Smarcel
34240116Smarcel#ifdef DEBUG
35240116Smarcel#define	DPRINT(x)	warn x
36240116Smarcel#define	DPRINTX(x)	warnx x
37240116Smarcel#else
38240116Smarcel#define	DPRINT(x)
39240116Smarcel#define	DPRINTX(x)
40240116Smarcel#endif
41240116Smarcel
42240116Smarcelstruct disk *
43240116SmarcelInt_Open_Disk(const char *name, char *conftxt)
44240116Smarcel{
45240116Smarcel	struct disk *d;
46240116Smarcel	int i;
47240116Smarcel	char *p, *q, *r, *a, *b, *n, *t, *sn;
48240116Smarcel	daddr_t o, len, off;
49240116Smarcel	u_int l, s, ty, sc, hd, alt;
50240116Smarcel	daddr_t lo[10];
51240116Smarcel
52240116Smarcel	for (p = conftxt; p != NULL && *p; p = strchr(p, '\n')) {
53240116Smarcel		if (*p == '\n')
54240116Smarcel			p++;
55240116Smarcel		a = strsep(&p, " ");
56240116Smarcel		if (strcmp(a, "0"))
57240116Smarcel			continue;
58240116Smarcel
59240116Smarcel		a = strsep(&p, " ");
60240116Smarcel		if (strcmp(a, "DISK"))
61240116Smarcel			continue;
62240116Smarcel
63240116Smarcel		a = strsep(&p, " ");
64240116Smarcel		if (strcmp(a, name))
65240116Smarcel			continue;
66240116Smarcel		break;
67240116Smarcel	}
68240116Smarcel
69240116Smarcel	q = strchr(p, '\n');
70240116Smarcel	if (q != NULL)
71240116Smarcel		*q++ = '\0';
72240116Smarcel
73240116Smarcel	d = (struct disk *)calloc(sizeof *d, 1);
74240116Smarcel	if(d == NULL)
75240116Smarcel		return NULL;
76240116Smarcel
77240116Smarcel	d->name = strdup(name);
78240116Smarcel
79240116Smarcel	a = strsep(&p, " ");	/* length in bytes */
80240116Smarcel	len = strtoimax(a, &r, 0);
81240116Smarcel	if (*r) {
82240116Smarcel		printf("BARF %d <%d>\n", __LINE__, *r);
83240116Smarcel		exit (0);
84240116Smarcel	}
85240116Smarcel
86240116Smarcel	a = strsep(&p, " ");	/* sectorsize */
87240116Smarcel	s = strtoul(a, &r, 0);
88240116Smarcel	if (*r) {
89240116Smarcel		printf("BARF %d <%d>\n", __LINE__, *r);
90240116Smarcel		exit (0);
91240116Smarcel	}
92240116Smarcel
93240116Smarcel	if (s == 0)
94240116Smarcel		return (NULL);
95240116Smarcel	d->sector_size = s;
96240116Smarcel	len /= s;	/* media size in number of sectors. */
97240116Smarcel
98240116Smarcel	if (Add_Chunk(d, 0, len, name, whole, 0, 0, "-")) {
99240116Smarcel		DPRINT(("Failed to add 'whole' chunk"));
100240116Smarcel	}
101240116Smarcel
102240116Smarcel	for (;;) {
103240116Smarcel		a = strsep(&p, " ");
104240116Smarcel		if (a == NULL)
105240116Smarcel			break;
106240116Smarcel		b = strsep(&p, " ");
107240116Smarcel		o = strtoimax(b, &r, 0);
108240116Smarcel		if (*r) {
109240116Smarcel			printf("BARF %d <%d>\n", __LINE__, *r);
110240116Smarcel			exit (0);
111240116Smarcel		}
112240116Smarcel		if (!strcmp(a, "hd"))
113240116Smarcel			d->bios_hd = o;
114240116Smarcel		else if (!strcmp(a, "sc"))
115240116Smarcel			d->bios_sect = o;
116240116Smarcel		else
117240116Smarcel			printf("HUH ? <%s> <%s>\n", a, b);
118240116Smarcel	}
119240116Smarcel
120240116Smarcel	/*
121240116Smarcel	 * Calculate the number of cylinders this disk must have. If we have
122240116Smarcel	 * an obvious insanity, we set the number of cylinders to zero.
123240116Smarcel	 */
124240116Smarcel	o = d->bios_hd * d->bios_sect;
125240116Smarcel	d->bios_cyl = (o != 0) ? len / o : 0;
126240116Smarcel
127240116Smarcel	p = q;
128240116Smarcel	lo[0] = 0;
129240116Smarcel
130240116Smarcel	for (; p != NULL && *p; p = q) {
131240116Smarcel		sn = NULL;
132240116Smarcel		q = strchr(p, '\n');
133240116Smarcel		if (q != NULL)
134240116Smarcel			*q++ = '\0';
135240116Smarcel		a = strsep(&p, " ");	/* Index */
136273929Sjmmv		if (!strcmp(a, "0"))
137			break;
138		l = strtoimax(a, &r, 0);
139		if (*r) {
140			printf("BARF %d <%d>\n", __LINE__, *r);
141			exit (0);
142		}
143		t = strsep(&p, " ");	/* Type {SUN, BSD, MBR, PC98, GPT} */
144		n = strsep(&p, " ");	/* name */
145		a = strsep(&p, " ");	/* len */
146		len = strtoimax(a, &r, 0);
147		if (*r) {
148			printf("BARF %d <%d>\n", __LINE__, *r);
149			exit (0);
150		}
151		a = strsep(&p, " ");	/* secsize */
152		s = strtoimax(a, &r, 0);
153		if (*r) {
154			printf("BARF %d <%d>\n", __LINE__, *r);
155			exit (0);
156		}
157		for (;;) {
158			a = strsep(&p, " ");
159			if (a == NULL)
160				break;
161			/* XXX: Slice name may include a space. */
162			if (!strcmp(a, "sn")) {
163				sn = p;
164				break;
165			}
166			b = strsep(&p, " ");
167			o = strtoimax(b, &r, 0);
168			/* APPLE have ty as a string */
169			if ((*r) && (strcmp(t, "APPLE") && strcmp(t, "GPT"))) {
170				printf("BARF %d <%d>\n", __LINE__, *r);
171				exit (0);
172			}
173			if (!strcmp(a, "o"))
174				off = o;
175			else if (!strcmp(a, "i"))
176				i = o;
177			else if (!strcmp(a, "ty"))
178				ty = o;
179			else if (!strcmp(a, "sc"))
180				sc = o;
181			else if (!strcmp(a, "hd"))
182				hd = o;
183			else if (!strcmp(a, "alt"))
184				alt = o;
185		}
186
187		/* PLATFORM POLICY BEGIN ----------------------------------- */
188		if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2)
189			continue;
190		if (platform == p_sparc64 && !strcmp(t, "SUN") &&
191		    d->chunks->part->part == NULL) {
192			d->bios_hd = hd;
193			d->bios_sect = sc;
194			o = d->chunks->size / (hd * sc);
195			o *= (hd * sc);
196			o -= alt * hd * sc;
197			if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
198				DPRINT(("Failed to add 'freebsd' chunk"));
199			}
200		}
201		if (platform == p_alpha && !strcmp(t, "BSD") &&
202		    d->chunks->part->part == NULL) {
203			if (Add_Chunk(d, 0, d->chunks->size, name, freebsd,
204				      0, 0, "-")) {
205				DPRINT(("Failed to add 'freebsd' chunk"));
206			}
207		}
208		if (!strcmp(t, "BSD") && i == RAW_PART)
209			continue;
210		/* PLATFORM POLICY END ------------------------------------- */
211
212		off /= s;
213		len /= s;
214		off += lo[l - 1];
215		lo[l] = off;
216		if (!strcmp(t, "SUN"))
217			i = Add_Chunk(d, off, len, n, part, 0, 0, 0);
218		else if (!strncmp(t, "MBR", 3)) {
219			switch (ty) {
220			case 0xa5:
221				i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0);
222				break;
223			case 0x01:
224			case 0x04:
225			case 0x06:
226			case 0x0b:
227			case 0x0c:
228			case 0x0e:
229				i = Add_Chunk(d, off, len, n, fat, ty, 0, 0);
230				break;
231			case 0xef:	/* EFI */
232				i = Add_Chunk(d, off, len, n, efi, ty, 0, 0);
233				break;
234			default:
235				i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0);
236				break;
237			}
238		} else if (!strcmp(t, "BSD"))
239			i = Add_Chunk(d, off, len, n, part, ty, 0, 0);
240		else if (!strcmp(t, "PC98")) {
241			switch (ty & 0x7f) {
242			case 0x14:
243				i = Add_Chunk(d, off, len, n, freebsd, ty, 0,
244					      sn);
245				break;
246			case 0x20:
247			case 0x21:
248			case 0x22:
249			case 0x23:
250			case 0x24:
251				i = Add_Chunk(d, off, len, n, fat, ty, 0, sn);
252				break;
253			default:
254				i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn);
255				break;
256			}
257		} else if (!strcmp(t, "GPT"))
258			i = Add_Chunk(d, off, len, n, gpt, 0, 0, b);
259		else if (!strcmp(t, "APPLE"))
260			i = Add_Chunk(d, off, len, n, apple, 0, 0, sn);
261		else
262			; /* Ignore unknown classes. */
263	}
264	/* PLATFORM POLICY BEGIN ------------------------------------- */
265	/* We have a chance to do things on a blank disk here */
266	if (platform == p_sparc64 && d->chunks->part->part == NULL) {
267		hd = d->bios_hd;
268		sc = d->bios_sect;
269		o = d->chunks->size / (hd * sc);
270		o *= (hd * sc);
271		o -= 2 * hd * sc;
272		if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
273			DPRINT(("Failed to add 'freebsd' chunk"));
274		}
275	}
276	/* PLATFORM POLICY END --------------------------------------- */
277
278	return (d);
279	i = 0;
280}
281