fdisk.c revision 50370
1162856Sdes/*
260573Skris * Mach Operating System
360573Skris * Copyright (c) 1992 Carnegie Mellon University
460573Skris * All Rights Reserved.
560573Skris *
660573Skris * Permission to use, copy, modify and distribute this software and its
760573Skris * documentation is hereby granted, provided that both the copyright
860573Skris * notice and this permission notice appear in all copies of the
960573Skris * software, derivative works or modified versions, and any portions
1060573Skris * thereof, and that both notices appear in supporting documentation.
1160573Skris *
1260573Skris * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
1360573Skris * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1460573Skris * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1560573Skris *
1660573Skris * Carnegie Mellon requests users of this software to return to
1760573Skris *
1860573Skris *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
1960573Skris *  School of Computer Science
2060573Skris *  Carnegie Mellon University
2160573Skris *  Pittsburgh PA 15213-3890
2260573Skris *
2360573Skris * any improvements or extensions that they make and grant Carnegie Mellon
2460573Skris * the rights to redistribute these changes.
2565674Skris */
2660573Skris
27162856Sdes#ifndef lint
2860573Skrisstatic const char rcsid[] =
29162856Sdes	"$Id: fdisk.c,v 1.30 1999/08/23 11:06:19 phk Exp $";
30162856Sdes#endif /* not lint */
31162856Sdes
32162856Sdes#include <sys/disklabel.h>
33162856Sdes#include <sys/stat.h>
34162856Sdes#include <ctype.h>
35162856Sdes#include <fcntl.h>
3676262Sgreen#include <err.h>
3760573Skris#include <errno.h>
3876262Sgreen#include <stdio.h>
39162856Sdes#include <stdlib.h>
4060573Skris#include <string.h>
4160573Skris#include <unistd.h>
42162856Sdes
43162856Sdesint iotest;
4460573Skris
4560573Skris#define LBUF 100
4676262Sgreenstatic char lbuf[LBUF];
47147005Sdes
48162856Sdes/*
4960573Skris *
50124211Sdes * Ported to 386bsd by Julian Elischer  Thu Oct 15 20:26:46 PDT 1992
51124211Sdes *
52124211Sdes * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
53162856Sdes *	Copyright (c) 1989	Robert. V. Baron
54124211Sdes *	Created.
5560573Skris */
5660573Skris
5776262Sgreen#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp
58124211Sdes#define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp
59147005Sdes#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); }
6060573Skris
6198684Sdes#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
6298684Sdes
6398684Sdes#define MAX_SEC_SIZE 2048	/* maximum section size that is supported */
6498684Sdes#define MIN_SEC_SIZE 512	/* the sector size to start sensing at */
6598684Sdesint secsize = 0;		/* the sensed sector size */
6698684Sdes
6798684Sdesconst char *disk;
68124211Sdesconst char *disks[] =
69124211Sdes{
70124211Sdes  "/dev/rwd0", "/dev/rda0", "/dev/rod0", 0
7198684Sdes};
7298684Sdes
7398684Sdesstruct disklabel disklabel;		/* disk parameters */
7498684Sdes
75124211Sdesint cyls, sectors, heads, cylsecs, disksecs;
76124211Sdes
77124211Sdesstruct mboot
7898684Sdes{
7998684Sdes	unsigned char padding[2]; /* force the longs to be long aligned */
8098684Sdes	unsigned char bootinst[DOSPARTOFF];
8198684Sdes	struct	dos_partition parts[4];
8269591Sgreen	unsigned short int	signature;
8369591Sgreen	/* room to read in MBRs that are bigger then DEV_BSIZE */
8460573Skris	unsigned char large_sector_overflow[MAX_SEC_SIZE-MIN_SEC_SIZE];
8560573Skris};
8692559Sdesstruct mboot mboot;
8792559Sdes
8860573Skris#define ACTIVE 0x80
8960573Skris#define BOOT_MAGIC 0xAA55
9092559Sdes
9192559Sdesint dos_cyls;
9298684Sdesint dos_heads;
9360573Skrisint dos_sectors;
9460573Skrisint dos_cylsecs;
9569591Sgreen
9660573Skris#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
9760573Skris#define DOSCYL(c)	(c & 0xff)
98126277Sdesstatic int partition = -1;
99126277Sdes
10060573Skris
10192559Sdes#define MAX_ARGS	10
10292559Sdes
10376262Sgreenstatic int	current_line_number;
10476262Sgreen
10592559Sdesstatic int	geom_processed = 0;
10660573Skrisstatic int	part_processed = 0;
10769591Sgreenstatic int	active_processed = 0;
10860573Skris
10960573Skris
110162856Sdestypedef struct cmd {
11192559Sdes    char		cmd;
11292559Sdes    int			n_args;
11360573Skris    struct arg {
11469591Sgreen	char	argtype;
11576262Sgreen	int	arg_val;
116106130Sdes    }			args[MAX_ARGS];
11760573Skris} CMD;
11892559Sdes
11960573Skris
12069591Sgreenstatic int B_flag  = 0;		/* replace boot code */
12169591Sgreenstatic int a_flag  = 0;		/* set active partition */
12269591Sgreenstatic char *b_flag = NULL;	/* path to boot code */
12360573Skrisstatic int e_flag  = 0;		/* use entire disk for FreeBSD */
12469591Sgreenstatic int i_flag  = 0;		/* replace partition data */
125106130Sdesstatic int u_flag  = 0;		/* update partition data */
12660573Skrisstatic int t_flag  = 0;		/* test only, if f_flag is given */
12760573Skrisstatic char *f_flag = NULL;	/* Read config info from file */
12860573Skrisstatic int v_flag  = 0;		/* Be verbose */
12960573Skris
13060573Skrisstruct part_type
13160573Skris{
132106130Sdes unsigned char type;
13360573Skris char *name;
13460573Skris}part_types[] =
13560573Skris{
13660573Skris	 {0x00, "unused"}
13760573Skris	,{0x01, "Primary DOS with 12 bit FAT"}
13860573Skris	,{0x02, "XENIX / filesystem"}
13960573Skris	,{0x03, "XENIX /usr filesystem"}
14060573Skris	,{0x04, "Primary DOS with 16 bit FAT (<= 32MB)"}
14160573Skris	,{0x05, "Extended DOS"}
14260573Skris	,{0x06, "Primary 'big' DOS (> 32MB)"}
14360573Skris	,{0x07, "OS/2 HPFS, NTFS, QNX or Advanced UNIX"}
144162856Sdes	,{0x08, "AIX filesystem"}
14592559Sdes	,{0x09, "AIX boot partition or Coherent"}
14692559Sdes	,{0x0A, "OS/2 Boot Manager or OPUS"}
14760573Skris	,{0x0B, "DOS or Windows 95 with 32 bit FAT"}
14869591Sgreen	,{0x0C, "DOS or Windows 95 with 32 bit FAT, LBA"}
14969591Sgreen	,{0x0E, "Primary 'big' DOS (> 32MB, LBA)"}
15076262Sgreen	,{0x0F, "Extended DOS, LBA"}
15160573Skris	,{0x10, "OPUS"}
15299053Sdes	,{0x40, "VENIX 286"}
15399053Sdes	,{0x50, "DM"}
15499053Sdes	,{0x51, "DM"}
15560573Skris	,{0x52, "CP/M or Microport SysV/AT"}
156124211Sdes	,{0x56, "GB"}
15799053Sdes	,{0x61, "Speed"}
15899053Sdes	,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
15999053Sdes	,{0x64, "Novell Netware 2.xx"}
16069591Sgreen	,{0x65, "Novell Netware 3.xx"}
16169591Sgreen	,{0x75, "PCIX"}
16260573Skris	,{0x80, "Minix 1.1 ... 1.4a"}
16369591Sgreen	,{0x81, "Minix 1.4b ... 1.5.10"}
16469591Sgreen	,{0x82, "Linux swap or Solaris x86"}
16569591Sgreen	,{0x83, "Linux filesystem"}
16660573Skris	,{0x93, "Amoeba filesystem"}
16776262Sgreen	,{0x94, "Amoeba bad block table"}
16860573Skris	,{0x9F, "BSD/OS"}
16976262Sgreen	,{0xA5, "FreeBSD/NetBSD/386BSD"}
17076262Sgreen	,{0xA6, "OpenBSD"}
17176262Sgreen	,{0xA7, "NEXTSTEP"}
17276262Sgreen	,{0xA9, "NetBSD"}
17369591Sgreen	,{0xB7, "BSDI BSD/386 filesystem"}
17498684Sdes	,{0xB8, "BSDI BSD/386 swap"}
175128460Sdes	,{0xDB, "Concurrent CPM or C.DOS or CTOS"}
17698684Sdes	,{0xE1, "Speed"}
17769591Sgreen	,{0xE3, "Speed"}
17869591Sgreen	,{0xE4, "Speed"}
17969591Sgreen	,{0xF1, "Speed"}
180137019Sdes	,{0xF2, "DOS 3.3+ Secondary"}
181124211Sdes	,{0xF4, "Speed"}
182147005Sdes	,{0xFF, "BBT (Bad Blocks Table)"}
183147005Sdes};
184147005Sdes
18560573Skrisstatic void print_s0(int which);
186157019Sdesstatic void print_part(int i);
187157019Sdesstatic void init_sector0(unsigned long start);
188157019Sdesstatic void init_boot(void);
189157019Sdesstatic void change_part(int i);
190137019Sdesstatic void print_params();
19198684Sdesstatic void change_active(int which);
19269591Sgreenstatic void change_code();
19392559Sdesstatic void get_params_to_use();
19498684Sdesstatic void dos(int sec, int size, unsigned char *c, unsigned char *s,
19598684Sdes		unsigned char *h);
19692559Sdesstatic int open_disk(int u_flag);
19792559Sdesstatic ssize_t read_disk(off_t sector, void *buf);
19892559Sdesstatic ssize_t write_disk(off_t sector, void *buf);
19992559Sdesstatic int get_params();
20092559Sdesstatic int read_s0();
20160573Skrisstatic int write_s0();
20299053Sdesstatic int ok(char *str);
20399053Sdesstatic int decimal(char *str, int *num, int deflt);
20499053Sdesstatic char *get_type(int type);
20599053Sdesstatic int read_config(char *config_file);
20699053Sdesstatic void reset_boot(void);
20799053Sdesstatic void usage(void);
20899053Sdes#if 0
209124211Sdesstatic int hex(char *str, int *num, int deflt);
21099053Sdesstatic int string(char *str, char **ans);
21199053Sdes#endif
21299053Sdes
21399053Sdes
214124211Sdesint
21599053Sdesmain(int argc, char *argv[])
21699053Sdes{
21799053Sdes	int	c, i;
21899053Sdes
21999053Sdes	while ((c = getopt(argc, argv, "Bab:ef:ituv1234")) != -1)
22099053Sdes		switch (c) {
22199053Sdes		case 'B':
22299053Sdes			B_flag = 1;
22376262Sgreen			break;
22492559Sdes		case 'a':
225124211Sdes			a_flag = 1;
226124211Sdes			break;
227124211Sdes		case 'b':
228124211Sdes			b_flag = optarg;
229124211Sdes			break;
230124211Sdes		case 'e':
23176262Sgreen			e_flag = 1;
23268704Sgreen			break;
23376262Sgreen		case 'f':
23469591Sgreen			f_flag = optarg;
23569591Sgreen			break;
23669591Sgreen		case 'i':
23769591Sgreen			i_flag = 1;
23869591Sgreen			break;
23976262Sgreen		case 't':
24069591Sgreen			t_flag = 1;
24169591Sgreen			break;
24269591Sgreen		case 'u':
24369591Sgreen			u_flag = 1;
24469591Sgreen			break;
24569591Sgreen		case 'v':
24669591Sgreen			v_flag = 1;
24776262Sgreen			break;
24869591Sgreen		case '1':
24992559Sdes		case '2':
25092559Sdes		case '3':
25176262Sgreen		case '4':
25276262Sgreen			partition = c - '0';
25376262Sgreen			break;
25469591Sgreen		default:
25576262Sgreen			usage();
256113911Sdes		}
257147005Sdes	if (f_flag || i_flag)
25876262Sgreen		u_flag = 1;
259147005Sdes	if (t_flag)
260147005Sdes		v_flag = 1;
261147005Sdes	argc -= optind;
262147005Sdes	argv += optind;
26360573Skris
26498941Sdes	if (argc > 0)
265147005Sdes	{
266147005Sdes		static char realname[12];
267147005Sdes
268147005Sdes		if(strncmp(argv[0], "/dev", 4) == 0)
269147005Sdes			disk = argv[0];
270147005Sdes		else
271147005Sdes		{
272147005Sdes			snprintf(realname, 12, "/dev/r%s", argv[0]);
273147005Sdes			disk = realname;
274149753Sdes		}
275147005Sdes
276147005Sdes		if (open_disk(u_flag) < 0)
277124211Sdes			err(1, "cannot open disk %s", disk);
27898941Sdes	}
279106130Sdes	else
280106130Sdes	{
281106130Sdes		int rv = 0;
282106130Sdes
283106130Sdes		for(i = 0; disks[i]; i++)
284106130Sdes		{
285106130Sdes			disk = disks[i];
28676262Sgreen			rv = open_disk(u_flag);
28776262Sgreen			if(rv != -2) break;
28869591Sgreen		}
28992559Sdes		if(rv < 0)
29092559Sdes			err(1, "cannot open any disk");
29192559Sdes	}
29292559Sdes
29392559Sdes	printf("******* Working on device %s *******\n",disk);
29492559Sdes
29592559Sdes	if (e_flag)
29692559Sdes	{
29792559Sdes		struct dos_partition *partp;
29892559Sdes
29992559Sdes		read_s0();
30092559Sdes		reset_boot();
30192559Sdes		partp = (struct dos_partition *) (&mboot.parts[0]);
302147005Sdes		partp->dp_typ = DOSPTYP_386BSD;
303147005Sdes		partp->dp_flag = ACTIVE;
304147005Sdes		partp->dp_start = dos_sectors;
305147005Sdes		partp->dp_size = disksecs - dos_sectors;
30692559Sdes
307147005Sdes		dos(partp->dp_start, partp->dp_size,
30892559Sdes		    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
30992559Sdes		dos(partp->dp_start + partp->dp_size - 1, partp->dp_size,
31092559Sdes		    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
31192559Sdes		if (v_flag)
31292559Sdes			print_s0(-1);
31392559Sdes		write_s0();
31492559Sdes		exit(0);
31592559Sdes	}
31676262Sgreen	if (f_flag)
31769591Sgreen	{
31869591Sgreen	    if (read_s0() || i_flag)
31969591Sgreen	    {
32092559Sdes		reset_boot();
32169591Sgreen	    }
32260573Skris
32392559Sdes	    if (!read_config(f_flag))
32469591Sgreen	    {
32598684Sdes		exit(1);
32660573Skris	    }
32792559Sdes	    if (v_flag)
32898684Sdes	    {
32998684Sdes		print_s0(-1);
33069591Sgreen	    }
33198684Sdes	    if (!t_flag)
33298684Sdes	    {
33392559Sdes		write_s0();
33492559Sdes	    }
33598684Sdes	}
33698684Sdes	else
33760573Skris	{
33869591Sgreen	    if(u_flag)
33992559Sdes	    {
34092559Sdes		get_params_to_use();
34192559Sdes	    }
34269591Sgreen	    else
34360573Skris	    {
34460573Skris		print_params();
34592559Sdes	    }
34669591Sgreen
34769591Sgreen	    if (read_s0())
34898684Sdes		init_sector0(1);
34998684Sdes
35069591Sgreen	    printf("Media sector size is %d\n", secsize);
35198684Sdes	    printf("Warning: BIOS sector numbering starts with sector 1\n");
35298684Sdes	    printf("Information from DOS bootblock is:\n");
35398684Sdes	    if (partition == -1)
35498684Sdes		for (i = 1; i <= NDOSPART; i++)
35598684Sdes		    change_part(i);
35698684Sdes	    else
35798684Sdes		change_part(partition);
35869591Sgreen
35969591Sgreen	    if (u_flag || a_flag)
360		change_active(partition);
361
362	    if (B_flag)
363		change_code();
364
365	    if (u_flag || a_flag || B_flag) {
366		if (!t_flag)
367		{
368		    printf("\nWe haven't changed the partition table yet.  ");
369		    printf("This is your last chance.\n");
370		}
371		print_s0(-1);
372		if (!t_flag)
373		{
374		    if (ok("Should we write new partition table?"))
375			write_s0();
376		}
377		else
378		{
379		    printf("\n-t flag specified -- partition table not written.\n");
380		}
381	    }
382	}
383
384	exit(0);
385}
386
387static void
388usage()
389{
390	fprintf(stderr, "%s%s",
391		"usage: fdisk [-Baeitu] [-b bootcode] [-1234] [disk]\n",
392 		"       fdisk -f configfile [-itv] [disk]\n");
393        exit(1);
394}
395
396static void
397print_s0(int which)
398{
399int	i;
400
401	print_params();
402	printf("Information from DOS bootblock is:\n");
403	if (which == -1)
404		for (i = 1; i <= NDOSPART; i++)
405			printf("%d: ", i), print_part(i);
406	else
407		print_part(which);
408}
409
410static struct dos_partition mtpart = { 0 };
411
412static void
413print_part(int i)
414{
415	struct	  dos_partition *partp;
416	u_int64_t part_mb;
417
418	partp = ((struct dos_partition *) &mboot.parts) + i - 1;
419
420	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
421		printf("<UNUSED>\n");
422		return;
423	}
424	/*
425	 * Be careful not to overflow.
426	 */
427	part_mb = partp->dp_size;
428	part_mb *= secsize;
429	part_mb /= (1024 * 1024);
430	printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ));
431	printf("    start %lu, size %lu (%qd Meg), flag %x%s\n",
432		(u_long)partp->dp_start,
433		(u_long)partp->dp_size,
434		part_mb,
435		partp->dp_flag,
436		partp->dp_flag == ACTIVE ? " (active)" : "");
437	printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n"
438		,DPCYL(partp->dp_scyl, partp->dp_ssect)
439		,DPSECT(partp->dp_ssect)
440		,partp->dp_shd
441		,DPCYL(partp->dp_ecyl, partp->dp_esect)
442		,DPSECT(partp->dp_esect)
443		,partp->dp_ehd);
444}
445
446
447static void
448init_boot(void)
449{
450	const char *fname;
451	int fd;
452
453	fname = b_flag ? b_flag : "/boot/mbr";
454	if ((fd = open(fname, O_RDONLY)) == -1 ||
455	    read(fd, mboot.bootinst, DOSPARTOFF) == -1 ||
456	    close(fd))
457		err(1, "%s", fname);
458	mboot.signature = BOOT_MAGIC;
459}
460
461
462static void
463init_sector0(unsigned long start)
464{
465struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
466unsigned long size = disksecs - start;
467
468	init_boot();
469
470	partp->dp_typ = DOSPTYP_386BSD;
471	partp->dp_flag = ACTIVE;
472	partp->dp_start = start;
473	partp->dp_size = size;
474
475	dos(partp->dp_start, partp->dp_size,
476	    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
477	dos(partp->dp_start + partp->dp_size - 1, partp->dp_size,
478	    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
479}
480
481static void
482change_part(int i)
483{
484struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1;
485
486    printf("The data for partition %d is:\n", i);
487    print_part(i);
488
489    if (u_flag && ok("Do you want to change it?")) {
490	int tmp;
491
492	if (i_flag) {
493		bzero((char *)partp, sizeof (struct dos_partition));
494		if (i == 4) {
495			init_sector0(1);
496			printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n");
497			print_part(i);
498		}
499	}
500
501	do {
502		Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp);
503		Decimal("start", partp->dp_start, tmp);
504		Decimal("size", partp->dp_size, tmp);
505
506		if (ok("Explicitly specify beg/end address ?"))
507		{
508			int	tsec,tcyl,thd;
509			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
510			thd = partp->dp_shd;
511			tsec = DPSECT(partp->dp_ssect);
512			Decimal("beginning cylinder", tcyl, tmp);
513			Decimal("beginning head", thd, tmp);
514			Decimal("beginning sector", tsec, tmp);
515			partp->dp_scyl = DOSCYL(tcyl);
516			partp->dp_ssect = DOSSECT(tsec,tcyl);
517			partp->dp_shd = thd;
518
519			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
520			thd = partp->dp_ehd;
521			tsec = DPSECT(partp->dp_esect);
522			Decimal("ending cylinder", tcyl, tmp);
523			Decimal("ending head", thd, tmp);
524			Decimal("ending sector", tsec, tmp);
525			partp->dp_ecyl = DOSCYL(tcyl);
526			partp->dp_esect = DOSSECT(tsec,tcyl);
527			partp->dp_ehd = thd;
528		} else {
529			dos(partp->dp_start, partp->dp_size,
530			    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
531			dos(partp->dp_start + partp->dp_size - 1, partp->dp_size,
532			    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
533		}
534
535		print_part(i);
536	} while (!ok("Are we happy with this entry?"));
537    }
538}
539
540static void
541print_params()
542{
543	printf("parameters extracted from in-core disklabel are:\n");
544	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
545			,cyls,heads,sectors,cylsecs);
546	if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
547		printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
548	printf("parameters to be used for BIOS calculations are:\n");
549	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
550		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
551}
552
553static void
554change_active(int which)
555{
556int i;
557int active = 4, tmp;
558struct dos_partition *partp = ((struct dos_partition *) &mboot.parts);
559
560	if (a_flag && which != -1)
561		active = which;
562	if (!ok("Do you want to change the active partition?"))
563		return;
564setactive:
565	active = 4;
566	do {
567		Decimal("active partition", active, tmp);
568		if (active < 1 || 4 < active) {
569			printf("Active partition number must be in range 1-4."
570					"  Try again.\n");
571			goto setactive;
572		}
573	} while (!ok("Are you happy with this choice"));
574	for (i = 0; i < NDOSPART; i++)
575		partp[i].dp_flag = 0;
576	if (active > 0 && active <= NDOSPART)
577		partp[active-1].dp_flag = ACTIVE;
578}
579
580static void
581change_code()
582{
583	if (ok("Do you want to change the boot code?"))
584		init_boot();
585
586}
587
588void
589get_params_to_use()
590{
591	int	tmp;
592	print_params();
593	if (ok("Do you want to change our idea of what BIOS thinks ?"))
594	{
595		do
596		{
597			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
598			Decimal("BIOS's idea of #heads", dos_heads, tmp);
599			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
600			dos_cylsecs = dos_heads * dos_sectors;
601			print_params();
602		}
603		while(!ok("Are you happy with this choice"));
604	}
605}
606
607
608/***********************************************\
609* Change real numbers into strange dos numbers	*
610\***********************************************/
611static void
612dos(sec, size, c, s, h)
613int sec, size;
614unsigned char *c, *s, *h;
615{
616int cy;
617int hd;
618
619	if (sec == 0 && size == 0) {
620		*s = *c = *h = 0;
621		return;
622	}
623
624	cy = sec / ( dos_cylsecs );
625	sec = sec - cy * ( dos_cylsecs );
626
627	hd = sec / dos_sectors;
628	sec = (sec - hd * dos_sectors) + 1;
629
630	*h = hd;
631	*c = cy & 0xff;
632	*s = (sec & 0x3f) | ( (cy & 0x300) >> 2);
633}
634
635int fd;
636
637	/* Getting device status */
638
639static int
640open_disk(int u_flag)
641{
642struct stat 	st;
643
644	if (stat(disk, &st) == -1) {
645		warnx("can't get file status of %s", disk);
646		return -1;
647	}
648	if ( !(st.st_mode & S_IFCHR) )
649		warnx("device %s is not character special", disk);
650	if ((fd = open(disk,
651	    a_flag || e_flag || B_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) {
652		if(errno == ENXIO)
653			return -2;
654		warnx("can't open device %s", disk);
655		return -1;
656	}
657	if (get_params(0) == -1) {
658		warnx("can't get disk parameters on %s", disk);
659		return -1;
660	}
661	return fd;
662}
663
664static ssize_t
665read_disk(off_t sector, void *buf)
666{
667	lseek(fd,(sector * 512), 0);
668	if( secsize == 0 )
669		for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 )
670			{
671			/* try the read */
672			int size = read(fd, buf, secsize);
673			if( size == secsize )
674				/* it worked so return */
675				return secsize;
676			}
677	else
678		return read( fd, buf, secsize );
679
680	/* we failed to read at any of the sizes */
681	return -1;
682}
683
684static ssize_t
685write_disk(off_t sector, void *buf)
686{
687	lseek(fd,(sector * 512), 0);
688	/* write out in the size that the read_disk found worked */
689	return write(fd, buf, secsize);
690}
691
692static int
693get_params()
694{
695
696    if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
697	warnx("can't get disk parameters on %s; supplying dummy ones", disk);
698	dos_cyls = cyls = 1;
699	dos_heads = heads = 1;
700	dos_sectors = sectors = 1;
701	dos_cylsecs = cylsecs = heads * sectors;
702	disksecs = cyls * heads * sectors;
703	return disksecs;
704    }
705
706    dos_cyls = cyls = disklabel.d_ncylinders;
707    dos_heads = heads = disklabel.d_ntracks;
708    dos_sectors = sectors = disklabel.d_nsectors;
709    dos_cylsecs = cylsecs = heads * sectors;
710    disksecs = cyls * heads * sectors;
711
712    return (disksecs);
713}
714
715
716static int
717read_s0()
718{
719	if (read_disk(0, (char *) mboot.bootinst) == -1) {
720		warnx("can't read fdisk partition table");
721		return -1;
722	}
723	if (mboot.signature != BOOT_MAGIC) {
724		warnx("invalid fdisk partition table found");
725		/* So should we initialize things */
726		return -1;
727	}
728	return 0;
729}
730
731static int
732write_s0()
733{
734	int	flag;
735	if (iotest) {
736		print_s0(-1);
737		return 0;
738	}
739	/*
740	 * write enable label sector before write (if necessary),
741	 * disable after writing.
742	 * needed if the disklabel protected area also protects
743	 * sector 0. (e.g. empty disk)
744	 */
745#ifdef NOT_NOW
746	flag = 1;
747	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
748		warn("ioctl DIOCWLABEL");
749#endif
750	if (write_disk(0, (char *) mboot.bootinst) == -1) {
751		warn("can't write fdisk partition table");
752		return -1;
753#ifdef NOT_NOW
754	flag = 0;
755	(void) ioctl(fd, DIOCWLABEL, &flag);
756#endif
757	}
758	return(0);
759}
760
761
762static int
763ok(str)
764char *str;
765{
766	printf("%s [n] ", str);
767	fgets(lbuf, LBUF, stdin);
768	lbuf[strlen(lbuf)-1] = 0;
769
770	if (*lbuf &&
771		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
772		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
773		return 1;
774	else
775		return 0;
776}
777
778static int
779decimal(char *str, int *num, int deflt)
780{
781int acc = 0, c;
782char *cp;
783
784	while (1) {
785		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
786		fgets(lbuf, LBUF, stdin);
787		lbuf[strlen(lbuf)-1] = 0;
788
789		if (!*lbuf)
790			return 0;
791
792		cp = lbuf;
793		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
794		if (!c)
795			return 0;
796		while ((c = *cp++)) {
797			if (c <= '9' && c >= '0')
798				acc = acc * 10 + c - '0';
799			else
800				break;
801		}
802		if (c == ' ' || c == '\t')
803			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
804		if (!c) {
805			*num = acc;
806			return 1;
807		} else
808			printf("%s is an invalid decimal number.  Try again.\n",
809				lbuf);
810	}
811
812}
813
814#if 0
815static int
816hex(char *str, int *num, int deflt)
817{
818int acc = 0, c;
819char *cp;
820
821	while (1) {
822		printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
823		fgets(lbuf, LBUF, stdin);
824		lbuf[strlen(lbuf)-1] = 0;
825
826		if (!*lbuf)
827			return 0;
828
829		cp = lbuf;
830		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
831		if (!c)
832			return 0;
833		while ((c = *cp++)) {
834			if (c <= '9' && c >= '0')
835				acc = (acc << 4) + c - '0';
836			else if (c <= 'f' && c >= 'a')
837				acc = (acc << 4) + c - 'a' + 10;
838			else if (c <= 'F' && c >= 'A')
839				acc = (acc << 4) + c - 'A' + 10;
840			else
841				break;
842		}
843		if (c == ' ' || c == '\t')
844			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
845		if (!c) {
846			*num = acc;
847			return 1;
848		} else
849			printf("%s is an invalid hex number.  Try again.\n",
850				lbuf);
851	}
852
853}
854
855static int
856string(char *str, char **ans)
857{
858int c;
859char *cp = lbuf;
860
861	while (1) {
862		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
863		fgets(lbuf, LBUF, stdin);
864		lbuf[strlen(lbuf)-1] = 0;
865
866		if (!*lbuf)
867			return 0;
868
869		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
870		if (c == '"') {
871			c = *++cp;
872			*ans = cp;
873			while ((c = *cp) && c != '"') cp++;
874		} else {
875			*ans = cp;
876			while ((c = *cp) && c != ' ' && c != '\t') cp++;
877		}
878
879		if (c)
880			*cp = 0;
881		return 1;
882	}
883}
884#endif
885
886static char *
887get_type(int type)
888{
889	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
890	int	counter = 0;
891	struct	part_type *ptr = part_types;
892
893
894	while(counter < numentries)
895	{
896		if(ptr->type == type)
897		{
898			return(ptr->name);
899		}
900		ptr++;
901		counter++;
902	}
903	return("unknown");
904}
905
906
907static void
908parse_config_line(line, command)
909    char	*line;
910    CMD		*command;
911{
912    char	*cp, *end;
913
914    cp = line;
915    while (1)	/* dirty trick used to insure one exit point for this
916		   function */
917    {
918	memset(command, 0, sizeof(*command));
919
920	while (isspace(*cp)) ++cp;
921	if (*cp == '\0' || *cp == '#')
922	{
923	    break;
924	}
925	command->cmd = *cp++;
926
927	/*
928	 * Parse args
929	 */
930	while (1)
931	{
932	    while (isspace(*cp)) ++cp;
933	    if (*cp == '#')
934	    {
935		break;		/* found comment */
936	    }
937	    if (isalpha(*cp))
938	    {
939		command->args[command->n_args].argtype = *cp++;
940	    }
941	    if (!isdigit(*cp))
942	    {
943		break;		/* assume end of line */
944	    }
945	    end = NULL;
946	    command->args[command->n_args].arg_val = strtol(cp, &end, 0);
947	    if (cp == end)
948	    {
949		break;		/* couldn't parse number */
950	    }
951	    cp = end;
952	    command->n_args++;
953	}
954	break;
955    }
956}
957
958
959static int
960process_geometry(command)
961    CMD		*command;
962{
963    int		status = 1, i;
964
965    while (1)
966    {
967	geom_processed = 1;
968	if (part_processed)
969	{
970	    warnx(
971	"ERROR line %d: the geometry specification line must occur before\n\
972    all partition specifications",
973		    current_line_number);
974	    status = 0;
975	    break;
976	}
977	if (command->n_args != 3)
978	{
979	    warnx("ERROR line %d: incorrect number of geometry args",
980		    current_line_number);
981	    status = 0;
982	    break;
983	}
984	dos_cyls = -1;
985	dos_heads = -1;
986	dos_sectors = -1;
987	for (i = 0; i < 3; ++i)
988	{
989	    switch (command->args[i].argtype)
990	    {
991	    case 'c':
992		dos_cyls = command->args[i].arg_val;
993		break;
994	    case 'h':
995		dos_heads = command->args[i].arg_val;
996		break;
997	    case 's':
998		dos_sectors = command->args[i].arg_val;
999		break;
1000	    default:
1001		warnx(
1002		"ERROR line %d: unknown geometry arg type: '%c' (0x%02x)",
1003			current_line_number, command->args[i].argtype,
1004			command->args[i].argtype);
1005		status = 0;
1006		break;
1007	    }
1008	}
1009	if (status == 0)
1010	{
1011	    break;
1012	}
1013
1014	dos_cylsecs = dos_heads * dos_sectors;
1015
1016	/*
1017	 * Do sanity checks on parameter values
1018	 */
1019	if (dos_cyls < 0)
1020	{
1021	    warnx("ERROR line %d: number of cylinders not specified",
1022		    current_line_number);
1023	    status = 0;
1024	}
1025	if (dos_cyls == 0 || dos_cyls > 1024)
1026	{
1027	    warnx(
1028	"WARNING line %d: number of cylinders (%d) may be out-of-range\n\
1029    (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\
1030    is dedicated to FreeBSD)",
1031		    current_line_number, dos_cyls);
1032	}
1033
1034	if (dos_heads < 0)
1035	{
1036	    warnx("ERROR line %d: number of heads not specified",
1037		    current_line_number);
1038	    status = 0;
1039	}
1040	else if (dos_heads < 1 || dos_heads > 256)
1041	{
1042	    warnx("ERROR line %d: number of heads must be within (1-256)",
1043		    current_line_number);
1044	    status = 0;
1045	}
1046
1047	if (dos_sectors < 0)
1048	{
1049	    warnx("ERROR line %d: number of sectors not specified",
1050		    current_line_number);
1051	    status = 0;
1052	}
1053	else if (dos_sectors < 1 || dos_sectors > 63)
1054	{
1055	    warnx("ERROR line %d: number of sectors must be within (1-63)",
1056		    current_line_number);
1057	    status = 0;
1058	}
1059
1060	break;
1061    }
1062    return (status);
1063}
1064
1065
1066static int
1067process_partition(command)
1068    CMD		*command;
1069{
1070    int				status = 0, partition;
1071    unsigned long		chunks, adj_size, max_end;
1072    struct dos_partition	*partp;
1073
1074    while (1)
1075    {
1076	part_processed = 1;
1077	if (command->n_args != 4)
1078	{
1079	    warnx("ERROR line %d: incorrect number of partition args",
1080		    current_line_number);
1081	    break;
1082	}
1083	partition = command->args[0].arg_val;
1084	if (partition < 1 || partition > 4)
1085	{
1086	    warnx("ERROR line %d: invalid partition number %d",
1087		    current_line_number, partition);
1088	    break;
1089	}
1090	partp = ((struct dos_partition *) &mboot.parts) + partition - 1;
1091	bzero((char *)partp, sizeof (struct dos_partition));
1092	partp->dp_typ = command->args[1].arg_val;
1093	partp->dp_start = command->args[2].arg_val;
1094	partp->dp_size = command->args[3].arg_val;
1095	max_end = partp->dp_start + partp->dp_size;
1096
1097	if (partp->dp_typ == 0)
1098	{
1099	    /*
1100	     * Get out, the partition is marked as unused.
1101	     */
1102	    /*
1103	     * Insure that it's unused.
1104	     */
1105	    bzero((char *)partp, sizeof (struct dos_partition));
1106	    status = 1;
1107	    break;
1108	}
1109
1110	/*
1111	 * Adjust start upwards, if necessary, to fall on an head boundary.
1112	 */
1113	if (partp->dp_start % dos_sectors != 0)
1114	{
1115	    adj_size =
1116		(partp->dp_start / dos_sectors + 1) * dos_sectors;
1117	    if (adj_size > max_end)
1118	    {
1119		/*
1120		 * Can't go past end of partition
1121		 */
1122		warnx(
1123	"ERROR line %d: unable to adjust start of partition %d to fall on\n\
1124    a cylinder boundary",
1125			current_line_number, partition);
1126		break;
1127	    }
1128	    warnx(
1129	"WARNING: adjusting start offset of partition '%d' from %lu\n\
1130    to %lu, to round to an head boundary",
1131		    partition, (u_long)partp->dp_start, adj_size);
1132	    partp->dp_start = adj_size;
1133	}
1134
1135	/*
1136	 * Adjust size downwards, if necessary, to fall on a cylinder
1137	 * boundary.
1138	 */
1139	chunks =
1140	    ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs;
1141	adj_size = chunks - partp->dp_start;
1142	if (adj_size != partp->dp_size)
1143	{
1144	    warnx(
1145	"WARNING: adjusting size of partition '%d' from %lu to %lu,\n\
1146    to round to a cylinder boundary",
1147		    partition, (u_long)partp->dp_size, adj_size);
1148	    if (chunks > 0)
1149	    {
1150		partp->dp_size = adj_size;
1151	    }
1152	    else
1153	    {
1154		partp->dp_size = 0;
1155	    }
1156	}
1157	if (partp->dp_size < 1)
1158	{
1159	    warnx("ERROR line %d: size for partition '%d' is zero",
1160		    current_line_number, partition);
1161	    break;
1162	}
1163
1164	dos(partp->dp_start, partp->dp_size,
1165	    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
1166	dos(partp->dp_start+partp->dp_size - 1, partp->dp_size,
1167	    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
1168	status = 1;
1169	break;
1170    }
1171    return (status);
1172}
1173
1174
1175static int
1176process_active(command)
1177    CMD		*command;
1178{
1179    int				status = 0, partition, i;
1180    struct dos_partition	*partp;
1181
1182    while (1)
1183    {
1184	active_processed = 1;
1185	if (command->n_args != 1)
1186	{
1187	    warnx("ERROR line %d: incorrect number of active args",
1188		    current_line_number);
1189	    status = 0;
1190	    break;
1191	}
1192	partition = command->args[0].arg_val;
1193	if (partition < 1 || partition > 4)
1194	{
1195	    warnx("ERROR line %d: invalid partition number %d",
1196		    current_line_number, partition);
1197	    break;
1198	}
1199	/*
1200	 * Reset active partition
1201	 */
1202	partp = ((struct dos_partition *) &mboot.parts);
1203	for (i = 0; i < NDOSPART; i++)
1204	    partp[i].dp_flag = 0;
1205	partp[partition-1].dp_flag = ACTIVE;
1206
1207	status = 1;
1208	break;
1209    }
1210    return (status);
1211}
1212
1213
1214static int
1215process_line(line)
1216    char	*line;
1217{
1218    CMD		command;
1219    int		status = 1;
1220
1221    while (1)
1222    {
1223	parse_config_line(line, &command);
1224	switch (command.cmd)
1225	{
1226	case 0:
1227	    /*
1228	     * Comment or blank line
1229	     */
1230	    break;
1231	case 'g':
1232	    /*
1233	     * Set geometry
1234	     */
1235	    status = process_geometry(&command);
1236	    break;
1237	case 'p':
1238	    status = process_partition(&command);
1239	    break;
1240	case 'a':
1241	    status = process_active(&command);
1242	    break;
1243	default:
1244	    status = 0;
1245	    break;
1246	}
1247	break;
1248    }
1249    return (status);
1250}
1251
1252
1253static int
1254read_config(config_file)
1255    char *config_file;
1256{
1257    FILE	*fp = NULL;
1258    int		status = 1;
1259    char	buf[1010];
1260
1261    while (1)	/* dirty trick used to insure one exit point for this
1262		   function */
1263    {
1264	if (strcmp(config_file, "-") != 0)
1265	{
1266	    /*
1267	     * We're not reading from stdin
1268	     */
1269	    if ((fp = fopen(config_file, "r")) == NULL)
1270	    {
1271		status = 0;
1272		break;
1273	    }
1274	}
1275	else
1276	{
1277	    fp = stdin;
1278	}
1279	current_line_number = 0;
1280	while (!feof(fp))
1281	{
1282	    if (fgets(buf, sizeof(buf), fp) == NULL)
1283	    {
1284		break;
1285	    }
1286	    ++current_line_number;
1287	    status = process_line(buf);
1288	    if (status == 0)
1289	    {
1290		break;
1291	    }
1292	}
1293	break;
1294    }
1295    if (fp)
1296    {
1297	/*
1298	 * It doesn't matter if we're reading from stdin, as we've reached EOF
1299	 */
1300	fclose(fp);
1301    }
1302    return (status);
1303}
1304
1305
1306static void
1307reset_boot(void)
1308{
1309    int				i;
1310    struct dos_partition	*partp;
1311
1312    init_boot();
1313    for (i = 0; i < 4; ++i)
1314    {
1315	partp = ((struct dos_partition *) &mboot.parts) + i;
1316	bzero((char *)partp, sizeof (struct dos_partition));
1317    }
1318}
1319