Home | History | Annotate | Line # | Download | only in fdisk
fdisk.c revision 1.24
      1 /*	$NetBSD: fdisk.c,v 1.24 1998/02/07 16:19:16 ghudson Exp $	*/
      2 
      3 /*
      4  * Mach Operating System
      5  * Copyright (c) 1992 Carnegie Mellon University
      6  * All Rights Reserved.
      7  *
      8  * Permission to use, copy, modify and distribute this software and its
      9  * documentation is hereby granted, provided that both the copyright
     10  * notice and this permission notice appear in all copies of the
     11  * software, derivative works or modified versions, and any portions
     12  * thereof, and that both notices appear in supporting documentation.
     13  *
     14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  *
     18  * Carnegie Mellon requests users of this software to return to
     19  *
     20  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  *  School of Computer Science
     22  *  Carnegie Mellon University
     23  *  Pittsburgh PA 15213-3890
     24  *
     25  * any improvements or extensions that they make and grant Carnegie Mellon
     26  * the rights to redistribute these changes.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 
     31 #ifndef lint
     32 __RCSID("$NetBSD: fdisk.c,v 1.24 1998/02/07 16:19:16 ghudson 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 	if (!sh_flag)
    518 		printf ("DOS partition table initialized.\n");
    519 }
    520 
    521 /* Prerequisite: the disklabel parameters and master boot record must
    522  *		 have been read (i.e. dos_* and mboot are meaningful).
    523  * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and
    524  *		  dos_cylindersectors to be consistent with what the
    525  *		  partition table is using, if we can find a geometry
    526  *		  which is consistent with all partition table entries.
    527  *		  We may get the number of cylinders slightly wrong (in
    528  *		  the conservative direction).  The idea is to be able
    529  *		  to create a NetBSD partition on a disk we don't know
    530  *		  the translated geometry of.
    531  * This whole routine should be replaced with a kernel interface to get
    532  * the BIOS geometry (which in turn requires modifications to the i386
    533  * boot loader to pass in the BIOS geometry for each disk). */
    534 void
    535 intuit_translated_geometry()
    536 {
    537 
    538 	int cylinders = -1, heads = -1, sectors = -1, i, j;
    539 	int c1, h1, s1, c2, h2, s2;
    540 	long a1, a2;
    541 	quad_t num, denom;
    542 
    543 	/* Try to deduce the number of heads from two different mappings. */
    544 	for (i = 0; i < NDOSPART * 2; i++) {
    545 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    546 			continue;
    547 		for (j = 0; j < 8; j++) {
    548 			if (get_mapping(j, &c2, &h2, &s2, &a2) < 0)
    549 				continue;
    550 			num = (quad_t)h1*(a2-s2) - (quad_t)h2*(a1-s1);
    551 			denom = (quad_t)c2*(a1-s1) - (quad_t)c1*(a2-s2);
    552 			if (denom != 0 && num % denom == 0) {
    553 				heads = num / denom;
    554 				break;
    555 			}
    556 		}
    557 		if (heads != -1)
    558 			break;
    559 	}
    560 
    561 	if (heads == -1)
    562 		return;
    563 
    564 	/* Now figure out the number of sectors from a single mapping. */
    565 	for (i = 0; i < NDOSPART * 2; i++) {
    566 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    567 			continue;
    568 		num = a1 - s1;
    569 		denom = c1 * heads + h1;
    570 		if (denom != 0 && num % denom == 0) {
    571 			sectors = num / denom;
    572 			break;
    573 		}
    574 	}
    575 
    576 	if (sectors == -1)
    577 		return;
    578 
    579 	/* Estimate the number of cylinders. */
    580 	cylinders = disklabel.d_secperunit / heads / sectors;
    581 
    582 	/* Now verify consistency with each of the partition table entries.
    583 	 * Be willing to shove cylinders up a little bit to make things work,
    584 	 * but translation mismatches are fatal. */
    585 	for (i = 0; i < NDOSPART * 2; i++) {
    586 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    587 			continue;
    588 		if (sectors * (c1 * heads + h1) + s1 != a1)
    589 			return;
    590 		if (c1 >= cylinders)
    591 			cylinders = c1 + 1;
    592 	}
    593 
    594 	/* Everything checks out.  Reset the geometry to use for further
    595 	 * calculations. */
    596 	dos_cylinders = cylinders;
    597 	dos_heads = heads;
    598 	dos_sectors = sectors;
    599 	dos_cylindersectors = heads * sectors;
    600 }
    601 
    602 /* For the purposes of intuit_translated_geometry(), treat the partition
    603  * table as a list of eight mapping between (cylinder, head, sector)
    604  * triplets and absolute sectors.  Get the relevant geometry triplet and
    605  * absolute sectors for a given entry, or return -1 if it isn't present.
    606  * Note: for simplicity, the returned sector is 0-based. */
    607 int
    608 get_mapping(i, cylinder, head, sector, absolute)
    609 	int i, *cylinder, *head, *sector;
    610 	long *absolute;
    611 {
    612 	struct dos_partition *part = &mboot.parts[i / 2];
    613 
    614 	if (part->dp_typ == 0)
    615 		return -1;
    616 	if (i % 2 == 0) {
    617 		*cylinder = DPCYL(part->dp_scyl, part->dp_ssect);
    618 		*head = part->dp_shd;
    619 		*sector = DPSECT(part->dp_ssect) - 1;
    620 		*absolute = getlong(&part->dp_start);
    621 	} else {
    622 		*cylinder = DPCYL(part->dp_ecyl, part->dp_esect);
    623 		*head = part->dp_ehd;
    624 		*sector = DPSECT(part->dp_esect) - 1;
    625 		*absolute = getlong(&part->dp_start)
    626 		    + getlong(&part->dp_size) - 1;
    627 	}
    628 	return 0;
    629 }
    630 
    631 void
    632 change_part(part, csysid, cstart, csize)
    633 	int part, csysid, cstart, csize;
    634 {
    635 	struct dos_partition *partp;
    636 
    637 	partp = &mboot.parts[part];
    638 
    639 	if (s_flag) {
    640 		partp->dp_typ = csysid;
    641 		putlong(&partp->dp_start, cstart);
    642 		putlong(&partp->dp_size, csize);
    643 		dos(getlong(&partp->dp_start),
    644 		    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    645 		dos(getlong(&partp->dp_start)
    646 		    + getlong(&partp->dp_size) - 1,
    647 		    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    648 		if (f_flag)
    649 			return;
    650 	}
    651 
    652 	printf("The data for partition %d is:\n", part);
    653 	print_part(part);
    654 	if (!u_flag || !yesno("Do you want to change it?"))
    655 		return;
    656 
    657 	do {
    658 		{
    659 			int sysid, start, size;
    660 
    661 			sysid = partp->dp_typ,
    662 			start = getlong(&partp->dp_start),
    663 			size = getlong(&partp->dp_size);
    664 			decimal("sysid", &sysid);
    665 			decimal("start", &start);
    666 			decimal("size", &size);
    667 			partp->dp_typ = sysid;
    668 			putlong(&partp->dp_start, start);
    669 			putlong(&partp->dp_size, size);
    670 		}
    671 
    672 		if (yesno("Explicitly specify beg/end address?")) {
    673 			int tsector, tcylinder, thead;
    674 
    675 			tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
    676 			thead = partp->dp_shd;
    677 			tsector = DPSECT(partp->dp_ssect);
    678 			decimal("beginning cylinder", &tcylinder);
    679 			decimal("beginning head", &thead);
    680 			decimal("beginning sector", &tsector);
    681 			partp->dp_scyl = DOSCYL(tcylinder);
    682 			partp->dp_shd = thead;
    683 			partp->dp_ssect = DOSSECT(tsector, tcylinder);
    684 
    685 			tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
    686 			thead = partp->dp_ehd;
    687 			tsector = DPSECT(partp->dp_esect);
    688 			decimal("ending cylinder", &tcylinder);
    689 			decimal("ending head", &thead);
    690 			decimal("ending sector", &tsector);
    691 			partp->dp_ecyl = DOSCYL(tcylinder);
    692 			partp->dp_ehd = thead;
    693 			partp->dp_esect = DOSSECT(tsector, tcylinder);
    694 		} else {
    695 			dos(getlong(&partp->dp_start),
    696 			    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    697 			dos(getlong(&partp->dp_start)
    698 			    + getlong(&partp->dp_size) - 1,
    699 			    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    700 		}
    701 
    702 		print_part(part);
    703 	} while (!yesno("Is this entry okay?"));
    704 }
    705 
    706 void
    707 print_params()
    708 {
    709 
    710 	if (sh_flag) {
    711 		printf ("DLCYL=%d\nDLHEAD=%d\nDLSEC=%d\n",
    712 			cylinders, heads, sectors);
    713 		printf ("BCYL=%d\nBHEAD=%d\nBSEC=%d\n",
    714 			dos_cylinders, dos_heads, dos_sectors);
    715 		return;
    716 	}
    717 
    718 	/* Not sh_flag */
    719 	printf("parameters extracted from in-core disklabel are:\n");
    720 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    721 	    cylinders, heads, sectors, cylindersectors);
    722 	if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255)
    723 		printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
    724 	printf("parameters to be used for BIOS calculations are:\n");
    725 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    726 	    dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
    727 }
    728 
    729 void
    730 change_active(which)
    731 	int which;
    732 {
    733 	struct dos_partition *partp;
    734 	int part;
    735 	int active = 4;
    736 
    737 	partp = &mboot.parts[0];
    738 
    739 	if (a_flag && which != -1)
    740 		active = which;
    741 	else {
    742 		for (part = 0; part < NDOSPART; part++)
    743 			if (partp[part].dp_flag & ACTIVE)
    744 				active = part;
    745 	}
    746 	if (!f_flag) {
    747 		if (yesno("Do you want to change the active partition?")) {
    748 			printf ("Choosing 4 will make no partition active.\n");
    749 			do {
    750 				decimal("active partition", &active);
    751 			} while (!yesno("Are you happy with this choice?"));
    752 		} else
    753 			return;
    754 	} else
    755 		if (active != 4)
    756 			printf ("Making partition %d active.\n", active);
    757 
    758 	for (part = 0; part < NDOSPART; part++)
    759 		partp[part].dp_flag &= ~ACTIVE;
    760 	if (active < 4)
    761 		partp[active].dp_flag |= ACTIVE;
    762 }
    763 
    764 void
    765 get_params_to_use()
    766 {
    767 	if (b_flag) {
    768 		dos_cylinders = b_cyl;
    769 		dos_heads = b_head;
    770 		dos_sectors = b_sec;
    771 		dos_cylindersectors = dos_heads * dos_sectors;
    772 		return;
    773 	}
    774 
    775 	print_params();
    776 	if (yesno("Do you want to change our idea of what BIOS thinks?")) {
    777 		do {
    778 			decimal("BIOS's idea of #cylinders", &dos_cylinders);
    779 			decimal("BIOS's idea of #heads", &dos_heads);
    780 			decimal("BIOS's idea of #sectors", &dos_sectors);
    781 			dos_cylindersectors = dos_heads * dos_sectors;
    782 			print_params();
    783 		} while (!yesno("Are you happy with this choice?"));
    784 	}
    785 }
    786 
    787 /***********************************************\
    788 * Change real numbers into strange dos numbers	*
    789 \***********************************************/
    790 void
    791 dos(sector, cylinderp, headp, sectorp)
    792 	int sector;
    793 	unsigned char *cylinderp, *headp, *sectorp;
    794 {
    795 	int cylinder, head;
    796 
    797 	cylinder = sector / dos_cylindersectors;
    798 	sector -= cylinder * dos_cylindersectors;
    799 
    800 	head = sector / dos_sectors;
    801 	sector -= head * dos_sectors;
    802 
    803 	*cylinderp = DOSCYL(cylinder);
    804 	*headp = head;
    805 	*sectorp = DOSSECT(sector + 1, cylinder);
    806 }
    807 
    808 int fd;
    809 
    810 int
    811 open_disk(u_flag)
    812 	int u_flag;
    813 {
    814 	static char namebuf[MAXPATHLEN + 1];
    815 	struct stat st;
    816 
    817 	fd = opendisk(disk, u_flag ? O_RDWR : O_RDONLY, namebuf,
    818 	    sizeof(namebuf), 0);
    819 	if (fd < 0) {
    820 		warn("%s", namebuf);
    821 		return (-1);
    822 	}
    823 	disk = namebuf;
    824 	if (fstat(fd, &st) == -1) {
    825 		close(fd);
    826 		warn("%s", disk);
    827 		return (-1);
    828 	}
    829 	if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
    830 		close(fd);
    831 		warnx("%s is not a character device or regular file", disk);
    832 		return (-1);
    833 	}
    834 	if (get_params() == -1) {
    835 		close(fd);
    836 		return (-1);
    837 	}
    838 	return (0);
    839 }
    840 
    841 int
    842 read_disk(sector, buf)
    843 	int sector;
    844 	void *buf;
    845 {
    846 
    847 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    848 		return (-1);
    849 	return (read(fd, buf, 512));
    850 }
    851 
    852 int
    853 write_disk(sector, buf)
    854 	int sector;
    855 	void *buf;
    856 {
    857 
    858 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    859 		return (-1);
    860 	return (write(fd, buf, 512));
    861 }
    862 
    863 int
    864 get_params()
    865 {
    866 
    867 	if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
    868 		warn("DIOCGDINFO");
    869 		return (-1);
    870 	}
    871 
    872 	dos_cylinders = cylinders = disklabel.d_ncylinders;
    873 	dos_heads = heads = disklabel.d_ntracks;
    874 	dos_sectors = sectors = disklabel.d_nsectors;
    875 	dos_cylindersectors = cylindersectors = heads * sectors;
    876 	disksectors = cylinders * heads * sectors;
    877 
    878 	return (0);
    879 }
    880 
    881 int
    882 read_s0()
    883 {
    884 
    885 	if (read_disk(0, mboot.bootinst) == -1) {
    886 		warn("can't read fdisk partition table");
    887 		return (-1);
    888 	}
    889 	if (getshort(&mboot.signature) != BOOT_MAGIC) {
    890 		warnx("invalid fdisk partition table found");
    891 		/* So should we initialize things? */
    892 		return (-1);
    893 	}
    894 	return (0);
    895 }
    896 
    897 int
    898 write_s0()
    899 {
    900 	int flag;
    901 
    902 	/*
    903 	 * write enable label sector before write (if necessary),
    904 	 * disable after writing.
    905 	 * needed if the disklabel protected area also protects
    906 	 * sector 0. (e.g. empty disk)
    907 	 */
    908 	flag = 1;
    909 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    910 		warn("DIOCWLABEL");
    911 	if (write_disk(0, mboot.bootinst) == -1) {
    912 		warn("can't write fdisk partition table");
    913 		return -1;
    914 	}
    915 	flag = 0;
    916 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    917 		warn("DIOCWLABEL");
    918 	return 0;
    919 }
    920 
    921 int
    922 yesno(str)
    923 	char *str;
    924 {
    925 	int ch, first;
    926 
    927 	printf("%s [n] ", str);
    928 
    929 	first = ch = getchar();
    930 	while (ch != '\n' && ch != EOF)
    931 		ch = getchar();
    932 	return (first == 'y' || first == 'Y');
    933 }
    934 
    935 void
    936 decimal(str, num)
    937 	char *str;
    938 	int *num;
    939 {
    940 	int acc = 0;
    941 	char *cp;
    942 
    943 	for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
    944 		printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
    945 
    946 		fgets(lbuf, LBUF, stdin);
    947 		lbuf[strlen(lbuf)-1] = '\0';
    948 		cp = lbuf;
    949 
    950 		cp += strspn(cp, " \t");
    951 		if (*cp == '\0')
    952 			return;
    953 
    954 		if (!isdigit(*cp))
    955 			continue;
    956 		acc = strtol(lbuf, &cp, 10);
    957 
    958 		cp += strspn(cp, " \t");
    959 		if (*cp != '\0')
    960 			continue;
    961 
    962 		*num = acc;
    963 		return;
    964 	}
    965 
    966 }
    967 
    968 int
    969 type_match(key, item)
    970 	const void *key, *item;
    971 {
    972 	const int *typep = key;
    973 	const struct part_type *ptr = item;
    974 
    975 	if (*typep < ptr->type)
    976 		return (-1);
    977 	if (*typep > ptr->type)
    978 		return (1);
    979 	return (0);
    980 }
    981 
    982 char *
    983 get_type(type)
    984 	int type;
    985 {
    986 	struct part_type *ptr;
    987 
    988 	ptr = bsearch(&type, part_types,
    989 	    sizeof(part_types) / sizeof(struct part_type),
    990 	    sizeof(struct part_type), type_match);
    991 	if (ptr == 0)
    992 		return ("unknown");
    993 	return (ptr->name);
    994 }
    995