open_disk.c revision 121888
1199989Srdivacky/*
2199989Srdivacky * ----------------------------------------------------------------------------
3199989Srdivacky * "THE BEER-WARE LICENSE" (Revision 42):
4199989Srdivacky * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5199989Srdivacky * can do whatever you want with this stuff. If we meet some day, and you think
6199989Srdivacky * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7199989Srdivacky * ----------------------------------------------------------------------------
8199989Srdivacky */
9199989Srdivacky
10199989Srdivacky#include <sys/cdefs.h>
11199989Srdivacky__FBSDID("$FreeBSD: head/lib/libdisk/open_disk.c 121888 2003-11-02 08:39:08Z marcel $");
12199989Srdivacky
13199989Srdivacky#include <stdio.h>
14199989Srdivacky#include <stdlib.h>
15199989Srdivacky#include <unistd.h>
16249423Sdim#include <fcntl.h>
17234353Sdim#include <string.h>
18207618Srdivacky#include <inttypes.h>
19249423Sdim#include <err.h>
20199989Srdivacky#include <sys/sysctl.h>
21199989Srdivacky#include <sys/stdint.h>
22199989Srdivacky#include <sys/types.h>
23199989Srdivacky#include <sys/stat.h>
24249423Sdim#include <sys/ioctl.h>
25249423Sdim#include <sys/disklabel.h>
26249423Sdim#include <sys/gpt.h>
27249423Sdim#include <paths.h>
28249423Sdim#include "libdisk.h"
29249423Sdim
30249423Sdim#include <ctype.h>
31249423Sdim#include <errno.h>
32249423Sdim#include <assert.h>
33249423Sdim
34249423Sdim#ifdef DEBUG
35199989Srdivacky#define	DPRINT(x)	warn x
36263765Sdim#define	DPRINTX(x)	warnx x
37199989Srdivacky#else
38199989Srdivacky#define	DPRINT(x)
39249423Sdim#define	DPRINTX(x)
40199989Srdivacky#endif
41199989Srdivacky
42199989Srdivackystruct disk *
43199989SrdivackyInt_Open_Disk(const char *name, char *conftxt)
44199989Srdivacky{
45199989Srdivacky	struct disk *d;
46207618Srdivacky	int i;
47207618Srdivacky	char *p, *q, *r, *a, *b, *n, *t, *sn;
48199989Srdivacky	off_t o, len, off;
49207618Srdivacky	u_int l, s, ty, sc, hd, alt;
50207618Srdivacky	off_t lo[10];
51210299Sed
52210299Sed	for (p = conftxt; p != NULL && *p; p = strchr(p, '\n')) {
53210299Sed		if (*p == '\n')
54199989Srdivacky			p++;
55210299Sed		a = strsep(&p, " ");
56199989Srdivacky		if (strcmp(a, "0"))
57199989Srdivacky			continue;
58199989Srdivacky
59263765Sdim		a = strsep(&p, " ");
60263765Sdim		if (strcmp(a, "DISK"))
61263508Sdim			continue;
62199989Srdivacky
63199989Srdivacky		a = strsep(&p, " ");
64199989Srdivacky		if (strcmp(a, name))
65199989Srdivacky			continue;
66199989Srdivacky		break;
67210299Sed	}
68210299Sed
69263508Sdim	q = strchr(p, '\n');
70263508Sdim	if (q != NULL)
71263508Sdim		*q++ = '\0';
72263508Sdim
73210299Sed	d = (struct disk *)calloc(sizeof *d, 1);
74199989Srdivacky	if(d == NULL)
75199989Srdivacky		return NULL;
76199989Srdivacky
77207618Srdivacky	d->name = strdup(name);
78207618Srdivacky
79207618Srdivacky	a = strsep(&p, " ");	/* length in bytes */
80207618Srdivacky	len = strtoimax(a, &r, 0);
81226633Sdim	if (*r) {
82263508Sdim		printf("BARF %d <%d>\n", __LINE__, *r);
83199989Srdivacky		exit (0);
84263508Sdim	}
85199989Srdivacky
86199989Srdivacky	a = strsep(&p, " ");	/* sectorsize */
87199989Srdivacky	s = strtoul(a, &r, 0);
88199989Srdivacky	if (*r) {
89212904Sdim		printf("BARF %d <%d>\n", __LINE__, *r);
90212904Sdim		exit (0);
91212904Sdim	}
92212904Sdim
93212904Sdim	if (s == 0)
94212904Sdim		return (NULL);
95234353Sdim	d->sector_size = s;
96212904Sdim	len /= s;	/* media size in number of sectors. */
97199989Srdivacky
98234353Sdim	if (Add_Chunk(d, 0, len, name, whole, 0, 0, "-"))
99243830Sdim		DPRINT(("Failed to add 'whole' chunk"));
100199989Srdivacky
101199989Srdivacky	for (;;) {
102199989Srdivacky		a = strsep(&p, " ");
103234353Sdim		if (a == NULL)
104234353Sdim			break;
105263765Sdim		b = strsep(&p, " ");
106263765Sdim		o = strtoul(b, &r, 0);
107263765Sdim		if (*r) {
108263765Sdim			printf("BARF %d <%d>\n", __LINE__, *r);
109263765Sdim			exit (0);
110263765Sdim		}
111263765Sdim		if (!strcmp(a, "hd"))
112263765Sdim			d->bios_hd = o;
113263765Sdim		else if (!strcmp(a, "sc"))
114263765Sdim			d->bios_sect = o;
115263765Sdim		else
116263765Sdim			printf("HUH ? <%s> <%s>\n", a, b);
117263765Sdim	}
118263765Sdim
119263765Sdim	/*
120263765Sdim	 * Calculate the number of cylinders this disk must have. If we have
121263765Sdim	 * an obvious insanity, we set the number of cyclinders to zero.
122263765Sdim	 */
123263765Sdim	o = d->bios_hd * d->bios_sect;
124263765Sdim	d->bios_cyl = (o != 0) ? len / o : 0;
125263765Sdim
126263765Sdim	p = q;
127263765Sdim	lo[0] = 0;
128263765Sdim
129263765Sdim	for (; p != NULL && *p; p = q) {
130263765Sdim		q = strchr(p, '\n');
131263765Sdim		if (q != NULL)
132263765Sdim			*q++ = '\0';
133263765Sdim		a = strsep(&p, " ");	/* Index */
134263765Sdim		if (!strcmp(a, "0"))
135263765Sdim			break;
136263765Sdim		l = strtoimax(a, &r, 0);
137263765Sdim		if (*r) {
138263765Sdim			printf("BARF %d <%d>\n", __LINE__, *r);
139263765Sdim			exit (0);
140263765Sdim		}
141263765Sdim		t = strsep(&p, " ");	/* Type {SUN, BSD, MBR, PC98, GPT} */
142212904Sdim		n = strsep(&p, " ");	/* name */
143212904Sdim		a = strsep(&p, " ");	/* len */
144207618Srdivacky		len = strtoimax(a, &r, 0);
145199989Srdivacky		if (*r) {
146199989Srdivacky			printf("BARF %d <%d>\n", __LINE__, *r);
147199989Srdivacky			exit (0);
148199989Srdivacky		}
149212904Sdim		a = strsep(&p, " ");	/* secsize */
150212904Sdim		s = strtoimax(a, &r, 0);
151212904Sdim		if (*r) {
152212904Sdim			printf("BARF %d <%d>\n", __LINE__, *r);
153212904Sdim			exit (0);
154263508Sdim		}
155263508Sdim		for (;;) {
156263508Sdim			a = strsep(&p, " ");
157212904Sdim			if (a == NULL)
158263508Sdim				break;
159212904Sdim			/* XXX: Slice name may include a space. */
160212904Sdim			if (!strcmp(a, "sn")) {
161212904Sdim				sn = p;
162212904Sdim				break;
163212904Sdim			}
164212904Sdim			b = strsep(&p, " ");
165212904Sdim			o = strtoimax(b, &r, 0);
166212904Sdim			if (*r) {
167212904Sdim				printf("BARF %d <%d>\n", __LINE__, *r);
168212904Sdim				exit (0);
169212904Sdim			}
170212904Sdim			if (!strcmp(a, "o"))
171212904Sdim				off = o;
172212904Sdim			else if (!strcmp(a, "i"))
173212904Sdim				i = o;
174212904Sdim			else if (!strcmp(a, "ty"))
175212904Sdim				ty = o;
176212904Sdim			else if (!strcmp(a, "sc"))
177212904Sdim				sc = o;
178212904Sdim			else if (!strcmp(a, "hd"))
179212904Sdim				hd = o;
180212904Sdim			else if (!strcmp(a, "alt"))
181199989Srdivacky				alt = o;
182199989Srdivacky		}
183199989Srdivacky
184207618Srdivacky		/* PLATFORM POLICY BEGIN ----------------------------------- */
185199989Srdivacky		if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2)
186199989Srdivacky			continue;
187199989Srdivacky		if (platform == p_sparc64 && !strcmp(t, "SUN") &&
188199989Srdivacky		    d->chunks->part->part == NULL) {
189199989Srdivacky			d->bios_hd = hd;
190199989Srdivacky			d->bios_sect = sc;
191199989Srdivacky			o = d->chunks->size / (hd * sc);
192199989Srdivacky			o *= (hd * sc);
193199989Srdivacky			o -= alt * hd * sc;
194199989Srdivacky			if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-"))
195199989Srdivacky				DPRINT(("Failed to add 'freebsd' chunk"));
196199989Srdivacky		}
197207618Srdivacky		if (platform == p_alpha && !strcmp(t, "BSD") &&
198207618Srdivacky		    d->chunks->part->part == NULL) {
199207618Srdivacky			if (Add_Chunk(d, 0, d->chunks->size, name, freebsd,
200199989Srdivacky				      0, 0, "-"))
201223017Sdim				DPRINT(("Failed to add 'freebsd' chunk"));
202223017Sdim		}
203223017Sdim		if (!strcmp(t, "BSD") && i == RAW_PART)
204223017Sdim			continue;
205207618Srdivacky		/* PLATFORM POLICY END ------------------------------------- */
206199989Srdivacky
207199989Srdivacky		off /= s;
208199989Srdivacky		len /= s;
209199989Srdivacky		off += lo[l - 1];
210263508Sdim		lo[l] = off;
211199989Srdivacky		if (!strcmp(t, "SUN"))
212199989Srdivacky			i = Add_Chunk(d, off, len, n, part, 0, 0, 0);
213263508Sdim		else if (!strncmp(t, "MBR", 3)) {
214199989Srdivacky			switch (ty) {
215199989Srdivacky			case 0xa5:
216203954Srdivacky				i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0);
217199989Srdivacky				break;
218199989Srdivacky			case 0x01:
219199989Srdivacky			case 0x04:
220199989Srdivacky			case 0x06:
221207618Srdivacky			case 0x0b:
222207618Srdivacky			case 0x0c:
223207618Srdivacky			case 0x0e:
224207618Srdivacky				i = Add_Chunk(d, off, len, n, fat, ty, 0, 0);
225207618Srdivacky				break;
226199989Srdivacky			case 0xef:	/* EFI */
227199989Srdivacky				i = Add_Chunk(d, off, len, n, efi, ty, 0, 0);
228199989Srdivacky				break;
229199989Srdivacky			default:
230199989Srdivacky				i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0);
231199989Srdivacky				break;
232207618Srdivacky			}
233207618Srdivacky		} else if (!strcmp(t, "BSD"))
234207618Srdivacky			i = Add_Chunk(d, off, len, n, part, ty, 0, 0);
235199989Srdivacky		else if (!strcmp(t, "PC98")) {
236199989Srdivacky			switch (ty & 0x7f) {
237199989Srdivacky			case 0x14:
238199989Srdivacky				i = Add_Chunk(d, off, len, n, freebsd, ty, 0,
239199989Srdivacky					      sn);
240199989Srdivacky				break;
241199989Srdivacky			case 0x20:
242199989Srdivacky			case 0x21:
243219077Sdim			case 0x22:
244207618Srdivacky			case 0x23:
245212904Sdim			case 0x24:
246210299Sed				i = Add_Chunk(d, off, len, n, fat, ty, 0, sn);
247199989Srdivacky				break;
248199989Srdivacky			default:
249210299Sed				i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn);
250249423Sdim				break;
251263508Sdim			}
252263508Sdim		} else if (!strcmp(t, "GPT"))
253199989Srdivacky			i = Add_Chunk(d, off, len, n, ty, 0, 0, 0);
254199989Srdivacky		else if (!strcmp(t, "BDE"))
255210299Sed			; /* nothing */
256199989Srdivacky		else if (!strcmp(t, "CCD"))
257199989Srdivacky			; /* nothing */
258199989Srdivacky		else {
259199989Srdivacky			printf("BARF %d\n", __LINE__);
260199989Srdivacky			exit(0);
261199989Srdivacky		}
262226633Sdim	}
263263508Sdim	/* PLATFORM POLICY BEGIN ------------------------------------- */
264263508Sdim	/* We have a chance to do things on a blank disk here */
265199989Srdivacky	if (platform == p_sparc64 && d->chunks->part->part == NULL) {
266263508Sdim		hd = d->bios_hd;
267199989Srdivacky		sc = d->bios_sect;
268199989Srdivacky		o = d->chunks->size / (hd * sc);
269199989Srdivacky		o *= (hd * sc);
270199989Srdivacky		o -= 2 * hd * sc;
271263508Sdim		if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-"))
272199989Srdivacky			DPRINT(("Failed to add 'freebsd' chunk"));
273263508Sdim	}
274199989Srdivacky	/* PLATFORM POLICY END --------------------------------------- */
275210299Sed
276199989Srdivacky	return (d);
277199989Srdivacky	i = 0;
278199989Srdivacky}
279199989Srdivacky