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