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