xref: /netbsd-src/sbin/fdisk/fdisk.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: fdisk.c,v 1.12 1997/03/29 20:46:17 thorpej 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@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.12 1997/03/29 20:46:17 thorpej 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 {
120 	int type;
121 	char *name;
122 } part_types[] = {
123 	{0x00, "unused"},
124 	{0x01, "Primary DOS with 12 bit FAT"},
125 	{0x02, "XENIX / filesystem"},
126 	{0x03, "XENIX /usr filesystem"},
127 	{0x04, "Primary DOS with 16 bit FAT"},
128 	{0x05, "Extended DOS"},
129 	{0x06, "Primary 'big' DOS (> 32MB)"},
130 	{0x07, "OS/2 HPFS, QNX or Advanced UNIX"},
131 	{0x08, "AIX filesystem"},
132 	{0x09, "AIX boot partition or Coherent"},
133 	{0x0A, "OS/2 Boot Manager or OPUS"},
134 	{0x10, "OPUS"},
135 	{0x40, "VENIX 286"},
136 	{0x50, "DM"},
137 	{0x51, "DM"},
138 	{0x52, "CP/M or Microport SysV/AT"},
139 	{0x56, "GB"},
140 	{0x61, "Speed"},
141 	{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"},
142 	{0x64, "Novell Netware 2.xx"},
143 	{0x65, "Novell Netware 3.xx"},
144 	{0x75, "PCIX"},
145 	{0x80, "Minix 1.1 ... 1.4a"},
146 	{0x81, "Minix 1.4b ... 1.5.10"},
147 	{0x82, "Linux swap"},
148 	{0x83, "Linux filesystem"},
149 	{0x93, "Amoeba filesystem"},
150 	{0x94, "Amoeba bad block table"},
151 	{0xA5, "NetBSD or 386BSD"},
152 	{0xB7, "BSDI BSD/386 filesystem"},
153 	{0xB8, "BSDI BSD/386 swap"},
154 	{0xDB, "Concurrent CPM or C.DOS or CTOS"},
155 	{0xE1, "Speed"},
156 	{0xE3, "Speed"},
157 	{0xE4, "Speed"},
158 	{0xF1, "Speed"},
159 	{0xF2, "DOS 3.3+ Secondary"},
160 	{0xF4, "Speed"},
161 	{0xFF, "BBT (Bad Blocks Table)"},
162 };
163 
164 void	usage __P((void));
165 void	print_s0 __P((int));
166 void	print_part __P((int));
167 void	init_sector0 __P((int));
168 void	intuit_translated_geometry __P((void));
169 int	try_heads __P((quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, quad_t,
170 		       quad_t));
171 int	try_sectors __P((quad_t, quad_t, quad_t, quad_t, quad_t));
172 void	change_part __P((int));
173 void	print_params __P((void));
174 void	change_active __P((int));
175 void	get_params_to_use __P((void));
176 void	dos __P((int, unsigned char *, unsigned char *, unsigned char *));
177 int	open_disk __P((int));
178 int	read_disk __P((int, void *));
179 int	write_disk __P((int, void *));
180 int	get_params __P((void));
181 int	read_s0 __P((void));
182 int	write_s0 __P((void));
183 int	yesno __P((char *));
184 void	decimal __P((char *, int *));
185 int	type_match __P((const void *, const void *));
186 char	*get_type __P((int));
187 
188 int
189 main(argc, argv)
190 	int argc;
191 	char *argv[];
192 {
193 	int ch;
194 	int part;
195 
196 	a_flag = i_flag = u_flag = 0;
197 	while ((ch = getopt(argc, argv, "0123aiu")) != -1)
198 		switch (ch) {
199 		case '0':
200 			partition = 0;
201 			break;
202 		case '1':
203 			partition = 1;
204 			break;
205 		case '2':
206 			partition = 2;
207 			break;
208 		case '3':
209 			partition = 3;
210 			break;
211 		case 'a':
212 			a_flag = 1;
213 			break;
214 		case 'i':
215 			i_flag = 1;
216 		case 'u':
217 			u_flag = 1;
218 			break;
219 		default:
220 			usage();
221 		}
222 	argc -= optind;
223 	argv += optind;
224 
225 	if (argc > 0)
226 		disk = argv[0];
227 
228 	if (open_disk(a_flag || i_flag || u_flag) < 0)
229 		exit(1);
230 
231 	if (read_s0())
232 		init_sector0(1);
233 
234 	intuit_translated_geometry();
235 
236 	printf("******* Working on device %s *******\n", disk);
237 	if (u_flag)
238 		get_params_to_use();
239 	else
240 		print_params();
241 
242 	printf("Warning: BIOS sector numbering starts with sector 1\n");
243 	printf("Information from DOS bootblock is:\n");
244 	if (partition == -1) {
245 		for (part = 0; part < NDOSPART; part++)
246 			change_part(part);
247 	} else
248 		change_part(partition);
249 
250 	if (u_flag || a_flag)
251 		change_active(partition);
252 
253 	if (u_flag || a_flag) {
254 		printf("\nWe haven't changed the partition table yet.  ");
255 		printf("This is your last chance.\n");
256 		print_s0(-1);
257 		if (yesno("Should we write new partition table?"))
258 			write_s0();
259 	}
260 
261 	exit(0);
262 }
263 
264 void
265 usage()
266 {
267 
268 	(void)fprintf(stderr, "usage: fdisk [-aiu] [-0|-1|-2|-3] [device]\n");
269 	exit(1);
270 }
271 
272 void
273 print_s0(which)
274 	int which;
275 {
276 	int part;
277 
278 	print_params();
279 	printf("Information from DOS bootblock is:\n");
280 	if (which == -1) {
281 		for (part = 0; part < NDOSPART; part++)
282 			printf("%d: ", part), print_part(part);
283 	} else
284 		print_part(which);
285 }
286 
287 static struct dos_partition mtpart = { 0 };
288 
289 static inline unsigned short
290 getshort(p)
291 	void *p;
292 {
293 	unsigned char *cp = p;
294 
295 	return cp[0] | (cp[1] << 8);
296 }
297 
298 static inline void
299 putshort(p, l)
300 	void *p;
301 	unsigned short l;
302 {
303 	unsigned char *cp = p;
304 
305 	*cp++ = l;
306 	*cp++ = l >> 8;
307 }
308 
309 static inline unsigned long
310 getlong(p)
311 	void *p;
312 {
313 	unsigned char *cp = p;
314 
315 	return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24);
316 }
317 
318 static inline void
319 putlong(p, l)
320 	void *p;
321 	unsigned long l;
322 {
323 	unsigned char *cp = p;
324 
325 	*cp++ = l;
326 	*cp++ = l >> 8;
327 	*cp++ = l >> 16;
328 	*cp++ = l >> 24;
329 }
330 
331 void
332 print_part(part)
333 	int part;
334 {
335 	struct dos_partition *partp;
336 
337 	partp = &mboot.parts[part];
338 	if (!memcmp(partp, &mtpart, sizeof(struct dos_partition))) {
339 		printf("<UNUSED>\n");
340 		return;
341 	}
342 	printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ));
343 	printf("    start %d, size %d (%d MB), flag %x\n",
344 	    getlong(&partp->dp_start), getlong(&partp->dp_size),
345 	    getlong(&partp->dp_size) * 512 / (1024 * 1024), partp->dp_flag);
346 	printf("\tbeg: cylinder %4d, head %3d, sector %2d\n",
347 	    DPCYL(partp->dp_scyl, partp->dp_ssect),
348 	    partp->dp_shd, DPSECT(partp->dp_ssect));
349 	printf("\tend: cylinder %4d, head %3d, sector %2d\n",
350 	    DPCYL(partp->dp_ecyl, partp->dp_esect),
351 	    partp->dp_ehd, DPSECT(partp->dp_esect));
352 }
353 
354 void
355 init_sector0(start)
356 	int start;
357 {
358 	struct dos_partition *partp;
359 
360 	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
361 	putshort(&mboot.signature, BOOT_MAGIC);
362 
363 	partp = &mboot.parts[3];
364 	partp->dp_typ = DOSPTYP_386BSD;
365 	partp->dp_flag = ACTIVE;
366 	putlong(&partp->dp_start, start);
367 	putlong(&partp->dp_size, disksectors - start);
368 
369 	dos(getlong(&partp->dp_start),
370 	    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
371 	dos(getlong(&partp->dp_start) + getlong(&partp->dp_size) - 1,
372 	    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
373 }
374 
375 /* Prerequisite: the disklabel parameters and master boot record must
376  *		 have been read (i.e. dos_* and mboot are meaningful).
377  * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and
378  *		  dos_cylindersectors to be consistent with what the
379  *		  partition table is using, if we can find a geometry
380  *		  which is consistent with all partition table entries.
381  *		  We may get the number of cylinders slightly wrong (in
382  *		  the conservative direction).  The idea is to be able
383  *		  to create a NetBSD partition on a disk we don't know
384  *		  the translated geometry of.
385  * This whole routine should be replaced with a kernel interface to get
386  * the BIOS geometry (which in turn requires modifications to the i386
387  * boot loader to pass in the BIOS geometry for each disk). */
388 void
389 intuit_translated_geometry()
390 {
391 	int cylinders = -1, heads = -1, sectors = -1, i, j;
392 	int c1, h1, s1, c2, h2, s2;
393 	long a1, a2;
394 	quad_t num, denom;
395 
396 	/* Try to deduce the number of heads from two different mappings. */
397 	for (i = 0; i < NDOSPART * 2; i++) {
398 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
399 			continue;
400 		for (j = 0; j < 8; j++) {
401 			if (get_mapping(j, &c2, &h2, &s2, &a2) < 0)
402 				continue;
403 			num = (quad_t)h1*(a2-s2) - h2*(a1-s1);
404 			denom = (quad_t)c2*(a1-s1) - c1*(a2-s2);
405 			if (denom != 0 && num % denom == 0) {
406 				heads = num / denom;
407 				break;
408 			}
409 		}
410 		if (heads != -1)
411 			break;
412 	}
413 
414 	if (heads == -1)
415 		return;
416 
417 	/* Now figure out the number of sectors from a single mapping. */
418 	for (i = 0; i < NDOSPART * 2; i++) {
419 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
420 			continue;
421 		num = a1 - s1;
422 		denom = c1 * heads + h1;
423 		if (denom != 0 && num % denom == 0) {
424 			sectors = num / denom;
425 			break;
426 		}
427 	}
428 
429 	if (sectors == -1)
430 		return;
431 
432 	/* Estimate the number of cylinders. */
433 	cylinders = dos_cylinders * dos_cylindersectors / heads / sectors;
434 
435 	/* Now verify consistency with each of the partition table entries.
436 	 * Be willing to shove cylinders up a little bit to make things work,
437 	 * but translation mismatches are fatal. */
438 	for (i = 0; i < NDOSPART * 2; i++) {
439 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
440 			continue;
441 		if (sectors * (c1 * heads + h1) + s1 != a1)
442 			return;
443 		if (c1 >= cylinders)
444 			cylinders = c1 + 1;
445 	}
446 
447 	/* Everything checks out.  Reset the geometry to use for further
448 	 * calculations. */
449 	dos_cylinders = cylinders;
450 	dos_heads = heads;
451 	dos_sectors = sectors;
452 	dos_cylindersectors = heads * sectors;
453 }
454 
455 /* For the purposes of intuit_translated_geometry(), treat the partition
456  * table as a list of eight mapping between (cylinder, head, sector)
457  * triplets and absolute sectors.  Get the relevant geometry triplet and
458  * absolute sectors for a given entry, or return -1 if it isn't present.
459  * Note: for simplicity, the returned sector is 0-based. */
460 int
461 get_mapping(i, cylinder, head, sector, absolute)
462 	int i, *cylinder, *head, *sector;
463 	long *absolute;
464 {
465 	struct dos_partition *part = &mboot.parts[i / 2];
466 
467 	if (part->dp_typ == 0)
468 		return -1;
469 	if (i % 2 == 0) {
470 		*cylinder = DPCYL(part->dp_scyl, part->dp_ssect);
471 		*head = part->dp_shd;
472 		*sector = DPSECT(part->dp_ssect) - 1;
473 		*absolute = getlong(&part->dp_start);
474 	} else {
475 		*cylinder = DPCYL(part->dp_ecyl, part->dp_esect);
476 		*head = part->dp_ehd;
477 		*sector = DPSECT(part->dp_esect) - 1;
478 		*absolute = getlong(&part->dp_start)
479 		    + getlong(&part->dp_size) - 1;
480 	}
481 	return 0;
482 }
483 
484 void
485 change_part(part)
486 	int part;
487 {
488 	struct dos_partition *partp;
489 
490 	partp = &mboot.parts[part];
491 
492 	printf("The data for partition %d is:\n", part);
493 	print_part(part);
494 
495 	if (!u_flag || !yesno("Do you want to change it?"))
496 		return;
497 
498 	if (i_flag) {
499 		memset(partp, 0, sizeof(*partp));
500 		if (part == 3) {
501 			init_sector0(1);
502 			printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
503 			print_part(part);
504 		}
505 	}
506 
507 	do {
508 		{
509 			int sysid, start, size;
510 
511 			sysid = partp->dp_typ,
512 			start = getlong(&partp->dp_start),
513 			size = getlong(&partp->dp_size);
514 			decimal("sysid", &sysid);
515 			decimal("start", &start);
516 			decimal("size", &size);
517 			partp->dp_typ = sysid;
518 			putlong(&partp->dp_start, start);
519 			putlong(&partp->dp_size, size);
520 		}
521 
522 		if (yesno("Explicitly specify beg/end address?")) {
523 			int tsector, tcylinder, thead;
524 
525 			tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
526 			thead = partp->dp_shd;
527 			tsector = DPSECT(partp->dp_ssect);
528 			decimal("beginning cylinder", &tcylinder);
529 			decimal("beginning head", &thead);
530 			decimal("beginning sector", &tsector);
531 			partp->dp_scyl = DOSCYL(tcylinder);
532 			partp->dp_shd = thead;
533 			partp->dp_ssect = DOSSECT(tsector, tcylinder);
534 
535 			tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
536 			thead = partp->dp_ehd;
537 			tsector = DPSECT(partp->dp_esect);
538 			decimal("ending cylinder", &tcylinder);
539 			decimal("ending head", &thead);
540 			decimal("ending sector", &tsector);
541 			partp->dp_ecyl = DOSCYL(tcylinder);
542 			partp->dp_ehd = thead;
543 			partp->dp_esect = DOSSECT(tsector, tcylinder);
544 		} else {
545 			dos(getlong(&partp->dp_start),
546 			    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
547 			dos(getlong(&partp->dp_start)
548 			    + getlong(&partp->dp_size) - 1,
549 			    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
550 		}
551 
552 		print_part(part);
553 	} while (!yesno("Is this entry okay?"));
554 }
555 
556 void
557 print_params()
558 {
559 
560 	printf("parameters extracted from in-core disklabel are:\n");
561 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
562 	    cylinders, heads, sectors, cylindersectors);
563 	if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255)
564 		printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
565 	printf("parameters to be used for BIOS calculations are:\n");
566 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
567 	    dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
568 }
569 
570 void
571 change_active(which)
572 	int which;
573 {
574 	struct dos_partition *partp;
575 	int part;
576 	int active = 3;
577 
578 	partp = &mboot.parts[0];
579 
580 	if (a_flag && which != -1)
581 		active = which;
582 	else {
583 		for (part = 0; part < NDOSPART; part++)
584 			if (partp[part].dp_flag & ACTIVE)
585 				active = part;
586 	}
587 	if (yesno("Do you want to change the active partition?")) {
588 		do {
589 			decimal("active partition", &active);
590 		} while (!yesno("Are you happy with this choice?"));
591 	}
592 	for (part = 0; part < NDOSPART; part++)
593 		partp[part].dp_flag &= ~ACTIVE;
594 	partp[active].dp_flag |= ACTIVE;
595 }
596 
597 void
598 get_params_to_use()
599 {
600 
601 	print_params();
602 	if (yesno("Do you want to change our idea of what BIOS thinks?")) {
603 		do {
604 			decimal("BIOS's idea of #cylinders", &dos_cylinders);
605 			decimal("BIOS's idea of #heads", &dos_heads);
606 			decimal("BIOS's idea of #sectors", &dos_sectors);
607 			dos_cylindersectors = dos_heads * dos_sectors;
608 			print_params();
609 		} while (!yesno("Are you happy with this choice?"));
610 	}
611 }
612 
613 /***********************************************\
614 * Change real numbers into strange dos numbers	*
615 \***********************************************/
616 void
617 dos(sector, cylinderp, headp, sectorp)
618 	int sector;
619 	unsigned char *cylinderp, *headp, *sectorp;
620 {
621 	int cylinder, head;
622 
623 	cylinder = sector / dos_cylindersectors;
624 	sector -= cylinder * dos_cylindersectors;
625 
626 	head = sector / dos_sectors;
627 	sector -= head * dos_sectors;
628 
629 	*cylinderp = DOSCYL(cylinder);
630 	*headp = head;
631 	*sectorp = DOSSECT(sector + 1, cylinder);
632 }
633 
634 int fd;
635 
636 int
637 open_disk(u_flag)
638 	int u_flag;
639 {
640 	struct stat st;
641 
642 	if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) {
643 		warn("%s", disk);
644 		return (-1);
645 	}
646 	if (fstat(fd, &st) == -1) {
647 		close(fd);
648 		warn("%s", disk);
649 		return (-1);
650 	}
651 	if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
652 		close(fd);
653 		warnx("%s is not a character device or regular file", disk);
654 		return (-1);
655 	}
656 	if (get_params() == -1) {
657 		close(fd);
658 		return (-1);
659 	}
660 	return (0);
661 }
662 
663 int
664 read_disk(sector, buf)
665 	int sector;
666 	void *buf;
667 {
668 
669 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
670 		return (-1);
671 	return (read(fd, buf, 512));
672 }
673 
674 int
675 write_disk(sector, buf)
676 	int sector;
677 	void *buf;
678 {
679 
680 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
681 		return (-1);
682 	return (write(fd, buf, 512));
683 }
684 
685 int
686 get_params()
687 {
688 
689 	if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
690 		warn("DIOCGDINFO");
691 		return (-1);
692 	}
693 
694 	dos_cylinders = cylinders = disklabel.d_ncylinders;
695 	dos_heads = heads = disklabel.d_ntracks;
696 	dos_sectors = sectors = disklabel.d_nsectors;
697 	dos_cylindersectors = cylindersectors = heads * sectors;
698 	disksectors = cylinders * heads * sectors;
699 
700 	return (0);
701 }
702 
703 int
704 read_s0()
705 {
706 
707 	if (read_disk(0, mboot.bootinst) == -1) {
708 		warn("can't read fdisk partition table");
709 		return (-1);
710 	}
711 	if (getshort(&mboot.signature) != BOOT_MAGIC) {
712 		warnx("invalid fdisk partition table found");
713 		/* So should we initialize things? */
714 		return (-1);
715 	}
716 	return (0);
717 }
718 
719 int
720 write_s0()
721 {
722 	int flag;
723 
724 	/*
725 	 * write enable label sector before write (if necessary),
726 	 * disable after writing.
727 	 * needed if the disklabel protected area also protects
728 	 * sector 0. (e.g. empty disk)
729 	 */
730 	flag = 1;
731 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
732 		warn("DIOCWLABEL");
733 	if (write_disk(0, mboot.bootinst) == -1) {
734 		warn("can't write fdisk partition table");
735 		return -1;
736 	}
737 	flag = 0;
738 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
739 		warn("DIOCWLABEL");
740 }
741 
742 int
743 yesno(str)
744 	char *str;
745 {
746 	int ch, first;
747 
748 	printf("%s [n] ", str);
749 
750 	first = ch = getchar();
751 	while (ch != '\n' && ch != EOF)
752 		ch = getchar();
753 	return (first == 'y' || first == 'Y');
754 }
755 
756 void
757 decimal(str, num)
758 	char *str;
759 	int *num;
760 {
761 	int acc = 0;
762 	char *cp;
763 
764 	for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
765 		printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
766 
767 		fgets(lbuf, LBUF, stdin);
768 		lbuf[strlen(lbuf)-1] = '\0';
769 		cp = lbuf;
770 
771 		cp += strspn(cp, " \t");
772 		if (*cp == '\0')
773 			return;
774 
775 		if (!isdigit(*cp))
776 			continue;
777 		acc = strtol(lbuf, &cp, 10);
778 
779 		cp += strspn(cp, " \t");
780 		if (*cp != '\0')
781 			continue;
782 
783 		*num = acc;
784 		return;
785 	}
786 
787 }
788 
789 int
790 type_match(key, item)
791 	const void *key, *item;
792 {
793 	const int *typep = key;
794 	const struct part_type *ptr = item;
795 
796 	if (*typep < ptr->type)
797 		return (-1);
798 	if (*typep > ptr->type)
799 		return (1);
800 	return (0);
801 }
802 
803 char *
804 get_type(type)
805 	int type;
806 {
807 	struct part_type *ptr;
808 
809 	ptr = bsearch(&type, part_types,
810 	    sizeof(part_types) / sizeof(struct part_type),
811 	    sizeof(struct part_type), type_match);
812 	if (ptr == 0)
813 		return ("unknown");
814 	else
815 		return (ptr->name);
816 }
817