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