disk.c revision 106232
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/disk.c 106232 2002-10-31 04:25:17Z jake $");
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/diskslice.h>
27#include <sys/diskmbr.h>
28#include <paths.h>
29#include "libdisk.h"
30
31#include <ctype.h>
32#include <errno.h>
33#include <assert.h>
34
35#define DOSPTYP_EXTENDED        5
36#ifdef DEBUG
37#define	DPRINT(x)	warn x
38#define	DPRINTX(x)	warnx x
39#else
40#define	DPRINT(x)
41#define	DPRINTX(x)
42#endif
43
44const char *
45chunk_name(chunk_e type)
46{
47	switch(type) {
48	case unused:	return ("unused");
49	case mbr:	return ("mbr");
50	case part:	return ("part");
51	case gpt:	return ("gpt");
52	case pc98:	return ("pc98");
53	case sun:	return ("sun");
54	case freebsd:	return ("freebsd");
55	case fat:	return ("fat");
56	case spare:	return ("spare");
57	default:	return ("??");
58	}
59};
60
61struct disk *
62Open_Disk(const char *name)
63{
64	return Int_Open_Disk(name);
65}
66
67struct disk *
68Int_Open_Disk(const char *name)
69{
70	char *conftxt = NULL;
71	struct disk *d;
72	size_t txtsize;
73	int error, i;
74	char *p, *q, *r, *a, *b, *n, *t;
75	off_t o, len, off;
76	u_int l, s, ty, sc, hd, alt;
77	off_t lo[10];
78
79	error = sysctlbyname("kern.geom.conftxt", NULL, &txtsize, NULL, 0);
80	if (error) {
81		warn("kern.geom.conftxt sysctl not available, giving up!");
82		return (NULL);
83	}
84	conftxt = (char *) malloc(txtsize+1);
85	if (conftxt == NULL) {
86		DPRINT(("cannot malloc memory for conftxt"));
87		return (NULL);
88	}
89	error = sysctlbyname("kern.geom.conftxt", conftxt, &txtsize, NULL, 0);
90	if (error) {
91		DPRINT(("error reading kern.geom.conftxt from the system"));
92		free(conftxt);
93		return (NULL);
94	}
95	conftxt[txtsize] = '\0';	/* in case kernel bug is still there */
96
97	for (p = conftxt; p != NULL && *p; p = strchr(p, '\n')) {
98		if (*p == '\n')
99			p++;
100		a = strsep(&p, " ");
101		if (strcmp(a, "0"))
102			continue;
103
104		a = strsep(&p, " ");
105		if (strcmp(a, "DISK"))
106			continue;
107
108		a = strsep(&p, " ");
109		if (strcmp(a, name))
110			continue;
111		break;
112	}
113
114	q = strchr(p, '\n');
115	if (q != NULL)
116		*q++ = '\0';
117
118	d = (struct disk *)calloc(sizeof *d, 1);
119	if(d == NULL)
120		return NULL;
121
122	d->name = strdup(name);
123
124	a = strsep(&p, " ");	/* length in bytes */
125	o = strtoimax(a, &r, 0);
126	if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); }
127
128	a = strsep(&p, " ");	/* sectorsize */
129	s = strtoul(a, &r, 0);
130	if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); }
131
132	if (Add_Chunk(d, 0, o / s, name, whole, 0, 0, "-"))
133		DPRINT(("Failed to add 'whole' chunk"));
134
135	len = o / s;
136
137	for (;;) {
138		a = strsep(&p, " ");
139		if (a == NULL)
140			break;
141		b = strsep(&p, " ");
142		o = strtoul(b, &r, 0);
143		if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); }
144		if (!strcmp(a, "hd"))
145			d->bios_hd = o;
146		else if (!strcmp(a, "sc"))
147			d->bios_sect = o;
148		else
149			printf("HUH ? <%s> <%s>\n", a, b);
150	}
151
152	p = q;
153	lo[0] = 0;
154
155	for (; p != NULL && *p; p = q) {
156		q = strchr(p, '\n');
157		if (q != NULL)
158			*q++ = '\0';
159		a = strsep(&p, " ");	/* Index */
160		if (!strcmp(a, "0"))
161			break;
162		l = strtoimax(a, &r, 0);
163		if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); }
164		t = strsep(&p, " ");	/* Type {SUN, BSD, MBR, GPT} */
165		n = strsep(&p, " ");	/* name */
166		a = strsep(&p, " ");	/* len */
167		len = strtoimax(a, &r, 0);
168		if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); }
169		a = strsep(&p, " ");	/* secsize */
170		s = strtoimax(a, &r, 0);
171		if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); }
172		for (;;) {
173			a = strsep(&p, " ");
174			if (a == NULL)
175				break;
176			b = strsep(&p, " ");
177			o = strtoimax(b, &r, 0);
178			if (*r) { printf("BARF %d <%d>\n", __LINE__, *r); exit (0); }
179			if (!strcmp(a, "o"))
180				off = o;
181			else if (!strcmp(a, "i"))
182				i = o;
183			else if (!strcmp(a, "ty"))
184				ty = o;
185			else if (!strcmp(a, "sc"))
186				sc = o;
187			else if (!strcmp(a, "hd"))
188				hd = o;
189			else if (!strcmp(a, "alt"))
190				alt = o;
191		}
192
193		/* PLATFORM POLICY BEGIN ------------------------------------- */
194		if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2)
195			continue;
196		if (platform == p_sparc64 && !strcmp(t, "SUN") &&
197		    d->chunks->part->part == NULL) {
198			d->bios_hd = hd;
199			d->bios_sect = sc;
200			o = d->chunks->size / (hd * sc);
201			o *= (hd * sc);
202			o -= alt * hd * sc;
203			if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-"))
204				DPRINT(("Failed to add 'freebsd' chunk"));
205		}
206		if (platform == p_alpha && !strcmp(t, "BSD") &&
207		    d->chunks->part->part == NULL) {
208			o = d->chunks->size;
209			if (Add_Chunk(d, 0, d->chunks->size, name, freebsd, 0, 0, "-"))
210				DPRINT(("Failed to add 'freebsd' chunk"));
211		}
212		if (!strcmp(t, "BSD") && i == RAW_PART)
213			continue;
214		/* PLATFORM POLICY END --------------------------------------- */
215
216		off /= s;
217		len /= s;
218		off += lo[l - 1];
219		lo[l] = off;
220		printf("%s [%s] %jd %jd\n", t, n, (intmax_t)(off / s), (intmax_t) (len / s));
221		if (!strcmp(t, "SUN"))
222			i = Add_Chunk(d, off, len, n, part, 0, 0, 0);
223		else if (!strcmp(t, "MBR") && ty == 165)
224			i = Add_Chunk(d, off, len, n, freebsd, 0, 0, 0);
225		else if (!strcmp(t, "MBR"))
226			i = Add_Chunk(d, off, len, n, mbr, 0, 0, 0);
227		else if (!strcmp(t, "BSD"))
228			i = Add_Chunk(d, off, len, n, part, 0, 0, 0);
229		else if (!strcmp(t, "PC98"))
230			i = Add_Chunk(d, off, len, n, pc98, 0, 0, 0);
231		else if (!strcmp(t, "GPT"))
232			i = Add_Chunk(d, off, len, n, gpt, 0, 0, 0);
233		else
234			{printf("BARF %d\n", __LINE__); exit(0); }
235		printf("error = %d\n", i);
236	}
237	/* PLATFORM POLICY BEGIN ------------------------------------- */
238	/* We have a chance to do things on a blank disk here */
239printf("c %p\n", d->chunks);
240printf("c->p %p\n", d->chunks->part);
241printf("c->p->p %p\n", d->chunks->part->part);
242	if (platform == p_sparc64 && d->chunks->part->part == NULL) {
243printf("HERE %d\n", __LINE__);
244		hd = d->bios_hd;
245		sc = d->bios_sect;
246		o = d->chunks->size / (hd * sc);
247		o *= (hd * sc);
248		o -= 2 * hd * sc;
249printf("HERE %d\n", __LINE__);
250		if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-"))
251			DPRINT(("Failed to add 'freebsd' chunk"));
252	}
253	/* PLATFORM POLICY END --------------------------------------- */
254
255	return (d);
256	i = 0;
257}
258
259void
260Debug_Disk(struct disk *d)
261{
262	printf("Debug_Disk(%s)", d->name);
263#if 0
264	printf("  real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect);
265#endif
266	printf("  bios_geom=%lu/%lu/%lu = %lu\n",
267		d->bios_cyl, d->bios_hd, d->bios_sect,
268		d->bios_cyl * d->bios_hd * d->bios_sect);
269#if   defined(__i386__)
270	printf("  boot1=%p, boot2=%p, bootmgr=%p\n",
271		d->boot1, d->boot2, d->bootmgr);
272#elif defined(__alpha__)
273	printf("  boot1=%p, bootmgr=%p\n",
274		d->boot1, d->bootmgr);
275#elif defined(__ia64__)
276	printf("\n");
277#else
278/* Should be: error "Debug_Disk: unknown arch"; */
279#endif
280	Debug_Chunk(d->chunks);
281}
282
283void
284Free_Disk(struct disk *d)
285{
286	if(d->chunks) Free_Chunk(d->chunks);
287	if(d->name) free(d->name);
288#ifdef PC98
289	if(d->bootipl) free(d->bootipl);
290	if(d->bootmenu) free(d->bootmenu);
291#else
292#if !defined(__ia64__)
293	if(d->bootmgr) free(d->bootmgr);
294#endif
295#endif
296#if !defined(__ia64__)
297	if(d->boot1) free(d->boot1);
298#endif
299#if defined(__i386__)
300	if(d->boot2) free(d->boot2);
301#endif
302	free(d);
303}
304
305#if 0
306void
307Collapse_Disk(struct disk *d)
308{
309
310	while(Collapse_Chunk(d, d->chunks))
311		;
312}
313#endif
314
315static int
316qstrcmp(const void* a, const void* b)
317{
318
319	char *str1 = *(char**)a;
320	char *str2 = *(char**)b;
321	return strcmp(str1, str2);
322}
323
324char **
325Disk_Names()
326{
327	int disk_cnt;
328	static char **disks;
329	int error;
330	size_t listsize;
331	char *disklist;
332
333	error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
334	if (error) {
335		warn("kern.disks sysctl not available");
336		return NULL;
337	}
338
339	disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
340	if (disks == NULL)
341		return NULL;
342	disklist = (char *)malloc(listsize + 1);
343	if (disklist == NULL) {
344		free(disks);
345		return NULL;
346	}
347	memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
348	memset(disklist, 0, listsize + 1);
349	error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
350	if (error) {
351		free(disklist);
352		free(disks);
353		return NULL;
354	}
355	for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) {
356		disks[disk_cnt] = strsep(&disklist, " ");
357		if (disks[disk_cnt] == NULL)
358			break;
359											}
360	qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
361	return disks;
362}
363
364void
365Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
366{
367#if !defined(__ia64__)
368#ifdef PC98
369	if (bootipl_size % d->sector_size != 0)
370		return;
371	if (d->bootipl)
372		free(d->bootipl);
373	if (!bootipl) {
374		d->bootipl = NULL;
375	} else {
376		d->bootipl_size = bootipl_size;
377		d->bootipl = malloc(bootipl_size);
378		if(!d->bootipl) return;
379		memcpy(d->bootipl, bootipl, bootipl_size);
380	}
381
382	if (bootmenu_size % d->sector_size != 0)
383		return;
384	if (d->bootmenu)
385		free(d->bootmenu);
386	if (!bootmenu) {
387		d->bootmenu = NULL;
388	} else {
389		d->bootmenu_size = bootmenu_size;
390		d->bootmenu = malloc(bootmenu_size);
391		if(!d->bootmenu) return;
392		memcpy(d->bootmenu, bootmenu, bootmenu_size);
393	}
394#else
395	if (s % d->sector_size != 0)
396		return;
397	if (d->bootmgr)
398		free(d->bootmgr);
399	if (!b) {
400		d->bootmgr = NULL;
401	} else {
402		d->bootmgr_size = s;
403		d->bootmgr = malloc(s);
404		if(!d->bootmgr) return;
405		memcpy(d->bootmgr, b, s);
406	}
407#endif
408#endif
409}
410
411int
412Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
413{
414#if defined(__i386__)
415	if (d->boot1) free(d->boot1);
416	d->boot1 = malloc(512);
417	if(!d->boot1) return -1;
418	memcpy(d->boot1, b1, 512);
419	if (d->boot2) free(d->boot2);
420	d->boot2 = malloc(15 * 512);
421	if(!d->boot2) return -1;
422	memcpy(d->boot2, b2, 15 * 512);
423#elif defined(__alpha__)
424	if (d->boot1) free(d->boot1);
425	d->boot1 = malloc(15 * 512);
426	if(!d->boot1) return -1;
427	memcpy(d->boot1, b1, 15 * 512);
428#elif defined(__sparc64__)
429	if (d->boot1 != NULL)
430		free(d->boot1);
431	d->boot1 = malloc(16 * 512);
432	if (d->boot1 == NULL)
433		return (-1);
434	memcpy(d->boot1, b1, 16 * 512);
435#elif defined(__ia64__)
436	/* nothing */
437#else
438/* Should be: #error "Set_Boot_Blocks: unknown arch"; */
439#endif
440	return 0;
441}
442
443const char *
444slice_type_name( int type, int subtype )
445{
446	switch (type) {
447		case 0:		return "whole";
448		case 1:		switch (subtype) {
449					case 1:		return "fat (12-bit)";
450					case 2:		return "XENIX /";
451					case 3:		return "XENIX /usr";
452					case 4:         return "fat (16-bit,<=32Mb)";
453					case 5:		return "extended DOS";
454					case 6:         return "fat (16-bit,>32Mb)";
455					case 7:         return "NTFS/HPFS/QNX";
456					case 8:         return "AIX bootable";
457					case 9:         return "AIX data";
458					case 10:	return "OS/2 bootmgr";
459					case 11:        return "fat (32-bit)";
460					case 12:        return "fat (32-bit,LBA)";
461					case 14:        return "fat (16-bit,>32Mb,LBA)";
462					case 15:        return "extended DOS, LBA";
463					case 18:        return "Compaq Diagnostic";
464					case 84:	return "OnTrack diskmgr";
465					case 100:	return "Netware 2.x";
466					case 101:	return "Netware 3.x";
467					case 115:	return "SCO UnixWare";
468					case 128:	return "Minix 1.1";
469					case 129:	return "Minix 1.5";
470					case 130:	return "linux_swap";
471					case 131:	return "ext2fs";
472					case 166:	return "OpenBSD FFS";	/* 0xA6 */
473					case 169:	return "NetBSD FFS";	/* 0xA9 */
474					case 182:	return "OpenBSD";		/* dedicated */
475					case 183:	return "bsd/os";
476					case 184:	return "bsd/os swap";
477					case 238:	return "EFI GPT";
478					case 239:	return "EFI Sys. Part.";
479					default:	return "unknown";
480				}
481		case 2:		return "fat";
482		case 3:		switch (subtype) {
483					case 165:	return "freebsd";
484					default:	return "unknown";
485				}
486		case 4:		return "extended";
487		case 5:		return "part";
488		case 6:		return "unused";
489		default:	return "unknown";
490	}
491}
492