fdisk.c revision 225007
1122394Sharti/*
2122394Sharti * Mach Operating System
3122394Sharti * Copyright (c) 1992 Carnegie Mellon University
4122394Sharti * All Rights Reserved.
5163820Sharti *
6163820Sharti * Permission to use, copy, modify and distribute this software and its
7163820Sharti * documentation is hereby granted, provided that both the copyright
8122394Sharti * notice and this permission notice appear in all copies of the
9122394Sharti * software, derivative works or modified versions, and any portions
10133211Sharti * thereof, and that both notices appear in supporting documentation.
11133211Sharti *
12133211Sharti * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13133211Sharti * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14133211Sharti * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15133211Sharti *
16122394Sharti * Carnegie Mellon requests users of this software to return to
17122394Sharti *
18122394Sharti *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19133211Sharti *  School of Computer Science
20133211Sharti *  Carnegie Mellon University
21133211Sharti *  Pittsburgh PA 15213-3890
22133211Sharti *
23133211Sharti * any improvements or extensions that they make and grant Carnegie Mellon
24133211Sharti * the rights to redistribute these changes.
25133211Sharti */
26133211Sharti
27133211Sharti#include <sys/cdefs.h>
28133211Sharti__FBSDID("$FreeBSD: head/sbin/fdisk/fdisk.c 225007 2011-08-19 12:48:06Z ae $");
29133211Sharti
30133211Sharti#include <sys/disk.h>
31122394Sharti#include <sys/disklabel.h>
32163820Sharti#include <sys/diskmbr.h>
33122394Sharti#include <sys/endian.h>
34122394Sharti#include <sys/param.h>
35122394Sharti#include <sys/stat.h>
36122394Sharti#include <sys/mount.h>
37216294Ssyrinx#include <ctype.h>
38122394Sharti#include <fcntl.h>
39122394Sharti#include <err.h>
40163820Sharti#include <errno.h>
41122394Sharti#include <libgeom.h>
42122394Sharti#include <paths.h>
43122394Sharti#include <regex.h>
44122394Sharti#include <stdint.h>
45122394Sharti#include <stdio.h>
46216294Ssyrinx#include <stdlib.h>
47122394Sharti#include <string.h>
48122394Sharti#include <unistd.h>
49122394Sharti
50122394Shartiint iotest;
51122394Sharti
52122394Sharti#define NO_DISK_SECTORS ((u_int32_t)-1)
53122394Sharti#define NO_TRACK_CYLINDERS 1023
54122394Sharti#define NO_TRACK_HEADS 255
55122394Sharti#define NO_TRACK_SECTORS 63
56122394Sharti#define LBUF 100
57163820Shartistatic char lbuf[LBUF];
58163820Sharti
59163820Sharti/*
60163820Sharti *
61163820Sharti * Ported to 386bsd by Julian Elischer  Thu Oct 15 20:26:46 PDT 1992
62122394Sharti *
63122394Sharti * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
64122394Sharti *	Copyright (c) 1989	Robert. V. Baron
65122394Sharti *	Created.
66122394Sharti */
67122394Sharti
68122394Sharti#define Decimal(str, ans, tmp, maxval) if (decimal(str, &tmp, ans, maxval)) ans = tmp
69122394Sharti
70122394Sharti#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
71122394Sharti
72122394Sharti#define MAX_SEC_SIZE 2048	/* maximum section size that is supported */
73122394Sharti#define MIN_SEC_SIZE 512	/* the sector size to start sensing at */
74122394Shartistatic int secsize = 0;		/* the sensed sector size */
75122394Sharti
76122394Shartistatic char *disk;
77122394Sharti
78122394Shartistatic int cyls, sectors, heads, cylsecs, disksecs;
79122394Sharti
80122394Shartistruct mboot {
81122394Sharti	unsigned char *bootinst;  /* boot code */
82122394Sharti	off_t bootinst_size;
83122394Sharti	struct	dos_partition parts[NDOSPART];
84122394Sharti};
85122394Sharti
86122394Shartistatic struct mboot mboot;
87122394Shartistatic int fd;
88122394Sharti
89122394Sharti#define ACTIVE 0x80
90122394Sharti
91122394Shartistatic uint dos_cyls;
92122394Shartistatic uint dos_heads;
93122394Shartistatic uint dos_sectors;
94122394Shartistatic uint dos_cylsecs;
95122394Sharti
96122394Sharti#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
97122394Sharti#define DOSCYL(c)	(c & 0xff)
98122394Sharti
99122394Sharti#define MAX_ARGS	10
100122394Sharti
101122394Shartistatic int	current_line_number;
102122394Sharti
103122394Shartistatic int	geom_processed = 0;
104122394Shartistatic int	part_processed = 0;
105122394Shartistatic int	active_processed = 0;
106122394Sharti
107122394Shartitypedef struct cmd {
108122394Sharti    char		cmd;
109122394Sharti    int			n_args;
110122394Sharti    struct arg {
111122394Sharti	char		argtype;
112122394Sharti	unsigned long	arg_val;
113122394Sharti	char *		arg_str;
114163820Sharti    }			args[MAX_ARGS];
115163820Sharti} CMD;
116122394Sharti
117163820Shartistatic int B_flag  = 0;		/* replace boot code */
118163820Shartistatic int I_flag  = 0;		/* use entire disk for FreeBSD */
119163820Shartistatic int a_flag  = 0;		/* set active partition */
120163820Shartistatic char *b_flag = NULL;	/* path to boot code */
121122394Shartistatic int i_flag  = 0;		/* replace partition data */
122163820Shartistatic int q_flag  = 0;		/* Be quiet */
123122394Shartistatic int u_flag  = 0;		/* update partition data */
124122394Shartistatic int s_flag  = 0;		/* Print a summary and exit */
125163820Shartistatic int t_flag  = 0;		/* test only */
126163820Shartistatic char *f_flag = NULL;	/* Read config info from file */
127122394Shartistatic int v_flag  = 0;		/* Be verbose */
128163820Shartistatic int print_config_flag = 0;
129163820Sharti
130122394Sharti/*
131163820Sharti * A list of partition types, probably outdated.
132163820Sharti */
133163820Shartistatic const char *const part_types[256] = {
134163820Sharti	[0x00] = "unused",
135122394Sharti	[0x01] = "Primary DOS with 12 bit FAT",
136163820Sharti	[0x02] = "XENIX / file system",
137163820Sharti	[0x03] = "XENIX /usr file system",
138163820Sharti	[0x04] = "Primary DOS with 16 bit FAT (< 32MB)",
139163820Sharti	[0x05] = "Extended DOS",
140163820Sharti	[0x06] = "Primary DOS, 16 bit FAT (>= 32MB)",
141163820Sharti	[0x07] = "NTFS, OS/2 HPFS, QNX-2 (16 bit) or Advanced UNIX",
142122394Sharti	[0x08] = "AIX file system or SplitDrive",
143163820Sharti	[0x09] = "AIX boot partition or Coherent",
144163820Sharti	[0x0A] = "OS/2 Boot Manager, OPUS or Coherent swap",
145163820Sharti	[0x0B] = "DOS or Windows 95 with 32 bit FAT",
146163820Sharti	[0x0C] = "DOS or Windows 95 with 32 bit FAT (LBA)",
147163820Sharti	[0x0E] = "Primary 'big' DOS (>= 32MB, LBA)",
148163820Sharti	[0x0F] = "Extended DOS (LBA)",
149163820Sharti	[0x10] = "OPUS",
150163820Sharti	[0x11] = "OS/2 BM: hidden DOS with 12-bit FAT",
151163820Sharti	[0x12] = "Compaq diagnostics",
152163820Sharti	[0x14] = "OS/2 BM: hidden DOS with 16-bit FAT (< 32MB)",
153163820Sharti	[0x16] = "OS/2 BM: hidden DOS with 16-bit FAT (>= 32MB)",
154163820Sharti	[0x17] = "OS/2 BM: hidden IFS (e.g. HPFS)",
155163820Sharti	[0x18] = "AST Windows swapfile",
156163820Sharti	[0x1b] = "ASUS Recovery partition (NTFS)",
157163820Sharti	[0x24] = "NEC DOS",
158163820Sharti	[0x3C] = "PartitionMagic recovery",
159163820Sharti	[0x39] = "plan9",
160163820Sharti	[0x40] = "VENIX 286",
161163820Sharti	[0x41] = "Linux/MINIX (sharing disk with DRDOS)",
162163820Sharti	[0x42] = "SFS or Linux swap (sharing disk with DRDOS)",
163163820Sharti	[0x43] = "Linux native (sharing disk with DRDOS)",
164122394Sharti	[0x4D] = "QNX 4.2 Primary",
165122394Sharti	[0x4E] = "QNX 4.2 Secondary",
166122394Sharti	[0x4F] = "QNX 4.2 Tertiary",
167216294Ssyrinx	[0x50] = "DM (disk manager)",
168216294Ssyrinx	[0x51] = "DM6 Aux1 (or Novell)",
169216294Ssyrinx	[0x52] = "CP/M or Microport SysV/AT",
170216294Ssyrinx	[0x53] = "DM6 Aux3",
171216294Ssyrinx	[0x54] = "DM6",
172216294Ssyrinx	[0x55] = "EZ-Drive (disk manager)",
173216294Ssyrinx	[0x56] = "Golden Bow (disk manager)",
174122394Sharti	[0x5c] = "Priam Edisk (disk manager)", /* according to S. Widlake */
175216294Ssyrinx	[0x61] = "SpeedStor",
176216294Ssyrinx	[0x63] = "System V/386 (such as ISC UNIX), GNU HURD or Mach",
177216294Ssyrinx	[0x64] = "Novell Netware/286 2.xx",
178122394Sharti	[0x65] = "Novell Netware/386 3.xx",
179216294Ssyrinx	[0x70] = "DiskSecure Multi-Boot",
180216294Ssyrinx	[0x75] = "PCIX",
181216294Ssyrinx	[0x77] = "QNX4.x",
182216294Ssyrinx	[0x78] = "QNX4.x 2nd part",
183216294Ssyrinx	[0x79] = "QNX4.x 3rd part",
184216294Ssyrinx	[0x80] = "Minix until 1.4a",
185216294Ssyrinx	[0x81] = "Minix since 1.4b, early Linux partition or Mitac disk manager",
186216294Ssyrinx	[0x82] = "Linux swap or Solaris x86",
187216294Ssyrinx	[0x83] = "Linux native",
188216294Ssyrinx	[0x84] = "OS/2 hidden C: drive",
189216294Ssyrinx	[0x85] = "Linux extended",
190216294Ssyrinx	[0x86] = "NTFS volume set??",
191216294Ssyrinx	[0x87] = "NTFS volume set??",
192216294Ssyrinx	[0x93] = "Amoeba file system",
193216294Ssyrinx	[0x94] = "Amoeba bad block table",
194216294Ssyrinx	[0x9F] = "BSD/OS",
195216294Ssyrinx	[0xA0] = "Suspend to Disk",
196216294Ssyrinx	[0xA5] = "FreeBSD/NetBSD/386BSD",
197216294Ssyrinx	[0xA6] = "OpenBSD",
198216294Ssyrinx	[0xA7] = "NeXTSTEP",
199216294Ssyrinx	[0xA9] = "NetBSD",
200216294Ssyrinx	[0xAC] = "IBM JFS",
201216294Ssyrinx	[0xAF] = "HFS+",
202216294Ssyrinx	[0xB7] = "BSDI BSD/386 file system",
203216294Ssyrinx	[0xB8] = "BSDI BSD/386 swap",
204216294Ssyrinx	[0xBE] = "Solaris x86 boot",
205216294Ssyrinx	[0xBF] = "Solaris x86 (new)",
206216294Ssyrinx	[0xC1] = "DRDOS/sec with 12-bit FAT",
207216294Ssyrinx	[0xC4] = "DRDOS/sec with 16-bit FAT (< 32MB)",
208216294Ssyrinx	[0xC6] = "DRDOS/sec with 16-bit FAT (>= 32MB)",
209216294Ssyrinx	[0xC7] = "Syrinx",
210216294Ssyrinx	[0xDB] = "CP/M, Concurrent CP/M, Concurrent DOS or CTOS",
211216294Ssyrinx	[0xDE] = "DELL Utilities - FAT filesystem",
212216294Ssyrinx	[0xE1] = "DOS access or SpeedStor with 12-bit FAT extended partition",
213216294Ssyrinx	[0xE3] = "DOS R/O or SpeedStor",
214216294Ssyrinx	[0xE4] = "SpeedStor with 16-bit FAT extended partition < 1024 cyl.",
215216294Ssyrinx	[0xEB] = "BeOS file system",
216216294Ssyrinx	[0xEE] = "EFI GPT",
217216294Ssyrinx	[0xEF] = "EFI System Partition",
218216294Ssyrinx	[0xF1] = "SpeedStor",
219216294Ssyrinx	[0xF2] = "DOS 3.3+ Secondary",
220216294Ssyrinx	[0xF4] = "SpeedStor large partition",
221216294Ssyrinx	[0xFE] = "SpeedStor >1024 cyl. or LANstep",
222216294Ssyrinx	[0xFF] = "Xenix bad blocks table",
223216294Ssyrinx};
224216294Ssyrinx
225216294Ssyrinxstatic const char *
226216294Ssyrinxget_type(int t)
227216294Ssyrinx{
228216294Ssyrinx	const char *ret;
229216294Ssyrinx
230216294Ssyrinx	ret = (t >= 0 && t <= 255) ? part_types[t] : NULL;
231216294Ssyrinx	return ret ? ret : "unknown";
232216294Ssyrinx}
233216294Ssyrinx
234216294Ssyrinx
235216294Ssyrinxstatic void print_s0(void);
236216294Ssyrinxstatic void print_part(const struct dos_partition *);
237216294Ssyrinxstatic void init_sector0(unsigned long start);
238216294Ssyrinxstatic void init_boot(void);
239216294Ssyrinxstatic void change_part(int i);
240216294Ssyrinxstatic void print_params(void);
241216294Ssyrinxstatic void change_active(int which);
242216294Ssyrinxstatic void change_code(void);
243216294Ssyrinxstatic void get_params_to_use(void);
244216294Ssyrinxstatic char *get_rootdisk(void);
245122394Shartistatic void dos(struct dos_partition *partp);
246122394Shartistatic int open_disk(int flag);
247122394Shartistatic ssize_t read_disk(off_t sector, void *buf);
248122394Shartistatic int write_disk(off_t sector, void *buf);
249122394Shartistatic int get_params(void);
250122394Shartistatic int read_s0(void);
251122394Shartistatic int write_s0(void);
252122394Shartistatic int ok(const char *str);
253122394Shartistatic int decimal(const char *str, int *num, int deflt, uint32_t maxval);
254122394Shartistatic int read_config(char *config_file);
255122394Shartistatic void reset_boot(void);
256122394Shartistatic int sanitize_partition(struct dos_partition *);
257122394Shartistatic void usage(void);
258122394Sharti
259122394Shartiint
260122394Shartimain(int argc, char *argv[])
261122394Sharti{
262122394Sharti	int	c, i;
263122394Sharti	int	partition = -1;
264122394Sharti	struct	dos_partition *partp;
265122394Sharti
266122394Sharti	while ((c = getopt(argc, argv, "BIab:f:ipqstuv1234")) != -1)
267122394Sharti		switch (c) {
268122394Sharti		case 'B':
269122394Sharti			B_flag = 1;
270122394Sharti			break;
271122394Sharti		case 'I':
272122394Sharti			I_flag = 1;
273122394Sharti			break;
274122394Sharti		case 'a':
275122394Sharti			a_flag = 1;
276122394Sharti			break;
277122394Sharti		case 'b':
278122394Sharti			b_flag = optarg;
279122394Sharti			break;
280122394Sharti		case 'f':
281122394Sharti			f_flag = optarg;
282122394Sharti			break;
283122394Sharti		case 'i':
284122394Sharti			i_flag = 1;
285122394Sharti			break;
286122394Sharti		case 'p':
287122394Sharti			print_config_flag = 1;
288122394Sharti			break;
289122394Sharti		case 'q':
290122394Sharti			q_flag = 1;
291122394Sharti			break;
292122394Sharti		case 's':
293122394Sharti			s_flag = 1;
294122394Sharti			break;
295122394Sharti		case 't':
296122394Sharti			t_flag = 1;
297122394Sharti			break;
298122394Sharti		case 'u':
299122394Sharti			u_flag = 1;
300122394Sharti			break;
301122394Sharti		case 'v':
302122394Sharti			v_flag = 1;
303122394Sharti			break;
304122394Sharti		case '1':
305122394Sharti		case '2':
306122394Sharti		case '3':
307122394Sharti		case '4':
308122394Sharti			partition = c - '0';
309122394Sharti			break;
310122394Sharti		default:
311122394Sharti			usage();
312122394Sharti		}
313122394Sharti	if (f_flag || i_flag)
314122394Sharti		u_flag = 1;
315122394Sharti	if (t_flag)
316122394Sharti		v_flag = 1;
317122394Sharti	argc -= optind;
318122394Sharti	argv += optind;
319122394Sharti
320122394Sharti	if (argc == 0) {
321122394Sharti		disk = get_rootdisk();
322122394Sharti	} else {
323122394Sharti		disk = g_device_path(argv[0]);
324122394Sharti		if (disk == NULL)
325122394Sharti			err(1, "unable to get correct path for %s", argv[0]);
326122394Sharti	}
327122394Sharti	if (open_disk(u_flag) < 0)
328122394Sharti		err(1, "cannot open disk %s", disk);
329122394Sharti
330122394Sharti	/* (abu)use mboot.bootinst to probe for the sector size */
331122394Sharti	if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL)
332122394Sharti		err(1, "cannot allocate buffer to determine disk sector size");
333122394Sharti	if (read_disk(0, mboot.bootinst) == -1)
334122394Sharti		errx(1, "could not detect sector size");
335122394Sharti	free(mboot.bootinst);
336122394Sharti	mboot.bootinst = NULL;
337122394Sharti
338122394Sharti	if (print_config_flag) {
339122394Sharti		if (read_s0())
340122394Sharti			err(1, "read_s0");
341122394Sharti
342122394Sharti		printf("# %s\n", disk);
343122394Sharti		printf("g c%d h%d s%d\n", dos_cyls, dos_heads, dos_sectors);
344122394Sharti
345122394Sharti		for (i = 0; i < NDOSPART; i++) {
346122394Sharti			partp = &mboot.parts[i];
347122394Sharti
348122394Sharti			if (partp->dp_start == 0 && partp->dp_size == 0)
349122394Sharti				continue;
350122394Sharti
351122394Sharti			printf("p %d 0x%02x %lu %lu\n", i + 1, partp->dp_typ,
352122394Sharti			    (u_long)partp->dp_start, (u_long)partp->dp_size);
353122394Sharti
354122394Sharti			/* Fill flags for the partition. */
355122394Sharti			if (partp->dp_flag & 0x80)
356122394Sharti				printf("a %d\n", i + 1);
357122394Sharti		}
358122394Sharti		exit(0);
359122394Sharti	}
360122394Sharti	if (s_flag) {
361122394Sharti		if (read_s0())
362122394Sharti			err(1, "read_s0");
363122394Sharti		printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads,
364122394Sharti		    dos_sectors);
365122394Sharti		printf("Part  %11s %11s Type Flags\n", "Start", "Size");
366122394Sharti		for (i = 0; i < NDOSPART; i++) {
367122394Sharti			partp = &mboot.parts[i];
368122394Sharti			if (partp->dp_start == 0 && partp->dp_size == 0)
369122394Sharti				continue;
370122394Sharti			printf("%4d: %11lu %11lu 0x%02x 0x%02x\n", i + 1,
371122394Sharti			    (u_long) partp->dp_start,
372122394Sharti			    (u_long) partp->dp_size, partp->dp_typ,
373122394Sharti			    partp->dp_flag);
374122394Sharti		}
375122394Sharti		exit(0);
376122394Sharti	}
377122394Sharti
378122394Sharti	printf("******* Working on device %s *******\n",disk);
379122394Sharti
380122394Sharti	if (I_flag) {
381122394Sharti		read_s0();
382122394Sharti		reset_boot();
383122394Sharti		partp = &mboot.parts[0];
384122394Sharti		partp->dp_typ = DOSPTYP_386BSD;
385122394Sharti		partp->dp_flag = ACTIVE;
386122394Sharti		partp->dp_start = dos_sectors;
387122394Sharti		partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs -
388122394Sharti		    dos_sectors;
389122394Sharti		dos(partp);
390122394Sharti		if (v_flag)
391122394Sharti			print_s0();
392122394Sharti		if (!t_flag)
393122394Sharti			write_s0();
394122394Sharti		exit(0);
395122394Sharti	}
396122394Sharti	if (f_flag) {
397122394Sharti	    if (read_s0() || i_flag)
398122394Sharti		reset_boot();
399122394Sharti	    if (!read_config(f_flag))
400122394Sharti		exit(1);
401122394Sharti	    if (v_flag)
402122394Sharti		print_s0();
403122394Sharti	    if (!t_flag)
404122394Sharti		write_s0();
405122394Sharti	} else {
406122394Sharti	    if(u_flag)
407122394Sharti		get_params_to_use();
408122394Sharti	    else
409122394Sharti		print_params();
410122394Sharti
411122394Sharti	    if (read_s0())
412122394Sharti		init_sector0(dos_sectors);
413122394Sharti
414122394Sharti	    printf("Media sector size is %d\n", secsize);
415122394Sharti	    printf("Warning: BIOS sector numbering starts with sector 1\n");
416122394Sharti	    printf("Information from DOS bootblock is:\n");
417122394Sharti	    if (partition == -1)
418122394Sharti		for (i = 1; i <= NDOSPART; i++)
419122394Sharti		    change_part(i);
420122394Sharti	    else
421122394Sharti		change_part(partition);
422122394Sharti
423122394Sharti	    if (u_flag || a_flag)
424122394Sharti		change_active(partition);
425122394Sharti
426122394Sharti	    if (B_flag)
427122394Sharti		change_code();
428122394Sharti
429122394Sharti	    if (u_flag || a_flag || B_flag) {
430122394Sharti		if (!t_flag) {
431122394Sharti		    printf("\nWe haven't changed the partition table yet.  ");
432122394Sharti		    printf("This is your last chance.\n");
433122394Sharti		}
434122394Sharti		print_s0();
435122394Sharti		if (!t_flag) {
436122394Sharti		    if (ok("Should we write new partition table?"))
437122394Sharti			write_s0();
438122394Sharti		} else {
439122394Sharti		    printf("\n-t flag specified -- partition table not written.\n");
440122394Sharti		}
441122394Sharti	    }
442122394Sharti	}
443122394Sharti
444122394Sharti	exit(0);
445122394Sharti}
446122394Sharti
447122394Shartistatic void
448122394Shartiusage()
449122394Sharti{
450122394Sharti	fprintf(stderr, "%s%s",
451122394Sharti		"usage: fdisk [-BIaipqstu] [-b bootcode] [-1234] [disk]\n",
452122394Sharti 		"       fdisk -f configfile [-itv] [disk]\n");
453122394Sharti        exit(1);
454122394Sharti}
455122394Sharti
456122394Shartistatic void
457122394Shartiprint_s0(void)
458122394Sharti{
459122394Sharti	int	i;
460122394Sharti
461122394Sharti	print_params();
462122394Sharti	printf("Information from DOS bootblock is:\n");
463122394Sharti	for (i = 1; i <= NDOSPART; i++) {
464122394Sharti		printf("%d: ", i);
465122394Sharti		print_part(&mboot.parts[i - 1]);
466122394Sharti	}
467122394Sharti}
468122394Sharti
469122394Shartistatic struct dos_partition mtpart;
470122394Sharti
471122394Shartistatic void
472122394Shartiprint_part(const struct dos_partition *partp)
473122394Sharti{
474122394Sharti	u_int64_t part_mb;
475122394Sharti
476122394Sharti	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
477122394Sharti		printf("<UNUSED>\n");
478122394Sharti		return;
479122394Sharti	}
480122394Sharti	/*
481122394Sharti	 * Be careful not to overflow.
482122394Sharti	 */
483122394Sharti	part_mb = partp->dp_size;
484122394Sharti	part_mb *= secsize;
485122394Sharti	part_mb /= (1024 * 1024);
486122394Sharti	printf("sysid %d (%#04x),(%s)\n", partp->dp_typ, partp->dp_typ,
487122394Sharti	    get_type(partp->dp_typ));
488122394Sharti	printf("    start %lu, size %lu (%ju Meg), flag %x%s\n",
489122394Sharti		(u_long)partp->dp_start,
490122394Sharti		(u_long)partp->dp_size,
491122394Sharti		(uintmax_t)part_mb,
492122394Sharti		partp->dp_flag,
493122394Sharti		partp->dp_flag == ACTIVE ? " (active)" : "");
494122394Sharti	printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n"
495122394Sharti		,DPCYL(partp->dp_scyl, partp->dp_ssect)
496122394Sharti		,partp->dp_shd
497122394Sharti		,DPSECT(partp->dp_ssect)
498122394Sharti		,DPCYL(partp->dp_ecyl, partp->dp_esect)
499122394Sharti		,partp->dp_ehd
500122394Sharti		,DPSECT(partp->dp_esect));
501122394Sharti}
502122394Sharti
503122394Sharti
504122394Shartistatic void
505122394Shartiinit_boot(void)
506122394Sharti{
507122394Sharti#ifndef __ia64__
508122394Sharti	const char *fname;
509122394Sharti	int fdesc, n;
510122394Sharti	struct stat sb;
511122394Sharti
512122394Sharti	fname = b_flag ? b_flag : "/boot/mbr";
513122394Sharti	if ((fdesc = open(fname, O_RDONLY)) == -1 ||
514122394Sharti	    fstat(fdesc, &sb) == -1)
515122394Sharti		err(1, "%s", fname);
516122394Sharti	if ((mboot.bootinst_size = sb.st_size) % secsize != 0)
517122394Sharti		errx(1, "%s: length must be a multiple of sector size", fname);
518122394Sharti	if (mboot.bootinst != NULL)
519122394Sharti		free(mboot.bootinst);
520122394Sharti	if ((mboot.bootinst = malloc(mboot.bootinst_size = sb.st_size)) == NULL)
521122394Sharti		errx(1, "%s: unable to allocate read buffer", fname);
522122394Sharti	if ((n = read(fdesc, mboot.bootinst, mboot.bootinst_size)) == -1 ||
523122394Sharti	    close(fdesc))
524122394Sharti		err(1, "%s", fname);
525122394Sharti	if (n != mboot.bootinst_size)
526122394Sharti		errx(1, "%s: short read", fname);
527122394Sharti#else
528122394Sharti	if (mboot.bootinst != NULL)
529122394Sharti		free(mboot.bootinst);
530122394Sharti	mboot.bootinst_size = secsize;
531122394Sharti	if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL)
532122394Sharti		errx(1, "unable to allocate boot block buffer");
533122394Sharti	memset(mboot.bootinst, 0, mboot.bootinst_size);
534122394Sharti	le16enc(&mboot.bootinst[DOSMAGICOFFSET], DOSMAGIC);
535122394Sharti#endif
536122394Sharti}
537122394Sharti
538122394Sharti
539122394Shartistatic void
540122394Shartiinit_sector0(unsigned long start)
541122394Sharti{
542122394Sharti	struct dos_partition *partp = &mboot.parts[0];
543122394Sharti
544122394Sharti	init_boot();
545122394Sharti
546122394Sharti	partp->dp_typ = DOSPTYP_386BSD;
547122394Sharti	partp->dp_flag = ACTIVE;
548122394Sharti	start = ((start + dos_sectors - 1) / dos_sectors) * dos_sectors;
549122394Sharti	if(start == 0)
550122394Sharti		start = dos_sectors;
551122394Sharti	partp->dp_start = start;
552122394Sharti	partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - start;
553122394Sharti
554122394Sharti	dos(partp);
555122394Sharti}
556122394Sharti
557122394Shartistatic void
558122394Shartichange_part(int i)
559122394Sharti{
560122394Sharti    struct dos_partition *partp = &mboot.parts[i - 1];
561122394Sharti
562122394Sharti    printf("The data for partition %d is:\n", i);
563122394Sharti    print_part(partp);
564122394Sharti
565122394Sharti    if (u_flag && ok("Do you want to change it?")) {
566122394Sharti	int tmp;
567122394Sharti
568122394Sharti	if (i_flag) {
569122394Sharti	    bzero(partp, sizeof (*partp));
570122394Sharti	    if (i == 1) {
571122394Sharti		init_sector0(1);
572122394Sharti		printf("\nThe static data for the slice 1 has been reinitialized to:\n");
573122394Sharti		print_part(partp);
574122394Sharti	    }
575122394Sharti	}
576122394Sharti
577122394Sharti	do {
578122394Sharti		Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp, 255);
579122394Sharti		Decimal("start", partp->dp_start, tmp, NO_DISK_SECTORS);
580122394Sharti		Decimal("size", partp->dp_size, tmp, NO_DISK_SECTORS);
581122394Sharti		if (!sanitize_partition(partp)) {
582122394Sharti			warnx("ERROR: failed to adjust; setting sysid to 0");
583122394Sharti			partp->dp_typ = 0;
584122394Sharti		}
585122394Sharti
586122394Sharti		if (ok("Explicitly specify beg/end address ?"))
587122394Sharti		{
588122394Sharti			int	tsec,tcyl,thd;
589122394Sharti			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
590122394Sharti			thd = partp->dp_shd;
591122394Sharti			tsec = DPSECT(partp->dp_ssect);
592122394Sharti			Decimal("beginning cylinder", tcyl, tmp, NO_TRACK_CYLINDERS);
593122394Sharti			Decimal("beginning head", thd, tmp, NO_TRACK_HEADS);
594122394Sharti			Decimal("beginning sector", tsec, tmp, NO_TRACK_SECTORS);
595122394Sharti			partp->dp_scyl = DOSCYL(tcyl);
596122394Sharti			partp->dp_ssect = DOSSECT(tsec,tcyl);
597122394Sharti			partp->dp_shd = thd;
598122394Sharti
599122394Sharti			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
600122394Sharti			thd = partp->dp_ehd;
601122394Sharti			tsec = DPSECT(partp->dp_esect);
602122394Sharti			Decimal("ending cylinder", tcyl, tmp, NO_TRACK_CYLINDERS);
603122394Sharti			Decimal("ending head", thd, tmp, NO_TRACK_HEADS);
604122394Sharti			Decimal("ending sector", tsec, tmp, NO_TRACK_SECTORS);
605122394Sharti			partp->dp_ecyl = DOSCYL(tcyl);
606122394Sharti			partp->dp_esect = DOSSECT(tsec,tcyl);
607122394Sharti			partp->dp_ehd = thd;
608122394Sharti		} else
609122394Sharti			dos(partp);
610122394Sharti
611122394Sharti		print_part(partp);
612122394Sharti	} while (!ok("Are we happy with this entry?"));
613122394Sharti    }
614122394Sharti}
615122394Sharti
616122394Shartistatic void
617122394Shartiprint_params()
618122394Sharti{
619122394Sharti	printf("parameters extracted from in-core disklabel are:\n");
620122394Sharti	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
621122394Sharti			,cyls,heads,sectors,cylsecs);
622122394Sharti	if (dos_cyls > 1023 || dos_heads > 255 || dos_sectors > 63)
623122394Sharti		printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
624122394Sharti	printf("parameters to be used for BIOS calculations are:\n");
625122394Sharti	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
626122394Sharti		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
627122394Sharti}
628122394Sharti
629122394Shartistatic void
630122394Shartichange_active(int which)
631122394Sharti{
632122394Sharti	struct dos_partition *partp = &mboot.parts[0];
633122394Sharti	int active, i, new, tmp;
634122394Sharti
635122394Sharti	active = -1;
636122394Sharti	for (i = 0; i < NDOSPART; i++) {
637122394Sharti		if ((partp[i].dp_flag & ACTIVE) == 0)
638122394Sharti			continue;
639122394Sharti		printf("Partition %d is marked active\n", i + 1);
640122394Sharti		if (active == -1)
641122394Sharti			active = i + 1;
642122394Sharti	}
643122394Sharti	if (a_flag && which != -1)
644122394Sharti		active = which;
645122394Sharti	else if (active == -1)
646122394Sharti		active = 1;
647122394Sharti
648122394Sharti	if (!ok("Do you want to change the active partition?"))
649122394Sharti		return;
650122394Shartisetactive:
651122394Sharti	do {
652122394Sharti		new = active;
653122394Sharti		Decimal("active partition", new, tmp, 0);
654122394Sharti		if (new < 1 || new > 4) {
655122394Sharti			printf("Active partition number must be in range 1-4."
656122394Sharti					"  Try again.\n");
657122394Sharti			goto setactive;
658122394Sharti		}
659122394Sharti		active = new;
660122394Sharti	} while (!ok("Are you happy with this choice"));
661124861Sharti	for (i = 0; i < NDOSPART; i++)
662124861Sharti		partp[i].dp_flag = 0;
663124861Sharti	if (active > 0 && active <= NDOSPART)
664122394Sharti		partp[active-1].dp_flag = ACTIVE;
665122394Sharti}
666122394Sharti
667122394Shartistatic void
668122394Shartichange_code()
669122394Sharti{
670122394Sharti	if (ok("Do you want to change the boot code?"))
671122394Sharti		init_boot();
672122394Sharti}
673122394Sharti
674122394Shartivoid
675122394Shartiget_params_to_use()
676122394Sharti{
677122394Sharti	int	tmp;
678122394Sharti	print_params();
679122394Sharti	if (ok("Do you want to change our idea of what BIOS thinks ?"))
680122394Sharti	{
681122394Sharti		do
682122394Sharti		{
683122394Sharti			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp, 0);
684122394Sharti			Decimal("BIOS's idea of #heads", dos_heads, tmp, 0);
685122394Sharti			Decimal("BIOS's idea of #sectors", dos_sectors, tmp, 0);
686122394Sharti			dos_cylsecs = dos_heads * dos_sectors;
687122394Sharti			print_params();
688122394Sharti		}
689122394Sharti		while(!ok("Are you happy with this choice"));
690122394Sharti	}
691122394Sharti}
692122394Sharti
693122394Sharti
694122394Sharti/***********************************************\
695122394Sharti* Change real numbers into strange dos numbers	*
696122394Sharti\***********************************************/
697122394Shartistatic void
698122394Shartidos(struct dos_partition *partp)
699122394Sharti{
700122394Sharti	int cy, sec;
701122394Sharti	u_int32_t end;
702124861Sharti
703124861Sharti	if (partp->dp_typ == 0 && partp->dp_start == 0 && partp->dp_size == 0) {
704124861Sharti		memcpy(partp, &mtpart, sizeof(*partp));
705124861Sharti		return;
706124861Sharti	}
707124861Sharti
708124861Sharti	/* Start c/h/s. */
709124861Sharti	partp->dp_shd = partp->dp_start % dos_cylsecs / dos_sectors;
710124861Sharti	cy = partp->dp_start / dos_cylsecs;
711124861Sharti	sec = partp->dp_start % dos_sectors + 1;
712122394Sharti	partp->dp_scyl = DOSCYL(cy);
713122394Sharti	partp->dp_ssect = DOSSECT(sec, cy);
714122394Sharti
715122394Sharti	/* End c/h/s. */
716122394Sharti	end = partp->dp_start + partp->dp_size - 1;
717122394Sharti	partp->dp_ehd = end % dos_cylsecs / dos_sectors;
718122394Sharti	cy = end / dos_cylsecs;
719122394Sharti	sec = end % dos_sectors + 1;
720122394Sharti	partp->dp_ecyl = DOSCYL(cy);
721122394Sharti	partp->dp_esect = DOSSECT(sec, cy);
722122394Sharti}
723122394Sharti
724122394Shartistatic int
725122394Shartiopen_disk(int flag)
726122394Sharti{
727122394Sharti	int rwmode;
728122394Sharti
729122394Sharti	/* Write mode if one of these flags are set. */
730124861Sharti	rwmode = (a_flag || I_flag || B_flag || flag);
731124861Sharti	fd = g_open(disk, rwmode);
732124861Sharti	/* If the mode fails, try read-only if we didn't. */
733122394Sharti	if (fd == -1 && errno == EPERM && rwmode)
734122394Sharti		fd = g_open(disk, 0);
735122394Sharti	if (fd == -1 && errno == ENXIO)
736122394Sharti		return -2;
737122394Sharti	if (fd == -1) {
738122394Sharti		warnx("can't open device %s", disk);
739122394Sharti		return -1;
740122394Sharti	}
741122394Sharti	if (get_params() == -1) {
742122394Sharti		warnx("can't get disk parameters on %s", disk);
743122394Sharti		return -1;
744122394Sharti	}
745122394Sharti	return fd;
746124861Sharti}
747124861Sharti
748122394Shartistatic ssize_t
749122394Shartiread_disk(off_t sector, void *buf)
750122394Sharti{
751122394Sharti
752122394Sharti	lseek(fd, (sector * 512), 0);
753122394Sharti	if (secsize == 0)
754122394Sharti		for (secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE;
755122394Sharti		     secsize *= 2) {
756122394Sharti			/* try the read */
757122394Sharti			int size = read(fd, buf, secsize);
758122394Sharti			if (size == secsize)
759122394Sharti				/* it worked so return */
760122394Sharti				return secsize;
761122394Sharti		}
762122394Sharti	else
763122394Sharti		return read(fd, buf, secsize);
764122394Sharti
765122394Sharti	/* we failed to read at any of the sizes */
766122394Sharti	return -1;
767122394Sharti}
768122394Sharti
769122394Shartistatic int
770122394Shartiwrite_disk(off_t sector, void *buf)
771122394Sharti{
772122394Sharti	int error;
773122394Sharti	struct gctl_req *grq;
774122394Sharti	const char *errmsg;
775122394Sharti	char fbuf[BUFSIZ], *pname;
776122394Sharti	int i, fdw;
777122394Sharti
778122394Sharti	grq = gctl_get_handle();
779122394Sharti	gctl_ro_param(grq, "verb", -1, "write MBR");
780122394Sharti	gctl_ro_param(grq, "class", -1, "MBR");
781122394Sharti	pname = g_providername(fd);
782122394Sharti	if (pname == NULL) {
783122394Sharti		warn("Error getting providername for %s", disk);
784122394Sharti		return (-1);
785122394Sharti	}
786122394Sharti	gctl_ro_param(grq, "geom", -1, pname);
787122394Sharti	gctl_ro_param(grq, "data", secsize, buf);
788122394Sharti	errmsg = gctl_issue(grq);
789122394Sharti	free(pname);
790122394Sharti	if (errmsg == NULL) {
791122394Sharti		gctl_free(grq);
792122394Sharti		return(0);
793122394Sharti	}
794122394Sharti	if (!q_flag)	/* GEOM errors are benign, not all devices supported */
795122394Sharti		warnx("%s", errmsg);
796122394Sharti	gctl_free(grq);
797122394Sharti
798122394Sharti	error = pwrite(fd, buf, secsize, (sector * 512));
799122394Sharti	if (error == secsize)
800122394Sharti		return (0);
801122394Sharti
802122394Sharti	for (i = 1; i < 5; i++) {
803122394Sharti		sprintf(fbuf, "%ss%d", disk, i);
804122394Sharti		fdw = open(fbuf, O_RDWR, 0);
805122394Sharti		if (fdw < 0)
806122394Sharti			continue;
807122394Sharti		error = ioctl(fdw, DIOCSMBR, buf);
808122394Sharti		close(fdw);
809122394Sharti		if (error == 0)
810122394Sharti			return (0);
811122394Sharti	}
812122394Sharti	warnx("Failed to write sector zero");
813122394Sharti	return(EINVAL);
814122394Sharti}
815122394Sharti
816122394Shartistatic int
817122394Shartiget_params()
818122394Sharti{
819122394Sharti	int error;
820122394Sharti	u_int u;
821122394Sharti	off_t o;
822122394Sharti
823122394Sharti	error = ioctl(fd, DIOCGFWSECTORS, &u);
824122394Sharti	if (error == 0)
825122394Sharti		sectors = dos_sectors = u;
826122394Sharti	else
827122394Sharti		sectors = dos_sectors = 63;
828122394Sharti
829122394Sharti	error = ioctl(fd, DIOCGFWHEADS, &u);
830122394Sharti	if (error == 0)
831122394Sharti		heads = dos_heads = u;
832122394Sharti	else
833122394Sharti		heads = dos_heads = 255;
834122394Sharti
835122394Sharti	dos_cylsecs = cylsecs = heads * sectors;
836122394Sharti	disksecs = cyls * heads * sectors;
837122394Sharti
838122394Sharti	u = g_sectorsize(fd);
839122394Sharti	if (u <= 0)
840122394Sharti		return (-1);
841122394Sharti
842122394Sharti	o = g_mediasize(fd);
843122394Sharti	if (o < 0)
844122394Sharti		return (-1);
845122394Sharti	disksecs = o / u;
846128237Sharti	cyls = dos_cyls = o / (u * dos_heads * dos_sectors);
847128237Sharti
848122394Sharti	return (disksecs);
849122394Sharti}
850128237Sharti
851122394Shartistatic int
852128237Shartiread_s0()
853128237Sharti{
854122394Sharti	int i;
855122394Sharti
856122394Sharti	mboot.bootinst_size = secsize;
857128237Sharti	if (mboot.bootinst != NULL)
858128237Sharti		free(mboot.bootinst);
859122394Sharti	if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) {
860122394Sharti		warnx("unable to allocate buffer to read fdisk "
861128237Sharti		      "partition table");
862122394Sharti		return -1;
863122394Sharti	}
864122394Sharti	if (read_disk(0, mboot.bootinst) == -1) {
865122394Sharti		warnx("can't read fdisk partition table");
866128237Sharti		return -1;
867122394Sharti	}
868122394Sharti	if (le16dec(&mboot.bootinst[DOSMAGICOFFSET]) != DOSMAGIC) {
869122394Sharti		warnx("invalid fdisk partition table found");
870122394Sharti		/* So should we initialize things */
871122394Sharti		return -1;
872128237Sharti	}
873128237Sharti	for (i = 0; i < NDOSPART; i++)
874128237Sharti		dos_partition_dec(
875128237Sharti		    &mboot.bootinst[DOSPARTOFF + i * DOSPARTSIZE],
876128237Sharti		    &mboot.parts[i]);
877128237Sharti	return 0;
878128237Sharti}
879128237Sharti
880128237Shartistatic int
881128237Shartiwrite_s0()
882128237Sharti{
883128237Sharti	int	sector, i;
884122394Sharti
885122394Sharti	if (iotest) {
886122394Sharti		print_s0();
887122394Sharti		return 0;
888122394Sharti	}
889122394Sharti	for(i = 0; i < NDOSPART; i++)
890122394Sharti		dos_partition_enc(&mboot.bootinst[DOSPARTOFF + i * DOSPARTSIZE],
891122394Sharti		    &mboot.parts[i]);
892122394Sharti	le16enc(&mboot.bootinst[DOSMAGICOFFSET], DOSMAGIC);
893122394Sharti	for(sector = 0; sector < mboot.bootinst_size / secsize; sector++)
894122394Sharti		if (write_disk(sector,
895122394Sharti			       &mboot.bootinst[sector * secsize]) == -1) {
896122394Sharti			warn("can't write fdisk partition table");
897122394Sharti			return -1;
898122394Sharti		}
899122394Sharti	return(0);
900122394Sharti}
901122394Sharti
902122394Sharti
903122394Shartistatic int
904122394Shartiok(const char *str)
905122394Sharti{
906122394Sharti	printf("%s [n] ", str);
907122394Sharti	fflush(stdout);
908122394Sharti	if (fgets(lbuf, LBUF, stdin) == NULL)
909122394Sharti		exit(1);
910122394Sharti	lbuf[strlen(lbuf)-1] = 0;
911122394Sharti
912122394Sharti	if (*lbuf &&
913122394Sharti		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
914122394Sharti		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
915122394Sharti		return 1;
916122394Sharti	else
917122394Sharti		return 0;
918122394Sharti}
919122394Sharti
920122394Shartistatic int
921122394Shartidecimal(const char *str, int *num, int deflt, uint32_t maxval)
922122394Sharti{
923122394Sharti	long long acc = 0;
924122394Sharti	int c;
925122394Sharti	char *cp;
926122394Sharti
927122394Sharti	while (1) {
928122394Sharti		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
929122394Sharti		fflush(stdout);
930122394Sharti		if (fgets(lbuf, LBUF, stdin) == NULL)
931122394Sharti			exit(1);
932122394Sharti		lbuf[strlen(lbuf)-1] = 0;
933122394Sharti
934122394Sharti		if (!*lbuf)
935122394Sharti			return 0;
936122394Sharti
937122394Sharti		cp = lbuf;
938122394Sharti		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
939122394Sharti		if (!c)
940122394Sharti			return 0;
941122394Sharti		while ((c = *cp++)) {
942122394Sharti			if (c <= '9' && c >= '0') {
943122394Sharti				if (acc <= maxval || maxval == 0)
944122394Sharti					acc = acc * 10 + c - '0';
945122394Sharti			} else
946122394Sharti				break;
947122394Sharti		}
948122394Sharti		if (c == ' ' || c == '\t')
949122394Sharti			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
950122394Sharti		if (!c) {
951122394Sharti			if (maxval > 0 && acc > maxval) {
952122394Sharti				acc = maxval;
953122394Sharti				printf("%s exceeds maximum value allowed for "
954122394Sharti				  "this field. The value has been reduced "
955122394Sharti				  "to %lld\n", lbuf, acc);
956122394Sharti			}
957122394Sharti			*num = acc;
958122394Sharti			return 1;
959122394Sharti		} else
960122394Sharti			printf("%s is an invalid decimal number.  Try again.\n",
961122394Sharti				lbuf);
962122394Sharti	}
963122394Sharti
964122394Sharti}
965122394Sharti
966122394Sharti
967122394Shartistatic void
968122394Shartiparse_config_line(char *line, CMD *command)
969122394Sharti{
970122394Sharti    char	*cp, *end;
971122394Sharti
972122394Sharti    cp = line;
973122394Sharti    while (1) {
974122394Sharti	memset(command, 0, sizeof(*command));
975122394Sharti
976122394Sharti	while (isspace(*cp)) ++cp;
977122394Sharti	if (*cp == '\0' || *cp == '#')
978122394Sharti	    break;
979122394Sharti	command->cmd = *cp++;
980122394Sharti
981122394Sharti	/*
982122394Sharti	 * Parse args
983122394Sharti	 */
984122394Sharti	    while (1) {
985122394Sharti	    while (isspace(*cp)) ++cp;
986122394Sharti	    if (*cp == '\0')
987122394Sharti		break;		/* eol */
988122394Sharti	    if (*cp == '#')
989122394Sharti		break;		/* found comment */
990122394Sharti	    if (isalpha(*cp))
991122394Sharti		command->args[command->n_args].argtype = *cp++;
992122394Sharti	    end = NULL;
993122394Sharti	    command->args[command->n_args].arg_val = strtoul(cp, &end, 0);
994122394Sharti 	    if (cp == end || (!isspace(*end) && *end != '\0')) {
995122394Sharti 		char ch;
996122394Sharti 		end = cp;
997122394Sharti 		while (!isspace(*end) && *end != '\0') ++end;
998122394Sharti 		ch = *end; *end = '\0';
999122394Sharti 		command->args[command->n_args].arg_str = strdup(cp);
1000122394Sharti 		*end = ch;
1001122394Sharti 	    } else
1002122394Sharti 		command->args[command->n_args].arg_str = NULL;
1003122394Sharti	    cp = end;
1004122394Sharti	    command->n_args++;
1005122394Sharti	}
1006122394Sharti	break;
1007122394Sharti    }
1008122394Sharti}
1009122394Sharti
1010122394Sharti
1011122394Shartistatic int
1012122394Shartiprocess_geometry(CMD *command)
1013122394Sharti{
1014122394Sharti    int		status = 1, i;
1015122394Sharti
1016122394Sharti    while (1) {
1017122394Sharti	geom_processed = 1;
1018122394Sharti	    if (part_processed) {
1019122394Sharti	    warnx(
1020122394Sharti	"ERROR line %d: the geometry specification line must occur before\n\
1021122394Sharti    all partition specifications",
1022122394Sharti		    current_line_number);
1023122394Sharti	    status = 0;
1024122394Sharti	    break;
1025122394Sharti	}
1026122394Sharti	    if (command->n_args != 3) {
1027122394Sharti	    warnx("ERROR line %d: incorrect number of geometry args",
1028122394Sharti		    current_line_number);
1029122394Sharti	    status = 0;
1030122394Sharti	    break;
1031122394Sharti	}
1032122394Sharti	    dos_cyls = 0;
1033122394Sharti	    dos_heads = 0;
1034122394Sharti	    dos_sectors = 0;
1035122394Sharti	    for (i = 0; i < 3; ++i) {
1036122394Sharti		    switch (command->args[i].argtype) {
1037122394Sharti	    case 'c':
1038122394Sharti		dos_cyls = command->args[i].arg_val;
1039122394Sharti		break;
1040122394Sharti	    case 'h':
1041122394Sharti		dos_heads = command->args[i].arg_val;
1042122394Sharti		break;
1043122394Sharti	    case 's':
1044122394Sharti		dos_sectors = command->args[i].arg_val;
1045122394Sharti		break;
1046122394Sharti	    default:
1047122394Sharti		warnx(
1048122394Sharti		"ERROR line %d: unknown geometry arg type: '%c' (0x%02x)",
1049122394Sharti			current_line_number, command->args[i].argtype,
1050122394Sharti			command->args[i].argtype);
1051122394Sharti		status = 0;
1052122394Sharti		break;
1053122394Sharti	    }
1054122394Sharti	}
1055122394Sharti	if (status == 0)
1056122394Sharti	    break;
1057122394Sharti
1058122394Sharti	dos_cylsecs = dos_heads * dos_sectors;
1059124861Sharti
1060124861Sharti	/*
1061216294Ssyrinx	 * Do sanity checks on parameter values
1062216294Ssyrinx	 */
1063216294Ssyrinx	    if (dos_cyls == 0) {
1064216294Ssyrinx	    warnx("ERROR line %d: number of cylinders not specified",
1065216294Ssyrinx		    current_line_number);
1066216294Ssyrinx	    status = 0;
1067216294Ssyrinx	}
1068216294Ssyrinx	    if (dos_cyls > 1024) {
1069216294Ssyrinx	    warnx(
1070216294Ssyrinx	"WARNING line %d: number of cylinders (%d) may be out-of-range\n\
1071216294Ssyrinx    (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\
1072216294Ssyrinx    is dedicated to FreeBSD)",
1073216294Ssyrinx		    current_line_number, dos_cyls);
1074216294Ssyrinx	}
1075216294Ssyrinx
1076216294Ssyrinx	    if (dos_heads == 0) {
1077216294Ssyrinx	    warnx("ERROR line %d: number of heads not specified",
1078216294Ssyrinx		    current_line_number);
1079216294Ssyrinx	    status = 0;
1080216294Ssyrinx	    } else if (dos_heads > 256) {
1081216294Ssyrinx	    warnx("ERROR line %d: number of heads must be within (1-256)",
1082216294Ssyrinx		    current_line_number);
1083216294Ssyrinx	    status = 0;
1084216294Ssyrinx	}
1085216294Ssyrinx
1086216294Ssyrinx	    if (dos_sectors == 0) {
1087216294Ssyrinx	    warnx("ERROR line %d: number of sectors not specified",
1088216294Ssyrinx		    current_line_number);
1089216294Ssyrinx	    status = 0;
1090216294Ssyrinx	    } else if (dos_sectors > 63) {
1091216294Ssyrinx	    warnx("ERROR line %d: number of sectors must be within (1-63)",
1092216294Ssyrinx		    current_line_number);
1093216294Ssyrinx	    status = 0;
1094216294Ssyrinx	}
1095216294Ssyrinx
1096216294Ssyrinx	break;
1097216294Ssyrinx    }
1098216294Ssyrinx    return (status);
1099216294Ssyrinx}
1100216294Ssyrinx
1101216294Ssyrinxstatic u_int32_t
1102216294Ssyrinxstr2sectors(const char *str)
1103216294Ssyrinx{
1104216294Ssyrinx	char *end;
1105216294Ssyrinx	unsigned long val;
1106216294Ssyrinx
1107216294Ssyrinx	val = strtoul(str, &end, 0);
1108216294Ssyrinx	if (str == end || *end == '\0') {
1109216294Ssyrinx		warnx("ERROR line %d: unexpected size: \'%s\'",
1110216294Ssyrinx		    current_line_number, str);
1111216294Ssyrinx		return NO_DISK_SECTORS;
1112216294Ssyrinx	}
1113216294Ssyrinx
1114216294Ssyrinx	if (*end == 'K')
1115216294Ssyrinx		val *= 1024UL / secsize;
1116216294Ssyrinx	else if (*end == 'M')
1117216294Ssyrinx		val *= 1024UL * 1024UL / secsize;
1118216294Ssyrinx	else if (*end == 'G')
1119216294Ssyrinx		val *= 1024UL * 1024UL * 1024UL / secsize;
1120216294Ssyrinx	else {
1121216294Ssyrinx		warnx("ERROR line %d: unexpected modifier: %c "
1122216294Ssyrinx		    "(not K/M/G)", current_line_number, *end);
1123216294Ssyrinx		return NO_DISK_SECTORS;
1124216294Ssyrinx	}
1125216294Ssyrinx
1126216294Ssyrinx	return val;
1127216294Ssyrinx}
1128216294Ssyrinx
1129216294Ssyrinxstatic int
1130216294Ssyrinxprocess_partition(CMD *command)
1131216294Ssyrinx{
1132216294Ssyrinx    int				status = 0, partition;
1133216294Ssyrinx    u_int32_t			prev_head_boundary, prev_cyl_boundary;
1134216294Ssyrinx    u_int32_t			adj_size, max_end;
1135216294Ssyrinx    struct dos_partition	*partp;
1136216294Ssyrinx
1137216294Ssyrinx	while (1) {
1138216294Ssyrinx	part_processed = 1;
1139216294Ssyrinx		if (command->n_args != 4) {
1140216294Ssyrinx	    warnx("ERROR line %d: incorrect number of partition args",
1141216294Ssyrinx		    current_line_number);
1142216294Ssyrinx	    break;
1143216294Ssyrinx	}
1144216294Ssyrinx	partition = command->args[0].arg_val;
1145216294Ssyrinx		if (partition < 1 || partition > 4) {
1146216294Ssyrinx	    warnx("ERROR line %d: invalid partition number %d",
1147216294Ssyrinx		    current_line_number, partition);
1148216294Ssyrinx	    break;
1149216294Ssyrinx	}
1150216294Ssyrinx	partp = &mboot.parts[partition - 1];
1151216294Ssyrinx	bzero(partp, sizeof (*partp));
1152216294Ssyrinx	partp->dp_typ = command->args[1].arg_val;
1153216294Ssyrinx	if (command->args[2].arg_str != NULL) {
1154216294Ssyrinx		if (strcmp(command->args[2].arg_str, "*") == 0) {
1155216294Ssyrinx			int i;
1156216294Ssyrinx			partp->dp_start = dos_sectors;
1157216294Ssyrinx			for (i = 1; i < partition; i++) {
1158124861Sharti    				struct dos_partition *prev_partp;
1159124861Sharti				prev_partp = ((struct dos_partition *)
1160124861Sharti				    &mboot.parts) + i - 1;
1161124861Sharti				if (prev_partp->dp_typ != 0)
1162124861Sharti					partp->dp_start = prev_partp->dp_start +
1163124861Sharti					    prev_partp->dp_size;
1164124861Sharti			}
1165124861Sharti			if (partp->dp_start % dos_sectors != 0) {
1166124861Sharti		    		prev_head_boundary = partp->dp_start /
1167124861Sharti				    dos_sectors * dos_sectors;
1168124861Sharti		    		partp->dp_start = prev_head_boundary +
1169124861Sharti				    dos_sectors;
1170124861Sharti			}
1171124861Sharti		} else {
1172124861Sharti			partp->dp_start = str2sectors(command->args[2].arg_str);
1173124861Sharti			if (partp->dp_start == NO_DISK_SECTORS)
1174124861Sharti				break;
1175124861Sharti		}
1176124861Sharti	} else
1177124861Sharti		partp->dp_start = command->args[2].arg_val;
1178124861Sharti
1179124861Sharti	if (command->args[3].arg_str != NULL) {
1180124861Sharti		if (strcmp(command->args[3].arg_str, "*") == 0)
1181124861Sharti			partp->dp_size = ((disksecs / dos_cylsecs) *
1182124861Sharti			    dos_cylsecs) - partp->dp_start;
1183124861Sharti		else {
1184124861Sharti			partp->dp_size = str2sectors(command->args[3].arg_str);
1185124861Sharti			if (partp->dp_size == NO_DISK_SECTORS)
1186124861Sharti				break;
1187124861Sharti		}
1188124861Sharti		prev_cyl_boundary = ((partp->dp_start + partp->dp_size) /
1189124861Sharti		    dos_cylsecs) * dos_cylsecs;
1190124861Sharti		if (prev_cyl_boundary > partp->dp_start)
1191124861Sharti			partp->dp_size = prev_cyl_boundary - partp->dp_start;
1192124861Sharti	} else
1193124861Sharti		partp->dp_size = command->args[3].arg_val;
1194124861Sharti
1195124861Sharti	max_end = partp->dp_start + partp->dp_size;
1196124861Sharti
1197124861Sharti	if (partp->dp_typ == 0) {
1198124861Sharti	    /*
1199124861Sharti	     * Get out, the partition is marked as unused.
1200124861Sharti	     */
1201124861Sharti	    /*
1202124861Sharti	     * Insure that it's unused.
1203124861Sharti	     */
1204124861Sharti	    bzero(partp, sizeof(*partp));
1205124861Sharti	    status = 1;
1206124861Sharti	    break;
1207124861Sharti	}
1208124861Sharti
1209124861Sharti	/*
1210124861Sharti	 * Adjust start upwards, if necessary, to fall on a head boundary.
1211124861Sharti	 */
1212124861Sharti		if (partp->dp_start % dos_sectors != 0) {
1213124861Sharti	    prev_head_boundary = partp->dp_start / dos_sectors * dos_sectors;
1214124861Sharti	    if (max_end < dos_sectors ||
1215124861Sharti			    prev_head_boundary > max_end - dos_sectors) {
1216124861Sharti		/*
1217124861Sharti		 * Can't go past end of partition
1218124861Sharti		 */
1219124861Sharti		warnx(
1220124861Sharti	"ERROR line %d: unable to adjust start of partition %d to fall on\n\
1221124861Sharti    a head boundary",
1222124861Sharti			current_line_number, partition);
1223124861Sharti		break;
1224124861Sharti	    }
1225124861Sharti	    warnx(
1226124861Sharti	"WARNING: adjusting start offset of partition %d\n\
1227124861Sharti    from %u to %u, to fall on a head boundary",
1228124861Sharti		    partition, (u_int)partp->dp_start,
1229124861Sharti		    (u_int)(prev_head_boundary + dos_sectors));
1230124861Sharti	    partp->dp_start = prev_head_boundary + dos_sectors;
1231124861Sharti	}
1232
1233	/*
1234	 * Adjust size downwards, if necessary, to fall on a cylinder
1235	 * boundary.
1236	 */
1237	prev_cyl_boundary =
1238	    ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs;
1239	if (prev_cyl_boundary > partp->dp_start)
1240	    adj_size = prev_cyl_boundary - partp->dp_start;
1241		else {
1242	    warnx(
1243	"ERROR: could not adjust partition to start on a head boundary\n\
1244    and end on a cylinder boundary.");
1245	    return (0);
1246	}
1247		if (adj_size != partp->dp_size) {
1248	    warnx(
1249	"WARNING: adjusting size of partition %d from %u to %u\n\
1250    to end on a cylinder boundary",
1251		    partition, (u_int)partp->dp_size, (u_int)adj_size);
1252	    partp->dp_size = adj_size;
1253	}
1254		if (partp->dp_size == 0) {
1255	    warnx("ERROR line %d: size of partition %d is zero",
1256		    current_line_number, partition);
1257	    break;
1258	}
1259
1260	dos(partp);
1261	status = 1;
1262	break;
1263    }
1264    return (status);
1265}
1266
1267
1268static int
1269process_active(CMD *command)
1270{
1271    int				status = 0, partition, i;
1272    struct dos_partition	*partp;
1273
1274	while (1) {
1275	active_processed = 1;
1276		if (command->n_args != 1) {
1277	    warnx("ERROR line %d: incorrect number of active args",
1278		    current_line_number);
1279	    status = 0;
1280	    break;
1281	}
1282	partition = command->args[0].arg_val;
1283		if (partition < 1 || partition > 4) {
1284	    warnx("ERROR line %d: invalid partition number %d",
1285		    current_line_number, partition);
1286	    break;
1287	}
1288	/*
1289	 * Reset active partition
1290	 */
1291	partp = mboot.parts;
1292	for (i = 0; i < NDOSPART; i++)
1293	    partp[i].dp_flag = 0;
1294	partp[partition-1].dp_flag = ACTIVE;
1295
1296	status = 1;
1297	break;
1298    }
1299    return (status);
1300}
1301
1302
1303static int
1304process_line(char *line)
1305{
1306    CMD		command;
1307    int		status = 1;
1308
1309	while (1) {
1310	parse_config_line(line, &command);
1311		switch (command.cmd) {
1312	case 0:
1313	    /*
1314	     * Comment or blank line
1315	     */
1316	    break;
1317	case 'g':
1318	    /*
1319	     * Set geometry
1320	     */
1321	    status = process_geometry(&command);
1322	    break;
1323	case 'p':
1324	    status = process_partition(&command);
1325	    break;
1326	case 'a':
1327	    status = process_active(&command);
1328	    break;
1329	default:
1330	    status = 0;
1331	    break;
1332	}
1333	break;
1334    }
1335    return (status);
1336}
1337
1338
1339static int
1340read_config(char *config_file)
1341{
1342    FILE	*fp = NULL;
1343    int		status = 1;
1344    char	buf[1010];
1345
1346	while (1) {
1347		if (strcmp(config_file, "-") != 0) {
1348	    /*
1349	     * We're not reading from stdin
1350	     */
1351			if ((fp = fopen(config_file, "r")) == NULL) {
1352		status = 0;
1353		break;
1354	    }
1355		} else {
1356	    fp = stdin;
1357	}
1358	current_line_number = 0;
1359		while (!feof(fp)) {
1360	    if (fgets(buf, sizeof(buf), fp) == NULL)
1361		break;
1362	    ++current_line_number;
1363	    status = process_line(buf);
1364	    if (status == 0)
1365		break;
1366	    }
1367	break;
1368    }
1369	if (fp) {
1370	/*
1371	 * It doesn't matter if we're reading from stdin, as we've reached EOF
1372	 */
1373	fclose(fp);
1374    }
1375    return (status);
1376}
1377
1378
1379static void
1380reset_boot(void)
1381{
1382    int				i;
1383    struct dos_partition	*partp;
1384
1385    init_boot();
1386    for (i = 0; i < 4; ++i) {
1387	partp = &mboot.parts[i];
1388	bzero(partp, sizeof(*partp));
1389    }
1390}
1391
1392static int
1393sanitize_partition(struct dos_partition *partp)
1394{
1395    u_int32_t			prev_head_boundary, prev_cyl_boundary;
1396    u_int32_t			max_end, size, start;
1397
1398    start = partp->dp_start;
1399    size = partp->dp_size;
1400    max_end = start + size;
1401    /* Only allow a zero size if the partition is being marked unused. */
1402    if (size == 0) {
1403	if (start == 0 && partp->dp_typ == 0)
1404	    return (1);
1405	warnx("ERROR: size of partition is zero");
1406	return (0);
1407    }
1408    /* Return if no adjustment is necessary. */
1409    if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0)
1410	return (1);
1411
1412    if (start == 0) {
1413	    warnx("WARNING: partition overlaps with partition table");
1414	    if (ok("Correct this automatically?"))
1415		    start = dos_sectors;
1416    }
1417    if (start % dos_sectors != 0)
1418	warnx("WARNING: partition does not start on a head boundary");
1419    if ((start  +size) % dos_sectors != 0)
1420	warnx("WARNING: partition does not end on a cylinder boundary");
1421    warnx("WARNING: this may confuse the BIOS or some operating systems");
1422    if (!ok("Correct this automatically?"))
1423	return (1);
1424
1425    /*
1426     * Adjust start upwards, if necessary, to fall on a head boundary.
1427     */
1428    if (start % dos_sectors != 0) {
1429	prev_head_boundary = start / dos_sectors * dos_sectors;
1430	if (max_end < dos_sectors ||
1431	    prev_head_boundary >= max_end - dos_sectors) {
1432	    /*
1433	     * Can't go past end of partition
1434	     */
1435	    warnx(
1436    "ERROR: unable to adjust start of partition to fall on a head boundary");
1437	    return (0);
1438        }
1439	start = prev_head_boundary + dos_sectors;
1440    }
1441
1442    /*
1443     * Adjust size downwards, if necessary, to fall on a cylinder
1444     * boundary.
1445     */
1446    prev_cyl_boundary = ((start + size) / dos_cylsecs) * dos_cylsecs;
1447    if (prev_cyl_boundary > start)
1448	size = prev_cyl_boundary - start;
1449    else {
1450	warnx("ERROR: could not adjust partition to start on a head boundary\n\
1451    and end on a cylinder boundary.");
1452	return (0);
1453    }
1454
1455    /* Finally, commit any changes to partp and return. */
1456    if (start != partp->dp_start) {
1457	warnx("WARNING: adjusting start offset of partition to %u",
1458	    (u_int)start);
1459	partp->dp_start = start;
1460    }
1461    if (size != partp->dp_size) {
1462	warnx("WARNING: adjusting size of partition to %u", (u_int)size);
1463	partp->dp_size = size;
1464    }
1465
1466    return (1);
1467}
1468
1469/*
1470 * Try figuring out the root device's canonical disk name.
1471 * The following choices are considered:
1472 *   /dev/ad0s1a     => /dev/ad0
1473 *   /dev/da0a       => /dev/da0
1474 *   /dev/vinum/root => /dev/vinum/root
1475 * A ".eli" part is removed if it exists (see geli(8)).
1476 * A ".journal" ending is removed if it exists (see gjournal(8)).
1477 */
1478static char *
1479get_rootdisk(void)
1480{
1481	struct statfs rootfs;
1482	regex_t re;
1483#define NMATCHES 2
1484	regmatch_t rm[NMATCHES];
1485	char dev[PATH_MAX], *s;
1486	int rv;
1487
1488	if (statfs("/", &rootfs) == -1)
1489		err(1, "statfs(\"/\")");
1490
1491	if ((rv = regcomp(&re, "^(/dev/[a-z/]+[0-9]*)([sp][0-9]+)?[a-h]?(\\.journal)?$",
1492		    REG_EXTENDED)) != 0)
1493		errx(1, "regcomp() failed (%d)", rv);
1494	strlcpy(dev, rootfs.f_mntfromname, sizeof (dev));
1495	if ((s = strstr(dev, ".eli")) != NULL)
1496	    memmove(s, s+4, strlen(s + 4) + 1);
1497
1498	if ((rv = regexec(&re, dev, NMATCHES, rm, 0)) != 0)
1499		errx(1,
1500"mounted root fs resource doesn't match expectations (regexec returned %d)",
1501		    rv);
1502	if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL)
1503		errx(1, "out of memory");
1504	memcpy(s, rootfs.f_mntfromname + rm[1].rm_so,
1505	    rm[1].rm_eo - rm[1].rm_so);
1506	s[rm[1].rm_eo - rm[1].rm_so] = 0;
1507
1508	return s;
1509}
1510