fdisk.c revision 145765
1/*
2 * Mach Operating System
3 * Copyright (c) 1992 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19 *  School of Computer Science
20 *  Carnegie Mellon University
21 *  Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sbin/fdisk_pc98/fdisk.c 145765 2005-05-01 10:08:35Z nyan $");
29
30#include <sys/disk.h>
31#include <sys/disklabel.h>
32#include <sys/diskpc98.h>
33#include <sys/param.h>
34#include <sys/stat.h>
35#include <sys/mount.h>
36#include <ctype.h>
37#include <fcntl.h>
38#include <err.h>
39#include <errno.h>
40#include <paths.h>
41#include <regex.h>
42#include <stdint.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47
48int iotest;
49
50#define LBUF 100
51static char lbuf[LBUF];
52
53/*
54 *
55 * Ported to 386bsd by Julian Elischer  Thu Oct 15 20:26:46 PDT 1992
56 *
57 * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
58 *	Copyright (c) 1989	Robert. V. Baron
59 *	Created.
60 */
61
62#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp
63#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); }
64
65#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
66
67#define MAX_SEC_SIZE 2048	/* maximum section size that is supported */
68#define MIN_SEC_SIZE 512	/* the sector size to start sensing at */
69static int secsize = 0;		/* the sensed sector size */
70
71static char *disk;
72
73static int cyls, sectors, heads, cylsecs, disksecs;
74
75struct mboot {
76	unsigned char padding[2]; /* force the longs to be long aligned */
77	unsigned char bootinst[510];
78	unsigned short int	signature;
79	struct	pc98_partition parts[8];
80	unsigned char large_sector_overflow[MAX_SEC_SIZE-MIN_SEC_SIZE];
81};
82
83static struct mboot mboot;
84static int fd, fdw;
85
86#define ACTIVE 0x80
87
88static uint dos_cyls;
89static uint dos_heads;
90static uint dos_sectors;
91static uint dos_cylsecs;
92
93#define MAX_ARGS	10
94
95typedef struct cmd {
96    char		cmd;
97    int			n_args;
98    struct arg {
99	char	argtype;
100	int	arg_val;
101    }			args[MAX_ARGS];
102} CMD;
103
104static int B_flag  = 0;		/* replace boot code */
105static int a_flag  = 0;		/* set active partition */
106static int i_flag  = 0;		/* replace partition data */
107static int u_flag  = 0;		/* update partition data */
108static int s_flag  = 0;		/* Print a summary and exit */
109static int t_flag  = 0;		/* test only */
110static char *f_flag = NULL;	/* Read config info from file */
111static int v_flag  = 0;		/* Be verbose */
112
113static struct part_type
114{
115	unsigned char type;
116	const char *name;
117} part_types[] = {
118	 {0x00, "unused"}
119	,{0x01, "Primary DOS with 12 bit FAT"}
120	,{0x11, "MSDOS"}
121	,{0x20, "MSDOS"}
122	,{0x21, "MSDOS"}
123	,{0x22, "MSDOS"}
124	,{0x23, "MSDOS"}
125	,{0x02, "XENIX / file system"}
126	,{0x03, "XENIX /usr file system"}
127	,{0x04, "PC-UX"}
128	,{0x05, "Extended DOS"}
129	,{0x06, "Primary 'big' DOS (> 32MB)"}
130	,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"}
131	,{0x08, "AIX file system"}
132	,{0x09, "AIX boot partition or Coherent"}
133	,{0x0A, "OS/2 Boot Manager or OPUS"}
134	,{0x10, "OPUS"}
135	,{0x14, "FreeBSD/NetBSD/386BSD"}
136	,{0x94, "FreeBSD/NetBSD/386BSD"}
137	,{0x40, "VENIX 286"}
138	,{0x50, "DM"}
139	,{0x51, "DM"}
140	,{0x52, "CP/M or Microport SysV/AT"}
141	,{0x56, "GB"}
142	,{0x61, "Speed"}
143	,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
144	,{0x64, "Novell Netware 2.xx"}
145	,{0x65, "Novell Netware 3.xx"}
146	,{0x75, "PCIX"}
147	,{0x40, "Minix"}
148};
149
150static void print_s0(int which);
151static void print_part(int i);
152static void init_sector0(unsigned long start);
153static void init_boot(void);
154static void change_part(int i);
155static void print_params(void);
156static void change_active(int which);
157static void change_code(void);
158static void get_params_to_use(void);
159static char *get_rootdisk(void);
160static void dos(u_int32_t start, u_int32_t size, struct pc98_partition *partp);
161static int open_disk(int flag);
162static ssize_t read_disk(off_t sector, void *buf);
163static ssize_t write_disk(off_t sector, void *buf);
164static int get_params(void);
165static int read_s0(void);
166static int write_s0(void);
167static int ok(const char *str);
168static int decimal(const char *str, int *num, int deflt);
169static const char *get_type(int type);
170static void usage(void);
171static int string(const char *str, char **ans);
172
173int
174main(int argc, char *argv[])
175{
176	struct	stat sb;
177	int	c, i;
178	int	partition = -1;
179	struct	pc98_partition *partp;
180
181	while ((c = getopt(argc, argv, "Ba:f:istuv12345678")) != -1)
182		switch (c) {
183		case 'B':
184			B_flag = 1;
185			break;
186		case 'a':
187			a_flag = 1;
188			break;
189		case 'f':
190			f_flag = optarg;
191			break;
192		case 'i':
193			i_flag = 1;
194			break;
195		case 's':
196			s_flag = 1;
197			break;
198		case 't':
199			t_flag = 1;
200			break;
201		case 'u':
202			u_flag = 1;
203			break;
204		case 'v':
205			v_flag = 1;
206			break;
207		case '1':
208		case '2':
209		case '3':
210		case '4':
211		case '5':
212		case '6':
213		case '7':
214		case '8':
215			partition = c - '0';
216			break;
217		default:
218			usage();
219		}
220	if (f_flag || i_flag)
221		u_flag = 1;
222	if (t_flag)
223		v_flag = 1;
224	argc -= optind;
225	argv += optind;
226
227	if (argc == 0) {
228		disk = get_rootdisk();
229	} else {
230		if (stat(argv[0], &sb) == 0) {
231			/* OK, full pathname given */
232			disk = argv[0];
233		} else if (errno == ENOENT && argv[0][0] != '/') {
234			/* Try prepending "/dev" */
235			asprintf(&disk, "%s%s", _PATH_DEV, argv[0]);
236			if (disk == NULL)
237				errx(1, "out of memory");
238		} else {
239			/* other stat error, let it fail below */
240			disk = argv[0];
241		}
242	}
243	if (open_disk(u_flag) < 0)
244		err(1, "cannot open disk %s", disk);
245
246	if (s_flag) {
247		if (read_s0())
248			err(1, "read_s0");
249		printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads,
250		    dos_sectors);
251		printf("Part  %11s %11s SID\n", "Start", "Size");
252		for (i = 0; i < NDOSPART; i++) {
253			partp = ((struct pc98_partition *) &mboot.parts) + i;
254			if (partp->dp_sid == 0)
255				continue;
256			printf("%4d: %11u %11u 0x%02x\n", i + 1,
257			    partp->dp_scyl * cylsecs,
258			    (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs,
259				partp->dp_sid);
260		}
261		exit(0);
262	}
263
264	printf("******* Working on device %s *******\n",disk);
265
266	if (f_flag) {
267	    if (v_flag)
268		print_s0(-1);
269	    if (!t_flag)
270		write_s0();
271	} else {
272	    if(u_flag)
273		get_params_to_use();
274	    else
275		print_params();
276
277	    if (read_s0())
278		init_sector0(dos_sectors);
279
280	    printf("Media sector size is %d\n", secsize);
281	    printf("Warning: BIOS sector numbering starts with sector 1\n");
282	    printf("Information from DOS bootblock is:\n");
283	    if (partition == -1)
284		for (i = 1; i <= NDOSPART; i++)
285		    change_part(i);
286	    else
287		change_part(partition);
288
289	    if (u_flag || a_flag)
290		change_active(partition);
291
292	    if (B_flag)
293		change_code();
294
295	    if (u_flag || a_flag || B_flag) {
296		if (!t_flag) {
297		    printf("\nWe haven't changed the partition table yet.  ");
298		    printf("This is your last chance.\n");
299		}
300		print_s0(-1);
301		if (!t_flag) {
302		    if (ok("Should we write new partition table?"))
303			write_s0();
304		} else {
305		    printf("\n-t flag specified -- partition table not written.\n");
306		}
307	    }
308	}
309
310	exit(0);
311}
312
313static void
314usage()
315{
316	fprintf(stderr, "%s%s",
317		"usage: fdisk [-Baistu] [-12345678] [disk]\n",
318 		"       fdisk -f configfile [-itv] [disk]\n");
319        exit(1);
320}
321
322static void
323print_s0(int which)
324{
325	int	i;
326
327	print_params();
328	printf("Information from DOS bootblock is:\n");
329	if (which == -1)
330		for (i = 1; i <= NDOSPART; i++)
331			printf("%d: ", i), print_part(i);
332	else
333		print_part(which);
334}
335
336static struct pc98_partition mtpart;
337
338static void
339print_part(int i)
340{
341	struct	  pc98_partition *partp;
342	u_int64_t part_sz, part_mb;
343
344	partp = ((struct pc98_partition *) &mboot.parts) + i - 1;
345
346	if (!bcmp(partp, &mtpart, sizeof (struct pc98_partition))) {
347		printf("<UNUSED>\n");
348		return;
349	}
350	/*
351	 * Be careful not to overflow.
352	 */
353	part_sz = (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs;
354	part_mb = part_sz * secsize;
355	part_mb /= (1024 * 1024);
356	printf("sysmid %d (%#04x),(%s)\n", partp->dp_mid, partp->dp_mid,
357	    get_type(partp->dp_mid));
358	printf("    start %lu, size %lu (%ju Meg), sid %d\n",
359		(u_long)(partp->dp_scyl * cylsecs), (u_long)part_sz,
360		(uintmax_t)part_mb, partp->dp_sid);
361	printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n"
362		,partp->dp_scyl
363		,partp->dp_shd
364		,partp->dp_ssect
365		,partp->dp_ecyl
366		,partp->dp_ehd
367		,partp->dp_esect);
368	printf ("\tsystem Name %.16s\n", partp->dp_name);
369}
370
371
372static void
373init_boot(void)
374{
375
376	mboot.signature = DOSMAGIC;
377}
378
379
380static void
381init_sector0(unsigned long start)
382{
383	struct pc98_partition *partp =
384		(struct pc98_partition *)(&mboot.parts[0]);
385
386	init_boot();
387
388	partp->dp_mid = DOSMID_386BSD;
389	partp->dp_sid = DOSSID_386BSD;
390
391	dos(start, disksecs - start, partp);
392}
393
394static void
395change_part(int i)
396{
397	struct pc98_partition *partp =
398		((struct pc98_partition *) &mboot.parts) + i - 1;
399
400    printf("The data for partition %d is:\n", i);
401    print_part(i);
402
403    if (u_flag && ok("Do you want to change it?")) {
404	int tmp;
405
406	if (i_flag) {
407		bzero((char *)partp, sizeof (struct pc98_partition));
408		if (i == 1) {
409			init_sector0(1);
410			printf("\nThe static data for the slice 1 has been reinitialized to:\n");
411			print_part(i);
412		}
413	}
414
415	do {
416		int x_start = partp->dp_scyl * cylsecs ;
417		int x_size  = (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs;
418		Decimal("sysmid", partp->dp_mid, tmp);
419		Decimal("syssid", partp->dp_sid, tmp);
420		String ("system name", partp->dp_name, 16);
421		Decimal("start", x_start, tmp);
422		Decimal("size", x_size, tmp);
423
424		if (ok("Explicitly specify beg/end address ?"))
425		{
426			int	tsec,tcyl,thd;
427			tcyl = partp->dp_scyl;
428			thd = partp->dp_shd;
429			tsec = partp->dp_ssect;
430			Decimal("beginning cylinder", tcyl, tmp);
431			Decimal("beginning head", thd, tmp);
432			Decimal("beginning sector", tsec, tmp);
433			partp->dp_scyl = tcyl;
434			partp->dp_ssect = tsec;
435			partp->dp_shd = thd;
436			partp->dp_ipl_cyl = partp->dp_scyl;
437			partp->dp_ipl_sct = partp->dp_ssect;
438			partp->dp_ipl_head = partp->dp_shd;
439
440			tcyl = partp->dp_ecyl;
441			thd = partp->dp_ehd;
442			tsec = partp->dp_esect;
443			Decimal("ending cylinder", tcyl, tmp);
444			Decimal("ending head", thd, tmp);
445			Decimal("ending sector", tsec, tmp);
446			partp->dp_ecyl = tcyl;
447			partp->dp_esect = tsec;
448			partp->dp_ehd = thd;
449		} else
450			dos(x_start, x_size, partp);
451
452		print_part(i);
453	} while (!ok("Are we happy with this entry?"));
454    }
455}
456
457static void
458print_params()
459{
460	printf("parameters extracted from in-core disklabel are:\n");
461	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
462			,cyls,heads,sectors,cylsecs);
463	if (dos_cyls > 65535 || dos_heads > 255 || dos_sectors > 255)
464		printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
465	printf("parameters to be used for BIOS calculations are:\n");
466	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
467		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
468}
469
470static void
471change_active(int which)
472{
473	struct pc98_partition *partp = &mboot.parts[0];
474	int active, i, new, tmp;
475
476	active = -1;
477	for (i = 0; i < NDOSPART; i++) {
478		if ((partp[i].dp_sid & ACTIVE) == 0)
479			continue;
480		printf("Partition %d is marked active\n", i + 1);
481		if (active == -1)
482			active = i + 1;
483	}
484	if (a_flag && which != -1)
485		active = which;
486	else if (active == -1)
487		active = 1;
488
489	if (!ok("Do you want to change the active partition?"))
490		return;
491setactive:
492	do {
493		new = active;
494		Decimal("active partition", new, tmp);
495		if (new < 1 || new > 8) {
496			printf("Active partition number must be in range 1-8."
497					"  Try again.\n");
498			goto setactive;
499		}
500		active = new;
501	} while (!ok("Are you happy with this choice"));
502	if (active > 0 && active <= 8)
503		partp[active-1].dp_sid |= ACTIVE;
504}
505
506static void
507change_code()
508{
509	if (ok("Do you want to change the boot code?"))
510		init_boot();
511}
512
513void
514get_params_to_use()
515{
516	int	tmp;
517	print_params();
518	if (ok("Do you want to change our idea of what BIOS thinks ?"))
519	{
520		do
521		{
522			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
523			Decimal("BIOS's idea of #heads", dos_heads, tmp);
524			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
525			dos_cylsecs = dos_heads * dos_sectors;
526			print_params();
527		}
528		while(!ok("Are you happy with this choice"));
529	}
530}
531
532
533/***********************************************\
534* Change real numbers into strange dos numbers	*
535\***********************************************/
536static void
537dos(u_int32_t start, u_int32_t size, struct pc98_partition *partp)
538{
539	u_int32_t end;
540
541	if (partp->dp_mid == 0 && partp->dp_sid == 0 &&
542	    start == 0 && size == 0) {
543		memcpy(partp, &mtpart, sizeof(*partp));
544		return;
545	}
546
547	/* Start c/h/s. */
548	partp->dp_scyl = partp->dp_ipl_cyl = start / dos_cylsecs;
549	partp->dp_shd = partp->dp_ipl_head = start % dos_cylsecs / dos_sectors;
550	partp->dp_ssect = partp->dp_ipl_sct = start % dos_sectors;
551
552	/* End c/h/s. */
553	end = start + size - cylsecs;
554	partp->dp_ecyl = end / dos_cylsecs;
555	partp->dp_ehd = end % dos_cylsecs / dos_sectors;
556	partp->dp_esect = end % dos_sectors;
557}
558
559static int
560open_disk(int flag)
561{
562	struct stat 	st;
563	int rwmode, p;
564	char *s;
565
566	fdw = -1;
567	if (stat(disk, &st) == -1) {
568		if (errno == ENOENT)
569			return -2;
570		warnx("can't get file status of %s", disk);
571		return -1;
572	}
573	if ( !(st.st_mode & S_IFCHR) )
574		warnx("device %s is not character special", disk);
575	rwmode = a_flag || B_flag || flag ? O_RDWR : O_RDONLY;
576	fd = open(disk, rwmode);
577	if (fd == -1 && errno == ENXIO)
578		return -2;
579	if (fd == -1 && errno == EPERM && rwmode == O_RDWR) {
580		fd = open(disk, O_RDONLY);
581		if (fd == -1)
582			return -3;
583		for (p = 0; p < NDOSPART; p++) {
584			asprintf(&s, "%ss%d", disk, p + 1);
585			fdw = open(s, rwmode);
586			free(s);
587			if (fdw == -1)
588				continue;
589			break;
590		}
591		if (fdw == -1)
592			return -4;
593	}
594	if (fd == -1) {
595		warnx("can't open device %s", disk);
596		return -1;
597	}
598	if (get_params() == -1) {
599		warnx("can't get disk parameters on %s", disk);
600		return -1;
601	}
602	return fd;
603}
604
605static ssize_t
606read_disk(off_t sector, void *buf)
607{
608
609	lseek(fd, (sector * 512), 0);
610	return read(fd, buf,
611		    secsize > MIN_SEC_SIZE ? secsize : MIN_SEC_SIZE * 2);
612}
613
614static ssize_t
615write_disk(off_t sector, void *buf)
616{
617
618	if (fdw != -1) {
619		return ioctl(fdw, DIOCSPC98, buf);
620	} else {
621		lseek(fd, (sector * 512), 0);
622		/* write out in the size that the read_disk found worked */
623		return write(fd, buf,
624		     secsize > MIN_SEC_SIZE ? secsize : MIN_SEC_SIZE * 2);
625	}
626}
627
628static int
629get_params()
630{
631	int error;
632	u_int u;
633	off_t o;
634
635	error = ioctl(fd, DIOCGFWSECTORS, &u);
636	if (error == 0)
637		sectors = dos_sectors = u;
638	else
639		sectors = dos_sectors = 17;
640
641	error = ioctl(fd, DIOCGFWHEADS, &u);
642	if (error == 0)
643		heads = dos_heads = u;
644	else
645		heads = dos_heads = 8;
646
647	dos_cylsecs = cylsecs = heads * sectors;
648	disksecs = cyls * heads * sectors;
649
650	error = ioctl(fd, DIOCGSECTORSIZE, &u);
651	if (error != 0 || u == 0)
652		u = 512;
653	secsize = u;
654
655	error = ioctl(fd, DIOCGMEDIASIZE, &o);
656	if (error == 0) {
657		disksecs = o / u;
658		cyls = dos_cyls = o / (u * dos_heads * dos_sectors);
659	}
660
661	return (disksecs);
662}
663
664
665static int
666read_s0()
667{
668
669	if (read_disk(0, (char *) mboot.bootinst) == -1) {
670		warnx("can't read fdisk partition table");
671		return -1;
672	}
673	if (mboot.signature != DOSMAGIC) {
674		warnx("invalid fdisk partition table found");
675		/* So should we initialize things */
676		return -1;
677	}
678
679	return 0;
680}
681
682static int
683write_s0()
684{
685
686	if (iotest) {
687		print_s0(-1);
688		return 0;
689	}
690
691	/*
692	 * write enable label sector before write (if necessary),
693	 * disable after writing.
694	 * needed if the disklabel protected area also protects
695	 * sector 0. (e.g. empty disk)
696	 */
697	if (write_disk(0, (char *) mboot.bootinst) == -1) {
698		warn("can't write fdisk partition table");
699		return -1;
700	}
701
702	return(0);
703}
704
705
706static int
707ok(const char *str)
708{
709	printf("%s [n] ", str);
710	fflush(stdout);
711	if (fgets(lbuf, LBUF, stdin) == NULL)
712		exit(1);
713	lbuf[strlen(lbuf)-1] = 0;
714
715	if (*lbuf &&
716		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
717		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
718		return 1;
719	else
720		return 0;
721}
722
723static int
724decimal(const char *str, int *num, int deflt)
725{
726	int acc = 0, c;
727	char *cp;
728
729	while (1) {
730		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
731		fflush(stdout);
732		if (fgets(lbuf, LBUF, stdin) == NULL)
733			exit(1);
734		lbuf[strlen(lbuf)-1] = 0;
735
736		if (!*lbuf)
737			return 0;
738
739		cp = lbuf;
740		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
741		if (!c)
742			return 0;
743		while ((c = *cp++)) {
744			if (c <= '9' && c >= '0')
745				acc = acc * 10 + c - '0';
746			else
747				break;
748		}
749		if (c == ' ' || c == '\t')
750			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
751		if (!c) {
752			*num = acc;
753			return 1;
754		} else
755			printf("%s is an invalid decimal number.  Try again.\n",
756				lbuf);
757	}
758
759}
760
761static int
762string(const char *str, char **ans)
763{
764	int i, c;
765	char *cp = lbuf;
766
767	while (1) {
768		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
769		fgets(lbuf, LBUF, stdin);
770		lbuf[strlen(lbuf)-1] = 0;
771
772		if (!*lbuf)
773			return 0;
774
775		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
776		if (c == '"') {
777			c = *++cp;
778			*ans = cp;
779			while ((c = *cp) && c != '"') cp++;
780		} else {
781			*ans = cp;
782			while ((c = *cp) && c != ' ' && c != '\t') cp++;
783		}
784
785		for (i = strlen(*ans); i < 16; i++)
786			(*ans)[i] = ' ';
787		(*ans)[16] = 0;
788
789		return 1;
790	}
791}
792
793static const char *
794get_type(int type)
795{
796	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
797	int	counter = 0;
798	struct	part_type *ptr = part_types;
799
800
801	while(counter < numentries) {
802		if(ptr->type == (type & 0x7f))
803			return(ptr->name);
804		ptr++;
805		counter++;
806	}
807	return("unknown");
808}
809
810/*
811 * Try figuring out the root device's canonical disk name.
812 * The following choices are considered:
813 *   /dev/ad0s1a     => /dev/ad0
814 *   /dev/da0a       => /dev/da0
815 *   /dev/vinum/root => /dev/vinum/root
816 */
817static char *
818get_rootdisk(void)
819{
820	struct statfs rootfs;
821	regex_t re;
822#define NMATCHES 2
823	regmatch_t rm[NMATCHES];
824	char *s;
825	int rv;
826
827	if (statfs("/", &rootfs) == -1)
828		err(1, "statfs(\"/\")");
829
830	if ((rv = regcomp(&re, "^(/dev/[a-z]+[0-9]+)([sp][0-9]+)?[a-h]?$",
831		    REG_EXTENDED)) != 0)
832		errx(1, "regcomp() failed (%d)", rv);
833	if ((rv = regexec(&re, rootfs.f_mntfromname, NMATCHES, rm, 0)) != 0)
834		errx(1,
835"mounted root fs resource doesn't match expectations (regexec returned %d)",
836		    rv);
837	if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL)
838		errx(1, "out of memory");
839	memcpy(s, rootfs.f_mntfromname + rm[1].rm_so,
840	    rm[1].rm_eo - rm[1].rm_so);
841	s[rm[1].rm_eo - rm[1].rm_so] = 0;
842
843	return s;
844}
845