Home | History | Annotate | Line # | Download | only in fdisk
fdisk.c revision 1.11
      1 /*	$NetBSD: fdisk.c,v 1.11 1995/10/04 23:11:19 ghudson Exp $	*/
      2 
      3 /*
      4  * Mach Operating System
      5  * Copyright (c) 1992 Carnegie Mellon University
      6  * All Rights Reserved.
      7  *
      8  * Permission to use, copy, modify and distribute this software and its
      9  * documentation is hereby granted, provided that both the copyright
     10  * notice and this permission notice appear in all copies of the
     11  * software, derivative works or modified versions, and any portions
     12  * thereof, and that both notices appear in supporting documentation.
     13  *
     14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  *
     18  * Carnegie Mellon requests users of this software to return to
     19  *
     20  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  *  School of Computer Science
     22  *  Carnegie Mellon University
     23  *  Pittsburgh PA 15213-3890
     24  *
     25  * any improvements or extensions that they make and grant Carnegie Mellon
     26  * the rights to redistribute these changes.
     27  */
     28 
     29 #ifndef lint
     30 static char rcsid[] = "$NetBSD: fdisk.c,v 1.11 1995/10/04 23:11:19 ghudson Exp $";
     31 #endif /* not lint */
     32 
     33 #include <sys/types.h>
     34 #include <sys/disklabel.h>
     35 #include <sys/ioctl.h>
     36 #include <sys/stat.h>
     37 
     38 #include <ctype.h>
     39 #include <err.h>
     40 #include <fcntl.h>
     41 #include <stdio.h>
     42 #include <stdlib.h>
     43 #include <string.h>
     44 #include <unistd.h>
     45 
     46 #define LBUF 100
     47 static char lbuf[LBUF];
     48 
     49 /*
     50  * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
     51  *	Copyright (c) 1989	Robert. V. Baron
     52  *	Created.
     53  */
     54 
     55 char *disk = "/dev/rwd0d";
     56 
     57 struct disklabel disklabel;		/* disk parameters */
     58 
     59 int cylinders, sectors, heads, cylindersectors, disksectors;
     60 
     61 struct mboot {
     62 	unsigned char padding[2]; /* force the longs to be long alligned */
     63 	unsigned char bootinst[DOSPARTOFF];
     64 	struct	dos_partition parts[4];
     65 	unsigned short int	signature;
     66 };
     67 struct mboot mboot;
     68 
     69 #define ACTIVE 0x80
     70 #define BOOT_MAGIC 0xAA55
     71 
     72 int dos_cylinders;
     73 int dos_heads;
     74 int dos_sectors;
     75 int dos_cylindersectors;
     76 
     77 #define DOSSECT(s,c)	(((s) & 0x3f) | (((c) >> 2) & 0xc0))
     78 #define DOSCYL(c)	((c) & 0xff)
     79 int partition = -1;
     80 
     81 int a_flag;		/* set active partition */
     82 int i_flag;		/* replace partition data */
     83 int u_flag;		/* update partition data */
     84 
     85 unsigned char bootcode[] = {
     86 0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
     87 0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
     88 0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
     89 0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
     90 0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
     91 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
     92 0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
     93 0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
     94 0xeb, 0xf4, 0xfb, 0xeb, 0xfe,
     95 'M', 'i', 's', 's', 'i', 'n', 'g', ' ',
     96 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
     97 'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ',
     98 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
     99 'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ',
    100 	'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0,
    101 'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ',
    102 	'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0,
    103 
    104   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    105   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    106   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    107   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    108   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    109   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    110   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    111   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    112   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    113   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    114   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    115   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    116   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
    117 };
    118 
    119 struct part_type {
    121 	int type;
    122 	char *name;
    123 } part_types[] = {
    124 	{0x00, "unused"},
    125 	{0x01, "Primary DOS with 12 bit FAT"},
    126 	{0x02, "XENIX / filesystem"},
    127 	{0x03, "XENIX /usr filesystem"},
    128 	{0x04, "Primary DOS with 16 bit FAT"},
    129 	{0x05, "Extended DOS"},
    130 	{0x06, "Primary 'big' DOS (> 32MB)"},
    131 	{0x07, "OS/2 HPFS, QNX or Advanced UNIX"},
    132 	{0x08, "AIX filesystem"},
    133 	{0x09, "AIX boot partition or Coherent"},
    134 	{0x0A, "OS/2 Boot Manager or OPUS"},
    135 	{0x10, "OPUS"},
    136 	{0x40, "VENIX 286"},
    137 	{0x50, "DM"},
    138 	{0x51, "DM"},
    139 	{0x52, "CP/M or Microport SysV/AT"},
    140 	{0x56, "GB"},
    141 	{0x61, "Speed"},
    142 	{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"},
    143 	{0x64, "Novell Netware 2.xx"},
    144 	{0x65, "Novell Netware 3.xx"},
    145 	{0x75, "PCIX"},
    146 	{0x80, "Minix 1.1 ... 1.4a"},
    147 	{0x81, "Minix 1.4b ... 1.5.10"},
    148 	{0x82, "Linux swap"},
    149 	{0x83, "Linux filesystem"},
    150 	{0x93, "Amoeba filesystem"},
    151 	{0x94, "Amoeba bad block table"},
    152 	{0xA5, "NetBSD or 386BSD"},
    153 	{0xB7, "BSDI BSD/386 filesystem"},
    154 	{0xB8, "BSDI BSD/386 swap"},
    155 	{0xDB, "Concurrent CPM or C.DOS or CTOS"},
    156 	{0xE1, "Speed"},
    157 	{0xE3, "Speed"},
    158 	{0xE4, "Speed"},
    159 	{0xF1, "Speed"},
    160 	{0xF2, "DOS 3.3+ Secondary"},
    161 	{0xF4, "Speed"},
    162 	{0xFF, "BBT (Bad Blocks Table)"},
    163 };
    164 
    165 void	usage __P((void));
    166 void	print_s0 __P((int));
    167 void	print_part __P((int));
    168 void	init_sector0 __P((int));
    169 void	intuit_translated_geometry __P((void));
    170 int	try_heads __P((quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, quad_t,
    171 		       quad_t));
    172 int	try_sectors __P((quad_t, quad_t, quad_t, quad_t, quad_t));
    173 void	change_part __P((int));
    174 void	print_params __P((void));
    175 void	change_active __P((int));
    176 void	get_params_to_use __P((void));
    177 void	dos __P((int, unsigned char *, unsigned char *, unsigned char *));
    178 int	open_disk __P((int));
    179 int	read_disk __P((int, void *));
    180 int	write_disk __P((int, void *));
    181 int	get_params __P((void));
    182 int	read_s0 __P((void));
    183 int	write_s0 __P((void));
    184 int	yesno __P((char *));
    185 void	decimal __P((char *, int *));
    186 int	type_match __P((const void *, const void *));
    187 char	*get_type __P((int));
    188 
    189 int
    190 main(argc, argv)
    191 	int argc;
    192 	char *argv[];
    193 {
    194 	int ch;
    195 	int part;
    196 
    197 	a_flag = i_flag = u_flag = 0;
    198 	while ((ch = getopt(argc, argv, "0123aiu")) != -1)
    199 		switch (ch) {
    200 		case '0':
    201 			partition = 0;
    202 			break;
    203 		case '1':
    204 			partition = 1;
    205 			break;
    206 		case '2':
    207 			partition = 2;
    208 			break;
    209 		case '3':
    210 			partition = 3;
    211 			break;
    212 		case 'a':
    213 			a_flag = 1;
    214 			break;
    215 		case 'i':
    216 			i_flag = 1;
    217 		case 'u':
    218 			u_flag = 1;
    219 			break;
    220 		default:
    221 			usage();
    222 		}
    223 	argc -= optind;
    224 	argv += optind;
    225 
    226 	if (argc > 0)
    227 		disk = argv[0];
    228 
    229 	if (open_disk(a_flag || i_flag || u_flag) < 0)
    230 		exit(1);
    231 
    232 	if (read_s0())
    233 		init_sector0(1);
    234 
    235 	intuit_translated_geometry();
    236 
    237 	printf("******* Working on device %s *******\n", disk);
    238 	if (u_flag)
    239 		get_params_to_use();
    240 	else
    241 		print_params();
    242 
    243 	printf("Warning: BIOS sector numbering starts with sector 1\n");
    244 	printf("Information from DOS bootblock is:\n");
    245 	if (partition == -1) {
    246 		for (part = 0; part < NDOSPART; part++)
    247 			change_part(part);
    248 	} else
    249 		change_part(partition);
    250 
    251 	if (u_flag || a_flag)
    252 		change_active(partition);
    253 
    254 	if (u_flag || a_flag) {
    255 		printf("\nWe haven't changed the partition table yet.  ");
    256 		printf("This is your last chance.\n");
    257 		print_s0(-1);
    258 		if (yesno("Should we write new partition table?"))
    259 			write_s0();
    260 	}
    261 
    262 	exit(0);
    263 }
    264 
    265 void
    266 usage()
    267 {
    268 
    269 	(void)fprintf(stderr, "usage: fdisk [-aiu] [-0|-1|-2|-3] [device]\n");
    270 	exit(1);
    271 }
    272 
    273 void
    274 print_s0(which)
    275 	int which;
    276 {
    277 	int part;
    278 
    279 	print_params();
    280 	printf("Information from DOS bootblock is:\n");
    281 	if (which == -1) {
    282 		for (part = 0; part < NDOSPART; part++)
    283 			printf("%d: ", part), print_part(part);
    284 	} else
    285 		print_part(which);
    286 }
    287 
    288 static struct dos_partition mtpart = { 0 };
    289 
    290 void
    291 print_part(part)
    292 	int part;
    293 {
    294 	struct dos_partition *partp;
    295 
    296 	partp = &mboot.parts[part];
    297 	if (!memcmp(partp, &mtpart, sizeof(struct dos_partition))) {
    298 		printf("<UNUSED>\n");
    299 		return;
    300 	}
    301 	printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ));
    302 	printf("    start %d, size %d (%d MB), flag %x\n",
    303 	    partp->dp_start, partp->dp_size,
    304 	    partp->dp_size * 512 / (1024 * 1024), partp->dp_flag);
    305 	printf("\tbeg: cylinder %4d, head %3d, sector %2d\n",
    306 	    DPCYL(partp->dp_scyl, partp->dp_ssect),
    307 	    partp->dp_shd, DPSECT(partp->dp_ssect));
    308 	printf("\tend: cylinder %4d, head %3d, sector %2d\n",
    309 	    DPCYL(partp->dp_ecyl, partp->dp_esect),
    310 	    partp->dp_ehd, DPSECT(partp->dp_esect));
    311 }
    312 
    313 void
    314 init_sector0(start)
    315 	int start;
    316 {
    317 	struct dos_partition *partp;
    318 
    319 	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
    320 	mboot.signature = BOOT_MAGIC;
    321 
    322 	partp = &mboot.parts[3];
    323 	partp->dp_typ = DOSPTYP_386BSD;
    324 	partp->dp_flag = ACTIVE;
    325 	partp->dp_start = start;
    326 	partp->dp_size = disksectors - start;
    327 
    328 	dos(partp->dp_start,
    329 	    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    330 	dos(partp->dp_start + partp->dp_size - 1,
    331 	    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    332 }
    333 
    334 /* Prerequisite: the disklabel parameters and master boot record must
    335  *		 have been read (i.e. dos_* and mboot are meaningful).
    336  * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and
    337  *		  dos_cylindersectors to be consistent with what the
    338  *		  partition table is using, if we can find a geometry
    339  *		  which is consistent with all partition table entries.
    340  *		  We may get the number of cylinders slightly wrong (in
    341  *		  the conservative direction).  The idea is to be able
    342  *		  to create a NetBSD partition on a disk we don't know
    343  *		  the translated geometry of.
    344  * This whole routine should be replaced with a kernel interface to get
    345  * the BIOS geometry (which in turn requires modifications to the i386
    346  * boot loader to pass in the BIOS geometry for each disk). */
    347 void
    348 intuit_translated_geometry()
    349 {
    350 	int cylinders = -1, heads = -1, sectors = -1, i, j;
    351 	int c1, h1, s1, c2, h2, s2;
    352 	long a1, a2;
    353 	quad_t num, denom;
    354 
    355 	/* Try to deduce the number of heads from two different mappings. */
    356 	for (i = 0; i < NDOSPART * 2; i++) {
    357 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    358 			continue;
    359 		for (j = 0; j < 8; j++) {
    360 			if (get_mapping(j, &c2, &h2, &s2, &a2) < 0)
    361 				continue;
    362 			num = (quad_t)h1*(a2-s2) - h2*(a1-s1);
    363 			denom = (quad_t)c2*(a1-s1) - c1*(a2-s2);
    364 			if (denom != 0 && num % denom == 0) {
    365 				heads = num / denom;
    366 				break;
    367 			}
    368 		}
    369 		if (heads != -1)
    370 			break;
    371 	}
    372 
    373 	if (heads == -1)
    374 		return;
    375 
    376 	/* Now figure out the number of sectors from a single mapping. */
    377 	for (i = 0; i < NDOSPART * 2; i++) {
    378 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    379 			continue;
    380 		num = a1 - s1;
    381 		denom = c1 * heads + h1;
    382 		if (denom != 0 && num % denom == 0) {
    383 			sectors = num / denom;
    384 			break;
    385 		}
    386 	}
    387 
    388 	if (sectors == -1)
    389 		return;
    390 
    391 	/* Estimate the number of cylinders. */
    392 	cylinders = dos_cylinders * dos_cylindersectors / heads / sectors;
    393 
    394 	/* Now verify consistency with each of the partition table entries.
    395 	 * Be willing to shove cylinders up a little bit to make things work,
    396 	 * but translation mismatches are fatal. */
    397 	for (i = 0; i < NDOSPART * 2; i++) {
    398 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    399 			continue;
    400 		if (sectors * (c1 * heads + h1) + s1 != a1)
    401 			return;
    402 		if (c1 >= cylinders)
    403 			cylinders = c1 + 1;
    404 	}
    405 
    406 	/* Everything checks out.  Reset the geometry to use for further
    407 	 * calculations. */
    408 	dos_cylinders = cylinders;
    409 	dos_heads = heads;
    410 	dos_sectors = sectors;
    411 	dos_cylindersectors = heads * sectors;
    412 }
    413 
    414 /* For the purposes of intuit_translated_geometry(), treat the partition
    415  * table as a list of eight mapping between (cylinder, head, sector)
    416  * triplets and absolute sectors.  Get the relevant geometry triplet and
    417  * absolute sectors for a given entry, or return -1 if it isn't present.
    418  * Note: for simplicity, the returned sector is 0-based. */
    419 int
    420 get_mapping(i, cylinder, head, sector, absolute)
    421 	int i, *cylinder, *head, *sector;
    422 	long *absolute;
    423 {
    424 	struct dos_partition *part = &mboot.parts[i / 2];
    425 
    426 	if (part->dp_typ == 0)
    427 		return -1;
    428 	if (i % 2 == 0) {
    429 		*cylinder = DPCYL(part->dp_scyl, part->dp_ssect);
    430 		*head = part->dp_shd;
    431 		*sector = DPSECT(part->dp_ssect) - 1;
    432 		*absolute = part->dp_start;
    433 	} else {
    434 		*cylinder = DPCYL(part->dp_ecyl, part->dp_esect);
    435 		*head = part->dp_ehd;
    436 		*sector = DPSECT(part->dp_esect) - 1;
    437 		*absolute = part->dp_start + part->dp_size - 1;
    438 	}
    439 	return 0;
    440 }
    441 
    442 void
    443 change_part(part)
    444 	int part;
    445 {
    446 	struct dos_partition *partp;
    447 
    448 	partp = &mboot.parts[part];
    449 
    450 	printf("The data for partition %d is:\n", part);
    451 	print_part(part);
    452 
    453 	if (!u_flag || !yesno("Do you want to change it?"))
    454 		return;
    455 
    456 	if (i_flag) {
    457 		memset(partp, 0, sizeof(*partp));
    458 		if (part == 3) {
    459 			init_sector0(1);
    460 			printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
    461 			print_part(part);
    462 		}
    463 	}
    464 
    465 	do {
    466 		{
    467 			int sysid, start, size;
    468 
    469 			sysid = partp->dp_typ,
    470 			start = partp->dp_start,
    471 			size = partp->dp_size;
    472 			decimal("sysid", &sysid);
    473 			decimal("start", &start);
    474 			decimal("size", &size);
    475 			partp->dp_typ = sysid;
    476 			partp->dp_start = start;
    477 			partp->dp_size = size;
    478 		}
    479 
    480 		if (yesno("Explicitly specify beg/end address?")) {
    481 			int tsector, tcylinder, thead;
    482 
    483 			tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
    484 			thead = partp->dp_shd;
    485 			tsector = DPSECT(partp->dp_ssect);
    486 			decimal("beginning cylinder", &tcylinder);
    487 			decimal("beginning head", &thead);
    488 			decimal("beginning sector", &tsector);
    489 			partp->dp_scyl = DOSCYL(tcylinder);
    490 			partp->dp_shd = thead;
    491 			partp->dp_ssect = DOSSECT(tsector, tcylinder);
    492 
    493 			tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
    494 			thead = partp->dp_ehd;
    495 			tsector = DPSECT(partp->dp_esect);
    496 			decimal("ending cylinder", &tcylinder);
    497 			decimal("ending head", &thead);
    498 			decimal("ending sector", &tsector);
    499 			partp->dp_ecyl = DOSCYL(tcylinder);
    500 			partp->dp_ehd = thead;
    501 			partp->dp_esect = DOSSECT(tsector, tcylinder);
    502 		} else {
    503 			dos(partp->dp_start,
    504 			    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    505 			dos(partp->dp_start + partp->dp_size - 1,
    506 			    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    507 		}
    508 
    509 		print_part(part);
    510 	} while (!yesno("Is this entry okay?"));
    511 }
    512 
    513 void
    514 print_params()
    515 {
    516 
    517 	printf("parameters extracted from in-core disklabel are:\n");
    518 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    519 	    cylinders, heads, sectors, cylindersectors);
    520 	if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255)
    521 		printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
    522 	printf("parameters to be used for BIOS calculations are:\n");
    523 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    524 	    dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
    525 }
    526 
    527 void
    528 change_active(which)
    529 	int which;
    530 {
    531 	struct dos_partition *partp;
    532 	int part;
    533 	int active = 3;
    534 
    535 	partp = &mboot.parts[0];
    536 
    537 	if (a_flag && which != -1)
    538 		active = which;
    539 	else {
    540 		for (part = 0; part < NDOSPART; part++)
    541 			if (partp[part].dp_flag & ACTIVE)
    542 				active = part;
    543 	}
    544 	if (yesno("Do you want to change the active partition?")) {
    545 		do {
    546 			decimal("active partition", &active);
    547 		} while (!yesno("Are you happy with this choice?"));
    548 	}
    549 	for (part = 0; part < NDOSPART; part++)
    550 		partp[part].dp_flag &= ~ACTIVE;
    551 	partp[active].dp_flag |= ACTIVE;
    552 }
    553 
    554 void
    555 get_params_to_use()
    556 {
    557 
    558 	print_params();
    559 	if (yesno("Do you want to change our idea of what BIOS thinks?")) {
    560 		do {
    561 			decimal("BIOS's idea of #cylinders", &dos_cylinders);
    562 			decimal("BIOS's idea of #heads", &dos_heads);
    563 			decimal("BIOS's idea of #sectors", &dos_sectors);
    564 			dos_cylindersectors = dos_heads * dos_sectors;
    565 			print_params();
    566 		} while (!yesno("Are you happy with this choice?"));
    567 	}
    568 }
    569 
    570 /***********************************************\
    571 * Change real numbers into strange dos numbers	*
    572 \***********************************************/
    573 void
    574 dos(sector, cylinderp, headp, sectorp)
    575 	int sector;
    576 	unsigned char *cylinderp, *headp, *sectorp;
    577 {
    578 	int cylinder, head;
    579 
    580 	cylinder = sector / dos_cylindersectors;
    581 	sector -= cylinder * dos_cylindersectors;
    582 
    583 	head = sector / dos_sectors;
    584 	sector -= head * dos_sectors;
    585 
    586 	*cylinderp = DOSCYL(cylinder);
    587 	*headp = head;
    588 	*sectorp = DOSSECT(sector + 1, cylinder);
    589 }
    590 
    591 int fd;
    592 
    593 int
    594 open_disk(u_flag)
    595 	int u_flag;
    596 {
    597 	struct stat st;
    598 
    599 	if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) {
    600 		warn("%s", disk);
    601 		return (-1);
    602 	}
    603 	if (fstat(fd, &st) == -1) {
    604 		close(fd);
    605 		warn("%s", disk);
    606 		return (-1);
    607 	}
    608 	if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
    609 		close(fd);
    610 		warnx("%s is not a character device or regular file", disk);
    611 		return (-1);
    612 	}
    613 	if (get_params() == -1) {
    614 		close(fd);
    615 		return (-1);
    616 	}
    617 	return (0);
    618 }
    619 
    620 int
    621 read_disk(sector, buf)
    622 	int sector;
    623 	void *buf;
    624 {
    625 
    626 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    627 		return (-1);
    628 	return (read(fd, buf, 512));
    629 }
    630 
    631 int
    632 write_disk(sector, buf)
    633 	int sector;
    634 	void *buf;
    635 {
    636 
    637 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    638 		return (-1);
    639 	return (write(fd, buf, 512));
    640 }
    641 
    642 int
    643 get_params()
    644 {
    645 
    646 	if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
    647 		warn("DIOCGDINFO");
    648 		return (-1);
    649 	}
    650 
    651 	dos_cylinders = cylinders = disklabel.d_ncylinders;
    652 	dos_heads = heads = disklabel.d_ntracks;
    653 	dos_sectors = sectors = disklabel.d_nsectors;
    654 	dos_cylindersectors = cylindersectors = heads * sectors;
    655 	disksectors = cylinders * heads * sectors;
    656 
    657 	return (0);
    658 }
    659 
    660 int
    661 read_s0()
    662 {
    663 
    664 	if (read_disk(0, mboot.bootinst) == -1) {
    665 		warn("can't read fdisk partition table");
    666 		return (-1);
    667 	}
    668 	if (mboot.signature != BOOT_MAGIC) {
    669 		warn("invalid fdisk partition table found");
    670 		/* So should we initialize things? */
    671 		return (-1);
    672 	}
    673 	return (0);
    674 }
    675 
    676 int
    677 write_s0()
    678 {
    679 	int flag;
    680 
    681 	/*
    682 	 * write enable label sector before write (if necessary),
    683 	 * disable after writing.
    684 	 * needed if the disklabel protected area also protects
    685 	 * sector 0. (e.g. empty disk)
    686 	 */
    687 	flag = 1;
    688 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    689 		warn("DIOCWLABEL");
    690 	if (write_disk(0, mboot.bootinst) == -1) {
    691 		warn("can't write fdisk partition table");
    692 		return -1;
    693 	}
    694 	flag = 0;
    695 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    696 		warn("DIOCWLABEL");
    697 }
    698 
    699 int
    700 yesno(str)
    701 	char *str;
    702 {
    703 	int ch, first;
    704 
    705 	printf("%s [n] ", str);
    706 
    707 	first = ch = getchar();
    708 	while (ch != '\n' && ch != EOF)
    709 		ch = getchar();
    710 	return (first == 'y' || first == 'Y');
    711 }
    712 
    713 void
    714 decimal(str, num)
    715 	char *str;
    716 	int *num;
    717 {
    718 	int acc = 0;
    719 	char *cp;
    720 
    721 	for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
    722 		printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
    723 
    724 		fgets(lbuf, LBUF, stdin);
    725 		lbuf[strlen(lbuf)-1] = '\0';
    726 		cp = lbuf;
    727 
    728 		cp += strspn(cp, " \t");
    729 		if (*cp == '\0')
    730 			return;
    731 
    732 		if (!isdigit(*cp))
    733 			continue;
    734 		acc = strtol(lbuf, &cp, 10);
    735 
    736 		cp += strspn(cp, " \t");
    737 		if (*cp != '\0')
    738 			continue;
    739 
    740 		*num = acc;
    741 		return;
    742 	}
    743 
    744 }
    745 
    746 int
    747 type_match(key, item)
    748 	const void *key, *item;
    749 {
    750 	const int *typep = key;
    751 	const struct part_type *ptr = item;
    752 
    753 	if (*typep < ptr->type)
    754 		return (-1);
    755 	if (*typep > ptr->type)
    756 		return (1);
    757 	return (0);
    758 }
    759 
    760 char *
    761 get_type(type)
    762 	int type;
    763 {
    764 	struct part_type *ptr;
    765 
    766 	ptr = bsearch(&type, part_types,
    767 	    sizeof(part_types) / sizeof(struct part_type),
    768 	    sizeof(struct part_type), type_match);
    769 	if (ptr == 0)
    770 		return ("unknown");
    771 	else
    772 		return (ptr->name);
    773 }
    774