disk.c revision 105791
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 105791 2002-10-23 13:00:09Z nyan $");
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <fcntl.h>
17#include <string.h>
18#include <err.h>
19#include <sys/sysctl.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <sys/ioctl.h>
23#include <sys/disklabel.h>
24#include <sys/diskslice.h>
25#ifndef PC98
26#include <sys/diskmbr.h>
27#endif
28#include <paths.h>
29#include "libdisk.h"
30
31#ifndef PC98
32#define	HAVE_GEOM
33#endif
34#ifdef HAVE_GEOM
35#include <ctype.h>
36#include <errno.h>
37#include <assert.h>
38#endif /*HAVE_GEOM*/
39
40#ifndef PC98
41#define DOSPTYP_EXTENDED        5
42#define DOSPTYP_ONTRACK         84
43#endif
44
45#ifdef DEBUG
46#define	DPRINT(x)	warn x
47#define	DPRINTX(x)	warnx x
48#else
49#define	DPRINT(x)
50#define	DPRINTX(x)
51#endif
52
53const char *chunk_n[] = {
54	"whole",
55	"unknown",
56	"fat",
57	"freebsd",
58	"extended",
59	"part",
60	"unused",
61	NULL
62};
63
64struct disk *
65Open_Disk(const char *name)
66{
67	return Int_Open_Disk(name, 0);
68}
69
70#ifndef PC98
71static u_int32_t
72Read_Int32(u_int32_t *p)
73{
74    u_int8_t *bp = (u_int8_t *)p;
75    return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24);
76}
77#endif
78
79#ifdef HAVE_GEOM
80/*
81 * XXX BEGIN HACK XXX
82 * Scan/parse the XML geom data to retrieve what we need to
83 * carry out the work of Int_Open_Disk.  This is a total hack
84 * and should be replaced with a real XML parser.
85 */
86typedef enum {
87	XML_MESH,
88	XML_MESH_END,
89	XML_CLASS,
90	XML_CLASS_END,
91	XML_GEOM,
92	XML_GEOM_END,
93	XML_CONFIG,
94	XML_CONFIG_END,
95	XML_PROVIDER,
96	XML_PROVIDER_END,
97	XML_NAME,
98	XML_NAME_END,
99	XML_INDEX,
100	XML_INDEX_END,
101	XML_SECLENGTH,
102	XML_SECLENGTH_END,
103	XML_SECOFFSET,
104	XML_SECOFFSET_END,
105	XML_TYPE,
106	XML_TYPE_END,
107	XML_MEDIASIZE,
108	XML_MEDIASIZE_END,
109	XML_SECTORSIZE,
110	XML_SECTORSIZE_END,
111	XML_FWHEADS,
112	XML_FWHEADS_END,
113	XML_FWSECTORS,
114	XML_FWSECTORS_END,
115
116	XML_OTHER,
117	XML_OTHER_END
118} XMLToken;
119
120const struct {
121	XMLToken	t;
122	const char*	token;
123	const char*	name;
124} xmltokens[] = {
125	{ XML_MESH,		"mesh",		"XML_MESH" },
126	{ XML_CLASS,		"class",	"XML_CLASS" },
127	{ XML_GEOM,		"geom",		"XML_GEOM" },
128	{ XML_CONFIG,		"config",	"XML_CONFIG" },
129	{ XML_PROVIDER,		"provider",	"XML_PROVIDE" },
130	{ XML_NAME,		"name",		"XML_NAME" },
131	{ XML_INDEX,		"index",	"XML_INDEX" },
132	{ XML_SECLENGTH,	"seclength",	"XML_SECLENGTH" },
133	{ XML_SECOFFSET,	"secoffset",	"XML_SECOFFSET" },
134	{ XML_TYPE,		"type",		"XML_TYPE" },
135	{ XML_FWHEADS,		"fwheads",	"XML_FWHEADS" },
136	{ XML_FWSECTORS,	"fwsectors",	"XML_FWSECTORS" },
137	{ XML_MEDIASIZE,	"mediasize",	"XML_MEDIASIZE" },
138	{ XML_SECTORSIZE,	"sectorsize",	"XML_SECTORSIZE" },
139	/* NB: this must be last */
140	{ XML_OTHER,		NULL,		"XML_OTHER" },
141};
142#define	N(x)	(sizeof (x) / sizeof (x[0]))
143
144#ifdef DEBUG
145static const char*
146xmltokenname(XMLToken t)
147{
148	int i;
149
150	for (i = 0; i < N(xmltokens); i++) {
151		if (t == xmltokens[i].t)
152			return xmltokens[i].name;
153		if ((t-1) == xmltokens[i].t) {
154			static char tbuf[80];
155			snprintf(tbuf, sizeof (tbuf), "%s_END",
156				xmltokens[i].name);
157			return tbuf;
158		}
159	}
160	return "???";
161}
162#endif /*DEBUG*/
163
164/*
165 * Parse the next XML token delimited by <..>.  If the token
166 * has a "builtin terminator" (<... />) then just skip it and
167 * go the next token.
168 */
169static int
170xmltoken(const char *start, const char **next, XMLToken *t)
171{
172	const char *cp = start;
173	const char *token;
174	int i;
175
176again:
177	while (*cp != '<') {
178		if (*cp == '\0') {
179			*next = cp;
180			DPRINTX(("xmltoken: EOD"));
181			return 0;
182		}
183		cp++;
184	}
185	token = ++cp;
186	for (; *cp && *cp != '>' && !isspace(*cp); cp++)
187		;
188	if (*cp == '\0') {
189		*next = cp;
190		DPRINTX(("xmltoken: EOD"));
191		return 0;
192	}
193	*t = (*token == '/');
194	if (*t)
195		token++;
196	for (i = 0; xmltokens[i].token != NULL; i++)
197		if (strncasecmp(token, xmltokens[i].token, cp-token) == 0)
198			break;
199	*t += xmltokens[i].t;
200	/* now collect the remainder of the string */
201	for (; *cp != '>' && *cp != '\0'; cp++)
202		;
203	if (*cp == '\0') {
204		*next = cp;
205		DPRINTX(("xmltoken: EOD"));
206		return 0;
207	}
208	if (cp > token && cp[-1] == '/') {
209		/* e.g. <geom ref="0xc1c8c100"/> */
210		start = cp+1;
211		goto again;
212	}
213	*next = cp+1;
214	DPRINTX(("xmltoken: %s \"%.*s\"", xmltokenname(*t), cp-token, token));
215	return 1;
216}
217
218/*
219 * Parse and discard XML up to the token terminator.
220 */
221static int
222discardxml(const char **next, XMLToken terminator)
223{
224	const char *xml = *next;
225	XMLToken t;
226
227	DPRINTX(("discard XML up to %s", xmltokenname(terminator)));
228	for (;;) {
229		if (xmltoken(xml, next, &t) == 0)
230			return EINVAL;
231		if (t == terminator)
232			break;
233		if ((t & 1) == 0) {
234			int error = discardxml(next, t+1);
235			if (error)
236				return error;
237		}
238		xml = *next;
239	}
240	return 0;
241}
242
243/*
244 * Parse XML from between a range of markers; e.g. <mesh> ... </mesh>.
245 * When the specified class name is located we descend looking for the
246 * geometry information given by diskname.  Once inside there we process
247 * tags calling f back for each useful one.  The arg is passed into f
248 * for use in storing the parsed data.
249 */
250static int
251parsexmlpair(
252	const char *xml,
253	const char **next,
254	const char *classname,
255	XMLToken terminator,
256	const char *diskname,
257	int (*f)(void *, XMLToken, u_int *, u_int64_t),
258	void *arg
259)
260{
261	const char *cp;
262	XMLToken t;
263	int error;
264	u_int ix = (u_int) -1;
265
266	DPRINTX(("parse XML up to %s", xmltokenname(terminator)));
267	do {
268		if (xmltoken(xml, next, &t) == 0) {
269			error = EINVAL;
270			break;
271		}
272		if (t == terminator) {
273			error = 0;
274			break;
275		}
276		if (t & 1) {		/* </mumble> w/o matching <mumble> */
277			DPRINTX(("Unexpected token %s", xmltokenname(t)));
278			error = EINVAL;
279			break;
280		}
281		switch ((int) t) {
282		case XML_NAME:
283			for (cp = *next; *cp && *cp != '<'; cp++)
284				;
285			if (*cp == '\0') {
286				DPRINTX(("parsexmlpair: EOD"));
287				error = EINVAL;
288				goto done;
289			    }
290			DPRINTX(("parsexmlpair: \"%.*s\"", cp-*next, *next));
291			switch ((int) terminator) {
292			case XML_CLASS_END:
293				if (strncasecmp(*next, classname, cp-*next))
294					return discardxml(next, terminator);
295				break;
296			case XML_GEOM_END:
297				if (strncasecmp(*next, diskname, cp-*next))
298					return discardxml(next, terminator);
299				break;
300			}
301			break;
302		case XML_SECOFFSET:
303		case XML_SECLENGTH:
304		case XML_TYPE:
305			if (ix == (u_int) -1) {
306				DPRINTX(("parsexmlpair: slice data w/o "
307					"preceding index"));
308				error = EINVAL;
309				goto done;
310			}
311			/* fall thru... */
312		case XML_INDEX:
313		case XML_FWHEADS:
314		case XML_FWSECTORS:
315		case XML_MEDIASIZE:
316		case XML_SECTORSIZE:
317			if (terminator != XML_CONFIG_END &&
318			    terminator != XML_PROVIDER_END) {
319				DPRINTX(("parsexmlpair: %s in unexpected "
320				      "context: terminator %s",
321				      xmltokenname(t),
322				      xmltokenname(terminator)));
323				error = EINVAL;
324				goto done;
325			}
326			error = (*f)(arg, t, &ix, strtoull(*next, NULL, 10));
327			if (error)
328				goto done;
329			break;
330		}
331		error = parsexmlpair(*next, &xml, classname,
332				     t+1, diskname, f, arg);
333	} while (error == 0);
334done:
335	return error;
336}
337
338/*
339 * XML parser.  Just barely smart enough to handle the
340 * gibberish that geom passed back from the kernel.
341 */
342static int
343xmlparse(
344	const char *confxml,
345	const char *classname,
346	const char *diskname,
347	int (*f)(void *, XMLToken, u_int *, u_int64_t),
348	void *arg
349)
350{
351	const char *next;
352	XMLToken t;
353	int error;
354
355	next = confxml;
356	while (xmltoken(next, &next, &t) && t != XML_MESH)
357		;
358	if (t == XML_MESH)
359		error = parsexmlpair(next, &next, classname, XML_MESH_END, diskname, f, arg);
360	else {
361		DPRINTX(("xmlparse: expecting mesh token, got %s",
362		      xmltokenname(t)));
363		error = EINVAL;
364	}
365
366	return (error ? -1 : 0);
367}
368
369/*
370 * Callback to collect slice-related data.
371 */
372static int
373assignToSlice(void *arg, XMLToken t, u_int *slice, u_int64_t v)
374{
375	struct diskslices *ds = (struct diskslices *) arg;
376
377	switch ((int) t) {
378	case XML_INDEX:
379		*slice = BASE_SLICE + (u_int) v;
380		if (*slice >= MAX_SLICES) {
381			DPRINTX(("assignToSlice: invalid slice index %u > max %u",
382			      *slice, MAX_SLICES));
383			return EINVAL;
384		}
385		if (*slice >= ds->dss_nslices)
386			ds->dss_nslices = (*slice)+1;
387		break;
388	case XML_SECOFFSET:
389		ds->dss_slices[*slice].ds_offset = (u_long) v;
390		break;
391	case XML_SECLENGTH:
392		ds->dss_slices[*slice].ds_size = (u_long) v;
393		break;
394	case XML_TYPE:
395		ds->dss_slices[*slice].ds_type = (int) v;
396		break;
397	}
398	return 0;
399}
400
401/*
402 * Callback to collect disk-related data.
403 */
404static int
405assignToDisk(void *arg, XMLToken t, const u_int *slice, u_int64_t v)
406{
407	struct disklabel *dl = (struct disklabel *) arg;
408
409	switch ((int) t) {
410	case XML_FWHEADS:
411		dl->d_ntracks = (u_int32_t) v;
412	case XML_FWSECTORS:
413		dl->d_nsectors = (u_int32_t) v;
414		break;
415	case XML_MEDIASIZE:
416		/* store this temporarily; it gets moved later */
417		dl->d_secpercyl = v >> 32;
418		dl->d_secperunit = v & 0xffffffff;
419		break;
420	case XML_SECTORSIZE:
421		dl->d_secsize = (u_int32_t) v;
422		break;
423	}
424	return 0;
425}
426
427/*
428 * Callback to collect partition-related data.
429 */
430static int
431assignToPartition(void *arg, XMLToken t, u_int *part, u_int64_t v)
432{
433	struct disklabel *dl = (struct disklabel *) arg;
434
435	switch ((int) t) {
436	case XML_INDEX:
437		*part = (u_int) v;
438		if (*part >= MAXPARTITIONS) {
439			DPRINTX(("assignToPartition: invalid partition index %u > max %u",
440			      *part, MAXPARTITIONS));
441			return EINVAL;
442		}
443		if (*part >= dl->d_npartitions)
444			dl->d_npartitions = (*part)+1;
445		break;
446	case XML_SECOFFSET:
447		dl->d_partitions[*part].p_offset = (u_int32_t) v;
448		break;
449	case XML_SECLENGTH:
450		dl->d_partitions[*part].p_size = (u_int32_t) v;
451		break;
452	case XML_TYPE:
453		dl->d_partitions[*part].p_fstype = (u_int8_t) v;
454		break;
455	}
456	return 0;
457}
458#undef N
459#endif /*HAVE_GEOM*/
460
461struct disk *
462Int_Open_Disk(const char *name, u_long size)
463{
464	int i;
465	int fd = -1;
466	struct diskslices ds;
467	struct disklabel dl;
468	char device[64];
469	struct disk *d;
470#ifdef PC98
471	unsigned char *p;
472#else
473	struct dos_partition *dp;
474	void *p;
475#endif
476#ifdef HAVE_GEOM
477	char *confxml = NULL;
478	size_t xmlsize;
479	u_int64_t mediasize;
480	int error;
481#else
482	u_long sector_size;
483	char *buf;
484#endif /*HAVE_GEOM*/
485
486	strlcpy(device, _PATH_DEV, sizeof(device));
487	strlcat(device, name, sizeof(device));
488
489	d = (struct disk *)malloc(sizeof *d);
490	if(!d) return NULL;
491	memset(d, 0, sizeof *d);
492
493	fd = open(device, O_RDONLY);
494	if (fd < 0) {
495		DPRINT(("open(%s) failed", device));
496		goto bad;
497	}
498
499	memset(&dl, 0, sizeof dl);
500	memset(&ds, 0, sizeof ds);
501#ifdef HAVE_GEOM
502	/*
503	 * Read and hack-parse the XML that provides the info we need.
504	 */
505	error = sysctlbyname("kern.geom.confxml", NULL, &xmlsize, NULL, 0);
506	if (error) {
507		warn("kern.geom.confxml sysctl not available, giving up!");
508		goto bad;
509	}
510	confxml = (char *) malloc(xmlsize+1);
511	if (confxml == NULL) {
512		DPRINT(("cannot malloc memory for confxml"));
513		goto bad;
514	}
515	error = sysctlbyname("kern.geom.confxml", confxml, &xmlsize, NULL, 0);
516	if (error) {
517		DPRINT(("error reading kern.geom.confxml from the system"));
518		goto bad;
519	}
520	confxml[xmlsize] = '\0';	/* in case kernel bug is still there */
521
522	if (xmlparse(confxml, "MBR", name, assignToSlice, &ds) != 0) {
523		DPRINTX(("Error parsing MBR geometry specification."));
524		goto bad;
525	}
526	if (xmlparse(confxml, "DISK", name, assignToDisk, &dl) != 0) {
527		DPRINTX(("Error parsing DISK geometry specification."));
528		goto bad;
529	}
530	if (dl.d_nsectors == 0) {
531		DPRINTX(("No (zero) sector information in DISK geometry"));
532		goto bad;
533	}
534	if (dl.d_ntracks == 0) {
535		DPRINTX(("No (zero) track information in DISK geometry"));
536		goto bad;
537	}
538	if (dl.d_secsize == 0) {
539		DPRINTX(("No (zero) sector size information in DISK geometry"));
540		goto bad;
541	}
542	if (dl.d_secpercyl == 0 && dl.d_secperunit == 0) {
543		DPRINTX(("No (zero) media size information in DISK geometry"));
544		goto bad;
545	}
546	/*
547	 * Now patch up disklabel and diskslice.
548	 */
549	d->sector_size = dl.d_secsize;
550	/* NB: media size was stashed in two parts while parsing */
551	mediasize = (((u_int64_t) dl.d_secpercyl) << 32) + dl.d_secperunit;
552	dl.d_secpercyl = 0;
553	dl.d_secperunit = 0;
554	size = mediasize / d->sector_size;
555	dl.d_ncylinders = size / (dl.d_ntracks * dl.d_nsectors);
556	/* "whole disk" slice maintained for compatibility */
557	ds.dss_slices[WHOLE_DISK_SLICE].ds_size = size;
558#else /* !HAVE_GEOM */
559	if (ioctl(fd, DIOCGDINFO, &dl) < 0) {
560		DPRINT(("DIOCGDINFO(%s) failed", device));
561		goto bad;
562	}
563	i = ioctl(fd, DIOCGSLICEINFO, &ds);
564	if (i < 0) {
565		DPRINT(("DIOCGSLICEINFO(%s) failed", device));
566		goto bad;
567	}
568
569#ifdef DEBUG
570	for(i = 0; i < ds.dss_nslices; i++)
571		if(ds.dss_slices[i].ds_openmask)
572			printf("  open(%d)=0x%2x",
573				i, ds.dss_slices[i].ds_openmask);
574	printf("\n");
575#endif
576
577/* XXX --- ds.dss_slice[WHOLE_DISK_SLICE].ds.size of MO disk is wrong!!! */
578#ifdef PC98
579	if (!size)
580		size = dl.d_ncylinders * dl.d_ntracks * dl.d_nsectors;
581#else
582	if (!size)
583		size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size;
584#endif
585
586	/* determine media sector size */
587	if ((buf = malloc(MAX_SEC_SIZE)) == NULL)
588		return NULL;
589	for (sector_size = MIN_SEC_SIZE; sector_size <= MAX_SEC_SIZE; sector_size *= 2) {
590		if (read(fd, buf, sector_size) == sector_size) {
591			d->sector_size = sector_size;
592			break;
593		}
594	}
595	free (buf);
596	if (sector_size > MAX_SEC_SIZE) {
597		DPRINT(("Int_Open_Disk: could not determine sector size, "
598		     "calculated %u, max %u\n", sector_size, MAX_SEC_SIZE));
599		/* could not determine sector size */
600		goto bad;
601	}
602#endif /*HAVE_GEOM*/
603
604#ifdef PC98
605	p = (unsigned char*)read_block(fd, 1, d->sector_size);
606#else
607	p = read_block(fd, 0, d->sector_size);
608	dp = (struct dos_partition*)(p + DOSPARTOFF);
609	for (i = 0; i < NDOSPART; i++) {
610		if (Read_Int32(&dp->dp_start) >= size)
611		    continue;
612		if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size)
613		    continue;
614		if (!Read_Int32(&dp->dp_size))
615		    continue;
616	}
617	free(p);
618#endif
619
620	d->bios_sect = dl.d_nsectors;
621	d->bios_hd = dl.d_ntracks;
622
623	d->name = strdup(name);
624
625
626	if (dl.d_ntracks && dl.d_nsectors)
627		d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors);
628
629	if (Add_Chunk(d, 0, size, name, whole, 0, 0, "-"))
630		DPRINT(("Failed to add 'whole' chunk"));
631
632#ifdef __i386__
633#ifdef PC98
634	/* XXX -- Quick Hack!
635	 * Check MS-DOS MO
636	 */
637	if ((*p == 0xf0 || *p == 0xf8) &&
638	    (*(p+1) == 0xff) &&
639	    (*(p+2) == 0xff)) {
640		Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name);
641	    free(p);
642	    goto pc98_mo_done;
643	}
644	free(p);
645#endif /* PC98 */
646	for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
647		char sname[20];
648		char pname[20];
649		chunk_e ce;
650		u_long flags=0;
651		int subtype=0;
652		int j;
653
654		if (! ds.dss_slices[i].ds_size)
655			continue;
656		snprintf(sname, sizeof(sname), "%ss%d", name, i - 1);
657#ifdef PC98
658		subtype = ds.dss_slices[i].ds_type |
659			ds.dss_slices[i].ds_subtype << 8;
660		switch (ds.dss_slices[i].ds_type & 0x7f) {
661			case 0x14:
662				ce = freebsd;
663				break;
664			case 0x20:
665			case 0x21:
666			case 0x22:
667			case 0x23:
668			case 0x24:
669				ce = fat;
670				break;
671#else /* IBM-PC */
672		subtype = ds.dss_slices[i].ds_type;
673		switch (ds.dss_slices[i].ds_type) {
674			case 0xa5:
675				ce = freebsd;
676				break;
677			case 0x1:
678			case 0x6:
679			case 0x4:
680			case 0xb:
681			case 0xc:
682			case 0xe:
683				ce = fat;
684				break;
685			case DOSPTYP_EXTENDED:
686			case 0xf:
687				ce = extended;
688				break;
689#endif
690			default:
691				ce = unknown;
692				break;
693		}
694#ifdef PC98
695		if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
696			ds.dss_slices[i].ds_size, sname, ce, subtype, flags,
697			ds.dss_slices[i].ds_name))
698#else
699		if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
700			ds.dss_slices[i].ds_size, sname, ce, subtype, flags, ""))
701#endif
702			DPRINT(("failed to add chunk for slice %d", i - 1));
703
704#ifdef PC98
705		if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14)
706#else
707		if (ds.dss_slices[i].ds_type != 0xa5)
708#endif
709			continue;
710#ifdef HAVE_GEOM
711		if (xmlparse(confxml, "BSD", sname, assignToPartition, &dl) != 0) {
712			DPRINTX(("Error parsing MBR geometry specification."));
713			goto bad;
714		}
715#else
716		{
717		struct disklabel dl;
718		int k;
719
720		strlcpy(pname, _PATH_DEV, sizeof(pname));
721		strlcat(pname, sname, sizeof(pname));
722		j = open(pname, O_RDONLY);
723		if (j < 0) {
724			DPRINT(("open(%s)", pname));
725			continue;
726		}
727		k = ioctl(j, DIOCGDINFO, &dl);
728		if (k < 0) {
729			DPRINT(("ioctl(%s, DIOCGDINFO)", pname));
730			close(j);
731			continue;
732		}
733		close(j);
734		}
735#endif /*HAVE_GEOM*/
736
737		for(j = 0; j <= dl.d_npartitions; j++) {
738			if (j == RAW_PART)
739				continue;
740			if (j == 3)
741				continue;
742			if (j == dl.d_npartitions) {
743				j = 3;
744				dl.d_npartitions = 0;
745			}
746			if (!dl.d_partitions[j].p_size)
747				continue;
748			if (dl.d_partitions[j].p_size +
749			    dl.d_partitions[j].p_offset >
750			    ds.dss_slices[i].ds_size)
751				continue;
752			snprintf(pname, sizeof(pname), "%s%c", sname, j + 'a');
753			if (Add_Chunk(d,
754				dl.d_partitions[j].p_offset +
755				ds.dss_slices[i].ds_offset,
756				dl.d_partitions[j].p_size,
757				pname,part,
758				dl.d_partitions[j].p_fstype,
759#ifdef PC98
760				0,
761				ds.dss_slices[i].ds_name) && j != 3)
762#else
763				0, "") && j != 3)
764#endif
765				DPRINT((
766			"Failed to add chunk for partition %c [%lu,%lu]",
767			j + 'a', dl.d_partitions[j].p_offset,
768			dl.d_partitions[j].p_size));
769		}
770	}
771#endif /* __i386__ */
772#ifdef __alpha__
773	{
774		struct disklabel dl;
775		char pname[20];
776		int j,k;
777
778		strlcpy(pname, _PATH_DEV, sizeof(pname));
779		strlcat(pname, name, sizeof(pname));
780		j = open(pname, O_RDONLY);
781		if (j < 0) {
782			DPRINT(("open(%s)", pname));
783			goto nolabel;
784		}
785		k = ioctl(j, DIOCGDINFO, &dl);
786		if (k < 0) {
787			DPRINT(("ioctl(%s, DIOCGDINFO)", pname));
788			close(j);
789			goto nolabel;
790		}
791		close(j);
792		All_FreeBSD(d, 1);
793
794		for(j = 0; j <= dl.d_npartitions; j++) {
795			if (j == RAW_PART)
796				continue;
797			if (j == 3)
798				continue;
799			if (j == dl.d_npartitions) {
800				j = 3;
801				dl.d_npartitions = 0;
802			}
803			if (!dl.d_partitions[j].p_size)
804				continue;
805			if (dl.d_partitions[j].p_size +
806			    dl.d_partitions[j].p_offset >
807			    ds.dss_slices[WHOLE_DISK_SLICE].ds_size)
808				continue;
809			snprintf(pname, sizeof(pname), "%s%c", name, j + 'a');
810			if (Add_Chunk(d,
811				      dl.d_partitions[j].p_offset,
812				      dl.d_partitions[j].p_size,
813				      pname,part,
814				      dl.d_partitions[j].p_fstype,
815				      0, "") && j != 3)
816				DPRINT((
817					"Failed to add chunk for partition %c [%lu,%lu]",
818					j + 'a', dl.d_partitions[j].p_offset,
819					dl.d_partitions[j].p_size));
820		}
821	nolabel:;
822	}
823#endif /* __alpha__ */
824#ifdef PC98
825pc98_mo_done:
826#endif
827	close(fd);
828	Fixup_Names(d);
829	return d;
830bad:
831#ifdef HAVE_GEOM
832	if (confxml != NULL)
833		free(confxml);
834#endif
835	if (fd >= 0)
836		close(fd);
837	return NULL;
838}
839
840void
841Debug_Disk(struct disk *d)
842{
843	printf("Debug_Disk(%s)", d->name);
844#if 0
845	printf("  real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect);
846#endif
847	printf("  bios_geom=%lu/%lu/%lu = %lu\n",
848		d->bios_cyl, d->bios_hd, d->bios_sect,
849		d->bios_cyl * d->bios_hd * d->bios_sect);
850#if defined(PC98)
851	printf("  boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n",
852		d->boot1, d->boot2, d->bootipl, d->bootmenu);
853#elif defined(__i386__)
854	printf("  boot1=%p, boot2=%p, bootmgr=%p\n",
855		d->boot1, d->boot2, d->bootmgr);
856#elif defined(__alpha__)
857	printf("  boot1=%p, bootmgr=%p\n",
858		d->boot1, d->bootmgr);
859#endif
860	Debug_Chunk(d->chunks);
861}
862
863void
864Free_Disk(struct disk *d)
865{
866	if(d->chunks) Free_Chunk(d->chunks);
867	if(d->name) free(d->name);
868#ifdef PC98
869	if(d->bootipl) free(d->bootipl);
870	if(d->bootmenu) free(d->bootmenu);
871#else
872	if(d->bootmgr) free(d->bootmgr);
873#endif
874	if(d->boot1) free(d->boot1);
875#if defined(__i386__)
876	if(d->boot2) free(d->boot2);
877#endif
878	free(d);
879}
880
881#if 0
882void
883Collapse_Disk(struct disk *d)
884{
885
886	while(Collapse_Chunk(d, d->chunks))
887		;
888}
889#endif
890
891#ifdef PC98
892static char * device_list[] = {"wd", "aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0};
893#else
894static char * device_list[] = {"aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0};
895#endif
896
897int qstrcmp(const void* a, const void* b) {
898
899	char *str1 = *(char**)a;
900	char *str2 = *(char**)b;
901	return strcmp(str1, str2);
902
903}
904
905char **
906Disk_Names()
907{
908    int i,j,disk_cnt;
909    char disk[25];
910    char diskname[25];
911    struct stat st;
912    struct diskslices ds;
913    int fd;
914    static char **disks;
915    int error;
916    size_t listsize;
917    char *disklist;
918
919    disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
920    if (disks == NULL)
921	    return NULL;
922    memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
923    error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
924    if (!error) {
925	    disklist = (char *)malloc(listsize+1);
926	    if (disklist == NULL) {
927		    free(disks);
928		    return NULL;
929	    }
930	    memset(disklist, 0, listsize+1);
931	    error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
932	    if (error) {
933		    free(disklist);
934		    free(disks);
935		    return NULL;
936	    }
937	    for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) {
938		    disks[disk_cnt] = strsep(&disklist, " ");
939		    if (disks[disk_cnt] == NULL)
940			    break;
941											    }
942    } else {
943    warn("kern.disks sysctl not available");
944    disk_cnt = 0;
945	for (j = 0; device_list[j]; j++) {
946		if(disk_cnt >= MAX_NO_DISKS)
947			break;
948		for (i = 0; i < MAX_NO_DISKS; i++) {
949			snprintf(diskname, sizeof(diskname), "%s%d",
950				device_list[j], i);
951			snprintf(disk, sizeof(disk), _PATH_DEV"%s", diskname);
952			if (stat(disk, &st) || !(st.st_mode & S_IFCHR))
953				continue;
954			if ((fd = open(disk, O_RDWR)) == -1)
955				continue;
956			if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) {
957				DPRINT(("DIOCGSLICEINFO %s", disk));
958				close(fd);
959				continue;
960			}
961			close(fd);
962			disks[disk_cnt++] = strdup(diskname);
963			if(disk_cnt >= MAX_NO_DISKS)
964				break;
965		}
966	}
967    }
968    qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
969
970    return disks;
971}
972
973#ifdef PC98
974void
975Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size,
976	     const u_char *bootmenu, const size_t bootmenu_size)
977#else
978void
979Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
980#endif
981{
982#ifdef PC98
983	if (bootipl_size % d->sector_size != 0)
984		return;
985	if (d->bootipl)
986		free(d->bootipl);
987	if (!bootipl) {
988		d->bootipl = NULL;
989	} else {
990		d->bootipl_size = bootipl_size;
991		d->bootipl = malloc(bootipl_size);
992		if(!d->bootipl) return;
993		memcpy(d->bootipl, bootipl, bootipl_size);
994	}
995
996	if (bootmenu_size % d->sector_size != 0)
997		return;
998	if (d->bootmenu)
999		free(d->bootmenu);
1000	if (!bootmenu) {
1001		d->bootmenu = NULL;
1002	} else {
1003		d->bootmenu_size = bootmenu_size;
1004		d->bootmenu = malloc(bootmenu_size);
1005		if(!d->bootmenu) return;
1006		memcpy(d->bootmenu, bootmenu, bootmenu_size);
1007	}
1008#else
1009	if (s % d->sector_size != 0)
1010		return;
1011	if (d->bootmgr)
1012		free(d->bootmgr);
1013	if (!b) {
1014		d->bootmgr = NULL;
1015	} else {
1016		d->bootmgr_size = s;
1017		d->bootmgr = malloc(s);
1018		if(!d->bootmgr) return;
1019		memcpy(d->bootmgr, b, s);
1020	}
1021#endif
1022}
1023
1024int
1025Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
1026{
1027#if defined(__i386__)
1028	if (d->boot1) free(d->boot1);
1029	d->boot1 = malloc(512);
1030	if(!d->boot1) return -1;
1031	memcpy(d->boot1, b1, 512);
1032	if (d->boot2) free(d->boot2);
1033	d->boot2 = malloc(15 * 512);
1034	if(!d->boot2) return -1;
1035	memcpy(d->boot2, b2, 15 * 512);
1036#elif defined(__alpha__)
1037	if (d->boot1) free(d->boot1);
1038	d->boot1 = malloc(15 * 512);
1039	if(!d->boot1) return -1;
1040	memcpy(d->boot1, b1, 15 * 512);
1041#endif
1042	return 0;
1043}
1044
1045const char *
1046slice_type_name( int type, int subtype )
1047{
1048	switch (type) {
1049		case 0:		return "whole";
1050#ifndef	PC98
1051		case 1:		switch (subtype) {
1052					case 1:		return "fat (12-bit)";
1053					case 2:		return "XENIX /";
1054					case 3:		return "XENIX /usr";
1055					case 4:         return "fat (16-bit,<=32Mb)";
1056					case 5:		return "extended DOS";
1057					case 6:         return "fat (16-bit,>32Mb)";
1058					case 7:         return "NTFS/HPFS/QNX";
1059					case 8:         return "AIX bootable";
1060					case 9:         return "AIX data";
1061					case 10:	return "OS/2 bootmgr";
1062					case 11:        return "fat (32-bit)";
1063					case 12:        return "fat (32-bit,LBA)";
1064					case 14:        return "fat (16-bit,>32Mb,LBA)";
1065					case 15:        return "extended DOS, LBA";
1066					case 18:        return "Compaq Diagnostic";
1067					case 84:	return "OnTrack diskmgr";
1068					case 100:	return "Netware 2.x";
1069					case 101:	return "Netware 3.x";
1070					case 115:	return "SCO UnixWare";
1071					case 128:	return "Minix 1.1";
1072					case 129:	return "Minix 1.5";
1073					case 130:	return "linux_swap";
1074					case 131:	return "ext2fs";
1075					case 166:	return "OpenBSD FFS";	/* 0xA6 */
1076					case 169:	return "NetBSD FFS";	/* 0xA9 */
1077					case 182:	return "OpenBSD";		/* dedicated */
1078					case 183:	return "bsd/os";
1079					case 184:	return "bsd/os swap";
1080					case 238:	return "EFI GPT";
1081					case 239:	return "EFI Sys. Part.";
1082					default:	return "unknown";
1083				}
1084#endif
1085		case 2:		return "fat";
1086		case 3:		switch (subtype) {
1087#ifdef	PC98
1088					case 0xc494:	return "freebsd";
1089#else
1090					case 165:	return "freebsd";
1091#endif
1092					default:	return "unknown";
1093				}
1094#ifndef	PC98
1095		case 4:		return "extended";
1096		case 5:		return "part";
1097		case 6:		return "unused";
1098#endif
1099		default:	return "unknown";
1100	}
1101}
1102