Home | History | Annotate | Line # | Download | only in fdisk
fdisk.c revision 1.25
      1 /*	$NetBSD: fdisk.c,v 1.25 1998/02/19 14:47:43 drochner 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.25 1998/02/19 14:47:43 drochner 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_386BSD;
    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 	*cylinderp = DOSCYL(cylinder);
    845 	*headp = head;
    846 	*sectorp = DOSSECT(sector + 1, cylinder);
    847 }
    848 
    849 int fd;
    850 
    851 int
    852 open_disk(u_flag)
    853 	int u_flag;
    854 {
    855 	static char namebuf[MAXPATHLEN + 1];
    856 	struct stat st;
    857 
    858 	fd = opendisk(disk, u_flag ? O_RDWR : O_RDONLY, namebuf,
    859 	    sizeof(namebuf), 0);
    860 	if (fd < 0) {
    861 		warn("%s", namebuf);
    862 		return (-1);
    863 	}
    864 	disk = namebuf;
    865 	if (fstat(fd, &st) == -1) {
    866 		close(fd);
    867 		warn("%s", disk);
    868 		return (-1);
    869 	}
    870 	if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
    871 		close(fd);
    872 		warnx("%s is not a character device or regular file", disk);
    873 		return (-1);
    874 	}
    875 	if (get_params() == -1) {
    876 		close(fd);
    877 		return (-1);
    878 	}
    879 	return (0);
    880 }
    881 
    882 int
    883 read_disk(sector, buf)
    884 	int sector;
    885 	void *buf;
    886 {
    887 
    888 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    889 		return (-1);
    890 	return (read(fd, buf, 512));
    891 }
    892 
    893 int
    894 write_disk(sector, buf)
    895 	int sector;
    896 	void *buf;
    897 {
    898 
    899 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    900 		return (-1);
    901 	return (write(fd, buf, 512));
    902 }
    903 
    904 int
    905 get_params()
    906 {
    907 
    908 	if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
    909 		warn("DIOCGDINFO");
    910 		return (-1);
    911 	}
    912 
    913 	dos_cylinders = cylinders = disklabel.d_ncylinders;
    914 	dos_heads = heads = disklabel.d_ntracks;
    915 	dos_sectors = sectors = disklabel.d_nsectors;
    916 	dos_cylindersectors = cylindersectors = heads * sectors;
    917 	disksectors = cylinders * heads * sectors;
    918 
    919 	return (0);
    920 }
    921 
    922 int
    923 read_s0()
    924 {
    925 
    926 	if (read_disk(0, mboot.bootinst) == -1) {
    927 		warn("can't read fdisk partition table");
    928 		return (-1);
    929 	}
    930 	if (getshort(&mboot.signature) != BOOT_MAGIC) {
    931 		warnx("invalid fdisk partition table found");
    932 		/* So should we initialize things? */
    933 		return (-1);
    934 	}
    935 	return (0);
    936 }
    937 
    938 int
    939 write_s0()
    940 {
    941 	int flag;
    942 
    943 	/*
    944 	 * write enable label sector before write (if necessary),
    945 	 * disable after writing.
    946 	 * needed if the disklabel protected area also protects
    947 	 * sector 0. (e.g. empty disk)
    948 	 */
    949 	flag = 1;
    950 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    951 		warn("DIOCWLABEL");
    952 	if (write_disk(0, mboot.bootinst) == -1) {
    953 		warn("can't write fdisk partition table");
    954 		return -1;
    955 	}
    956 	flag = 0;
    957 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    958 		warn("DIOCWLABEL");
    959 	return 0;
    960 }
    961 
    962 int
    963 yesno(str)
    964 	char *str;
    965 {
    966 	int ch, first;
    967 
    968 	printf("%s [n] ", str);
    969 
    970 	first = ch = getchar();
    971 	while (ch != '\n' && ch != EOF)
    972 		ch = getchar();
    973 	return (first == 'y' || first == 'Y');
    974 }
    975 
    976 void
    977 decimal(str, num)
    978 	char *str;
    979 	int *num;
    980 {
    981 	int acc = 0;
    982 	char *cp;
    983 
    984 	for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
    985 		printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
    986 
    987 		fgets(lbuf, LBUF, stdin);
    988 		lbuf[strlen(lbuf)-1] = '\0';
    989 		cp = lbuf;
    990 
    991 		cp += strspn(cp, " \t");
    992 		if (*cp == '\0')
    993 			return;
    994 
    995 		if (!isdigit(*cp))
    996 			continue;
    997 		acc = strtol(lbuf, &cp, 10);
    998 
    999 		cp += strspn(cp, " \t");
   1000 		if (*cp != '\0')
   1001 			continue;
   1002 
   1003 		*num = acc;
   1004 		return;
   1005 	}
   1006 
   1007 }
   1008 
   1009 int
   1010 type_match(key, item)
   1011 	const void *key, *item;
   1012 {
   1013 	const int *typep = key;
   1014 	const struct part_type *ptr = item;
   1015 
   1016 	if (*typep < ptr->type)
   1017 		return (-1);
   1018 	if (*typep > ptr->type)
   1019 		return (1);
   1020 	return (0);
   1021 }
   1022 
   1023 char *
   1024 get_type(type)
   1025 	int type;
   1026 {
   1027 	struct part_type *ptr;
   1028 
   1029 	ptr = bsearch(&type, part_types,
   1030 	    sizeof(part_types) / sizeof(struct part_type),
   1031 	    sizeof(struct part_type), type_match);
   1032 	if (ptr == 0)
   1033 		return ("unknown");
   1034 	return (ptr->name);
   1035 }
   1036