open_disk.c revision 172285
1226584Sdim/*
2226584Sdim * ----------------------------------------------------------------------------
3226584Sdim * "THE BEER-WARE LICENSE" (Revision 42):
4226584Sdim * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5226584Sdim * can do whatever you want with this stuff. If we meet some day, and you think
6226584Sdim * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7226584Sdim * ----------------------------------------------------------------------------
8226584Sdim */
9226584Sdim
10226584Sdim#include <sys/cdefs.h>
11226584Sdim__FBSDID("$FreeBSD: head/lib/libdisk/open_disk.c 172285 2007-09-21 16:19:50Z marcel $");
12226584Sdim
13226584Sdim#include <stdio.h>
14226584Sdim#include <stdlib.h>
15226584Sdim#include <unistd.h>
16226584Sdim#include <fcntl.h>
17226584Sdim#include <string.h>
18234353Sdim#include <inttypes.h>
19234353Sdim#include <err.h>
20226584Sdim#include <sys/sysctl.h>
21226584Sdim#include <sys/stdint.h>
22226584Sdim#include <sys/types.h>
23226584Sdim#include <sys/stat.h>
24226584Sdim#include <sys/ioctl.h>
25226584Sdim#include <sys/disklabel.h>
26226584Sdim#include <sys/gpt.h>
27226584Sdim#include <paths.h>
28226584Sdim#include "libdisk.h"
29226584Sdim
30226584Sdim#include <ctype.h>
31226584Sdim#include <errno.h>
32226584Sdim#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, line = 1;
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	/*
53	 * Locate the disk (by name) in our sysctl output
54	 */
55	for (p = conftxt; p != NULL && *p; p = strchr(p, '\n'), line++) {
56		if (*p == '\n')
57			p++;
58		a = strsep(&p, " ");
59		/* Skip anything not with index 0 */
60		if (strcmp(a, "0"))
61			continue;
62
63		/* Skip anything not a disk */
64		a = strsep(&p, " ");
65		if (strcmp(a, "DISK"))
66			continue;
67
68		a = strsep(&p, " ");
69		if (strcmp(a, name))
70			continue;
71		break;
72	}
73
74	q = strchr(p, '\n');
75	if (q != NULL)
76		*q++ = '\0';
77
78	d = (struct disk *)calloc(sizeof *d, 1);
79	if(d == NULL)
80		return NULL;
81
82	d->name = strdup(name);
83
84	a = strsep(&p, " ");	/* length in bytes */
85	len = strtoimax(a, &r, 0);
86	if (*r) {
87		printf("libdisk: Int_Open_Disk(%s): can't parse length in line %d (r='%s')\n",
88			name, line, r);
89		return NULL;
90	}
91
92	a = strsep(&p, " ");	/* sectorsize */
93	s = strtoul(a, &r, 0);
94	if (*r) {
95		printf("libdisk: Int_Open_Disk(%s): can't parse sector size in line %d (r='%s')\n",
96			name, line, r);
97		return NULL;
98	}
99
100	if (s == 0)
101		return (NULL);
102	d->sector_size = s;
103	len /= s;	/* media size in number of sectors. */
104
105	if (Add_Chunk(d, 0, len, name, whole, 0, 0, "-")) {
106		DPRINT(("Failed to add 'whole' chunk"));
107	}
108
109	/* Try to parse any fields after the sector size in the DISK entry line */
110	for (;;) {
111		a = strsep(&p, " ");
112		if (a == NULL)
113			break;
114		b = strsep(&p, " ");
115		o = strtoimax(b, &r, 0);
116		if (*r) {
117			printf("libdisk: Int_Open_Disk(%s): can't parse parameter '%s' in line %d (r='%s')\n",
118				name, a, line, r);
119			return NULL;
120		}
121		if (!strcmp(a, "hd"))
122			d->bios_hd = o;
123		else if (!strcmp(a, "sc"))
124			d->bios_sect = o;
125		else
126			printf("libdisk: Int_Open_Disk(%s): unknown parameter '%s' with value '%s' in line %d, ignored\n",
127				name, a, b, line);
128	}
129
130	/*
131	 * Calculate the number of cylinders this disk must have. If we have
132	 * an obvious insanity, we set the number of cylinders to zero.
133	 */
134	o = d->bios_hd * d->bios_sect;
135	d->bios_cyl = (o != 0) ? len / o : 0;
136
137	p = q; line++; /* p is now the start of the line _after_ the DISK entry */
138	lo[0] = 0;
139
140	for (; p != NULL && *p; p = q, line++) {
141		sn = NULL;
142		q = strchr(p, '\n');
143		if (q != NULL)
144			*q++ = '\0';
145		a = strsep(&p, " ");	/* Index */
146		/*
147		 * If we find index 0 again, this means we've encountered another disk, so it's safe to assume this disk
148		 * has been processed.
149		 */
150		if (!strcmp(a, "0"))
151			break;
152		l = strtoimax(a, &r, 0);
153		if (*r) {
154			printf("libdisk: Int_Open_Disk(%s): can't parse depth '%s' in line %d (r='%s')\n",
155				name, a, line, r);
156			return NULL;
157
158		}
159		t = strsep(&p, " ");	/* Type {SUN, BSD, MBR, PC98, GPT} */
160		n = strsep(&p, " ");	/* name */
161		a = strsep(&p, " ");	/* len */
162		len = strtoimax(a, &r, 0);
163		if (*r) {
164			printf("libdisk: Int_Open_Disk(%s): can't parse length '%s' in line %d (r='%s')\n",
165				name, a, line, r);
166			continue;
167		}
168		a = strsep(&p, " ");	/* secsize */
169		s = strtoimax(a, &r, 0);
170		if (*r) {
171			printf("libdisk: Int_Open_Disk(%s): can't parse sector size '%s' in line %d (r='%s')\n",
172				name, a, line, r);
173			continue;
174		}
175		for (;;) {
176			a = strsep(&p, " ");
177			if (a == NULL)
178				break;
179			/* XXX: Slice name may include a space. */
180			if (!strcmp(a, "sn")) {
181				sn = p;
182				break;
183			}
184			b = strsep(&p, " ");
185			o = strtoimax(b, &r, 0);
186			/* APPLE have ty as a string */
187			if ((*r) && strcmp(t, "APPLE") &&
188			    strcmp(t, "GPT") && strcmp(t, "PART")) {
189				printf("libdisk: Int_Open_Disk(%s): can't parse parameter '%s' in line %d (r='%s')\n",
190					name, a, line, r);
191				break;
192			}
193			if (!strcmp(a, "o"))
194				off = o;
195			else if (!strcmp(a, "i"))
196				i = o;
197			else if (!strcmp(a, "ty"))
198				ty = o;
199			else if (!strcmp(a, "sc"))
200				sc = o;
201			else if (!strcmp(a, "hd"))
202				hd = o;
203			else if (!strcmp(a, "alt"))
204				alt = o;
205		}
206
207		/* PLATFORM POLICY BEGIN ----------------------------------- */
208		if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2)
209			continue;
210		if (platform == p_sparc64 && !strcmp(t, "SUN") &&
211		    d->chunks->part->part == NULL) {
212			d->bios_hd = hd;
213			d->bios_sect = sc;
214			o = d->chunks->size / (hd * sc);
215			o *= (hd * sc);
216			o -= alt * hd * sc;
217			if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
218				DPRINT(("Failed to add 'freebsd' chunk"));
219			}
220		}
221		if (platform == p_alpha && !strcmp(t, "BSD") &&
222		    d->chunks->part->part == NULL) {
223			if (Add_Chunk(d, 0, d->chunks->size, name, freebsd,
224				      0, 0, "-")) {
225				DPRINT(("Failed to add 'freebsd' chunk"));
226			}
227		}
228		if (!strcmp(t, "BSD") && i == RAW_PART)
229			continue;
230		/* PLATFORM POLICY END ------------------------------------- */
231
232		off /= s;
233		len /= s;
234		off += lo[l - 1];
235		lo[l] = off;
236		if (!strcmp(t, "SUN"))
237			i = Add_Chunk(d, off, len, n, part, 0, 0, 0);
238		else if (!strncmp(t, "MBR", 3)) {
239			switch (ty) {
240			case 0xa5:
241				i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0);
242				break;
243			case 0x01:
244			case 0x04:
245			case 0x06:
246			case 0x0b:
247			case 0x0c:
248			case 0x0e:
249				i = Add_Chunk(d, off, len, n, fat, ty, 0, 0);
250				break;
251			case 0xef:	/* EFI */
252				i = Add_Chunk(d, off, len, n, efi, ty, 0, 0);
253				break;
254			default:
255				i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0);
256				break;
257			}
258		} else if (!strcmp(t, "BSD"))
259			i = Add_Chunk(d, off, len, n, part, ty, 0, 0);
260		else if (!strcmp(t, "PC98")) {
261			switch (ty & 0x7f) {
262			case 0x14:
263				i = Add_Chunk(d, off, len, n, freebsd, ty, 0,
264					      sn);
265				break;
266			case 0x20:
267			case 0x21:
268			case 0x22:
269			case 0x23:
270			case 0x24:
271				i = Add_Chunk(d, off, len, n, fat, ty, 0, sn);
272				break;
273			default:
274				i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn);
275				break;
276			}
277		} else if (!strcmp(t, "GPT"))
278			i = Add_Chunk(d, off, len, n, gpt, 0, 0, b);
279		else if (!strcmp(t, "APPLE"))
280			i = Add_Chunk(d, off, len, n, apple, 0, 0, sn);
281		else if (!strcmp(t, "PART")) {
282#ifdef __powerpc__
283			i = Add_Chunk(d, off, len, n, apple, 0, 0, sn);
284#endif
285		} else
286			; /* Ignore unknown classes. */
287	}
288	/* PLATFORM POLICY BEGIN ------------------------------------- */
289	/* We have a chance to do things on a blank disk here */
290	if (platform == p_sparc64 && d->chunks->part->part == NULL) {
291		hd = d->bios_hd;
292		sc = d->bios_sect;
293		o = d->chunks->size / (hd * sc);
294		o *= (hd * sc);
295		o -= 2 * hd * sc;
296		if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
297			DPRINT(("Failed to add 'freebsd' chunk"));
298		}
299	}
300	/* PLATFORM POLICY END --------------------------------------- */
301
302	return (d);
303	i = 0;
304}
305