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