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