Home | History | Annotate | Line # | Download | only in fdisk
fdisk.c revision 1.15
      1 /*	$NetBSD: fdisk.c,v 1.15 1997/08/11 23:31:42 phil 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.15 1997/08/11 23:31:42 phil 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 int sh_flag;		/* Output data as shell defines */
     85 int f_flag;		/* force --not interactive */
     86 int s_flag;		/* set id,offset,size */
     87 
     88 unsigned char bootcode[] = {
     89 0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
     90 0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
     91 0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
     92 0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
     93 0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
     94 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
     95 0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
     96 0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
     97 0xeb, 0xf4, 0xfb, 0xeb, 0xfe,
     98 'M', 'i', 's', 's', 'i', 'n', 'g', ' ',
     99 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
    100 'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ',
    101 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
    102 'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ',
    103 	'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0,
    104 'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ',
    105 	'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0,
    106 
    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,   0,   0,
    117   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    118   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    119   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
    120 };
    121 
    122 struct part_type {
    124 	int type;
    125 	char *name;
    126 } part_types[] = {
    127 	{0x00, "unused"},
    128 	{0x01, "Primary DOS with 12 bit FAT"},
    129 	{0x02, "XENIX / filesystem"},
    130 	{0x03, "XENIX /usr filesystem"},
    131 	{0x04, "Primary DOS with 16 bit FAT <32M"},
    132 	{0x05, "Extended DOS"},
    133 	{0x06, "Primary 'big' DOS, 16-bit FAT (> 32MB)"},
    134 	{0x07, "OS/2 HPFS or NTFS or QNX2 or Advanced UNIX"},
    135 	{0x08, "AIX filesystem"},
    136 	{0x09, "AIX boot partition or Coherent"},
    137 	{0x0A, "OS/2 Boot Manager or Coherent swap or OPUS"},
    138 	{0x0E, "DOS (16-bit FAT), CHS-mapped"},
    139 	{0x0F, "Ext. partition, CHS-mapped"},
    140 	{0x10, "OPUS"},
    141 	{0x11, "OS/2 BM: hidden DOS 12-bit FAT"},
    142 	{0x12, "Compaq diagnostics"},
    143 	{0x14, "OS/2 BM: hidden DOS 16-bit FAT <32M"},
    144 	{0x16, "OS/2 BM: hidden DOS 16-bit FAT >=32M"},
    145 	{0x17, "OS/2 BM: hidden IFS"},
    146 	{0x18, "AST Windows swapfile"},
    147 	{0x24, "NEC DOS"},
    148 	{0x3C, "PartitionMagic recovery"},
    149 	{0x40, "VENIX 286"},
    150 	{0x41, "Linux/MINIX (sharing disk with DRDOS)"},
    151 	{0x42, "SFS or Linux swap (sharing disk with DRDOS)"},
    152 	{0x43, "Linux native (sharing disk with DRDOS)"},
    153 	{0x50, "DM (disk manager)"},
    154 	{0x51, "DM6 Aux1 (or Novell)"},
    155 	{0x52, "CP/M or Microport SysV/AT"},
    156 	{0x53, "DM6 Aux3"},
    157 	{0x54, "DM6"},
    158 	{0x55, "EZ-Drive (disk manager)"},
    159 	{0x56, "Golden Bow (disk manager)"},
    160 	{0x5C, "Priam Edisk (disk manager)"},
    161 	{0x61, "SpeedStor"},
    162 	{0x63, "GNU HURD or Mach or Sys V/386 (such as ISC UNIX)"},
    163 	{0x64, "Novell Netware 2.xx"},
    164 	{0x65, "Novell Netware 3.xx"},
    165 	{0x70, "DiskSecure Multi-Boot"},
    166 	{0x75, "PC/IX"},
    167 	{0x77, "QNX4.x"},
    168 	{0x78, "QNX4.x 2nd part"},
    169 	{0x79, "QNX4.x 3rd part"},
    170 	{0x80, "MINIX until 1.4a"},
    171 	{0x81, "MINIX since 1.4b, early Linux, Mitac dmgr"},
    172 	{0x82, "Linux swap"},
    173 	{0x83, "Linux native"},
    174 	{0x84, "OS/2 hidden C: drive"},
    175 	{0x85, "Linux extended"},
    176 	{0x86, "NTFS volume set??"},
    177 	{0x87, "NTFS volume set??"},
    178 	{0x93, "Amoeba filesystem"},
    179 	{0x94, "Amoeba bad block table"},
    180 	{0xA0, "IBM Thinkpad hibernation"},
    181 	{0xA5, "NetBSD or FreeBSD or 386BSD"},
    182 	{0xA6, "OpenBSD"},
    183 	{0xA7, "NeXTSTEP 486"},
    184 	{0xB7, "BSDI BSD/386 filesystem"},
    185 	{0xB8, "BSDI BSD/386 swap"},
    186 	{0xC1, "DRDOS/sec (FAT-12)"},
    187 	{0xC4, "DRDOS/sec (FAT-16, < 32M)"},
    188 	{0xC6, "DRDOS/sec (FAT-16, >= 32M)"},
    189 	{0xC7, "Syrinx"},
    190 	{0xDB, "CP/M or Concurrent CP/M or Concurrent DOS or CTOS"},
    191 	{0xE1, "DOS access or SpeedStor 12-bit FAT extended partition"},
    192 	{0xE3, "DOS R/O or SpeedStor"},
    193 	{0xE4, "SpeedStor 16-bit FAT extended partition < 1024 cyl."},
    194 	{0xF1, "SpeedStor"},
    195 	{0xF2, "DOS 3.3+ Secondary"},
    196 	{0xF4, "SpeedStor large partition"},
    197 	{0xFE, "SpeedStor >1024 cyl. or LANstep"},
    198 	{0xFF, "Xenix Bad Block Table"},
    199 };
    200 
    201 void	usage __P((void));
    202 void	print_s0 __P((int));
    203 void	print_part __P((int));
    204 void	init_sector0 __P((int));
    205 void	intuit_translated_geometry __P((void));
    206 int	try_heads __P((quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, quad_t,
    207 		       quad_t));
    208 int	try_sectors __P((quad_t, quad_t, quad_t, quad_t, quad_t));
    209 void	change_part __P((int, int, int, int));
    210 void	print_params __P((void));
    211 void	change_active __P((int));
    212 void	get_params_to_use __P((void));
    213 void	dos __P((int, unsigned char *, unsigned char *, unsigned char *));
    214 int	open_disk __P((int));
    215 int	read_disk __P((int, void *));
    216 int	write_disk __P((int, void *));
    217 int	get_params __P((void));
    218 int	read_s0 __P((void));
    219 int	write_s0 __P((void));
    220 int	yesno __P((char *));
    221 void	decimal __P((char *, int *));
    222 int	type_match __P((const void *, const void *));
    223 char	*get_type __P((int));
    224 
    225 int
    226 main(argc, argv)
    227 	int argc;
    228 	char *argv[];
    229 {
    230 	int ch;
    231 	int part;
    232 
    233 	int csysid, cstart, csize;	/* For the b_flag. */
    234 
    235 	a_flag = i_flag = u_flag = sh_flag = f_flag = s_flag = 0;
    236 	csysid = cstart = csize = 0;
    237 	while ((ch = getopt(argc, argv, "0123Safisu")) != -1)
    238 		switch (ch) {
    239 		case '0':
    240 			partition = 0;
    241 			break;
    242 		case '1':
    243 			partition = 1;
    244 			break;
    245 		case '2':
    246 			partition = 2;
    247 			break;
    248 		case '3':
    249 			partition = 3;
    250 			break;
    251 		case 'S':
    252 			sh_flag = 1;
    253 			break;
    254 		case 'a':
    255 			a_flag = 1;
    256 			break;
    257 		case 'f':
    258 			f_flag = 1;
    259 			break;
    260 		case 'i':
    261 			i_flag = 1;
    262 			break;
    263 		case 'u':
    264 			u_flag = 1;
    265 			break;
    266 		case 's':
    267 			s_flag = 1;
    268 			break;
    269 		default:
    270 			usage();
    271 		}
    272 	argc -= optind;
    273 	argv += optind;
    274 
    275 	if (sh_flag && (a_flag || i_flag || u_flag || f_flag || s_flag))
    276 		usage();
    277 
    278 	if (partition == -1 && s_flag) {
    279 		(void) fprintf (stderr,
    280 				"-s flag requires a partition selected.\n");
    281 		usage();
    282 	}
    283 
    284 	/* get s_flag parameters. */
    285 	if (s_flag) {
    286 		if (argc >= 3) {
    287 			csysid = atoi(argv[0]);
    288 			cstart = atoi(argv[1]);
    289 			csize  = atoi(argv[2]);
    290 			argc -= 3;
    291 			argv += 3;
    292 		} else
    293 			usage();
    294 	}
    295 
    296 	if (argc > 0)
    297 		disk = argv[0];
    298 
    299 	if (open_disk(a_flag || i_flag || u_flag) < 0)
    300 		exit(1);
    301 
    302 	if (read_s0())
    303 		init_sector0(sectors > 63 ? 63 : sectors);
    304 
    305 	intuit_translated_geometry();
    306 
    307 	if (!sh_flag)
    308 		printf("******* Working on device %s *******\n", disk);
    309 
    310 
    311 	if ((i_flag || u_flag) && !f_flag)
    312 		get_params_to_use();
    313 
    314 	if (i_flag)
    315 		init_sector0(dos_sectors > 63 ? 63 : dos_sectors);
    316 
    317 	if (!sh_flag)
    318 		printf("Warning: BIOS sector numbering starts with sector 1\n");
    319 
    320 	/* Do the update stuff! */
    321 	if (u_flag) {
    322 		if (!f_flag)
    323 			printf("Information from DOS bootblock is:\n");
    324 		if (partition == -1)
    325 			for (part = 0; part < NDOSPART; part++)
    326 				change_part(part,-1, -1, -1);
    327 		else
    328 			change_part(partition, csysid, cstart, csize);
    329 	} else
    330 		if (!i_flag)
    331 			print_s0(partition);
    332 
    333 	if (a_flag)
    334 		change_active(partition);
    335 
    336 	if (u_flag || a_flag || i_flag) {
    337 		if (!f_flag) {
    338 			printf("\nWe haven't changed the partition table "
    339 			       "yet.  This is your last chance.\n");
    340 			print_s0(-1);
    341 			if (yesno("Should we write new partition table?"))
    342 				write_s0();
    343 		} else
    344 			write_s0();
    345 	}
    346 
    347 	exit(0);
    348 }
    349 
    350 void
    351 usage()
    352 {
    353 	(void)fprintf(stderr, "usage: fdisk [-aiufS] [-0|-1|-2|-3] "
    354 		      "[-s sysid start size] [device]\n");
    355 	exit(1);
    356 }
    357 
    358 void
    359 print_s0(which)
    360 	int which;
    361 {
    362 	int part;
    363 
    364 	print_params();
    365 	if (!sh_flag)
    366 		printf("Information from DOS bootblock is:\n");
    367 	if (which == -1) {
    368 		for (part = 0; part < NDOSPART; part++) {
    369 			if (!sh_flag)
    370 				printf("%d: ", part);
    371 			print_part(part);
    372 		}
    373 	} else
    374 		print_part(which);
    375 }
    376 
    377 static struct dos_partition mtpart = { 0 };
    378 
    379 static inline unsigned short
    380 getshort(p)
    381 	void *p;
    382 {
    383 	unsigned char *cp = p;
    384 
    385 	return cp[0] | (cp[1] << 8);
    386 }
    387 
    388 static inline void
    389 putshort(p, l)
    390 	void *p;
    391 	unsigned short l;
    392 {
    393 	unsigned char *cp = p;
    394 
    395 	*cp++ = l;
    396 	*cp++ = l >> 8;
    397 }
    398 
    399 static inline unsigned long
    400 getlong(p)
    401 	void *p;
    402 {
    403 	unsigned char *cp = p;
    404 
    405 	return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24);
    406 }
    407 
    408 static inline void
    409 putlong(p, l)
    410 	void *p;
    411 	unsigned long l;
    412 {
    413 	unsigned char *cp = p;
    414 
    415 	*cp++ = l;
    416 	*cp++ = l >> 8;
    417 	*cp++ = l >> 16;
    418 	*cp++ = l >> 24;
    419 }
    420 
    421 void
    422 print_part(part)
    423 	int part;
    424 {
    425 	struct dos_partition *partp;
    426 	int empty;
    427 
    428 	partp = &mboot.parts[part];
    429 	empty = !memcmp(partp, &mtpart, sizeof(struct dos_partition));
    430 
    431 	if (sh_flag) {
    432 		if (empty) {
    433 			printf("PART%dSIZE=0\n", part);
    434 			return;
    435 		}
    436 
    437 		printf("PART%dID=%d\n", part, partp->dp_typ);
    438 		printf("PART%dSIZE=%d\n", part, getlong(&partp->dp_size));
    439 		printf("PART%dSTART=%d\n", part, getlong(&partp->dp_start));
    440 		printf("PART%dFLAG=%x\n", part, partp->dp_flag);
    441 		printf("PART%dBCYL=%d\n", part, DPCYL(partp->dp_scyl,
    442 						      partp->dp_ssect));
    443 		printf("PART%dBHEAD=%d\n", part, partp->dp_shd);
    444 		printf("PART%dBSEC=%d\n", part, DPSECT(partp->dp_ssect));
    445 		printf("PART%dECYL=%d\n", part, DPCYL(partp->dp_ecyl,
    446 						      partp->dp_esect));
    447 		printf("PART%dEHEAD=%d\n", part, partp->dp_ehd);
    448 		printf("PART%dESEC=%d\n", part, DPSECT(partp->dp_esect));
    449 		return;
    450 	}
    451 
    452 	/* Not sh_flag. */
    453 	if (empty) {
    454 		printf("<UNUSED>\n");
    455 		return;
    456 	}
    457 	printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ));
    458 	printf("    start %d, size %d (%d MB), flag %x\n",
    459 	    getlong(&partp->dp_start), getlong(&partp->dp_size),
    460 	    getlong(&partp->dp_size) * 512 / (1024 * 1024), partp->dp_flag);
    461 	printf("\tbeg: cylinder %4d, head %3d, sector %2d\n",
    462 	    DPCYL(partp->dp_scyl, partp->dp_ssect),
    463 	    partp->dp_shd, DPSECT(partp->dp_ssect));
    464 	printf("\tend: cylinder %4d, head %3d, sector %2d\n",
    465 	    DPCYL(partp->dp_ecyl, partp->dp_esect),
    466 	    partp->dp_ehd, DPSECT(partp->dp_esect));
    467 }
    468 
    469 void
    470 init_sector0(start)
    471 	int start;
    472 {
    473 	int i;
    474 	struct dos_partition *partp;
    475 
    476 	int dos_disksectors = dos_cylinders * dos_heads * dos_sectors;
    477 
    478 	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
    479 	putshort(&mboot.signature, BOOT_MAGIC);
    480 
    481 	for (i=0; i<3; i++)
    482 		memset (&mboot.parts[i], 0, sizeof(struct dos_partition));
    483 
    484 	partp = &mboot.parts[3];
    485 	partp->dp_typ = DOSPTYP_386BSD;
    486 	partp->dp_flag = ACTIVE;
    487 	putlong(&partp->dp_start, start);
    488 	putlong(&partp->dp_size, dos_disksectors - start);
    489 
    490 	dos(getlong(&partp->dp_start),
    491 	    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    492 	dos(getlong(&partp->dp_start) + getlong(&partp->dp_size) - 1,
    493 	    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    494 
    495 	printf ("DOS partition table initialized.\n");
    496 }
    497 
    498 /* Prerequisite: the disklabel parameters and master boot record must
    499  *		 have been read (i.e. dos_* and mboot are meaningful).
    500  * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and
    501  *		  dos_cylindersectors to be consistent with what the
    502  *		  partition table is using, if we can find a geometry
    503  *		  which is consistent with all partition table entries.
    504  *		  We may get the number of cylinders slightly wrong (in
    505  *		  the conservative direction).  The idea is to be able
    506  *		  to create a NetBSD partition on a disk we don't know
    507  *		  the translated geometry of.
    508  * This whole routine should be replaced with a kernel interface to get
    509  * the BIOS geometry (which in turn requires modifications to the i386
    510  * boot loader to pass in the BIOS geometry for each disk). */
    511 void
    512 intuit_translated_geometry()
    513 {
    514 
    515 	int cylinders = -1, heads = -1, sectors = -1, i, j;
    516 	int c1, h1, s1, c2, h2, s2;
    517 	long a1, a2;
    518 	quad_t num, denom;
    519 
    520 	/* Try to deduce the number of heads from two different mappings. */
    521 	for (i = 0; i < NDOSPART * 2; i++) {
    522 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    523 			continue;
    524 		for (j = 0; j < 8; j++) {
    525 			if (get_mapping(j, &c2, &h2, &s2, &a2) < 0)
    526 				continue;
    527 			num = (quad_t)h1*(a2-s2) - h2*(a1-s1);
    528 			denom = (quad_t)c2*(a1-s1) - c1*(a2-s2);
    529 			if (denom != 0 && num % denom == 0) {
    530 				heads = num / denom;
    531 				break;
    532 			}
    533 		}
    534 		if (heads != -1)
    535 			break;
    536 	}
    537 
    538 	if (heads == -1)
    539 		return;
    540 
    541 	/* Now figure out the number of sectors from a single mapping. */
    542 	for (i = 0; i < NDOSPART * 2; i++) {
    543 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    544 			continue;
    545 		num = a1 - s1;
    546 		denom = c1 * heads + h1;
    547 		if (denom != 0 && num % denom == 0) {
    548 			sectors = num / denom;
    549 			break;
    550 		}
    551 	}
    552 
    553 	if (sectors == -1)
    554 		return;
    555 
    556 	/* Estimate the number of cylinders. */
    557 	cylinders = dos_cylinders * dos_cylindersectors / heads / sectors;
    558 
    559 	/* Now verify consistency with each of the partition table entries.
    560 	 * Be willing to shove cylinders up a little bit to make things work,
    561 	 * but translation mismatches are fatal. */
    562 	for (i = 0; i < NDOSPART * 2; i++) {
    563 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    564 			continue;
    565 		if (sectors * (c1 * heads + h1) + s1 != a1)
    566 			return;
    567 		if (c1 >= cylinders)
    568 			cylinders = c1 + 1;
    569 	}
    570 
    571 	/* Everything checks out.  Reset the geometry to use for further
    572 	 * calculations. */
    573 	dos_cylinders = cylinders;
    574 	dos_heads = heads;
    575 	dos_sectors = sectors;
    576 	dos_cylindersectors = heads * sectors;
    577 }
    578 
    579 /* For the purposes of intuit_translated_geometry(), treat the partition
    580  * table as a list of eight mapping between (cylinder, head, sector)
    581  * triplets and absolute sectors.  Get the relevant geometry triplet and
    582  * absolute sectors for a given entry, or return -1 if it isn't present.
    583  * Note: for simplicity, the returned sector is 0-based. */
    584 int
    585 get_mapping(i, cylinder, head, sector, absolute)
    586 	int i, *cylinder, *head, *sector;
    587 	long *absolute;
    588 {
    589 	struct dos_partition *part = &mboot.parts[i / 2];
    590 
    591 	if (part->dp_typ == 0)
    592 		return -1;
    593 	if (i % 2 == 0) {
    594 		*cylinder = DPCYL(part->dp_scyl, part->dp_ssect);
    595 		*head = part->dp_shd;
    596 		*sector = DPSECT(part->dp_ssect) - 1;
    597 		*absolute = getlong(&part->dp_start);
    598 	} else {
    599 		*cylinder = DPCYL(part->dp_ecyl, part->dp_esect);
    600 		*head = part->dp_ehd;
    601 		*sector = DPSECT(part->dp_esect) - 1;
    602 		*absolute = getlong(&part->dp_start)
    603 		    + getlong(&part->dp_size) - 1;
    604 	}
    605 	return 0;
    606 }
    607 
    608 void
    609 change_part(part, csysid, cstart, csize)
    610 	int part, csysid, cstart, csize;
    611 {
    612 	struct dos_partition *partp;
    613 
    614 	partp = &mboot.parts[part];
    615 
    616 	if (s_flag) {
    617 		partp->dp_typ = csysid;
    618 		putlong(&partp->dp_start, cstart);
    619 		putlong(&partp->dp_size, csize);
    620 		dos(getlong(&partp->dp_start),
    621 		    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    622 		dos(getlong(&partp->dp_start)
    623 		    + getlong(&partp->dp_size) - 1,
    624 		    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    625 		if (f_flag)
    626 			return;
    627 	}
    628 
    629 	printf("The data for partition %d is:\n", part);
    630 	print_part(part);
    631 	if (!u_flag || !yesno("Do you want to change it?"))
    632 		return;
    633 
    634 	do {
    635 		{
    636 			int sysid, start, size;
    637 
    638 			sysid = partp->dp_typ,
    639 			start = getlong(&partp->dp_start),
    640 			size = getlong(&partp->dp_size);
    641 			decimal("sysid", &sysid);
    642 			decimal("start", &start);
    643 			decimal("size", &size);
    644 			partp->dp_typ = sysid;
    645 			putlong(&partp->dp_start, start);
    646 			putlong(&partp->dp_size, size);
    647 		}
    648 
    649 		if (yesno("Explicitly specify beg/end address?")) {
    650 			int tsector, tcylinder, thead;
    651 
    652 			tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
    653 			thead = partp->dp_shd;
    654 			tsector = DPSECT(partp->dp_ssect);
    655 			decimal("beginning cylinder", &tcylinder);
    656 			decimal("beginning head", &thead);
    657 			decimal("beginning sector", &tsector);
    658 			partp->dp_scyl = DOSCYL(tcylinder);
    659 			partp->dp_shd = thead;
    660 			partp->dp_ssect = DOSSECT(tsector, tcylinder);
    661 
    662 			tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
    663 			thead = partp->dp_ehd;
    664 			tsector = DPSECT(partp->dp_esect);
    665 			decimal("ending cylinder", &tcylinder);
    666 			decimal("ending head", &thead);
    667 			decimal("ending sector", &tsector);
    668 			partp->dp_ecyl = DOSCYL(tcylinder);
    669 			partp->dp_ehd = thead;
    670 			partp->dp_esect = DOSSECT(tsector, tcylinder);
    671 		} else {
    672 			dos(getlong(&partp->dp_start),
    673 			    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    674 			dos(getlong(&partp->dp_start)
    675 			    + getlong(&partp->dp_size) - 1,
    676 			    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    677 		}
    678 
    679 		print_part(part);
    680 	} while (!yesno("Is this entry okay?"));
    681 }
    682 
    683 void
    684 print_params()
    685 {
    686 
    687 	if (sh_flag) {
    688 		printf ("DLCYL=%d\nDLHEAD=%d\nDLSEC=%d\n",
    689 			cylinders, heads, sectors);
    690 		printf ("BCYL=%d\nBHEAD=%d\nBSEC=%d\n",
    691 			dos_cylinders, dos_heads, dos_sectors);
    692 		return;
    693 	}
    694 
    695 	/* Not sh_flag */
    696 	printf("parameters extracted from in-core disklabel are:\n");
    697 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    698 	    cylinders, heads, sectors, cylindersectors);
    699 	if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255)
    700 		printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
    701 	printf("parameters to be used for BIOS calculations are:\n");
    702 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    703 	    dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
    704 }
    705 
    706 void
    707 change_active(which)
    708 	int which;
    709 {
    710 	struct dos_partition *partp;
    711 	int part;
    712 	int active = 4;
    713 
    714 	partp = &mboot.parts[0];
    715 
    716 	if (a_flag && which != -1)
    717 		active = which;
    718 	else {
    719 		for (part = 0; part < NDOSPART; part++)
    720 			if (partp[part].dp_flag & ACTIVE)
    721 				active = part;
    722 	}
    723 	if (!f_flag) {
    724 		if (yesno("Do you want to change the active partition?")) {
    725 			printf ("Choosing 4 will make no partition active.\n");
    726 			do {
    727 				decimal("active partition", &active);
    728 			} while (!yesno("Are you happy with this choice?"));
    729 		} else
    730 			return;
    731 	} else
    732 		if (active != 4)
    733 			printf ("Making partition %d active.\n", active);
    734 
    735 	for (part = 0; part < NDOSPART; part++)
    736 		partp[part].dp_flag &= ~ACTIVE;
    737 	if (active < 4)
    738 		partp[active].dp_flag |= ACTIVE;
    739 }
    740 
    741 void
    742 get_params_to_use()
    743 {
    744 
    745 	print_params();
    746 	if (yesno("Do you want to change our idea of what BIOS thinks?")) {
    747 		do {
    748 			decimal("BIOS's idea of #cylinders", &dos_cylinders);
    749 			decimal("BIOS's idea of #heads", &dos_heads);
    750 			decimal("BIOS's idea of #sectors", &dos_sectors);
    751 			dos_cylindersectors = dos_heads * dos_sectors;
    752 			print_params();
    753 		} while (!yesno("Are you happy with this choice?"));
    754 	}
    755 }
    756 
    757 /***********************************************\
    758 * Change real numbers into strange dos numbers	*
    759 \***********************************************/
    760 void
    761 dos(sector, cylinderp, headp, sectorp)
    762 	int sector;
    763 	unsigned char *cylinderp, *headp, *sectorp;
    764 {
    765 	int cylinder, head;
    766 
    767 	cylinder = sector / dos_cylindersectors;
    768 	sector -= cylinder * dos_cylindersectors;
    769 
    770 	head = sector / dos_sectors;
    771 	sector -= head * dos_sectors;
    772 
    773 	*cylinderp = DOSCYL(cylinder);
    774 	*headp = head;
    775 	*sectorp = DOSSECT(sector + 1, cylinder);
    776 }
    777 
    778 int fd;
    779 
    780 int
    781 open_disk(u_flag)
    782 	int u_flag;
    783 {
    784 	struct stat st;
    785 
    786 	if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) {
    787 		warn("%s", disk);
    788 		return (-1);
    789 	}
    790 	if (fstat(fd, &st) == -1) {
    791 		close(fd);
    792 		warn("%s", disk);
    793 		return (-1);
    794 	}
    795 	if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
    796 		close(fd);
    797 		warnx("%s is not a character device or regular file", disk);
    798 		return (-1);
    799 	}
    800 	if (get_params() == -1) {
    801 		close(fd);
    802 		return (-1);
    803 	}
    804 	return (0);
    805 }
    806 
    807 int
    808 read_disk(sector, buf)
    809 	int sector;
    810 	void *buf;
    811 {
    812 
    813 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    814 		return (-1);
    815 	return (read(fd, buf, 512));
    816 }
    817 
    818 int
    819 write_disk(sector, buf)
    820 	int sector;
    821 	void *buf;
    822 {
    823 
    824 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    825 		return (-1);
    826 	return (write(fd, buf, 512));
    827 }
    828 
    829 int
    830 get_params()
    831 {
    832 
    833 	if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
    834 		warn("DIOCGDINFO");
    835 		return (-1);
    836 	}
    837 
    838 	dos_cylinders = cylinders = disklabel.d_ncylinders;
    839 	dos_heads = heads = disklabel.d_ntracks;
    840 	dos_sectors = sectors = disklabel.d_nsectors;
    841 	dos_cylindersectors = cylindersectors = heads * sectors;
    842 	disksectors = cylinders * heads * sectors;
    843 
    844 	return (0);
    845 }
    846 
    847 int
    848 read_s0()
    849 {
    850 
    851 	if (read_disk(0, mboot.bootinst) == -1) {
    852 		warn("can't read fdisk partition table");
    853 		return (-1);
    854 	}
    855 	if (getshort(&mboot.signature) != BOOT_MAGIC) {
    856 		warnx("invalid fdisk partition table found");
    857 		/* So should we initialize things? */
    858 		return (-1);
    859 	}
    860 	return (0);
    861 }
    862 
    863 int
    864 write_s0()
    865 {
    866 	int flag;
    867 
    868 	/*
    869 	 * write enable label sector before write (if necessary),
    870 	 * disable after writing.
    871 	 * needed if the disklabel protected area also protects
    872 	 * sector 0. (e.g. empty disk)
    873 	 */
    874 	flag = 1;
    875 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    876 		warn("DIOCWLABEL");
    877 	if (write_disk(0, mboot.bootinst) == -1) {
    878 		warn("can't write fdisk partition table");
    879 		return -1;
    880 	}
    881 	flag = 0;
    882 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    883 		warn("DIOCWLABEL");
    884 }
    885 
    886 int
    887 yesno(str)
    888 	char *str;
    889 {
    890 	int ch, first;
    891 
    892 	printf("%s [n] ", str);
    893 
    894 	first = ch = getchar();
    895 	while (ch != '\n' && ch != EOF)
    896 		ch = getchar();
    897 	return (first == 'y' || first == 'Y');
    898 }
    899 
    900 void
    901 decimal(str, num)
    902 	char *str;
    903 	int *num;
    904 {
    905 	int acc = 0;
    906 	char *cp;
    907 
    908 	for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
    909 		printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
    910 
    911 		fgets(lbuf, LBUF, stdin);
    912 		lbuf[strlen(lbuf)-1] = '\0';
    913 		cp = lbuf;
    914 
    915 		cp += strspn(cp, " \t");
    916 		if (*cp == '\0')
    917 			return;
    918 
    919 		if (!isdigit(*cp))
    920 			continue;
    921 		acc = strtol(lbuf, &cp, 10);
    922 
    923 		cp += strspn(cp, " \t");
    924 		if (*cp != '\0')
    925 			continue;
    926 
    927 		*num = acc;
    928 		return;
    929 	}
    930 
    931 }
    932 
    933 int
    934 type_match(key, item)
    935 	const void *key, *item;
    936 {
    937 	const int *typep = key;
    938 	const struct part_type *ptr = item;
    939 
    940 	if (*typep < ptr->type)
    941 		return (-1);
    942 	if (*typep > ptr->type)
    943 		return (1);
    944 	return (0);
    945 }
    946 
    947 char *
    948 get_type(type)
    949 	int type;
    950 {
    951 	struct part_type *ptr;
    952 
    953 	ptr = bsearch(&type, part_types,
    954 	    sizeof(part_types) / sizeof(struct part_type),
    955 	    sizeof(struct part_type), type_match);
    956 	if (ptr == 0)
    957 		return ("unknown");
    958 	else
    959 		return (ptr->name);
    960 }
    961