disk.c revision 105681
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 105681 2002-10-22 09:13:02Z 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#ifdef PC98
628	if (Add_Chunk(d, 0, size, name, whole, 0, 0, "-"))
629#else
630	if (Add_Chunk(d, 0, size, name, whole, 0, 0))
631#endif
632		DPRINT(("Failed to add 'whole' chunk"));
633
634#ifdef __i386__
635#ifdef PC98
636	/* XXX -- Quick Hack!
637	 * Check MS-DOS MO
638	 */
639	if ((*p == 0xf0 || *p == 0xf8) &&
640	    (*(p+1) == 0xff) &&
641	    (*(p+2) == 0xff)) {
642		Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name);
643	    free(p);
644	    goto pc98_mo_done;
645	}
646	free(p);
647#endif /* PC98 */
648	for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
649		char sname[20];
650		char pname[20];
651		chunk_e ce;
652		u_long flags=0;
653		int subtype=0;
654		int j;
655
656		if (! ds.dss_slices[i].ds_size)
657			continue;
658		snprintf(sname, sizeof(sname), "%ss%d", name, i - 1);
659#ifdef PC98
660		subtype = ds.dss_slices[i].ds_type |
661			ds.dss_slices[i].ds_subtype << 8;
662		switch (ds.dss_slices[i].ds_type & 0x7f) {
663			case 0x14:
664				ce = freebsd;
665				break;
666			case 0x20:
667			case 0x21:
668			case 0x22:
669			case 0x23:
670			case 0x24:
671				ce = fat;
672				break;
673#else /* IBM-PC */
674		subtype = ds.dss_slices[i].ds_type;
675		switch (ds.dss_slices[i].ds_type) {
676			case 0xa5:
677				ce = freebsd;
678				break;
679			case 0x1:
680			case 0x6:
681			case 0x4:
682			case 0xb:
683			case 0xc:
684			case 0xe:
685				ce = fat;
686				break;
687			case DOSPTYP_EXTENDED:
688			case 0xf:
689				ce = extended;
690				break;
691#endif
692			default:
693				ce = unknown;
694				break;
695		}
696#ifdef PC98
697		if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
698			ds.dss_slices[i].ds_size, sname, ce, subtype, flags,
699			ds.dss_slices[i].ds_name))
700#else
701		if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
702			ds.dss_slices[i].ds_size, sname, ce, subtype, flags))
703#endif
704			DPRINT(("failed to add chunk for slice %d", i - 1));
705
706#ifdef PC98
707		if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14)
708#else
709		if (ds.dss_slices[i].ds_type != 0xa5)
710#endif
711			continue;
712#ifdef HAVE_GEOM
713		if (xmlparse(confxml, "BSD", sname, assignToPartition, &dl) != 0) {
714			DPRINTX(("Error parsing MBR geometry specification."));
715			goto bad;
716		}
717#else
718		{
719		struct disklabel dl;
720		int k;
721
722		strlcpy(pname, _PATH_DEV, sizeof(pname));
723		strlcat(pname, sname, sizeof(pname));
724		j = open(pname, O_RDONLY);
725		if (j < 0) {
726			DPRINT(("open(%s)", pname));
727			continue;
728		}
729		k = ioctl(j, DIOCGDINFO, &dl);
730		if (k < 0) {
731			DPRINT(("ioctl(%s, DIOCGDINFO)", pname));
732			close(j);
733			continue;
734		}
735		close(j);
736		}
737#endif /*HAVE_GEOM*/
738
739		for(j = 0; j <= dl.d_npartitions; j++) {
740			if (j == RAW_PART)
741				continue;
742			if (j == 3)
743				continue;
744			if (j == dl.d_npartitions) {
745				j = 3;
746				dl.d_npartitions = 0;
747			}
748			if (!dl.d_partitions[j].p_size)
749				continue;
750			if (dl.d_partitions[j].p_size +
751			    dl.d_partitions[j].p_offset >
752			    ds.dss_slices[i].ds_size)
753				continue;
754			snprintf(pname, sizeof(pname), "%s%c", sname, j + 'a');
755			if (Add_Chunk(d,
756				dl.d_partitions[j].p_offset +
757				ds.dss_slices[i].ds_offset,
758				dl.d_partitions[j].p_size,
759				pname,part,
760				dl.d_partitions[j].p_fstype,
761#ifdef PC98
762				0,
763				ds.dss_slices[i].ds_name) && j != 3)
764#else
765				0) && j != 3)
766#endif
767				DPRINT((
768			"Failed to add chunk for partition %c [%lu,%lu]",
769			j + 'a', dl.d_partitions[j].p_offset,
770			dl.d_partitions[j].p_size));
771		}
772	}
773#endif /* __i386__ */
774#ifdef __alpha__
775	{
776		struct disklabel dl;
777		char pname[20];
778		int j,k;
779
780		strlcpy(pname, _PATH_DEV, sizeof(pname));
781		strlcat(pname, name, sizeof(pname));
782		j = open(pname, O_RDONLY);
783		if (j < 0) {
784			DPRINT(("open(%s)", pname));
785			goto nolabel;
786		}
787		k = ioctl(j, DIOCGDINFO, &dl);
788		if (k < 0) {
789			DPRINT(("ioctl(%s, DIOCGDINFO)", pname));
790			close(j);
791			goto nolabel;
792		}
793		close(j);
794		All_FreeBSD(d, 1);
795
796		for(j = 0; j <= dl.d_npartitions; j++) {
797			if (j == RAW_PART)
798				continue;
799			if (j == 3)
800				continue;
801			if (j == dl.d_npartitions) {
802				j = 3;
803				dl.d_npartitions = 0;
804			}
805			if (!dl.d_partitions[j].p_size)
806				continue;
807			if (dl.d_partitions[j].p_size +
808			    dl.d_partitions[j].p_offset >
809			    ds.dss_slices[WHOLE_DISK_SLICE].ds_size)
810				continue;
811			snprintf(pname, sizeof(pname), "%s%c", name, j + 'a');
812			if (Add_Chunk(d,
813				      dl.d_partitions[j].p_offset,
814				      dl.d_partitions[j].p_size,
815				      pname,part,
816				      dl.d_partitions[j].p_fstype,
817				      0) && j != 3)
818				DPRINT((
819					"Failed to add chunk for partition %c [%lu,%lu]",
820					j + 'a', dl.d_partitions[j].p_offset,
821					dl.d_partitions[j].p_size));
822		}
823	nolabel:;
824	}
825#endif /* __alpha__ */
826#ifdef PC98
827pc98_mo_done:
828#endif
829	close(fd);
830	Fixup_Names(d);
831	return d;
832bad:
833	if (confxml != NULL)
834		free(confxml);
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