disk.c revision 105873
1169689Skan/*
2169689Skan * ----------------------------------------------------------------------------
3169689Skan * "THE BEER-WARE LICENSE" (Revision 42):
4169689Skan * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5169689Skan * can do whatever you want with this stuff. If we meet some day, and you think
6169689Skan * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7169689Skan * ----------------------------------------------------------------------------
8169689Skan */
9169689Skan
10169689Skan#include <sys/cdefs.h>
11169689Skan__FBSDID("$FreeBSD: head/lib/libdisk/disk.c 105873 2002-10-24 13:35:52Z gallatin $");
12169689Skan
13169689Skan#include <stdio.h>
14169689Skan#include <stdlib.h>
15169689Skan#include <unistd.h>
16169689Skan#include <fcntl.h>
17169689Skan#include <string.h>
18169689Skan#include <err.h>
19169689Skan#include <sys/sysctl.h>
20169689Skan#include <sys/types.h>
21169689Skan#include <sys/stat.h>
22169689Skan#include <sys/ioctl.h>
23169689Skan#include <sys/disklabel.h>
24169689Skan#include <sys/diskslice.h>
25169689Skan#ifndef PC98
26169689Skan#include <sys/diskmbr.h>
27169689Skan#endif
28169689Skan#include <paths.h>
29169689Skan#include "libdisk.h"
30169689Skan
31169689Skan#ifndef PC98
32169689Skan#define	HAVE_GEOM
33169689Skan#endif
34169689Skan#include <ctype.h>
35169689Skan#include <errno.h>
36169689Skan#include <assert.h>
37169689Skan
38169689Skan#ifndef PC98
39169689Skan#define DOSPTYP_EXTENDED        5
40169689Skan#endif
41169689Skan
42169689Skan#ifdef DEBUG
43169689Skan#define	DPRINT(x)	warn x
44169689Skan#define	DPRINTX(x)	warnx x
45169689Skan#else
46169689Skan#define	DPRINT(x)
47169689Skan#define	DPRINTX(x)
48169689Skan#endif
49169689Skan
50169689Skanconst char *chunk_n[] = {
51169689Skan	"whole",
52169689Skan	"unknown",
53169689Skan	"fat",
54169689Skan	"freebsd",
55169689Skan	"extended",
56169689Skan	"part",
57169689Skan	"unused",
58169689Skan	NULL
59169689Skan};
60169689Skan
61169689Skanstruct disk *
62169689SkanOpen_Disk(const char *name)
63169689Skan{
64169689Skan	return Int_Open_Disk(name, 0);
65169689Skan}
66169689Skan
67169689Skan#ifndef PC98
68169689Skanstatic u_int32_t
69169689SkanRead_Int32(u_int32_t *p)
70169689Skan{
71169689Skan    u_int8_t *bp = (u_int8_t *)p;
72169689Skan    return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24);
73169689Skan}
74169689Skan#endif
75169689Skan
76169689Skan/*
77169689Skan * XXX BEGIN HACK XXX
78169689Skan * Scan/parse the XML geom data to retrieve what we need to
79169689Skan * carry out the work of Int_Open_Disk.  This is a total hack
80169689Skan * and should be replaced with a real XML parser.
81169689Skan */
82169689Skantypedef enum {
83169689Skan	XML_MESH,
84169689Skan	XML_MESH_END,
85169689Skan	XML_CLASS,
86169689Skan	XML_CLASS_END,
87169689Skan	XML_GEOM,
88169689Skan	XML_GEOM_END,
89169689Skan	XML_CONFIG,
90169689Skan	XML_CONFIG_END,
91169689Skan	XML_PROVIDER,
92169689Skan	XML_PROVIDER_END,
93169689Skan	XML_NAME,
94169689Skan	XML_NAME_END,
95169689Skan	XML_INDEX,
96169689Skan	XML_INDEX_END,
97169689Skan	XML_SECLENGTH,
98169689Skan	XML_SECLENGTH_END,
99169689Skan	XML_SECOFFSET,
100169689Skan	XML_SECOFFSET_END,
101169689Skan	XML_TYPE,
102169689Skan	XML_TYPE_END,
103169689Skan	XML_MEDIASIZE,
104169689Skan	XML_MEDIASIZE_END,
105169689Skan	XML_SECTORSIZE,
106169689Skan	XML_SECTORSIZE_END,
107169689Skan	XML_FWHEADS,
108169689Skan	XML_FWHEADS_END,
109169689Skan	XML_FWSECTORS,
110169689Skan	XML_FWSECTORS_END,
111169689Skan
112169689Skan	XML_OTHER,
113169689Skan	XML_OTHER_END
114169689Skan} XMLToken;
115169689Skan
116169689Skanconst struct {
117169689Skan	XMLToken	t;
118169689Skan	const char*	token;
119169689Skan	const char*	name;
120169689Skan} xmltokens[] = {
121169689Skan	{ XML_MESH,		"mesh",		"XML_MESH" },
122169689Skan	{ XML_CLASS,		"class",	"XML_CLASS" },
123169689Skan	{ XML_GEOM,		"geom",		"XML_GEOM" },
124169689Skan	{ XML_CONFIG,		"config",	"XML_CONFIG" },
125169689Skan	{ XML_PROVIDER,		"provider",	"XML_PROVIDE" },
126169689Skan	{ XML_NAME,		"name",		"XML_NAME" },
127169689Skan	{ XML_INDEX,		"index",	"XML_INDEX" },
128169689Skan	{ XML_SECLENGTH,	"seclength",	"XML_SECLENGTH" },
129169689Skan	{ XML_SECOFFSET,	"secoffset",	"XML_SECOFFSET" },
130169689Skan	{ XML_TYPE,		"type",		"XML_TYPE" },
131169689Skan	{ XML_FWHEADS,		"fwheads",	"XML_FWHEADS" },
132169689Skan	{ XML_FWSECTORS,	"fwsectors",	"XML_FWSECTORS" },
133169689Skan	{ XML_MEDIASIZE,	"mediasize",	"XML_MEDIASIZE" },
134169689Skan	{ XML_SECTORSIZE,	"sectorsize",	"XML_SECTORSIZE" },
135169689Skan	/* NB: this must be last */
136169689Skan	{ XML_OTHER,		NULL,		"XML_OTHER" },
137169689Skan};
138169689Skan#define	N(x)	(sizeof (x) / sizeof (x[0]))
139169689Skan
140169689Skan#ifdef DEBUG
141169689Skanstatic const char*
142169689Skanxmltokenname(XMLToken t)
143169689Skan{
144169689Skan	int i;
145169689Skan
146169689Skan	for (i = 0; i < N(xmltokens); i++) {
147169689Skan		if (t == xmltokens[i].t)
148169689Skan			return xmltokens[i].name;
149169689Skan		if ((t-1) == xmltokens[i].t) {
150169689Skan			static char tbuf[80];
151169689Skan			snprintf(tbuf, sizeof (tbuf), "%s_END",
152169689Skan				xmltokens[i].name);
153169689Skan			return tbuf;
154169689Skan		}
155169689Skan	}
156169689Skan	return "???";
157169689Skan}
158169689Skan#endif /*DEBUG*/
159169689Skan
160169689Skan/*
161169689Skan * Parse the next XML token delimited by <..>.  If the token
162169689Skan * has a "builtin terminator" (<... />) then just skip it and
163169689Skan * go the next token.
164169689Skan */
165169689Skanstatic int
166169689Skanxmltoken(const char *start, const char **next, XMLToken *t)
167169689Skan{
168169689Skan	const char *cp = start;
169169689Skan	const char *token;
170169689Skan	int i;
171169689Skan
172169689Skanagain:
173169689Skan	while (*cp != '<') {
174169689Skan		if (*cp == '\0') {
175169689Skan			*next = cp;
176169689Skan			DPRINTX(("xmltoken: EOD"));
177169689Skan			return 0;
178169689Skan		}
179169689Skan		cp++;
180169689Skan	}
181169689Skan	token = ++cp;
182169689Skan	for (; *cp && *cp != '>' && !isspace(*cp); cp++)
183169689Skan		;
184169689Skan	if (*cp == '\0') {
185169689Skan		*next = cp;
186169689Skan		DPRINTX(("xmltoken: EOD"));
187169689Skan		return 0;
188169689Skan	}
189169689Skan	*t = (*token == '/');
190169689Skan	if (*t)
191169689Skan		token++;
192169689Skan	for (i = 0; xmltokens[i].token != NULL; i++)
193169689Skan		if (strncasecmp(token, xmltokens[i].token, cp-token) == 0)
194169689Skan			break;
195169689Skan	*t += xmltokens[i].t;
196169689Skan	/* now collect the remainder of the string */
197169689Skan	for (; *cp != '>' && *cp != '\0'; cp++)
198169689Skan		;
199169689Skan	if (*cp == '\0') {
200169689Skan		*next = cp;
201169689Skan		DPRINTX(("xmltoken: EOD"));
202169689Skan		return 0;
203169689Skan	}
204169689Skan	if (cp > token && cp[-1] == '/') {
205169689Skan		/* e.g. <geom ref="0xc1c8c100"/> */
206169689Skan		start = cp+1;
207169689Skan		goto again;
208169689Skan	}
209169689Skan	*next = cp+1;
210169689Skan	DPRINTX(("xmltoken: %s \"%.*s\"", xmltokenname(*t), cp-token, token));
211169689Skan	return 1;
212169689Skan}
213169689Skan
214169689Skan/*
215169689Skan * Parse and discard XML up to the token terminator.
216169689Skan */
217169689Skanstatic int
218169689Skandiscardxml(const char **next, XMLToken terminator)
219169689Skan{
220169689Skan	const char *xml = *next;
221169689Skan	XMLToken t;
222169689Skan
223169689Skan	DPRINTX(("discard XML up to %s", xmltokenname(terminator)));
224169689Skan	for (;;) {
225169689Skan		if (xmltoken(xml, next, &t) == 0)
226169689Skan			return EINVAL;
227169689Skan		if (t == terminator)
228169689Skan			break;
229169689Skan		if ((t & 1) == 0) {
230169689Skan			int error = discardxml(next, t+1);
231169689Skan			if (error)
232169689Skan				return error;
233169689Skan		}
234169689Skan		xml = *next;
235169689Skan	}
236169689Skan	return 0;
237169689Skan}
238169689Skan
239169689Skan/*
240169689Skan * Parse XML from between a range of markers; e.g. <mesh> ... </mesh>.
241169689Skan * When the specified class name is located we descend looking for the
242169689Skan * geometry information given by diskname.  Once inside there we process
243169689Skan * tags calling f back for each useful one.  The arg is passed into f
244169689Skan * for use in storing the parsed data.
245169689Skan */
246169689Skanstatic int
247169689Skanparsexmlpair(
248169689Skan	const char *xml,
249169689Skan	const char **next,
250169689Skan	const char *classname,
251169689Skan	XMLToken terminator,
252169689Skan	const char *diskname,
253169689Skan	int (*f)(void *, XMLToken, u_int *, u_int64_t),
254169689Skan	void *arg
255169689Skan)
256169689Skan{
257169689Skan	const char *cp;
258169689Skan	XMLToken t;
259169689Skan	int error;
260169689Skan	u_int ix = (u_int) -1;
261169689Skan
262169689Skan	DPRINTX(("parse XML up to %s", xmltokenname(terminator)));
263169689Skan	do {
264169689Skan		if (xmltoken(xml, next, &t) == 0) {
265169689Skan			error = EINVAL;
266169689Skan			break;
267169689Skan		}
268169689Skan		if (t == terminator) {
269169689Skan			error = 0;
270169689Skan			break;
271169689Skan		}
272169689Skan		if (t & 1) {		/* </mumble> w/o matching <mumble> */
273169689Skan			DPRINTX(("Unexpected token %s", xmltokenname(t)));
274169689Skan			error = EINVAL;
275169689Skan			break;
276169689Skan		}
277169689Skan		switch ((int) t) {
278169689Skan		case XML_NAME:
279169689Skan			for (cp = *next; *cp && *cp != '<'; cp++)
280169689Skan				;
281169689Skan			if (*cp == '\0') {
282169689Skan				DPRINTX(("parsexmlpair: EOD"));
283169689Skan				error = EINVAL;
284169689Skan				goto done;
285169689Skan			    }
286169689Skan			DPRINTX(("parsexmlpair: \"%.*s\"", cp-*next, *next));
287169689Skan			switch ((int) terminator) {
288169689Skan			case XML_CLASS_END:
289169689Skan				if (strncasecmp(*next, classname, cp-*next))
290169689Skan					return discardxml(next, terminator);
291169689Skan				break;
292169689Skan			case XML_GEOM_END:
293169689Skan				if (strncasecmp(*next, diskname, cp-*next))
294169689Skan					return discardxml(next, terminator);
295169689Skan				break;
296169689Skan			}
297169689Skan			break;
298169689Skan		case XML_SECOFFSET:
299169689Skan		case XML_SECLENGTH:
300169689Skan		case XML_TYPE:
301169689Skan			if (ix == (u_int) -1) {
302169689Skan				DPRINTX(("parsexmlpair: slice data w/o "
303169689Skan					"preceding index"));
304169689Skan				error = EINVAL;
305169689Skan				goto done;
306169689Skan			}
307169689Skan			/* fall thru... */
308169689Skan		case XML_INDEX:
309169689Skan		case XML_FWHEADS:
310169689Skan		case XML_FWSECTORS:
311169689Skan		case XML_MEDIASIZE:
312169689Skan		case XML_SECTORSIZE:
313169689Skan			if (terminator != XML_CONFIG_END &&
314169689Skan			    terminator != XML_PROVIDER_END) {
315169689Skan				DPRINTX(("parsexmlpair: %s in unexpected "
316169689Skan				      "context: terminator %s",
317169689Skan				      xmltokenname(t),
318169689Skan				      xmltokenname(terminator)));
319169689Skan				error = EINVAL;
320169689Skan				goto done;
321169689Skan			}
322169689Skan			error = (*f)(arg, t, &ix, strtoull(*next, NULL, 10));
323169689Skan			if (error)
324169689Skan				goto done;
325169689Skan			break;
326169689Skan		}
327169689Skan		error = parsexmlpair(*next, &xml, classname,
328169689Skan				     t+1, diskname, f, arg);
329169689Skan	} while (error == 0);
330169689Skandone:
331169689Skan	return error;
332169689Skan}
333169689Skan
334169689Skan/*
335169689Skan * XML parser.  Just barely smart enough to handle the
336169689Skan * gibberish that geom passed back from the kernel.
337169689Skan */
338169689Skanstatic int
339169689Skanxmlparse(
340169689Skan	const char *confxml,
341169689Skan	const char *classname,
342169689Skan	const char *diskname,
343169689Skan	int (*f)(void *, XMLToken, u_int *, u_int64_t),
344169689Skan	void *arg
345169689Skan)
346169689Skan{
347169689Skan	const char *next;
348169689Skan	XMLToken t;
349169689Skan	int error;
350169689Skan
351169689Skan	next = confxml;
352169689Skan	while (xmltoken(next, &next, &t) && t != XML_MESH)
353169689Skan		;
354169689Skan	if (t == XML_MESH)
355169689Skan		error = parsexmlpair(next, &next, classname, XML_MESH_END, diskname, f, arg);
356169689Skan	else {
357169689Skan		DPRINTX(("xmlparse: expecting mesh token, got %s",
358169689Skan		      xmltokenname(t)));
359169689Skan		error = EINVAL;
360169689Skan	}
361169689Skan
362169689Skan	return (error ? -1 : 0);
363169689Skan}
364169689Skan
365169689Skan/*
366169689Skan * Callback to collect slice-related data.
367169689Skan */
368169689Skanstatic int
369169689SkanassignToSlice(void *arg, XMLToken t, u_int *slice, u_int64_t v)
370169689Skan{
371169689Skan	struct diskslices *ds = (struct diskslices *) arg;
372169689Skan
373169689Skan	switch ((int) t) {
374169689Skan	case XML_INDEX:
375169689Skan		*slice = BASE_SLICE + (u_int) v;
376169689Skan		if (*slice >= MAX_SLICES) {
377169689Skan			DPRINTX(("assignToSlice: invalid slice index %u > max %u",
378169689Skan			      *slice, MAX_SLICES));
379169689Skan			return EINVAL;
380169689Skan		}
381169689Skan		if (*slice >= ds->dss_nslices)
382169689Skan			ds->dss_nslices = (*slice)+1;
383169689Skan		break;
384169689Skan	case XML_SECOFFSET:
385169689Skan		ds->dss_slices[*slice].ds_offset = (u_long) v;
386169689Skan		break;
387169689Skan	case XML_SECLENGTH:
388169689Skan		ds->dss_slices[*slice].ds_size = (u_long) v;
389169689Skan		break;
390169689Skan	case XML_TYPE:
391169689Skan		ds->dss_slices[*slice].ds_type = (int) v;
392169689Skan		break;
393169689Skan	}
394169689Skan	return 0;
395169689Skan}
396169689Skan
397169689Skan/*
398169689Skan * Callback to collect disk-related data.
399169689Skan */
400169689Skanstatic int
401169689SkanassignToDisk(void *arg, XMLToken t, u_int *slice, u_int64_t v)
402169689Skan{
403169689Skan	struct disklabel *dl = (struct disklabel *) arg;
404169689Skan
405169689Skan	switch ((int) t) {
406169689Skan	case XML_FWHEADS:
407169689Skan		dl->d_ntracks = (u_int32_t) v;
408169689Skan	case XML_FWSECTORS:
409169689Skan		dl->d_nsectors = (u_int32_t) v;
410169689Skan		break;
411169689Skan	case XML_MEDIASIZE:
412169689Skan		/* store this temporarily; it gets moved later */
413169689Skan		dl->d_secpercyl = v >> 32;
414169689Skan		dl->d_secperunit = v & 0xffffffff;
415169689Skan		break;
416169689Skan	case XML_SECTORSIZE:
417169689Skan		dl->d_secsize = (u_int32_t) v;
418169689Skan		break;
419169689Skan	}
420169689Skan	return 0;
421169689Skan}
422169689Skan
423169689Skan#ifdef __i386__
424169689Skan/*
425169689Skan * Callback to collect partition-related data.
426169689Skan */
427169689Skanstatic int
428169689SkanassignToPartition(void *arg, XMLToken t, u_int *part, u_int64_t v)
429169689Skan{
430169689Skan	struct disklabel *dl = (struct disklabel *) arg;
431169689Skan
432169689Skan	switch ((int) t) {
433169689Skan	case XML_INDEX:
434169689Skan		*part = (u_int) v;
435169689Skan		if (*part >= MAXPARTITIONS) {
436169689Skan			DPRINTX(("assignToPartition: invalid partition index %u > max %u",
437169689Skan			      *part, MAXPARTITIONS));
438169689Skan			return EINVAL;
439169689Skan		}
440169689Skan		if (*part >= dl->d_npartitions)
441169689Skan			dl->d_npartitions = (*part)+1;
442		break;
443	case XML_SECOFFSET:
444		dl->d_partitions[*part].p_offset = (u_int32_t) v;
445		break;
446	case XML_SECLENGTH:
447		dl->d_partitions[*part].p_size = (u_int32_t) v;
448		break;
449	case XML_TYPE:
450		dl->d_partitions[*part].p_fstype = (u_int8_t) v;
451		break;
452	}
453	return 0;
454}
455#endif /* __i386__ */
456#undef N
457
458struct disk *
459Int_Open_Disk(const char *name, u_long size)
460{
461	int i;
462	int fd = -1;
463	struct diskslices ds;
464	struct disklabel dl;
465	char device[64];
466	struct disk *d;
467#ifdef PC98
468	unsigned char *p;
469#else
470	struct dos_partition *dp;
471	void *p;
472#endif
473	char *confxml = NULL;
474	size_t xmlsize;
475	u_int64_t mediasize;
476	int error;
477
478	strlcpy(device, _PATH_DEV, sizeof(device));
479	strlcat(device, name, sizeof(device));
480
481	d = (struct disk *)malloc(sizeof *d);
482	if(!d) return NULL;
483	memset(d, 0, sizeof *d);
484
485	fd = open(device, O_RDONLY);
486	if (fd < 0) {
487		DPRINT(("open(%s) failed", device));
488		goto bad;
489	}
490
491	memset(&dl, 0, sizeof dl);
492	memset(&ds, 0, sizeof ds);
493	/*
494	 * Read and hack-parse the XML that provides the info we need.
495	 */
496	error = sysctlbyname("kern.geom.confxml", NULL, &xmlsize, NULL, 0);
497	if (error) {
498		warn("kern.geom.confxml sysctl not available, giving up!");
499		goto bad;
500	}
501	confxml = (char *) malloc(xmlsize+1);
502	if (confxml == NULL) {
503		DPRINT(("cannot malloc memory for confxml"));
504		goto bad;
505	}
506	error = sysctlbyname("kern.geom.confxml", confxml, &xmlsize, NULL, 0);
507	if (error) {
508		DPRINT(("error reading kern.geom.confxml from the system"));
509		goto bad;
510	}
511	confxml[xmlsize] = '\0';	/* in case kernel bug is still there */
512
513	if (xmlparse(confxml, "MBR", name, assignToSlice, &ds) != 0) {
514		DPRINTX(("Error parsing MBR geometry specification."));
515		goto bad;
516	}
517	if (xmlparse(confxml, "DISK", name, assignToDisk, &dl) != 0) {
518		DPRINTX(("Error parsing DISK geometry specification."));
519		goto bad;
520	}
521	if (dl.d_nsectors == 0) {
522		DPRINTX(("No (zero) sector information in DISK geometry"));
523		goto bad;
524	}
525	if (dl.d_ntracks == 0) {
526		DPRINTX(("No (zero) track information in DISK geometry"));
527		goto bad;
528	}
529	if (dl.d_secsize == 0) {
530		DPRINTX(("No (zero) sector size information in DISK geometry"));
531		goto bad;
532	}
533	if (dl.d_secpercyl == 0 && dl.d_secperunit == 0) {
534		DPRINTX(("No (zero) media size information in DISK geometry"));
535		goto bad;
536	}
537	/*
538	 * Now patch up disklabel and diskslice.
539	 */
540	d->sector_size = dl.d_secsize;
541	/* NB: media size was stashed in two parts while parsing */
542	mediasize = (((u_int64_t) dl.d_secpercyl) << 32) + dl.d_secperunit;
543	dl.d_secpercyl = 0;
544	dl.d_secperunit = 0;
545	size = mediasize / d->sector_size;
546	dl.d_ncylinders = size / (dl.d_ntracks * dl.d_nsectors);
547	/* "whole disk" slice maintained for compatibility */
548	ds.dss_slices[WHOLE_DISK_SLICE].ds_size = size;
549
550#ifdef PC98
551	p = (unsigned char*)read_block(fd, 1, d->sector_size);
552#else
553	p = read_block(fd, 0, d->sector_size);
554	dp = (struct dos_partition*)(p + DOSPARTOFF);
555	for (i = 0; i < NDOSPART; i++) {
556		if (Read_Int32(&dp->dp_start) >= size)
557		    continue;
558		if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size)
559		    continue;
560		if (!Read_Int32(&dp->dp_size))
561		    continue;
562	}
563	free(p);
564#endif
565
566	d->bios_sect = dl.d_nsectors;
567	d->bios_hd = dl.d_ntracks;
568
569	d->name = strdup(name);
570
571
572	if (dl.d_ntracks && dl.d_nsectors)
573		d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors);
574
575	if (Add_Chunk(d, 0, size, name, whole, 0, 0, "-"))
576		DPRINT(("Failed to add 'whole' chunk"));
577
578#ifdef __i386__
579#ifdef PC98
580	/* XXX -- Quick Hack!
581	 * Check MS-DOS MO
582	 */
583	if ((*p == 0xf0 || *p == 0xf8) &&
584	    (*(p+1) == 0xff) &&
585	    (*(p+2) == 0xff)) {
586		Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name);
587	    free(p);
588	    goto pc98_mo_done;
589	}
590	free(p);
591#endif /* PC98 */
592	for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
593		char sname[20];
594		char pname[20];
595		chunk_e ce;
596		u_long flags=0;
597		int subtype=0;
598		int j;
599
600		if (! ds.dss_slices[i].ds_size)
601			continue;
602		snprintf(sname, sizeof(sname), "%ss%d", name, i - 1);
603#ifdef PC98
604		subtype = ds.dss_slices[i].ds_type |
605			ds.dss_slices[i].ds_subtype << 8;
606		switch (ds.dss_slices[i].ds_type & 0x7f) {
607			case 0x14:
608				ce = freebsd;
609				break;
610			case 0x20:
611			case 0x21:
612			case 0x22:
613			case 0x23:
614			case 0x24:
615				ce = fat;
616				break;
617#else /* IBM-PC */
618		subtype = ds.dss_slices[i].ds_type;
619		switch (ds.dss_slices[i].ds_type) {
620			case 0xa5:
621				ce = freebsd;
622				break;
623			case 0x1:
624			case 0x6:
625			case 0x4:
626			case 0xb:
627			case 0xc:
628			case 0xe:
629				ce = fat;
630				break;
631			case DOSPTYP_EXTENDED:
632			case 0xf:
633				ce = extended;
634				break;
635#endif
636			default:
637				ce = unknown;
638				break;
639		}
640#ifdef PC98
641		if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
642			ds.dss_slices[i].ds_size, sname, ce, subtype, flags,
643			ds.dss_slices[i].ds_name))
644#else
645		if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
646			ds.dss_slices[i].ds_size, sname, ce, subtype, flags, ""))
647#endif
648			DPRINT(("failed to add chunk for slice %d", i - 1));
649
650#ifdef PC98
651		if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14)
652#else
653		if (ds.dss_slices[i].ds_type != 0xa5)
654#endif
655			continue;
656		if (xmlparse(confxml, "BSD", sname, assignToPartition, &dl) != 0) {
657			DPRINTX(("Error parsing MBR geometry specification."));
658			goto bad;
659		}
660
661		for(j = 0; j <= dl.d_npartitions; j++) {
662			if (j == RAW_PART)
663				continue;
664			if (j == 3)
665				continue;
666			if (j == dl.d_npartitions) {
667				j = 3;
668				dl.d_npartitions = 0;
669			}
670			if (!dl.d_partitions[j].p_size)
671				continue;
672			if (dl.d_partitions[j].p_size +
673			    dl.d_partitions[j].p_offset >
674			    ds.dss_slices[i].ds_size)
675				continue;
676			snprintf(pname, sizeof(pname), "%s%c", sname, j + 'a');
677			if (Add_Chunk(d,
678				dl.d_partitions[j].p_offset +
679				ds.dss_slices[i].ds_offset,
680				dl.d_partitions[j].p_size,
681				pname,part,
682				dl.d_partitions[j].p_fstype,
683#ifdef PC98
684				0,
685				ds.dss_slices[i].ds_name) && j != 3)
686#else
687				0, "") && j != 3)
688#endif
689				DPRINT((
690			"Failed to add chunk for partition %c [%lu,%lu]",
691			j + 'a', dl.d_partitions[j].p_offset,
692			dl.d_partitions[j].p_size));
693		}
694	}
695#endif /* __i386__ */
696#ifdef __alpha__
697	{
698		struct disklabel dl;
699		char pname[20];
700		int j,k;
701
702		strlcpy(pname, _PATH_DEV, sizeof(pname));
703		strlcat(pname, name, sizeof(pname));
704		j = open(pname, O_RDONLY);
705		if (j < 0) {
706			DPRINT(("open(%s)", pname));
707			goto nolabel;
708		}
709		k = ioctl(j, DIOCGDINFO, &dl);
710		if (k < 0) {
711			DPRINT(("ioctl(%s, DIOCGDINFO)", pname));
712			close(j);
713			goto nolabel;
714		}
715		close(j);
716		All_FreeBSD(d, 1);
717
718		for(j = 0; j <= dl.d_npartitions; j++) {
719			if (j == RAW_PART)
720				continue;
721			if (j == 3)
722				continue;
723			if (j == dl.d_npartitions) {
724				j = 3;
725				dl.d_npartitions = 0;
726			}
727			if (!dl.d_partitions[j].p_size)
728				continue;
729			if (dl.d_partitions[j].p_size +
730			    dl.d_partitions[j].p_offset >
731			    ds.dss_slices[WHOLE_DISK_SLICE].ds_size)
732				continue;
733			snprintf(pname, sizeof(pname), "%s%c", name, j + 'a');
734			if (Add_Chunk(d,
735				      dl.d_partitions[j].p_offset,
736				      dl.d_partitions[j].p_size,
737				      pname,part,
738				      dl.d_partitions[j].p_fstype,
739				      0, "") && j != 3)
740				DPRINT((
741					"Failed to add chunk for partition %c [%lu,%lu]",
742					j + 'a', dl.d_partitions[j].p_offset,
743					dl.d_partitions[j].p_size));
744		}
745	nolabel:;
746	}
747#endif /* __alpha__ */
748#ifdef PC98
749pc98_mo_done:
750#endif
751	close(fd);
752	Fixup_Names(d);
753	return d;
754bad:
755	if (confxml != NULL)
756		free(confxml);
757	if (fd >= 0)
758		close(fd);
759	return NULL;
760}
761
762void
763Debug_Disk(struct disk *d)
764{
765	printf("Debug_Disk(%s)", d->name);
766#if 0
767	printf("  real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect);
768#endif
769	printf("  bios_geom=%lu/%lu/%lu = %lu\n",
770		d->bios_cyl, d->bios_hd, d->bios_sect,
771		d->bios_cyl * d->bios_hd * d->bios_sect);
772#if defined(PC98)
773	printf("  boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n",
774		d->boot1, d->boot2, d->bootipl, d->bootmenu);
775#elif defined(__i386__)
776	printf("  boot1=%p, boot2=%p, bootmgr=%p\n",
777		d->boot1, d->boot2, d->bootmgr);
778#elif defined(__alpha__)
779	printf("  boot1=%p, bootmgr=%p\n",
780		d->boot1, d->bootmgr);
781#endif
782	Debug_Chunk(d->chunks);
783}
784
785void
786Free_Disk(struct disk *d)
787{
788	if(d->chunks) Free_Chunk(d->chunks);
789	if(d->name) free(d->name);
790#ifdef PC98
791	if(d->bootipl) free(d->bootipl);
792	if(d->bootmenu) free(d->bootmenu);
793#else
794	if(d->bootmgr) free(d->bootmgr);
795#endif
796	if(d->boot1) free(d->boot1);
797#if defined(__i386__)
798	if(d->boot2) free(d->boot2);
799#endif
800	free(d);
801}
802
803#if 0
804void
805Collapse_Disk(struct disk *d)
806{
807
808	while(Collapse_Chunk(d, d->chunks))
809		;
810}
811#endif
812
813static int
814qstrcmp(const void* a, const void* b)
815{
816
817	char *str1 = *(char**)a;
818	char *str2 = *(char**)b;
819	return strcmp(str1, str2);
820}
821
822char **
823Disk_Names()
824{
825	int disk_cnt;
826	static char **disks;
827	int error;
828	size_t listsize;
829	char *disklist;
830
831	error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
832	if (error) {
833		warn("kern.disks sysctl not available");
834		return NULL;
835	}
836
837	disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
838	if (disks == NULL)
839		return NULL;
840	disklist = (char *)malloc(listsize + 1);
841	if (disklist == NULL) {
842		free(disks);
843		return NULL;
844	}
845	memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
846	memset(disklist, 0, listsize + 1);
847	error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
848	if (error) {
849		free(disklist);
850		free(disks);
851		return NULL;
852	}
853	for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) {
854		disks[disk_cnt] = strsep(&disklist, " ");
855		if (disks[disk_cnt] == NULL)
856			break;
857											}
858	qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
859	return disks;
860}
861
862#ifdef PC98
863void
864Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size,
865	     const u_char *bootmenu, const size_t bootmenu_size)
866#else
867void
868Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
869#endif
870{
871#ifdef PC98
872	if (bootipl_size % d->sector_size != 0)
873		return;
874	if (d->bootipl)
875		free(d->bootipl);
876	if (!bootipl) {
877		d->bootipl = NULL;
878	} else {
879		d->bootipl_size = bootipl_size;
880		d->bootipl = malloc(bootipl_size);
881		if(!d->bootipl) return;
882		memcpy(d->bootipl, bootipl, bootipl_size);
883	}
884
885	if (bootmenu_size % d->sector_size != 0)
886		return;
887	if (d->bootmenu)
888		free(d->bootmenu);
889	if (!bootmenu) {
890		d->bootmenu = NULL;
891	} else {
892		d->bootmenu_size = bootmenu_size;
893		d->bootmenu = malloc(bootmenu_size);
894		if(!d->bootmenu) return;
895		memcpy(d->bootmenu, bootmenu, bootmenu_size);
896	}
897#else
898	if (s % d->sector_size != 0)
899		return;
900	if (d->bootmgr)
901		free(d->bootmgr);
902	if (!b) {
903		d->bootmgr = NULL;
904	} else {
905		d->bootmgr_size = s;
906		d->bootmgr = malloc(s);
907		if(!d->bootmgr) return;
908		memcpy(d->bootmgr, b, s);
909	}
910#endif
911}
912
913int
914Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
915{
916#if defined(__i386__)
917	if (d->boot1) free(d->boot1);
918	d->boot1 = malloc(512);
919	if(!d->boot1) return -1;
920	memcpy(d->boot1, b1, 512);
921	if (d->boot2) free(d->boot2);
922	d->boot2 = malloc(15 * 512);
923	if(!d->boot2) return -1;
924	memcpy(d->boot2, b2, 15 * 512);
925#elif defined(__alpha__)
926	if (d->boot1) free(d->boot1);
927	d->boot1 = malloc(15 * 512);
928	if(!d->boot1) return -1;
929	memcpy(d->boot1, b1, 15 * 512);
930#endif
931	return 0;
932}
933
934const char *
935slice_type_name( int type, int subtype )
936{
937	switch (type) {
938		case 0:		return "whole";
939#ifndef	PC98
940		case 1:		switch (subtype) {
941					case 1:		return "fat (12-bit)";
942					case 2:		return "XENIX /";
943					case 3:		return "XENIX /usr";
944					case 4:         return "fat (16-bit,<=32Mb)";
945					case 5:		return "extended DOS";
946					case 6:         return "fat (16-bit,>32Mb)";
947					case 7:         return "NTFS/HPFS/QNX";
948					case 8:         return "AIX bootable";
949					case 9:         return "AIX data";
950					case 10:	return "OS/2 bootmgr";
951					case 11:        return "fat (32-bit)";
952					case 12:        return "fat (32-bit,LBA)";
953					case 14:        return "fat (16-bit,>32Mb,LBA)";
954					case 15:        return "extended DOS, LBA";
955					case 18:        return "Compaq Diagnostic";
956					case 84:	return "OnTrack diskmgr";
957					case 100:	return "Netware 2.x";
958					case 101:	return "Netware 3.x";
959					case 115:	return "SCO UnixWare";
960					case 128:	return "Minix 1.1";
961					case 129:	return "Minix 1.5";
962					case 130:	return "linux_swap";
963					case 131:	return "ext2fs";
964					case 166:	return "OpenBSD FFS";	/* 0xA6 */
965					case 169:	return "NetBSD FFS";	/* 0xA9 */
966					case 182:	return "OpenBSD";		/* dedicated */
967					case 183:	return "bsd/os";
968					case 184:	return "bsd/os swap";
969					case 238:	return "EFI GPT";
970					case 239:	return "EFI Sys. Part.";
971					default:	return "unknown";
972				}
973#endif
974		case 2:		return "fat";
975		case 3:		switch (subtype) {
976#ifdef	PC98
977					case 0xc494:	return "freebsd";
978#else
979					case 165:	return "freebsd";
980#endif
981					default:	return "unknown";
982				}
983#ifndef	PC98
984		case 4:		return "extended";
985		case 5:		return "part";
986		case 6:		return "unused";
987#endif
988		default:	return "unknown";
989	}
990}
991