fdisk.c revision 104272
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 104272 2002-10-01 07:24:55Z phk $";
3037415Scharnier#endif /* not lint */
3137415Scharnier
32103348Sphk#include <sys/disk.h>
334Srgrimes#include <sys/disklabel.h>
34104272Sphk#include <sys/diskmbr.h>
3579681Sjoerg#include <sys/param.h>
3637415Scharnier#include <sys/stat.h>
3779681Sjoerg#include <sys/mount.h>
3837415Scharnier#include <ctype.h>
3937415Scharnier#include <fcntl.h>
4037415Scharnier#include <err.h>
4137415Scharnier#include <errno.h>
4279681Sjoerg#include <paths.h>
4379681Sjoerg#include <regex.h>
44100202Sbde#include <stdint.h>
454Srgrimes#include <stdio.h>
4637415Scharnier#include <stdlib.h>
4716561Salex#include <string.h>
4816561Salex#include <unistd.h>
494Srgrimes
504Srgrimesint iotest;
514Srgrimes
524Srgrimes#define LBUF 100
534Srgrimesstatic char lbuf[LBUF];
544Srgrimes
5563027Sjhb#define MBRSIGOFF	510
5663027Sjhb
574Srgrimes/*
584Srgrimes *
594Srgrimes * Ported to 386bsd by Julian Elischer  Thu Oct 15 20:26:46 PDT 1992
604Srgrimes *
614Srgrimes * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
624Srgrimes *	Copyright (c) 1989	Robert. V. Baron
634Srgrimes *	Created.
644Srgrimes */
654Srgrimes
664Srgrimes#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp
674Srgrimes
684Srgrimes#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
694Srgrimes
7020061Ssos#define MAX_SEC_SIZE 2048	/* maximum section size that is supported */
7120061Ssos#define MIN_SEC_SIZE 512	/* the sector size to start sensing at */
7293394Sphkstatic int secsize = 0;		/* the sensed sector size */
734Srgrimes
7493394Sphkstatic char *disk;
7510514Sjoerg
7693394Sphkstatic struct disklabel disklabel;		/* disk parameters */
774Srgrimes
7893394Sphkstatic int cyls, sectors, heads, cylsecs, disksecs;
794Srgrimes
8093394Sphkstruct mboot {
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};
864Srgrimes
8793394Sphkstatic struct mboot mboot;
8893394Sphkstatic int fd;
8993394Sphk
904Srgrimes#define ACTIVE 0x80
914Srgrimes#define BOOT_MAGIC 0xAA55
924Srgrimes
9393394Sphkstatic uint dos_cyls;
9493394Sphkstatic uint dos_heads;
9593394Sphkstatic uint dos_sectors;
9693394Sphkstatic uint dos_cylsecs;
974Srgrimes
984Srgrimes#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
994Srgrimes#define DOSCYL(c)	(c & 0xff)
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
10919459Sjkhtypedef struct cmd {
11019459Sjkh    char		cmd;
11119459Sjkh    int			n_args;
11219459Sjkh    struct arg {
11319459Sjkh	char	argtype;
11419459Sjkh	int	arg_val;
11519459Sjkh    }			args[MAX_ARGS];
11619459Sjkh} CMD;
11719459Sjkh
11848282Srnordierstatic int B_flag  = 0;		/* replace boot code */
11957896Simpstatic int I_flag  = 0;		/* use entire disk for FreeBSD */
1204Srgrimesstatic int a_flag  = 0;		/* set active partition */
12148282Srnordierstatic char *b_flag = NULL;	/* path to boot code */
1224Srgrimesstatic int i_flag  = 0;		/* replace partition data */
1234Srgrimesstatic int u_flag  = 0;		/* update partition data */
12457896Simpstatic int s_flag  = 0;		/* Print a summary and exit */
12595002Strhodesstatic int t_flag  = 0;		/* test only */
12619459Sjkhstatic char *f_flag = NULL;	/* Read config info from file */
12719459Sjkhstatic int v_flag  = 0;		/* Be verbose */
1284Srgrimes
12993394Sphkstatic struct part_type
1304Srgrimes{
1314Srgrimes unsigned char type;
13293394Sphk	const char *name;
13393394Sphk} part_types[] = {
1348871Srgrimes	 {0x00, "unused"}
1358871Srgrimes	,{0x01, "Primary DOS with 12 bit FAT"}
136102231Strhodes	,{0x02, "XENIX / file system"}
137102231Strhodes	,{0x03, "XENIX /usr file system"}
13890866Sjoe	,{0x04, "Primary DOS with 16 bit FAT (< 32MB)"}
1398871Srgrimes	,{0x05, "Extended DOS"}
14090866Sjoe	,{0x06, "Primary 'big' DOS (>= 32MB)"}
14161461Sghelmer	,{0x07, "OS/2 HPFS, NTFS, QNX-2 (16 bit) or Advanced UNIX"}
142102231Strhodes	,{0x08, "AIX file system or SplitDrive"}
1438871Srgrimes	,{0x09, "AIX boot partition or Coherent"}
14490866Sjoe	,{0x0A, "OS/2 Boot Manager, OPUS or Coherent swap"}
14534582Sache	,{0x0B, "DOS or Windows 95 with 32 bit FAT"}
14690866Sjoe	,{0x0C, "DOS or Windows 95 with 32 bit FAT (LBA)"}
14790866Sjoe	,{0x0E, "Primary 'big' DOS (>= 32MB, LBA)"}
14890866Sjoe	,{0x0F, "Extended DOS (LBA)"}
1498871Srgrimes	,{0x10, "OPUS"}
15090866Sjoe	,{0x11, "OS/2 BM: hidden DOS with 12-bit FAT"}
15190866Sjoe	,{0x12, "Compaq diagnostics"}
15290866Sjoe	,{0x14, "OS/2 BM: hidden DOS with 16-bit FAT (< 32MB)"}
15390866Sjoe	,{0x16, "OS/2 BM: hidden DOS with 16-bit FAT (>= 32MB)"}
15490866Sjoe	,{0x17, "OS/2 BM: hidden IFS (e.g. HPFS)"}
15590866Sjoe	,{0x18, "AST Windows swapfile"}
15690866Sjoe	,{0x24, "NEC DOS"}
15790866Sjoe	,{0x3C, "PartitionMagic recovery"}
15861568Sbrian	,{0x39, "plan9"}
1598871Srgrimes	,{0x40, "VENIX 286"}
16090866Sjoe	,{0x41, "Linux/MINIX (sharing disk with DRDOS)"}
16190866Sjoe	,{0x42, "SFS or Linux swap (sharing disk with DRDOS)"}
16290866Sjoe	,{0x43, "Linux native (sharing disk with DRDOS)"}
16361461Sghelmer	,{0x4D, "QNX 4.2 Primary"}
16461461Sghelmer	,{0x4E, "QNX 4.2 Secondary"}
16561461Sghelmer	,{0x4F, "QNX 4.2 Tertiary"}
16690866Sjoe	,{0x50, "DM (disk manager)"}
16790866Sjoe	,{0x51, "DM6 Aux1 (or Novell)"}
1688871Srgrimes	,{0x52, "CP/M or Microport SysV/AT"}
16990866Sjoe	,{0x53, "DM6 Aux3"}
17090866Sjoe	,{0x54, "DM6"}
17190866Sjoe	,{0x55, "EZ-Drive (disk manager)"}
17290866Sjoe	,{0x56, "Golden Bow (disk manager)"}
17390866Sjoe	,{0x5c, "Priam Edisk (disk manager)"} /* according to S. Widlake */
17490866Sjoe	,{0x61, "SpeedStor"}
17590866Sjoe	,{0x63, "System V/386 (such as ISC UNIX), GNU HURD or Mach"}
17690866Sjoe	,{0x64, "Novell Netware/286 2.xx"}
17790866Sjoe	,{0x65, "Novell Netware/386 3.xx"}
17890866Sjoe	,{0x70, "DiskSecure Multi-Boot"}
1798871Srgrimes	,{0x75, "PCIX"}
18090866Sjoe	,{0x77, "QNX4.x"}
18190866Sjoe	,{0x78, "QNX4.x 2nd part"}
18290866Sjoe	,{0x79, "QNX4.x 3rd part"}
18390866Sjoe	,{0x80, "Minix until 1.4a"}
18493394Sphk	,{0x81, "Minix since 1.4b, early Linux partition or Mitac disk manager"}
18539377Sobrien	,{0x82, "Linux swap or Solaris x86"}
18690866Sjoe	,{0x83, "Linux native"}
18790866Sjoe	,{0x84, "OS/2 hidden C: drive"}
18890866Sjoe	,{0x85, "Linux extended"}
18990866Sjoe	,{0x86, "NTFS volume set??"}
19090866Sjoe	,{0x87, "NTFS volume set??"}
191102231Strhodes	,{0x93, "Amoeba file system"}
1928871Srgrimes	,{0x94, "Amoeba bad block table"}
19340946Sjkoshy	,{0x9F, "BSD/OS"}
19464316Sjoe	,{0xA0, "Suspend to Disk"}
1958871Srgrimes	,{0xA5, "FreeBSD/NetBSD/386BSD"}
19625378Simp	,{0xA6, "OpenBSD"}
19790866Sjoe	,{0xA7, "NeXTSTEP"}
19840947Salex	,{0xA9, "NetBSD"}
19995602Sgrog	,{0xAC, "IBM JFS"}
200102231Strhodes	,{0xB7, "BSDI BSD/386 file system"}
2018871Srgrimes	,{0xB8, "BSDI BSD/386 swap"}
20290866Sjoe	,{0xC1, "DRDOS/sec with 12-bit FAT"}
20390866Sjoe	,{0xC4, "DRDOS/sec with 16-bit FAT (< 32MB)"}
20490866Sjoe	,{0xC6, "DRDOS/sec with 16-bit FAT (>= 32MB)"}
20590866Sjoe	,{0xC7, "Syrinx"}
20690866Sjoe	,{0xDB, "CP/M, Concurrent CP/M, Concurrent DOS or CTOS"}
20790866Sjoe	,{0xE1, "DOS access or SpeedStor with 12-bit FAT extended partition"}
20890866Sjoe	,{0xE3, "DOS R/O or SpeedStor"}
20990866Sjoe	,{0xE4, "SpeedStor with 16-bit FAT extended partition < 1024 cyl."}
210102231Strhodes	,{0xEB, "BeOS file system"}
21184964Speter	,{0xEE, "EFI GPT"}
21285027Sbde	,{0xEF, "EFI System Partition"}
21390866Sjoe	,{0xF1, "SpeedStor"}
2148871Srgrimes	,{0xF2, "DOS 3.3+ Secondary"}
21590866Sjoe	,{0xF4, "SpeedStor large partition"}
21690866Sjoe	,{0xFE, "SpeedStor >1024 cyl. or LANstep"}
21790866Sjoe	,{0xFF, "Xenix bad blocks table"}
2184Srgrimes};
2194Srgrimes
22016561Salexstatic void print_s0(int which);
22116561Salexstatic void print_part(int i);
22216561Salexstatic void init_sector0(unsigned long start);
22319459Sjkhstatic void init_boot(void);
22416561Salexstatic void change_part(int i);
22593394Sphkstatic void print_params(void);
22616561Salexstatic void change_active(int which);
22793394Sphkstatic void change_code(void);
22893394Sphkstatic void get_params_to_use(void);
22979681Sjoergstatic char *get_rootdisk(void);
23081164Siedowsestatic void dos(struct dos_partition *partp);
23193394Sphkstatic int open_disk(int flag);
23216561Salexstatic ssize_t read_disk(off_t sector, void *buf);
23316561Salexstatic ssize_t write_disk(off_t sector, void *buf);
23493394Sphkstatic int get_params(void);
23593394Sphkstatic int read_s0(void);
23693394Sphkstatic int write_s0(void);
23793394Sphkstatic int ok(const char *str);
23893394Sphkstatic int decimal(const char *str, int *num, int deflt);
23993394Sphkstatic const char *get_type(int type);
24019459Sjkhstatic int read_config(char *config_file);
24119459Sjkhstatic void reset_boot(void);
24265054Sjhbstatic int sanitize_partition(struct dos_partition *);
24337415Scharnierstatic void usage(void);
2444Srgrimes
24516561Salexint
24616561Salexmain(int argc, char *argv[])
2474Srgrimes{
24879681Sjoerg	struct	stat sb;
24948282Srnordier	int	c, i;
25093394Sphk	int	partition = -1;
25193394Sphk	struct	dos_partition *partp;
2524Srgrimes
25357896Simp	while ((c = getopt(argc, argv, "BIab:f:istuv1234")) != -1)
25448282Srnordier		switch (c) {
25548282Srnordier		case 'B':
25648282Srnordier			B_flag = 1;
2574Srgrimes			break;
25857896Simp		case 'I':
25957896Simp			I_flag = 1;
26057896Simp			break;
26148282Srnordier		case 'a':
26248282Srnordier			a_flag = 1;
26348282Srnordier			break;
26448282Srnordier		case 'b':
26548282Srnordier			b_flag = optarg;
26648282Srnordier			break;
26748282Srnordier		case 'f':
26848282Srnordier			f_flag = optarg;
26948282Srnordier			break;
27048282Srnordier		case 'i':
27148282Srnordier			i_flag = 1;
27248282Srnordier			break;
27357896Simp		case 's':
27457896Simp			s_flag = 1;
27557896Simp			break;
27648282Srnordier		case 't':
27748282Srnordier			t_flag = 1;
27848282Srnordier			break;
27948282Srnordier		case 'u':
28048282Srnordier			u_flag = 1;
28148282Srnordier			break;
28248282Srnordier		case 'v':
28348282Srnordier			v_flag = 1;
28448282Srnordier			break;
28548282Srnordier		case '1':
28648282Srnordier		case '2':
28748282Srnordier		case '3':
28848282Srnordier		case '4':
28948282Srnordier			partition = c - '0';
29048282Srnordier			break;
29148282Srnordier		default:
29248282Srnordier			usage();
2934Srgrimes		}
29448282Srnordier	if (f_flag || i_flag)
29548282Srnordier		u_flag = 1;
29648282Srnordier	if (t_flag)
29748282Srnordier		v_flag = 1;
29848282Srnordier	argc -= optind;
29948282Srnordier	argv += optind;
3004Srgrimes
30179681Sjoerg	if (argc == 0) {
30279681Sjoerg		disk = get_rootdisk();
30379681Sjoerg	} else {
30479681Sjoerg		if (stat(argv[0], &sb) == 0) {
30579681Sjoerg			/* OK, full pathname given */
30610514Sjoerg			disk = argv[0];
30779681Sjoerg		} else if (errno == ENOENT) {
30879681Sjoerg			/* Try prepending "/dev" */
30993394Sphk			asprintf(&disk, "%s%s", _PATH_DEV, argv[0]);
31093394Sphk			if (disk == NULL)
31179681Sjoerg				errx(1, "out of memory");
31279681Sjoerg		} else {
31379681Sjoerg			/* other stat error, let it fail below */
31479681Sjoerg			disk = argv[0];
31510514Sjoerg		}
31610514Sjoerg	}
31779681Sjoerg	if (open_disk(u_flag) < 0)
31879681Sjoerg		err(1, "cannot open disk %s", disk);
3194Srgrimes
32063027Sjhb	/* (abu)use mboot.bootinst to probe for the sector size */
32163027Sjhb	if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL)
32263027Sjhb		err(1, "cannot allocate buffer to determine disk sector size");
32363027Sjhb	read_disk(0, mboot.bootinst);
32463329Sjhb	free(mboot.bootinst);
32563329Sjhb	mboot.bootinst = NULL;
32663027Sjhb
32793394Sphk	if (s_flag) {
32857896Simp		if (read_s0())
32957896Simp			err(1, "read_s0");
33057896Simp		printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads,
33157896Simp		    dos_sectors);
33257896Simp		printf("Part  %11s %11s Type Flags\n", "Start", "Size");
33357896Simp		for (i = 0; i < NDOSPART; i++) {
33457896Simp			partp = ((struct dos_partition *) &mboot.parts) + i;
33557896Simp			if (partp->dp_start == 0 && partp->dp_size == 0)
33657896Simp				continue;
33757896Simp			printf("%4d: %11lu %11lu 0x%02x 0x%02x\n", i + 1,
33857896Simp			    (u_long) partp->dp_start,
33957896Simp			    (u_long) partp->dp_size, partp->dp_typ,
34057896Simp			    partp->dp_flag);
34157896Simp		}
34257896Simp		exit(0);
34357896Simp	}
34457896Simp
3454Srgrimes	printf("******* Working on device %s *******\n",disk);
34619459Sjkh
34793394Sphk	if (I_flag) {
34850215Sphk		read_s0();
34950215Sphk		reset_boot();
35050215Sphk		partp = (struct dos_partition *) (&mboot.parts[0]);
35150215Sphk		partp->dp_typ = DOSPTYP_386BSD;
35250215Sphk		partp->dp_flag = ACTIVE;
35350215Sphk		partp->dp_start = dos_sectors;
35465054Sjhb		partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs -
35565054Sjhb		    dos_sectors;
35681164Siedowse		dos(partp);
35750215Sphk		if (v_flag)
35850215Sphk			print_s0(-1);
35995002Strhodes		if (!t_flag)
36095002Strhodes			write_s0();
36150215Sphk		exit(0);
36250215Sphk	}
36393394Sphk	if (f_flag) {
36419459Sjkh	    if (read_s0() || i_flag)
36519459Sjkh		reset_boot();
36619459Sjkh	    if (!read_config(f_flag))
36719459Sjkh		exit(1);
36819459Sjkh	    if (v_flag)
36919459Sjkh		print_s0(-1);
37019459Sjkh	    if (!t_flag)
37119459Sjkh		write_s0();
37293394Sphk	} else {
37319459Sjkh	    if(u_flag)
37419459Sjkh		get_params_to_use();
37519459Sjkh	    else
3764Srgrimes		print_params();
3774Srgrimes
37819459Sjkh	    if (read_s0())
37965054Sjhb		init_sector0(dos_sectors);
3804Srgrimes
38120061Ssos	    printf("Media sector size is %d\n", secsize);
38219459Sjkh	    printf("Warning: BIOS sector numbering starts with sector 1\n");
38319459Sjkh	    printf("Information from DOS bootblock is:\n");
38419459Sjkh	    if (partition == -1)
38526421Sbrian		for (i = 1; i <= NDOSPART; i++)
38619459Sjkh		    change_part(i);
38719459Sjkh	    else
3884Srgrimes		change_part(partition);
3894Srgrimes
39019459Sjkh	    if (u_flag || a_flag)
3914Srgrimes		change_active(partition);
3924Srgrimes
39348282Srnordier	    if (B_flag)
39443054Srnordier		change_code();
39543054Srnordier
39648282Srnordier	    if (u_flag || a_flag || B_flag) {
39795002Strhodes		if (!t_flag) {
39819459Sjkh		    printf("\nWe haven't changed the partition table yet.  ");
39919459Sjkh		    printf("This is your last chance.\n");
40019459Sjkh		}
4014Srgrimes		print_s0(-1);
40295002Strhodes		if (!t_flag) {
40319459Sjkh		    if (ok("Should we write new partition table?"))
4044Srgrimes			write_s0();
40593394Sphk			} else {
40619459Sjkh		    printf("\n-t flag specified -- partition table not written.\n");
40719459Sjkh		}
40819459Sjkh	    }
4094Srgrimes	}
4104Srgrimes
4114Srgrimes	exit(0);
41237415Scharnier}
4134Srgrimes
41437415Scharnierstatic void
41537415Scharnierusage()
41637415Scharnier{
41748282Srnordier	fprintf(stderr, "%s%s",
41862178Sjhb		"usage: fdisk [-BIaistu] [-b bootcode] [-1234] [disk]\n",
41948282Srnordier 		"       fdisk -f configfile [-itv] [disk]\n");
42037415Scharnier        exit(1);
4214Srgrimes}
4224Srgrimes
42316561Salexstatic void
42416561Salexprint_s0(int which)
4254Srgrimes{
42693394Sphk	int	i;
4274Srgrimes
4284Srgrimes	print_params();
4294Srgrimes	printf("Information from DOS bootblock is:\n");
4304Srgrimes	if (which == -1)
43126421Sbrian		for (i = 1; i <= NDOSPART; i++)
4324Srgrimes			printf("%d: ", i), print_part(i);
4334Srgrimes	else
4344Srgrimes		print_part(which);
4354Srgrimes}
4364Srgrimes
43793394Sphkstatic struct dos_partition mtpart;
4384Srgrimes
43916561Salexstatic void
44016561Salexprint_part(int i)
4414Srgrimes{
44226389Sgibbs	struct	  dos_partition *partp;
44326389Sgibbs	u_int64_t part_mb;
4444Srgrimes
44526421Sbrian	partp = ((struct dos_partition *) &mboot.parts) + i - 1;
4464Srgrimes
4474Srgrimes	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
4484Srgrimes		printf("<UNUSED>\n");
4494Srgrimes		return;
4504Srgrimes	}
45126389Sgibbs	/*
45226389Sgibbs	 * Be careful not to overflow.
45326389Sgibbs	 */
45426389Sgibbs	part_mb = partp->dp_size;
45526389Sgibbs	part_mb *= secsize;
45626389Sgibbs	part_mb /= (1024 * 1024);
45790866Sjoe	printf("sysid %d (%#04x),(%s)\n", partp->dp_typ, partp->dp_typ,
45890866Sjoe	    get_type(partp->dp_typ));
459100202Sbde	printf("    start %lu, size %lu (%ju Meg), flag %x%s\n",
46037244Sbde		(u_long)partp->dp_start,
46137244Sbde		(u_long)partp->dp_size,
462100202Sbde		(uintmax_t)part_mb,
46334952Sobrien		partp->dp_flag,
46434952Sobrien		partp->dp_flag == ACTIVE ? " (active)" : "");
46569371Sobrien	printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n"
4664Srgrimes		,DPCYL(partp->dp_scyl, partp->dp_ssect)
46769371Sobrien		,partp->dp_shd
4684Srgrimes		,DPSECT(partp->dp_ssect)
4694Srgrimes		,DPCYL(partp->dp_ecyl, partp->dp_esect)
47069371Sobrien		,partp->dp_ehd
47169371Sobrien		,DPSECT(partp->dp_esect));
4724Srgrimes}
4734Srgrimes
47419459Sjkh
47516561Salexstatic void
47619459Sjkhinit_boot(void)
47719459Sjkh{
47895860Speter#ifndef __ia64__
47948282Srnordier	const char *fname;
48093394Sphk	int fdesc, n;
48163027Sjhb	struct stat sb;
48248282Srnordier
48348282Srnordier	fname = b_flag ? b_flag : "/boot/mbr";
48493394Sphk	if ((fdesc = open(fname, O_RDONLY)) == -1 ||
48593394Sphk	    fstat(fdesc, &sb) == -1)
48663027Sjhb		err(1, "%s", fname);
48763027Sjhb	if ((mboot.bootinst_size = sb.st_size) % secsize != 0)
48863027Sjhb		errx(1, "%s: length must be a multiple of sector size", fname);
48963218Sache	if (mboot.bootinst != NULL)
49063218Sache		free(mboot.bootinst);
49163027Sjhb	if ((mboot.bootinst = malloc(mboot.bootinst_size = sb.st_size)) == NULL)
49263027Sjhb		errx(1, "%s: unable to allocate read buffer", fname);
49393394Sphk	if ((n = read(fdesc, mboot.bootinst, mboot.bootinst_size)) == -1 ||
49493394Sphk	    close(fdesc))
49548282Srnordier		err(1, "%s", fname);
49663027Sjhb	if (n != mboot.bootinst_size)
49763027Sjhb		errx(1, "%s: short read", fname);
49895860Speter#else
49995860Speter	if (mboot.bootinst != NULL)
50095860Speter		free(mboot.bootinst);
50195860Speter	mboot.bootinst_size = secsize;
50295860Speter	if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL)
50395860Speter		errx(1, "unable to allocate boot block buffer");
50495860Speter	memset(mboot.bootinst, 0, mboot.bootinst_size);
505100202Sbde	*(uint16_t *)(void *)&mboot.bootinst[MBRSIGOFF] = BOOT_MAGIC;
50695860Speter#endif
50719459Sjkh}
50819459Sjkh
50919459Sjkh
51019459Sjkhstatic void
51116561Salexinit_sector0(unsigned long start)
5124Srgrimes{
51393394Sphk	struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
5144Srgrimes
51519459Sjkh	init_boot();
5164Srgrimes
5174Srgrimes	partp->dp_typ = DOSPTYP_386BSD;
5184Srgrimes	partp->dp_flag = ACTIVE;
51965054Sjhb	start = ((start + dos_sectors - 1) / dos_sectors) * dos_sectors;
52063027Sjhb	if(start == 0)
52163027Sjhb		start = dos_sectors;
5224Srgrimes	partp->dp_start = start;
52365054Sjhb	partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - start;
5244Srgrimes
52581164Siedowse	dos(partp);
5264Srgrimes}
5274Srgrimes
52816561Salexstatic void
52916561Salexchange_part(int i)
5304Srgrimes{
53193394Sphk	struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1;
5324Srgrimes
5334Srgrimes    printf("The data for partition %d is:\n", i);
5344Srgrimes    print_part(i);
5354Srgrimes
5364Srgrimes    if (u_flag && ok("Do you want to change it?")) {
5374Srgrimes	int tmp;
5384Srgrimes
5394Srgrimes	if (i_flag) {
5404Srgrimes		bzero((char *)partp, sizeof (struct dos_partition));
54126421Sbrian		if (i == 4) {
5424Srgrimes			init_sector0(1);
54326421Sbrian			printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n");
5444Srgrimes			print_part(i);
5454Srgrimes		}
5464Srgrimes	}
5474Srgrimes
5484Srgrimes	do {
54934952Sobrien		Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp);
5504Srgrimes		Decimal("start", partp->dp_start, tmp);
5514Srgrimes		Decimal("size", partp->dp_size, tmp);
55281164Siedowse		if (!sanitize_partition(partp)) {
55381164Siedowse			warnx("ERROR: failed to adjust; setting sysid to 0");
55481164Siedowse			partp->dp_typ = 0;
55581164Siedowse		}
5564Srgrimes
55736262Sjraynard		if (ok("Explicitly specify beg/end address ?"))
5584Srgrimes		{
5594Srgrimes			int	tsec,tcyl,thd;
5604Srgrimes			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
5614Srgrimes			thd = partp->dp_shd;
5624Srgrimes			tsec = DPSECT(partp->dp_ssect);
5634Srgrimes			Decimal("beginning cylinder", tcyl, tmp);
56469371Sobrien			Decimal("beginning head", thd, tmp);
56568871Sobrien			Decimal("beginning sector", tsec, tmp);
5664Srgrimes			partp->dp_scyl = DOSCYL(tcyl);
5674Srgrimes			partp->dp_ssect = DOSSECT(tsec,tcyl);
5684Srgrimes			partp->dp_shd = thd;
5694Srgrimes
5704Srgrimes			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
5714Srgrimes			thd = partp->dp_ehd;
5724Srgrimes			tsec = DPSECT(partp->dp_esect);
5734Srgrimes			Decimal("ending cylinder", tcyl, tmp);
57469371Sobrien			Decimal("ending head", thd, tmp);
57568871Sobrien			Decimal("ending sector", tsec, tmp);
5764Srgrimes			partp->dp_ecyl = DOSCYL(tcyl);
5774Srgrimes			partp->dp_esect = DOSSECT(tsec,tcyl);
5784Srgrimes			partp->dp_ehd = thd;
57981164Siedowse		} else
58081164Siedowse			dos(partp);
5818871Srgrimes
5824Srgrimes		print_part(i);
5834Srgrimes	} while (!ok("Are we happy with this entry?"));
5844Srgrimes    }
58593394Sphk    }
5864Srgrimes
58716561Salexstatic void
5884Srgrimesprint_params()
5894Srgrimes{
5904Srgrimes	printf("parameters extracted from in-core disklabel are:\n");
5914Srgrimes	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
5924Srgrimes			,cyls,heads,sectors,cylsecs);
5934Srgrimes	if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
59420061Ssos		printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
5954Srgrimes	printf("parameters to be used for BIOS calculations are:\n");
5964Srgrimes	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
5974Srgrimes		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
5984Srgrimes}
5994Srgrimes
60016561Salexstatic void
60116561Salexchange_active(int which)
6024Srgrimes{
60381164Siedowse	struct dos_partition *partp = &mboot.parts[0];
60481164Siedowse	int active, i, new, tmp;
6054Srgrimes
60681164Siedowse	active = -1;
60781164Siedowse	for (i = 0; i < NDOSPART; i++) {
60881164Siedowse		if ((partp[i].dp_flag & ACTIVE) == 0)
60981164Siedowse			continue;
61081164Siedowse		printf("Partition %d is marked active\n", i + 1);
61181164Siedowse		if (active == -1)
61281164Siedowse			active = i + 1;
61381164Siedowse	}
6144Srgrimes	if (a_flag && which != -1)
6154Srgrimes		active = which;
61681164Siedowse	else if (active == -1)
61781164Siedowse		active = 1;
61881164Siedowse
6193723Sbde	if (!ok("Do you want to change the active partition?"))
6203723Sbde		return;
62134952Sobriensetactive:
62234952Sobrien	do {
62381164Siedowse		new = active;
62481164Siedowse		Decimal("active partition", new, tmp);
62581164Siedowse		if (new < 1 || new > 4) {
62634952Sobrien			printf("Active partition number must be in range 1-4."
62734952Sobrien					"  Try again.\n");
62834952Sobrien			goto setactive;
62934952Sobrien		}
63081164Siedowse		active = new;
63134952Sobrien	} while (!ok("Are you happy with this choice"));
6324Srgrimes	for (i = 0; i < NDOSPART; i++)
6334Srgrimes		partp[i].dp_flag = 0;
63426421Sbrian	if (active > 0 && active <= NDOSPART)
63526421Sbrian		partp[active-1].dp_flag = ACTIVE;
6364Srgrimes}
6374Srgrimes
63843054Srnordierstatic void
63943054Srnordierchange_code()
64043054Srnordier{
64143054Srnordier	if (ok("Do you want to change the boot code?"))
64243054Srnordier		init_boot();
64343054Srnordier}
64443054Srnordier
64516561Salexvoid
6464Srgrimesget_params_to_use()
6474Srgrimes{
6484Srgrimes	int	tmp;
6494Srgrimes	print_params();
6504Srgrimes	if (ok("Do you want to change our idea of what BIOS thinks ?"))
6514Srgrimes	{
6524Srgrimes		do
6534Srgrimes		{
6544Srgrimes			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
6554Srgrimes			Decimal("BIOS's idea of #heads", dos_heads, tmp);
6564Srgrimes			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
6574Srgrimes			dos_cylsecs = dos_heads * dos_sectors;
6584Srgrimes			print_params();
6594Srgrimes		}
6604Srgrimes		while(!ok("Are you happy with this choice"));
6614Srgrimes	}
6624Srgrimes}
6634Srgrimes
66419459Sjkh
6654Srgrimes/***********************************************\
6664Srgrimes* Change real numbers into strange dos numbers	*
6674Srgrimes\***********************************************/
66816561Salexstatic void
66993394Sphkdos(struct dos_partition *partp)
6704Srgrimes{
67181164Siedowse	int cy, sec;
67281164Siedowse	u_int32_t end;
6734Srgrimes
67488714Siedowse	if (partp->dp_typ == 0 && partp->dp_start == 0 && partp->dp_size == 0) {
67588714Siedowse		memcpy(partp, &mtpart, sizeof(*partp));
6763723Sbde		return;
6773723Sbde	}
6783723Sbde
67981164Siedowse	/* Start c/h/s. */
68081164Siedowse	partp->dp_shd = partp->dp_start % dos_cylsecs / dos_sectors;
68181164Siedowse	cy = partp->dp_start / dos_cylsecs;
68281164Siedowse	sec = partp->dp_start % dos_sectors + 1;
68381164Siedowse	partp->dp_scyl = DOSCYL(cy);
68481164Siedowse	partp->dp_ssect = DOSSECT(sec, cy);
6854Srgrimes
68681164Siedowse	/* End c/h/s. */
68781164Siedowse	end = partp->dp_start + partp->dp_size - 1;
68881164Siedowse	partp->dp_ehd = end % dos_cylsecs / dos_sectors;
68981164Siedowse	cy = end / dos_cylsecs;
69081164Siedowse	sec = end % dos_sectors + 1;
69181164Siedowse	partp->dp_ecyl = DOSCYL(cy);
69281164Siedowse	partp->dp_esect = DOSSECT(sec, cy);
6934Srgrimes}
6944Srgrimes
69516561Salexstatic int
69693394Sphkopen_disk(int flag)
6974Srgrimes{
69879306Sjoerg	struct stat 	st;
6994Srgrimes
7008871Srgrimes	if (stat(disk, &st) == -1) {
70179306Sjoerg		if (errno == ENOENT)
70279306Sjoerg			return -2;
70337415Scharnier		warnx("can't get file status of %s", disk);
7044Srgrimes		return -1;
7052810Sbde	}
7062810Sbde	if ( !(st.st_mode & S_IFCHR) )
70737415Scharnier		warnx("device %s is not character special", disk);
70843054Srnordier	if ((fd = open(disk,
70993394Sphk	    a_flag || I_flag || B_flag || flag ? O_RDWR : O_RDONLY)) == -1) {
71010514Sjoerg		if(errno == ENXIO)
71110514Sjoerg			return -2;
71237415Scharnier		warnx("can't open device %s", disk);
7134Srgrimes		return -1;
7144Srgrimes	}
71593394Sphk	if (get_params() == -1) {
71637415Scharnier		warnx("can't get disk parameters on %s", disk);
7174Srgrimes		return -1;
7184Srgrimes	}
7194Srgrimes	return fd;
7204Srgrimes}
7214Srgrimes
72216561Salexstatic ssize_t
72316561Salexread_disk(off_t sector, void *buf)
7244Srgrimes{
7254Srgrimes	lseek(fd,(sector * 512), 0);
72620061Ssos	if( secsize == 0 )
72720061Ssos		for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 )
72820061Ssos			{
72920061Ssos			/* try the read */
73020061Ssos			int size = read(fd, buf, secsize);
73120061Ssos			if( size == secsize )
73220061Ssos				/* it worked so return */
73320061Ssos				return secsize;
73420061Ssos			}
73520061Ssos	else
73620061Ssos		return read( fd, buf, secsize );
73720061Ssos
73820061Ssos	/* we failed to read at any of the sizes */
73920061Ssos	return -1;
7404Srgrimes}
7414Srgrimes
74216561Salexstatic ssize_t
74316561Salexwrite_disk(off_t sector, void *buf)
7444Srgrimes{
7454Srgrimes	lseek(fd,(sector * 512), 0);
74620061Ssos	/* write out in the size that the read_disk found worked */
74720061Ssos	return write(fd, buf, secsize);
7484Srgrimes}
7494Srgrimes
75016561Salexstatic int
75116561Salexget_params()
7524Srgrimes{
753103665Sphk	int error;
754103665Sphk	u_int u;
755103665Sphk	off_t o;
7564Srgrimes
757103665Sphk	if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
758103665Sphk		warnx("can't get disk parameters on %s; supplying dummy ones", disk);
759103665Sphk		dos_cyls = cyls = 1;
760103665Sphk		dos_heads = heads = 1;
761103665Sphk		dos_sectors = sectors = 1;
762103665Sphk		dos_cylsecs = cylsecs = heads * sectors;
763103665Sphk		disksecs = cyls * heads * sectors;
764103665Sphk	} else {
765103665Sphk		dos_cyls = cyls = disklabel.d_ncylinders;
766103665Sphk		dos_heads = heads = disklabel.d_ntracks;
767103665Sphk		dos_sectors = sectors = disklabel.d_nsectors;
768103665Sphk	}
769103665Sphk	error = ioctl(fd, DIOCGFWSECTORS, &u);
770103665Sphk	if (error == 0)
771103665Sphk		sectors = dos_sectors = u;
772103665Sphk	error = ioctl(fd, DIOCGFWHEADS, &u);
773103665Sphk	if (error == 0)
774103665Sphk		heads = dos_heads = u;
775103665Sphk
7762810Sbde	dos_cylsecs = cylsecs = heads * sectors;
7772810Sbde	disksecs = cyls * heads * sectors;
7784Srgrimes
779103665Sphk	error = ioctl(fd, DIOCGSECTORSIZE, &u);
780103665Sphk	if (error != 0)
781103665Sphk		u = 512;
7824Srgrimes
783103665Sphk	error = ioctl(fd, DIOCGMEDIASIZE, &o);
784103665Sphk	if (error == 0) {
785103665Sphk		disksecs = o / u;
786103665Sphk		cyls = dos_cyls = o / (u * dos_heads * dos_sectors);
787103665Sphk	}
788103665Sphk
789103665Sphk
790103665Sphk	return (disksecs);
7914Srgrimes}
7924Srgrimes
7934Srgrimes
79416561Salexstatic int
7954Srgrimesread_s0()
7964Srgrimes{
79763218Sache	mboot.bootinst_size = secsize;
79863218Sache	if (mboot.bootinst != NULL)
79963027Sjhb		free(mboot.bootinst);
80063218Sache	if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) {
80163218Sache		warnx("unable to allocate buffer to read fdisk "
80263218Sache		      "partition table");
80363218Sache		return -1;
80463027Sjhb	}
80563027Sjhb	if (read_disk(0, mboot.bootinst) == -1) {
80637415Scharnier		warnx("can't read fdisk partition table");
8074Srgrimes		return -1;
8084Srgrimes	}
809100202Sbde	if (*(uint16_t *)(void *)&mboot.bootinst[MBRSIGOFF] != BOOT_MAGIC) {
81037415Scharnier		warnx("invalid fdisk partition table found");
8114Srgrimes		/* So should we initialize things */
8124Srgrimes		return -1;
8134Srgrimes	}
81463027Sjhb	memcpy(mboot.parts, &mboot.bootinst[DOSPARTOFF], sizeof(mboot.parts));
8154Srgrimes	return 0;
8164Srgrimes}
8174Srgrimes
81816561Salexstatic int
8194Srgrimeswrite_s0()
8204Srgrimes{
82163027Sjhb	int	sector;
82263027Sjhb
8234Srgrimes	if (iotest) {
8244Srgrimes		print_s0(-1);
8254Srgrimes		return 0;
8264Srgrimes	}
82763027Sjhb	memcpy(&mboot.bootinst[DOSPARTOFF], mboot.parts, sizeof(mboot.parts));
8284Srgrimes	/*
8294Srgrimes	 * write enable label sector before write (if necessary),
8304Srgrimes	 * disable after writing.
8314Srgrimes	 * needed if the disklabel protected area also protects
8324Srgrimes	 * sector 0. (e.g. empty disk)
8334Srgrimes	 */
83463027Sjhb	for(sector = 0; sector < mboot.bootinst_size / secsize; sector++)
83563027Sjhb		if (write_disk(sector,
83663027Sjhb			       &mboot.bootinst[sector * secsize]) == -1) {
83763027Sjhb			warn("can't write fdisk partition table");
83863027Sjhb			return -1;
83963027Sjhb		}
84016561Salex	return(0);
8414Srgrimes}
8424Srgrimes
8434Srgrimes
84416561Salexstatic int
84593394Sphkok(const char *str)
8464Srgrimes{
8474Srgrimes	printf("%s [n] ", str);
84881164Siedowse	fflush(stdout);
84981164Siedowse	if (fgets(lbuf, LBUF, stdin) == NULL)
85081164Siedowse		exit(1);
8514Srgrimes	lbuf[strlen(lbuf)-1] = 0;
8524Srgrimes
8534Srgrimes	if (*lbuf &&
8544Srgrimes		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
8554Srgrimes		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
8564Srgrimes		return 1;
8574Srgrimes	else
8584Srgrimes		return 0;
8594Srgrimes}
8604Srgrimes
86116561Salexstatic int
86293394Sphkdecimal(const char *str, int *num, int deflt)
8634Srgrimes{
86493394Sphk	int acc = 0, c;
86593394Sphk	char *cp;
8664Srgrimes
8674Srgrimes	while (1) {
8684Srgrimes		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
86981164Siedowse		fflush(stdout);
87081164Siedowse		if (fgets(lbuf, LBUF, stdin) == NULL)
87181164Siedowse			exit(1);
8724Srgrimes		lbuf[strlen(lbuf)-1] = 0;
8734Srgrimes
8744Srgrimes		if (!*lbuf)
8754Srgrimes			return 0;
8764Srgrimes
8774Srgrimes		cp = lbuf;
8784Srgrimes		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
8794Srgrimes		if (!c)
8804Srgrimes			return 0;
88116561Salex		while ((c = *cp++)) {
8824Srgrimes			if (c <= '9' && c >= '0')
8834Srgrimes				acc = acc * 10 + c - '0';
8844Srgrimes			else
8854Srgrimes				break;
8864Srgrimes		}
8874Srgrimes		if (c == ' ' || c == '\t')
8884Srgrimes			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
8894Srgrimes		if (!c) {
8904Srgrimes			*num = acc;
8914Srgrimes			return 1;
8924Srgrimes		} else
89334952Sobrien			printf("%s is an invalid decimal number.  Try again.\n",
8944Srgrimes				lbuf);
8954Srgrimes	}
8964Srgrimes
8974Srgrimes}
8984Srgrimes
89993394Sphkstatic const char *
90016561Salexget_type(int type)
9014Srgrimes{
9024Srgrimes	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
9034Srgrimes	int	counter = 0;
9044Srgrimes	struct	part_type *ptr = part_types;
9054Srgrimes
9068871Srgrimes
90793394Sphk	while(counter < numentries) {
9084Srgrimes		if(ptr->type == type)
9094Srgrimes			return(ptr->name);
9104Srgrimes		ptr++;
9114Srgrimes		counter++;
9124Srgrimes	}
9134Srgrimes	return("unknown");
9144Srgrimes}
91519459Sjkh
91619459Sjkh
91719459Sjkhstatic void
91893394Sphkparse_config_line(char *line, CMD *command)
91919459Sjkh{
92019459Sjkh    char	*cp, *end;
92119459Sjkh
92219459Sjkh    cp = line;
92393394Sphk    while (1) {
92419459Sjkh	memset(command, 0, sizeof(*command));
92519459Sjkh
92619459Sjkh	while (isspace(*cp)) ++cp;
92719459Sjkh	if (*cp == '\0' || *cp == '#')
92819459Sjkh	    break;
92919459Sjkh	command->cmd = *cp++;
93019459Sjkh
93119459Sjkh	/*
93219459Sjkh	 * Parse args
93319459Sjkh	 */
93493394Sphk	    while (1) {
93519459Sjkh	    while (isspace(*cp)) ++cp;
93619459Sjkh	    if (*cp == '#')
93719459Sjkh		break;		/* found comment */
93819459Sjkh	    if (isalpha(*cp))
93919459Sjkh		command->args[command->n_args].argtype = *cp++;
94019459Sjkh	    if (!isdigit(*cp))
94119459Sjkh		break;		/* assume end of line */
94219459Sjkh	    end = NULL;
94319459Sjkh	    command->args[command->n_args].arg_val = strtol(cp, &end, 0);
94419459Sjkh	    if (cp == end)
94519459Sjkh		break;		/* couldn't parse number */
94619459Sjkh	    cp = end;
94719459Sjkh	    command->n_args++;
94819459Sjkh	}
94919459Sjkh	break;
95019459Sjkh    }
95119459Sjkh}
95219459Sjkh
95319459Sjkh
95419459Sjkhstatic int
95593394Sphkprocess_geometry(CMD *command)
95619459Sjkh{
95719459Sjkh    int		status = 1, i;
95819459Sjkh
95993394Sphk    while (1) {
96019459Sjkh	geom_processed = 1;
96193394Sphk	    if (part_processed) {
96237415Scharnier	    warnx(
96337415Scharnier	"ERROR line %d: the geometry specification line must occur before\n\
96437415Scharnier    all partition specifications",
96537415Scharnier		    current_line_number);
96619459Sjkh	    status = 0;
96719459Sjkh	    break;
96819459Sjkh	}
96993394Sphk	    if (command->n_args != 3) {
97037415Scharnier	    warnx("ERROR line %d: incorrect number of geometry args",
97137415Scharnier		    current_line_number);
97219459Sjkh	    status = 0;
97319459Sjkh	    break;
97419459Sjkh	}
97593394Sphk	    dos_cyls = 0;
97693394Sphk	    dos_heads = 0;
97793394Sphk	    dos_sectors = 0;
97893394Sphk	    for (i = 0; i < 3; ++i) {
97993394Sphk		    switch (command->args[i].argtype) {
98019459Sjkh	    case 'c':
98119459Sjkh		dos_cyls = command->args[i].arg_val;
98219459Sjkh		break;
98319459Sjkh	    case 'h':
98419459Sjkh		dos_heads = command->args[i].arg_val;
98519459Sjkh		break;
98619459Sjkh	    case 's':
98719459Sjkh		dos_sectors = command->args[i].arg_val;
98819459Sjkh		break;
98919459Sjkh	    default:
99037415Scharnier		warnx(
99137415Scharnier		"ERROR line %d: unknown geometry arg type: '%c' (0x%02x)",
99237415Scharnier			current_line_number, command->args[i].argtype,
99319459Sjkh			command->args[i].argtype);
99419459Sjkh		status = 0;
99519459Sjkh		break;
99619459Sjkh	    }
99719459Sjkh	}
99819459Sjkh	if (status == 0)
99919459Sjkh	    break;
100019459Sjkh
100119459Sjkh	dos_cylsecs = dos_heads * dos_sectors;
100219459Sjkh
100319459Sjkh	/*
100419459Sjkh	 * Do sanity checks on parameter values
100519459Sjkh	 */
100693394Sphk	    if (dos_cyls == 0) {
100737415Scharnier	    warnx("ERROR line %d: number of cylinders not specified",
100837415Scharnier		    current_line_number);
100919459Sjkh	    status = 0;
101019459Sjkh	}
101193394Sphk	    if (dos_cyls > 1024) {
101237415Scharnier	    warnx(
101337415Scharnier	"WARNING line %d: number of cylinders (%d) may be out-of-range\n\
101419459Sjkh    (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\
101537415Scharnier    is dedicated to FreeBSD)",
101637415Scharnier		    current_line_number, dos_cyls);
101719459Sjkh	}
101819459Sjkh
101993394Sphk	    if (dos_heads == 0) {
102037415Scharnier	    warnx("ERROR line %d: number of heads not specified",
102137415Scharnier		    current_line_number);
102219459Sjkh	    status = 0;
102393394Sphk	    } else if (dos_heads > 256) {
102437415Scharnier	    warnx("ERROR line %d: number of heads must be within (1-256)",
102537415Scharnier		    current_line_number);
102619459Sjkh	    status = 0;
102719459Sjkh	}
102819459Sjkh
102993394Sphk	    if (dos_sectors == 0) {
103037415Scharnier	    warnx("ERROR line %d: number of sectors not specified",
103137415Scharnier		    current_line_number);
103219459Sjkh	    status = 0;
103393394Sphk	    } else if (dos_sectors > 63) {
103437415Scharnier	    warnx("ERROR line %d: number of sectors must be within (1-63)",
103537415Scharnier		    current_line_number);
103619459Sjkh	    status = 0;
103719459Sjkh	}
103819459Sjkh
103919459Sjkh	break;
104019459Sjkh    }
104119459Sjkh    return (status);
104219459Sjkh}
104319459Sjkh
104419459Sjkh
104519459Sjkhstatic int
104693394Sphkprocess_partition(CMD *command)
104719459Sjkh{
104819459Sjkh    int				status = 0, partition;
104965054Sjhb    u_int32_t			prev_head_boundary, prev_cyl_boundary;
105065054Sjhb    u_int32_t			adj_size, max_end;
105119459Sjkh    struct dos_partition	*partp;
105219459Sjkh
105393394Sphk	while (1) {
105419459Sjkh	part_processed = 1;
105593394Sphk		if (command->n_args != 4) {
105637415Scharnier	    warnx("ERROR line %d: incorrect number of partition args",
105737415Scharnier		    current_line_number);
105819459Sjkh	    break;
105919459Sjkh	}
106019459Sjkh	partition = command->args[0].arg_val;
106193394Sphk		if (partition < 1 || partition > 4) {
106237415Scharnier	    warnx("ERROR line %d: invalid partition number %d",
106337415Scharnier		    current_line_number, partition);
106419459Sjkh	    break;
106519459Sjkh	}
106626421Sbrian	partp = ((struct dos_partition *) &mboot.parts) + partition - 1;
106719459Sjkh	bzero((char *)partp, sizeof (struct dos_partition));
106819459Sjkh	partp->dp_typ = command->args[1].arg_val;
106919459Sjkh	partp->dp_start = command->args[2].arg_val;
107019459Sjkh	partp->dp_size = command->args[3].arg_val;
107119459Sjkh	max_end = partp->dp_start + partp->dp_size;
107219459Sjkh
107393394Sphk		if (partp->dp_typ == 0) {
107419459Sjkh	    /*
107519459Sjkh	     * Get out, the partition is marked as unused.
107619459Sjkh	     */
107719459Sjkh	    /*
107819459Sjkh	     * Insure that it's unused.
107919459Sjkh	     */
108019459Sjkh	    bzero((char *)partp, sizeof (struct dos_partition));
108119459Sjkh	    status = 1;
108219459Sjkh	    break;
108319459Sjkh	}
108419459Sjkh
108519459Sjkh	/*
108619459Sjkh	 * Adjust start upwards, if necessary, to fall on an head boundary.
108719459Sjkh	 */
108893394Sphk		if (partp->dp_start % dos_sectors != 0) {
108965054Sjhb	    prev_head_boundary = partp->dp_start / dos_sectors * dos_sectors;
109065054Sjhb	    if (max_end < dos_sectors ||
109193394Sphk			    prev_head_boundary > max_end - dos_sectors) {
109219459Sjkh		/*
109319459Sjkh		 * Can't go past end of partition
109419459Sjkh		 */
109537415Scharnier		warnx(
109637415Scharnier	"ERROR line %d: unable to adjust start of partition %d to fall on\n\
109765054Sjhb    a head boundary",
109837415Scharnier			current_line_number, partition);
109919459Sjkh		break;
110019459Sjkh	    }
110137415Scharnier	    warnx(
110265054Sjhb	"WARNING: adjusting start offset of partition %d\n\
110365054Sjhb    from %u to %u, to fall on a head boundary",
110465054Sjhb		    partition, (u_int)partp->dp_start,
110565054Sjhb		    (u_int)(prev_head_boundary + dos_sectors));
110665054Sjhb	    partp->dp_start = prev_head_boundary + dos_sectors;
110719459Sjkh	}
110819459Sjkh
110919459Sjkh	/*
111019459Sjkh	 * Adjust size downwards, if necessary, to fall on a cylinder
111119459Sjkh	 * boundary.
111219459Sjkh	 */
111365054Sjhb	prev_cyl_boundary =
111419459Sjkh	    ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs;
111565054Sjhb	if (prev_cyl_boundary > partp->dp_start)
111665054Sjhb	    adj_size = prev_cyl_boundary - partp->dp_start;
111793394Sphk		else {
111865054Sjhb	    warnx(
111965054Sjhb	"ERROR: could not adjust partition to start on a head boundary\n\
112065054Sjhb    and end on a cylinder boundary.");
112165054Sjhb	    return (0);
112265054Sjhb	}
112393394Sphk		if (adj_size != partp->dp_size) {
112437415Scharnier	    warnx(
112565054Sjhb	"WARNING: adjusting size of partition %d from %u to %u\n\
112665054Sjhb    to end on a cylinder boundary",
112765054Sjhb		    partition, (u_int)partp->dp_size, (u_int)adj_size);
112865054Sjhb	    partp->dp_size = adj_size;
112919459Sjkh	}
113093394Sphk		if (partp->dp_size == 0) {
113181164Siedowse	    warnx("ERROR line %d: size of partition %d is zero",
113237415Scharnier		    current_line_number, partition);
113319459Sjkh	    break;
113419459Sjkh	}
113519459Sjkh
113681164Siedowse	dos(partp);
113719459Sjkh	status = 1;
113819459Sjkh	break;
113919459Sjkh    }
114019459Sjkh    return (status);
114119459Sjkh}
114219459Sjkh
114319459Sjkh
114419459Sjkhstatic int
114593394Sphkprocess_active(CMD *command)
114619459Sjkh{
114719459Sjkh    int				status = 0, partition, i;
114819459Sjkh    struct dos_partition	*partp;
114919459Sjkh
115093394Sphk	while (1) {
115119459Sjkh	active_processed = 1;
115293394Sphk		if (command->n_args != 1) {
115337415Scharnier	    warnx("ERROR line %d: incorrect number of active args",
115437415Scharnier		    current_line_number);
115519459Sjkh	    status = 0;
115619459Sjkh	    break;
115719459Sjkh	}
115819459Sjkh	partition = command->args[0].arg_val;
115993394Sphk		if (partition < 1 || partition > 4) {
116037415Scharnier	    warnx("ERROR line %d: invalid partition number %d",
116137415Scharnier		    current_line_number, partition);
116219459Sjkh	    break;
116319459Sjkh	}
116419459Sjkh	/*
116519459Sjkh	 * Reset active partition
116619459Sjkh	 */
116719459Sjkh	partp = ((struct dos_partition *) &mboot.parts);
116819459Sjkh	for (i = 0; i < NDOSPART; i++)
116919459Sjkh	    partp[i].dp_flag = 0;
117026421Sbrian	partp[partition-1].dp_flag = ACTIVE;
117119459Sjkh
117219459Sjkh	status = 1;
117319459Sjkh	break;
117419459Sjkh    }
117519459Sjkh    return (status);
117619459Sjkh}
117719459Sjkh
117819459Sjkh
117919459Sjkhstatic int
118093394Sphkprocess_line(char *line)
118119459Sjkh{
118219459Sjkh    CMD		command;
118319459Sjkh    int		status = 1;
118419459Sjkh
118593394Sphk	while (1) {
118619459Sjkh	parse_config_line(line, &command);
118793394Sphk		switch (command.cmd) {
118819459Sjkh	case 0:
118919459Sjkh	    /*
119019459Sjkh	     * Comment or blank line
119119459Sjkh	     */
119219459Sjkh	    break;
119319459Sjkh	case 'g':
119419459Sjkh	    /*
119519459Sjkh	     * Set geometry
119619459Sjkh	     */
119719459Sjkh	    status = process_geometry(&command);
119819459Sjkh	    break;
119919459Sjkh	case 'p':
120019459Sjkh	    status = process_partition(&command);
120119459Sjkh	    break;
120219459Sjkh	case 'a':
120319459Sjkh	    status = process_active(&command);
120419459Sjkh	    break;
120519459Sjkh	default:
120619459Sjkh	    status = 0;
120719459Sjkh	    break;
120819459Sjkh	}
120919459Sjkh	break;
121019459Sjkh    }
121119459Sjkh    return (status);
121219459Sjkh}
121319459Sjkh
121419459Sjkh
121519459Sjkhstatic int
121693394Sphkread_config(char *config_file)
121719459Sjkh{
121819459Sjkh    FILE	*fp = NULL;
121919459Sjkh    int		status = 1;
122019459Sjkh    char	buf[1010];
122119459Sjkh
122293394Sphk	while (1) {
122393394Sphk		if (strcmp(config_file, "-") != 0) {
122419459Sjkh	    /*
122519459Sjkh	     * We're not reading from stdin
122619459Sjkh	     */
122793394Sphk			if ((fp = fopen(config_file, "r")) == NULL) {
122819459Sjkh		status = 0;
122919459Sjkh		break;
123019459Sjkh	    }
123193394Sphk		} else {
123219459Sjkh	    fp = stdin;
123319459Sjkh	}
123419459Sjkh	current_line_number = 0;
123593394Sphk		while (!feof(fp)) {
123619459Sjkh	    if (fgets(buf, sizeof(buf), fp) == NULL)
123719459Sjkh		break;
123819459Sjkh	    ++current_line_number;
123919459Sjkh	    status = process_line(buf);
124019459Sjkh	    if (status == 0)
124119459Sjkh		break;
124219459Sjkh	    }
124319459Sjkh	break;
124419459Sjkh    }
124593394Sphk	if (fp) {
124619459Sjkh	/*
124719459Sjkh	 * It doesn't matter if we're reading from stdin, as we've reached EOF
124819459Sjkh	 */
124919459Sjkh	fclose(fp);
125019459Sjkh    }
125119459Sjkh    return (status);
125219459Sjkh}
125319459Sjkh
125419459Sjkh
125519459Sjkhstatic void
125619459Sjkhreset_boot(void)
125719459Sjkh{
125819459Sjkh    int				i;
125919459Sjkh    struct dos_partition	*partp;
126019459Sjkh
126119459Sjkh    init_boot();
126293394Sphk	for (i = 0; i < 4; ++i) {
126319459Sjkh	partp = ((struct dos_partition *) &mboot.parts) + i;
126419459Sjkh	bzero((char *)partp, sizeof (struct dos_partition));
126519459Sjkh    }
126619459Sjkh}
126765054Sjhb
126865054Sjhbstatic int
126993394Sphksanitize_partition(struct dos_partition *partp)
127065054Sjhb{
127165054Sjhb    u_int32_t			prev_head_boundary, prev_cyl_boundary;
127281164Siedowse    u_int32_t			max_end, size, start;
127365054Sjhb
127481164Siedowse    start = partp->dp_start;
127581164Siedowse    size = partp->dp_size;
127681164Siedowse    max_end = start + size;
127781164Siedowse    /* Only allow a zero size if the partition is being marked unused. */
127881164Siedowse    if (size == 0) {
127981164Siedowse	if (start == 0 && partp->dp_typ == 0)
128081164Siedowse	    return (1);
128181164Siedowse	warnx("ERROR: size of partition is zero");
128281164Siedowse	return (0);
128381164Siedowse    }
128481164Siedowse    /* Return if no adjustment is necessary. */
128581164Siedowse    if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0)
128681164Siedowse	return (1);
128765054Sjhb
128881164Siedowse    if (start % dos_sectors != 0)
128981164Siedowse	warnx("WARNING: partition does not start on a head boundary");
129081164Siedowse    if ((start  +size) % dos_sectors != 0)
129181164Siedowse	warnx("WARNING: partition does not end on a cylinder boundary");
129281164Siedowse    warnx("WARNING: this may confuse the BIOS or some operating systems");
129381164Siedowse    if (!ok("Correct this automatically?"))
129481164Siedowse	return (1);
129581164Siedowse
129665054Sjhb    /*
129765054Sjhb     * Adjust start upwards, if necessary, to fall on an head boundary.
129865054Sjhb     */
129981164Siedowse    if (start % dos_sectors != 0) {
130081164Siedowse	prev_head_boundary = start / dos_sectors * dos_sectors;
130165054Sjhb	if (max_end < dos_sectors ||
130281164Siedowse	    prev_head_boundary >= max_end - dos_sectors) {
130365054Sjhb	    /*
130465054Sjhb	     * Can't go past end of partition
130565054Sjhb	     */
130665054Sjhb	    warnx(
130765054Sjhb    "ERROR: unable to adjust start of partition to fall on a head boundary");
130865054Sjhb	    return (0);
130965054Sjhb        }
131081164Siedowse	start = prev_head_boundary + dos_sectors;
131165054Sjhb    }
131265054Sjhb
131365054Sjhb    /*
131465054Sjhb     * Adjust size downwards, if necessary, to fall on a cylinder
131565054Sjhb     * boundary.
131665054Sjhb     */
131781164Siedowse    prev_cyl_boundary = ((start + size) / dos_cylsecs) * dos_cylsecs;
131881164Siedowse    if (prev_cyl_boundary > start)
131981164Siedowse	size = prev_cyl_boundary - start;
132081164Siedowse    else {
132165054Sjhb	warnx("ERROR: could not adjust partition to start on a head boundary\n\
132265054Sjhb    and end on a cylinder boundary.");
132365054Sjhb	return (0);
132465054Sjhb    }
132581164Siedowse
132681164Siedowse    /* Finally, commit any changes to partp and return. */
132781164Siedowse    if (start != partp->dp_start) {
132881164Siedowse	warnx("WARNING: adjusting start offset of partition to %u",
132981164Siedowse	    (u_int)start);
133081164Siedowse	partp->dp_start = start;
133165054Sjhb    }
133281164Siedowse    if (size != partp->dp_size) {
133381164Siedowse	warnx("WARNING: adjusting size of partition to %u", (u_int)size);
133481164Siedowse	partp->dp_size = size;
133565054Sjhb    }
133665054Sjhb
133765054Sjhb    return (1);
133865054Sjhb}
133979681Sjoerg
134079681Sjoerg/*
134179681Sjoerg * Try figuring out the root device's canonical disk name.
134279681Sjoerg * The following choices are considered:
134379681Sjoerg *   /dev/ad0s1a     => /dev/ad0
134479681Sjoerg *   /dev/da0a       => /dev/da0
134579681Sjoerg *   /dev/vinum/root => /dev/vinum/root
134679681Sjoerg */
134779681Sjoergstatic char *
134879681Sjoergget_rootdisk(void)
134979681Sjoerg{
135079681Sjoerg	struct statfs rootfs;
135179681Sjoerg	regex_t re;
135279681Sjoerg#define NMATCHES 2
135379681Sjoerg	regmatch_t rm[NMATCHES];
135479681Sjoerg	char *s;
135579681Sjoerg	int rv;
135679681Sjoerg
135779681Sjoerg	if (statfs("/", &rootfs) == -1)
135879681Sjoerg		err(1, "statfs(\"/\")");
135979681Sjoerg
136079681Sjoerg	if ((rv = regcomp(&re, "^(/dev/.*)(\\d+(s\\d+)?[a-h])?$",
136179681Sjoerg		    REG_EXTENDED)) != 0)
136279681Sjoerg		errx(1, "regcomp() failed (%d)", rv);
136379681Sjoerg	if ((rv = regexec(&re, rootfs.f_mntfromname, NMATCHES, rm, 0)) != 0)
136479681Sjoerg		errx(1,
136579681Sjoerg"mounted root fs resource doesn't match expectations (regexec returned %d)",
136679681Sjoerg		    rv);
136779681Sjoerg	if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL)
136879681Sjoerg		errx(1, "out of memory");
136979681Sjoerg	memcpy(s, rootfs.f_mntfromname + rm[1].rm_so,
137079681Sjoerg	    rm[1].rm_eo - rm[1].rm_so);
137179681Sjoerg	s[rm[1].rm_eo - rm[1].rm_so] = 0;
137279681Sjoerg
137379681Sjoerg	return s;
137479681Sjoerg}
1375