disk.c revision 105821
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 105821 2002-10-23 21:05:42Z 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#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/*
424 * Callback to collect partition-related data.
425 */
426static int
427assignToPartition(void *arg, XMLToken t, u_int *part, u_int64_t v)
428{
429	struct disklabel *dl = (struct disklabel *) arg;
430
431	switch ((int) t) {
432	case XML_INDEX:
433		*part = (u_int) v;
434		if (*part >= MAXPARTITIONS) {
435			DPRINTX(("assignToPartition: invalid partition index %u > max %u",
436			      *part, MAXPARTITIONS));
437			return EINVAL;
438		}
439		if (*part >= dl->d_npartitions)
440			dl->d_npartitions = (*part)+1;
441		break;
442	case XML_SECOFFSET:
443		dl->d_partitions[*part].p_offset = (u_int32_t) v;
444		break;
445	case XML_SECLENGTH:
446		dl->d_partitions[*part].p_size = (u_int32_t) v;
447		break;
448	case XML_TYPE:
449		dl->d_partitions[*part].p_fstype = (u_int8_t) v;
450		break;
451	}
452	return 0;
453}
454#undef N
455
456struct disk *
457Int_Open_Disk(const char *name, u_long size)
458{
459	int i;
460	int fd = -1;
461	struct diskslices ds;
462	struct disklabel dl;
463	char device[64];
464	struct disk *d;
465#ifdef PC98
466	unsigned char *p;
467#else
468	struct dos_partition *dp;
469	void *p;
470#endif
471	char *confxml = NULL;
472	size_t xmlsize;
473	u_int64_t mediasize;
474	int error;
475
476	strlcpy(device, _PATH_DEV, sizeof(device));
477	strlcat(device, name, sizeof(device));
478
479	d = (struct disk *)malloc(sizeof *d);
480	if(!d) return NULL;
481	memset(d, 0, sizeof *d);
482
483	fd = open(device, O_RDONLY);
484	if (fd < 0) {
485		DPRINT(("open(%s) failed", device));
486		goto bad;
487	}
488
489	memset(&dl, 0, sizeof dl);
490	memset(&ds, 0, sizeof ds);
491	/*
492	 * Read and hack-parse the XML that provides the info we need.
493	 */
494	error = sysctlbyname("kern.geom.confxml", NULL, &xmlsize, NULL, 0);
495	if (error) {
496		warn("kern.geom.confxml sysctl not available, giving up!");
497		goto bad;
498	}
499	confxml = (char *) malloc(xmlsize+1);
500	if (confxml == NULL) {
501		DPRINT(("cannot malloc memory for confxml"));
502		goto bad;
503	}
504	error = sysctlbyname("kern.geom.confxml", confxml, &xmlsize, NULL, 0);
505	if (error) {
506		DPRINT(("error reading kern.geom.confxml from the system"));
507		goto bad;
508	}
509	confxml[xmlsize] = '\0';	/* in case kernel bug is still there */
510
511	if (xmlparse(confxml, "MBR", name, assignToSlice, &ds) != 0) {
512		DPRINTX(("Error parsing MBR geometry specification."));
513		goto bad;
514	}
515	if (xmlparse(confxml, "DISK", name, assignToDisk, &dl) != 0) {
516		DPRINTX(("Error parsing DISK geometry specification."));
517		goto bad;
518	}
519	if (dl.d_nsectors == 0) {
520		DPRINTX(("No (zero) sector information in DISK geometry"));
521		goto bad;
522	}
523	if (dl.d_ntracks == 0) {
524		DPRINTX(("No (zero) track information in DISK geometry"));
525		goto bad;
526	}
527	if (dl.d_secsize == 0) {
528		DPRINTX(("No (zero) sector size information in DISK geometry"));
529		goto bad;
530	}
531	if (dl.d_secpercyl == 0 && dl.d_secperunit == 0) {
532		DPRINTX(("No (zero) media size information in DISK geometry"));
533		goto bad;
534	}
535	/*
536	 * Now patch up disklabel and diskslice.
537	 */
538	d->sector_size = dl.d_secsize;
539	/* NB: media size was stashed in two parts while parsing */
540	mediasize = (((u_int64_t) dl.d_secpercyl) << 32) + dl.d_secperunit;
541	dl.d_secpercyl = 0;
542	dl.d_secperunit = 0;
543	size = mediasize / d->sector_size;
544	dl.d_ncylinders = size / (dl.d_ntracks * dl.d_nsectors);
545	/* "whole disk" slice maintained for compatibility */
546	ds.dss_slices[WHOLE_DISK_SLICE].ds_size = size;
547
548#ifdef PC98
549	p = (unsigned char*)read_block(fd, 1, d->sector_size);
550#else
551	p = read_block(fd, 0, d->sector_size);
552	dp = (struct dos_partition*)(p + DOSPARTOFF);
553	for (i = 0; i < NDOSPART; i++) {
554		if (Read_Int32(&dp->dp_start) >= size)
555		    continue;
556		if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size)
557		    continue;
558		if (!Read_Int32(&dp->dp_size))
559		    continue;
560	}
561	free(p);
562#endif
563
564	d->bios_sect = dl.d_nsectors;
565	d->bios_hd = dl.d_ntracks;
566
567	d->name = strdup(name);
568
569
570	if (dl.d_ntracks && dl.d_nsectors)
571		d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors);
572
573	if (Add_Chunk(d, 0, size, name, whole, 0, 0, "-"))
574		DPRINT(("Failed to add 'whole' chunk"));
575
576#ifdef __i386__
577#ifdef PC98
578	/* XXX -- Quick Hack!
579	 * Check MS-DOS MO
580	 */
581	if ((*p == 0xf0 || *p == 0xf8) &&
582	    (*(p+1) == 0xff) &&
583	    (*(p+2) == 0xff)) {
584		Add_Chunk(d, 0, size, name, fat, 0xa0a0, 0, name);
585	    free(p);
586	    goto pc98_mo_done;
587	}
588	free(p);
589#endif /* PC98 */
590	for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
591		char sname[20];
592		char pname[20];
593		chunk_e ce;
594		u_long flags=0;
595		int subtype=0;
596		int j;
597
598		if (! ds.dss_slices[i].ds_size)
599			continue;
600		snprintf(sname, sizeof(sname), "%ss%d", name, i - 1);
601#ifdef PC98
602		subtype = ds.dss_slices[i].ds_type |
603			ds.dss_slices[i].ds_subtype << 8;
604		switch (ds.dss_slices[i].ds_type & 0x7f) {
605			case 0x14:
606				ce = freebsd;
607				break;
608			case 0x20:
609			case 0x21:
610			case 0x22:
611			case 0x23:
612			case 0x24:
613				ce = fat;
614				break;
615#else /* IBM-PC */
616		subtype = ds.dss_slices[i].ds_type;
617		switch (ds.dss_slices[i].ds_type) {
618			case 0xa5:
619				ce = freebsd;
620				break;
621			case 0x1:
622			case 0x6:
623			case 0x4:
624			case 0xb:
625			case 0xc:
626			case 0xe:
627				ce = fat;
628				break;
629			case DOSPTYP_EXTENDED:
630			case 0xf:
631				ce = extended;
632				break;
633#endif
634			default:
635				ce = unknown;
636				break;
637		}
638#ifdef PC98
639		if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
640			ds.dss_slices[i].ds_size, sname, ce, subtype, flags,
641			ds.dss_slices[i].ds_name))
642#else
643		if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
644			ds.dss_slices[i].ds_size, sname, ce, subtype, flags, ""))
645#endif
646			DPRINT(("failed to add chunk for slice %d", i - 1));
647
648#ifdef PC98
649		if ((ds.dss_slices[i].ds_type & 0x7f) != 0x14)
650#else
651		if (ds.dss_slices[i].ds_type != 0xa5)
652#endif
653			continue;
654		if (xmlparse(confxml, "BSD", sname, assignToPartition, &dl) != 0) {
655			DPRINTX(("Error parsing MBR geometry specification."));
656			goto bad;
657		}
658
659		for(j = 0; j <= dl.d_npartitions; j++) {
660			if (j == RAW_PART)
661				continue;
662			if (j == 3)
663				continue;
664			if (j == dl.d_npartitions) {
665				j = 3;
666				dl.d_npartitions = 0;
667			}
668			if (!dl.d_partitions[j].p_size)
669				continue;
670			if (dl.d_partitions[j].p_size +
671			    dl.d_partitions[j].p_offset >
672			    ds.dss_slices[i].ds_size)
673				continue;
674			snprintf(pname, sizeof(pname), "%s%c", sname, j + 'a');
675			if (Add_Chunk(d,
676				dl.d_partitions[j].p_offset +
677				ds.dss_slices[i].ds_offset,
678				dl.d_partitions[j].p_size,
679				pname,part,
680				dl.d_partitions[j].p_fstype,
681#ifdef PC98
682				0,
683				ds.dss_slices[i].ds_name) && j != 3)
684#else
685				0, "") && j != 3)
686#endif
687				DPRINT((
688			"Failed to add chunk for partition %c [%lu,%lu]",
689			j + 'a', dl.d_partitions[j].p_offset,
690			dl.d_partitions[j].p_size));
691		}
692	}
693#endif /* __i386__ */
694#ifdef __alpha__
695	{
696		struct disklabel dl;
697		char pname[20];
698		int j,k;
699
700		strlcpy(pname, _PATH_DEV, sizeof(pname));
701		strlcat(pname, name, sizeof(pname));
702		j = open(pname, O_RDONLY);
703		if (j < 0) {
704			DPRINT(("open(%s)", pname));
705			goto nolabel;
706		}
707		k = ioctl(j, DIOCGDINFO, &dl);
708		if (k < 0) {
709			DPRINT(("ioctl(%s, DIOCGDINFO)", pname));
710			close(j);
711			goto nolabel;
712		}
713		close(j);
714		All_FreeBSD(d, 1);
715
716		for(j = 0; j <= dl.d_npartitions; j++) {
717			if (j == RAW_PART)
718				continue;
719			if (j == 3)
720				continue;
721			if (j == dl.d_npartitions) {
722				j = 3;
723				dl.d_npartitions = 0;
724			}
725			if (!dl.d_partitions[j].p_size)
726				continue;
727			if (dl.d_partitions[j].p_size +
728			    dl.d_partitions[j].p_offset >
729			    ds.dss_slices[WHOLE_DISK_SLICE].ds_size)
730				continue;
731			snprintf(pname, sizeof(pname), "%s%c", name, j + 'a');
732			if (Add_Chunk(d,
733				      dl.d_partitions[j].p_offset,
734				      dl.d_partitions[j].p_size,
735				      pname,part,
736				      dl.d_partitions[j].p_fstype,
737				      0, "") && j != 3)
738				DPRINT((
739					"Failed to add chunk for partition %c [%lu,%lu]",
740					j + 'a', dl.d_partitions[j].p_offset,
741					dl.d_partitions[j].p_size));
742		}
743	nolabel:;
744	}
745#endif /* __alpha__ */
746#ifdef PC98
747pc98_mo_done:
748#endif
749	close(fd);
750	Fixup_Names(d);
751	return d;
752bad:
753	if (confxml != NULL)
754		free(confxml);
755	if (fd >= 0)
756		close(fd);
757	return NULL;
758}
759
760void
761Debug_Disk(struct disk *d)
762{
763	printf("Debug_Disk(%s)", d->name);
764#if 0
765	printf("  real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect);
766#endif
767	printf("  bios_geom=%lu/%lu/%lu = %lu\n",
768		d->bios_cyl, d->bios_hd, d->bios_sect,
769		d->bios_cyl * d->bios_hd * d->bios_sect);
770#if defined(PC98)
771	printf("  boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n",
772		d->boot1, d->boot2, d->bootipl, d->bootmenu);
773#elif defined(__i386__)
774	printf("  boot1=%p, boot2=%p, bootmgr=%p\n",
775		d->boot1, d->boot2, d->bootmgr);
776#elif defined(__alpha__)
777	printf("  boot1=%p, bootmgr=%p\n",
778		d->boot1, d->bootmgr);
779#endif
780	Debug_Chunk(d->chunks);
781}
782
783void
784Free_Disk(struct disk *d)
785{
786	if(d->chunks) Free_Chunk(d->chunks);
787	if(d->name) free(d->name);
788#ifdef PC98
789	if(d->bootipl) free(d->bootipl);
790	if(d->bootmenu) free(d->bootmenu);
791#else
792	if(d->bootmgr) free(d->bootmgr);
793#endif
794	if(d->boot1) free(d->boot1);
795#if defined(__i386__)
796	if(d->boot2) free(d->boot2);
797#endif
798	free(d);
799}
800
801#if 0
802void
803Collapse_Disk(struct disk *d)
804{
805
806	while(Collapse_Chunk(d, d->chunks))
807		;
808}
809#endif
810
811static int
812qstrcmp(const void* a, const void* b)
813{
814
815	char *str1 = *(char**)a;
816	char *str2 = *(char**)b;
817	return strcmp(str1, str2);
818}
819
820char **
821Disk_Names()
822{
823	int disk_cnt;
824	static char **disks;
825	int error;
826	size_t listsize;
827	char *disklist;
828
829	error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
830	if (error) {
831		warn("kern.disks sysctl not available");
832		return NULL;
833	}
834
835	disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
836	if (disks == NULL)
837		return NULL;
838	disklist = (char *)malloc(listsize + 1);
839	if (disklist == NULL) {
840		free(disks);
841		return NULL;
842	}
843	memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
844	memset(disklist, 0, listsize + 1);
845	error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
846	if (error) {
847		free(disklist);
848		free(disks);
849		return NULL;
850	}
851	for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) {
852		disks[disk_cnt] = strsep(&disklist, " ");
853		if (disks[disk_cnt] == NULL)
854			break;
855											}
856	qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
857	return disks;
858}
859
860#ifdef PC98
861void
862Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size,
863	     const u_char *bootmenu, const size_t bootmenu_size)
864#else
865void
866Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
867#endif
868{
869#ifdef PC98
870	if (bootipl_size % d->sector_size != 0)
871		return;
872	if (d->bootipl)
873		free(d->bootipl);
874	if (!bootipl) {
875		d->bootipl = NULL;
876	} else {
877		d->bootipl_size = bootipl_size;
878		d->bootipl = malloc(bootipl_size);
879		if(!d->bootipl) return;
880		memcpy(d->bootipl, bootipl, bootipl_size);
881	}
882
883	if (bootmenu_size % d->sector_size != 0)
884		return;
885	if (d->bootmenu)
886		free(d->bootmenu);
887	if (!bootmenu) {
888		d->bootmenu = NULL;
889	} else {
890		d->bootmenu_size = bootmenu_size;
891		d->bootmenu = malloc(bootmenu_size);
892		if(!d->bootmenu) return;
893		memcpy(d->bootmenu, bootmenu, bootmenu_size);
894	}
895#else
896	if (s % d->sector_size != 0)
897		return;
898	if (d->bootmgr)
899		free(d->bootmgr);
900	if (!b) {
901		d->bootmgr = NULL;
902	} else {
903		d->bootmgr_size = s;
904		d->bootmgr = malloc(s);
905		if(!d->bootmgr) return;
906		memcpy(d->bootmgr, b, s);
907	}
908#endif
909}
910
911int
912Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
913{
914#if defined(__i386__)
915	if (d->boot1) free(d->boot1);
916	d->boot1 = malloc(512);
917	if(!d->boot1) return -1;
918	memcpy(d->boot1, b1, 512);
919	if (d->boot2) free(d->boot2);
920	d->boot2 = malloc(15 * 512);
921	if(!d->boot2) return -1;
922	memcpy(d->boot2, b2, 15 * 512);
923#elif defined(__alpha__)
924	if (d->boot1) free(d->boot1);
925	d->boot1 = malloc(15 * 512);
926	if(!d->boot1) return -1;
927	memcpy(d->boot1, b1, 15 * 512);
928#endif
929	return 0;
930}
931
932const char *
933slice_type_name( int type, int subtype )
934{
935	switch (type) {
936		case 0:		return "whole";
937#ifndef	PC98
938		case 1:		switch (subtype) {
939					case 1:		return "fat (12-bit)";
940					case 2:		return "XENIX /";
941					case 3:		return "XENIX /usr";
942					case 4:         return "fat (16-bit,<=32Mb)";
943					case 5:		return "extended DOS";
944					case 6:         return "fat (16-bit,>32Mb)";
945					case 7:         return "NTFS/HPFS/QNX";
946					case 8:         return "AIX bootable";
947					case 9:         return "AIX data";
948					case 10:	return "OS/2 bootmgr";
949					case 11:        return "fat (32-bit)";
950					case 12:        return "fat (32-bit,LBA)";
951					case 14:        return "fat (16-bit,>32Mb,LBA)";
952					case 15:        return "extended DOS, LBA";
953					case 18:        return "Compaq Diagnostic";
954					case 84:	return "OnTrack diskmgr";
955					case 100:	return "Netware 2.x";
956					case 101:	return "Netware 3.x";
957					case 115:	return "SCO UnixWare";
958					case 128:	return "Minix 1.1";
959					case 129:	return "Minix 1.5";
960					case 130:	return "linux_swap";
961					case 131:	return "ext2fs";
962					case 166:	return "OpenBSD FFS";	/* 0xA6 */
963					case 169:	return "NetBSD FFS";	/* 0xA9 */
964					case 182:	return "OpenBSD";		/* dedicated */
965					case 183:	return "bsd/os";
966					case 184:	return "bsd/os swap";
967					case 238:	return "EFI GPT";
968					case 239:	return "EFI Sys. Part.";
969					default:	return "unknown";
970				}
971#endif
972		case 2:		return "fat";
973		case 3:		switch (subtype) {
974#ifdef	PC98
975					case 0xc494:	return "freebsd";
976#else
977					case 165:	return "freebsd";
978#endif
979					default:	return "unknown";
980				}
981#ifndef	PC98
982		case 4:		return "extended";
983		case 5:		return "part";
984		case 6:		return "unused";
985#endif
986		default:	return "unknown";
987	}
988}
989