fdisk.c revision 90866
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 90866 2002-02-18 19:32:38Z joe $";
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"}
14190866Sjoe	,{0x04, "Primary DOS with 16 bit FAT (< 32MB)"}
1428871Srgrimes	,{0x05, "Extended DOS"}
14390866Sjoe	,{0x06, "Primary 'big' DOS (>= 32MB)"}
14461461Sghelmer	,{0x07, "OS/2 HPFS, NTFS, QNX-2 (16 bit) or Advanced UNIX"}
14590866Sjoe	,{0x08, "AIX filesystem or SplitDrive"}
1468871Srgrimes	,{0x09, "AIX boot partition or Coherent"}
14790866Sjoe	,{0x0A, "OS/2 Boot Manager, OPUS or Coherent swap"}
14834582Sache	,{0x0B, "DOS or Windows 95 with 32 bit FAT"}
14990866Sjoe	,{0x0C, "DOS or Windows 95 with 32 bit FAT (LBA)"}
15090866Sjoe	,{0x0E, "Primary 'big' DOS (>= 32MB, LBA)"}
15190866Sjoe	,{0x0F, "Extended DOS (LBA)"}
1528871Srgrimes	,{0x10, "OPUS"}
15390866Sjoe	,{0x11, "OS/2 BM: hidden DOS with 12-bit FAT"}
15490866Sjoe	,{0x12, "Compaq diagnostics"}
15590866Sjoe	,{0x14, "OS/2 BM: hidden DOS with 16-bit FAT (< 32MB)"}
15690866Sjoe	,{0x16, "OS/2 BM: hidden DOS with 16-bit FAT (>= 32MB)"}
15790866Sjoe	,{0x17, "OS/2 BM: hidden IFS (e.g. HPFS)"}
15890866Sjoe	,{0x18, "AST Windows swapfile"}
15990866Sjoe	,{0x24, "NEC DOS"}
16090866Sjoe	,{0x3C, "PartitionMagic recovery"}
16161568Sbrian	,{0x39, "plan9"}
1628871Srgrimes	,{0x40, "VENIX 286"}
16390866Sjoe	,{0x41, "Linux/MINIX (sharing disk with DRDOS)"}
16490866Sjoe	,{0x42, "SFS or Linux swap (sharing disk with DRDOS)"}
16590866Sjoe	,{0x43, "Linux native (sharing disk with DRDOS)"}
16661461Sghelmer	,{0x4D, "QNX 4.2 Primary"}
16761461Sghelmer	,{0x4E, "QNX 4.2 Secondary"}
16861461Sghelmer	,{0x4F, "QNX 4.2 Tertiary"}
16990866Sjoe	,{0x50, "DM (disk manager)"}
17090866Sjoe	,{0x51, "DM6 Aux1 (or Novell)"}
1718871Srgrimes	,{0x52, "CP/M or Microport SysV/AT"}
17290866Sjoe	,{0x53, "DM6 Aux3"}
17390866Sjoe	,{0x54, "DM6"}
17490866Sjoe	,{0x55, "EZ-Drive (disk manager)"}
17590866Sjoe	,{0x56, "Golden Bow (disk manager)"}
17690866Sjoe	,{0x5c, "Priam Edisk (disk manager)"} /* according to S. Widlake */
17790866Sjoe	,{0x61, "SpeedStor"}
17890866Sjoe	,{0x63, "System V/386 (such as ISC UNIX), GNU HURD or Mach"}
17990866Sjoe	,{0x64, "Novell Netware/286 2.xx"}
18090866Sjoe	,{0x65, "Novell Netware/386 3.xx"}
18190866Sjoe	,{0x70, "DiskSecure Multi-Boot"}
1828871Srgrimes	,{0x75, "PCIX"}
18390866Sjoe	,{0x77, "QNX4.x"}
18490866Sjoe	,{0x78, "QNX4.x 2nd part"}
18590866Sjoe	,{0x79, "QNX4.x 3rd part"}
18690866Sjoe	,{0x80, "Minix until 1.4a"}
18790866Sjoe	,{0x81, "Minix since 1.4b, early Linux partition or Mitac (disk manager)"}
18839377Sobrien	,{0x82, "Linux swap or Solaris x86"}
18990866Sjoe	,{0x83, "Linux native"}
19090866Sjoe	,{0x84, "OS/2 hidden C: drive"}
19190866Sjoe	,{0x85, "Linux extended"}
19290866Sjoe	,{0x86, "NTFS volume set??"}
19390866Sjoe	,{0x87, "NTFS volume set??"}
1948871Srgrimes	,{0x93, "Amoeba filesystem"}
1958871Srgrimes	,{0x94, "Amoeba bad block table"}
19640946Sjkoshy	,{0x9F, "BSD/OS"}
19764316Sjoe	,{0xA0, "Suspend to Disk"}
1988871Srgrimes	,{0xA5, "FreeBSD/NetBSD/386BSD"}
19925378Simp	,{0xA6, "OpenBSD"}
20090866Sjoe	,{0xA7, "NeXTSTEP"}
20140947Salex	,{0xA9, "NetBSD"}
2028871Srgrimes	,{0xB7, "BSDI BSD/386 filesystem"}
2038871Srgrimes	,{0xB8, "BSDI BSD/386 swap"}
20490866Sjoe	,{0xC1, "DRDOS/sec with 12-bit FAT"}
20590866Sjoe	,{0xC4, "DRDOS/sec with 16-bit FAT (< 32MB)"}
20690866Sjoe	,{0xC6, "DRDOS/sec with 16-bit FAT (>= 32MB)"}
20790866Sjoe	,{0xC7, "Syrinx"}
20890866Sjoe	,{0xDB, "CP/M, Concurrent CP/M, Concurrent DOS or CTOS"}
20990866Sjoe	,{0xE1, "DOS access or SpeedStor with 12-bit FAT extended partition"}
21090866Sjoe	,{0xE3, "DOS R/O or SpeedStor"}
21190866Sjoe	,{0xE4, "SpeedStor with 16-bit FAT extended partition < 1024 cyl."}
21290866Sjoe	,{0xEB, "BeOS filesystem"}
21384964Speter	,{0xEE, "EFI GPT"}
21485027Sbde	,{0xEF, "EFI System Partition"}
21590866Sjoe	,{0xF1, "SpeedStor"}
2168871Srgrimes	,{0xF2, "DOS 3.3+ Secondary"}
21790866Sjoe	,{0xF4, "SpeedStor large partition"}
21890866Sjoe	,{0xFE, "SpeedStor >1024 cyl. or LANstep"}
21990866Sjoe	,{0xFF, "Xenix bad blocks table"}
2204Srgrimes};
2214Srgrimes
22216561Salexstatic void print_s0(int which);
22316561Salexstatic void print_part(int i);
22416561Salexstatic void init_sector0(unsigned long start);
22519459Sjkhstatic void init_boot(void);
22616561Salexstatic void change_part(int i);
22716561Salexstatic void print_params();
22816561Salexstatic void change_active(int which);
22943054Srnordierstatic void change_code();
23016561Salexstatic void get_params_to_use();
23179681Sjoergstatic char *get_rootdisk(void);
23281164Siedowsestatic void dos(struct dos_partition *partp);
23316561Salexstatic int open_disk(int u_flag);
23416561Salexstatic ssize_t read_disk(off_t sector, void *buf);
23516561Salexstatic ssize_t write_disk(off_t sector, void *buf);
23616561Salexstatic int get_params();
23716561Salexstatic int read_s0();
23816561Salexstatic int write_s0();
23916561Salexstatic int ok(char *str);
24016561Salexstatic int decimal(char *str, int *num, int deflt);
24116561Salexstatic char *get_type(int type);
24219459Sjkhstatic int read_config(char *config_file);
24319459Sjkhstatic void reset_boot(void);
24465054Sjhbstatic int sanitize_partition(struct dos_partition *);
24537415Scharnierstatic void usage(void);
24616561Salex#if 0
24716561Salexstatic int hex(char *str, int *num, int deflt);
24816561Salexstatic int string(char *str, char **ans);
24916561Salex#endif
2504Srgrimes
25116561Salex
25216561Salexint
25316561Salexmain(int argc, char *argv[])
2544Srgrimes{
25579681Sjoerg	struct	stat sb;
25648282Srnordier	int	c, i;
2574Srgrimes
25857896Simp	while ((c = getopt(argc, argv, "BIab:f:istuv1234")) != -1)
25948282Srnordier		switch (c) {
26048282Srnordier		case 'B':
26148282Srnordier			B_flag = 1;
2624Srgrimes			break;
26357896Simp		case 'I':
26457896Simp			I_flag = 1;
26557896Simp			break;
26648282Srnordier		case 'a':
26748282Srnordier			a_flag = 1;
26848282Srnordier			break;
26948282Srnordier		case 'b':
27048282Srnordier			b_flag = optarg;
27148282Srnordier			break;
27248282Srnordier		case 'f':
27348282Srnordier			f_flag = optarg;
27448282Srnordier			break;
27548282Srnordier		case 'i':
27648282Srnordier			i_flag = 1;
27748282Srnordier			break;
27857896Simp		case 's':
27957896Simp			s_flag = 1;
28057896Simp			break;
28148282Srnordier		case 't':
28248282Srnordier			t_flag = 1;
28348282Srnordier			break;
28448282Srnordier		case 'u':
28548282Srnordier			u_flag = 1;
28648282Srnordier			break;
28748282Srnordier		case 'v':
28848282Srnordier			v_flag = 1;
28948282Srnordier			break;
29048282Srnordier		case '1':
29148282Srnordier		case '2':
29248282Srnordier		case '3':
29348282Srnordier		case '4':
29448282Srnordier			partition = c - '0';
29548282Srnordier			break;
29648282Srnordier		default:
29748282Srnordier			usage();
2984Srgrimes		}
29948282Srnordier	if (f_flag || i_flag)
30048282Srnordier		u_flag = 1;
30148282Srnordier	if (t_flag)
30248282Srnordier		v_flag = 1;
30348282Srnordier	argc -= optind;
30448282Srnordier	argv += optind;
3054Srgrimes
30679681Sjoerg	if (argc == 0) {
30779681Sjoerg		disk = get_rootdisk();
30879681Sjoerg	} else {
30979681Sjoerg		if (stat(argv[0], &sb) == 0) {
31079681Sjoerg			/* OK, full pathname given */
31110514Sjoerg			disk = argv[0];
31279681Sjoerg		} else if (errno == ENOENT) {
31379681Sjoerg			/* Try prepending "/dev" */
31479681Sjoerg			if ((disk = malloc(strlen(argv[0]) + strlen(_PATH_DEV) +
31579681Sjoerg			     1)) == NULL)
31679681Sjoerg				errx(1, "out of memory");
31779681Sjoerg			strcpy(disk, _PATH_DEV);
31879681Sjoerg			strcat(disk, argv[0]);
31979681Sjoerg		} else {
32079681Sjoerg			/* other stat error, let it fail below */
32179681Sjoerg			disk = argv[0];
32210514Sjoerg		}
32310514Sjoerg	}
32479681Sjoerg	if (open_disk(u_flag) < 0)
32579681Sjoerg		err(1, "cannot open disk %s", disk);
3264Srgrimes
32763027Sjhb	/* (abu)use mboot.bootinst to probe for the sector size */
32863027Sjhb	if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL)
32963027Sjhb		err(1, "cannot allocate buffer to determine disk sector size");
33063027Sjhb	read_disk(0, mboot.bootinst);
33163329Sjhb	free(mboot.bootinst);
33263329Sjhb	mboot.bootinst = NULL;
33363027Sjhb
33457896Simp	if (s_flag)
33557896Simp	{
33657896Simp		int i;
33757896Simp		struct dos_partition *partp;
33810514Sjoerg
33957896Simp		if (read_s0())
34057896Simp			err(1, "read_s0");
34157896Simp		printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads,
34257896Simp		    dos_sectors);
34357896Simp		printf("Part  %11s %11s Type Flags\n", "Start", "Size");
34457896Simp		for (i = 0; i < NDOSPART; i++) {
34557896Simp			partp = ((struct dos_partition *) &mboot.parts) + i;
34657896Simp			if (partp->dp_start == 0 && partp->dp_size == 0)
34757896Simp				continue;
34857896Simp			printf("%4d: %11lu %11lu 0x%02x 0x%02x\n", i + 1,
34957896Simp			    (u_long) partp->dp_start,
35057896Simp			    (u_long) partp->dp_size, partp->dp_typ,
35157896Simp			    partp->dp_flag);
35257896Simp		}
35357896Simp		exit(0);
35457896Simp	}
35557896Simp
3564Srgrimes	printf("******* Working on device %s *******\n",disk);
35719459Sjkh
35857896Simp	if (I_flag)
35950215Sphk	{
36050215Sphk		struct dos_partition *partp;
36150215Sphk
36250215Sphk		read_s0();
36350215Sphk		reset_boot();
36450215Sphk		partp = (struct dos_partition *) (&mboot.parts[0]);
36550215Sphk		partp->dp_typ = DOSPTYP_386BSD;
36650215Sphk		partp->dp_flag = ACTIVE;
36750215Sphk		partp->dp_start = dos_sectors;
36865054Sjhb		partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs -
36965054Sjhb		    dos_sectors;
37050215Sphk
37181164Siedowse		dos(partp);
37250215Sphk		if (v_flag)
37350215Sphk			print_s0(-1);
37450215Sphk		write_s0();
37550215Sphk		exit(0);
37650215Sphk	}
37719459Sjkh	if (f_flag)
3784Srgrimes	{
37919459Sjkh	    if (read_s0() || i_flag)
38019459Sjkh	    {
38119459Sjkh		reset_boot();
38219459Sjkh	    }
38319459Sjkh
38419459Sjkh	    if (!read_config(f_flag))
38519459Sjkh	    {
38619459Sjkh		exit(1);
38719459Sjkh	    }
38819459Sjkh	    if (v_flag)
38919459Sjkh	    {
39019459Sjkh		print_s0(-1);
39119459Sjkh	    }
39219459Sjkh	    if (!t_flag)
39319459Sjkh	    {
39419459Sjkh		write_s0();
39519459Sjkh	    }
3964Srgrimes	}
3974Srgrimes	else
3984Srgrimes	{
39919459Sjkh	    if(u_flag)
40019459Sjkh	    {
40119459Sjkh		get_params_to_use();
40219459Sjkh	    }
40319459Sjkh	    else
40419459Sjkh	    {
4054Srgrimes		print_params();
40619459Sjkh	    }
4074Srgrimes
40819459Sjkh	    if (read_s0())
40965054Sjhb		init_sector0(dos_sectors);
4104Srgrimes
41120061Ssos	    printf("Media sector size is %d\n", secsize);
41219459Sjkh	    printf("Warning: BIOS sector numbering starts with sector 1\n");
41319459Sjkh	    printf("Information from DOS bootblock is:\n");
41419459Sjkh	    if (partition == -1)
41526421Sbrian		for (i = 1; i <= NDOSPART; i++)
41619459Sjkh		    change_part(i);
41719459Sjkh	    else
4184Srgrimes		change_part(partition);
4194Srgrimes
42019459Sjkh	    if (u_flag || a_flag)
4214Srgrimes		change_active(partition);
4224Srgrimes
42348282Srnordier	    if (B_flag)
42443054Srnordier		change_code();
42543054Srnordier
42648282Srnordier	    if (u_flag || a_flag || B_flag) {
42719459Sjkh		if (!t_flag)
42819459Sjkh		{
42919459Sjkh		    printf("\nWe haven't changed the partition table yet.  ");
43019459Sjkh		    printf("This is your last chance.\n");
43119459Sjkh		}
4324Srgrimes		print_s0(-1);
43319459Sjkh		if (!t_flag)
43419459Sjkh		{
43519459Sjkh		    if (ok("Should we write new partition table?"))
4364Srgrimes			write_s0();
43719459Sjkh		}
43819459Sjkh		else
43919459Sjkh		{
44019459Sjkh		    printf("\n-t flag specified -- partition table not written.\n");
44119459Sjkh		}
44219459Sjkh	    }
4434Srgrimes	}
4444Srgrimes
4454Srgrimes	exit(0);
44637415Scharnier}
4474Srgrimes
44837415Scharnierstatic void
44937415Scharnierusage()
45037415Scharnier{
45148282Srnordier	fprintf(stderr, "%s%s",
45262178Sjhb		"usage: fdisk [-BIaistu] [-b bootcode] [-1234] [disk]\n",
45348282Srnordier 		"       fdisk -f configfile [-itv] [disk]\n");
45437415Scharnier        exit(1);
4554Srgrimes}
4564Srgrimes
45716561Salexstatic void
45816561Salexprint_s0(int which)
4594Srgrimes{
4604Srgrimesint	i;
4614Srgrimes
4624Srgrimes	print_params();
4634Srgrimes	printf("Information from DOS bootblock is:\n");
4644Srgrimes	if (which == -1)
46526421Sbrian		for (i = 1; i <= NDOSPART; i++)
4664Srgrimes			printf("%d: ", i), print_part(i);
4674Srgrimes	else
4684Srgrimes		print_part(which);
4694Srgrimes}
4704Srgrimes
4714Srgrimesstatic struct dos_partition mtpart = { 0 };
4724Srgrimes
47316561Salexstatic void
47416561Salexprint_part(int i)
4754Srgrimes{
47626389Sgibbs	struct	  dos_partition *partp;
47726389Sgibbs	u_int64_t part_mb;
4784Srgrimes
47926421Sbrian	partp = ((struct dos_partition *) &mboot.parts) + i - 1;
4804Srgrimes
4814Srgrimes	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
4824Srgrimes		printf("<UNUSED>\n");
4834Srgrimes		return;
4844Srgrimes	}
48526389Sgibbs	/*
48626389Sgibbs	 * Be careful not to overflow.
48726389Sgibbs	 */
48826389Sgibbs	part_mb = partp->dp_size;
48926389Sgibbs	part_mb *= secsize;
49026389Sgibbs	part_mb /= (1024 * 1024);
49190866Sjoe	printf("sysid %d (%#04x),(%s)\n", partp->dp_typ, partp->dp_typ,
49290866Sjoe	    get_type(partp->dp_typ));
49337244Sbde	printf("    start %lu, size %lu (%qd Meg), flag %x%s\n",
49437244Sbde		(u_long)partp->dp_start,
49537244Sbde		(u_long)partp->dp_size,
49626389Sgibbs		part_mb,
49734952Sobrien		partp->dp_flag,
49834952Sobrien		partp->dp_flag == ACTIVE ? " (active)" : "");
49969371Sobrien	printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n"
5004Srgrimes		,DPCYL(partp->dp_scyl, partp->dp_ssect)
50169371Sobrien		,partp->dp_shd
5024Srgrimes		,DPSECT(partp->dp_ssect)
5034Srgrimes		,DPCYL(partp->dp_ecyl, partp->dp_esect)
50469371Sobrien		,partp->dp_ehd
50569371Sobrien		,DPSECT(partp->dp_esect));
5064Srgrimes}
5074Srgrimes
50819459Sjkh
50916561Salexstatic void
51019459Sjkhinit_boot(void)
51119459Sjkh{
51248282Srnordier	const char *fname;
51363027Sjhb	int fd, n;
51463027Sjhb	struct stat sb;
51548282Srnordier
51648282Srnordier	fname = b_flag ? b_flag : "/boot/mbr";
51748282Srnordier	if ((fd = open(fname, O_RDONLY)) == -1 ||
51863027Sjhb	    fstat(fd, &sb) == -1)
51963027Sjhb		err(1, "%s", fname);
52063027Sjhb	if ((mboot.bootinst_size = sb.st_size) % secsize != 0)
52163027Sjhb		errx(1, "%s: length must be a multiple of sector size", fname);
52263218Sache	if (mboot.bootinst != NULL)
52363218Sache		free(mboot.bootinst);
52463027Sjhb	if ((mboot.bootinst = malloc(mboot.bootinst_size = sb.st_size)) == NULL)
52563027Sjhb		errx(1, "%s: unable to allocate read buffer", fname);
52663027Sjhb	if ((n = read(fd, mboot.bootinst, mboot.bootinst_size)) == -1 ||
52748282Srnordier	    close(fd))
52848282Srnordier		err(1, "%s", fname);
52963027Sjhb	if (n != mboot.bootinst_size)
53063027Sjhb		errx(1, "%s: short read", fname);
53119459Sjkh}
53219459Sjkh
53319459Sjkh
53419459Sjkhstatic void
53516561Salexinit_sector0(unsigned long start)
5364Srgrimes{
5374Srgrimesstruct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
5384Srgrimes
53919459Sjkh	init_boot();
5404Srgrimes
5414Srgrimes	partp->dp_typ = DOSPTYP_386BSD;
5424Srgrimes	partp->dp_flag = ACTIVE;
54365054Sjhb	start = ((start + dos_sectors - 1) / dos_sectors) * dos_sectors;
54463027Sjhb	if(start == 0)
54563027Sjhb		start = dos_sectors;
5464Srgrimes	partp->dp_start = start;
54765054Sjhb	partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - start;
5484Srgrimes
54981164Siedowse	dos(partp);
5504Srgrimes}
5514Srgrimes
55216561Salexstatic void
55316561Salexchange_part(int i)
5544Srgrimes{
55526421Sbrianstruct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1;
5564Srgrimes
5574Srgrimes    printf("The data for partition %d is:\n", i);
5584Srgrimes    print_part(i);
5594Srgrimes
5604Srgrimes    if (u_flag && ok("Do you want to change it?")) {
5614Srgrimes	int tmp;
5624Srgrimes
5634Srgrimes	if (i_flag) {
5644Srgrimes		bzero((char *)partp, sizeof (struct dos_partition));
56526421Sbrian		if (i == 4) {
5664Srgrimes			init_sector0(1);
56726421Sbrian			printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n");
5684Srgrimes			print_part(i);
5694Srgrimes		}
5704Srgrimes	}
5714Srgrimes
5724Srgrimes	do {
57334952Sobrien		Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp);
5744Srgrimes		Decimal("start", partp->dp_start, tmp);
5754Srgrimes		Decimal("size", partp->dp_size, tmp);
57681164Siedowse		if (!sanitize_partition(partp)) {
57781164Siedowse			warnx("ERROR: failed to adjust; setting sysid to 0");
57881164Siedowse			partp->dp_typ = 0;
57981164Siedowse		}
5804Srgrimes
58136262Sjraynard		if (ok("Explicitly specify beg/end address ?"))
5824Srgrimes		{
5834Srgrimes			int	tsec,tcyl,thd;
5844Srgrimes			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
5854Srgrimes			thd = partp->dp_shd;
5864Srgrimes			tsec = DPSECT(partp->dp_ssect);
5874Srgrimes			Decimal("beginning cylinder", tcyl, tmp);
58869371Sobrien			Decimal("beginning head", thd, tmp);
58968871Sobrien			Decimal("beginning sector", tsec, tmp);
5904Srgrimes			partp->dp_scyl = DOSCYL(tcyl);
5914Srgrimes			partp->dp_ssect = DOSSECT(tsec,tcyl);
5924Srgrimes			partp->dp_shd = thd;
5934Srgrimes
5944Srgrimes			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
5954Srgrimes			thd = partp->dp_ehd;
5964Srgrimes			tsec = DPSECT(partp->dp_esect);
5974Srgrimes			Decimal("ending cylinder", tcyl, tmp);
59869371Sobrien			Decimal("ending head", thd, tmp);
59968871Sobrien			Decimal("ending sector", tsec, tmp);
6004Srgrimes			partp->dp_ecyl = DOSCYL(tcyl);
6014Srgrimes			partp->dp_esect = DOSSECT(tsec,tcyl);
6024Srgrimes			partp->dp_ehd = thd;
60381164Siedowse		} else
60481164Siedowse			dos(partp);
6058871Srgrimes
6064Srgrimes		print_part(i);
6074Srgrimes	} while (!ok("Are we happy with this entry?"));
6084Srgrimes    }
6094Srgrimes}
6104Srgrimes
61116561Salexstatic void
6124Srgrimesprint_params()
6134Srgrimes{
6144Srgrimes	printf("parameters extracted from in-core disklabel are:\n");
6154Srgrimes	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
6164Srgrimes			,cyls,heads,sectors,cylsecs);
6174Srgrimes	if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
61820061Ssos		printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
6194Srgrimes	printf("parameters to be used for BIOS calculations are:\n");
6204Srgrimes	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
6214Srgrimes		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
6224Srgrimes}
6234Srgrimes
62416561Salexstatic void
62516561Salexchange_active(int which)
6264Srgrimes{
62781164Siedowse	struct dos_partition *partp = &mboot.parts[0];
62881164Siedowse	int active, i, new, tmp;
6294Srgrimes
63081164Siedowse	active = -1;
63181164Siedowse	for (i = 0; i < NDOSPART; i++) {
63281164Siedowse		if ((partp[i].dp_flag & ACTIVE) == 0)
63381164Siedowse			continue;
63481164Siedowse		printf("Partition %d is marked active\n", i + 1);
63581164Siedowse		if (active == -1)
63681164Siedowse			active = i + 1;
63781164Siedowse	}
6384Srgrimes	if (a_flag && which != -1)
6394Srgrimes		active = which;
64081164Siedowse	else if (active == -1)
64181164Siedowse		active = 1;
64281164Siedowse
6433723Sbde	if (!ok("Do you want to change the active partition?"))
6443723Sbde		return;
64534952Sobriensetactive:
64634952Sobrien	do {
64781164Siedowse		new = active;
64881164Siedowse		Decimal("active partition", new, tmp);
64981164Siedowse		if (new < 1 || new > 4) {
65034952Sobrien			printf("Active partition number must be in range 1-4."
65134952Sobrien					"  Try again.\n");
65234952Sobrien			goto setactive;
65334952Sobrien		}
65481164Siedowse		active = new;
65534952Sobrien	} while (!ok("Are you happy with this choice"));
6564Srgrimes	for (i = 0; i < NDOSPART; i++)
6574Srgrimes		partp[i].dp_flag = 0;
65826421Sbrian	if (active > 0 && active <= NDOSPART)
65926421Sbrian		partp[active-1].dp_flag = ACTIVE;
6604Srgrimes}
6614Srgrimes
66243054Srnordierstatic void
66343054Srnordierchange_code()
66443054Srnordier{
66543054Srnordier	if (ok("Do you want to change the boot code?"))
66643054Srnordier		init_boot();
66743054Srnordier}
66843054Srnordier
66916561Salexvoid
6704Srgrimesget_params_to_use()
6714Srgrimes{
6724Srgrimes	int	tmp;
6734Srgrimes	print_params();
6744Srgrimes	if (ok("Do you want to change our idea of what BIOS thinks ?"))
6754Srgrimes	{
6764Srgrimes		do
6774Srgrimes		{
6784Srgrimes			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
6794Srgrimes			Decimal("BIOS's idea of #heads", dos_heads, tmp);
6804Srgrimes			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
6814Srgrimes			dos_cylsecs = dos_heads * dos_sectors;
6824Srgrimes			print_params();
6834Srgrimes		}
6844Srgrimes		while(!ok("Are you happy with this choice"));
6854Srgrimes	}
6864Srgrimes}
6874Srgrimes
68819459Sjkh
6894Srgrimes/***********************************************\
6904Srgrimes* Change real numbers into strange dos numbers	*
6914Srgrimes\***********************************************/
69216561Salexstatic void
69381164Siedowsedos(partp)
69481164Siedowse	struct dos_partition *partp;
6954Srgrimes{
69681164Siedowse	int cy, sec;
69781164Siedowse	u_int32_t end;
6984Srgrimes
69988714Siedowse	if (partp->dp_typ == 0 && partp->dp_start == 0 && partp->dp_size == 0) {
70088714Siedowse		memcpy(partp, &mtpart, sizeof(*partp));
7013723Sbde		return;
7023723Sbde	}
7033723Sbde
70481164Siedowse	/* Start c/h/s. */
70581164Siedowse	partp->dp_shd = partp->dp_start % dos_cylsecs / dos_sectors;
70681164Siedowse	cy = partp->dp_start / dos_cylsecs;
70781164Siedowse	sec = partp->dp_start % dos_sectors + 1;
70881164Siedowse	partp->dp_scyl = DOSCYL(cy);
70981164Siedowse	partp->dp_ssect = DOSSECT(sec, cy);
7104Srgrimes
71181164Siedowse	/* End c/h/s. */
71281164Siedowse	end = partp->dp_start + partp->dp_size - 1;
71381164Siedowse	partp->dp_ehd = end % dos_cylsecs / dos_sectors;
71481164Siedowse	cy = end / dos_cylsecs;
71581164Siedowse	sec = end % dos_sectors + 1;
71681164Siedowse	partp->dp_ecyl = DOSCYL(cy);
71781164Siedowse	partp->dp_esect = DOSSECT(sec, cy);
7184Srgrimes}
7194Srgrimes
7204Srgrimesint fd;
7214Srgrimes
7224Srgrimes	/* Getting device status */
7234Srgrimes
72416561Salexstatic int
72516561Salexopen_disk(int u_flag)
7264Srgrimes{
72779306Sjoerg	struct stat 	st;
7284Srgrimes
7298871Srgrimes	if (stat(disk, &st) == -1) {
73079306Sjoerg		if (errno == ENOENT)
73179306Sjoerg			return -2;
73237415Scharnier		warnx("can't get file status of %s", disk);
7334Srgrimes		return -1;
7342810Sbde	}
7352810Sbde	if ( !(st.st_mode & S_IFCHR) )
73637415Scharnier		warnx("device %s is not character special", disk);
73743054Srnordier	if ((fd = open(disk,
73857896Simp	    a_flag || I_flag || B_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) {
73910514Sjoerg		if(errno == ENXIO)
74010514Sjoerg			return -2;
74137415Scharnier		warnx("can't open device %s", disk);
7424Srgrimes		return -1;
7434Srgrimes	}
7444Srgrimes	if (get_params(0) == -1) {
74537415Scharnier		warnx("can't get disk parameters on %s", disk);
7464Srgrimes		return -1;
7474Srgrimes	}
7484Srgrimes	return fd;
7494Srgrimes}
7504Srgrimes
75116561Salexstatic ssize_t
75216561Salexread_disk(off_t sector, void *buf)
7534Srgrimes{
7544Srgrimes	lseek(fd,(sector * 512), 0);
75520061Ssos	if( secsize == 0 )
75620061Ssos		for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 )
75720061Ssos			{
75820061Ssos			/* try the read */
75920061Ssos			int size = read(fd, buf, secsize);
76020061Ssos			if( size == secsize )
76120061Ssos				/* it worked so return */
76220061Ssos				return secsize;
76320061Ssos			}
76420061Ssos	else
76520061Ssos		return read( fd, buf, secsize );
76620061Ssos
76720061Ssos	/* we failed to read at any of the sizes */
76820061Ssos	return -1;
7694Srgrimes}
7704Srgrimes
77116561Salexstatic ssize_t
77216561Salexwrite_disk(off_t sector, void *buf)
7734Srgrimes{
7744Srgrimes	lseek(fd,(sector * 512), 0);
77520061Ssos	/* write out in the size that the read_disk found worked */
77620061Ssos	return write(fd, buf, secsize);
7774Srgrimes}
7784Srgrimes
77916561Salexstatic int
78016561Salexget_params()
7814Srgrimes{
7824Srgrimes
7834Srgrimes    if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
78437415Scharnier	warnx("can't get disk parameters on %s; supplying dummy ones", disk);
7852810Sbde	dos_cyls = cyls = 1;
7862810Sbde	dos_heads = heads = 1;
7872810Sbde	dos_sectors = sectors = 1;
7882810Sbde	dos_cylsecs = cylsecs = heads * sectors;
7892810Sbde	disksecs = cyls * heads * sectors;
7902810Sbde	return disksecs;
7914Srgrimes    }
7924Srgrimes
7934Srgrimes    dos_cyls = cyls = disklabel.d_ncylinders;
7944Srgrimes    dos_heads = heads = disklabel.d_ntracks;
7954Srgrimes    dos_sectors = sectors = disklabel.d_nsectors;
7964Srgrimes    dos_cylsecs = cylsecs = heads * sectors;
7974Srgrimes    disksecs = cyls * heads * sectors;
7984Srgrimes
7994Srgrimes    return (disksecs);
8004Srgrimes}
8014Srgrimes
8024Srgrimes
80316561Salexstatic int
8044Srgrimesread_s0()
8054Srgrimes{
80663218Sache	mboot.bootinst_size = secsize;
80763218Sache	if (mboot.bootinst != NULL)
80863027Sjhb		free(mboot.bootinst);
80963218Sache	if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) {
81063218Sache		warnx("unable to allocate buffer to read fdisk "
81163218Sache		      "partition table");
81263218Sache		return -1;
81363027Sjhb	}
81463027Sjhb	if (read_disk(0, mboot.bootinst) == -1) {
81537415Scharnier		warnx("can't read fdisk partition table");
8164Srgrimes		return -1;
8174Srgrimes	}
81863729Sjhb	if (*(uint16_t *)&mboot.bootinst[MBRSIGOFF] != BOOT_MAGIC) {
81937415Scharnier		warnx("invalid fdisk partition table found");
8204Srgrimes		/* So should we initialize things */
8214Srgrimes		return -1;
8224Srgrimes	}
82363027Sjhb	memcpy(mboot.parts, &mboot.bootinst[DOSPARTOFF], sizeof(mboot.parts));
8244Srgrimes	return 0;
8254Srgrimes}
8264Srgrimes
82716561Salexstatic int
8284Srgrimeswrite_s0()
8294Srgrimes{
83051636Sbillf#ifdef NOT_NOW
8314Srgrimes	int	flag;
83251636Sbillf#endif
83363027Sjhb	int	sector;
83463027Sjhb
8354Srgrimes	if (iotest) {
8364Srgrimes		print_s0(-1);
8374Srgrimes		return 0;
8384Srgrimes	}
83963027Sjhb	memcpy(&mboot.bootinst[DOSPARTOFF], mboot.parts, sizeof(mboot.parts));
8404Srgrimes	/*
8414Srgrimes	 * write enable label sector before write (if necessary),
8424Srgrimes	 * disable after writing.
8434Srgrimes	 * needed if the disklabel protected area also protects
8444Srgrimes	 * sector 0. (e.g. empty disk)
8454Srgrimes	 */
84650215Sphk#ifdef NOT_NOW
8474Srgrimes	flag = 1;
8484Srgrimes	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
84937415Scharnier		warn("ioctl DIOCWLABEL");
85011143Sjulian#endif
85163027Sjhb	for(sector = 0; sector < mboot.bootinst_size / secsize; sector++)
85263027Sjhb		if (write_disk(sector,
85363027Sjhb			       &mboot.bootinst[sector * secsize]) == -1) {
85463027Sjhb			warn("can't write fdisk partition table");
85563027Sjhb			return -1;
85650215Sphk#ifdef NOT_NOW
85763027Sjhb			flag = 0;
85863027Sjhb			(void) ioctl(fd, DIOCWLABEL, &flag);
85963027Sjhb#endif
86063027Sjhb		}
86163027Sjhb#ifdef NOT_NOW
8624Srgrimes	flag = 0;
8634Srgrimes	(void) ioctl(fd, DIOCWLABEL, &flag);
86411143Sjulian#endif
86516561Salex	return(0);
8664Srgrimes}
8674Srgrimes
8684Srgrimes
86916561Salexstatic int
8704Srgrimesok(str)
8714Srgrimeschar *str;
8724Srgrimes{
8734Srgrimes	printf("%s [n] ", str);
87481164Siedowse	fflush(stdout);
87581164Siedowse	if (fgets(lbuf, LBUF, stdin) == NULL)
87681164Siedowse		exit(1);
8774Srgrimes	lbuf[strlen(lbuf)-1] = 0;
8784Srgrimes
8794Srgrimes	if (*lbuf &&
8804Srgrimes		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
8814Srgrimes		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
8824Srgrimes		return 1;
8834Srgrimes	else
8844Srgrimes		return 0;
8854Srgrimes}
8864Srgrimes
88716561Salexstatic int
88816561Salexdecimal(char *str, int *num, int deflt)
8894Srgrimes{
8904Srgrimesint acc = 0, c;
8914Srgrimeschar *cp;
8924Srgrimes
8934Srgrimes	while (1) {
8944Srgrimes		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
89581164Siedowse		fflush(stdout);
89681164Siedowse		if (fgets(lbuf, LBUF, stdin) == NULL)
89781164Siedowse			exit(1);
8984Srgrimes		lbuf[strlen(lbuf)-1] = 0;
8994Srgrimes
9004Srgrimes		if (!*lbuf)
9014Srgrimes			return 0;
9024Srgrimes
9034Srgrimes		cp = lbuf;
9044Srgrimes		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
9054Srgrimes		if (!c)
9064Srgrimes			return 0;
90716561Salex		while ((c = *cp++)) {
9084Srgrimes			if (c <= '9' && c >= '0')
9094Srgrimes				acc = acc * 10 + c - '0';
9104Srgrimes			else
9114Srgrimes				break;
9124Srgrimes		}
9134Srgrimes		if (c == ' ' || c == '\t')
9144Srgrimes			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
9154Srgrimes		if (!c) {
9164Srgrimes			*num = acc;
9174Srgrimes			return 1;
9184Srgrimes		} else
91934952Sobrien			printf("%s is an invalid decimal number.  Try again.\n",
9204Srgrimes				lbuf);
9214Srgrimes	}
9224Srgrimes
9234Srgrimes}
9244Srgrimes
92516561Salex#if 0
92616561Salexstatic int
92716561Salexhex(char *str, int *num, int deflt)
9284Srgrimes{
9294Srgrimesint acc = 0, c;
9304Srgrimeschar *cp;
9314Srgrimes
9324Srgrimes	while (1) {
9334Srgrimes		printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
9344Srgrimes		fgets(lbuf, LBUF, stdin);
9354Srgrimes		lbuf[strlen(lbuf)-1] = 0;
9364Srgrimes
9374Srgrimes		if (!*lbuf)
9384Srgrimes			return 0;
9394Srgrimes
9404Srgrimes		cp = lbuf;
9414Srgrimes		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
9424Srgrimes		if (!c)
9434Srgrimes			return 0;
94416561Salex		while ((c = *cp++)) {
9454Srgrimes			if (c <= '9' && c >= '0')
9464Srgrimes				acc = (acc << 4) + c - '0';
9474Srgrimes			else if (c <= 'f' && c >= 'a')
9484Srgrimes				acc = (acc << 4) + c - 'a' + 10;
9494Srgrimes			else if (c <= 'F' && c >= 'A')
9504Srgrimes				acc = (acc << 4) + c - 'A' + 10;
9514Srgrimes			else
9524Srgrimes				break;
9534Srgrimes		}
9544Srgrimes		if (c == ' ' || c == '\t')
9554Srgrimes			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
9564Srgrimes		if (!c) {
9574Srgrimes			*num = acc;
9584Srgrimes			return 1;
9594Srgrimes		} else
96034952Sobrien			printf("%s is an invalid hex number.  Try again.\n",
9614Srgrimes				lbuf);
9624Srgrimes	}
9634Srgrimes
9644Srgrimes}
9654Srgrimes
96616561Salexstatic int
96716561Salexstring(char *str, char **ans)
9684Srgrimes{
9694Srgrimesint c;
9704Srgrimeschar *cp = lbuf;
9714Srgrimes
9724Srgrimes	while (1) {
9734Srgrimes		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
9744Srgrimes		fgets(lbuf, LBUF, stdin);
9754Srgrimes		lbuf[strlen(lbuf)-1] = 0;
9764Srgrimes
9774Srgrimes		if (!*lbuf)
9784Srgrimes			return 0;
9794Srgrimes
9804Srgrimes		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
9814Srgrimes		if (c == '"') {
9824Srgrimes			c = *++cp;
9834Srgrimes			*ans = cp;
9844Srgrimes			while ((c = *cp) && c != '"') cp++;
9854Srgrimes		} else {
9864Srgrimes			*ans = cp;
9874Srgrimes			while ((c = *cp) && c != ' ' && c != '\t') cp++;
9884Srgrimes		}
9894Srgrimes
9904Srgrimes		if (c)
9914Srgrimes			*cp = 0;
9924Srgrimes		return 1;
9934Srgrimes	}
9944Srgrimes}
99516561Salex#endif
9964Srgrimes
99716561Salexstatic char *
99816561Salexget_type(int type)
9994Srgrimes{
10004Srgrimes	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
10014Srgrimes	int	counter = 0;
10024Srgrimes	struct	part_type *ptr = part_types;
10034Srgrimes
10048871Srgrimes
10054Srgrimes	while(counter < numentries)
10064Srgrimes	{
10074Srgrimes		if(ptr->type == type)
10084Srgrimes		{
10094Srgrimes			return(ptr->name);
10104Srgrimes		}
10114Srgrimes		ptr++;
10124Srgrimes		counter++;
10134Srgrimes	}
10144Srgrimes	return("unknown");
10154Srgrimes}
101619459Sjkh
101719459Sjkh
101819459Sjkhstatic void
101919459Sjkhparse_config_line(line, command)
102019459Sjkh    char	*line;
102119459Sjkh    CMD		*command;
102219459Sjkh{
102319459Sjkh    char	*cp, *end;
102419459Sjkh
102519459Sjkh    cp = line;
102619459Sjkh    while (1)	/* dirty trick used to insure one exit point for this
102719459Sjkh		   function */
102819459Sjkh    {
102919459Sjkh	memset(command, 0, sizeof(*command));
103019459Sjkh
103119459Sjkh	while (isspace(*cp)) ++cp;
103219459Sjkh	if (*cp == '\0' || *cp == '#')
103319459Sjkh	{
103419459Sjkh	    break;
103519459Sjkh	}
103619459Sjkh	command->cmd = *cp++;
103719459Sjkh
103819459Sjkh	/*
103919459Sjkh	 * Parse args
104019459Sjkh	 */
104119459Sjkh	while (1)
104219459Sjkh	{
104319459Sjkh	    while (isspace(*cp)) ++cp;
104419459Sjkh	    if (*cp == '#')
104519459Sjkh	    {
104619459Sjkh		break;		/* found comment */
104719459Sjkh	    }
104819459Sjkh	    if (isalpha(*cp))
104919459Sjkh	    {
105019459Sjkh		command->args[command->n_args].argtype = *cp++;
105119459Sjkh	    }
105219459Sjkh	    if (!isdigit(*cp))
105319459Sjkh	    {
105419459Sjkh		break;		/* assume end of line */
105519459Sjkh	    }
105619459Sjkh	    end = NULL;
105719459Sjkh	    command->args[command->n_args].arg_val = strtol(cp, &end, 0);
105819459Sjkh	    if (cp == end)
105919459Sjkh	    {
106019459Sjkh		break;		/* couldn't parse number */
106119459Sjkh	    }
106219459Sjkh	    cp = end;
106319459Sjkh	    command->n_args++;
106419459Sjkh	}
106519459Sjkh	break;
106619459Sjkh    }
106719459Sjkh}
106819459Sjkh
106919459Sjkh
107019459Sjkhstatic int
107119459Sjkhprocess_geometry(command)
107219459Sjkh    CMD		*command;
107319459Sjkh{
107419459Sjkh    int		status = 1, i;
107519459Sjkh
107619459Sjkh    while (1)
107719459Sjkh    {
107819459Sjkh	geom_processed = 1;
107919459Sjkh	if (part_processed)
108019459Sjkh	{
108137415Scharnier	    warnx(
108237415Scharnier	"ERROR line %d: the geometry specification line must occur before\n\
108337415Scharnier    all partition specifications",
108437415Scharnier		    current_line_number);
108519459Sjkh	    status = 0;
108619459Sjkh	    break;
108719459Sjkh	}
108819459Sjkh	if (command->n_args != 3)
108919459Sjkh	{
109037415Scharnier	    warnx("ERROR line %d: incorrect number of geometry args",
109137415Scharnier		    current_line_number);
109219459Sjkh	    status = 0;
109319459Sjkh	    break;
109419459Sjkh	}
109519459Sjkh	dos_cyls = -1;
109619459Sjkh	dos_heads = -1;
109719459Sjkh	dos_sectors = -1;
109819459Sjkh	for (i = 0; i < 3; ++i)
109919459Sjkh	{
110019459Sjkh	    switch (command->args[i].argtype)
110119459Sjkh	    {
110219459Sjkh	    case 'c':
110319459Sjkh		dos_cyls = command->args[i].arg_val;
110419459Sjkh		break;
110519459Sjkh	    case 'h':
110619459Sjkh		dos_heads = command->args[i].arg_val;
110719459Sjkh		break;
110819459Sjkh	    case 's':
110919459Sjkh		dos_sectors = command->args[i].arg_val;
111019459Sjkh		break;
111119459Sjkh	    default:
111237415Scharnier		warnx(
111337415Scharnier		"ERROR line %d: unknown geometry arg type: '%c' (0x%02x)",
111437415Scharnier			current_line_number, command->args[i].argtype,
111519459Sjkh			command->args[i].argtype);
111619459Sjkh		status = 0;
111719459Sjkh		break;
111819459Sjkh	    }
111919459Sjkh	}
112019459Sjkh	if (status == 0)
112119459Sjkh	{
112219459Sjkh	    break;
112319459Sjkh	}
112419459Sjkh
112519459Sjkh	dos_cylsecs = dos_heads * dos_sectors;
112619459Sjkh
112719459Sjkh	/*
112819459Sjkh	 * Do sanity checks on parameter values
112919459Sjkh	 */
113019459Sjkh	if (dos_cyls < 0)
113119459Sjkh	{
113237415Scharnier	    warnx("ERROR line %d: number of cylinders not specified",
113337415Scharnier		    current_line_number);
113419459Sjkh	    status = 0;
113519459Sjkh	}
113619459Sjkh	if (dos_cyls == 0 || dos_cyls > 1024)
113719459Sjkh	{
113837415Scharnier	    warnx(
113937415Scharnier	"WARNING line %d: number of cylinders (%d) may be out-of-range\n\
114019459Sjkh    (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\
114137415Scharnier    is dedicated to FreeBSD)",
114237415Scharnier		    current_line_number, dos_cyls);
114319459Sjkh	}
114419459Sjkh
114519459Sjkh	if (dos_heads < 0)
114619459Sjkh	{
114737415Scharnier	    warnx("ERROR line %d: number of heads not specified",
114837415Scharnier		    current_line_number);
114919459Sjkh	    status = 0;
115019459Sjkh	}
115119459Sjkh	else if (dos_heads < 1 || dos_heads > 256)
115219459Sjkh	{
115337415Scharnier	    warnx("ERROR line %d: number of heads must be within (1-256)",
115437415Scharnier		    current_line_number);
115519459Sjkh	    status = 0;
115619459Sjkh	}
115719459Sjkh
115819459Sjkh	if (dos_sectors < 0)
115919459Sjkh	{
116037415Scharnier	    warnx("ERROR line %d: number of sectors not specified",
116137415Scharnier		    current_line_number);
116219459Sjkh	    status = 0;
116319459Sjkh	}
116419459Sjkh	else if (dos_sectors < 1 || dos_sectors > 63)
116519459Sjkh	{
116637415Scharnier	    warnx("ERROR line %d: number of sectors must be within (1-63)",
116737415Scharnier		    current_line_number);
116819459Sjkh	    status = 0;
116919459Sjkh	}
117019459Sjkh
117119459Sjkh	break;
117219459Sjkh    }
117319459Sjkh    return (status);
117419459Sjkh}
117519459Sjkh
117619459Sjkh
117719459Sjkhstatic int
117819459Sjkhprocess_partition(command)
117919459Sjkh    CMD		*command;
118019459Sjkh{
118119459Sjkh    int				status = 0, partition;
118265054Sjhb    u_int32_t			prev_head_boundary, prev_cyl_boundary;
118365054Sjhb    u_int32_t			adj_size, max_end;
118419459Sjkh    struct dos_partition	*partp;
118519459Sjkh
118619459Sjkh    while (1)
118719459Sjkh    {
118819459Sjkh	part_processed = 1;
118919459Sjkh	if (command->n_args != 4)
119019459Sjkh	{
119137415Scharnier	    warnx("ERROR line %d: incorrect number of partition args",
119237415Scharnier		    current_line_number);
119319459Sjkh	    break;
119419459Sjkh	}
119519459Sjkh	partition = command->args[0].arg_val;
119626421Sbrian	if (partition < 1 || partition > 4)
119719459Sjkh	{
119837415Scharnier	    warnx("ERROR line %d: invalid partition number %d",
119937415Scharnier		    current_line_number, partition);
120019459Sjkh	    break;
120119459Sjkh	}
120226421Sbrian	partp = ((struct dos_partition *) &mboot.parts) + partition - 1;
120319459Sjkh	bzero((char *)partp, sizeof (struct dos_partition));
120419459Sjkh	partp->dp_typ = command->args[1].arg_val;
120519459Sjkh	partp->dp_start = command->args[2].arg_val;
120619459Sjkh	partp->dp_size = command->args[3].arg_val;
120719459Sjkh	max_end = partp->dp_start + partp->dp_size;
120819459Sjkh
120919459Sjkh	if (partp->dp_typ == 0)
121019459Sjkh	{
121119459Sjkh	    /*
121219459Sjkh	     * Get out, the partition is marked as unused.
121319459Sjkh	     */
121419459Sjkh	    /*
121519459Sjkh	     * Insure that it's unused.
121619459Sjkh	     */
121719459Sjkh	    bzero((char *)partp, sizeof (struct dos_partition));
121819459Sjkh	    status = 1;
121919459Sjkh	    break;
122019459Sjkh	}
122119459Sjkh
122219459Sjkh	/*
122319459Sjkh	 * Adjust start upwards, if necessary, to fall on an head boundary.
122419459Sjkh	 */
122519459Sjkh	if (partp->dp_start % dos_sectors != 0)
122619459Sjkh	{
122765054Sjhb	    prev_head_boundary = partp->dp_start / dos_sectors * dos_sectors;
122865054Sjhb	    if (max_end < dos_sectors ||
122965054Sjhb		prev_head_boundary > max_end - dos_sectors)
123019459Sjkh	    {
123119459Sjkh		/*
123219459Sjkh		 * Can't go past end of partition
123319459Sjkh		 */
123437415Scharnier		warnx(
123537415Scharnier	"ERROR line %d: unable to adjust start of partition %d to fall on\n\
123665054Sjhb    a head boundary",
123737415Scharnier			current_line_number, partition);
123819459Sjkh		break;
123919459Sjkh	    }
124037415Scharnier	    warnx(
124165054Sjhb	"WARNING: adjusting start offset of partition %d\n\
124265054Sjhb    from %u to %u, to fall on a head boundary",
124365054Sjhb		    partition, (u_int)partp->dp_start,
124465054Sjhb		    (u_int)(prev_head_boundary + dos_sectors));
124565054Sjhb	    partp->dp_start = prev_head_boundary + dos_sectors;
124619459Sjkh	}
124719459Sjkh
124819459Sjkh	/*
124919459Sjkh	 * Adjust size downwards, if necessary, to fall on a cylinder
125019459Sjkh	 * boundary.
125119459Sjkh	 */
125265054Sjhb	prev_cyl_boundary =
125319459Sjkh	    ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs;
125465054Sjhb	if (prev_cyl_boundary > partp->dp_start)
125565054Sjhb	    adj_size = prev_cyl_boundary - partp->dp_start;
125665054Sjhb	else
125765054Sjhb	{
125865054Sjhb	    warnx(
125965054Sjhb	"ERROR: could not adjust partition to start on a head boundary\n\
126065054Sjhb    and end on a cylinder boundary.");
126165054Sjhb	    return (0);
126265054Sjhb	}
126319459Sjkh	if (adj_size != partp->dp_size)
126419459Sjkh	{
126537415Scharnier	    warnx(
126665054Sjhb	"WARNING: adjusting size of partition %d from %u to %u\n\
126765054Sjhb    to end on a cylinder boundary",
126865054Sjhb		    partition, (u_int)partp->dp_size, (u_int)adj_size);
126965054Sjhb	    partp->dp_size = adj_size;
127019459Sjkh	}
127165054Sjhb	if (partp->dp_size == 0)
127219459Sjkh	{
127381164Siedowse	    warnx("ERROR line %d: size of partition %d is zero",
127437415Scharnier		    current_line_number, partition);
127519459Sjkh	    break;
127619459Sjkh	}
127719459Sjkh
127881164Siedowse	dos(partp);
127919459Sjkh	status = 1;
128019459Sjkh	break;
128119459Sjkh    }
128219459Sjkh    return (status);
128319459Sjkh}
128419459Sjkh
128519459Sjkh
128619459Sjkhstatic int
128719459Sjkhprocess_active(command)
128819459Sjkh    CMD		*command;
128919459Sjkh{
129019459Sjkh    int				status = 0, partition, i;
129119459Sjkh    struct dos_partition	*partp;
129219459Sjkh
129319459Sjkh    while (1)
129419459Sjkh    {
129519459Sjkh	active_processed = 1;
129619459Sjkh	if (command->n_args != 1)
129719459Sjkh	{
129837415Scharnier	    warnx("ERROR line %d: incorrect number of active args",
129937415Scharnier		    current_line_number);
130019459Sjkh	    status = 0;
130119459Sjkh	    break;
130219459Sjkh	}
130319459Sjkh	partition = command->args[0].arg_val;
130426421Sbrian	if (partition < 1 || partition > 4)
130519459Sjkh	{
130637415Scharnier	    warnx("ERROR line %d: invalid partition number %d",
130737415Scharnier		    current_line_number, partition);
130819459Sjkh	    break;
130919459Sjkh	}
131019459Sjkh	/*
131119459Sjkh	 * Reset active partition
131219459Sjkh	 */
131319459Sjkh	partp = ((struct dos_partition *) &mboot.parts);
131419459Sjkh	for (i = 0; i < NDOSPART; i++)
131519459Sjkh	    partp[i].dp_flag = 0;
131626421Sbrian	partp[partition-1].dp_flag = ACTIVE;
131719459Sjkh
131819459Sjkh	status = 1;
131919459Sjkh	break;
132019459Sjkh    }
132119459Sjkh    return (status);
132219459Sjkh}
132319459Sjkh
132419459Sjkh
132519459Sjkhstatic int
132619459Sjkhprocess_line(line)
132719459Sjkh    char	*line;
132819459Sjkh{
132919459Sjkh    CMD		command;
133019459Sjkh    int		status = 1;
133119459Sjkh
133219459Sjkh    while (1)
133319459Sjkh    {
133419459Sjkh	parse_config_line(line, &command);
133519459Sjkh	switch (command.cmd)
133619459Sjkh	{
133719459Sjkh	case 0:
133819459Sjkh	    /*
133919459Sjkh	     * Comment or blank line
134019459Sjkh	     */
134119459Sjkh	    break;
134219459Sjkh	case 'g':
134319459Sjkh	    /*
134419459Sjkh	     * Set geometry
134519459Sjkh	     */
134619459Sjkh	    status = process_geometry(&command);
134719459Sjkh	    break;
134819459Sjkh	case 'p':
134919459Sjkh	    status = process_partition(&command);
135019459Sjkh	    break;
135119459Sjkh	case 'a':
135219459Sjkh	    status = process_active(&command);
135319459Sjkh	    break;
135419459Sjkh	default:
135519459Sjkh	    status = 0;
135619459Sjkh	    break;
135719459Sjkh	}
135819459Sjkh	break;
135919459Sjkh    }
136019459Sjkh    return (status);
136119459Sjkh}
136219459Sjkh
136319459Sjkh
136419459Sjkhstatic int
136519459Sjkhread_config(config_file)
136619459Sjkh    char *config_file;
136719459Sjkh{
136819459Sjkh    FILE	*fp = NULL;
136919459Sjkh    int		status = 1;
137019459Sjkh    char	buf[1010];
137119459Sjkh
137219459Sjkh    while (1)	/* dirty trick used to insure one exit point for this
137319459Sjkh		   function */
137419459Sjkh    {
137519459Sjkh	if (strcmp(config_file, "-") != 0)
137619459Sjkh	{
137719459Sjkh	    /*
137819459Sjkh	     * We're not reading from stdin
137919459Sjkh	     */
138019459Sjkh	    if ((fp = fopen(config_file, "r")) == NULL)
138119459Sjkh	    {
138219459Sjkh		status = 0;
138319459Sjkh		break;
138419459Sjkh	    }
138519459Sjkh	}
138619459Sjkh	else
138719459Sjkh	{
138819459Sjkh	    fp = stdin;
138919459Sjkh	}
139019459Sjkh	current_line_number = 0;
139119459Sjkh	while (!feof(fp))
139219459Sjkh	{
139319459Sjkh	    if (fgets(buf, sizeof(buf), fp) == NULL)
139419459Sjkh	    {
139519459Sjkh		break;
139619459Sjkh	    }
139719459Sjkh	    ++current_line_number;
139819459Sjkh	    status = process_line(buf);
139919459Sjkh	    if (status == 0)
140019459Sjkh	    {
140119459Sjkh		break;
140219459Sjkh	    }
140319459Sjkh	}
140419459Sjkh	break;
140519459Sjkh    }
140619459Sjkh    if (fp)
140719459Sjkh    {
140819459Sjkh	/*
140919459Sjkh	 * It doesn't matter if we're reading from stdin, as we've reached EOF
141019459Sjkh	 */
141119459Sjkh	fclose(fp);
141219459Sjkh    }
141319459Sjkh    return (status);
141419459Sjkh}
141519459Sjkh
141619459Sjkh
141719459Sjkhstatic void
141819459Sjkhreset_boot(void)
141919459Sjkh{
142019459Sjkh    int				i;
142119459Sjkh    struct dos_partition	*partp;
142219459Sjkh
142319459Sjkh    init_boot();
142419459Sjkh    for (i = 0; i < 4; ++i)
142519459Sjkh    {
142619459Sjkh	partp = ((struct dos_partition *) &mboot.parts) + i;
142719459Sjkh	bzero((char *)partp, sizeof (struct dos_partition));
142819459Sjkh    }
142919459Sjkh}
143065054Sjhb
143165054Sjhbstatic int
143265054Sjhbsanitize_partition(partp)
143365054Sjhb    struct dos_partition	*partp;
143465054Sjhb{
143565054Sjhb    u_int32_t			prev_head_boundary, prev_cyl_boundary;
143681164Siedowse    u_int32_t			max_end, size, start;
143765054Sjhb
143881164Siedowse    start = partp->dp_start;
143981164Siedowse    size = partp->dp_size;
144081164Siedowse    max_end = start + size;
144181164Siedowse    /* Only allow a zero size if the partition is being marked unused. */
144281164Siedowse    if (size == 0) {
144381164Siedowse	if (start == 0 && partp->dp_typ == 0)
144481164Siedowse	    return (1);
144581164Siedowse	warnx("ERROR: size of partition is zero");
144681164Siedowse	return (0);
144781164Siedowse    }
144881164Siedowse    /* Return if no adjustment is necessary. */
144981164Siedowse    if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0)
145081164Siedowse	return (1);
145165054Sjhb
145281164Siedowse    if (start % dos_sectors != 0)
145381164Siedowse	warnx("WARNING: partition does not start on a head boundary");
145481164Siedowse    if ((start  +size) % dos_sectors != 0)
145581164Siedowse	warnx("WARNING: partition does not end on a cylinder boundary");
145681164Siedowse    warnx("WARNING: this may confuse the BIOS or some operating systems");
145781164Siedowse    if (!ok("Correct this automatically?"))
145881164Siedowse	return (1);
145981164Siedowse
146065054Sjhb    /*
146165054Sjhb     * Adjust start upwards, if necessary, to fall on an head boundary.
146265054Sjhb     */
146381164Siedowse    if (start % dos_sectors != 0) {
146481164Siedowse	prev_head_boundary = start / dos_sectors * dos_sectors;
146565054Sjhb	if (max_end < dos_sectors ||
146681164Siedowse	    prev_head_boundary >= max_end - dos_sectors) {
146765054Sjhb	    /*
146865054Sjhb	     * Can't go past end of partition
146965054Sjhb	     */
147065054Sjhb	    warnx(
147165054Sjhb    "ERROR: unable to adjust start of partition to fall on a head boundary");
147265054Sjhb	    return (0);
147365054Sjhb        }
147481164Siedowse	start = prev_head_boundary + dos_sectors;
147565054Sjhb    }
147665054Sjhb
147765054Sjhb    /*
147865054Sjhb     * Adjust size downwards, if necessary, to fall on a cylinder
147965054Sjhb     * boundary.
148065054Sjhb     */
148181164Siedowse    prev_cyl_boundary = ((start + size) / dos_cylsecs) * dos_cylsecs;
148281164Siedowse    if (prev_cyl_boundary > start)
148381164Siedowse	size = prev_cyl_boundary - start;
148481164Siedowse    else {
148565054Sjhb	warnx("ERROR: could not adjust partition to start on a head boundary\n\
148665054Sjhb    and end on a cylinder boundary.");
148765054Sjhb	return (0);
148865054Sjhb    }
148981164Siedowse
149081164Siedowse    /* Finally, commit any changes to partp and return. */
149181164Siedowse    if (start != partp->dp_start) {
149281164Siedowse	warnx("WARNING: adjusting start offset of partition to %u",
149381164Siedowse	    (u_int)start);
149481164Siedowse	partp->dp_start = start;
149565054Sjhb    }
149681164Siedowse    if (size != partp->dp_size) {
149781164Siedowse	warnx("WARNING: adjusting size of partition to %u", (u_int)size);
149881164Siedowse	partp->dp_size = size;
149965054Sjhb    }
150065054Sjhb
150165054Sjhb    return (1);
150265054Sjhb}
150379681Sjoerg
150479681Sjoerg/*
150579681Sjoerg * Try figuring out the root device's canonical disk name.
150679681Sjoerg * The following choices are considered:
150779681Sjoerg *   /dev/ad0s1a     => /dev/ad0
150879681Sjoerg *   /dev/da0a       => /dev/da0
150979681Sjoerg *   /dev/vinum/root => /dev/vinum/root
151079681Sjoerg */
151179681Sjoergstatic char *
151279681Sjoergget_rootdisk(void)
151379681Sjoerg{
151479681Sjoerg	struct statfs rootfs;
151579681Sjoerg	regex_t re;
151679681Sjoerg#define NMATCHES 2
151779681Sjoerg	regmatch_t rm[NMATCHES];
151879681Sjoerg	char *s;
151979681Sjoerg	int rv;
152079681Sjoerg
152179681Sjoerg	if (statfs("/", &rootfs) == -1)
152279681Sjoerg		err(1, "statfs(\"/\")");
152379681Sjoerg
152479681Sjoerg	if ((rv = regcomp(&re, "^(/dev/.*)(\\d+(s\\d+)?[a-h])?$",
152579681Sjoerg		    REG_EXTENDED)) != 0)
152679681Sjoerg		errx(1, "regcomp() failed (%d)", rv);
152779681Sjoerg	if ((rv = regexec(&re, rootfs.f_mntfromname, NMATCHES, rm, 0)) != 0)
152879681Sjoerg		errx(1,
152979681Sjoerg"mounted root fs resource doesn't match expectations (regexec returned %d)",
153079681Sjoerg		    rv);
153179681Sjoerg	if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL)
153279681Sjoerg		errx(1, "out of memory");
153379681Sjoerg	memcpy(s, rootfs.f_mntfromname + rm[1].rm_so,
153479681Sjoerg	    rm[1].rm_eo - rm[1].rm_so);
153579681Sjoerg	s[rm[1].rm_eo - rm[1].rm_so] = 0;
153679681Sjoerg
153779681Sjoerg	return s;
153879681Sjoerg}
1539