Home | History | Annotate | Line # | Download | only in fdisk
fdisk.c revision 1.28
      1 /*	$NetBSD: fdisk.c,v 1.28 1998/09/28 15:44:18 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.28 1998/09/28 15:44:18 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 		partp->dp_typ = csysid;
    671 #if 0
    672 		checkcyl(cstart / dos_cylindersectors);
    673 #endif
    674 		putlong(&partp->dp_start, cstart);
    675 		putlong(&partp->dp_size, csize);
    676 		dos(getlong(&partp->dp_start),
    677 		    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    678 		dos(getlong(&partp->dp_start)
    679 		    + getlong(&partp->dp_size) - 1,
    680 		    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    681 		if (f_flag)
    682 			return;
    683 	}
    684 
    685 	printf("The data for partition %d is:\n", part);
    686 	print_part(part);
    687 	if (!u_flag || !yesno("Do you want to change it?"))
    688 		return;
    689 
    690 	do {
    691 		{
    692 			int sysid, start, size;
    693 
    694 			sysid = partp->dp_typ,
    695 			start = getlong(&partp->dp_start),
    696 			size = getlong(&partp->dp_size);
    697 			decimal("sysid", &sysid);
    698 			decimal("start", &start);
    699 			decimal("size", &size);
    700 			partp->dp_typ = sysid;
    701 			putlong(&partp->dp_start, start);
    702 			putlong(&partp->dp_size, size);
    703 		}
    704 
    705 		if (yesno("Explicitly specify beg/end address?")) {
    706 			int tsector, tcylinder, thead;
    707 
    708 			tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
    709 			thead = partp->dp_shd;
    710 			tsector = DPSECT(partp->dp_ssect);
    711 			decimal("beginning cylinder", &tcylinder);
    712 #if 0
    713 			checkcyl(tcylinder);
    714 #endif
    715 			decimal("beginning head", &thead);
    716 			decimal("beginning sector", &tsector);
    717 			partp->dp_scyl = DOSCYL(tcylinder);
    718 			partp->dp_shd = thead;
    719 			partp->dp_ssect = DOSSECT(tsector, tcylinder);
    720 
    721 			tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
    722 			thead = partp->dp_ehd;
    723 			tsector = DPSECT(partp->dp_esect);
    724 			decimal("ending cylinder", &tcylinder);
    725 			decimal("ending head", &thead);
    726 			decimal("ending sector", &tsector);
    727 			partp->dp_ecyl = DOSCYL(tcylinder);
    728 			partp->dp_ehd = thead;
    729 			partp->dp_esect = DOSSECT(tsector, tcylinder);
    730 		} else {
    731 
    732 #if 0
    733 			checkcyl(getlong(&partp->dp_start) / dos_cylindersectors);
    734 #endif
    735 			dos(getlong(&partp->dp_start),
    736 			    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    737 			dos(getlong(&partp->dp_start)
    738 			    + getlong(&partp->dp_size) - 1,
    739 			    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    740 		}
    741 
    742 		print_part(part);
    743 	} while (!yesno("Is this entry okay?"));
    744 }
    745 
    746 void
    747 print_params()
    748 {
    749 
    750 	if (sh_flag) {
    751 		printf ("DLCYL=%d\nDLHEAD=%d\nDLSEC=%d\n",
    752 			cylinders, heads, sectors);
    753 		printf ("BCYL=%d\nBHEAD=%d\nBSEC=%d\n",
    754 			dos_cylinders, dos_heads, dos_sectors);
    755 		return;
    756 	}
    757 
    758 	/* Not sh_flag */
    759 	printf("parameters extracted from in-core disklabel are:\n");
    760 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    761 	    cylinders, heads, sectors, cylindersectors);
    762 	if (dos_sectors > 63 || dos_heads > 255)
    763 		printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
    764 	printf("parameters to be used for BIOS calculations are:\n");
    765 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    766 	    dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
    767 }
    768 
    769 void
    770 change_active(which)
    771 	int which;
    772 {
    773 	struct dos_partition *partp;
    774 	int part;
    775 	int active = 4;
    776 
    777 	partp = &mboot.parts[0];
    778 
    779 	if (a_flag && which != -1)
    780 		active = which;
    781 	else {
    782 		for (part = 0; part < NDOSPART; part++)
    783 			if (partp[part].dp_flag & ACTIVE)
    784 				active = part;
    785 	}
    786 	if (!f_flag) {
    787 		if (yesno("Do you want to change the active partition?")) {
    788 			printf ("Choosing 4 will make no partition active.\n");
    789 			do {
    790 				decimal("active partition", &active);
    791 			} while (!yesno("Are you happy with this choice?"));
    792 		} else
    793 			return;
    794 	} else
    795 		if (active != 4)
    796 			printf ("Making partition %d active.\n", active);
    797 
    798 	for (part = 0; part < NDOSPART; part++)
    799 		partp[part].dp_flag &= ~ACTIVE;
    800 	if (active < 4)
    801 		partp[active].dp_flag |= ACTIVE;
    802 }
    803 
    804 void
    805 get_params_to_use()
    806 {
    807 	if (b_flag) {
    808 		dos_cylinders = b_cyl;
    809 		dos_heads = b_head;
    810 		dos_sectors = b_sec;
    811 		dos_cylindersectors = dos_heads * dos_sectors;
    812 		return;
    813 	}
    814 
    815 	print_params();
    816 	if (yesno("Do you want to change our idea of what BIOS thinks?")) {
    817 		do {
    818 			decimal("BIOS's idea of #cylinders", &dos_cylinders);
    819 			decimal("BIOS's idea of #heads", &dos_heads);
    820 			decimal("BIOS's idea of #sectors", &dos_sectors);
    821 			dos_cylindersectors = dos_heads * dos_sectors;
    822 			print_params();
    823 		} while (!yesno("Are you happy with this choice?"));
    824 	}
    825 }
    826 
    827 /***********************************************\
    828 * Change real numbers into strange dos numbers	*
    829 \***********************************************/
    830 void
    831 dos(sector, cylinderp, headp, sectorp)
    832 	int sector;
    833 	unsigned char *cylinderp, *headp, *sectorp;
    834 {
    835 	int cylinder, head;
    836 
    837 	cylinder = sector / dos_cylindersectors;
    838 
    839 	sector -= cylinder * dos_cylindersectors;
    840 
    841 	head = sector / dos_sectors;
    842 	sector -= head * dos_sectors;
    843 
    844 	if (cylinder >= MAXCYL)
    845 		cylinder = MAXCYL - 1;
    846 	*cylinderp = DOSCYL(cylinder);
    847 	*headp = head;
    848 	*sectorp = DOSSECT(sector + 1, cylinder);
    849 }
    850 
    851 #if 0
    852 void
    853 checkcyl(cyl)
    854 	int cyl;
    855 {
    856 	if (cyl >= MAXCYL)
    857 		warnx("partition start beyond BIOS limit");
    858 }
    859 #endif
    860 
    861 int fd;
    862 
    863 int
    864 open_disk(u_flag)
    865 	int u_flag;
    866 {
    867 	static char namebuf[MAXPATHLEN + 1];
    868 	struct stat st;
    869 
    870 	fd = opendisk(disk, u_flag ? O_RDWR : O_RDONLY, namebuf,
    871 	    sizeof(namebuf), 0);
    872 	if (fd < 0) {
    873 		warn("%s", namebuf);
    874 		return (-1);
    875 	}
    876 	disk = namebuf;
    877 	if (fstat(fd, &st) == -1) {
    878 		close(fd);
    879 		warn("%s", disk);
    880 		return (-1);
    881 	}
    882 	if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
    883 		close(fd);
    884 		warnx("%s is not a character device or regular file", disk);
    885 		return (-1);
    886 	}
    887 	if (get_params() == -1) {
    888 		close(fd);
    889 		return (-1);
    890 	}
    891 	return (0);
    892 }
    893 
    894 int
    895 read_disk(sector, buf)
    896 	int sector;
    897 	void *buf;
    898 {
    899 
    900 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    901 		return (-1);
    902 	return (read(fd, buf, 512));
    903 }
    904 
    905 int
    906 write_disk(sector, buf)
    907 	int sector;
    908 	void *buf;
    909 {
    910 
    911 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    912 		return (-1);
    913 	return (write(fd, buf, 512));
    914 }
    915 
    916 int
    917 get_params()
    918 {
    919 
    920 	if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
    921 		warn("DIOCGDINFO");
    922 		return (-1);
    923 	}
    924 
    925 	dos_cylinders = cylinders = disklabel.d_ncylinders;
    926 	dos_heads = heads = disklabel.d_ntracks;
    927 	dos_sectors = sectors = disklabel.d_nsectors;
    928 	dos_cylindersectors = cylindersectors = heads * sectors;
    929 	disksectors = cylinders * heads * sectors;
    930 
    931 	return (0);
    932 }
    933 
    934 int
    935 read_s0()
    936 {
    937 
    938 	if (read_disk(0, mboot.bootinst) == -1) {
    939 		warn("can't read fdisk partition table");
    940 		return (-1);
    941 	}
    942 	if (getshort(&mboot.signature) != BOOT_MAGIC) {
    943 		warnx("invalid fdisk partition table found");
    944 		return (-1);
    945 	}
    946 	return (0);
    947 }
    948 
    949 int
    950 write_s0()
    951 {
    952 	int flag;
    953 
    954 	/*
    955 	 * write enable label sector before write (if necessary),
    956 	 * disable after writing.
    957 	 * needed if the disklabel protected area also protects
    958 	 * sector 0. (e.g. empty disk)
    959 	 */
    960 	flag = 1;
    961 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    962 		warn("DIOCWLABEL");
    963 	if (write_disk(0, mboot.bootinst) == -1) {
    964 		warn("can't write fdisk partition table");
    965 		return -1;
    966 	}
    967 	flag = 0;
    968 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    969 		warn("DIOCWLABEL");
    970 	return 0;
    971 }
    972 
    973 int
    974 yesno(str)
    975 	char *str;
    976 {
    977 	int ch, first;
    978 
    979 	printf("%s [n] ", str);
    980 
    981 	first = ch = getchar();
    982 	while (ch != '\n' && ch != EOF)
    983 		ch = getchar();
    984 	return (first == 'y' || first == 'Y');
    985 }
    986 
    987 void
    988 decimal(str, num)
    989 	char *str;
    990 	int *num;
    991 {
    992 	int acc = 0;
    993 	char *cp;
    994 
    995 	for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
    996 		printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
    997 
    998 		fgets(lbuf, LBUF, stdin);
    999 		lbuf[strlen(lbuf)-1] = '\0';
   1000 		cp = lbuf;
   1001 
   1002 		cp += strspn(cp, " \t");
   1003 		if (*cp == '\0')
   1004 			return;
   1005 
   1006 		if (!isdigit(*cp))
   1007 			continue;
   1008 		acc = strtol(lbuf, &cp, 10);
   1009 
   1010 		cp += strspn(cp, " \t");
   1011 		if (*cp != '\0')
   1012 			continue;
   1013 
   1014 		*num = acc;
   1015 		return;
   1016 	}
   1017 
   1018 }
   1019 
   1020 int
   1021 type_match(key, item)
   1022 	const void *key, *item;
   1023 {
   1024 	const int *typep = key;
   1025 	const struct part_type *ptr = item;
   1026 
   1027 	if (*typep < ptr->type)
   1028 		return (-1);
   1029 	if (*typep > ptr->type)
   1030 		return (1);
   1031 	return (0);
   1032 }
   1033 
   1034 char *
   1035 get_type(type)
   1036 	int type;
   1037 {
   1038 	struct part_type *ptr;
   1039 
   1040 	ptr = bsearch(&type, part_types,
   1041 	    sizeof(part_types) / sizeof(struct part_type),
   1042 	    sizeof(struct part_type), type_match);
   1043 	if (ptr == 0)
   1044 		return ("unknown");
   1045 	return (ptr->name);
   1046 }
   1047