Home | History | Annotate | Line # | Download | only in fdisk
fdisk.c revision 1.13
      1 /*	$NetBSD: fdisk.c,v 1.13 1997/06/24 06:38:50 perry 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 #ifndef lint
     30 static char rcsid[] = "$NetBSD: fdisk.c,v 1.13 1997/06/24 06:38:50 perry Exp $";
     31 #endif /* not lint */
     32 
     33 #include <sys/types.h>
     34 #include <sys/disklabel.h>
     35 #include <sys/ioctl.h>
     36 #include <sys/stat.h>
     37 
     38 #include <ctype.h>
     39 #include <err.h>
     40 #include <fcntl.h>
     41 #include <stdio.h>
     42 #include <stdlib.h>
     43 #include <string.h>
     44 #include <unistd.h>
     45 
     46 #define LBUF 100
     47 static char lbuf[LBUF];
     48 
     49 /*
     50  * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
     51  *	Copyright (c) 1989	Robert. V. Baron
     52  *	Created.
     53  */
     54 
     55 char *disk = "/dev/rwd0d";
     56 
     57 struct disklabel disklabel;		/* disk parameters */
     58 
     59 int cylinders, sectors, heads, cylindersectors, disksectors;
     60 
     61 struct mboot {
     62 	unsigned char padding[2]; /* force the longs to be long alligned */
     63 	unsigned char bootinst[DOSPARTOFF];
     64 	struct	dos_partition parts[4];
     65 	unsigned short int	signature;
     66 };
     67 struct mboot mboot;
     68 
     69 #define ACTIVE 0x80
     70 #define BOOT_MAGIC 0xAA55
     71 
     72 int dos_cylinders;
     73 int dos_heads;
     74 int dos_sectors;
     75 int dos_cylindersectors;
     76 
     77 #define DOSSECT(s,c)	(((s) & 0x3f) | (((c) >> 2) & 0xc0))
     78 #define DOSCYL(c)	((c) & 0xff)
     79 int partition = -1;
     80 
     81 int a_flag;		/* set active partition */
     82 int i_flag;		/* replace partition data */
     83 int u_flag;		/* update partition data */
     84 
     85 unsigned char bootcode[] = {
     86 0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
     87 0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
     88 0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
     89 0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
     90 0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
     91 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
     92 0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
     93 0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
     94 0xeb, 0xf4, 0xfb, 0xeb, 0xfe,
     95 'M', 'i', 's', 's', 'i', 'n', 'g', ' ',
     96 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
     97 'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ',
     98 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
     99 'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ',
    100 	'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0,
    101 'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ',
    102 	'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0,
    103 
    104   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    105   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    106   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    107   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    108   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    109   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    110   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    111   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    112   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    113   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    114   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    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
    117 };
    118 
    119 struct part_type {
    121 	int type;
    122 	char *name;
    123 } part_types[] = {
    124 	{0x00, "unused"},
    125 	{0x01, "Primary DOS with 12 bit FAT"},
    126 	{0x02, "XENIX / filesystem"},
    127 	{0x03, "XENIX /usr filesystem"},
    128 	{0x04, "Primary DOS with 16 bit FAT <32M"},
    129 	{0x05, "Extended DOS"},
    130 	{0x06, "Primary 'big' DOS, 16-bit FAT (> 32MB)"},
    131 	{0x07, "OS/2 HPFS or NTFS or QNX2 or Advanced UNIX"},
    132 	{0x08, "AIX filesystem"},
    133 	{0x09, "AIX boot partition or Coherent"},
    134 	{0x0A, "OS/2 Boot Manager or Coherent swap or OPUS"},
    135 	{0x0E, "DOS (16-bit FAT), CHS-mapped"},
    136 	{0x0F, "Ext. partition, CHS-mapped"},
    137 	{0x10, "OPUS"},
    138 	{0x11, "OS/2 BM: hidden DOS 12-bit FAT"},
    139 	{0x12, "Compaq diagnostics"},
    140 	{0x14, "OS/2 BM: hidden DOS 16-bit FAT <32M"},
    141 	{0x16, "OS/2 BM: hidden DOS 16-bit FAT >=32M"},
    142 	{0x17, "OS/2 BM: hidden IFS"},
    143 	{0x18, "AST Windows swapfile"},
    144 	{0x24, "NEC DOS"},
    145 	{0x3C, "PartitionMagic recovery"},
    146 	{0x40, "VENIX 286"},
    147 	{0x41, "Linux/MINIX (sharing disk with DRDOS)"},
    148 	{0x42, "SFS or Linux swap (sharing disk with DRDOS)"},
    149 	{0x43, "Linux native (sharing disk with DRDOS)"},
    150 	{0x50, "DM (disk manager)"},
    151 	{0x51, "DM6 Aux1 (or Novell)"},
    152 	{0x52, "CP/M or Microport SysV/AT"},
    153 	{0x53, "DM6 Aux3"},
    154 	{0x54, "DM6"},
    155 	{0x55, "EZ-Drive (disk manager)"},
    156 	{0x56, "Golden Bow (disk manager)"},
    157 	{0x5C, "Priam Edisk (disk manager)"},
    158 	{0x61, "SpeedStor"},
    159 	{0x63, "GNU HURD or Mach or Sys V/386 (such as ISC UNIX)"},
    160 	{0x64, "Novell Netware 2.xx"},
    161 	{0x65, "Novell Netware 3.xx"},
    162 	{0x70, "DiskSecure Multi-Boot"},
    163 	{0x75, "PC/IX"},
    164 	{0x77, "QNX4.x"},
    165 	{0x78, "QNX4.x 2nd part"},
    166 	{0x79, "QNX4.x 3rd part"},
    167 	{0x80, "MINIX until 1.4a"},
    168 	{0x81, "MINIX since 1.4b, early Linux, Mitac dmgr"},
    169 	{0x82, "Linux swap"},
    170 	{0x83, "Linux native"},
    171 	{0x84, "OS/2 hidden C: drive"},
    172 	{0x85, "Linux extended"},
    173 	{0x86, "NTFS volume set??"},
    174 	{0x87, "NTFS volume set??"},
    175 	{0x93, "Amoeba filesystem"},
    176 	{0x94, "Amoeba bad block table"},
    177 	{0xA0, "IBM Thinkpad hibernation"},
    178 	{0xA5, "NetBSD or FreeBSD or 386BSD"},
    179 	{0xA6, "OpenBSD"},
    180 	{0xA7, "NeXTSTEP 486"},
    181 	{0xB7, "BSDI BSD/386 filesystem"},
    182 	{0xB8, "BSDI BSD/386 swap"},
    183 	{0xC1, "DRDOS/sec (FAT-12)"},
    184 	{0xC4, "DRDOS/sec (FAT-16, < 32M)"},
    185 	{0xC6, "DRDOS/sec (FAT-16, >= 32M)"},
    186 	{0xC7, "Syrinx"},
    187 	{0xDB, "CP/M or Concurrent CP/M or Concurrent DOS or CTOS"},
    188 	{0xE1, "DOS access or SpeedStor 12-bit FAT extended partition"},
    189 	{0xE3, "DOS R/O or SpeedStor"},
    190 	{0xE4, "SpeedStor 16-bit FAT extended partition < 1024 cyl."},
    191 	{0xF1, "SpeedStor"},
    192 	{0xF2, "DOS 3.3+ Secondary"},
    193 	{0xF4, "SpeedStor large partition"},
    194 	{0xFE, "SpeedStor >1024 cyl. or LANstep"},
    195 	{0xFF, "Xenix Bad Block Table"},
    196 };
    197 
    198 void	usage __P((void));
    199 void	print_s0 __P((int));
    200 void	print_part __P((int));
    201 void	init_sector0 __P((int));
    202 void	intuit_translated_geometry __P((void));
    203 int	try_heads __P((quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, quad_t,
    204 		       quad_t));
    205 int	try_sectors __P((quad_t, quad_t, quad_t, quad_t, quad_t));
    206 void	change_part __P((int));
    207 void	print_params __P((void));
    208 void	change_active __P((int));
    209 void	get_params_to_use __P((void));
    210 void	dos __P((int, unsigned char *, unsigned char *, unsigned char *));
    211 int	open_disk __P((int));
    212 int	read_disk __P((int, void *));
    213 int	write_disk __P((int, void *));
    214 int	get_params __P((void));
    215 int	read_s0 __P((void));
    216 int	write_s0 __P((void));
    217 int	yesno __P((char *));
    218 void	decimal __P((char *, int *));
    219 int	type_match __P((const void *, const void *));
    220 char	*get_type __P((int));
    221 
    222 int
    223 main(argc, argv)
    224 	int argc;
    225 	char *argv[];
    226 {
    227 	int ch;
    228 	int part;
    229 
    230 	a_flag = i_flag = u_flag = 0;
    231 	while ((ch = getopt(argc, argv, "0123aiu")) != -1)
    232 		switch (ch) {
    233 		case '0':
    234 			partition = 0;
    235 			break;
    236 		case '1':
    237 			partition = 1;
    238 			break;
    239 		case '2':
    240 			partition = 2;
    241 			break;
    242 		case '3':
    243 			partition = 3;
    244 			break;
    245 		case 'a':
    246 			a_flag = 1;
    247 			break;
    248 		case 'i':
    249 			i_flag = 1;
    250 		case 'u':
    251 			u_flag = 1;
    252 			break;
    253 		default:
    254 			usage();
    255 		}
    256 	argc -= optind;
    257 	argv += optind;
    258 
    259 	if (argc > 0)
    260 		disk = argv[0];
    261 
    262 	if (open_disk(a_flag || i_flag || u_flag) < 0)
    263 		exit(1);
    264 
    265 	if (read_s0())
    266 		init_sector0(1);
    267 
    268 	intuit_translated_geometry();
    269 
    270 	printf("******* Working on device %s *******\n", disk);
    271 	if (u_flag)
    272 		get_params_to_use();
    273 	else
    274 		print_params();
    275 
    276 	printf("Warning: BIOS sector numbering starts with sector 1\n");
    277 	printf("Information from DOS bootblock is:\n");
    278 	if (partition == -1) {
    279 		for (part = 0; part < NDOSPART; part++)
    280 			change_part(part);
    281 	} else
    282 		change_part(partition);
    283 
    284 	if (u_flag || a_flag)
    285 		change_active(partition);
    286 
    287 	if (u_flag || a_flag) {
    288 		printf("\nWe haven't changed the partition table yet.  ");
    289 		printf("This is your last chance.\n");
    290 		print_s0(-1);
    291 		if (yesno("Should we write new partition table?"))
    292 			write_s0();
    293 	}
    294 
    295 	exit(0);
    296 }
    297 
    298 void
    299 usage()
    300 {
    301 
    302 	(void)fprintf(stderr, "usage: fdisk [-aiu] [-0|-1|-2|-3] [device]\n");
    303 	exit(1);
    304 }
    305 
    306 void
    307 print_s0(which)
    308 	int which;
    309 {
    310 	int part;
    311 
    312 	print_params();
    313 	printf("Information from DOS bootblock is:\n");
    314 	if (which == -1) {
    315 		for (part = 0; part < NDOSPART; part++)
    316 			printf("%d: ", part), print_part(part);
    317 	} else
    318 		print_part(which);
    319 }
    320 
    321 static struct dos_partition mtpart = { 0 };
    322 
    323 static inline unsigned short
    324 getshort(p)
    325 	void *p;
    326 {
    327 	unsigned char *cp = p;
    328 
    329 	return cp[0] | (cp[1] << 8);
    330 }
    331 
    332 static inline void
    333 putshort(p, l)
    334 	void *p;
    335 	unsigned short l;
    336 {
    337 	unsigned char *cp = p;
    338 
    339 	*cp++ = l;
    340 	*cp++ = l >> 8;
    341 }
    342 
    343 static inline unsigned long
    344 getlong(p)
    345 	void *p;
    346 {
    347 	unsigned char *cp = p;
    348 
    349 	return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24);
    350 }
    351 
    352 static inline void
    353 putlong(p, l)
    354 	void *p;
    355 	unsigned long l;
    356 {
    357 	unsigned char *cp = p;
    358 
    359 	*cp++ = l;
    360 	*cp++ = l >> 8;
    361 	*cp++ = l >> 16;
    362 	*cp++ = l >> 24;
    363 }
    364 
    365 void
    366 print_part(part)
    367 	int part;
    368 {
    369 	struct dos_partition *partp;
    370 
    371 	partp = &mboot.parts[part];
    372 	if (!memcmp(partp, &mtpart, sizeof(struct dos_partition))) {
    373 		printf("<UNUSED>\n");
    374 		return;
    375 	}
    376 	printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ));
    377 	printf("    start %d, size %d (%d MB), flag %x\n",
    378 	    getlong(&partp->dp_start), getlong(&partp->dp_size),
    379 	    getlong(&partp->dp_size) * 512 / (1024 * 1024), partp->dp_flag);
    380 	printf("\tbeg: cylinder %4d, head %3d, sector %2d\n",
    381 	    DPCYL(partp->dp_scyl, partp->dp_ssect),
    382 	    partp->dp_shd, DPSECT(partp->dp_ssect));
    383 	printf("\tend: cylinder %4d, head %3d, sector %2d\n",
    384 	    DPCYL(partp->dp_ecyl, partp->dp_esect),
    385 	    partp->dp_ehd, DPSECT(partp->dp_esect));
    386 }
    387 
    388 void
    389 init_sector0(start)
    390 	int start;
    391 {
    392 	struct dos_partition *partp;
    393 
    394 	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
    395 	putshort(&mboot.signature, BOOT_MAGIC);
    396 
    397 	partp = &mboot.parts[3];
    398 	partp->dp_typ = DOSPTYP_386BSD;
    399 	partp->dp_flag = ACTIVE;
    400 	putlong(&partp->dp_start, start);
    401 	putlong(&partp->dp_size, disksectors - start);
    402 
    403 	dos(getlong(&partp->dp_start),
    404 	    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    405 	dos(getlong(&partp->dp_start) + getlong(&partp->dp_size) - 1,
    406 	    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    407 }
    408 
    409 /* Prerequisite: the disklabel parameters and master boot record must
    410  *		 have been read (i.e. dos_* and mboot are meaningful).
    411  * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and
    412  *		  dos_cylindersectors to be consistent with what the
    413  *		  partition table is using, if we can find a geometry
    414  *		  which is consistent with all partition table entries.
    415  *		  We may get the number of cylinders slightly wrong (in
    416  *		  the conservative direction).  The idea is to be able
    417  *		  to create a NetBSD partition on a disk we don't know
    418  *		  the translated geometry of.
    419  * This whole routine should be replaced with a kernel interface to get
    420  * the BIOS geometry (which in turn requires modifications to the i386
    421  * boot loader to pass in the BIOS geometry for each disk). */
    422 void
    423 intuit_translated_geometry()
    424 {
    425 	int cylinders = -1, heads = -1, sectors = -1, i, j;
    426 	int c1, h1, s1, c2, h2, s2;
    427 	long a1, a2;
    428 	quad_t num, denom;
    429 
    430 	/* Try to deduce the number of heads from two different mappings. */
    431 	for (i = 0; i < NDOSPART * 2; i++) {
    432 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    433 			continue;
    434 		for (j = 0; j < 8; j++) {
    435 			if (get_mapping(j, &c2, &h2, &s2, &a2) < 0)
    436 				continue;
    437 			num = (quad_t)h1*(a2-s2) - h2*(a1-s1);
    438 			denom = (quad_t)c2*(a1-s1) - c1*(a2-s2);
    439 			if (denom != 0 && num % denom == 0) {
    440 				heads = num / denom;
    441 				break;
    442 			}
    443 		}
    444 		if (heads != -1)
    445 			break;
    446 	}
    447 
    448 	if (heads == -1)
    449 		return;
    450 
    451 	/* Now figure out the number of sectors from a single mapping. */
    452 	for (i = 0; i < NDOSPART * 2; i++) {
    453 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    454 			continue;
    455 		num = a1 - s1;
    456 		denom = c1 * heads + h1;
    457 		if (denom != 0 && num % denom == 0) {
    458 			sectors = num / denom;
    459 			break;
    460 		}
    461 	}
    462 
    463 	if (sectors == -1)
    464 		return;
    465 
    466 	/* Estimate the number of cylinders. */
    467 	cylinders = dos_cylinders * dos_cylindersectors / heads / sectors;
    468 
    469 	/* Now verify consistency with each of the partition table entries.
    470 	 * Be willing to shove cylinders up a little bit to make things work,
    471 	 * but translation mismatches are fatal. */
    472 	for (i = 0; i < NDOSPART * 2; i++) {
    473 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
    474 			continue;
    475 		if (sectors * (c1 * heads + h1) + s1 != a1)
    476 			return;
    477 		if (c1 >= cylinders)
    478 			cylinders = c1 + 1;
    479 	}
    480 
    481 	/* Everything checks out.  Reset the geometry to use for further
    482 	 * calculations. */
    483 	dos_cylinders = cylinders;
    484 	dos_heads = heads;
    485 	dos_sectors = sectors;
    486 	dos_cylindersectors = heads * sectors;
    487 }
    488 
    489 /* For the purposes of intuit_translated_geometry(), treat the partition
    490  * table as a list of eight mapping between (cylinder, head, sector)
    491  * triplets and absolute sectors.  Get the relevant geometry triplet and
    492  * absolute sectors for a given entry, or return -1 if it isn't present.
    493  * Note: for simplicity, the returned sector is 0-based. */
    494 int
    495 get_mapping(i, cylinder, head, sector, absolute)
    496 	int i, *cylinder, *head, *sector;
    497 	long *absolute;
    498 {
    499 	struct dos_partition *part = &mboot.parts[i / 2];
    500 
    501 	if (part->dp_typ == 0)
    502 		return -1;
    503 	if (i % 2 == 0) {
    504 		*cylinder = DPCYL(part->dp_scyl, part->dp_ssect);
    505 		*head = part->dp_shd;
    506 		*sector = DPSECT(part->dp_ssect) - 1;
    507 		*absolute = getlong(&part->dp_start);
    508 	} else {
    509 		*cylinder = DPCYL(part->dp_ecyl, part->dp_esect);
    510 		*head = part->dp_ehd;
    511 		*sector = DPSECT(part->dp_esect) - 1;
    512 		*absolute = getlong(&part->dp_start)
    513 		    + getlong(&part->dp_size) - 1;
    514 	}
    515 	return 0;
    516 }
    517 
    518 void
    519 change_part(part)
    520 	int part;
    521 {
    522 	struct dos_partition *partp;
    523 
    524 	partp = &mboot.parts[part];
    525 
    526 	printf("The data for partition %d is:\n", part);
    527 	print_part(part);
    528 
    529 	if (!u_flag || !yesno("Do you want to change it?"))
    530 		return;
    531 
    532 	if (i_flag) {
    533 		memset(partp, 0, sizeof(*partp));
    534 		if (part == 3) {
    535 			init_sector0(1);
    536 			printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
    537 			print_part(part);
    538 		}
    539 	}
    540 
    541 	do {
    542 		{
    543 			int sysid, start, size;
    544 
    545 			sysid = partp->dp_typ,
    546 			start = getlong(&partp->dp_start),
    547 			size = getlong(&partp->dp_size);
    548 			decimal("sysid", &sysid);
    549 			decimal("start", &start);
    550 			decimal("size", &size);
    551 			partp->dp_typ = sysid;
    552 			putlong(&partp->dp_start, start);
    553 			putlong(&partp->dp_size, size);
    554 		}
    555 
    556 		if (yesno("Explicitly specify beg/end address?")) {
    557 			int tsector, tcylinder, thead;
    558 
    559 			tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
    560 			thead = partp->dp_shd;
    561 			tsector = DPSECT(partp->dp_ssect);
    562 			decimal("beginning cylinder", &tcylinder);
    563 			decimal("beginning head", &thead);
    564 			decimal("beginning sector", &tsector);
    565 			partp->dp_scyl = DOSCYL(tcylinder);
    566 			partp->dp_shd = thead;
    567 			partp->dp_ssect = DOSSECT(tsector, tcylinder);
    568 
    569 			tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
    570 			thead = partp->dp_ehd;
    571 			tsector = DPSECT(partp->dp_esect);
    572 			decimal("ending cylinder", &tcylinder);
    573 			decimal("ending head", &thead);
    574 			decimal("ending sector", &tsector);
    575 			partp->dp_ecyl = DOSCYL(tcylinder);
    576 			partp->dp_ehd = thead;
    577 			partp->dp_esect = DOSSECT(tsector, tcylinder);
    578 		} else {
    579 			dos(getlong(&partp->dp_start),
    580 			    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
    581 			dos(getlong(&partp->dp_start)
    582 			    + getlong(&partp->dp_size) - 1,
    583 			    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
    584 		}
    585 
    586 		print_part(part);
    587 	} while (!yesno("Is this entry okay?"));
    588 }
    589 
    590 void
    591 print_params()
    592 {
    593 
    594 	printf("parameters extracted from in-core disklabel are:\n");
    595 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    596 	    cylinders, heads, sectors, cylindersectors);
    597 	if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255)
    598 		printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
    599 	printf("parameters to be used for BIOS calculations are:\n");
    600 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
    601 	    dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
    602 }
    603 
    604 void
    605 change_active(which)
    606 	int which;
    607 {
    608 	struct dos_partition *partp;
    609 	int part;
    610 	int active = 3;
    611 
    612 	partp = &mboot.parts[0];
    613 
    614 	if (a_flag && which != -1)
    615 		active = which;
    616 	else {
    617 		for (part = 0; part < NDOSPART; part++)
    618 			if (partp[part].dp_flag & ACTIVE)
    619 				active = part;
    620 	}
    621 	if (yesno("Do you want to change the active partition?")) {
    622 		do {
    623 			decimal("active partition", &active);
    624 		} while (!yesno("Are you happy with this choice?"));
    625 	}
    626 	for (part = 0; part < NDOSPART; part++)
    627 		partp[part].dp_flag &= ~ACTIVE;
    628 	partp[active].dp_flag |= ACTIVE;
    629 }
    630 
    631 void
    632 get_params_to_use()
    633 {
    634 
    635 	print_params();
    636 	if (yesno("Do you want to change our idea of what BIOS thinks?")) {
    637 		do {
    638 			decimal("BIOS's idea of #cylinders", &dos_cylinders);
    639 			decimal("BIOS's idea of #heads", &dos_heads);
    640 			decimal("BIOS's idea of #sectors", &dos_sectors);
    641 			dos_cylindersectors = dos_heads * dos_sectors;
    642 			print_params();
    643 		} while (!yesno("Are you happy with this choice?"));
    644 	}
    645 }
    646 
    647 /***********************************************\
    648 * Change real numbers into strange dos numbers	*
    649 \***********************************************/
    650 void
    651 dos(sector, cylinderp, headp, sectorp)
    652 	int sector;
    653 	unsigned char *cylinderp, *headp, *sectorp;
    654 {
    655 	int cylinder, head;
    656 
    657 	cylinder = sector / dos_cylindersectors;
    658 	sector -= cylinder * dos_cylindersectors;
    659 
    660 	head = sector / dos_sectors;
    661 	sector -= head * dos_sectors;
    662 
    663 	*cylinderp = DOSCYL(cylinder);
    664 	*headp = head;
    665 	*sectorp = DOSSECT(sector + 1, cylinder);
    666 }
    667 
    668 int fd;
    669 
    670 int
    671 open_disk(u_flag)
    672 	int u_flag;
    673 {
    674 	struct stat st;
    675 
    676 	if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) {
    677 		warn("%s", disk);
    678 		return (-1);
    679 	}
    680 	if (fstat(fd, &st) == -1) {
    681 		close(fd);
    682 		warn("%s", disk);
    683 		return (-1);
    684 	}
    685 	if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
    686 		close(fd);
    687 		warnx("%s is not a character device or regular file", disk);
    688 		return (-1);
    689 	}
    690 	if (get_params() == -1) {
    691 		close(fd);
    692 		return (-1);
    693 	}
    694 	return (0);
    695 }
    696 
    697 int
    698 read_disk(sector, buf)
    699 	int sector;
    700 	void *buf;
    701 {
    702 
    703 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    704 		return (-1);
    705 	return (read(fd, buf, 512));
    706 }
    707 
    708 int
    709 write_disk(sector, buf)
    710 	int sector;
    711 	void *buf;
    712 {
    713 
    714 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
    715 		return (-1);
    716 	return (write(fd, buf, 512));
    717 }
    718 
    719 int
    720 get_params()
    721 {
    722 
    723 	if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
    724 		warn("DIOCGDINFO");
    725 		return (-1);
    726 	}
    727 
    728 	dos_cylinders = cylinders = disklabel.d_ncylinders;
    729 	dos_heads = heads = disklabel.d_ntracks;
    730 	dos_sectors = sectors = disklabel.d_nsectors;
    731 	dos_cylindersectors = cylindersectors = heads * sectors;
    732 	disksectors = cylinders * heads * sectors;
    733 
    734 	return (0);
    735 }
    736 
    737 int
    738 read_s0()
    739 {
    740 
    741 	if (read_disk(0, mboot.bootinst) == -1) {
    742 		warn("can't read fdisk partition table");
    743 		return (-1);
    744 	}
    745 	if (getshort(&mboot.signature) != BOOT_MAGIC) {
    746 		warnx("invalid fdisk partition table found");
    747 		/* So should we initialize things? */
    748 		return (-1);
    749 	}
    750 	return (0);
    751 }
    752 
    753 int
    754 write_s0()
    755 {
    756 	int flag;
    757 
    758 	/*
    759 	 * write enable label sector before write (if necessary),
    760 	 * disable after writing.
    761 	 * needed if the disklabel protected area also protects
    762 	 * sector 0. (e.g. empty disk)
    763 	 */
    764 	flag = 1;
    765 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    766 		warn("DIOCWLABEL");
    767 	if (write_disk(0, mboot.bootinst) == -1) {
    768 		warn("can't write fdisk partition table");
    769 		return -1;
    770 	}
    771 	flag = 0;
    772 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
    773 		warn("DIOCWLABEL");
    774 }
    775 
    776 int
    777 yesno(str)
    778 	char *str;
    779 {
    780 	int ch, first;
    781 
    782 	printf("%s [n] ", str);
    783 
    784 	first = ch = getchar();
    785 	while (ch != '\n' && ch != EOF)
    786 		ch = getchar();
    787 	return (first == 'y' || first == 'Y');
    788 }
    789 
    790 void
    791 decimal(str, num)
    792 	char *str;
    793 	int *num;
    794 {
    795 	int acc = 0;
    796 	char *cp;
    797 
    798 	for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
    799 		printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
    800 
    801 		fgets(lbuf, LBUF, stdin);
    802 		lbuf[strlen(lbuf)-1] = '\0';
    803 		cp = lbuf;
    804 
    805 		cp += strspn(cp, " \t");
    806 		if (*cp == '\0')
    807 			return;
    808 
    809 		if (!isdigit(*cp))
    810 			continue;
    811 		acc = strtol(lbuf, &cp, 10);
    812 
    813 		cp += strspn(cp, " \t");
    814 		if (*cp != '\0')
    815 			continue;
    816 
    817 		*num = acc;
    818 		return;
    819 	}
    820 
    821 }
    822 
    823 int
    824 type_match(key, item)
    825 	const void *key, *item;
    826 {
    827 	const int *typep = key;
    828 	const struct part_type *ptr = item;
    829 
    830 	if (*typep < ptr->type)
    831 		return (-1);
    832 	if (*typep > ptr->type)
    833 		return (1);
    834 	return (0);
    835 }
    836 
    837 char *
    838 get_type(type)
    839 	int type;
    840 {
    841 	struct part_type *ptr;
    842 
    843 	ptr = bsearch(&type, part_types,
    844 	    sizeof(part_types) / sizeof(struct part_type),
    845 	    sizeof(struct part_type), type_match);
    846 	if (ptr == 0)
    847 		return ("unknown");
    848 	else
    849 		return (ptr->name);
    850 }
    851