fdisk.c revision 81164
18871Srgrimes/*
24Srgrimes * Mach Operating System
34Srgrimes * Copyright (c) 1992 Carnegie Mellon University
44Srgrimes * All Rights Reserved.
58871Srgrimes *
64Srgrimes * Permission to use, copy, modify and distribute this software and its
74Srgrimes * documentation is hereby granted, provided that both the copyright
84Srgrimes * notice and this permission notice appear in all copies of the
94Srgrimes * software, derivative works or modified versions, and any portions
104Srgrimes * thereof, and that both notices appear in supporting documentation.
118871Srgrimes *
124Srgrimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
134Srgrimes * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
144Srgrimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
158871Srgrimes *
164Srgrimes * Carnegie Mellon requests users of this software to return to
178871Srgrimes *
184Srgrimes *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
194Srgrimes *  School of Computer Science
204Srgrimes *  Carnegie Mellon University
214Srgrimes *  Pittsburgh PA 15213-3890
228871Srgrimes *
234Srgrimes * any improvements or extensions that they make and grant Carnegie Mellon
244Srgrimes * the rights to redistribute these changes.
254Srgrimes */
264Srgrimes
2737415Scharnier#ifndef lint
2837415Scharnierstatic const char rcsid[] =
2950476Speter  "$FreeBSD: head/sbin/fdisk/fdisk.c 81164 2001-08-05 16:24:13Z iedowse $";
3037415Scharnier#endif /* not lint */
3137415Scharnier
324Srgrimes#include <sys/disklabel.h>
3379681Sjoerg#include <sys/param.h>
3437415Scharnier#include <sys/stat.h>
3579681Sjoerg#include <sys/mount.h>
3637415Scharnier#include <ctype.h>
3737415Scharnier#include <fcntl.h>
3837415Scharnier#include <err.h>
3937415Scharnier#include <errno.h>
4079681Sjoerg#include <paths.h>
4179681Sjoerg#include <regex.h>
424Srgrimes#include <stdio.h>
4337415Scharnier#include <stdlib.h>
4416561Salex#include <string.h>
4516561Salex#include <unistd.h>
464Srgrimes
474Srgrimesint iotest;
484Srgrimes
494Srgrimes#define LBUF 100
504Srgrimesstatic char lbuf[LBUF];
514Srgrimes
5263027Sjhb#define MBRSIGOFF	510
5363027Sjhb
544Srgrimes/*
554Srgrimes *
564Srgrimes * Ported to 386bsd by Julian Elischer  Thu Oct 15 20:26:46 PDT 1992
574Srgrimes *
584Srgrimes * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
594Srgrimes *	Copyright (c) 1989	Robert. V. Baron
604Srgrimes *	Created.
614Srgrimes */
624Srgrimes
634Srgrimes#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp
644Srgrimes#define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp
654Srgrimes#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); }
664Srgrimes
674Srgrimes#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
684Srgrimes
6920061Ssos#define MAX_SEC_SIZE 2048	/* maximum section size that is supported */
7020061Ssos#define MIN_SEC_SIZE 512	/* the sector size to start sensing at */
7120061Ssosint secsize = 0;		/* the sensed sector size */
724Srgrimes
7379681Sjoergchar *disk;
7410514Sjoerg
754Srgrimesstruct disklabel disklabel;		/* disk parameters */
764Srgrimes
774Srgrimesint cyls, sectors, heads, cylsecs, disksecs;
784Srgrimes
794Srgrimesstruct mboot
804Srgrimes{
8137415Scharnier	unsigned char padding[2]; /* force the longs to be long aligned */
8263027Sjhb  	unsigned char *bootinst;  /* boot code */
8363027Sjhb  	off_t bootinst_size;
844Srgrimes	struct	dos_partition parts[4];
854Srgrimes};
8663027Sjhbstruct mboot mboot = {{0}, NULL, 0};
874Srgrimes
884Srgrimes#define ACTIVE 0x80
894Srgrimes#define BOOT_MAGIC 0xAA55
904Srgrimes
914Srgrimesint dos_cyls;
924Srgrimesint dos_heads;
934Srgrimesint dos_sectors;
944Srgrimesint dos_cylsecs;
954Srgrimes
964Srgrimes#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
974Srgrimes#define DOSCYL(c)	(c & 0xff)
984Srgrimesstatic int partition = -1;
994Srgrimes
1004Srgrimes
10119459Sjkh#define MAX_ARGS	10
10219459Sjkh
10319459Sjkhstatic int	current_line_number;
10419459Sjkh
10519459Sjkhstatic int	geom_processed = 0;
10619459Sjkhstatic int	part_processed = 0;
10719459Sjkhstatic int	active_processed = 0;
10819459Sjkh
10919459Sjkh
11019459Sjkhtypedef struct cmd {
11119459Sjkh    char		cmd;
11219459Sjkh    int			n_args;
11319459Sjkh    struct arg {
11419459Sjkh	char	argtype;
11519459Sjkh	int	arg_val;
11619459Sjkh    }			args[MAX_ARGS];
11719459Sjkh} CMD;
11819459Sjkh
11919459Sjkh
12048282Srnordierstatic int B_flag  = 0;		/* replace boot code */
12157896Simpstatic int I_flag  = 0;		/* use entire disk for FreeBSD */
1224Srgrimesstatic int a_flag  = 0;		/* set active partition */
12348282Srnordierstatic char *b_flag = NULL;	/* path to boot code */
1244Srgrimesstatic int i_flag  = 0;		/* replace partition data */
1254Srgrimesstatic int u_flag  = 0;		/* update partition data */
12657896Simpstatic int s_flag  = 0;		/* Print a summary and exit */
12719459Sjkhstatic int t_flag  = 0;		/* test only, if f_flag is given */
12819459Sjkhstatic char *f_flag = NULL;	/* Read config info from file */
12919459Sjkhstatic int v_flag  = 0;		/* Be verbose */
1304Srgrimes
1314Srgrimesstruct part_type
1324Srgrimes{
1334Srgrimes unsigned char type;
1344Srgrimes char *name;
1354Srgrimes}part_types[] =
1364Srgrimes{
1378871Srgrimes	 {0x00, "unused"}
1388871Srgrimes	,{0x01, "Primary DOS with 12 bit FAT"}
1398871Srgrimes	,{0x02, "XENIX / filesystem"}
1408871Srgrimes	,{0x03, "XENIX /usr filesystem"}
14134582Sache	,{0x04, "Primary DOS with 16 bit FAT (<= 32MB)"}
1428871Srgrimes	,{0x05, "Extended DOS"}
1438871Srgrimes	,{0x06, "Primary 'big' DOS (> 32MB)"}
14461461Sghelmer	,{0x07, "OS/2 HPFS, NTFS, QNX-2 (16 bit) or Advanced UNIX"}
1458871Srgrimes	,{0x08, "AIX filesystem"}
1468871Srgrimes	,{0x09, "AIX boot partition or Coherent"}
1478871Srgrimes	,{0x0A, "OS/2 Boot Manager or OPUS"}
14834582Sache	,{0x0B, "DOS or Windows 95 with 32 bit FAT"}
14934582Sache	,{0x0C, "DOS or Windows 95 with 32 bit FAT, LBA"}
15034582Sache	,{0x0E, "Primary 'big' DOS (> 32MB, LBA)"}
15134582Sache	,{0x0F, "Extended DOS, LBA"}
1528871Srgrimes	,{0x10, "OPUS"}
15361568Sbrian	,{0x39, "plan9"}
1548871Srgrimes	,{0x40, "VENIX 286"}
15561461Sghelmer	,{0x4D, "QNX 4.2 Primary"}
15661461Sghelmer	,{0x4E, "QNX 4.2 Secondary"}
15761461Sghelmer	,{0x4F, "QNX 4.2 Tertiary"}
1588871Srgrimes	,{0x50, "DM"}
1598871Srgrimes	,{0x51, "DM"}
1608871Srgrimes	,{0x52, "CP/M or Microport SysV/AT"}
1618871Srgrimes	,{0x56, "GB"}
1628871Srgrimes	,{0x61, "Speed"}
1638871Srgrimes	,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
1648871Srgrimes	,{0x64, "Novell Netware 2.xx"}
1658871Srgrimes	,{0x65, "Novell Netware 3.xx"}
1668871Srgrimes	,{0x75, "PCIX"}
1678871Srgrimes	,{0x80, "Minix 1.1 ... 1.4a"}
1688871Srgrimes	,{0x81, "Minix 1.4b ... 1.5.10"}
16939377Sobrien	,{0x82, "Linux swap or Solaris x86"}
1708871Srgrimes	,{0x83, "Linux filesystem"}
1718871Srgrimes	,{0x93, "Amoeba filesystem"}
1728871Srgrimes	,{0x94, "Amoeba bad block table"}
17340946Sjkoshy	,{0x9F, "BSD/OS"}
17464316Sjoe	,{0xA0, "Suspend to Disk"}
1758871Srgrimes	,{0xA5, "FreeBSD/NetBSD/386BSD"}
17625378Simp	,{0xA6, "OpenBSD"}
1777902Sgpalmer	,{0xA7, "NEXTSTEP"}
17840947Salex	,{0xA9, "NetBSD"}
1798871Srgrimes	,{0xB7, "BSDI BSD/386 filesystem"}
1808871Srgrimes	,{0xB8, "BSDI BSD/386 swap"}
1818871Srgrimes	,{0xDB, "Concurrent CPM or C.DOS or CTOS"}
1828871Srgrimes	,{0xE1, "Speed"}
1838871Srgrimes	,{0xE3, "Speed"}
1848871Srgrimes	,{0xE4, "Speed"}
1858871Srgrimes	,{0xF1, "Speed"}
1868871Srgrimes	,{0xF2, "DOS 3.3+ Secondary"}
1878871Srgrimes	,{0xF4, "Speed"}
1888871Srgrimes	,{0xFF, "BBT (Bad Blocks Table)"}
1894Srgrimes};
1904Srgrimes
19116561Salexstatic void print_s0(int which);
19216561Salexstatic void print_part(int i);
19316561Salexstatic void init_sector0(unsigned long start);
19419459Sjkhstatic void init_boot(void);
19516561Salexstatic void change_part(int i);
19616561Salexstatic void print_params();
19716561Salexstatic void change_active(int which);
19843054Srnordierstatic void change_code();
19916561Salexstatic void get_params_to_use();
20079681Sjoergstatic char *get_rootdisk(void);
20181164Siedowsestatic void dos(struct dos_partition *partp);
20216561Salexstatic int open_disk(int u_flag);
20316561Salexstatic ssize_t read_disk(off_t sector, void *buf);
20416561Salexstatic ssize_t write_disk(off_t sector, void *buf);
20516561Salexstatic int get_params();
20616561Salexstatic int read_s0();
20716561Salexstatic int write_s0();
20816561Salexstatic int ok(char *str);
20916561Salexstatic int decimal(char *str, int *num, int deflt);
21016561Salexstatic char *get_type(int type);
21119459Sjkhstatic int read_config(char *config_file);
21219459Sjkhstatic void reset_boot(void);
21365054Sjhbstatic int sanitize_partition(struct dos_partition *);
21437415Scharnierstatic void usage(void);
21516561Salex#if 0
21616561Salexstatic int hex(char *str, int *num, int deflt);
21716561Salexstatic int string(char *str, char **ans);
21816561Salex#endif
2194Srgrimes
22016561Salex
22116561Salexint
22216561Salexmain(int argc, char *argv[])
2234Srgrimes{
22479681Sjoerg	struct	stat sb;
22548282Srnordier	int	c, i;
2264Srgrimes
22757896Simp	while ((c = getopt(argc, argv, "BIab:f:istuv1234")) != -1)
22848282Srnordier		switch (c) {
22948282Srnordier		case 'B':
23048282Srnordier			B_flag = 1;
2314Srgrimes			break;
23257896Simp		case 'I':
23357896Simp			I_flag = 1;
23457896Simp			break;
23548282Srnordier		case 'a':
23648282Srnordier			a_flag = 1;
23748282Srnordier			break;
23848282Srnordier		case 'b':
23948282Srnordier			b_flag = optarg;
24048282Srnordier			break;
24148282Srnordier		case 'f':
24248282Srnordier			f_flag = optarg;
24348282Srnordier			break;
24448282Srnordier		case 'i':
24548282Srnordier			i_flag = 1;
24648282Srnordier			break;
24757896Simp		case 's':
24857896Simp			s_flag = 1;
24957896Simp			break;
25048282Srnordier		case 't':
25148282Srnordier			t_flag = 1;
25248282Srnordier			break;
25348282Srnordier		case 'u':
25448282Srnordier			u_flag = 1;
25548282Srnordier			break;
25648282Srnordier		case 'v':
25748282Srnordier			v_flag = 1;
25848282Srnordier			break;
25948282Srnordier		case '1':
26048282Srnordier		case '2':
26148282Srnordier		case '3':
26248282Srnordier		case '4':
26348282Srnordier			partition = c - '0';
26448282Srnordier			break;
26548282Srnordier		default:
26648282Srnordier			usage();
2674Srgrimes		}
26848282Srnordier	if (f_flag || i_flag)
26948282Srnordier		u_flag = 1;
27048282Srnordier	if (t_flag)
27148282Srnordier		v_flag = 1;
27248282Srnordier	argc -= optind;
27348282Srnordier	argv += optind;
2744Srgrimes
27579681Sjoerg	if (argc == 0) {
27679681Sjoerg		disk = get_rootdisk();
27779681Sjoerg	} else {
27879681Sjoerg		if (stat(argv[0], &sb) == 0) {
27979681Sjoerg			/* OK, full pathname given */
28010514Sjoerg			disk = argv[0];
28179681Sjoerg		} else if (errno == ENOENT) {
28279681Sjoerg			/* Try prepending "/dev" */
28379681Sjoerg			if ((disk = malloc(strlen(argv[0]) + strlen(_PATH_DEV) +
28479681Sjoerg			     1)) == NULL)
28579681Sjoerg				errx(1, "out of memory");
28679681Sjoerg			strcpy(disk, _PATH_DEV);
28779681Sjoerg			strcat(disk, argv[0]);
28879681Sjoerg		} else {
28979681Sjoerg			/* other stat error, let it fail below */
29079681Sjoerg			disk = argv[0];
29110514Sjoerg		}
29210514Sjoerg	}
29379681Sjoerg	if (open_disk(u_flag) < 0)
29479681Sjoerg		err(1, "cannot open disk %s", disk);
2954Srgrimes
29663027Sjhb	/* (abu)use mboot.bootinst to probe for the sector size */
29763027Sjhb	if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL)
29863027Sjhb		err(1, "cannot allocate buffer to determine disk sector size");
29963027Sjhb	read_disk(0, mboot.bootinst);
30063329Sjhb	free(mboot.bootinst);
30163329Sjhb	mboot.bootinst = NULL;
30263027Sjhb
30357896Simp	if (s_flag)
30457896Simp	{
30557896Simp		int i;
30657896Simp		struct dos_partition *partp;
30710514Sjoerg
30857896Simp		if (read_s0())
30957896Simp			err(1, "read_s0");
31057896Simp		printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads,
31157896Simp		    dos_sectors);
31257896Simp		printf("Part  %11s %11s Type Flags\n", "Start", "Size");
31357896Simp		for (i = 0; i < NDOSPART; i++) {
31457896Simp			partp = ((struct dos_partition *) &mboot.parts) + i;
31557896Simp			if (partp->dp_start == 0 && partp->dp_size == 0)
31657896Simp				continue;
31757896Simp			printf("%4d: %11lu %11lu 0x%02x 0x%02x\n", i + 1,
31857896Simp			    (u_long) partp->dp_start,
31957896Simp			    (u_long) partp->dp_size, partp->dp_typ,
32057896Simp			    partp->dp_flag);
32157896Simp		}
32257896Simp		exit(0);
32357896Simp	}
32457896Simp
3254Srgrimes	printf("******* Working on device %s *******\n",disk);
32619459Sjkh
32757896Simp	if (I_flag)
32850215Sphk	{
32950215Sphk		struct dos_partition *partp;
33050215Sphk
33150215Sphk		read_s0();
33250215Sphk		reset_boot();
33350215Sphk		partp = (struct dos_partition *) (&mboot.parts[0]);
33450215Sphk		partp->dp_typ = DOSPTYP_386BSD;
33550215Sphk		partp->dp_flag = ACTIVE;
33650215Sphk		partp->dp_start = dos_sectors;
33765054Sjhb		partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs -
33865054Sjhb		    dos_sectors;
33950215Sphk
34081164Siedowse		dos(partp);
34150215Sphk		if (v_flag)
34250215Sphk			print_s0(-1);
34350215Sphk		write_s0();
34450215Sphk		exit(0);
34550215Sphk	}
34619459Sjkh	if (f_flag)
3474Srgrimes	{
34819459Sjkh	    if (read_s0() || i_flag)
34919459Sjkh	    {
35019459Sjkh		reset_boot();
35119459Sjkh	    }
35219459Sjkh
35319459Sjkh	    if (!read_config(f_flag))
35419459Sjkh	    {
35519459Sjkh		exit(1);
35619459Sjkh	    }
35719459Sjkh	    if (v_flag)
35819459Sjkh	    {
35919459Sjkh		print_s0(-1);
36019459Sjkh	    }
36119459Sjkh	    if (!t_flag)
36219459Sjkh	    {
36319459Sjkh		write_s0();
36419459Sjkh	    }
3654Srgrimes	}
3664Srgrimes	else
3674Srgrimes	{
36819459Sjkh	    if(u_flag)
36919459Sjkh	    {
37019459Sjkh		get_params_to_use();
37119459Sjkh	    }
37219459Sjkh	    else
37319459Sjkh	    {
3744Srgrimes		print_params();
37519459Sjkh	    }
3764Srgrimes
37719459Sjkh	    if (read_s0())
37865054Sjhb		init_sector0(dos_sectors);
3794Srgrimes
38020061Ssos	    printf("Media sector size is %d\n", secsize);
38119459Sjkh	    printf("Warning: BIOS sector numbering starts with sector 1\n");
38219459Sjkh	    printf("Information from DOS bootblock is:\n");
38319459Sjkh	    if (partition == -1)
38426421Sbrian		for (i = 1; i <= NDOSPART; i++)
38519459Sjkh		    change_part(i);
38619459Sjkh	    else
3874Srgrimes		change_part(partition);
3884Srgrimes
38919459Sjkh	    if (u_flag || a_flag)
3904Srgrimes		change_active(partition);
3914Srgrimes
39248282Srnordier	    if (B_flag)
39343054Srnordier		change_code();
39443054Srnordier
39548282Srnordier	    if (u_flag || a_flag || B_flag) {
39619459Sjkh		if (!t_flag)
39719459Sjkh		{
39819459Sjkh		    printf("\nWe haven't changed the partition table yet.  ");
39919459Sjkh		    printf("This is your last chance.\n");
40019459Sjkh		}
4014Srgrimes		print_s0(-1);
40219459Sjkh		if (!t_flag)
40319459Sjkh		{
40419459Sjkh		    if (ok("Should we write new partition table?"))
4054Srgrimes			write_s0();
40619459Sjkh		}
40719459Sjkh		else
40819459Sjkh		{
40919459Sjkh		    printf("\n-t flag specified -- partition table not written.\n");
41019459Sjkh		}
41119459Sjkh	    }
4124Srgrimes	}
4134Srgrimes
4144Srgrimes	exit(0);
41537415Scharnier}
4164Srgrimes
41737415Scharnierstatic void
41837415Scharnierusage()
41937415Scharnier{
42048282Srnordier	fprintf(stderr, "%s%s",
42162178Sjhb		"usage: fdisk [-BIaistu] [-b bootcode] [-1234] [disk]\n",
42248282Srnordier 		"       fdisk -f configfile [-itv] [disk]\n");
42337415Scharnier        exit(1);
4244Srgrimes}
4254Srgrimes
42616561Salexstatic void
42716561Salexprint_s0(int which)
4284Srgrimes{
4294Srgrimesint	i;
4304Srgrimes
4314Srgrimes	print_params();
4324Srgrimes	printf("Information from DOS bootblock is:\n");
4334Srgrimes	if (which == -1)
43426421Sbrian		for (i = 1; i <= NDOSPART; i++)
4354Srgrimes			printf("%d: ", i), print_part(i);
4364Srgrimes	else
4374Srgrimes		print_part(which);
4384Srgrimes}
4394Srgrimes
4404Srgrimesstatic struct dos_partition mtpart = { 0 };
4414Srgrimes
44216561Salexstatic void
44316561Salexprint_part(int i)
4444Srgrimes{
44526389Sgibbs	struct	  dos_partition *partp;
44626389Sgibbs	u_int64_t part_mb;
4474Srgrimes
44826421Sbrian	partp = ((struct dos_partition *) &mboot.parts) + i - 1;
4494Srgrimes
4504Srgrimes	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
4514Srgrimes		printf("<UNUSED>\n");
4524Srgrimes		return;
4534Srgrimes	}
45426389Sgibbs	/*
45526389Sgibbs	 * Be careful not to overflow.
45626389Sgibbs	 */
45726389Sgibbs	part_mb = partp->dp_size;
45826389Sgibbs	part_mb *= secsize;
45926389Sgibbs	part_mb /= (1024 * 1024);
4604Srgrimes	printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ));
46137244Sbde	printf("    start %lu, size %lu (%qd Meg), flag %x%s\n",
46237244Sbde		(u_long)partp->dp_start,
46337244Sbde		(u_long)partp->dp_size,
46426389Sgibbs		part_mb,
46534952Sobrien		partp->dp_flag,
46634952Sobrien		partp->dp_flag == ACTIVE ? " (active)" : "");
46769371Sobrien	printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n"
4684Srgrimes		,DPCYL(partp->dp_scyl, partp->dp_ssect)
46969371Sobrien		,partp->dp_shd
4704Srgrimes		,DPSECT(partp->dp_ssect)
4714Srgrimes		,DPCYL(partp->dp_ecyl, partp->dp_esect)
47269371Sobrien		,partp->dp_ehd
47369371Sobrien		,DPSECT(partp->dp_esect));
4744Srgrimes}
4754Srgrimes
47619459Sjkh
47716561Salexstatic void
47819459Sjkhinit_boot(void)
47919459Sjkh{
48048282Srnordier	const char *fname;
48163027Sjhb	int fd, n;
48263027Sjhb	struct stat sb;
48348282Srnordier
48448282Srnordier	fname = b_flag ? b_flag : "/boot/mbr";
48548282Srnordier	if ((fd = open(fname, O_RDONLY)) == -1 ||
48663027Sjhb	    fstat(fd, &sb) == -1)
48763027Sjhb		err(1, "%s", fname);
48863027Sjhb	if ((mboot.bootinst_size = sb.st_size) % secsize != 0)
48963027Sjhb		errx(1, "%s: length must be a multiple of sector size", fname);
49063218Sache	if (mboot.bootinst != NULL)
49163218Sache		free(mboot.bootinst);
49263027Sjhb	if ((mboot.bootinst = malloc(mboot.bootinst_size = sb.st_size)) == NULL)
49363027Sjhb		errx(1, "%s: unable to allocate read buffer", fname);
49463027Sjhb	if ((n = read(fd, mboot.bootinst, mboot.bootinst_size)) == -1 ||
49548282Srnordier	    close(fd))
49648282Srnordier		err(1, "%s", fname);
49763027Sjhb	if (n != mboot.bootinst_size)
49863027Sjhb		errx(1, "%s: short read", fname);
49919459Sjkh}
50019459Sjkh
50119459Sjkh
50219459Sjkhstatic void
50316561Salexinit_sector0(unsigned long start)
5044Srgrimes{
5054Srgrimesstruct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
5064Srgrimes
50719459Sjkh	init_boot();
5084Srgrimes
5094Srgrimes	partp->dp_typ = DOSPTYP_386BSD;
5104Srgrimes	partp->dp_flag = ACTIVE;
51165054Sjhb	start = ((start + dos_sectors - 1) / dos_sectors) * dos_sectors;
51263027Sjhb	if(start == 0)
51363027Sjhb		start = dos_sectors;
5144Srgrimes	partp->dp_start = start;
51565054Sjhb	partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - start;
5164Srgrimes
51781164Siedowse	dos(partp);
5184Srgrimes}
5194Srgrimes
52016561Salexstatic void
52116561Salexchange_part(int i)
5224Srgrimes{
52326421Sbrianstruct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1;
5244Srgrimes
5254Srgrimes    printf("The data for partition %d is:\n", i);
5264Srgrimes    print_part(i);
5274Srgrimes
5284Srgrimes    if (u_flag && ok("Do you want to change it?")) {
5294Srgrimes	int tmp;
5304Srgrimes
5314Srgrimes	if (i_flag) {
5324Srgrimes		bzero((char *)partp, sizeof (struct dos_partition));
53326421Sbrian		if (i == 4) {
5344Srgrimes			init_sector0(1);
53526421Sbrian			printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n");
5364Srgrimes			print_part(i);
5374Srgrimes		}
5384Srgrimes	}
5394Srgrimes
5404Srgrimes	do {
54134952Sobrien		Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp);
5424Srgrimes		Decimal("start", partp->dp_start, tmp);
5434Srgrimes		Decimal("size", partp->dp_size, tmp);
54481164Siedowse		if (!sanitize_partition(partp)) {
54581164Siedowse			warnx("ERROR: failed to adjust; setting sysid to 0");
54681164Siedowse			partp->dp_typ = 0;
54781164Siedowse		}
5484Srgrimes
54936262Sjraynard		if (ok("Explicitly specify beg/end address ?"))
5504Srgrimes		{
5514Srgrimes			int	tsec,tcyl,thd;
5524Srgrimes			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
5534Srgrimes			thd = partp->dp_shd;
5544Srgrimes			tsec = DPSECT(partp->dp_ssect);
5554Srgrimes			Decimal("beginning cylinder", tcyl, tmp);
55669371Sobrien			Decimal("beginning head", thd, tmp);
55768871Sobrien			Decimal("beginning sector", tsec, tmp);
5584Srgrimes			partp->dp_scyl = DOSCYL(tcyl);
5594Srgrimes			partp->dp_ssect = DOSSECT(tsec,tcyl);
5604Srgrimes			partp->dp_shd = thd;
5614Srgrimes
5624Srgrimes			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
5634Srgrimes			thd = partp->dp_ehd;
5644Srgrimes			tsec = DPSECT(partp->dp_esect);
5654Srgrimes			Decimal("ending cylinder", tcyl, tmp);
56669371Sobrien			Decimal("ending head", thd, tmp);
56768871Sobrien			Decimal("ending sector", tsec, tmp);
5684Srgrimes			partp->dp_ecyl = DOSCYL(tcyl);
5694Srgrimes			partp->dp_esect = DOSSECT(tsec,tcyl);
5704Srgrimes			partp->dp_ehd = thd;
57181164Siedowse		} else
57281164Siedowse			dos(partp);
5738871Srgrimes
5744Srgrimes		print_part(i);
5754Srgrimes	} while (!ok("Are we happy with this entry?"));
5764Srgrimes    }
5774Srgrimes}
5784Srgrimes
57916561Salexstatic void
5804Srgrimesprint_params()
5814Srgrimes{
5824Srgrimes	printf("parameters extracted from in-core disklabel are:\n");
5834Srgrimes	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
5844Srgrimes			,cyls,heads,sectors,cylsecs);
5854Srgrimes	if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
58620061Ssos		printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
5874Srgrimes	printf("parameters to be used for BIOS calculations are:\n");
5884Srgrimes	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
5894Srgrimes		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
5904Srgrimes}
5914Srgrimes
59216561Salexstatic void
59316561Salexchange_active(int which)
5944Srgrimes{
59581164Siedowse	struct dos_partition *partp = &mboot.parts[0];
59681164Siedowse	int active, i, new, tmp;
5974Srgrimes
59881164Siedowse	active = -1;
59981164Siedowse	for (i = 0; i < NDOSPART; i++) {
60081164Siedowse		if ((partp[i].dp_flag & ACTIVE) == 0)
60181164Siedowse			continue;
60281164Siedowse		printf("Partition %d is marked active\n", i + 1);
60381164Siedowse		if (active == -1)
60481164Siedowse			active = i + 1;
60581164Siedowse	}
6064Srgrimes	if (a_flag && which != -1)
6074Srgrimes		active = which;
60881164Siedowse	else if (active == -1)
60981164Siedowse		active = 1;
61081164Siedowse
6113723Sbde	if (!ok("Do you want to change the active partition?"))
6123723Sbde		return;
61334952Sobriensetactive:
61434952Sobrien	do {
61581164Siedowse		new = active;
61681164Siedowse		Decimal("active partition", new, tmp);
61781164Siedowse		if (new < 1 || new > 4) {
61834952Sobrien			printf("Active partition number must be in range 1-4."
61934952Sobrien					"  Try again.\n");
62034952Sobrien			goto setactive;
62134952Sobrien		}
62281164Siedowse		active = new;
62334952Sobrien	} while (!ok("Are you happy with this choice"));
6244Srgrimes	for (i = 0; i < NDOSPART; i++)
6254Srgrimes		partp[i].dp_flag = 0;
62626421Sbrian	if (active > 0 && active <= NDOSPART)
62726421Sbrian		partp[active-1].dp_flag = ACTIVE;
6284Srgrimes}
6294Srgrimes
63043054Srnordierstatic void
63143054Srnordierchange_code()
63243054Srnordier{
63343054Srnordier	if (ok("Do you want to change the boot code?"))
63443054Srnordier		init_boot();
63543054Srnordier}
63643054Srnordier
63716561Salexvoid
6384Srgrimesget_params_to_use()
6394Srgrimes{
6404Srgrimes	int	tmp;
6414Srgrimes	print_params();
6424Srgrimes	if (ok("Do you want to change our idea of what BIOS thinks ?"))
6434Srgrimes	{
6444Srgrimes		do
6454Srgrimes		{
6464Srgrimes			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
6474Srgrimes			Decimal("BIOS's idea of #heads", dos_heads, tmp);
6484Srgrimes			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
6494Srgrimes			dos_cylsecs = dos_heads * dos_sectors;
6504Srgrimes			print_params();
6514Srgrimes		}
6524Srgrimes		while(!ok("Are you happy with this choice"));
6534Srgrimes	}
6544Srgrimes}
6554Srgrimes
65619459Sjkh
6574Srgrimes/***********************************************\
6584Srgrimes* Change real numbers into strange dos numbers	*
6594Srgrimes\***********************************************/
66016561Salexstatic void
66181164Siedowsedos(partp)
66281164Siedowse	struct dos_partition *partp;
6634Srgrimes{
66481164Siedowse	int cy, sec;
66581164Siedowse	u_int32_t end;
6664Srgrimes
66781164Siedowse	if (partp->dp_typ == 0 && partp->dp_start == 0 &&
66881164Siedowse	    partp->dp_size == 0) {
66981164Siedowse		bcopy(partp, &mtpart, sizeof(*partp));
6703723Sbde		return;
6713723Sbde	}
6723723Sbde
67381164Siedowse	/* Start c/h/s. */
67481164Siedowse	partp->dp_shd = partp->dp_start % dos_cylsecs / dos_sectors;
67581164Siedowse	cy = partp->dp_start / dos_cylsecs;
67681164Siedowse	sec = partp->dp_start % dos_sectors + 1;
67781164Siedowse	partp->dp_scyl = DOSCYL(cy);
67881164Siedowse	partp->dp_ssect = DOSSECT(sec, cy);
6794Srgrimes
68081164Siedowse	/* End c/h/s. */
68181164Siedowse	end = partp->dp_start + partp->dp_size - 1;
68281164Siedowse	partp->dp_ehd = end % dos_cylsecs / dos_sectors;
68381164Siedowse	cy = end / dos_cylsecs;
68481164Siedowse	sec = end % dos_sectors + 1;
68581164Siedowse	partp->dp_ecyl = DOSCYL(cy);
68681164Siedowse	partp->dp_esect = DOSSECT(sec, cy);
6874Srgrimes}
6884Srgrimes
6894Srgrimesint fd;
6904Srgrimes
6914Srgrimes	/* Getting device status */
6924Srgrimes
69316561Salexstatic int
69416561Salexopen_disk(int u_flag)
6954Srgrimes{
69679306Sjoerg	struct stat 	st;
6974Srgrimes
6988871Srgrimes	if (stat(disk, &st) == -1) {
69979306Sjoerg		if (errno == ENOENT)
70079306Sjoerg			return -2;
70137415Scharnier		warnx("can't get file status of %s", disk);
7024Srgrimes		return -1;
7032810Sbde	}
7042810Sbde	if ( !(st.st_mode & S_IFCHR) )
70537415Scharnier		warnx("device %s is not character special", disk);
70643054Srnordier	if ((fd = open(disk,
70757896Simp	    a_flag || I_flag || B_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) {
70810514Sjoerg		if(errno == ENXIO)
70910514Sjoerg			return -2;
71037415Scharnier		warnx("can't open device %s", disk);
7114Srgrimes		return -1;
7124Srgrimes	}
7134Srgrimes	if (get_params(0) == -1) {
71437415Scharnier		warnx("can't get disk parameters on %s", disk);
7154Srgrimes		return -1;
7164Srgrimes	}
7174Srgrimes	return fd;
7184Srgrimes}
7194Srgrimes
72016561Salexstatic ssize_t
72116561Salexread_disk(off_t sector, void *buf)
7224Srgrimes{
7234Srgrimes	lseek(fd,(sector * 512), 0);
72420061Ssos	if( secsize == 0 )
72520061Ssos		for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 )
72620061Ssos			{
72720061Ssos			/* try the read */
72820061Ssos			int size = read(fd, buf, secsize);
72920061Ssos			if( size == secsize )
73020061Ssos				/* it worked so return */
73120061Ssos				return secsize;
73220061Ssos			}
73320061Ssos	else
73420061Ssos		return read( fd, buf, secsize );
73520061Ssos
73620061Ssos	/* we failed to read at any of the sizes */
73720061Ssos	return -1;
7384Srgrimes}
7394Srgrimes
74016561Salexstatic ssize_t
74116561Salexwrite_disk(off_t sector, void *buf)
7424Srgrimes{
7434Srgrimes	lseek(fd,(sector * 512), 0);
74420061Ssos	/* write out in the size that the read_disk found worked */
74520061Ssos	return write(fd, buf, secsize);
7464Srgrimes}
7474Srgrimes
74816561Salexstatic int
74916561Salexget_params()
7504Srgrimes{
7514Srgrimes
7524Srgrimes    if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
75337415Scharnier	warnx("can't get disk parameters on %s; supplying dummy ones", disk);
7542810Sbde	dos_cyls = cyls = 1;
7552810Sbde	dos_heads = heads = 1;
7562810Sbde	dos_sectors = sectors = 1;
7572810Sbde	dos_cylsecs = cylsecs = heads * sectors;
7582810Sbde	disksecs = cyls * heads * sectors;
7592810Sbde	return disksecs;
7604Srgrimes    }
7614Srgrimes
7624Srgrimes    dos_cyls = cyls = disklabel.d_ncylinders;
7634Srgrimes    dos_heads = heads = disklabel.d_ntracks;
7644Srgrimes    dos_sectors = sectors = disklabel.d_nsectors;
7654Srgrimes    dos_cylsecs = cylsecs = heads * sectors;
7664Srgrimes    disksecs = cyls * heads * sectors;
7674Srgrimes
7684Srgrimes    return (disksecs);
7694Srgrimes}
7704Srgrimes
7714Srgrimes
77216561Salexstatic int
7734Srgrimesread_s0()
7744Srgrimes{
77563218Sache	mboot.bootinst_size = secsize;
77663218Sache	if (mboot.bootinst != NULL)
77763027Sjhb		free(mboot.bootinst);
77863218Sache	if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) {
77963218Sache		warnx("unable to allocate buffer to read fdisk "
78063218Sache		      "partition table");
78163218Sache		return -1;
78263027Sjhb	}
78363027Sjhb	if (read_disk(0, mboot.bootinst) == -1) {
78437415Scharnier		warnx("can't read fdisk partition table");
7854Srgrimes		return -1;
7864Srgrimes	}
78763729Sjhb	if (*(uint16_t *)&mboot.bootinst[MBRSIGOFF] != BOOT_MAGIC) {
78837415Scharnier		warnx("invalid fdisk partition table found");
7894Srgrimes		/* So should we initialize things */
7904Srgrimes		return -1;
7914Srgrimes	}
79263027Sjhb	memcpy(mboot.parts, &mboot.bootinst[DOSPARTOFF], sizeof(mboot.parts));
7934Srgrimes	return 0;
7944Srgrimes}
7954Srgrimes
79616561Salexstatic int
7974Srgrimeswrite_s0()
7984Srgrimes{
79951636Sbillf#ifdef NOT_NOW
8004Srgrimes	int	flag;
80151636Sbillf#endif
80263027Sjhb	int	sector;
80363027Sjhb
8044Srgrimes	if (iotest) {
8054Srgrimes		print_s0(-1);
8064Srgrimes		return 0;
8074Srgrimes	}
80863027Sjhb	memcpy(&mboot.bootinst[DOSPARTOFF], mboot.parts, sizeof(mboot.parts));
8094Srgrimes	/*
8104Srgrimes	 * write enable label sector before write (if necessary),
8114Srgrimes	 * disable after writing.
8124Srgrimes	 * needed if the disklabel protected area also protects
8134Srgrimes	 * sector 0. (e.g. empty disk)
8144Srgrimes	 */
81550215Sphk#ifdef NOT_NOW
8164Srgrimes	flag = 1;
8174Srgrimes	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
81837415Scharnier		warn("ioctl DIOCWLABEL");
81911143Sjulian#endif
82063027Sjhb	for(sector = 0; sector < mboot.bootinst_size / secsize; sector++)
82163027Sjhb		if (write_disk(sector,
82263027Sjhb			       &mboot.bootinst[sector * secsize]) == -1) {
82363027Sjhb			warn("can't write fdisk partition table");
82463027Sjhb			return -1;
82550215Sphk#ifdef NOT_NOW
82663027Sjhb			flag = 0;
82763027Sjhb			(void) ioctl(fd, DIOCWLABEL, &flag);
82863027Sjhb#endif
82963027Sjhb		}
83063027Sjhb#ifdef NOT_NOW
8314Srgrimes	flag = 0;
8324Srgrimes	(void) ioctl(fd, DIOCWLABEL, &flag);
83311143Sjulian#endif
83416561Salex	return(0);
8354Srgrimes}
8364Srgrimes
8374Srgrimes
83816561Salexstatic int
8394Srgrimesok(str)
8404Srgrimeschar *str;
8414Srgrimes{
8424Srgrimes	printf("%s [n] ", str);
84381164Siedowse	fflush(stdout);
84481164Siedowse	if (fgets(lbuf, LBUF, stdin) == NULL)
84581164Siedowse		exit(1);
8464Srgrimes	lbuf[strlen(lbuf)-1] = 0;
8474Srgrimes
8484Srgrimes	if (*lbuf &&
8494Srgrimes		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
8504Srgrimes		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
8514Srgrimes		return 1;
8524Srgrimes	else
8534Srgrimes		return 0;
8544Srgrimes}
8554Srgrimes
85616561Salexstatic int
85716561Salexdecimal(char *str, int *num, int deflt)
8584Srgrimes{
8594Srgrimesint acc = 0, c;
8604Srgrimeschar *cp;
8614Srgrimes
8624Srgrimes	while (1) {
8634Srgrimes		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
86481164Siedowse		fflush(stdout);
86581164Siedowse		if (fgets(lbuf, LBUF, stdin) == NULL)
86681164Siedowse			exit(1);
8674Srgrimes		lbuf[strlen(lbuf)-1] = 0;
8684Srgrimes
8694Srgrimes		if (!*lbuf)
8704Srgrimes			return 0;
8714Srgrimes
8724Srgrimes		cp = lbuf;
8734Srgrimes		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
8744Srgrimes		if (!c)
8754Srgrimes			return 0;
87616561Salex		while ((c = *cp++)) {
8774Srgrimes			if (c <= '9' && c >= '0')
8784Srgrimes				acc = acc * 10 + c - '0';
8794Srgrimes			else
8804Srgrimes				break;
8814Srgrimes		}
8824Srgrimes		if (c == ' ' || c == '\t')
8834Srgrimes			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
8844Srgrimes		if (!c) {
8854Srgrimes			*num = acc;
8864Srgrimes			return 1;
8874Srgrimes		} else
88834952Sobrien			printf("%s is an invalid decimal number.  Try again.\n",
8894Srgrimes				lbuf);
8904Srgrimes	}
8914Srgrimes
8924Srgrimes}
8934Srgrimes
89416561Salex#if 0
89516561Salexstatic int
89616561Salexhex(char *str, int *num, int deflt)
8974Srgrimes{
8984Srgrimesint acc = 0, c;
8994Srgrimeschar *cp;
9004Srgrimes
9014Srgrimes	while (1) {
9024Srgrimes		printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
9034Srgrimes		fgets(lbuf, LBUF, stdin);
9044Srgrimes		lbuf[strlen(lbuf)-1] = 0;
9054Srgrimes
9064Srgrimes		if (!*lbuf)
9074Srgrimes			return 0;
9084Srgrimes
9094Srgrimes		cp = lbuf;
9104Srgrimes		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
9114Srgrimes		if (!c)
9124Srgrimes			return 0;
91316561Salex		while ((c = *cp++)) {
9144Srgrimes			if (c <= '9' && c >= '0')
9154Srgrimes				acc = (acc << 4) + c - '0';
9164Srgrimes			else if (c <= 'f' && c >= 'a')
9174Srgrimes				acc = (acc << 4) + c - 'a' + 10;
9184Srgrimes			else if (c <= 'F' && c >= 'A')
9194Srgrimes				acc = (acc << 4) + c - 'A' + 10;
9204Srgrimes			else
9214Srgrimes				break;
9224Srgrimes		}
9234Srgrimes		if (c == ' ' || c == '\t')
9244Srgrimes			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
9254Srgrimes		if (!c) {
9264Srgrimes			*num = acc;
9274Srgrimes			return 1;
9284Srgrimes		} else
92934952Sobrien			printf("%s is an invalid hex number.  Try again.\n",
9304Srgrimes				lbuf);
9314Srgrimes	}
9324Srgrimes
9334Srgrimes}
9344Srgrimes
93516561Salexstatic int
93616561Salexstring(char *str, char **ans)
9374Srgrimes{
9384Srgrimesint c;
9394Srgrimeschar *cp = lbuf;
9404Srgrimes
9414Srgrimes	while (1) {
9424Srgrimes		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
9434Srgrimes		fgets(lbuf, LBUF, stdin);
9444Srgrimes		lbuf[strlen(lbuf)-1] = 0;
9454Srgrimes
9464Srgrimes		if (!*lbuf)
9474Srgrimes			return 0;
9484Srgrimes
9494Srgrimes		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
9504Srgrimes		if (c == '"') {
9514Srgrimes			c = *++cp;
9524Srgrimes			*ans = cp;
9534Srgrimes			while ((c = *cp) && c != '"') cp++;
9544Srgrimes		} else {
9554Srgrimes			*ans = cp;
9564Srgrimes			while ((c = *cp) && c != ' ' && c != '\t') cp++;
9574Srgrimes		}
9584Srgrimes
9594Srgrimes		if (c)
9604Srgrimes			*cp = 0;
9614Srgrimes		return 1;
9624Srgrimes	}
9634Srgrimes}
96416561Salex#endif
9654Srgrimes
96616561Salexstatic char *
96716561Salexget_type(int type)
9684Srgrimes{
9694Srgrimes	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
9704Srgrimes	int	counter = 0;
9714Srgrimes	struct	part_type *ptr = part_types;
9724Srgrimes
9738871Srgrimes
9744Srgrimes	while(counter < numentries)
9754Srgrimes	{
9764Srgrimes		if(ptr->type == type)
9774Srgrimes		{
9784Srgrimes			return(ptr->name);
9794Srgrimes		}
9804Srgrimes		ptr++;
9814Srgrimes		counter++;
9824Srgrimes	}
9834Srgrimes	return("unknown");
9844Srgrimes}
98519459Sjkh
98619459Sjkh
98719459Sjkhstatic void
98819459Sjkhparse_config_line(line, command)
98919459Sjkh    char	*line;
99019459Sjkh    CMD		*command;
99119459Sjkh{
99219459Sjkh    char	*cp, *end;
99319459Sjkh
99419459Sjkh    cp = line;
99519459Sjkh    while (1)	/* dirty trick used to insure one exit point for this
99619459Sjkh		   function */
99719459Sjkh    {
99819459Sjkh	memset(command, 0, sizeof(*command));
99919459Sjkh
100019459Sjkh	while (isspace(*cp)) ++cp;
100119459Sjkh	if (*cp == '\0' || *cp == '#')
100219459Sjkh	{
100319459Sjkh	    break;
100419459Sjkh	}
100519459Sjkh	command->cmd = *cp++;
100619459Sjkh
100719459Sjkh	/*
100819459Sjkh	 * Parse args
100919459Sjkh	 */
101019459Sjkh	while (1)
101119459Sjkh	{
101219459Sjkh	    while (isspace(*cp)) ++cp;
101319459Sjkh	    if (*cp == '#')
101419459Sjkh	    {
101519459Sjkh		break;		/* found comment */
101619459Sjkh	    }
101719459Sjkh	    if (isalpha(*cp))
101819459Sjkh	    {
101919459Sjkh		command->args[command->n_args].argtype = *cp++;
102019459Sjkh	    }
102119459Sjkh	    if (!isdigit(*cp))
102219459Sjkh	    {
102319459Sjkh		break;		/* assume end of line */
102419459Sjkh	    }
102519459Sjkh	    end = NULL;
102619459Sjkh	    command->args[command->n_args].arg_val = strtol(cp, &end, 0);
102719459Sjkh	    if (cp == end)
102819459Sjkh	    {
102919459Sjkh		break;		/* couldn't parse number */
103019459Sjkh	    }
103119459Sjkh	    cp = end;
103219459Sjkh	    command->n_args++;
103319459Sjkh	}
103419459Sjkh	break;
103519459Sjkh    }
103619459Sjkh}
103719459Sjkh
103819459Sjkh
103919459Sjkhstatic int
104019459Sjkhprocess_geometry(command)
104119459Sjkh    CMD		*command;
104219459Sjkh{
104319459Sjkh    int		status = 1, i;
104419459Sjkh
104519459Sjkh    while (1)
104619459Sjkh    {
104719459Sjkh	geom_processed = 1;
104819459Sjkh	if (part_processed)
104919459Sjkh	{
105037415Scharnier	    warnx(
105137415Scharnier	"ERROR line %d: the geometry specification line must occur before\n\
105237415Scharnier    all partition specifications",
105337415Scharnier		    current_line_number);
105419459Sjkh	    status = 0;
105519459Sjkh	    break;
105619459Sjkh	}
105719459Sjkh	if (command->n_args != 3)
105819459Sjkh	{
105937415Scharnier	    warnx("ERROR line %d: incorrect number of geometry args",
106037415Scharnier		    current_line_number);
106119459Sjkh	    status = 0;
106219459Sjkh	    break;
106319459Sjkh	}
106419459Sjkh	dos_cyls = -1;
106519459Sjkh	dos_heads = -1;
106619459Sjkh	dos_sectors = -1;
106719459Sjkh	for (i = 0; i < 3; ++i)
106819459Sjkh	{
106919459Sjkh	    switch (command->args[i].argtype)
107019459Sjkh	    {
107119459Sjkh	    case 'c':
107219459Sjkh		dos_cyls = command->args[i].arg_val;
107319459Sjkh		break;
107419459Sjkh	    case 'h':
107519459Sjkh		dos_heads = command->args[i].arg_val;
107619459Sjkh		break;
107719459Sjkh	    case 's':
107819459Sjkh		dos_sectors = command->args[i].arg_val;
107919459Sjkh		break;
108019459Sjkh	    default:
108137415Scharnier		warnx(
108237415Scharnier		"ERROR line %d: unknown geometry arg type: '%c' (0x%02x)",
108337415Scharnier			current_line_number, command->args[i].argtype,
108419459Sjkh			command->args[i].argtype);
108519459Sjkh		status = 0;
108619459Sjkh		break;
108719459Sjkh	    }
108819459Sjkh	}
108919459Sjkh	if (status == 0)
109019459Sjkh	{
109119459Sjkh	    break;
109219459Sjkh	}
109319459Sjkh
109419459Sjkh	dos_cylsecs = dos_heads * dos_sectors;
109519459Sjkh
109619459Sjkh	/*
109719459Sjkh	 * Do sanity checks on parameter values
109819459Sjkh	 */
109919459Sjkh	if (dos_cyls < 0)
110019459Sjkh	{
110137415Scharnier	    warnx("ERROR line %d: number of cylinders not specified",
110237415Scharnier		    current_line_number);
110319459Sjkh	    status = 0;
110419459Sjkh	}
110519459Sjkh	if (dos_cyls == 0 || dos_cyls > 1024)
110619459Sjkh	{
110737415Scharnier	    warnx(
110837415Scharnier	"WARNING line %d: number of cylinders (%d) may be out-of-range\n\
110919459Sjkh    (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\
111037415Scharnier    is dedicated to FreeBSD)",
111137415Scharnier		    current_line_number, dos_cyls);
111219459Sjkh	}
111319459Sjkh
111419459Sjkh	if (dos_heads < 0)
111519459Sjkh	{
111637415Scharnier	    warnx("ERROR line %d: number of heads not specified",
111737415Scharnier		    current_line_number);
111819459Sjkh	    status = 0;
111919459Sjkh	}
112019459Sjkh	else if (dos_heads < 1 || dos_heads > 256)
112119459Sjkh	{
112237415Scharnier	    warnx("ERROR line %d: number of heads must be within (1-256)",
112337415Scharnier		    current_line_number);
112419459Sjkh	    status = 0;
112519459Sjkh	}
112619459Sjkh
112719459Sjkh	if (dos_sectors < 0)
112819459Sjkh	{
112937415Scharnier	    warnx("ERROR line %d: number of sectors not specified",
113037415Scharnier		    current_line_number);
113119459Sjkh	    status = 0;
113219459Sjkh	}
113319459Sjkh	else if (dos_sectors < 1 || dos_sectors > 63)
113419459Sjkh	{
113537415Scharnier	    warnx("ERROR line %d: number of sectors must be within (1-63)",
113637415Scharnier		    current_line_number);
113719459Sjkh	    status = 0;
113819459Sjkh	}
113919459Sjkh
114019459Sjkh	break;
114119459Sjkh    }
114219459Sjkh    return (status);
114319459Sjkh}
114419459Sjkh
114519459Sjkh
114619459Sjkhstatic int
114719459Sjkhprocess_partition(command)
114819459Sjkh    CMD		*command;
114919459Sjkh{
115019459Sjkh    int				status = 0, partition;
115165054Sjhb    u_int32_t			prev_head_boundary, prev_cyl_boundary;
115265054Sjhb    u_int32_t			adj_size, max_end;
115319459Sjkh    struct dos_partition	*partp;
115419459Sjkh
115519459Sjkh    while (1)
115619459Sjkh    {
115719459Sjkh	part_processed = 1;
115819459Sjkh	if (command->n_args != 4)
115919459Sjkh	{
116037415Scharnier	    warnx("ERROR line %d: incorrect number of partition args",
116137415Scharnier		    current_line_number);
116219459Sjkh	    break;
116319459Sjkh	}
116419459Sjkh	partition = command->args[0].arg_val;
116526421Sbrian	if (partition < 1 || partition > 4)
116619459Sjkh	{
116737415Scharnier	    warnx("ERROR line %d: invalid partition number %d",
116837415Scharnier		    current_line_number, partition);
116919459Sjkh	    break;
117019459Sjkh	}
117126421Sbrian	partp = ((struct dos_partition *) &mboot.parts) + partition - 1;
117219459Sjkh	bzero((char *)partp, sizeof (struct dos_partition));
117319459Sjkh	partp->dp_typ = command->args[1].arg_val;
117419459Sjkh	partp->dp_start = command->args[2].arg_val;
117519459Sjkh	partp->dp_size = command->args[3].arg_val;
117619459Sjkh	max_end = partp->dp_start + partp->dp_size;
117719459Sjkh
117819459Sjkh	if (partp->dp_typ == 0)
117919459Sjkh	{
118019459Sjkh	    /*
118119459Sjkh	     * Get out, the partition is marked as unused.
118219459Sjkh	     */
118319459Sjkh	    /*
118419459Sjkh	     * Insure that it's unused.
118519459Sjkh	     */
118619459Sjkh	    bzero((char *)partp, sizeof (struct dos_partition));
118719459Sjkh	    status = 1;
118819459Sjkh	    break;
118919459Sjkh	}
119019459Sjkh
119119459Sjkh	/*
119219459Sjkh	 * Adjust start upwards, if necessary, to fall on an head boundary.
119319459Sjkh	 */
119419459Sjkh	if (partp->dp_start % dos_sectors != 0)
119519459Sjkh	{
119665054Sjhb	    prev_head_boundary = partp->dp_start / dos_sectors * dos_sectors;
119765054Sjhb	    if (max_end < dos_sectors ||
119865054Sjhb		prev_head_boundary > max_end - dos_sectors)
119919459Sjkh	    {
120019459Sjkh		/*
120119459Sjkh		 * Can't go past end of partition
120219459Sjkh		 */
120337415Scharnier		warnx(
120437415Scharnier	"ERROR line %d: unable to adjust start of partition %d to fall on\n\
120565054Sjhb    a head boundary",
120637415Scharnier			current_line_number, partition);
120719459Sjkh		break;
120819459Sjkh	    }
120937415Scharnier	    warnx(
121065054Sjhb	"WARNING: adjusting start offset of partition %d\n\
121165054Sjhb    from %u to %u, to fall on a head boundary",
121265054Sjhb		    partition, (u_int)partp->dp_start,
121365054Sjhb		    (u_int)(prev_head_boundary + dos_sectors));
121465054Sjhb	    partp->dp_start = prev_head_boundary + dos_sectors;
121519459Sjkh	}
121619459Sjkh
121719459Sjkh	/*
121819459Sjkh	 * Adjust size downwards, if necessary, to fall on a cylinder
121919459Sjkh	 * boundary.
122019459Sjkh	 */
122165054Sjhb	prev_cyl_boundary =
122219459Sjkh	    ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs;
122365054Sjhb	if (prev_cyl_boundary > partp->dp_start)
122465054Sjhb	    adj_size = prev_cyl_boundary - partp->dp_start;
122565054Sjhb	else
122665054Sjhb	{
122765054Sjhb	    warnx(
122865054Sjhb	"ERROR: could not adjust partition to start on a head boundary\n\
122965054Sjhb    and end on a cylinder boundary.");
123065054Sjhb	    return (0);
123165054Sjhb	}
123219459Sjkh	if (adj_size != partp->dp_size)
123319459Sjkh	{
123437415Scharnier	    warnx(
123565054Sjhb	"WARNING: adjusting size of partition %d from %u to %u\n\
123665054Sjhb    to end on a cylinder boundary",
123765054Sjhb		    partition, (u_int)partp->dp_size, (u_int)adj_size);
123865054Sjhb	    partp->dp_size = adj_size;
123919459Sjkh	}
124065054Sjhb	if (partp->dp_size == 0)
124119459Sjkh	{
124281164Siedowse	    warnx("ERROR line %d: size of partition %d is zero",
124337415Scharnier		    current_line_number, partition);
124419459Sjkh	    break;
124519459Sjkh	}
124619459Sjkh
124781164Siedowse	dos(partp);
124819459Sjkh	status = 1;
124919459Sjkh	break;
125019459Sjkh    }
125119459Sjkh    return (status);
125219459Sjkh}
125319459Sjkh
125419459Sjkh
125519459Sjkhstatic int
125619459Sjkhprocess_active(command)
125719459Sjkh    CMD		*command;
125819459Sjkh{
125919459Sjkh    int				status = 0, partition, i;
126019459Sjkh    struct dos_partition	*partp;
126119459Sjkh
126219459Sjkh    while (1)
126319459Sjkh    {
126419459Sjkh	active_processed = 1;
126519459Sjkh	if (command->n_args != 1)
126619459Sjkh	{
126737415Scharnier	    warnx("ERROR line %d: incorrect number of active args",
126837415Scharnier		    current_line_number);
126919459Sjkh	    status = 0;
127019459Sjkh	    break;
127119459Sjkh	}
127219459Sjkh	partition = command->args[0].arg_val;
127326421Sbrian	if (partition < 1 || partition > 4)
127419459Sjkh	{
127537415Scharnier	    warnx("ERROR line %d: invalid partition number %d",
127637415Scharnier		    current_line_number, partition);
127719459Sjkh	    break;
127819459Sjkh	}
127919459Sjkh	/*
128019459Sjkh	 * Reset active partition
128119459Sjkh	 */
128219459Sjkh	partp = ((struct dos_partition *) &mboot.parts);
128319459Sjkh	for (i = 0; i < NDOSPART; i++)
128419459Sjkh	    partp[i].dp_flag = 0;
128526421Sbrian	partp[partition-1].dp_flag = ACTIVE;
128619459Sjkh
128719459Sjkh	status = 1;
128819459Sjkh	break;
128919459Sjkh    }
129019459Sjkh    return (status);
129119459Sjkh}
129219459Sjkh
129319459Sjkh
129419459Sjkhstatic int
129519459Sjkhprocess_line(line)
129619459Sjkh    char	*line;
129719459Sjkh{
129819459Sjkh    CMD		command;
129919459Sjkh    int		status = 1;
130019459Sjkh
130119459Sjkh    while (1)
130219459Sjkh    {
130319459Sjkh	parse_config_line(line, &command);
130419459Sjkh	switch (command.cmd)
130519459Sjkh	{
130619459Sjkh	case 0:
130719459Sjkh	    /*
130819459Sjkh	     * Comment or blank line
130919459Sjkh	     */
131019459Sjkh	    break;
131119459Sjkh	case 'g':
131219459Sjkh	    /*
131319459Sjkh	     * Set geometry
131419459Sjkh	     */
131519459Sjkh	    status = process_geometry(&command);
131619459Sjkh	    break;
131719459Sjkh	case 'p':
131819459Sjkh	    status = process_partition(&command);
131919459Sjkh	    break;
132019459Sjkh	case 'a':
132119459Sjkh	    status = process_active(&command);
132219459Sjkh	    break;
132319459Sjkh	default:
132419459Sjkh	    status = 0;
132519459Sjkh	    break;
132619459Sjkh	}
132719459Sjkh	break;
132819459Sjkh    }
132919459Sjkh    return (status);
133019459Sjkh}
133119459Sjkh
133219459Sjkh
133319459Sjkhstatic int
133419459Sjkhread_config(config_file)
133519459Sjkh    char *config_file;
133619459Sjkh{
133719459Sjkh    FILE	*fp = NULL;
133819459Sjkh    int		status = 1;
133919459Sjkh    char	buf[1010];
134019459Sjkh
134119459Sjkh    while (1)	/* dirty trick used to insure one exit point for this
134219459Sjkh		   function */
134319459Sjkh    {
134419459Sjkh	if (strcmp(config_file, "-") != 0)
134519459Sjkh	{
134619459Sjkh	    /*
134719459Sjkh	     * We're not reading from stdin
134819459Sjkh	     */
134919459Sjkh	    if ((fp = fopen(config_file, "r")) == NULL)
135019459Sjkh	    {
135119459Sjkh		status = 0;
135219459Sjkh		break;
135319459Sjkh	    }
135419459Sjkh	}
135519459Sjkh	else
135619459Sjkh	{
135719459Sjkh	    fp = stdin;
135819459Sjkh	}
135919459Sjkh	current_line_number = 0;
136019459Sjkh	while (!feof(fp))
136119459Sjkh	{
136219459Sjkh	    if (fgets(buf, sizeof(buf), fp) == NULL)
136319459Sjkh	    {
136419459Sjkh		break;
136519459Sjkh	    }
136619459Sjkh	    ++current_line_number;
136719459Sjkh	    status = process_line(buf);
136819459Sjkh	    if (status == 0)
136919459Sjkh	    {
137019459Sjkh		break;
137119459Sjkh	    }
137219459Sjkh	}
137319459Sjkh	break;
137419459Sjkh    }
137519459Sjkh    if (fp)
137619459Sjkh    {
137719459Sjkh	/*
137819459Sjkh	 * It doesn't matter if we're reading from stdin, as we've reached EOF
137919459Sjkh	 */
138019459Sjkh	fclose(fp);
138119459Sjkh    }
138219459Sjkh    return (status);
138319459Sjkh}
138419459Sjkh
138519459Sjkh
138619459Sjkhstatic void
138719459Sjkhreset_boot(void)
138819459Sjkh{
138919459Sjkh    int				i;
139019459Sjkh    struct dos_partition	*partp;
139119459Sjkh
139219459Sjkh    init_boot();
139319459Sjkh    for (i = 0; i < 4; ++i)
139419459Sjkh    {
139519459Sjkh	partp = ((struct dos_partition *) &mboot.parts) + i;
139619459Sjkh	bzero((char *)partp, sizeof (struct dos_partition));
139719459Sjkh    }
139819459Sjkh}
139965054Sjhb
140065054Sjhbstatic int
140165054Sjhbsanitize_partition(partp)
140265054Sjhb    struct dos_partition	*partp;
140365054Sjhb{
140465054Sjhb    u_int32_t			prev_head_boundary, prev_cyl_boundary;
140581164Siedowse    u_int32_t			max_end, size, start;
140665054Sjhb
140781164Siedowse    start = partp->dp_start;
140881164Siedowse    size = partp->dp_size;
140981164Siedowse    max_end = start + size;
141081164Siedowse    /* Only allow a zero size if the partition is being marked unused. */
141181164Siedowse    if (size == 0) {
141281164Siedowse	if (start == 0 && partp->dp_typ == 0)
141381164Siedowse	    return (1);
141481164Siedowse	warnx("ERROR: size of partition is zero");
141581164Siedowse	return (0);
141681164Siedowse    }
141781164Siedowse    /* Return if no adjustment is necessary. */
141881164Siedowse    if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0)
141981164Siedowse	return (1);
142065054Sjhb
142181164Siedowse    if (start % dos_sectors != 0)
142281164Siedowse	warnx("WARNING: partition does not start on a head boundary");
142381164Siedowse    if ((start  +size) % dos_sectors != 0)
142481164Siedowse	warnx("WARNING: partition does not end on a cylinder boundary");
142581164Siedowse    warnx("WARNING: this may confuse the BIOS or some operating systems");
142681164Siedowse    if (!ok("Correct this automatically?"))
142781164Siedowse	return (1);
142881164Siedowse
142965054Sjhb    /*
143065054Sjhb     * Adjust start upwards, if necessary, to fall on an head boundary.
143165054Sjhb     */
143281164Siedowse    if (start % dos_sectors != 0) {
143381164Siedowse	prev_head_boundary = start / dos_sectors * dos_sectors;
143465054Sjhb	if (max_end < dos_sectors ||
143581164Siedowse	    prev_head_boundary >= max_end - dos_sectors) {
143665054Sjhb	    /*
143765054Sjhb	     * Can't go past end of partition
143865054Sjhb	     */
143965054Sjhb	    warnx(
144065054Sjhb    "ERROR: unable to adjust start of partition to fall on a head boundary");
144165054Sjhb	    return (0);
144265054Sjhb        }
144381164Siedowse	start = prev_head_boundary + dos_sectors;
144465054Sjhb    }
144565054Sjhb
144665054Sjhb    /*
144765054Sjhb     * Adjust size downwards, if necessary, to fall on a cylinder
144865054Sjhb     * boundary.
144965054Sjhb     */
145081164Siedowse    prev_cyl_boundary = ((start + size) / dos_cylsecs) * dos_cylsecs;
145181164Siedowse    if (prev_cyl_boundary > start)
145281164Siedowse	size = prev_cyl_boundary - start;
145381164Siedowse    else {
145465054Sjhb	warnx("ERROR: could not adjust partition to start on a head boundary\n\
145565054Sjhb    and end on a cylinder boundary.");
145665054Sjhb	return (0);
145765054Sjhb    }
145881164Siedowse
145981164Siedowse    /* Finally, commit any changes to partp and return. */
146081164Siedowse    if (start != partp->dp_start) {
146181164Siedowse	warnx("WARNING: adjusting start offset of partition to %u",
146281164Siedowse	    (u_int)start);
146381164Siedowse	partp->dp_start = start;
146465054Sjhb    }
146581164Siedowse    if (size != partp->dp_size) {
146681164Siedowse	warnx("WARNING: adjusting size of partition to %u", (u_int)size);
146781164Siedowse	partp->dp_size = size;
146865054Sjhb    }
146965054Sjhb
147065054Sjhb    return (1);
147165054Sjhb}
147279681Sjoerg
147379681Sjoerg/*
147479681Sjoerg * Try figuring out the root device's canonical disk name.
147579681Sjoerg * The following choices are considered:
147679681Sjoerg *   /dev/ad0s1a     => /dev/ad0
147779681Sjoerg *   /dev/da0a       => /dev/da0
147879681Sjoerg *   /dev/vinum/root => /dev/vinum/root
147979681Sjoerg */
148079681Sjoergstatic char *
148179681Sjoergget_rootdisk(void)
148279681Sjoerg{
148379681Sjoerg	struct statfs rootfs;
148479681Sjoerg	regex_t re;
148579681Sjoerg#define NMATCHES 2
148679681Sjoerg	regmatch_t rm[NMATCHES];
148779681Sjoerg	char *s;
148879681Sjoerg	int rv;
148979681Sjoerg
149079681Sjoerg	if (statfs("/", &rootfs) == -1)
149179681Sjoerg		err(1, "statfs(\"/\")");
149279681Sjoerg
149379681Sjoerg	if ((rv = regcomp(&re, "^(/dev/.*)(\\d+(s\\d+)?[a-h])?$",
149479681Sjoerg		    REG_EXTENDED)) != 0)
149579681Sjoerg		errx(1, "regcomp() failed (%d)", rv);
149679681Sjoerg	if ((rv = regexec(&re, rootfs.f_mntfromname, NMATCHES, rm, 0)) != 0)
149779681Sjoerg		errx(1,
149879681Sjoerg"mounted root fs resource doesn't match expectations (regexec returned %d)",
149979681Sjoerg		    rv);
150079681Sjoerg	if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL)
150179681Sjoerg		errx(1, "out of memory");
150279681Sjoerg	memcpy(s, rootfs.f_mntfromname + rm[1].rm_so,
150379681Sjoerg	    rm[1].rm_eo - rm[1].rm_so);
150479681Sjoerg	s[rm[1].rm_eo - rm[1].rm_so] = 0;
150579681Sjoerg
150679681Sjoerg	return s;
150779681Sjoerg}
1508