Home | History | Annotate | Line # | Download | only in fdisk
fdisk.c revision 1.12
      1 /*	$NetBSD: fdisk.c,v 1.12 1997/03/29 20:46:17 thorpej 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.12 1997/03/29 20:46:17 thorpej 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 static inline unsigned short
    291 getshort(p)
    292 	void *p;
    293 {
    294 	unsigned char *cp = p;
    295 
    296 	return cp[0] | (cp[1] << 8);
    297 }
    298 
    299 static inline void
    300 putshort(p, l)
    301 	void *p;
    302 	unsigned short l;
    303 {
    304 	unsigned char *cp = p;
    305 
    306 	*cp++ = l;
    307 	*cp++ = l >> 8;
    308 }
    309 
    310 static inline unsigned long
    311 getlong(p)
    312 	void *p;
    313 {
    314 	unsigned char *cp = p;
    315 
    316 	return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24);
    317 }
    318 
    319 static inline void
    320 putlong(p, l)
    321 	void *p;
    322 	unsigned long l;
    323 {
    324 	unsigned char *cp = p;
    325 
    326 	*cp++ = l;
    327 	*cp++ = l >> 8;
    328 	*cp++ = l >> 16;
    329 	*cp++ = l >> 24;
    330 }
    331 
    332 void
    333 print_part(part)
    334 	int part;
    335 {
    336 	struct dos_partition *partp;
    337 
    338 	partp = &mboot.parts[part];
    339 	if (!memcmp(partp, &mtpart, sizeof(struct dos_partition))) {
    340 		printf("<UNUSED>\n");
    341 		return;
    342 	}
    343 	printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ));
    344 	printf("    start %d, size %d (%d MB), flag %x\n",
    345 	    getlong(&partp->dp_start), getlong(&partp->dp_size),
    346 	    getlong(&partp->dp_size) * 512 / (1024 * 1024), partp->dp_flag);
    347 	printf("\tbeg: cylinder %4d, head %3d, sector %2d\n",
    348 	    DPCYL(partp->dp_scyl, partp->dp_ssect),
    349 	    partp->dp_shd, DPSECT(partp->dp_ssect));
    350 	printf("\tend: cylinder %4d, head %3d, sector %2d\n",
    351 	    DPCYL(partp->dp_ecyl, partp->dp_esect),
    352 	    partp->dp_ehd, DPSECT(partp->dp_esect));
    353 }
    354 
    355 void
    356 init_sector0(start)
    357 	int start;
    358 {
    359 	struct dos_partition *partp;
    360 
    361 	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
    362 	putshort(&mboot.signature, BOOT_MAGIC);
    363 
    364 	partp = &mboot.parts[3];
    365 	partp->dp_typ = DOSPTYP_386BSD;
    366 	partp->dp_flag = ACTIVE;
    367 	putlong(&partp->dp_start, start);
    368 	putlong(&partp->dp_size, disksectors - start);
    369 
    370 	dos(getlong(&partp->dp_start),
    371 	    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    372 	dos(getlong(&partp->dp_start) + getlong(&partp->dp_size) - 1,
    373 	    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    374 }
    375 
    376 /* Prerequisite: the disklabel parameters and master boot record must
    377  *		 have been read (i.e. dos_* and mboot are meaningful).
    378  * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and
    379  *		  dos_cylindersectors to be consistent with what the
    380  *		  partition table is using, if we can find a geometry
    381  *		  which is consistent with all partition table entries.
    382  *		  We may get the number of cylinders slightly wrong (in
    383  *		  the conservative direction).  The idea is to be able
    384  *		  to create a NetBSD partition on a disk we don't know
    385  *		  the translated geometry of.
    386  * This whole routine should be replaced with a kernel interface to get
    387  * the BIOS geometry (which in turn requires modifications to the i386
    388  * boot loader to pass in the BIOS geometry for each disk). */
    389 void
    390 intuit_translated_geometry()
    391 {
    392 	int cylinders = -1, heads = -1, sectors = -1, i, j;
    393 	int c1, h1, s1, c2, h2, s2;
    394 	long a1, a2;
    395 	quad_t num, denom;
    396 
    397 	/* Try to deduce the number of heads from two different mappings. */
    398 	for (i = 0; i < NDOSPART * 2; i++) {
    399 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    400 			continue;
    401 		for (j = 0; j < 8; j++) {
    402 			if (get_mapping(j, &c2, &h2, &s2, &a2) < 0)
    403 				continue;
    404 			num = (quad_t)h1*(a2-s2) - h2*(a1-s1);
    405 			denom = (quad_t)c2*(a1-s1) - c1*(a2-s2);
    406 			if (denom != 0 && num % denom == 0) {
    407 				heads = num / denom;
    408 				break;
    409 			}
    410 		}
    411 		if (heads != -1)
    412 			break;
    413 	}
    414 
    415 	if (heads == -1)
    416 		return;
    417 
    418 	/* Now figure out the number of sectors from a single mapping. */
    419 	for (i = 0; i < NDOSPART * 2; i++) {
    420 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    421 			continue;
    422 		num = a1 - s1;
    423 		denom = c1 * heads + h1;
    424 		if (denom != 0 && num % denom == 0) {
    425 			sectors = num / denom;
    426 			break;
    427 		}
    428 	}
    429 
    430 	if (sectors == -1)
    431 		return;
    432 
    433 	/* Estimate the number of cylinders. */
    434 	cylinders = dos_cylinders * dos_cylindersectors / heads / sectors;
    435 
    436 	/* Now verify consistency with each of the partition table entries.
    437 	 * Be willing to shove cylinders up a little bit to make things work,
    438 	 * but translation mismatches are fatal. */
    439 	for (i = 0; i < NDOSPART * 2; i++) {
    440 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    441 			continue;
    442 		if (sectors * (c1 * heads + h1) + s1 != a1)
    443 			return;
    444 		if (c1 >= cylinders)
    445 			cylinders = c1 + 1;
    446 	}
    447 
    448 	/* Everything checks out.  Reset the geometry to use for further
    449 	 * calculations. */
    450 	dos_cylinders = cylinders;
    451 	dos_heads = heads;
    452 	dos_sectors = sectors;
    453 	dos_cylindersectors = heads * sectors;
    454 }
    455 
    456 /* For the purposes of intuit_translated_geometry(), treat the partition
    457  * table as a list of eight mapping between (cylinder, head, sector)
    458  * triplets and absolute sectors.  Get the relevant geometry triplet and
    459  * absolute sectors for a given entry, or return -1 if it isn't present.
    460  * Note: for simplicity, the returned sector is 0-based. */
    461 int
    462 get_mapping(i, cylinder, head, sector, absolute)
    463 	int i, *cylinder, *head, *sector;
    464 	long *absolute;
    465 {
    466 	struct dos_partition *part = &mboot.parts[i / 2];
    467 
    468 	if (part->dp_typ == 0)
    469 		return -1;
    470 	if (i % 2 == 0) {
    471 		*cylinder = DPCYL(part->dp_scyl, part->dp_ssect);
    472 		*head = part->dp_shd;
    473 		*sector = DPSECT(part->dp_ssect) - 1;
    474 		*absolute = getlong(&part->dp_start);
    475 	} else {
    476 		*cylinder = DPCYL(part->dp_ecyl, part->dp_esect);
    477 		*head = part->dp_ehd;
    478 		*sector = DPSECT(part->dp_esect) - 1;
    479 		*absolute = getlong(&part->dp_start)
    480 		    + getlong(&part->dp_size) - 1;
    481 	}
    482 	return 0;
    483 }
    484 
    485 void
    486 change_part(part)
    487 	int part;
    488 {
    489 	struct dos_partition *partp;
    490 
    491 	partp = &mboot.parts[part];
    492 
    493 	printf("The data for partition %d is:\n", part);
    494 	print_part(part);
    495 
    496 	if (!u_flag || !yesno("Do you want to change it?"))
    497 		return;
    498 
    499 	if (i_flag) {
    500 		memset(partp, 0, sizeof(*partp));
    501 		if (part == 3) {
    502 			init_sector0(1);
    503 			printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
    504 			print_part(part);
    505 		}
    506 	}
    507 
    508 	do {
    509 		{
    510 			int sysid, start, size;
    511 
    512 			sysid = partp->dp_typ,
    513 			start = getlong(&partp->dp_start),
    514 			size = getlong(&partp->dp_size);
    515 			decimal("sysid", &sysid);
    516 			decimal("start", &start);
    517 			decimal("size", &size);
    518 			partp->dp_typ = sysid;
    519 			putlong(&partp->dp_start, start);
    520 			putlong(&partp->dp_size, size);
    521 		}
    522 
    523 		if (yesno("Explicitly specify beg/end address?")) {
    524 			int tsector, tcylinder, thead;
    525 
    526 			tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
    527 			thead = partp->dp_shd;
    528 			tsector = DPSECT(partp->dp_ssect);
    529 			decimal("beginning cylinder", &tcylinder);
    530 			decimal("beginning head", &thead);
    531 			decimal("beginning sector", &tsector);
    532 			partp->dp_scyl = DOSCYL(tcylinder);
    533 			partp->dp_shd = thead;
    534 			partp->dp_ssect = DOSSECT(tsector, tcylinder);
    535 
    536 			tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
    537 			thead = partp->dp_ehd;
    538 			tsector = DPSECT(partp->dp_esect);
    539 			decimal("ending cylinder", &tcylinder);
    540 			decimal("ending head", &thead);
    541 			decimal("ending sector", &tsector);
    542 			partp->dp_ecyl = DOSCYL(tcylinder);
    543 			partp->dp_ehd = thead;
    544 			partp->dp_esect = DOSSECT(tsector, tcylinder);
    545 		} else {
    546 			dos(getlong(&partp->dp_start),
    547 			    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    548 			dos(getlong(&partp->dp_start)
    549 			    + getlong(&partp->dp_size) - 1,
    550 			    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    551 		}
    552 
    553 		print_part(part);
    554 	} while (!yesno("Is this entry okay?"));
    555 }
    556 
    557 void
    558 print_params()
    559 {
    560 
    561 	printf("parameters extracted from in-core disklabel are:\n");
    562 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    563 	    cylinders, heads, sectors, cylindersectors);
    564 	if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255)
    565 		printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
    566 	printf("parameters to be used for BIOS calculations are:\n");
    567 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    568 	    dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
    569 }
    570 
    571 void
    572 change_active(which)
    573 	int which;
    574 {
    575 	struct dos_partition *partp;
    576 	int part;
    577 	int active = 3;
    578 
    579 	partp = &mboot.parts[0];
    580 
    581 	if (a_flag && which != -1)
    582 		active = which;
    583 	else {
    584 		for (part = 0; part < NDOSPART; part++)
    585 			if (partp[part].dp_flag & ACTIVE)
    586 				active = part;
    587 	}
    588 	if (yesno("Do you want to change the active partition?")) {
    589 		do {
    590 			decimal("active partition", &active);
    591 		} while (!yesno("Are you happy with this choice?"));
    592 	}
    593 	for (part = 0; part < NDOSPART; part++)
    594 		partp[part].dp_flag &= ~ACTIVE;
    595 	partp[active].dp_flag |= ACTIVE;
    596 }
    597 
    598 void
    599 get_params_to_use()
    600 {
    601 
    602 	print_params();
    603 	if (yesno("Do you want to change our idea of what BIOS thinks?")) {
    604 		do {
    605 			decimal("BIOS's idea of #cylinders", &dos_cylinders);
    606 			decimal("BIOS's idea of #heads", &dos_heads);
    607 			decimal("BIOS's idea of #sectors", &dos_sectors);
    608 			dos_cylindersectors = dos_heads * dos_sectors;
    609 			print_params();
    610 		} while (!yesno("Are you happy with this choice?"));
    611 	}
    612 }
    613 
    614 /***********************************************\
    615 * Change real numbers into strange dos numbers	*
    616 \***********************************************/
    617 void
    618 dos(sector, cylinderp, headp, sectorp)
    619 	int sector;
    620 	unsigned char *cylinderp, *headp, *sectorp;
    621 {
    622 	int cylinder, head;
    623 
    624 	cylinder = sector / dos_cylindersectors;
    625 	sector -= cylinder * dos_cylindersectors;
    626 
    627 	head = sector / dos_sectors;
    628 	sector -= head * dos_sectors;
    629 
    630 	*cylinderp = DOSCYL(cylinder);
    631 	*headp = head;
    632 	*sectorp = DOSSECT(sector + 1, cylinder);
    633 }
    634 
    635 int fd;
    636 
    637 int
    638 open_disk(u_flag)
    639 	int u_flag;
    640 {
    641 	struct stat st;
    642 
    643 	if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) {
    644 		warn("%s", disk);
    645 		return (-1);
    646 	}
    647 	if (fstat(fd, &st) == -1) {
    648 		close(fd);
    649 		warn("%s", disk);
    650 		return (-1);
    651 	}
    652 	if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
    653 		close(fd);
    654 		warnx("%s is not a character device or regular file", disk);
    655 		return (-1);
    656 	}
    657 	if (get_params() == -1) {
    658 		close(fd);
    659 		return (-1);
    660 	}
    661 	return (0);
    662 }
    663 
    664 int
    665 read_disk(sector, buf)
    666 	int sector;
    667 	void *buf;
    668 {
    669 
    670 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    671 		return (-1);
    672 	return (read(fd, buf, 512));
    673 }
    674 
    675 int
    676 write_disk(sector, buf)
    677 	int sector;
    678 	void *buf;
    679 {
    680 
    681 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    682 		return (-1);
    683 	return (write(fd, buf, 512));
    684 }
    685 
    686 int
    687 get_params()
    688 {
    689 
    690 	if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
    691 		warn("DIOCGDINFO");
    692 		return (-1);
    693 	}
    694 
    695 	dos_cylinders = cylinders = disklabel.d_ncylinders;
    696 	dos_heads = heads = disklabel.d_ntracks;
    697 	dos_sectors = sectors = disklabel.d_nsectors;
    698 	dos_cylindersectors = cylindersectors = heads * sectors;
    699 	disksectors = cylinders * heads * sectors;
    700 
    701 	return (0);
    702 }
    703 
    704 int
    705 read_s0()
    706 {
    707 
    708 	if (read_disk(0, mboot.bootinst) == -1) {
    709 		warn("can't read fdisk partition table");
    710 		return (-1);
    711 	}
    712 	if (getshort(&mboot.signature) != BOOT_MAGIC) {
    713 		warnx("invalid fdisk partition table found");
    714 		/* So should we initialize things? */
    715 		return (-1);
    716 	}
    717 	return (0);
    718 }
    719 
    720 int
    721 write_s0()
    722 {
    723 	int flag;
    724 
    725 	/*
    726 	 * write enable label sector before write (if necessary),
    727 	 * disable after writing.
    728 	 * needed if the disklabel protected area also protects
    729 	 * sector 0. (e.g. empty disk)
    730 	 */
    731 	flag = 1;
    732 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    733 		warn("DIOCWLABEL");
    734 	if (write_disk(0, mboot.bootinst) == -1) {
    735 		warn("can't write fdisk partition table");
    736 		return -1;
    737 	}
    738 	flag = 0;
    739 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    740 		warn("DIOCWLABEL");
    741 }
    742 
    743 int
    744 yesno(str)
    745 	char *str;
    746 {
    747 	int ch, first;
    748 
    749 	printf("%s [n] ", str);
    750 
    751 	first = ch = getchar();
    752 	while (ch != '\n' && ch != EOF)
    753 		ch = getchar();
    754 	return (first == 'y' || first == 'Y');
    755 }
    756 
    757 void
    758 decimal(str, num)
    759 	char *str;
    760 	int *num;
    761 {
    762 	int acc = 0;
    763 	char *cp;
    764 
    765 	for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
    766 		printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
    767 
    768 		fgets(lbuf, LBUF, stdin);
    769 		lbuf[strlen(lbuf)-1] = '\0';
    770 		cp = lbuf;
    771 
    772 		cp += strspn(cp, " \t");
    773 		if (*cp == '\0')
    774 			return;
    775 
    776 		if (!isdigit(*cp))
    777 			continue;
    778 		acc = strtol(lbuf, &cp, 10);
    779 
    780 		cp += strspn(cp, " \t");
    781 		if (*cp != '\0')
    782 			continue;
    783 
    784 		*num = acc;
    785 		return;
    786 	}
    787 
    788 }
    789 
    790 int
    791 type_match(key, item)
    792 	const void *key, *item;
    793 {
    794 	const int *typep = key;
    795 	const struct part_type *ptr = item;
    796 
    797 	if (*typep < ptr->type)
    798 		return (-1);
    799 	if (*typep > ptr->type)
    800 		return (1);
    801 	return (0);
    802 }
    803 
    804 char *
    805 get_type(type)
    806 	int type;
    807 {
    808 	struct part_type *ptr;
    809 
    810 	ptr = bsearch(&type, part_types,
    811 	    sizeof(part_types) / sizeof(struct part_type),
    812 	    sizeof(struct part_type), type_match);
    813 	if (ptr == 0)
    814 		return ("unknown");
    815 	else
    816 		return (ptr->name);
    817 }
    818