disk.c revision 105575
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 105575 2002-10-20 22:19:37Z sam $");
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, 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_nsectors = (u_int32_t) v;
410	case XML_FWSECTORS:
411		dl->d_ntracks = (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	u_long offset = 0;
475#ifdef HAVE_GEOM
476	char *confxml = NULL;
477	size_t xmlsize;
478	u_int64_t mediasize;
479	int error;
480#else
481	u_long sector_size;
482	char *buf;
483#endif /*HAVE_GEOM*/
484
485	strlcpy(device, _PATH_DEV, sizeof(device));
486	strlcat(device, name, sizeof(device));
487
488	d = (struct disk *)malloc(sizeof *d);
489	if(!d) return NULL;
490	memset(d, 0, sizeof *d);
491
492	fd = open(device, O_RDONLY);
493	if (fd < 0) {
494		DPRINT(("open(%s) failed", device));
495		goto bad;
496	}
497
498	memset(&dl, 0, sizeof dl);
499	memset(&ds, 0, sizeof ds);
500#ifdef HAVE_GEOM
501	/*
502	 * Read and hack-parse the XML that provides the info we need.
503	 */
504	error = sysctlbyname("kern.geom.confxml", NULL, &xmlsize, NULL, 0);
505	if (error) {
506		warn("kern.geom.confxml sysctl not available, giving up!");
507		goto bad;
508	}
509	confxml = (char *) malloc(xmlsize+1);
510	if (confxml == NULL) {
511		DPRINT(("cannot malloc memory for confxml"));
512		goto bad;
513	}
514	error = sysctlbyname("kern.geom.confxml", confxml, &xmlsize, NULL, 0);
515	if (error) {
516		DPRINT(("error reading kern.geom.confxml from the system"));
517		goto bad;
518	}
519	confxml[xmlsize] = '\0';	/* in case kernel bug is still there */
520
521	if (xmlparse(confxml, "MBR", name, assignToSlice, &ds) != 0) {
522		DPRINTX(("Error parsing MBR geometry specification."));
523		goto bad;
524	}
525	if (xmlparse(confxml, "DISK", name, assignToDisk, &dl) != 0) {
526		DPRINTX(("Error parsing DISK geometry specification."));
527		goto bad;
528	}
529	if (dl.d_nsectors == 0) {
530		DPRINTX(("No (zero) sector information in DISK geometry"));
531		goto bad;
532	}
533	if (dl.d_ntracks == 0) {
534		DPRINTX(("No (zero) track information in DISK geometry"));
535		goto bad;
536	}
537	if (dl.d_secsize == 0) {
538		DPRINTX(("No (zero) sector size information in DISK geometry"));
539		goto bad;
540	}
541	if (dl.d_secpercyl == 0 && dl.d_secperunit == 0) {
542		DPRINTX(("No (zero) media size information in DISK geometry"));
543		goto bad;
544	}
545	/*
546	 * Now patch up disklabel and diskslice.
547	 */
548	d->sector_size = dl.d_secsize;
549	/* NB: media size was stashed in two parts while parsing */
550	mediasize = (((u_int64_t) dl.d_secpercyl) << 32) + dl.d_secperunit;
551	dl.d_secpercyl = 0;
552	dl.d_secperunit = 0;
553	size = mediasize / d->sector_size;
554	dl.d_ncylinders = size / (dl.d_ntracks * dl.d_nsectors);
555	/* "whole disk" slice maintained for compatibility */
556	ds.dss_slices[WHOLE_DISK_SLICE].ds_size = size;
557#else /* !HAVE_GEOM */
558	if (ioctl(fd, DIOCGDINFO, &dl) < 0) {
559		DPRINT(("DIOCGDINFO(%s) failed", device));
560		goto bad;
561	}
562	i = ioctl(fd, DIOCGSLICEINFO, &ds);
563	if (i < 0) {
564		DPRINT(("DIOCGSLICEINFO(%s) failed", device));
565		goto bad;
566	}
567
568#ifdef DEBUG
569	for(i = 0; i < ds.dss_nslices; i++)
570		if(ds.dss_slices[i].ds_openmask)
571			printf("  open(%d)=0x%2x",
572				i, ds.dss_slices[i].ds_openmask);
573	printf("\n");
574#endif
575
576/* XXX --- ds.dss_slice[WHOLE_DISK_SLICE].ds.size of MO disk is wrong!!! */
577#ifdef PC98
578	if (!size)
579		size = dl.d_ncylinders * dl.d_ntracks * dl.d_nsectors;
580#else
581	if (!size)
582		size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size;
583#endif
584
585	/* determine media sector size */
586	if ((buf = malloc(MAX_SEC_SIZE)) == NULL)
587		return NULL;
588	for (sector_size = MIN_SEC_SIZE; sector_size <= MAX_SEC_SIZE; sector_size *= 2) {
589		if (read(fd, buf, sector_size) == sector_size) {
590			d->sector_size = sector_size;
591			break;
592		}
593	}
594	free (buf);
595	if (sector_size > MAX_SEC_SIZE) {
596		DPRINT(("Int_Open_Disk: could not determine sector size, "
597		     "calculated %u, max %u\n", sector_size, MAX_SEC_SIZE));
598		/* could not determine sector size */
599		goto bad;
600	}
601#endif /*HAVE_GEOM*/
602
603#ifdef PC98
604	p = (unsigned char*)read_block(fd, 1, d->sector_size);
605#else
606	p = read_block(fd, 0, d->sector_size);
607	dp = (struct dos_partition*)(p + DOSPARTOFF);
608	for (i = 0; i < NDOSPART; i++) {
609		if (Read_Int32(&dp->dp_start) >= size)
610		    continue;
611		if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size)
612		    continue;
613		if (!Read_Int32(&dp->dp_size))
614		    continue;
615
616		if (dp->dp_typ == DOSPTYP_ONTRACK) {
617			d->flags |= DISK_ON_TRACK;
618			offset = 63;
619		}
620
621	}
622	free(p);
623#endif
624
625	d->bios_sect = dl.d_nsectors;
626	d->bios_hd = dl.d_ntracks;
627
628	d->name = strdup(name);
629
630
631	if (dl.d_ntracks && dl.d_nsectors)
632		d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors);
633
634#ifdef PC98
635	if (Add_Chunk(d, -offset, size, name, whole, 0, 0, "-"))
636#else
637	if (Add_Chunk(d, -offset, size, name, whole, 0, 0))
638#endif
639		DPRINT(("Failed to add 'whole' chunk"));
640
641#ifdef __i386__
642#ifdef PC98
643	/* XXX -- Quick Hack!
644	 * Check MS-DOS MO
645	 */
646	if ((*p == 0xf0 || *p == 0xf8) &&
647	    (*(p+1) == 0xff) &&
648	    (*(p+2) == 0xff)) {
649		Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name);
650	    free(p);
651	    goto pc98_mo_done;
652	}
653	free(p);
654#endif /* PC98 */
655	for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
656		char sname[20];
657		char pname[20];
658		chunk_e ce;
659		u_long flags=0;
660		int subtype=0;
661		int j;
662
663		if (! ds.dss_slices[i].ds_size)
664			continue;
665		ds.dss_slices[i].ds_offset -= offset;
666		snprintf(sname, sizeof(sname), "%ss%d", name, i - 1);
667#ifdef PC98
668		subtype = ds.dss_slices[i].ds_type |
669			ds.dss_slices[i].ds_subtype << 8;
670		switch (ds.dss_slices[i].ds_type & 0x7f) {
671			case 0x14:
672				ce = freebsd;
673				break;
674			case 0x20:
675			case 0x21:
676			case 0x22:
677			case 0x23:
678			case 0x24:
679				ce = fat;
680				break;
681#else /* IBM-PC */
682		subtype = ds.dss_slices[i].ds_type;
683		switch (ds.dss_slices[i].ds_type) {
684			case 0xa5:
685				ce = freebsd;
686				break;
687			case 0x1:
688			case 0x6:
689			case 0x4:
690			case 0xb:
691			case 0xc:
692			case 0xe:
693				ce = fat;
694				break;
695			case DOSPTYP_EXTENDED:
696			case 0xf:
697				ce = extended;
698				break;
699#endif
700			default:
701				ce = unknown;
702				break;
703		}
704#ifdef PC98
705		if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
706			ds.dss_slices[i].ds_size, sname, ce, subtype, flags,
707			ds.dss_slices[i].ds_name))
708#else
709		if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
710			ds.dss_slices[i].ds_size, sname, ce, subtype, flags))
711#endif
712			DPRINT(("failed to add chunk for slice %d", i - 1));
713
714#ifdef PC98
715		if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14)
716#else
717		if (ds.dss_slices[i].ds_type != 0xa5)
718#endif
719			continue;
720#ifdef HAVE_GEOM
721		if (xmlparse(confxml, "BSD", sname, assignToPartition, &dl) != 0) {
722			DPRINTX(("Error parsing MBR geometry specification."));
723			goto bad;
724		}
725#else
726		{
727		struct disklabel dl;
728		int k;
729
730		strlcpy(pname, _PATH_DEV, sizeof(pname));
731		strlcat(pname, sname, sizeof(pname));
732		j = open(pname, O_RDONLY);
733		if (j < 0) {
734			DPRINT(("open(%s)", pname));
735			continue;
736		}
737		k = ioctl(j, DIOCGDINFO, &dl);
738		if (k < 0) {
739			DPRINT(("ioctl(%s, DIOCGDINFO)", pname));
740			close(j);
741			continue;
742		}
743		close(j);
744		}
745#endif /*HAVE_GEOM*/
746
747		for(j = 0; j <= dl.d_npartitions; j++) {
748			if (j == RAW_PART)
749				continue;
750			if (j == 3)
751				continue;
752			if (j == dl.d_npartitions) {
753				j = 3;
754				dl.d_npartitions = 0;
755			}
756			if (!dl.d_partitions[j].p_size)
757				continue;
758			if (dl.d_partitions[j].p_size +
759			    dl.d_partitions[j].p_offset >
760			    ds.dss_slices[i].ds_size)
761				continue;
762			snprintf(pname, sizeof(pname), "%s%c", sname, j + 'a');
763			if (Add_Chunk(d,
764				dl.d_partitions[j].p_offset +
765				ds.dss_slices[i].ds_offset,
766				dl.d_partitions[j].p_size,
767				pname,part,
768				dl.d_partitions[j].p_fstype,
769#ifdef PC98
770				0,
771				ds.dss_slices[i].ds_name) && j != 3)
772#else
773				0) && j != 3)
774#endif
775				DPRINT((
776			"Failed to add chunk for partition %c [%lu,%lu]",
777			j + 'a', dl.d_partitions[j].p_offset,
778			dl.d_partitions[j].p_size));
779		}
780	}
781#endif /* __i386__ */
782#ifdef __alpha__
783	{
784		struct disklabel dl;
785		char pname[20];
786		int j,k;
787
788		strlcpy(pname, _PATH_DEV, sizeof(pname));
789		strlcat(pname, name, sizeof(pname));
790		j = open(pname, O_RDONLY);
791		if (j < 0) {
792			DPRINT(("open(%s)", pname));
793			goto nolabel;
794		}
795		k = ioctl(j, DIOCGDINFO, &dl);
796		if (k < 0) {
797			DPRINT(("ioctl(%s, DIOCGDINFO)", pname));
798			close(j);
799			goto nolabel;
800		}
801		close(j);
802		All_FreeBSD(d, 1);
803
804		for(j = 0; j <= dl.d_npartitions; j++) {
805			if (j == RAW_PART)
806				continue;
807			if (j == 3)
808				continue;
809			if (j == dl.d_npartitions) {
810				j = 3;
811				dl.d_npartitions = 0;
812			}
813			if (!dl.d_partitions[j].p_size)
814				continue;
815			if (dl.d_partitions[j].p_size +
816			    dl.d_partitions[j].p_offset >
817			    ds.dss_slices[WHOLE_DISK_SLICE].ds_size)
818				continue;
819			snprintf(pname, sizeof(pname), "%s%c", name, j + 'a');
820			if (Add_Chunk(d,
821				      dl.d_partitions[j].p_offset,
822				      dl.d_partitions[j].p_size,
823				      pname,part,
824				      dl.d_partitions[j].p_fstype,
825				      0) && j != 3)
826				DPRINT((
827					"Failed to add chunk for partition %c [%lu,%lu]",
828					j + 'a', dl.d_partitions[j].p_offset,
829					dl.d_partitions[j].p_size));
830		}
831	nolabel:;
832	}
833#endif /* __alpha__ */
834#ifdef PC98
835pc98_mo_done:
836#endif
837	close(fd);
838	Fixup_Names(d);
839	return d;
840bad:
841	if (confxml != NULL)
842		free(confxml);
843	if (fd >= 0)
844		close(fd);
845	return NULL;
846}
847
848void
849Debug_Disk(struct disk *d)
850{
851	printf("Debug_Disk(%s)", d->name);
852	printf("  flags=%lx", d->flags);
853#if 0
854	printf("  real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect);
855#endif
856	printf("  bios_geom=%lu/%lu/%lu = %lu\n",
857		d->bios_cyl, d->bios_hd, d->bios_sect,
858		d->bios_cyl * d->bios_hd * d->bios_sect);
859#if defined(PC98)
860	printf("  boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n",
861		d->boot1, d->boot2, d->bootipl, d->bootmenu);
862#elif defined(__i386__)
863	printf("  boot1=%p, boot2=%p, bootmgr=%p\n",
864		d->boot1, d->boot2, d->bootmgr);
865#elif defined(__alpha__)
866	printf("  boot1=%p, bootmgr=%p\n",
867		d->boot1, d->bootmgr);
868#endif
869	Debug_Chunk(d->chunks);
870}
871
872void
873Free_Disk(struct disk *d)
874{
875	if(d->chunks) Free_Chunk(d->chunks);
876	if(d->name) free(d->name);
877#ifdef PC98
878	if(d->bootipl) free(d->bootipl);
879	if(d->bootmenu) free(d->bootmenu);
880#else
881	if(d->bootmgr) free(d->bootmgr);
882#endif
883	if(d->boot1) free(d->boot1);
884#if defined(__i386__)
885	if(d->boot2) free(d->boot2);
886#endif
887	free(d);
888}
889
890struct disk *
891Clone_Disk(struct disk *d)
892{
893	struct disk *d2;
894
895	d2 = (struct disk*) malloc(sizeof *d2);
896	if(!d2) return NULL;
897	*d2 = *d;
898	d2->name = strdup(d2->name);
899	d2->chunks = Clone_Chunk(d2->chunks);
900#ifdef PC98
901	if(d2->bootipl) {
902		d2->bootipl = malloc(d2->bootipl_size);
903		memcpy(d2->bootipl, d->bootipl, d2->bootipl_size);
904	}
905	if(d2->bootmenu) {
906		d2->bootmenu = malloc(d2->bootmenu_size);
907		memcpy(d2->bootmenu, d->bootmenu, d2->bootmenu_size);
908	}
909#else
910	if(d2->bootmgr) {
911		d2->bootmgr = malloc(d2->bootmgr_size);
912		memcpy(d2->bootmgr, d->bootmgr, d2->bootmgr_size);
913	}
914#endif
915#if defined(__i386__)
916	if(d2->boot1) {
917		d2->boot1 = malloc(512);
918		memcpy(d2->boot1, d->boot1, 512);
919	}
920	if(d2->boot2) {
921		d2->boot2 = malloc(512 * 15);
922		memcpy(d2->boot2, d->boot2, 512 * 15);
923	}
924#elif defined(__alpha__)
925	if(d2->boot1) {
926		d2->boot1 = malloc(512 * 15);
927		memcpy(d2->boot1, d->boot1, 512 * 15);
928	}
929#endif
930	return d2;
931}
932
933#if 0
934void
935Collapse_Disk(struct disk *d)
936{
937
938	while(Collapse_Chunk(d, d->chunks))
939		;
940}
941#endif
942
943#ifdef PC98
944static char * device_list[] = {"wd", "aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0};
945#else
946static char * device_list[] = {"aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0};
947#endif
948
949int qstrcmp(const void* a, const void* b) {
950
951	char *str1 = *(char**)a;
952	char *str2 = *(char**)b;
953	return strcmp(str1, str2);
954
955}
956
957char **
958Disk_Names()
959{
960    int i,j,disk_cnt;
961    char disk[25];
962    char diskname[25];
963    struct stat st;
964    struct diskslices ds;
965    int fd;
966    static char **disks;
967    int error;
968    size_t listsize;
969    char *disklist;
970
971    disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
972    if (disks == NULL)
973	    return NULL;
974    memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
975    error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
976    if (!error) {
977	    disklist = (char *)malloc(listsize+1);
978	    if (disklist == NULL) {
979		    free(disks);
980		    return NULL;
981	    }
982	    memset(disklist, 0, listsize+1);
983	    error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
984	    if (error) {
985		    free(disklist);
986		    free(disks);
987		    return NULL;
988	    }
989	    for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) {
990		    disks[disk_cnt] = strsep(&disklist, " ");
991		    if (disks[disk_cnt] == NULL)
992			    break;
993											    }
994    } else {
995    warn("kern.disks sysctl not available");
996    disk_cnt = 0;
997	for (j = 0; device_list[j]; j++) {
998		if(disk_cnt >= MAX_NO_DISKS)
999			break;
1000		for (i = 0; i < MAX_NO_DISKS; i++) {
1001			snprintf(diskname, sizeof(diskname), "%s%d",
1002				device_list[j], i);
1003			snprintf(disk, sizeof(disk), _PATH_DEV"%s", diskname);
1004			if (stat(disk, &st) || !(st.st_mode & S_IFCHR))
1005				continue;
1006			if ((fd = open(disk, O_RDWR)) == -1)
1007				continue;
1008			if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) {
1009				DPRINT(("DIOCGSLICEINFO %s", disk));
1010				close(fd);
1011				continue;
1012			}
1013			close(fd);
1014			disks[disk_cnt++] = strdup(diskname);
1015			if(disk_cnt >= MAX_NO_DISKS)
1016				break;
1017		}
1018	}
1019    }
1020    qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
1021
1022    return disks;
1023}
1024
1025#ifdef PC98
1026void
1027Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size,
1028	     const u_char *bootmenu, const size_t bootmenu_size)
1029#else
1030void
1031Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
1032#endif
1033{
1034#ifdef PC98
1035	if (bootipl_size % d->sector_size != 0)
1036		return;
1037	if (d->bootipl)
1038		free(d->bootipl);
1039	if (!bootipl) {
1040		d->bootipl = NULL;
1041	} else {
1042		d->bootipl_size = bootipl_size;
1043		d->bootipl = malloc(bootipl_size);
1044		if(!d->bootipl) return;
1045		memcpy(d->bootipl, bootipl, bootipl_size);
1046	}
1047
1048	if (bootmenu_size % d->sector_size != 0)
1049		return;
1050	if (d->bootmenu)
1051		free(d->bootmenu);
1052	if (!bootmenu) {
1053		d->bootmenu = NULL;
1054	} else {
1055		d->bootmenu_size = bootmenu_size;
1056		d->bootmenu = malloc(bootmenu_size);
1057		if(!d->bootmenu) return;
1058		memcpy(d->bootmenu, bootmenu, bootmenu_size);
1059	}
1060#else
1061	if (s % d->sector_size != 0)
1062		return;
1063	if (d->bootmgr)
1064		free(d->bootmgr);
1065	if (!b) {
1066		d->bootmgr = NULL;
1067	} else {
1068		d->bootmgr_size = s;
1069		d->bootmgr = malloc(s);
1070		if(!d->bootmgr) return;
1071		memcpy(d->bootmgr, b, s);
1072	}
1073#endif
1074}
1075
1076int
1077Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
1078{
1079#if defined(__i386__)
1080	if (d->boot1) free(d->boot1);
1081	d->boot1 = malloc(512);
1082	if(!d->boot1) return -1;
1083	memcpy(d->boot1, b1, 512);
1084	if (d->boot2) free(d->boot2);
1085	d->boot2 = malloc(15 * 512);
1086	if(!d->boot2) return -1;
1087	memcpy(d->boot2, b2, 15 * 512);
1088#elif defined(__alpha__)
1089	if (d->boot1) free(d->boot1);
1090	d->boot1 = malloc(15 * 512);
1091	if(!d->boot1) return -1;
1092	memcpy(d->boot1, b1, 15 * 512);
1093#endif
1094	return 0;
1095}
1096
1097const char *
1098slice_type_name( int type, int subtype )
1099{
1100	switch (type) {
1101		case 0:		return "whole";
1102#ifndef	PC98
1103		case 1:		switch (subtype) {
1104					case 1:		return "fat (12-bit)";
1105					case 2:		return "XENIX /";
1106					case 3:		return "XENIX /usr";
1107					case 4:         return "fat (16-bit,<=32Mb)";
1108					case 5:		return "extended DOS";
1109					case 6:         return "fat (16-bit,>32Mb)";
1110					case 7:         return "NTFS/HPFS/QNX";
1111					case 8:         return "AIX bootable";
1112					case 9:         return "AIX data";
1113					case 10:	return "OS/2 bootmgr";
1114					case 11:        return "fat (32-bit)";
1115					case 12:        return "fat (32-bit,LBA)";
1116					case 14:        return "fat (16-bit,>32Mb,LBA)";
1117					case 15:        return "extended DOS, LBA";
1118					case 18:        return "Compaq Diagnostic";
1119					case 84:	return "OnTrack diskmgr";
1120					case 100:	return "Netware 2.x";
1121					case 101:	return "Netware 3.x";
1122					case 115:	return "SCO UnixWare";
1123					case 128:	return "Minix 1.1";
1124					case 129:	return "Minix 1.5";
1125					case 130:	return "linux_swap";
1126					case 131:	return "ext2fs";
1127					case 166:	return "OpenBSD FFS";	/* 0xA6 */
1128					case 169:	return "NetBSD FFS";	/* 0xA9 */
1129					case 182:	return "OpenBSD";		/* dedicated */
1130					case 183:	return "bsd/os";
1131					case 184:	return "bsd/os swap";
1132					case 238:	return "EFI GPT";
1133					case 239:	return "EFI Sys. Part.";
1134					default:	return "unknown";
1135				}
1136#endif
1137		case 2:		return "fat";
1138		case 3:		switch (subtype) {
1139#ifdef	PC98
1140					case 0xc494:	return "freebsd";
1141#else
1142					case 165:	return "freebsd";
1143#endif
1144					default:	return "unknown";
1145				}
1146#ifndef	PC98
1147		case 4:		return "extended";
1148		case 5:		return "part";
1149		case 6:		return "unused";
1150#endif
1151		default:	return "unknown";
1152	}
1153}
1154