fdisk.c revision 217714
1232950Stheraven/*
2232950Stheraven * Mach Operating System
3232950Stheraven * Copyright (c) 1992 Carnegie Mellon University
4232950Stheraven * All Rights Reserved.
5232950Stheraven *
6232950Stheraven * Permission to use, copy, modify and distribute this software and its
7232950Stheraven * documentation is hereby granted, provided that both the copyright
8232950Stheraven * notice and this permission notice appear in all copies of the
9232950Stheraven * software, derivative works or modified versions, and any portions
10232950Stheraven * thereof, and that both notices appear in supporting documentation.
11232950Stheraven *
12232950Stheraven * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13232950Stheraven * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14232950Stheraven * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15232950Stheraven *
16232950Stheraven * Carnegie Mellon requests users of this software to return to
17232950Stheraven *
18232950Stheraven *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19232950Stheraven *  School of Computer Science
20232950Stheraven *  Carnegie Mellon University
21232950Stheraven *  Pittsburgh PA 15213-3890
22232950Stheraven *
23232950Stheraven * any improvements or extensions that they make and grant Carnegie Mellon
24232950Stheraven * the rights to redistribute these changes.
25232950Stheraven */
26232950Stheraven
27227825Stheraven#include <sys/cdefs.h>
28227825Stheraven__FBSDID("$FreeBSD: head/sbin/fdisk/fdisk.c 217714 2011-01-22 05:21:20Z sobomax $");
29227825Stheraven
30227825Stheraven#include <sys/disk.h>
31227972Stheraven#include <sys/disklabel.h>
32227825Stheraven#include <sys/diskmbr.h>
33227825Stheraven#include <sys/endian.h>
34227825Stheraven#include <sys/param.h>
35250241Sdim#include <sys/stat.h>
36227825Stheraven#include <sys/mount.h>
37227825Stheraven#include <ctype.h>
38228004Stheraven#include <fcntl.h>
39228004Stheraven#include <err.h>
40228004Stheraven#include <errno.h>
41228004Stheraven#include <libgeom.h>
42253222Sdim#include <paths.h>
43253222Sdim#include <regex.h>
44253222Sdim#include <stdint.h>
45253222Sdim#include <stdio.h>
46253222Sdim#include <stdlib.h>
47253222Sdim#include <string.h>
48253222Sdim#include <unistd.h>
49253222Sdim
50253222Sdimint iotest;
51253222Sdim
52253222Sdim#define NOSECTORS ((u_int32_t)-1)
53253222Sdim#define LBUF 100
54253222Sdimstatic char lbuf[LBUF];
55253222Sdim
56253222Sdim/*
57253222Sdim *
58253222Sdim * Ported to 386bsd by Julian Elischer  Thu Oct 15 20:26:46 PDT 1992
59253222Sdim *
60228004Stheraven * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
61227825Stheraven *	Copyright (c) 1989	Robert. V. Baron
62227825Stheraven *	Created.
63227972Stheraven */
64227972Stheraven
65227972Stheraven#define Decimal(str, ans, tmp, size) if (decimal(str, &tmp, ans, size)) ans = tmp
66227972Stheraven
67227972Stheraven#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
68227972Stheraven
69227972Stheraven#define MAX_SEC_SIZE 2048	/* maximum section size that is supported */
70227972Stheraven#define MIN_SEC_SIZE 512	/* the sector size to start sensing at */
71227972Stheravenstatic int secsize = 0;		/* the sensed sector size */
72227972Stheraven
73227972Stheravenstatic char *disk;
74227972Stheraven
75227972Stheravenstatic int cyls, sectors, heads, cylsecs, disksecs;
76227972Stheraven
77227972Stheravenstruct mboot {
78227972Stheraven	unsigned char *bootinst;  /* boot code */
79227972Stheraven	off_t bootinst_size;
80227972Stheraven	struct	dos_partition parts[NDOSPART];
81227972Stheraven};
82227972Stheraven
83227972Stheravenstatic struct mboot mboot;
84227972Stheravenstatic int fd;
85227972Stheraven
86227972Stheraven#define ACTIVE 0x80
87227972Stheraven
88227972Stheravenstatic uint dos_cyls;
89227972Stheravenstatic uint dos_heads;
90227972Stheravenstatic uint dos_sectors;
91227972Stheravenstatic uint dos_cylsecs;
92227972Stheraven
93227972Stheraven#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
94227972Stheraven#define DOSCYL(c)	(c & 0xff)
95227972Stheraven
96227972Stheraven#define MAX_ARGS	10
97227972Stheraven
98227972Stheravenstatic int	current_line_number;
99227972Stheraven
100227972Stheravenstatic int	geom_processed = 0;
101227972Stheravenstatic int	part_processed = 0;
102227972Stheravenstatic int	active_processed = 0;
103227972Stheraven
104227972Stheraventypedef struct cmd {
105227972Stheraven    char		cmd;
106227972Stheraven    int			n_args;
107227972Stheraven    struct arg {
108227972Stheraven	char	argtype;
109227972Stheraven	int	arg_val;
110227972Stheraven	char	*arg_str;
111227972Stheraven    }			args[MAX_ARGS];
112227972Stheraven} CMD;
113227972Stheraven
114227972Stheravenstatic int B_flag  = 0;		/* replace boot code */
115227972Stheravenstatic int I_flag  = 0;		/* use entire disk for FreeBSD */
116227972Stheravenstatic int a_flag  = 0;		/* set active partition */
117227972Stheravenstatic char *b_flag = NULL;	/* path to boot code */
118227972Stheravenstatic int i_flag  = 0;		/* replace partition data */
119227972Stheravenstatic int q_flag  = 0;		/* Be quiet */
120227972Stheravenstatic int u_flag  = 0;		/* update partition data */
121227972Stheravenstatic int s_flag  = 0;		/* Print a summary and exit */
122227972Stheravenstatic int t_flag  = 0;		/* test only */
123227825Stheravenstatic char *f_flag = NULL;	/* Read config info from file */
124227825Stheravenstatic int v_flag  = 0;		/* Be verbose */
125227825Stheravenstatic int print_config_flag = 0;
126227825Stheraven
127227825Stheraven/*
128227825Stheraven * A list of partition types, probably outdated.
129227825Stheraven */
130227825Stheravenstatic const char *const part_types[256] = {
131227825Stheraven	[0x00] = "unused",
132227825Stheraven	[0x01] = "Primary DOS with 12 bit FAT",
133227825Stheraven	[0x02] = "XENIX / file system",
134227825Stheraven	[0x03] = "XENIX /usr file system",
135227825Stheraven	[0x04] = "Primary DOS with 16 bit FAT (< 32MB)",
136227825Stheraven	[0x05] = "Extended DOS",
137227825Stheraven	[0x06] = "Primary DOS, 16 bit FAT (>= 32MB)",
138227825Stheraven	[0x07] = "NTFS, OS/2 HPFS, QNX-2 (16 bit) or Advanced UNIX",
139227825Stheraven	[0x08] = "AIX file system or SplitDrive",
140227825Stheraven	[0x09] = "AIX boot partition or Coherent",
141227825Stheraven	[0x0A] = "OS/2 Boot Manager, OPUS or Coherent swap",
142227825Stheraven	[0x0B] = "DOS or Windows 95 with 32 bit FAT",
143227825Stheraven	[0x0C] = "DOS or Windows 95 with 32 bit FAT (LBA)",
144227825Stheraven	[0x0E] = "Primary 'big' DOS (>= 32MB, LBA)",
145227825Stheraven	[0x0F] = "Extended DOS (LBA)",
146227825Stheraven	[0x10] = "OPUS",
147227825Stheraven	[0x11] = "OS/2 BM: hidden DOS with 12-bit FAT",
148227825Stheraven	[0x12] = "Compaq diagnostics",
149227825Stheraven	[0x14] = "OS/2 BM: hidden DOS with 16-bit FAT (< 32MB)",
150227825Stheraven	[0x16] = "OS/2 BM: hidden DOS with 16-bit FAT (>= 32MB)",
151227825Stheraven	[0x17] = "OS/2 BM: hidden IFS (e.g. HPFS)",
152227825Stheraven	[0x18] = "AST Windows swapfile",
153227825Stheraven	[0x1b] = "ASUS Recovery partition (NTFS)",
154227825Stheraven	[0x24] = "NEC DOS",
155227825Stheraven	[0x3C] = "PartitionMagic recovery",
156227825Stheraven	[0x39] = "plan9",
157227825Stheraven	[0x40] = "VENIX 286",
158227825Stheraven	[0x41] = "Linux/MINIX (sharing disk with DRDOS)",
159227825Stheraven	[0x42] = "SFS or Linux swap (sharing disk with DRDOS)",
160227825Stheraven	[0x43] = "Linux native (sharing disk with DRDOS)",
161227825Stheraven	[0x4D] = "QNX 4.2 Primary",
162227825Stheraven	[0x4E] = "QNX 4.2 Secondary",
163227825Stheraven	[0x4F] = "QNX 4.2 Tertiary",
164227825Stheraven	[0x50] = "DM (disk manager)",
165227825Stheraven	[0x51] = "DM6 Aux1 (or Novell)",
166227825Stheraven	[0x52] = "CP/M or Microport SysV/AT",
167227825Stheraven	[0x53] = "DM6 Aux3",
168227825Stheraven	[0x54] = "DM6",
169227825Stheraven	[0x55] = "EZ-Drive (disk manager)",
170227825Stheraven	[0x56] = "Golden Bow (disk manager)",
171227825Stheraven	[0x5c] = "Priam Edisk (disk manager)", /* according to S. Widlake */
172227825Stheraven	[0x61] = "SpeedStor",
173227972Stheraven	[0x63] = "System V/386 (such as ISC UNIX), GNU HURD or Mach",
174227972Stheraven	[0x64] = "Novell Netware/286 2.xx",
175227972Stheraven	[0x65] = "Novell Netware/386 3.xx",
176227972Stheraven	[0x70] = "DiskSecure Multi-Boot",
177250241Sdim	[0x75] = "PCIX",
178250241Sdim	[0x77] = "QNX4.x",
179250241Sdim	[0x78] = "QNX4.x 2nd part",
180250241Sdim	[0x79] = "QNX4.x 3rd part",
181250241Sdim	[0x80] = "Minix until 1.4a",
182250241Sdim	[0x81] = "Minix since 1.4b, early Linux partition or Mitac disk manager",
183250241Sdim	[0x82] = "Linux swap or Solaris x86",
184250241Sdim	[0x83] = "Linux native",
185250241Sdim	[0x84] = "OS/2 hidden C: drive",
186250241Sdim	[0x85] = "Linux extended",
187250241Sdim	[0x86] = "NTFS volume set??",
188227825Stheraven	[0x87] = "NTFS volume set??",
189227825Stheraven	[0x93] = "Amoeba file system",
190227825Stheraven	[0x94] = "Amoeba bad block table",
191227825Stheraven	[0x9F] = "BSD/OS",
192227825Stheraven	[0xA0] = "Suspend to Disk",
193227825Stheraven	[0xA5] = "FreeBSD/NetBSD/386BSD",
194227825Stheraven	[0xA6] = "OpenBSD",
195227825Stheraven	[0xA7] = "NeXTSTEP",
196227825Stheraven	[0xA9] = "NetBSD",
197227825Stheraven	[0xAC] = "IBM JFS",
198227825Stheraven	[0xAF] = "HFS+",
199227825Stheraven	[0xB7] = "BSDI BSD/386 file system",
200227825Stheraven	[0xB8] = "BSDI BSD/386 swap",
201227825Stheraven	[0xBE] = "Solaris x86 boot",
202227825Stheraven	[0xBF] = "Solaris x86 (new)",
203227825Stheraven	[0xC1] = "DRDOS/sec with 12-bit FAT",
204227825Stheraven	[0xC4] = "DRDOS/sec with 16-bit FAT (< 32MB)",
205227825Stheraven	[0xC6] = "DRDOS/sec with 16-bit FAT (>= 32MB)",
206227825Stheraven	[0xC7] = "Syrinx",
207227972Stheraven	[0xDB] = "CP/M, Concurrent CP/M, Concurrent DOS or CTOS",
208227972Stheraven	[0xDE] = "DELL Utilities - FAT filesystem",
209227972Stheraven	[0xE1] = "DOS access or SpeedStor with 12-bit FAT extended partition",
210227972Stheraven	[0xE3] = "DOS R/O or SpeedStor",
211227825Stheraven	[0xE4] = "SpeedStor with 16-bit FAT extended partition < 1024 cyl.",
212227825Stheraven	[0xEB] = "BeOS file system",
213227825Stheraven	[0xEE] = "EFI GPT",
214227825Stheraven	[0xEF] = "EFI System Partition",
215227825Stheraven	[0xF1] = "SpeedStor",
216227825Stheraven	[0xF2] = "DOS 3.3+ Secondary",
217227825Stheraven	[0xF4] = "SpeedStor large partition",
218227825Stheraven	[0xFE] = "SpeedStor >1024 cyl. or LANstep",
219227825Stheraven	[0xFF] = "Xenix bad blocks table",
220227825Stheraven};
221227825Stheraven
222227825Stheravenstatic const char *
223227825Stheravenget_type(int t)
224227825Stheraven{
225227825Stheraven	const char *ret;
226227825Stheraven
227227825Stheraven	ret = (t >= 0 && t <= 255) ? part_types[t] : NULL;
228227825Stheraven	return ret ? ret : "unknown";
229227825Stheraven}
230227825Stheraven
231227825Stheraven
232227825Stheravenstatic void print_s0(void);
233227825Stheravenstatic void print_part(const struct dos_partition *);
234227825Stheravenstatic void init_sector0(unsigned long start);
235227825Stheravenstatic void init_boot(void);
236227825Stheravenstatic void change_part(int i);
237227825Stheravenstatic void print_params(void);
238227825Stheravenstatic void change_active(int which);
239227825Stheravenstatic void change_code(void);
240227825Stheravenstatic void get_params_to_use(void);
241227825Stheravenstatic char *get_rootdisk(void);
242227825Stheravenstatic void dos(struct dos_partition *partp);
243227825Stheravenstatic int open_disk(int flag);
244227825Stheravenstatic ssize_t read_disk(off_t sector, void *buf);
245227825Stheravenstatic int write_disk(off_t sector, void *buf);
246227825Stheravenstatic int get_params(void);
247227825Stheravenstatic int read_s0(void);
248227825Stheravenstatic int write_s0(void);
249227825Stheravenstatic int ok(const char *str);
250227825Stheravenstatic int decimal(const char *str, int *num, int deflt, int size);
251227825Stheravenstatic int read_config(char *config_file);
252227825Stheravenstatic void reset_boot(void);
253227825Stheravenstatic int sanitize_partition(struct dos_partition *);
254227825Stheravenstatic void usage(void);
255227825Stheraven
256227825Stheravenint
257227825Stheravenmain(int argc, char *argv[])
258227825Stheraven{
259227825Stheraven	int	c, i;
260227825Stheraven	int	partition = -1;
261227825Stheraven	struct	dos_partition *partp;
262227825Stheraven
263227825Stheraven	while ((c = getopt(argc, argv, "BIab:f:ipqstuv1234")) != -1)
264227825Stheraven		switch (c) {
265227825Stheraven		case 'B':
266227825Stheraven			B_flag = 1;
267227825Stheraven			break;
268227825Stheraven		case 'I':
269227825Stheraven			I_flag = 1;
270227825Stheraven			break;
271227825Stheraven		case 'a':
272227825Stheraven			a_flag = 1;
273227825Stheraven			break;
274227825Stheraven		case 'b':
275227825Stheraven			b_flag = optarg;
276227825Stheraven			break;
277227825Stheraven		case 'f':
278227825Stheraven			f_flag = optarg;
279227825Stheraven			break;
280227825Stheraven		case 'i':
281227825Stheraven			i_flag = 1;
282227825Stheraven			break;
283227825Stheraven		case 'p':
284227825Stheraven			print_config_flag = 1;
285227825Stheraven			break;
286227825Stheraven		case 'q':
287227825Stheraven			q_flag = 1;
288227825Stheraven			break;
289227825Stheraven		case 's':
290227825Stheraven			s_flag = 1;
291227825Stheraven			break;
292227825Stheraven		case 't':
293227825Stheraven			t_flag = 1;
294227825Stheraven			break;
295227825Stheraven		case 'u':
296227825Stheraven			u_flag = 1;
297227825Stheraven			break;
298227825Stheraven		case 'v':
299227825Stheraven			v_flag = 1;
300227825Stheraven			break;
301227825Stheraven		case '1':
302227825Stheraven		case '2':
303227825Stheraven		case '3':
304227825Stheraven		case '4':
305227825Stheraven			partition = c - '0';
306227825Stheraven			break;
307227825Stheraven		default:
308227825Stheraven			usage();
309227825Stheraven		}
310227825Stheraven	if (f_flag || i_flag)
311227825Stheraven		u_flag = 1;
312227825Stheraven	if (t_flag)
313227825Stheraven		v_flag = 1;
314227825Stheraven	argc -= optind;
315227825Stheraven	argv += optind;
316227825Stheraven
317227825Stheraven	if (argc == 0) {
318227825Stheraven		disk = get_rootdisk();
319227825Stheraven	} else {
320227825Stheraven		disk = g_device_path(argv[0]);
321227825Stheraven		if (disk == NULL)
322227825Stheraven			err(1, "unable to get correct path for %s", argv[0]);
323227825Stheraven	}
324227825Stheraven	if (open_disk(u_flag) < 0)
325227825Stheraven		err(1, "cannot open disk %s", disk);
326227825Stheraven
327227825Stheraven	/* (abu)use mboot.bootinst to probe for the sector size */
328227825Stheraven	if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL)
329227825Stheraven		err(1, "cannot allocate buffer to determine disk sector size");
330227825Stheraven	if (read_disk(0, mboot.bootinst) == -1)
331227825Stheraven		errx(1, "could not detect sector size");
332227825Stheraven	free(mboot.bootinst);
333227825Stheraven	mboot.bootinst = NULL;
334227825Stheraven
335227825Stheraven	if (print_config_flag) {
336227825Stheraven		if (read_s0())
337227825Stheraven			err(1, "read_s0");
338227825Stheraven
339250241Sdim		printf("# %s\n", disk);
340250241Sdim		printf("g c%d h%d s%d\n", dos_cyls, dos_heads, dos_sectors);
341250241Sdim
342250241Sdim		for (i = 0; i < NDOSPART; i++) {
343250241Sdim			partp = &mboot.parts[i];
344250241Sdim
345250241Sdim			if (partp->dp_start == 0 && partp->dp_size == 0)
346250241Sdim				continue;
347250241Sdim
348250241Sdim			printf("p %d 0x%02x %lu %lu\n", i + 1, partp->dp_typ,
349227825Stheraven			    (u_long)partp->dp_start, (u_long)partp->dp_size);
350227825Stheraven
351227825Stheraven			/* Fill flags for the partition. */
352227825Stheraven			if (partp->dp_flag & 0x80)
353227825Stheraven				printf("a %d\n", i + 1);
354227825Stheraven		}
355227825Stheraven		exit(0);
356227825Stheraven	}
357227825Stheraven	if (s_flag) {
358227825Stheraven		if (read_s0())
359227825Stheraven			err(1, "read_s0");
360228004Stheraven		printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads,
361228004Stheraven		    dos_sectors);
362228004Stheraven		printf("Part  %11s %11s Type Flags\n", "Start", "Size");
363228004Stheraven		for (i = 0; i < NDOSPART; i++) {
364228004Stheraven			partp = &mboot.parts[i];
365228004Stheraven			if (partp->dp_start == 0 && partp->dp_size == 0)
366228004Stheraven				continue;
367228004Stheraven			printf("%4d: %11lu %11lu 0x%02x 0x%02x\n", i + 1,
368228004Stheraven			    (u_long) partp->dp_start,
369228004Stheraven			    (u_long) partp->dp_size, partp->dp_typ,
370227825Stheraven			    partp->dp_flag);
371227825Stheraven		}
372227825Stheraven		exit(0);
373227825Stheraven	}
374228004Stheraven
375228004Stheraven	printf("******* Working on device %s *******\n",disk);
376228004Stheraven
377228004Stheraven	if (I_flag) {
378228004Stheraven		read_s0();
379228004Stheraven		reset_boot();
380228004Stheraven		partp = &mboot.parts[0];
381227825Stheraven		partp->dp_typ = DOSPTYP_386BSD;
382228004Stheraven		partp->dp_flag = ACTIVE;
383228004Stheraven		partp->dp_start = dos_sectors;
384228004Stheraven		partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs -
385227825Stheraven		    dos_sectors;
386227825Stheraven		dos(partp);
387227825Stheraven		if (v_flag)
388227825Stheraven			print_s0();
389227825Stheraven		if (!t_flag)
390227825Stheraven			write_s0();
391227825Stheraven		exit(0);
392228004Stheraven	}
393228004Stheraven	if (f_flag) {
394228004Stheraven	    if (read_s0() || i_flag)
395228004Stheraven		reset_boot();
396228004Stheraven	    if (!read_config(f_flag))
397227825Stheraven		exit(1);
398227825Stheraven	    if (v_flag)
399227825Stheraven		print_s0();
400227825Stheraven	    if (!t_flag)
401227825Stheraven		write_s0();
402227825Stheraven	} else {
403227825Stheraven	    if(u_flag)
404227825Stheraven		get_params_to_use();
405227825Stheraven	    else
406227825Stheraven		print_params();
407227825Stheraven
408227825Stheraven	    if (read_s0())
409227825Stheraven		init_sector0(dos_sectors);
410227825Stheraven
411228004Stheraven	    printf("Media sector size is %d\n", secsize);
412227825Stheraven	    printf("Warning: BIOS sector numbering starts with sector 1\n");
413227825Stheraven	    printf("Information from DOS bootblock is:\n");
414227825Stheraven	    if (partition == -1)
415227825Stheraven		for (i = 1; i <= NDOSPART; i++)
416227825Stheraven		    change_part(i);
417227825Stheraven	    else
418227825Stheraven		change_part(partition);
419227825Stheraven
420227825Stheraven	    if (u_flag || a_flag)
421227825Stheraven		change_active(partition);
422227825Stheraven
423227825Stheraven	    if (B_flag)
424227825Stheraven		change_code();
425227825Stheraven
426227825Stheraven	    if (u_flag || a_flag || B_flag) {
427227825Stheraven		if (!t_flag) {
428227825Stheraven		    printf("\nWe haven't changed the partition table yet.  ");
429227825Stheraven		    printf("This is your last chance.\n");
430227825Stheraven		}
431227825Stheraven		print_s0();
432227825Stheraven		if (!t_flag) {
433227825Stheraven		    if (ok("Should we write new partition table?"))
434227825Stheraven			write_s0();
435227825Stheraven		} else {
436227825Stheraven		    printf("\n-t flag specified -- partition table not written.\n");
437227825Stheraven		}
438227825Stheraven	    }
439227825Stheraven	}
440227825Stheraven
441227825Stheraven	exit(0);
442227825Stheraven}
443227825Stheraven
444227825Stheravenstatic void
445227825Stheravenusage()
446227825Stheraven{
447227825Stheraven	fprintf(stderr, "%s%s",
448227825Stheraven		"usage: fdisk [-BIaipqstu] [-b bootcode] [-1234] [disk]\n",
449227825Stheraven 		"       fdisk -f configfile [-itv] [disk]\n");
450227825Stheraven        exit(1);
451227825Stheraven}
452227825Stheraven
453227825Stheravenstatic void
454227825Stheravenprint_s0(void)
455227825Stheraven{
456227825Stheraven	int	i;
457227825Stheraven
458227825Stheraven	print_params();
459227825Stheraven	printf("Information from DOS bootblock is:\n");
460227825Stheraven	for (i = 1; i <= NDOSPART; i++) {
461227825Stheraven		printf("%d: ", i);
462227825Stheraven		print_part(&mboot.parts[i - 1]);
463232950Stheraven	}
464227825Stheraven}
465227825Stheraven
466227825Stheravenstatic struct dos_partition mtpart;
467227825Stheraven
468227825Stheravenstatic void
469227825Stheravenprint_part(const struct dos_partition *partp)
470227825Stheraven{
471227825Stheraven	u_int64_t part_mb;
472227825Stheraven
473227825Stheraven	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
474232950Stheraven		printf("<UNUSED>\n");
475227825Stheraven		return;
476227825Stheraven	}
477227825Stheraven	/*
478227825Stheraven	 * Be careful not to overflow.
479227825Stheraven	 */
480227825Stheraven	part_mb = partp->dp_size;
481227825Stheraven	part_mb *= secsize;
482227825Stheraven	part_mb /= (1024 * 1024);
483227825Stheraven	printf("sysid %d (%#04x),(%s)\n", partp->dp_typ, partp->dp_typ,
484227825Stheraven	    get_type(partp->dp_typ));
485227825Stheraven	printf("    start %lu, size %lu (%ju Meg), flag %x%s\n",
486227825Stheraven		(u_long)partp->dp_start,
487227825Stheraven		(u_long)partp->dp_size,
488227825Stheraven		(uintmax_t)part_mb,
489227825Stheraven		partp->dp_flag,
490227825Stheraven		partp->dp_flag == ACTIVE ? " (active)" : "");
491227825Stheraven	printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n"
492227825Stheraven		,DPCYL(partp->dp_scyl, partp->dp_ssect)
493227825Stheraven		,partp->dp_shd
494232950Stheraven		,DPSECT(partp->dp_ssect)
495227825Stheraven		,DPCYL(partp->dp_ecyl, partp->dp_esect)
496227825Stheraven		,partp->dp_ehd
497227825Stheraven		,DPSECT(partp->dp_esect));
498227825Stheraven}
499227825Stheraven
500227825Stheraven
501227825Stheravenstatic void
502227825Stheraveninit_boot(void)
503227825Stheraven{
504227825Stheraven#ifndef __ia64__
505227825Stheraven	const char *fname;
506227825Stheraven	int fdesc, n;
507227825Stheraven	struct stat sb;
508227825Stheraven
509227825Stheraven	fname = b_flag ? b_flag : "/boot/mbr";
510227825Stheraven	if ((fdesc = open(fname, O_RDONLY)) == -1 ||
511227825Stheraven	    fstat(fdesc, &sb) == -1)
512227825Stheraven		err(1, "%s", fname);
513227825Stheraven	if ((mboot.bootinst_size = sb.st_size) % secsize != 0)
514227825Stheraven		errx(1, "%s: length must be a multiple of sector size", fname);
515227825Stheraven	if (mboot.bootinst != NULL)
516227825Stheraven		free(mboot.bootinst);
517227825Stheraven	if ((mboot.bootinst = malloc(mboot.bootinst_size = sb.st_size)) == NULL)
518227825Stheraven		errx(1, "%s: unable to allocate read buffer", fname);
519227825Stheraven	if ((n = read(fdesc, mboot.bootinst, mboot.bootinst_size)) == -1 ||
520227825Stheraven	    close(fdesc))
521227825Stheraven		err(1, "%s", fname);
522227825Stheraven	if (n != mboot.bootinst_size)
523227825Stheraven		errx(1, "%s: short read", fname);
524227825Stheraven#else
525227825Stheraven	if (mboot.bootinst != NULL)
526227825Stheraven		free(mboot.bootinst);
527232950Stheraven	mboot.bootinst_size = secsize;
528227825Stheraven	if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL)
529227825Stheraven		errx(1, "unable to allocate boot block buffer");
530227825Stheraven	memset(mboot.bootinst, 0, mboot.bootinst_size);
531227825Stheraven	le16enc(&mboot.bootinst[DOSMAGICOFFSET], DOSMAGIC);
532232950Stheraven#endif
533232950Stheraven}
534227825Stheraven
535227825Stheraven
536227825Stheravenstatic void
537227825Stheraveninit_sector0(unsigned long start)
538227825Stheraven{
539227825Stheraven	struct dos_partition *partp = &mboot.parts[0];
540227825Stheraven
541227825Stheraven	init_boot();
542227825Stheraven
543227825Stheraven	partp->dp_typ = DOSPTYP_386BSD;
544227825Stheraven	partp->dp_flag = ACTIVE;
545227825Stheraven	start = ((start + dos_sectors - 1) / dos_sectors) * dos_sectors;
546227825Stheraven	if(start == 0)
547227825Stheraven		start = dos_sectors;
548227825Stheraven	partp->dp_start = start;
549227825Stheraven	partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - start;
550227825Stheraven
551227825Stheraven	dos(partp);
552227825Stheraven}
553227825Stheraven
554227825Stheravenstatic void
555227825Stheravenchange_part(int i)
556227825Stheraven{
557227825Stheraven    struct dos_partition *partp = &mboot.parts[i - 1];
558227825Stheraven
559227825Stheraven    printf("The data for partition %d is:\n", i);
560227825Stheraven    print_part(partp);
561227825Stheraven
562227825Stheraven    if (u_flag && ok("Do you want to change it?")) {
563227825Stheraven	int tmp;
564227825Stheraven
565227825Stheraven	if (i_flag) {
566227825Stheraven	    bzero(partp, sizeof (*partp));
567227825Stheraven	    if (i == 1) {
568227825Stheraven		init_sector0(1);
569227825Stheraven		printf("\nThe static data for the slice 1 has been reinitialized to:\n");
570227825Stheraven		print_part(partp);
571227825Stheraven	    }
572227825Stheraven	}
573227825Stheraven
574227825Stheraven	do {
575227825Stheraven		Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp, sizeof(partp->dp_typ));
576227825Stheraven		Decimal("start", partp->dp_start, tmp, sizeof(partp->dp_start));
577227825Stheraven		Decimal("size", partp->dp_size, tmp, sizeof(partp->dp_size));
578227825Stheraven		if (!sanitize_partition(partp)) {
579227825Stheraven			warnx("ERROR: failed to adjust; setting sysid to 0");
580227825Stheraven			partp->dp_typ = 0;
581227825Stheraven		}
582227825Stheraven
583227825Stheraven		if (ok("Explicitly specify beg/end address ?"))
584227825Stheraven		{
585227825Stheraven			int	tsec,tcyl,thd;
586227825Stheraven			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
587227825Stheraven			thd = partp->dp_shd;
588227825Stheraven			tsec = DPSECT(partp->dp_ssect);
589227825Stheraven			Decimal("beginning cylinder", tcyl, tmp, sizeof(partp->dp_scyl));
590227825Stheraven			Decimal("beginning head", thd, tmp, sizeof(partp->dp_shd));
591227825Stheraven			Decimal("beginning sector", tsec, tmp, sizeof(partp->dp_ssect));
592227825Stheraven			partp->dp_scyl = DOSCYL(tcyl);
593227825Stheraven			partp->dp_ssect = DOSSECT(tsec,tcyl);
594227825Stheraven			partp->dp_shd = thd;
595227825Stheraven
596227825Stheraven			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
597227825Stheraven			thd = partp->dp_ehd;
598227825Stheraven			tsec = DPSECT(partp->dp_esect);
599227825Stheraven			Decimal("ending cylinder", tcyl, tmp, sizeof(partp->dp_ecyl));
600227825Stheraven			Decimal("ending head", thd, tmp, sizeof(partp->dp_ehd));
601227825Stheraven			Decimal("ending sector", tsec, tmp, sizeof(partp->dp_esect));
602227825Stheraven			partp->dp_ecyl = DOSCYL(tcyl);
603227825Stheraven			partp->dp_esect = DOSSECT(tsec,tcyl);
604227825Stheraven			partp->dp_ehd = thd;
605227825Stheraven		} else
606227825Stheraven			dos(partp);
607227825Stheraven
608227825Stheraven		print_part(partp);
609227825Stheraven	} while (!ok("Are we happy with this entry?"));
610227825Stheraven    }
611227825Stheraven}
612227825Stheraven
613227825Stheravenstatic void
614227825Stheravenprint_params()
615227825Stheraven{
616227825Stheraven	printf("parameters extracted from in-core disklabel are:\n");
617227825Stheraven	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
618227825Stheraven			,cyls,heads,sectors,cylsecs);
619227825Stheraven	if (dos_cyls > 1023 || dos_heads > 255 || dos_sectors > 63)
620227825Stheraven		printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
621227825Stheraven	printf("parameters to be used for BIOS calculations are:\n");
622227825Stheraven	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
623227825Stheraven		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
624227825Stheraven}
625227825Stheraven
626227825Stheravenstatic void
627227825Stheravenchange_active(int which)
628227825Stheraven{
629227825Stheraven	struct dos_partition *partp = &mboot.parts[0];
630227825Stheraven	int active, i, new, tmp;
631227825Stheraven
632227825Stheraven	active = -1;
633227825Stheraven	for (i = 0; i < NDOSPART; i++) {
634227825Stheraven		if ((partp[i].dp_flag & ACTIVE) == 0)
635227825Stheraven			continue;
636227825Stheraven		printf("Partition %d is marked active\n", i + 1);
637227825Stheraven		if (active == -1)
638227825Stheraven			active = i + 1;
639227825Stheraven	}
640227825Stheraven	if (a_flag && which != -1)
641227825Stheraven		active = which;
642227825Stheraven	else if (active == -1)
643227825Stheraven		active = 1;
644227825Stheraven
645227825Stheraven	if (!ok("Do you want to change the active partition?"))
646227825Stheraven		return;
647227825Stheravensetactive:
648227825Stheraven	do {
649227825Stheraven		new = active;
650227825Stheraven		Decimal("active partition", new, tmp, 0);
651227825Stheraven		if (new < 1 || new > 4) {
652227825Stheraven			printf("Active partition number must be in range 1-4."
653227825Stheraven					"  Try again.\n");
654227825Stheraven			goto setactive;
655227825Stheraven		}
656227825Stheraven		active = new;
657227825Stheraven	} while (!ok("Are you happy with this choice"));
658227825Stheraven	for (i = 0; i < NDOSPART; i++)
659227825Stheraven		partp[i].dp_flag = 0;
660227825Stheraven	if (active > 0 && active <= NDOSPART)
661227825Stheraven		partp[active-1].dp_flag = ACTIVE;
662227825Stheraven}
663227825Stheraven
664227825Stheravenstatic void
665227825Stheravenchange_code()
666227825Stheraven{
667227825Stheraven	if (ok("Do you want to change the boot code?"))
668227825Stheraven		init_boot();
669227825Stheraven}
670227825Stheraven
671227825Stheravenvoid
672227825Stheravenget_params_to_use()
673227825Stheraven{
674227825Stheraven	int	tmp;
675227825Stheraven	print_params();
676227825Stheraven	if (ok("Do you want to change our idea of what BIOS thinks ?"))
677227825Stheraven	{
678227825Stheraven		do
679227825Stheraven		{
680227825Stheraven			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp, 0);
681227825Stheraven			Decimal("BIOS's idea of #heads", dos_heads, tmp, 0);
682227825Stheraven			Decimal("BIOS's idea of #sectors", dos_sectors, tmp, 0);
683227825Stheraven			dos_cylsecs = dos_heads * dos_sectors;
684227972Stheraven			print_params();
685227825Stheraven		}
686227825Stheraven		while(!ok("Are you happy with this choice"));
687227825Stheraven	}
688227972Stheraven}
689227825Stheraven
690227825Stheraven
691227825Stheraven/***********************************************\
692227825Stheraven* Change real numbers into strange dos numbers	*
693227825Stheraven\***********************************************/
694227825Stheravenstatic void
695227825Stheravendos(struct dos_partition *partp)
696227825Stheraven{
697227825Stheraven	int cy, sec;
698227825Stheraven	u_int32_t end;
699227825Stheraven
700227825Stheraven	if (partp->dp_typ == 0 && partp->dp_start == 0 && partp->dp_size == 0) {
701227825Stheraven		memcpy(partp, &mtpart, sizeof(*partp));
702227825Stheraven		return;
703227825Stheraven	}
704227825Stheraven
705227825Stheraven	/* Start c/h/s. */
706227825Stheraven	partp->dp_shd = partp->dp_start % dos_cylsecs / dos_sectors;
707227825Stheraven	cy = partp->dp_start / dos_cylsecs;
708227825Stheraven	sec = partp->dp_start % dos_sectors + 1;
709227825Stheraven	partp->dp_scyl = DOSCYL(cy);
710227825Stheraven	partp->dp_ssect = DOSSECT(sec, cy);
711227825Stheraven
712227825Stheraven	/* End c/h/s. */
713227825Stheraven	end = partp->dp_start + partp->dp_size - 1;
714227825Stheraven	partp->dp_ehd = end % dos_cylsecs / dos_sectors;
715227825Stheraven	cy = end / dos_cylsecs;
716227825Stheraven	sec = end % dos_sectors + 1;
717227825Stheraven	partp->dp_ecyl = DOSCYL(cy);
718227825Stheraven	partp->dp_esect = DOSSECT(sec, cy);
719227825Stheraven}
720227825Stheraven
721227825Stheravenstatic int
722227825Stheravenopen_disk(int flag)
723227825Stheraven{
724227825Stheraven	int rwmode;
725227825Stheraven
726227825Stheraven	/* Write mode if one of these flags are set. */
727227825Stheraven	rwmode = (a_flag || I_flag || B_flag || flag);
728227825Stheraven	fd = g_open(disk, rwmode);
729227825Stheraven	/* If the mode fails, try read-only if we didn't. */
730227825Stheraven	if (fd == -1 && errno == EPERM && rwmode)
731227825Stheraven		fd = g_open(disk, 0);
732227825Stheraven	if (fd == -1 && errno == ENXIO)
733227825Stheraven		return -2;
734227825Stheraven	if (fd == -1) {
735227825Stheraven		warnx("can't open device %s", disk);
736227825Stheraven		return -1;
737227825Stheraven	}
738227825Stheraven	if (get_params() == -1) {
739227825Stheraven		warnx("can't get disk parameters on %s", disk);
740227825Stheraven		return -1;
741227825Stheraven	}
742227825Stheraven	return fd;
743227825Stheraven}
744227825Stheraven
745227825Stheravenstatic ssize_t
746227825Stheravenread_disk(off_t sector, void *buf)
747227825Stheraven{
748227825Stheraven
749227825Stheraven	lseek(fd, (sector * 512), 0);
750227825Stheraven	if (secsize == 0)
751227825Stheraven		for (secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE;
752227825Stheraven		     secsize *= 2) {
753227825Stheraven			/* try the read */
754227825Stheraven			int size = read(fd, buf, secsize);
755227825Stheraven			if (size == secsize)
756227825Stheraven				/* it worked so return */
757227825Stheraven				return secsize;
758227825Stheraven		}
759227825Stheraven	else
760227825Stheraven		return read(fd, buf, secsize);
761227825Stheraven
762227825Stheraven	/* we failed to read at any of the sizes */
763227825Stheraven	return -1;
764227825Stheraven}
765227825Stheraven
766227825Stheravenstatic int
767227825Stheravenwrite_disk(off_t sector, void *buf)
768227825Stheraven{
769227825Stheraven	int error;
770227825Stheraven	struct gctl_req *grq;
771227825Stheraven	const char *errmsg;
772227825Stheraven	char fbuf[BUFSIZ], *pname;
773227825Stheraven	int i, fdw;
774227825Stheraven
775227825Stheraven	grq = gctl_get_handle();
776227825Stheraven	gctl_ro_param(grq, "verb", -1, "write MBR");
777227825Stheraven	gctl_ro_param(grq, "class", -1, "MBR");
778227825Stheraven	pname = g_providername(fd);
779227825Stheraven	if (pname == NULL) {
780227825Stheraven		warn("Error getting providername for %s", disk);
781227825Stheraven		return (-1);
782227825Stheraven	}
783227825Stheraven	gctl_ro_param(grq, "geom", -1, pname);
784227825Stheraven	gctl_ro_param(grq, "data", secsize, buf);
785227825Stheraven	errmsg = gctl_issue(grq);
786227825Stheraven	free(pname);
787227825Stheraven	if (errmsg == NULL) {
788227825Stheraven		gctl_free(grq);
789227825Stheraven		return(0);
790227825Stheraven	}
791227825Stheraven	if (!q_flag)	/* GEOM errors are benign, not all devices supported */
792227825Stheraven		warnx("%s", errmsg);
793227825Stheraven	gctl_free(grq);
794227825Stheraven
795227825Stheraven	error = pwrite(fd, buf, secsize, (sector * 512));
796227825Stheraven	if (error == secsize)
797227825Stheraven		return (0);
798227825Stheraven
799227825Stheraven	for (i = 1; i < 5; i++) {
800227825Stheraven		sprintf(fbuf, "%ss%d", disk, i);
801227825Stheraven		fdw = open(fbuf, O_RDWR, 0);
802227825Stheraven		if (fdw < 0)
803227825Stheraven			continue;
804227825Stheraven		error = ioctl(fdw, DIOCSMBR, buf);
805227825Stheraven		close(fdw);
806227825Stheraven		if (error == 0)
807227825Stheraven			return (0);
808227825Stheraven	}
809227825Stheraven	warnx("Failed to write sector zero");
810227825Stheraven	return(EINVAL);
811227825Stheraven}
812227825Stheraven
813227825Stheravenstatic int
814227825Stheravenget_params()
815227825Stheraven{
816227825Stheraven	int error;
817227825Stheraven	u_int u;
818227825Stheraven	off_t o;
819227825Stheraven
820250241Sdim	error = ioctl(fd, DIOCGFWSECTORS, &u);
821250241Sdim	if (error == 0)
822227825Stheraven		sectors = dos_sectors = u;
823227825Stheraven	else
824227825Stheraven		sectors = dos_sectors = 63;
825227825Stheraven
826227825Stheraven	error = ioctl(fd, DIOCGFWHEADS, &u);
827227825Stheraven	if (error == 0)
828227825Stheraven		heads = dos_heads = u;
829227825Stheraven	else
830227825Stheraven		heads = dos_heads = 255;
831227825Stheraven
832227825Stheraven	dos_cylsecs = cylsecs = heads * sectors;
833227825Stheraven	disksecs = cyls * heads * sectors;
834227825Stheraven
835227825Stheraven	u = g_sectorsize(fd);
836250241Sdim	if (u <= 0)
837250241Sdim		return (-1);
838250241Sdim
839250241Sdim	o = g_mediasize(fd);
840250241Sdim	if (o < 0)
841250241Sdim		return (-1);
842250241Sdim	disksecs = o / u;
843250241Sdim	cyls = dos_cyls = o / (u * dos_heads * dos_sectors);
844250241Sdim
845227825Stheraven	return (disksecs);
846227825Stheraven}
847227825Stheraven
848227825Stheravenstatic int
849227825Stheravenread_s0()
850227825Stheraven{
851227825Stheraven	int i;
852227825Stheraven
853227825Stheraven	mboot.bootinst_size = secsize;
854227825Stheraven	if (mboot.bootinst != NULL)
855227825Stheraven		free(mboot.bootinst);
856227825Stheraven	if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) {
857227825Stheraven		warnx("unable to allocate buffer to read fdisk "
858227825Stheraven		      "partition table");
859227825Stheraven		return -1;
860227825Stheraven	}
861227825Stheraven	if (read_disk(0, mboot.bootinst) == -1) {
862227825Stheraven		warnx("can't read fdisk partition table");
863227825Stheraven		return -1;
864227825Stheraven	}
865227825Stheraven	if (le16dec(&mboot.bootinst[DOSMAGICOFFSET]) != DOSMAGIC) {
866227825Stheraven		warnx("invalid fdisk partition table found");
867227825Stheraven		/* So should we initialize things */
868227825Stheraven		return -1;
869227825Stheraven	}
870227825Stheraven	for (i = 0; i < NDOSPART; i++)
871227825Stheraven		dos_partition_dec(
872227825Stheraven		    &mboot.bootinst[DOSPARTOFF + i * DOSPARTSIZE],
873227972Stheraven		    &mboot.parts[i]);
874227825Stheraven	return 0;
875227825Stheraven}
876227825Stheraven
877227825Stheravenstatic int
878227825Stheravenwrite_s0()
879227825Stheraven{
880227825Stheraven	int	sector, i;
881227825Stheraven
882227825Stheraven	if (iotest) {
883227825Stheraven		print_s0();
884227825Stheraven		return 0;
885227825Stheraven	}
886227825Stheraven	for(i = 0; i < NDOSPART; i++)
887227972Stheraven		dos_partition_enc(&mboot.bootinst[DOSPARTOFF + i * DOSPARTSIZE],
888227825Stheraven		    &mboot.parts[i]);
889227825Stheraven	le16enc(&mboot.bootinst[DOSMAGICOFFSET], DOSMAGIC);
890227825Stheraven	for(sector = 0; sector < mboot.bootinst_size / secsize; sector++)
891227825Stheraven		if (write_disk(sector,
892227825Stheraven			       &mboot.bootinst[sector * secsize]) == -1) {
893227825Stheraven			warn("can't write fdisk partition table");
894227825Stheraven			return -1;
895227825Stheraven		}
896227825Stheraven	return(0);
897227825Stheraven}
898250241Sdim
899227825Stheraven
900250241Sdimstatic int
901233235Stheravenok(const char *str)
902227825Stheraven{
903227825Stheraven	printf("%s [n] ", str);
904227825Stheraven	fflush(stdout);
905227825Stheraven	if (fgets(lbuf, LBUF, stdin) == NULL)
906227825Stheraven		exit(1);
907227825Stheraven	lbuf[strlen(lbuf)-1] = 0;
908227825Stheraven
909227825Stheraven	if (*lbuf &&
910227825Stheraven		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
911227825Stheraven		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
912227825Stheraven		return 1;
913227825Stheraven	else
914227825Stheraven		return 0;
915227825Stheraven}
916227825Stheraven
917227825Stheravenstatic int
918227825Stheravendecimal(const char *str, int *num, int deflt, int size)
919227825Stheraven{
920227825Stheraven	long long acc = 0, maxval;
921227825Stheraven	int c;
922227825Stheraven	char *cp;
923227825Stheraven
924227825Stheraven	if (size == 0) {
925227825Stheraven		size = sizeof(*num);
926227825Stheraven	}
927227825Stheraven	maxval = (long long)1 << (size * 8);
928233235Stheraven	while (1) {
929227825Stheraven		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
930233235Stheraven		fflush(stdout);
931227825Stheraven		if (fgets(lbuf, LBUF, stdin) == NULL)
932227825Stheraven			exit(1);
933233235Stheraven		lbuf[strlen(lbuf)-1] = 0;
934227825Stheraven
935227825Stheraven		if (!*lbuf)
936227825Stheraven			return 0;
937227825Stheraven
938227825Stheraven		cp = lbuf;
939227825Stheraven		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
940227825Stheraven		if (!c)
941227825Stheraven			return 0;
942227825Stheraven		while ((c = *cp++)) {
943227825Stheraven			if (c <= '9' && c >= '0') {
944227825Stheraven				if (acc < maxval)
945227825Stheraven					acc = acc * 10 + c - '0';
946227825Stheraven			} else
947227825Stheraven				break;
948227825Stheraven		}
949227825Stheraven		if (c == ' ' || c == '\t')
950227825Stheraven			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
951227825Stheraven		if (!c) {
952227825Stheraven			if (acc >= maxval) {
953227825Stheraven				acc = maxval - 1;
954227825Stheraven				printf("%s is too big, it will be truncated to %lld\n",
955227825Stheraven				    lbuf, acc);
956227825Stheraven			}
957227825Stheraven			*num = acc;
958227825Stheraven			return 1;
959227825Stheraven		} else
960227825Stheraven			printf("%s is an invalid decimal number.  Try again.\n",
961250241Sdim				lbuf);
962250241Sdim	}
963227825Stheraven
964227825Stheraven}
965227825Stheraven
966227825Stheraven
967227825Stheravenstatic void
968227825Stheravenparse_config_line(char *line, CMD *command)
969227825Stheraven{
970227825Stheraven    char	*cp, *end;
971227825Stheraven
972227825Stheraven    cp = line;
973227825Stheraven    while (1) {
974227825Stheraven	memset(command, 0, sizeof(*command));
975227972Stheraven
976227972Stheraven	while (isspace(*cp)) ++cp;
977227972Stheraven	if (*cp == '\0' || *cp == '#')
978227972Stheraven	    break;
979227972Stheraven	command->cmd = *cp++;
980227972Stheraven
981227972Stheraven	/*
982227972Stheraven	 * Parse args
983227972Stheraven	 */
984227972Stheraven	    while (1) {
985227972Stheraven	    while (isspace(*cp)) ++cp;
986227972Stheraven	    if (*cp == '\0')
987227972Stheraven		break;		/* eol */
988227972Stheraven	    if (*cp == '#')
989227825Stheraven		break;		/* found comment */
990227825Stheraven	    if (isalpha(*cp))
991227825Stheraven		command->args[command->n_args].argtype = *cp++;
992227825Stheraven	    end = NULL;
993227825Stheraven	    command->args[command->n_args].arg_val = strtol(cp, &end, 0);
994227825Stheraven 	    if (cp == end || (!isspace(*end) && *end != '\0')) {
995227825Stheraven 		char ch;
996227825Stheraven 		end = cp;
997227825Stheraven 		while (!isspace(*end) && *end != '\0') ++end;
998227825Stheraven 		ch = *end; *end = '\0';
999227825Stheraven 		command->args[command->n_args].arg_str = strdup(cp);
1000227825Stheraven 		*end = ch;
1001227972Stheraven 	    } else
1002227825Stheraven 		command->args[command->n_args].arg_str = NULL;
1003227825Stheraven	    cp = end;
1004227825Stheraven	    command->n_args++;
1005227825Stheraven	}
1006227825Stheraven	break;
1007227825Stheraven    }
1008227825Stheraven}
1009227825Stheraven
1010227825Stheraven
1011227825Stheravenstatic int
1012227825Stheravenprocess_geometry(CMD *command)
1013227825Stheraven{
1014227825Stheraven    int		status = 1, i;
1015227825Stheraven
1016227825Stheraven    while (1) {
1017227972Stheraven	geom_processed = 1;
1018227972Stheraven	    if (part_processed) {
1019227972Stheraven	    warnx(
1020227972Stheraven	"ERROR line %d: the geometry specification line must occur before\n\
1021227972Stheraven    all partition specifications",
1022227972Stheraven		    current_line_number);
1023227972Stheraven	    status = 0;
1024227972Stheraven	    break;
1025227972Stheraven	}
1026227972Stheraven	    if (command->n_args != 3) {
1027227972Stheraven	    warnx("ERROR line %d: incorrect number of geometry args",
1028227972Stheraven		    current_line_number);
1029227972Stheraven	    status = 0;
1030227972Stheraven	    break;
1031227972Stheraven	}
1032227972Stheraven	    dos_cyls = 0;
1033227972Stheraven	    dos_heads = 0;
1034227972Stheraven	    dos_sectors = 0;
1035227972Stheraven	    for (i = 0; i < 3; ++i) {
1036227825Stheraven		    switch (command->args[i].argtype) {
1037227825Stheraven	    case 'c':
1038227825Stheraven		dos_cyls = command->args[i].arg_val;
1039227825Stheraven		break;
1040227825Stheraven	    case 'h':
1041227972Stheraven		dos_heads = command->args[i].arg_val;
1042227972Stheraven		break;
1043227825Stheraven	    case 's':
1044227825Stheraven		dos_sectors = command->args[i].arg_val;
1045227825Stheraven		break;
1046227825Stheraven	    default:
1047227825Stheraven		warnx(
1048227825Stheraven		"ERROR line %d: unknown geometry arg type: '%c' (0x%02x)",
1049227825Stheraven			current_line_number, command->args[i].argtype,
1050227825Stheraven			command->args[i].argtype);
1051227825Stheraven		status = 0;
1052227825Stheraven		break;
1053227825Stheraven	    }
1054227825Stheraven	}
1055227825Stheraven	if (status == 0)
1056227825Stheraven	    break;
1057227825Stheraven
1058227825Stheraven	dos_cylsecs = dos_heads * dos_sectors;
1059227825Stheraven
1060227825Stheraven	/*
1061227825Stheraven	 * Do sanity checks on parameter values
1062227825Stheraven	 */
1063227825Stheraven	    if (dos_cyls == 0) {
1064227825Stheraven	    warnx("ERROR line %d: number of cylinders not specified",
1065227825Stheraven		    current_line_number);
1066227825Stheraven	    status = 0;
1067227825Stheraven	}
1068227825Stheraven	    if (dos_cyls > 1024) {
1069227972Stheraven	    warnx(
1070227825Stheraven	"WARNING line %d: number of cylinders (%d) may be out-of-range\n\
1071227825Stheraven    (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\
1072227825Stheraven    is dedicated to FreeBSD)",
1073227825Stheraven		    current_line_number, dos_cyls);
1074227825Stheraven	}
1075227825Stheraven
1076227825Stheraven	    if (dos_heads == 0) {
1077227825Stheraven	    warnx("ERROR line %d: number of heads not specified",
1078227825Stheraven		    current_line_number);
1079227825Stheraven	    status = 0;
1080227825Stheraven	    } else if (dos_heads > 256) {
1081227825Stheraven	    warnx("ERROR line %d: number of heads must be within (1-256)",
1082227825Stheraven		    current_line_number);
1083227825Stheraven	    status = 0;
1084227825Stheraven	}
1085227825Stheraven
1086227825Stheraven	    if (dos_sectors == 0) {
1087227825Stheraven	    warnx("ERROR line %d: number of sectors not specified",
1088227825Stheraven		    current_line_number);
1089227825Stheraven	    status = 0;
1090227825Stheraven	    } else if (dos_sectors > 63) {
1091227825Stheraven	    warnx("ERROR line %d: number of sectors must be within (1-63)",
1092227825Stheraven		    current_line_number);
1093227825Stheraven	    status = 0;
1094227825Stheraven	}
1095227825Stheraven
1096227825Stheraven	break;
1097227825Stheraven    }
1098227825Stheraven    return (status);
1099227825Stheraven}
1100227825Stheraven
1101227825Stheravenstatic u_int32_t
1102227825Stheravenstr2sectors(const char *str)
1103227825Stheraven{
1104227825Stheraven	char *end;
1105227825Stheraven	unsigned long val;
1106227825Stheraven
1107227825Stheraven	val = strtoul(str, &end, 0);
1108227825Stheraven	if (str == end || *end == '\0') {
1109227825Stheraven		warnx("ERROR line %d: unexpected size: \'%s\'",
1110227825Stheraven		    current_line_number, str);
1111227825Stheraven		return NOSECTORS;
1112227825Stheraven	}
1113227825Stheraven
1114227972Stheraven	if (*end == 'K')
1115227972Stheraven		val *= 1024UL / secsize;
1116227825Stheraven	else if (*end == 'M')
1117227825Stheraven		val *= 1024UL * 1024UL / secsize;
1118227825Stheraven	else if (*end == 'G')
1119227825Stheraven		val *= 1024UL * 1024UL * 1024UL / secsize;
1120227825Stheraven	else {
1121227972Stheraven		warnx("ERROR line %d: unexpected modifier: %c "
1122227825Stheraven		    "(not K/M/G)", current_line_number, *end);
1123227825Stheraven		return NOSECTORS;
1124227825Stheraven	}
1125227825Stheraven
1126227825Stheraven	return val;
1127227825Stheraven}
1128227825Stheraven
1129227825Stheravenstatic int
1130227825Stheravenprocess_partition(CMD *command)
1131227825Stheraven{
1132227825Stheraven    int				status = 0, partition;
1133227825Stheraven    u_int32_t			prev_head_boundary, prev_cyl_boundary;
1134227972Stheraven    u_int32_t			adj_size, max_end;
1135227825Stheraven    struct dos_partition	*partp;
1136227825Stheraven
1137227825Stheraven	while (1) {
1138227972Stheraven	part_processed = 1;
1139227972Stheraven		if (command->n_args != 4) {
1140227825Stheraven	    warnx("ERROR line %d: incorrect number of partition args",
1141227825Stheraven		    current_line_number);
1142227825Stheraven	    break;
1143227825Stheraven	}
1144227825Stheraven	partition = command->args[0].arg_val;
1145227825Stheraven		if (partition < 1 || partition > 4) {
1146227825Stheraven	    warnx("ERROR line %d: invalid partition number %d",
1147227825Stheraven		    current_line_number, partition);
1148227825Stheraven	    break;
1149227825Stheraven	}
1150227825Stheraven	partp = &mboot.parts[partition - 1];
1151227825Stheraven	bzero(partp, sizeof (*partp));
1152227825Stheraven	partp->dp_typ = command->args[1].arg_val;
1153227825Stheraven	if (command->args[2].arg_str != NULL) {
1154227825Stheraven		if (strcmp(command->args[2].arg_str, "*") == 0) {
1155227825Stheraven			int i;
1156227972Stheraven			partp->dp_start = dos_sectors;
1157227825Stheraven			for (i = 1; i < partition; i++) {
1158227825Stheraven    				struct dos_partition *prev_partp;
1159227825Stheraven				prev_partp = ((struct dos_partition *)
1160227825Stheraven				    &mboot.parts) + i - 1;
1161227825Stheraven				if (prev_partp->dp_typ != 0)
1162227825Stheraven					partp->dp_start = prev_partp->dp_start +
1163227825Stheraven					    prev_partp->dp_size;
1164227825Stheraven			}
1165227825Stheraven			if (partp->dp_start % dos_sectors != 0) {
1166227825Stheraven		    		prev_head_boundary = partp->dp_start /
1167227825Stheraven				    dos_sectors * dos_sectors;
1168227825Stheraven		    		partp->dp_start = prev_head_boundary +
1169227825Stheraven				    dos_sectors;
1170227825Stheraven			}
1171227825Stheraven		} else {
1172227825Stheraven			partp->dp_start = str2sectors(command->args[2].arg_str);
1173227825Stheraven			if (partp->dp_start == NOSECTORS)
1174227825Stheraven				break;
1175227825Stheraven		}
1176227825Stheraven	} else
1177227825Stheraven		partp->dp_start = command->args[2].arg_val;
1178227825Stheraven
1179227825Stheraven	if (command->args[3].arg_str != NULL) {
1180227825Stheraven		if (strcmp(command->args[3].arg_str, "*") == 0)
1181227825Stheraven			partp->dp_size = ((disksecs / dos_cylsecs) *
1182227825Stheraven			    dos_cylsecs) - partp->dp_start;
1183250241Sdim		else {
1184250241Sdim			partp->dp_size = str2sectors(command->args[3].arg_str);
1185250241Sdim			if (partp->dp_size == NOSECTORS)
1186250241Sdim				break;
1187227825Stheraven		}
1188227825Stheraven		prev_cyl_boundary = ((partp->dp_start + partp->dp_size) /
1189227825Stheraven		    dos_cylsecs) * dos_cylsecs;
1190227825Stheraven		if (prev_cyl_boundary > partp->dp_start)
1191227825Stheraven			partp->dp_size = prev_cyl_boundary - partp->dp_start;
1192227825Stheraven	} else
1193227825Stheraven		partp->dp_size = command->args[3].arg_val;
1194227825Stheraven
1195227825Stheraven	max_end = partp->dp_start + partp->dp_size;
1196227825Stheraven
1197227825Stheraven	if (partp->dp_typ == 0) {
1198227825Stheraven	    /*
1199227825Stheraven	     * Get out, the partition is marked as unused.
1200227825Stheraven	     */
1201227825Stheraven	    /*
1202227825Stheraven	     * Insure that it's unused.
1203227825Stheraven	     */
1204227825Stheraven	    bzero(partp, sizeof(*partp));
1205227825Stheraven	    status = 1;
1206227825Stheraven	    break;
1207227825Stheraven	}
1208227825Stheraven
1209227825Stheraven	/*
1210227825Stheraven	 * Adjust start upwards, if necessary, to fall on a head boundary.
1211227825Stheraven	 */
1212227825Stheraven		if (partp->dp_start % dos_sectors != 0) {
1213227825Stheraven	    prev_head_boundary = partp->dp_start / dos_sectors * dos_sectors;
1214227825Stheraven	    if (max_end < dos_sectors ||
1215227825Stheraven			    prev_head_boundary > max_end - dos_sectors) {
1216227825Stheraven		/*
1217227825Stheraven		 * Can't go past end of partition
1218227825Stheraven		 */
1219227825Stheraven		warnx(
1220227825Stheraven	"ERROR line %d: unable to adjust start of partition %d to fall on\n\
1221227825Stheraven    a head boundary",
1222227825Stheraven			current_line_number, partition);
1223227825Stheraven		break;
1224227825Stheraven	    }
1225227825Stheraven	    warnx(
1226227825Stheraven	"WARNING: adjusting start offset of partition %d\n\
1227227825Stheraven    from %u to %u, to fall on a head boundary",
1228227825Stheraven		    partition, (u_int)partp->dp_start,
1229250241Sdim		    (u_int)(prev_head_boundary + dos_sectors));
1230227825Stheraven	    partp->dp_start = prev_head_boundary + dos_sectors;
1231227825Stheraven	}
1232227825Stheraven
1233250241Sdim	/*
1234250241Sdim	 * Adjust size downwards, if necessary, to fall on a cylinder
1235250241Sdim	 * boundary.
1236250241Sdim	 */
1237250241Sdim	prev_cyl_boundary =
1238250241Sdim	    ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs;
1239250241Sdim	if (prev_cyl_boundary > partp->dp_start)
1240250241Sdim	    adj_size = prev_cyl_boundary - partp->dp_start;
1241250241Sdim		else {
1242250241Sdim	    warnx(
1243250241Sdim	"ERROR: could not adjust partition to start on a head boundary\n\
1244250241Sdim    and end on a cylinder boundary.");
1245227825Stheraven	    return (0);
1246227825Stheraven	}
1247227825Stheraven		if (adj_size != partp->dp_size) {
1248227825Stheraven	    warnx(
1249227825Stheraven	"WARNING: adjusting size of partition %d from %u to %u\n\
1250227972Stheraven    to end on a cylinder boundary",
1251227972Stheraven		    partition, (u_int)partp->dp_size, (u_int)adj_size);
1252227825Stheraven	    partp->dp_size = adj_size;
1253227825Stheraven	}
1254227825Stheraven		if (partp->dp_size == 0) {
1255227825Stheraven	    warnx("ERROR line %d: size of partition %d is zero",
1256227825Stheraven		    current_line_number, partition);
1257227825Stheraven	    break;
1258227825Stheraven	}
1259227825Stheraven
1260250241Sdim	dos(partp);
1261250241Sdim	status = 1;
1262227825Stheraven	break;
1263227825Stheraven    }
1264227825Stheraven    return (status);
1265250241Sdim}
1266250241Sdim
1267250241Sdim
1268250241Sdimstatic int
1269250241Sdimprocess_active(CMD *command)
1270250241Sdim{
1271250241Sdim    int				status = 0, partition, i;
1272250241Sdim    struct dos_partition	*partp;
1273250241Sdim
1274250241Sdim	while (1) {
1275250241Sdim	active_processed = 1;
1276250241Sdim		if (command->n_args != 1) {
1277227825Stheraven	    warnx("ERROR line %d: incorrect number of active args",
1278227825Stheraven		    current_line_number);
1279227825Stheraven	    status = 0;
1280227825Stheraven	    break;
1281227825Stheraven	}
1282227825Stheraven	partition = command->args[0].arg_val;
1283227825Stheraven		if (partition < 1 || partition > 4) {
1284227825Stheraven	    warnx("ERROR line %d: invalid partition number %d",
1285227825Stheraven		    current_line_number, partition);
1286227825Stheraven	    break;
1287227825Stheraven	}
1288227825Stheraven	/*
1289227825Stheraven	 * Reset active partition
1290227825Stheraven	 */
1291227825Stheraven	partp = mboot.parts;
1292227825Stheraven	for (i = 0; i < NDOSPART; i++)
1293227825Stheraven	    partp[i].dp_flag = 0;
1294227825Stheraven	partp[partition-1].dp_flag = ACTIVE;
1295227825Stheraven
1296227825Stheraven	status = 1;
1297227825Stheraven	break;
1298227825Stheraven    }
1299227825Stheraven    return (status);
1300227825Stheraven}
1301227825Stheraven
1302227825Stheraven
1303227825Stheravenstatic int
1304227825Stheravenprocess_line(char *line)
1305227825Stheraven{
1306227825Stheraven    CMD		command;
1307227825Stheraven    int		status = 1;
1308227825Stheraven
1309227825Stheraven	while (1) {
1310227825Stheraven	parse_config_line(line, &command);
1311227825Stheraven		switch (command.cmd) {
1312227825Stheraven	case 0:
1313227825Stheraven	    /*
1314227825Stheraven	     * Comment or blank line
1315227825Stheraven	     */
1316227825Stheraven	    break;
1317227825Stheraven	case 'g':
1318227825Stheraven	    /*
1319227825Stheraven	     * Set geometry
1320227825Stheraven	     */
1321227825Stheraven	    status = process_geometry(&command);
1322227825Stheraven	    break;
1323227825Stheraven	case 'p':
1324227825Stheraven	    status = process_partition(&command);
1325227825Stheraven	    break;
1326227825Stheraven	case 'a':
1327227825Stheraven	    status = process_active(&command);
1328227825Stheraven	    break;
1329227825Stheraven	default:
1330227825Stheraven	    status = 0;
1331227825Stheraven	    break;
1332227825Stheraven	}
1333227825Stheraven	break;
1334227825Stheraven    }
1335227825Stheraven    return (status);
1336227825Stheraven}
1337227825Stheraven
1338227825Stheraven
1339227825Stheravenstatic int
1340227825Stheravenread_config(char *config_file)
1341227825Stheraven{
1342227825Stheraven    FILE	*fp = NULL;
1343227825Stheraven    int		status = 1;
1344227825Stheraven    char	buf[1010];
1345227825Stheraven
1346227825Stheraven	while (1) {
1347227825Stheraven		if (strcmp(config_file, "-") != 0) {
1348227825Stheraven	    /*
1349227825Stheraven	     * We're not reading from stdin
1350227825Stheraven	     */
1351227825Stheraven			if ((fp = fopen(config_file, "r")) == NULL) {
1352227825Stheraven		status = 0;
1353227825Stheraven		break;
1354227825Stheraven	    }
1355227825Stheraven		} else {
1356227825Stheraven	    fp = stdin;
1357227825Stheraven	}
1358227825Stheraven	current_line_number = 0;
1359227825Stheraven		while (!feof(fp)) {
1360227825Stheraven	    if (fgets(buf, sizeof(buf), fp) == NULL)
1361227825Stheraven		break;
1362227825Stheraven	    ++current_line_number;
1363227825Stheraven	    status = process_line(buf);
1364227825Stheraven	    if (status == 0)
1365227825Stheraven		break;
1366227825Stheraven	    }
1367227825Stheraven	break;
1368227825Stheraven    }
1369227825Stheraven	if (fp) {
1370227825Stheraven	/*
1371227825Stheraven	 * It doesn't matter if we're reading from stdin, as we've reached EOF
1372227825Stheraven	 */
1373227825Stheraven	fclose(fp);
1374227825Stheraven    }
1375227825Stheraven    return (status);
1376227825Stheraven}
1377227825Stheraven
1378227825Stheraven
1379227825Stheravenstatic void
1380227825Stheravenreset_boot(void)
1381227825Stheraven{
1382227825Stheraven    int				i;
1383227825Stheraven    struct dos_partition	*partp;
1384227825Stheraven
1385227825Stheraven    init_boot();
1386227825Stheraven    for (i = 0; i < 4; ++i) {
1387227825Stheraven	partp = &mboot.parts[i];
1388227825Stheraven	bzero(partp, sizeof(*partp));
1389227825Stheraven    }
1390227825Stheraven}
1391227825Stheraven
1392227825Stheravenstatic int
1393227825Stheravensanitize_partition(struct dos_partition *partp)
1394227825Stheraven{
1395227825Stheraven    u_int32_t			prev_head_boundary, prev_cyl_boundary;
1396227825Stheraven    u_int32_t			max_end, size, start;
1397227825Stheraven
1398227825Stheraven    start = partp->dp_start;
1399227825Stheraven    size = partp->dp_size;
1400227825Stheraven    max_end = start + size;
1401227825Stheraven    /* Only allow a zero size if the partition is being marked unused. */
1402227825Stheraven    if (size == 0) {
1403227825Stheraven	if (start == 0 && partp->dp_typ == 0)
1404227825Stheraven	    return (1);
1405227825Stheraven	warnx("ERROR: size of partition is zero");
1406250241Sdim	return (0);
1407227825Stheraven    }
1408227825Stheraven    /* Return if no adjustment is necessary. */
1409227825Stheraven    if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0)
1410227825Stheraven	return (1);
1411227825Stheraven
1412227825Stheraven    if (start == 0) {
1413227825Stheraven	    warnx("WARNING: partition overlaps with partition table");
1414250241Sdim	    if (ok("Correct this automatically?"))
1415250241Sdim		    start = dos_sectors;
1416227825Stheraven    }
1417227825Stheraven    if (start % dos_sectors != 0)
1418227825Stheraven	warnx("WARNING: partition does not start on a head boundary");
1419227825Stheraven    if ((start  +size) % dos_sectors != 0)
1420227825Stheraven	warnx("WARNING: partition does not end on a cylinder boundary");
1421227825Stheraven    warnx("WARNING: this may confuse the BIOS or some operating systems");
1422227825Stheraven    if (!ok("Correct this automatically?"))
1423250241Sdim	return (1);
1424227825Stheraven
1425227825Stheraven    /*
1426227825Stheraven     * Adjust start upwards, if necessary, to fall on a head boundary.
1427227825Stheraven     */
1428227825Stheraven    if (start % dos_sectors != 0) {
1429227825Stheraven	prev_head_boundary = start / dos_sectors * dos_sectors;
1430227825Stheraven	if (max_end < dos_sectors ||
1431227825Stheraven	    prev_head_boundary >= max_end - dos_sectors) {
1432227825Stheraven	    /*
1433227825Stheraven	     * Can't go past end of partition
1434227825Stheraven	     */
1435227825Stheraven	    warnx(
1436227825Stheraven    "ERROR: unable to adjust start of partition to fall on a head boundary");
1437227825Stheraven	    return (0);
1438227825Stheraven        }
1439227825Stheraven	start = prev_head_boundary + dos_sectors;
1440250241Sdim    }
1441227825Stheraven
1442227825Stheraven    /*
1443227825Stheraven     * Adjust size downwards, if necessary, to fall on a cylinder
1444227825Stheraven     * boundary.
1445227825Stheraven     */
1446227825Stheraven    prev_cyl_boundary = ((start + size) / dos_cylsecs) * dos_cylsecs;
1447227825Stheraven    if (prev_cyl_boundary > start)
1448227825Stheraven	size = prev_cyl_boundary - start;
1449227825Stheraven    else {
1450227825Stheraven	warnx("ERROR: could not adjust partition to start on a head boundary\n\
1451227825Stheraven    and end on a cylinder boundary.");
1452227825Stheraven	return (0);
1453227825Stheraven    }
1454227825Stheraven
1455227825Stheraven    /* Finally, commit any changes to partp and return. */
1456227825Stheraven    if (start != partp->dp_start) {
1457227825Stheraven	warnx("WARNING: adjusting start offset of partition to %u",
1458227825Stheraven	    (u_int)start);
1459227825Stheraven	partp->dp_start = start;
1460227825Stheraven    }
1461227825Stheraven    if (size != partp->dp_size) {
1462227825Stheraven	warnx("WARNING: adjusting size of partition to %u", (u_int)size);
1463227825Stheraven	partp->dp_size = size;
1464227825Stheraven    }
1465227825Stheraven
1466227825Stheraven    return (1);
1467227825Stheraven}
1468227825Stheraven
1469250241Sdim/*
1470227825Stheraven * Try figuring out the root device's canonical disk name.
1471227825Stheraven * The following choices are considered:
1472227825Stheraven *   /dev/ad0s1a     => /dev/ad0
1473227825Stheraven *   /dev/da0a       => /dev/da0
1474227825Stheraven *   /dev/vinum/root => /dev/vinum/root
1475227825Stheraven * A ".eli" part is removed if it exists (see geli(8)).
1476227825Stheraven * A ".journal" ending is removed if it exists (see gjournal(8)).
1477227825Stheraven */
1478227825Stheravenstatic char *
1479227825Stheravenget_rootdisk(void)
1480227825Stheraven{
1481250241Sdim	struct statfs rootfs;
1482227825Stheraven	regex_t re;
1483227825Stheraven#define NMATCHES 2
1484227972Stheraven	regmatch_t rm[NMATCHES];
1485227972Stheraven	char dev[PATH_MAX], *s;
1486227972Stheraven	int rv;
1487227972Stheraven
1488227972Stheraven	if (statfs("/", &rootfs) == -1)
1489227972Stheraven		err(1, "statfs(\"/\")");
1490227972Stheraven
1491227972Stheraven	if ((rv = regcomp(&re, "^(/dev/[a-z/]+[0-9]*)([sp][0-9]+)?[a-h]?(\\.journal)?$",
1492227972Stheraven		    REG_EXTENDED)) != 0)
1493227972Stheraven		errx(1, "regcomp() failed (%d)", rv);
1494227972Stheraven	strlcpy(dev, rootfs.f_mntfromname, sizeof (dev));
1495227972Stheraven	if ((s = strstr(dev, ".eli")) != NULL)
1496227972Stheraven	    memmove(s, s+4, strlen(s + 4) + 1);
1497227972Stheraven
1498227972Stheraven	if ((rv = regexec(&re, dev, NMATCHES, rm, 0)) != 0)
1499227972Stheraven		errx(1,
1500227972Stheraven"mounted root fs resource doesn't match expectations (regexec returned %d)",
1501227972Stheraven		    rv);
1502227972Stheraven	if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL)
1503227972Stheraven		errx(1, "out of memory");
1504227972Stheraven	memcpy(s, rootfs.f_mntfromname + rm[1].rm_so,
1505227972Stheraven	    rm[1].rm_eo - rm[1].rm_so);
1506227972Stheraven	s[rm[1].rm_eo - rm[1].rm_so] = 0;
1507227972Stheraven
1508227972Stheraven	return s;
1509227972Stheraven}
1510227972Stheraven