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