158234Skato/*
258234Skato * Mach Operating System
358234Skato * Copyright (c) 1992 Carnegie Mellon University
458234Skato * All Rights Reserved.
558234Skato *
658234Skato * Permission to use, copy, modify and distribute this software and its
758234Skato * documentation is hereby granted, provided that both the copyright
858234Skato * notice and this permission notice appear in all copies of the
958234Skato * software, derivative works or modified versions, and any portions
1058234Skato * thereof, and that both notices appear in supporting documentation.
1158234Skato *
1258234Skato * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
1358234Skato * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1458234Skato * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1558234Skato *
1658234Skato * Carnegie Mellon requests users of this software to return to
1758234Skato *
1858234Skato *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
1958234Skato *  School of Computer Science
2058234Skato *  Carnegie Mellon University
2158234Skato *  Pittsburgh PA 15213-3890
2258234Skato *
2358234Skato * any improvements or extensions that they make and grant Carnegie Mellon
2458234Skato * the rights to redistribute these changes.
2558234Skato */
2658234Skato
27145748Snyan#include <sys/cdefs.h>
28145748Snyan__FBSDID("$FreeBSD$");
2958234Skato
30106047Snyan#include <sys/disk.h>
3158234Skato#include <sys/disklabel.h>
32104459Snyan#include <sys/diskpc98.h>
33106047Snyan#include <sys/param.h>
3458234Skato#include <sys/stat.h>
35106047Snyan#include <sys/mount.h>
3658234Skato#include <ctype.h>
3758234Skato#include <fcntl.h>
3858234Skato#include <err.h>
3958234Skato#include <errno.h>
40148062Snyan#include <libgeom.h>
4169793Sobrien#include <paths.h>
42106047Snyan#include <regex.h>
43106047Snyan#include <stdint.h>
4458234Skato#include <stdio.h>
4558234Skato#include <stdlib.h>
4658234Skato#include <string.h>
4758234Skato#include <unistd.h>
4858234Skato
4958234Skatoint iotest;
5058234Skato
5158234Skato#define LBUF 100
5258234Skatostatic char lbuf[LBUF];
5358234Skato
5458234Skato/*
5558234Skato *
5658234Skato * Ported to 386bsd by Julian Elischer  Thu Oct 15 20:26:46 PDT 1992
5758234Skato *
5858234Skato * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
5958234Skato *	Copyright (c) 1989	Robert. V. Baron
6058234Skato *	Created.
6158234Skato */
6258234Skato
6358234Skato#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp
6458234Skato#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); }
6558234Skato
6658234Skato#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
6758234Skato
6858234Skato#define MAX_SEC_SIZE 2048	/* maximum section size that is supported */
6958234Skato#define MIN_SEC_SIZE 512	/* the sector size to start sensing at */
70106047Snyanstatic int secsize = 0;		/* the sensed sector size */
7158234Skato
72106047Snyanstatic char *disk;
7358234Skato
74106047Snyanstatic int cyls, sectors, heads, cylsecs, disksecs;
7558234Skato
76106047Snyanstruct mboot {
7758234Skato	unsigned char padding[2]; /* force the longs to be long aligned */
7858234Skato	unsigned char bootinst[510];
7958234Skato	unsigned short int	signature;
80108650Snyan	struct	pc98_partition parts[8];
8158234Skato	unsigned char large_sector_overflow[MAX_SEC_SIZE-MIN_SEC_SIZE];
8258234Skato};
8358234Skato
84106047Snyanstatic struct mboot mboot;
85148062Snyanstatic int fd;
86106047Snyan
87106047Snyanstatic uint dos_cyls;
88106047Snyanstatic uint dos_heads;
89106047Snyanstatic uint dos_sectors;
90106047Snyanstatic uint dos_cylsecs;
9158234Skato
9258234Skato#define MAX_ARGS	10
9358234Skato
9458234Skatotypedef struct cmd {
9558234Skato    char		cmd;
9658234Skato    int			n_args;
9758234Skato    struct arg {
9858234Skato	char	argtype;
9958234Skato	int	arg_val;
10058234Skato    }			args[MAX_ARGS];
10158234Skato} CMD;
10258234Skato
10358234Skatostatic int B_flag  = 0;		/* replace boot code */
104156020Simpstatic int I_flag  = 0;		/* Inizialize disk to defaults */
10558234Skatostatic int a_flag  = 0;		/* set active partition */
10658234Skatostatic int i_flag  = 0;		/* replace partition data */
10758234Skatostatic int u_flag  = 0;		/* update partition data */
10858234Skatostatic int s_flag  = 0;		/* Print a summary and exit */
109106047Snyanstatic int t_flag  = 0;		/* test only */
11058234Skatostatic char *f_flag = NULL;	/* Read config info from file */
11158234Skatostatic int v_flag  = 0;		/* Be verbose */
11258234Skato
113106047Snyanstatic struct part_type
11458234Skato{
115106047Snyan	unsigned char type;
116106047Snyan	const char *name;
117106047Snyan} part_types[] = {
11858234Skato	 {0x00, "unused"}
11958234Skato	,{0x01, "Primary DOS with 12 bit FAT"}
12058234Skato	,{0x11, "MSDOS"}
12158234Skato	,{0x20, "MSDOS"}
12258234Skato	,{0x21, "MSDOS"}
12358234Skato	,{0x22, "MSDOS"}
12458234Skato	,{0x23, "MSDOS"}
125102231Strhodes	,{0x02, "XENIX / file system"}
126102231Strhodes	,{0x03, "XENIX /usr file system"}
12758234Skato	,{0x04, "PC-UX"}
12858234Skato	,{0x05, "Extended DOS"}
12958234Skato	,{0x06, "Primary 'big' DOS (> 32MB)"}
13058234Skato	,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"}
131102231Strhodes	,{0x08, "AIX file system"}
13258234Skato	,{0x09, "AIX boot partition or Coherent"}
13358234Skato	,{0x0A, "OS/2 Boot Manager or OPUS"}
13458234Skato	,{0x10, "OPUS"}
13558234Skato	,{0x14, "FreeBSD/NetBSD/386BSD"}
13658234Skato	,{0x94, "FreeBSD/NetBSD/386BSD"}
13758234Skato	,{0x40, "VENIX 286"}
13858234Skato	,{0x50, "DM"}
13958234Skato	,{0x51, "DM"}
14058234Skato	,{0x52, "CP/M or Microport SysV/AT"}
14158234Skato	,{0x56, "GB"}
14258234Skato	,{0x61, "Speed"}
14358234Skato	,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
14458234Skato	,{0x64, "Novell Netware 2.xx"}
14558234Skato	,{0x65, "Novell Netware 3.xx"}
14658234Skato	,{0x75, "PCIX"}
14758234Skato	,{0x40, "Minix"}
14858234Skato};
14958234Skato
15058234Skatostatic void print_s0(int which);
15158234Skatostatic void print_part(int i);
15258234Skatostatic void init_sector0(unsigned long start);
15358234Skatostatic void init_boot(void);
154168934Simpstatic void change_part(int i, int force);
155106047Snyanstatic void print_params(void);
15658234Skatostatic void change_active(int which);
157106047Snyanstatic void change_code(void);
158106047Snyanstatic void get_params_to_use(void);
159106047Snyanstatic char *get_rootdisk(void);
160145765Snyanstatic void dos(u_int32_t start, u_int32_t size, struct pc98_partition *partp);
161106047Snyanstatic int open_disk(int flag);
16258234Skatostatic ssize_t read_disk(off_t sector, void *buf);
163148062Snyanstatic int write_disk(off_t sector, void *buf);
164106047Snyanstatic int get_params(void);
165106047Snyanstatic int read_s0(void);
166106047Snyanstatic int write_s0(void);
167106047Snyanstatic int ok(const char *str);
168106047Snyanstatic int decimal(const char *str, int *num, int deflt);
169106047Snyanstatic const char *get_type(int type);
17058234Skatostatic void usage(void);
171145765Snyanstatic int string(const char *str, char **ans);
172156020Simpstatic void reset_boot(void);
17358234Skato
17458234Skatoint
17558234Skatomain(int argc, char *argv[])
17658234Skato{
177106047Snyan	struct	stat sb;
17858234Skato	int	c, i;
179106047Snyan	int	partition = -1;
180108650Snyan	struct	pc98_partition *partp;
18158234Skato
182156020Simp	while ((c = getopt(argc, argv, "BIa:f:istuv12345678")) != -1)
18358234Skato		switch (c) {
18458234Skato		case 'B':
18558234Skato			B_flag = 1;
18658234Skato			break;
187156020Simp		case 'I':
188156020Simp			I_flag = 1;
189156020Simp			break;
19058234Skato		case 'a':
19158234Skato			a_flag = 1;
19258234Skato			break;
19358234Skato		case 'f':
19458234Skato			f_flag = optarg;
19558234Skato			break;
19658234Skato		case 'i':
19758234Skato			i_flag = 1;
19858234Skato			break;
19958234Skato		case 's':
20058234Skato			s_flag = 1;
20158234Skato			break;
20258234Skato		case 't':
20358234Skato			t_flag = 1;
20458234Skato			break;
20558234Skato		case 'u':
20658234Skato			u_flag = 1;
20758234Skato			break;
20858234Skato		case 'v':
20958234Skato			v_flag = 1;
21058234Skato			break;
21158234Skato		case '1':
21258234Skato		case '2':
21358234Skato		case '3':
21458234Skato		case '4':
21558234Skato		case '5':
21658234Skato		case '6':
21758234Skato		case '7':
21858234Skato		case '8':
21958234Skato			partition = c - '0';
22058234Skato			break;
22158234Skato		default:
22258234Skato			usage();
22358234Skato		}
22458234Skato	if (f_flag || i_flag)
22558234Skato		u_flag = 1;
22658234Skato	if (t_flag)
22758234Skato		v_flag = 1;
22858234Skato	argc -= optind;
22958234Skato	argv += optind;
23058234Skato
231106047Snyan	if (argc == 0) {
232106047Snyan		disk = get_rootdisk();
233106047Snyan	} else {
234106047Snyan		if (stat(argv[0], &sb) == 0) {
235106047Snyan			/* OK, full pathname given */
23658234Skato			disk = argv[0];
237136887Snyan		} else if (errno == ENOENT && argv[0][0] != '/') {
238106047Snyan			/* Try prepending "/dev" */
239106047Snyan			asprintf(&disk, "%s%s", _PATH_DEV, argv[0]);
240106047Snyan			if (disk == NULL)
241106047Snyan				errx(1, "out of memory");
242106047Snyan		} else {
243106047Snyan			/* other stat error, let it fail below */
244106047Snyan			disk = argv[0];
24558234Skato		}
24658234Skato	}
247106047Snyan	if (open_disk(u_flag) < 0)
248106047Snyan		err(1, "cannot open disk %s", disk);
24958234Skato
250106047Snyan	if (s_flag) {
25158234Skato		if (read_s0())
25258234Skato			err(1, "read_s0");
25358234Skato		printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads,
25458234Skato		    dos_sectors);
255168934Simp		printf("Part  %11s %11s %4s %4s %-16s\n", "Start", "Size", "MID",
256168934Simp		    "SID", "Name");
257254015Smarcel		for (i = 0; i < PC98_NPARTS; i++) {
258108650Snyan			partp = ((struct pc98_partition *) &mboot.parts) + i;
25958234Skato			if (partp->dp_sid == 0)
26058234Skato				continue;
261168934Simp			printf("%4d: %11u %11u 0x%02x 0x%02x %-16.16s\n", i + 1,
26258234Skato			    partp->dp_scyl * cylsecs,
26358234Skato			    (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs,
264168934Simp			    partp->dp_mid, partp->dp_sid, partp->dp_name);
26558234Skato		}
26658234Skato		exit(0);
26758234Skato	}
26858234Skato
26958234Skato	printf("******* Working on device %s *******\n",disk);
27058234Skato
271156020Simp	if (I_flag) {
272156020Simp		read_s0();
273156020Simp		reset_boot();
274156020Simp		partp = (struct pc98_partition *) (&mboot.parts[0]);
275156020Simp		partp->dp_mid = DOSMID_386BSD;
276156020Simp		partp->dp_sid = DOSSID_386BSD;
277168934Simp		strncpy(partp->dp_name, "FreeBSD", sizeof(partp->dp_name));
278156020Simp		/* Start c/h/s. */
279156020Simp		partp->dp_scyl = partp->dp_ipl_cyl = 1;
280156020Simp		partp->dp_shd = partp->dp_ipl_head = 1;
281156020Simp		partp->dp_ssect = partp->dp_ipl_sct = 0;
282156020Simp
283156020Simp		/* End c/h/s. */
284156020Simp		partp->dp_ecyl = dos_cyls - 1;
285156020Simp		partp->dp_ehd = dos_cylsecs / dos_sectors;
286156020Simp		partp->dp_esect = dos_sectors;
287156020Simp
288156020Simp		if (v_flag)
289156020Simp			print_s0(-1);
290156020Simp		if (!t_flag)
291156020Simp			write_s0();
292156020Simp		exit(0);
293156020Simp	}
294156020Simp
295106047Snyan	if (f_flag) {
29658234Skato	    if (v_flag)
29758234Skato		print_s0(-1);
29858234Skato	    if (!t_flag)
29958234Skato		write_s0();
300106047Snyan	} else {
30158234Skato	    if(u_flag)
30258234Skato		get_params_to_use();
30358234Skato	    else
30458234Skato		print_params();
30558234Skato
30658234Skato	    if (read_s0())
307106047Snyan		init_sector0(dos_sectors);
30858234Skato
30958234Skato	    printf("Media sector size is %d\n", secsize);
31058234Skato	    printf("Warning: BIOS sector numbering starts with sector 1\n");
31158234Skato	    printf("Information from DOS bootblock is:\n");
31258234Skato	    if (partition == -1)
313254015Smarcel		for (i = 1; i <= PC98_NPARTS; i++)
314168934Simp		    change_part(i, v_flag);
31558234Skato	    else
316168934Simp		change_part(partition, 1);
31758234Skato
31858234Skato	    if (u_flag || a_flag)
31958234Skato		change_active(partition);
32058234Skato
32158234Skato	    if (B_flag)
32258234Skato		change_code();
32358234Skato
32458234Skato	    if (u_flag || a_flag || B_flag) {
325106047Snyan		if (!t_flag) {
32658234Skato		    printf("\nWe haven't changed the partition table yet.  ");
32758234Skato		    printf("This is your last chance.\n");
32858234Skato		}
32958234Skato		print_s0(-1);
330106047Snyan		if (!t_flag) {
33158234Skato		    if (ok("Should we write new partition table?"))
33258234Skato			write_s0();
333106047Snyan		} else {
33458234Skato		    printf("\n-t flag specified -- partition table not written.\n");
33558234Skato		}
33658234Skato	    }
33758234Skato	}
33858234Skato
33958234Skato	exit(0);
34058234Skato}
34158234Skato
34258234Skatostatic void
34358234Skatousage()
34458234Skato{
34558234Skato	fprintf(stderr, "%s%s",
346156020Simp		"usage: fdisk [-BIaistu] [-12345678] [disk]\n",
34758234Skato 		"       fdisk -f configfile [-itv] [disk]\n");
34858234Skato        exit(1);
34958234Skato}
35058234Skato
351168934Simpstatic struct pc98_partition mtpart;
352168934Simp
353168934Simpstatic int
354168934Simppart_unused(int i)
355168934Simp{
356168934Simp	struct	  pc98_partition *partp;
357168934Simp
358168934Simp	partp = ((struct pc98_partition *) &mboot.parts) + i - 1;
359168934Simp	return (bcmp(partp, &mtpart, sizeof (struct pc98_partition)) == 0);
360168934Simp}
361168934Simp
36258234Skatostatic void
36358234Skatoprint_s0(int which)
36458234Skato{
365106047Snyan	int	i;
36658234Skato
36758234Skato	print_params();
36858234Skato	printf("Information from DOS bootblock is:\n");
369168934Simp	if (which == -1) {
370254015Smarcel		for (i = 1; i <= PC98_NPARTS; i++)
371168934Simp			if (v_flag || !part_unused(i)) {
372168934Simp				printf("%d: ", i);
373168934Simp				print_part(i);
374168934Simp			}
375168934Simp	}
37658234Skato	else
37758234Skato		print_part(which);
37858234Skato}
37958234Skato
38058234Skatostatic void
38158234Skatoprint_part(int i)
38258234Skato{
383108650Snyan	struct	  pc98_partition *partp;
384106047Snyan	u_int64_t part_sz, part_mb;
38558234Skato
386168934Simp	if (part_unused(i)) {
38758234Skato		printf("<UNUSED>\n");
38858234Skato		return;
38958234Skato	}
39058234Skato	/*
39158234Skato	 * Be careful not to overflow.
39258234Skato	 */
393168934Simp	partp = ((struct pc98_partition *) &mboot.parts) + i - 1;
394106047Snyan	part_sz = (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs;
395106047Snyan	part_mb = part_sz * secsize;
396106047Snyan	part_mb /= (1024 * 1024);
397106047Snyan	printf("sysmid %d (%#04x),(%s)\n", partp->dp_mid, partp->dp_mid,
398106047Snyan	    get_type(partp->dp_mid));
399106047Snyan	printf("    start %lu, size %lu (%ju Meg), sid %d\n",
400106047Snyan		(u_long)(partp->dp_scyl * cylsecs), (u_long)part_sz,
401106047Snyan		(uintmax_t)part_mb, partp->dp_sid);
402106047Snyan	printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n"
403104617Snyan		,partp->dp_scyl
404106047Snyan		,partp->dp_shd
405104617Snyan		,partp->dp_ssect
406104617Snyan		,partp->dp_ecyl
407106047Snyan		,partp->dp_ehd
408106047Snyan		,partp->dp_esect);
409145765Snyan	printf ("\tsystem Name %.16s\n", partp->dp_name);
41058234Skato}
41158234Skato
41258234Skato
41358234Skatostatic void
41458234Skatoinit_boot(void)
41558234Skato{
41658234Skato
417254015Smarcel	mboot.signature = PC98_MAGIC;
41858234Skato}
41958234Skato
42058234Skato
42158234Skatostatic void
42258234Skatoinit_sector0(unsigned long start)
42358234Skato{
424108650Snyan	struct pc98_partition *partp =
425145765Snyan		(struct pc98_partition *)(&mboot.parts[0]);
42658234Skato
42758234Skato	init_boot();
42858234Skato
42958234Skato	partp->dp_mid = DOSMID_386BSD;
43058234Skato	partp->dp_sid = DOSSID_386BSD;
43158234Skato
432145765Snyan	dos(start, disksecs - start, partp);
43358234Skato}
43458234Skato
43558234Skatostatic void
436168934Simpchange_part(int i, int force)
43758234Skato{
438108650Snyan	struct pc98_partition *partp =
439108650Snyan		((struct pc98_partition *) &mboot.parts) + i - 1;
44058234Skato
441168934Simp	if (!force && part_unused(i))
442168934Simp		return;
44358234Skato
444168934Simp	printf("The data for partition %d is:\n", i);
445168934Simp	print_part(i);
44658234Skato
447168934Simp	if (u_flag && ok("Do you want to change it?")) {
448168934Simp		int tmp;
449168934Simp
450168934Simp		if (i_flag) {
451168934Simp			bzero((char *)partp, sizeof (struct pc98_partition));
452168934Simp			if (i == 1) {
453168934Simp				init_sector0(1);
454168934Simp				printf("\nThe static data for the slice 1 has been reinitialized to:\n");
455168934Simp				print_part(i);
456168934Simp			}
45758234Skato		}
458168934Simp		do {
459168934Simp			int x_start = partp->dp_scyl * cylsecs ;
460168934Simp			int x_size  = (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs;
461168934Simp			Decimal("sysmid", partp->dp_mid, tmp);
462168934Simp			Decimal("syssid", partp->dp_sid, tmp);
463168934Simp			String ("system name", partp->dp_name, 16);
464168934Simp			Decimal("start", x_start, tmp);
465168934Simp			Decimal("size", x_size, tmp);
46658234Skato
467168934Simp			if (ok("Explicitly specify beg/end address ?"))
468168934Simp			{
469168934Simp				int	tsec,tcyl,thd;
470168934Simp				tcyl = partp->dp_scyl;
471168934Simp				thd = partp->dp_shd;
472168934Simp				tsec = partp->dp_ssect;
473168934Simp				Decimal("beginning cylinder", tcyl, tmp);
474168934Simp				Decimal("beginning head", thd, tmp);
475168934Simp				Decimal("beginning sector", tsec, tmp);
476168934Simp				partp->dp_scyl = tcyl;
477168934Simp				partp->dp_ssect = tsec;
478168934Simp				partp->dp_shd = thd;
479168934Simp				partp->dp_ipl_cyl = partp->dp_scyl;
480168934Simp				partp->dp_ipl_sct = partp->dp_ssect;
481168934Simp				partp->dp_ipl_head = partp->dp_shd;
482106047Snyan
483168934Simp				tcyl = partp->dp_ecyl;
484168934Simp				thd = partp->dp_ehd;
485168934Simp				tsec = partp->dp_esect;
486168934Simp				Decimal("ending cylinder", tcyl, tmp);
487168934Simp				Decimal("ending head", thd, tmp);
488168934Simp				Decimal("ending sector", tsec, tmp);
489168934Simp				partp->dp_ecyl = tcyl;
490168934Simp				partp->dp_esect = tsec;
491168934Simp				partp->dp_ehd = thd;
492168934Simp			} else
493168934Simp				dos(x_start, x_size, partp);
49458234Skato
495168934Simp			print_part(i);
496168934Simp		} while (!ok("Are we happy with this entry?"));
497168934Simp	}
49858234Skato}
49958234Skato
50058234Skatostatic void
50158234Skatoprint_params()
50258234Skato{
50358234Skato	printf("parameters extracted from in-core disklabel are:\n");
50458234Skato	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
50558234Skato			,cyls,heads,sectors,cylsecs);
506145765Snyan	if (dos_cyls > 65535 || dos_heads > 255 || dos_sectors > 255)
50758234Skato		printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
50858234Skato	printf("parameters to be used for BIOS calculations are:\n");
50958234Skato	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
51058234Skato		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
51158234Skato}
51258234Skato
51358234Skatostatic void
51458234Skatochange_active(int which)
51558234Skato{
516145765Snyan	struct pc98_partition *partp = &mboot.parts[0];
517106047Snyan	int active, i, new, tmp;
518106047Snyan
519106047Snyan	active = -1;
520254015Smarcel	for (i = 0; i < PC98_NPARTS; i++) {
521190027Snyan		if ((partp[i].dp_sid & PC98_SID_ACTIVE) == 0)
522106047Snyan			continue;
523106047Snyan		printf("Partition %d is marked active\n", i + 1);
524106047Snyan		if (active == -1)
525106047Snyan			active = i + 1;
526106047Snyan	}
52758234Skato	if (a_flag && which != -1)
52858234Skato		active = which;
529106047Snyan	else if (active == -1)
530106047Snyan		active = 1;
531106047Snyan
53258234Skato	if (!ok("Do you want to change the active partition?"))
53358234Skato		return;
53458234Skatosetactive:
53558234Skato	do {
536106047Snyan		new = active;
537106047Snyan		Decimal("active partition", new, tmp);
538145765Snyan		if (new < 1 || new > 8) {
539145765Snyan			printf("Active partition number must be in range 1-8."
54058234Skato					"  Try again.\n");
54158234Skato			goto setactive;
54258234Skato		}
543106047Snyan		active = new;
54458234Skato	} while (!ok("Are you happy with this choice"));
545145765Snyan	if (active > 0 && active <= 8)
546190027Snyan		partp[active-1].dp_sid |= PC98_SID_ACTIVE;
54758234Skato}
54858234Skato
54958234Skatostatic void
55058234Skatochange_code()
55158234Skato{
55258234Skato	if (ok("Do you want to change the boot code?"))
55358234Skato		init_boot();
55458234Skato}
55558234Skato
55658234Skatovoid
55758234Skatoget_params_to_use()
55858234Skato{
55958234Skato	int	tmp;
56058234Skato	print_params();
56158234Skato	if (ok("Do you want to change our idea of what BIOS thinks ?"))
56258234Skato	{
56358234Skato		do
56458234Skato		{
56558234Skato			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
56658234Skato			Decimal("BIOS's idea of #heads", dos_heads, tmp);
56758234Skato			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
56858234Skato			dos_cylsecs = dos_heads * dos_sectors;
56958234Skato			print_params();
57058234Skato		}
57158234Skato		while(!ok("Are you happy with this choice"));
57258234Skato	}
57358234Skato}
57458234Skato
57558234Skato
57658234Skato/***********************************************\
57758234Skato* Change real numbers into strange dos numbers	*
57858234Skato\***********************************************/
57958234Skatostatic void
580145765Snyandos(u_int32_t start, u_int32_t size, struct pc98_partition *partp)
58158234Skato{
582106047Snyan	u_int32_t end;
58358234Skato
584145765Snyan	if (partp->dp_mid == 0 && partp->dp_sid == 0 &&
585145765Snyan	    start == 0 && size == 0) {
586106047Snyan		memcpy(partp, &mtpart, sizeof(*partp));
587106047Snyan		return;
588106047Snyan	}
58958234Skato
590106047Snyan	/* Start c/h/s. */
591145765Snyan	partp->dp_scyl = partp->dp_ipl_cyl = start / dos_cylsecs;
592145765Snyan	partp->dp_shd = partp->dp_ipl_head = start % dos_cylsecs / dos_sectors;
593145765Snyan	partp->dp_ssect = partp->dp_ipl_sct = start % dos_sectors;
59458234Skato
595106047Snyan	/* End c/h/s. */
596145765Snyan	end = start + size - cylsecs;
597145765Snyan	partp->dp_ecyl = end / dos_cylsecs;
598106047Snyan	partp->dp_ehd = end % dos_cylsecs / dos_sectors;
599145765Snyan	partp->dp_esect = end % dos_sectors;
600106047Snyan}
60158234Skato
60258234Skatostatic int
603106047Snyanopen_disk(int flag)
60458234Skato{
605106047Snyan	struct stat 	st;
606148062Snyan	int rwmode;
60758234Skato
60858234Skato	if (stat(disk, &st) == -1) {
609106047Snyan		if (errno == ENOENT)
610106047Snyan			return -2;
61158234Skato		warnx("can't get file status of %s", disk);
61258234Skato		return -1;
61358234Skato	}
61458234Skato	if ( !(st.st_mode & S_IFCHR) )
61558234Skato		warnx("device %s is not character special", disk);
616156020Simp	rwmode = I_flag || a_flag || B_flag || flag ? O_RDWR : O_RDONLY;
617110679Snyan	fd = open(disk, rwmode);
618148062Snyan	if (fd == -1 && errno == EPERM && rwmode == O_RDWR)
619148062Snyan		fd = open(disk, O_RDONLY);
620110679Snyan	if (fd == -1 && errno == ENXIO)
621110679Snyan		return -2;
622110679Snyan	if (fd == -1) {
623106047Snyan		warnx("can't open device %s", disk);
624106047Snyan		return -1;
625106047Snyan	}
626106047Snyan	if (get_params() == -1) {
62758234Skato		warnx("can't get disk parameters on %s", disk);
62858234Skato		return -1;
62958234Skato	}
63058234Skato	return fd;
63158234Skato}
63258234Skato
63358234Skatostatic ssize_t
63458234Skatoread_disk(off_t sector, void *buf)
63558234Skato{
636145765Snyan
637145765Snyan	lseek(fd, (sector * 512), 0);
638106047Snyan	return read(fd, buf,
639106047Snyan		    secsize > MIN_SEC_SIZE ? secsize : MIN_SEC_SIZE * 2);
64058234Skato}
64158234Skato
642148062Snyanstatic int
64358234Skatowrite_disk(off_t sector, void *buf)
64458234Skato{
645148062Snyan	int error;
646148062Snyan	struct gctl_req *grq;
647148062Snyan	const char *q;
648148062Snyan	char fbuf[BUFSIZ];
649156020Simp	int i, fdw, sz;
650110679Snyan
651156020Simp	sz = secsize > MIN_SEC_SIZE ? secsize : MIN_SEC_SIZE * 2;
652148062Snyan	grq = gctl_get_handle();
653148062Snyan	gctl_ro_param(grq, "verb", -1, "write PC98");
654148062Snyan	gctl_ro_param(grq, "class", -1, "PC98");
655148062Snyan	q = strrchr(disk, '/');
656148062Snyan	if (q == NULL)
657148062Snyan		q = disk;
658148062Snyan	else
659148062Snyan		q++;
660148062Snyan	gctl_ro_param(grq, "geom", -1, q);
661156020Simp	gctl_ro_param(grq, "data", sz, buf);
662148062Snyan	q = gctl_issue(grq);
663150268Snyan	if (q == NULL) {
664150268Snyan		gctl_free(grq);
665148062Snyan		return(0);
666150268Snyan	}
667156020Simp	warnx("Geom problem: %s", q);
668150268Snyan	gctl_free(grq);
669148062Snyan
670156020Simp	warnx("Warning: Partitioning via geom failed, trying raw write");
671156020Simp	error = pwrite(fd, buf, sz, sector * 512);
672156020Simp	if (error == sz)
673148062Snyan		return (0);
674148062Snyan
675254015Smarcel	for (i = 0; i < PC98_NPARTS; i++) {
676148062Snyan		sprintf(fbuf, "%ss%d", disk, i + 1);
677148062Snyan		fdw = open(fbuf, O_RDWR, 0);
678148062Snyan		if (fdw < 0)
679148062Snyan			continue;
680148062Snyan		error = ioctl(fdw, DIOCSPC98, buf);
681148062Snyan		close(fdw);
682148062Snyan		if (error == 0)
683148062Snyan			return (0);
684110679Snyan	}
685148062Snyan	warnx("Failed to write sector zero");
686148062Snyan	return(EINVAL);
68758234Skato}
68858234Skato
68958234Skatostatic int
69058234Skatoget_params()
69158234Skato{
692106047Snyan	int error;
693106047Snyan	u_int u;
694106047Snyan	off_t o;
69558234Skato
696106047Snyan	error = ioctl(fd, DIOCGFWSECTORS, &u);
697106047Snyan	if (error == 0)
698106047Snyan		sectors = dos_sectors = u;
699114413Snyan	else
700145765Snyan		sectors = dos_sectors = 17;
701114413Snyan
702106047Snyan	error = ioctl(fd, DIOCGFWHEADS, &u);
703106047Snyan	if (error == 0)
704106047Snyan		heads = dos_heads = u;
705114413Snyan	else
706145765Snyan		heads = dos_heads = 8;
707106047Snyan
70858234Skato	dos_cylsecs = cylsecs = heads * sectors;
70958234Skato	disksecs = cyls * heads * sectors;
710106047Snyan
711106047Snyan	error = ioctl(fd, DIOCGSECTORSIZE, &u);
712114413Snyan	if (error != 0 || u == 0)
713106047Snyan		u = 512;
714106047Snyan	secsize = u;
71558234Skato
716106047Snyan	error = ioctl(fd, DIOCGMEDIASIZE, &o);
717106047Snyan	if (error == 0) {
718106047Snyan		disksecs = o / u;
719106047Snyan		cyls = dos_cyls = o / (u * dos_heads * dos_sectors);
720106047Snyan	}
721106047Snyan
722106047Snyan	return (disksecs);
72358234Skato}
72458234Skato
72558234Skato
72658234Skatostatic int
72758234Skatoread_s0()
72858234Skato{
729145765Snyan
73058234Skato	if (read_disk(0, (char *) mboot.bootinst) == -1) {
73158234Skato		warnx("can't read fdisk partition table");
73258234Skato		return -1;
73358234Skato	}
734254015Smarcel	if (mboot.signature != PC98_MAGIC) {
73558234Skato		warnx("invalid fdisk partition table found");
73658234Skato		/* So should we initialize things */
73758234Skato		return -1;
73858234Skato	}
739145765Snyan
74058234Skato	return 0;
74158234Skato}
74258234Skato
74358234Skatostatic int
74458234Skatowrite_s0()
74558234Skato{
746106047Snyan
74758234Skato	if (iotest) {
74858234Skato		print_s0(-1);
74958234Skato		return 0;
75058234Skato	}
751145765Snyan
75258234Skato	/*
75358234Skato	 * write enable label sector before write (if necessary),
75458234Skato	 * disable after writing.
75558234Skato	 * needed if the disklabel protected area also protects
75658234Skato	 * sector 0. (e.g. empty disk)
75758234Skato	 */
75858234Skato	if (write_disk(0, (char *) mboot.bootinst) == -1) {
75958234Skato		warn("can't write fdisk partition table");
76058234Skato		return -1;
761106047Snyan	}
762145765Snyan
76358234Skato	return(0);
76458234Skato}
76558234Skato
76658234Skato
76758234Skatostatic int
768106047Snyanok(const char *str)
76958234Skato{
77058234Skato	printf("%s [n] ", str);
771106047Snyan	fflush(stdout);
772106047Snyan	if (fgets(lbuf, LBUF, stdin) == NULL)
773106047Snyan		exit(1);
77458234Skato	lbuf[strlen(lbuf)-1] = 0;
77558234Skato
77658234Skato	if (*lbuf &&
77758234Skato		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
77858234Skato		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
77958234Skato		return 1;
78058234Skato	else
78158234Skato		return 0;
78258234Skato}
78358234Skato
78458234Skatostatic int
785106047Snyandecimal(const char *str, int *num, int deflt)
78658234Skato{
787106047Snyan	int acc = 0, c;
788106047Snyan	char *cp;
78958234Skato
79058234Skato	while (1) {
79158234Skato		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
792106047Snyan		fflush(stdout);
793106047Snyan		if (fgets(lbuf, LBUF, stdin) == NULL)
794106047Snyan			exit(1);
79558234Skato		lbuf[strlen(lbuf)-1] = 0;
79658234Skato
79758234Skato		if (!*lbuf)
79858234Skato			return 0;
79958234Skato
80058234Skato		cp = lbuf;
80158234Skato		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
80258234Skato		if (!c)
80358234Skato			return 0;
80458234Skato		while ((c = *cp++)) {
80558234Skato			if (c <= '9' && c >= '0')
80658234Skato				acc = acc * 10 + c - '0';
80758234Skato			else
80858234Skato				break;
80958234Skato		}
81058234Skato		if (c == ' ' || c == '\t')
81158234Skato			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
81258234Skato		if (!c) {
81358234Skato			*num = acc;
81458234Skato			return 1;
81558234Skato		} else
81658234Skato			printf("%s is an invalid decimal number.  Try again.\n",
81758234Skato				lbuf);
81858234Skato	}
81958234Skato
82058234Skato}
82158234Skato
82258234Skatostatic int
823145765Snyanstring(const char *str, char **ans)
82458234Skato{
825106047Snyan	int i, c;
826106047Snyan	char *cp = lbuf;
82758234Skato
82858234Skato	while (1) {
82958234Skato		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
83058234Skato		fgets(lbuf, LBUF, stdin);
83158234Skato		lbuf[strlen(lbuf)-1] = 0;
83258234Skato
83358234Skato		if (!*lbuf)
83458234Skato			return 0;
83558234Skato
83658234Skato		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
83758234Skato		if (c == '"') {
83858234Skato			c = *++cp;
83958234Skato			*ans = cp;
84058234Skato			while ((c = *cp) && c != '"') cp++;
84158234Skato		} else {
84258234Skato			*ans = cp;
84358234Skato			while ((c = *cp) && c != ' ' && c != '\t') cp++;
84458234Skato		}
84558234Skato
84658234Skato		for (i = strlen(*ans); i < 16; i++)
84758234Skato			(*ans)[i] = ' ';
84858234Skato		(*ans)[16] = 0;
849106047Snyan
85058234Skato		return 1;
85158234Skato	}
85258234Skato}
85358234Skato
854106047Snyanstatic const char *
85558234Skatoget_type(int type)
85658234Skato{
85758234Skato	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
85858234Skato	int	counter = 0;
85958234Skato	struct	part_type *ptr = part_types;
86058234Skato
86158234Skato
862106047Snyan	while(counter < numentries) {
86358234Skato		if(ptr->type == (type & 0x7f))
864106047Snyan			return(ptr->name);
86558234Skato		ptr++;
86658234Skato		counter++;
86758234Skato	}
86858234Skato	return("unknown");
86958234Skato}
87058234Skato
871106047Snyan/*
872106047Snyan * Try figuring out the root device's canonical disk name.
873106047Snyan * The following choices are considered:
874106047Snyan *   /dev/ad0s1a     => /dev/ad0
875106047Snyan *   /dev/da0a       => /dev/da0
876106047Snyan *   /dev/vinum/root => /dev/vinum/root
877106047Snyan */
878106047Snyanstatic char *
879106047Snyanget_rootdisk(void)
88058234Skato{
881106047Snyan	struct statfs rootfs;
882106047Snyan	regex_t re;
883106047Snyan#define NMATCHES 2
884106047Snyan	regmatch_t rm[NMATCHES];
885106047Snyan	char *s;
886106047Snyan	int rv;
88758234Skato
888106047Snyan	if (statfs("/", &rootfs) == -1)
889106047Snyan		err(1, "statfs(\"/\")");
89058234Skato
891106047Snyan	if ((rv = regcomp(&re, "^(/dev/[a-z]+[0-9]+)([sp][0-9]+)?[a-h]?$",
892106047Snyan		    REG_EXTENDED)) != 0)
893106047Snyan		errx(1, "regcomp() failed (%d)", rv);
894106047Snyan	if ((rv = regexec(&re, rootfs.f_mntfromname, NMATCHES, rm, 0)) != 0)
895106047Snyan		errx(1,
896106047Snyan"mounted root fs resource doesn't match expectations (regexec returned %d)",
897106047Snyan		    rv);
898106047Snyan	if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL)
899106047Snyan		errx(1, "out of memory");
900106047Snyan	memcpy(s, rootfs.f_mntfromname + rm[1].rm_so,
901106047Snyan	    rm[1].rm_eo - rm[1].rm_so);
902106047Snyan	s[rm[1].rm_eo - rm[1].rm_so] = 0;
90358234Skato
904106047Snyan	return s;
90558234Skato}
906156020Simp
907156020Simpstatic void
908156020Simpreset_boot(void)
909156020Simp{
910156020Simp	int i;
911156020Simp	struct pc98_partition *partp;
912156020Simp
913156020Simp	init_boot();
914254015Smarcel	for (i = 1; i <= PC98_NPARTS; i++) {
915156020Simp		partp = ((struct pc98_partition *) &mboot.parts) + i - 1;
916156020Simp		bzero((char *)partp, sizeof (struct pc98_partition));
917156020Simp	}
918156020Simp}
919