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