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