xref: /netbsd-src/sbin/fdisk/fdisk.c (revision 81b108b45f75f89f1e3ffad9fb6f074e771c0935)
1 /*	$NetBSD: fdisk.c,v 1.11 1995/10/04 23:11:19 ghudson 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.11 1995/10/04 23:11:19 ghudson 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 void
290 print_part(part)
291 	int part;
292 {
293 	struct dos_partition *partp;
294 
295 	partp = &mboot.parts[part];
296 	if (!memcmp(partp, &mtpart, sizeof(struct dos_partition))) {
297 		printf("<UNUSED>\n");
298 		return;
299 	}
300 	printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ));
301 	printf("    start %d, size %d (%d MB), flag %x\n",
302 	    partp->dp_start, partp->dp_size,
303 	    partp->dp_size * 512 / (1024 * 1024), partp->dp_flag);
304 	printf("\tbeg: cylinder %4d, head %3d, sector %2d\n",
305 	    DPCYL(partp->dp_scyl, partp->dp_ssect),
306 	    partp->dp_shd, DPSECT(partp->dp_ssect));
307 	printf("\tend: cylinder %4d, head %3d, sector %2d\n",
308 	    DPCYL(partp->dp_ecyl, partp->dp_esect),
309 	    partp->dp_ehd, DPSECT(partp->dp_esect));
310 }
311 
312 void
313 init_sector0(start)
314 	int start;
315 {
316 	struct dos_partition *partp;
317 
318 	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
319 	mboot.signature = BOOT_MAGIC;
320 
321 	partp = &mboot.parts[3];
322 	partp->dp_typ = DOSPTYP_386BSD;
323 	partp->dp_flag = ACTIVE;
324 	partp->dp_start = start;
325 	partp->dp_size = disksectors - start;
326 
327 	dos(partp->dp_start,
328 	    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
329 	dos(partp->dp_start + partp->dp_size - 1,
330 	    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
331 }
332 
333 /* Prerequisite: the disklabel parameters and master boot record must
334  *		 have been read (i.e. dos_* and mboot are meaningful).
335  * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and
336  *		  dos_cylindersectors to be consistent with what the
337  *		  partition table is using, if we can find a geometry
338  *		  which is consistent with all partition table entries.
339  *		  We may get the number of cylinders slightly wrong (in
340  *		  the conservative direction).  The idea is to be able
341  *		  to create a NetBSD partition on a disk we don't know
342  *		  the translated geometry of.
343  * This whole routine should be replaced with a kernel interface to get
344  * the BIOS geometry (which in turn requires modifications to the i386
345  * boot loader to pass in the BIOS geometry for each disk). */
346 void
347 intuit_translated_geometry()
348 {
349 	int cylinders = -1, heads = -1, sectors = -1, i, j;
350 	int c1, h1, s1, c2, h2, s2;
351 	long a1, a2;
352 	quad_t num, denom;
353 
354 	/* Try to deduce the number of heads from two different mappings. */
355 	for (i = 0; i < NDOSPART * 2; i++) {
356 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
357 			continue;
358 		for (j = 0; j < 8; j++) {
359 			if (get_mapping(j, &c2, &h2, &s2, &a2) < 0)
360 				continue;
361 			num = (quad_t)h1*(a2-s2) - h2*(a1-s1);
362 			denom = (quad_t)c2*(a1-s1) - c1*(a2-s2);
363 			if (denom != 0 && num % denom == 0) {
364 				heads = num / denom;
365 				break;
366 			}
367 		}
368 		if (heads != -1)
369 			break;
370 	}
371 
372 	if (heads == -1)
373 		return;
374 
375 	/* Now figure out the number of sectors from a single mapping. */
376 	for (i = 0; i < NDOSPART * 2; i++) {
377 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
378 			continue;
379 		num = a1 - s1;
380 		denom = c1 * heads + h1;
381 		if (denom != 0 && num % denom == 0) {
382 			sectors = num / denom;
383 			break;
384 		}
385 	}
386 
387 	if (sectors == -1)
388 		return;
389 
390 	/* Estimate the number of cylinders. */
391 	cylinders = dos_cylinders * dos_cylindersectors / heads / sectors;
392 
393 	/* Now verify consistency with each of the partition table entries.
394 	 * Be willing to shove cylinders up a little bit to make things work,
395 	 * but translation mismatches are fatal. */
396 	for (i = 0; i < NDOSPART * 2; i++) {
397 		if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
398 			continue;
399 		if (sectors * (c1 * heads + h1) + s1 != a1)
400 			return;
401 		if (c1 >= cylinders)
402 			cylinders = c1 + 1;
403 	}
404 
405 	/* Everything checks out.  Reset the geometry to use for further
406 	 * calculations. */
407 	dos_cylinders = cylinders;
408 	dos_heads = heads;
409 	dos_sectors = sectors;
410 	dos_cylindersectors = heads * sectors;
411 }
412 
413 /* For the purposes of intuit_translated_geometry(), treat the partition
414  * table as a list of eight mapping between (cylinder, head, sector)
415  * triplets and absolute sectors.  Get the relevant geometry triplet and
416  * absolute sectors for a given entry, or return -1 if it isn't present.
417  * Note: for simplicity, the returned sector is 0-based. */
418 int
419 get_mapping(i, cylinder, head, sector, absolute)
420 	int i, *cylinder, *head, *sector;
421 	long *absolute;
422 {
423 	struct dos_partition *part = &mboot.parts[i / 2];
424 
425 	if (part->dp_typ == 0)
426 		return -1;
427 	if (i % 2 == 0) {
428 		*cylinder = DPCYL(part->dp_scyl, part->dp_ssect);
429 		*head = part->dp_shd;
430 		*sector = DPSECT(part->dp_ssect) - 1;
431 		*absolute = part->dp_start;
432 	} else {
433 		*cylinder = DPCYL(part->dp_ecyl, part->dp_esect);
434 		*head = part->dp_ehd;
435 		*sector = DPSECT(part->dp_esect) - 1;
436 		*absolute = part->dp_start + part->dp_size - 1;
437 	}
438 	return 0;
439 }
440 
441 void
442 change_part(part)
443 	int part;
444 {
445 	struct dos_partition *partp;
446 
447 	partp = &mboot.parts[part];
448 
449 	printf("The data for partition %d is:\n", part);
450 	print_part(part);
451 
452 	if (!u_flag || !yesno("Do you want to change it?"))
453 		return;
454 
455 	if (i_flag) {
456 		memset(partp, 0, sizeof(*partp));
457 		if (part == 3) {
458 			init_sector0(1);
459 			printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
460 			print_part(part);
461 		}
462 	}
463 
464 	do {
465 		{
466 			int sysid, start, size;
467 
468 			sysid = partp->dp_typ,
469 			start = partp->dp_start,
470 			size = partp->dp_size;
471 			decimal("sysid", &sysid);
472 			decimal("start", &start);
473 			decimal("size", &size);
474 			partp->dp_typ = sysid;
475 			partp->dp_start = start;
476 			partp->dp_size = size;
477 		}
478 
479 		if (yesno("Explicitly specify beg/end address?")) {
480 			int tsector, tcylinder, thead;
481 
482 			tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
483 			thead = partp->dp_shd;
484 			tsector = DPSECT(partp->dp_ssect);
485 			decimal("beginning cylinder", &tcylinder);
486 			decimal("beginning head", &thead);
487 			decimal("beginning sector", &tsector);
488 			partp->dp_scyl = DOSCYL(tcylinder);
489 			partp->dp_shd = thead;
490 			partp->dp_ssect = DOSSECT(tsector, tcylinder);
491 
492 			tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
493 			thead = partp->dp_ehd;
494 			tsector = DPSECT(partp->dp_esect);
495 			decimal("ending cylinder", &tcylinder);
496 			decimal("ending head", &thead);
497 			decimal("ending sector", &tsector);
498 			partp->dp_ecyl = DOSCYL(tcylinder);
499 			partp->dp_ehd = thead;
500 			partp->dp_esect = DOSSECT(tsector, tcylinder);
501 		} else {
502 			dos(partp->dp_start,
503 			    &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
504 			dos(partp->dp_start + partp->dp_size - 1,
505 			    &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
506 		}
507 
508 		print_part(part);
509 	} while (!yesno("Is this entry okay?"));
510 }
511 
512 void
513 print_params()
514 {
515 
516 	printf("parameters extracted from in-core disklabel are:\n");
517 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
518 	    cylinders, heads, sectors, cylindersectors);
519 	if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255)
520 		printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
521 	printf("parameters to be used for BIOS calculations are:\n");
522 	printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
523 	    dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
524 }
525 
526 void
527 change_active(which)
528 	int which;
529 {
530 	struct dos_partition *partp;
531 	int part;
532 	int active = 3;
533 
534 	partp = &mboot.parts[0];
535 
536 	if (a_flag && which != -1)
537 		active = which;
538 	else {
539 		for (part = 0; part < NDOSPART; part++)
540 			if (partp[part].dp_flag & ACTIVE)
541 				active = part;
542 	}
543 	if (yesno("Do you want to change the active partition?")) {
544 		do {
545 			decimal("active partition", &active);
546 		} while (!yesno("Are you happy with this choice?"));
547 	}
548 	for (part = 0; part < NDOSPART; part++)
549 		partp[part].dp_flag &= ~ACTIVE;
550 	partp[active].dp_flag |= ACTIVE;
551 }
552 
553 void
554 get_params_to_use()
555 {
556 
557 	print_params();
558 	if (yesno("Do you want to change our idea of what BIOS thinks?")) {
559 		do {
560 			decimal("BIOS's idea of #cylinders", &dos_cylinders);
561 			decimal("BIOS's idea of #heads", &dos_heads);
562 			decimal("BIOS's idea of #sectors", &dos_sectors);
563 			dos_cylindersectors = dos_heads * dos_sectors;
564 			print_params();
565 		} while (!yesno("Are you happy with this choice?"));
566 	}
567 }
568 
569 /***********************************************\
570 * Change real numbers into strange dos numbers	*
571 \***********************************************/
572 void
573 dos(sector, cylinderp, headp, sectorp)
574 	int sector;
575 	unsigned char *cylinderp, *headp, *sectorp;
576 {
577 	int cylinder, head;
578 
579 	cylinder = sector / dos_cylindersectors;
580 	sector -= cylinder * dos_cylindersectors;
581 
582 	head = sector / dos_sectors;
583 	sector -= head * dos_sectors;
584 
585 	*cylinderp = DOSCYL(cylinder);
586 	*headp = head;
587 	*sectorp = DOSSECT(sector + 1, cylinder);
588 }
589 
590 int fd;
591 
592 int
593 open_disk(u_flag)
594 	int u_flag;
595 {
596 	struct stat st;
597 
598 	if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) {
599 		warn("%s", disk);
600 		return (-1);
601 	}
602 	if (fstat(fd, &st) == -1) {
603 		close(fd);
604 		warn("%s", disk);
605 		return (-1);
606 	}
607 	if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
608 		close(fd);
609 		warnx("%s is not a character device or regular file", disk);
610 		return (-1);
611 	}
612 	if (get_params() == -1) {
613 		close(fd);
614 		return (-1);
615 	}
616 	return (0);
617 }
618 
619 int
620 read_disk(sector, buf)
621 	int sector;
622 	void *buf;
623 {
624 
625 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
626 		return (-1);
627 	return (read(fd, buf, 512));
628 }
629 
630 int
631 write_disk(sector, buf)
632 	int sector;
633 	void *buf;
634 {
635 
636 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
637 		return (-1);
638 	return (write(fd, buf, 512));
639 }
640 
641 int
642 get_params()
643 {
644 
645 	if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
646 		warn("DIOCGDINFO");
647 		return (-1);
648 	}
649 
650 	dos_cylinders = cylinders = disklabel.d_ncylinders;
651 	dos_heads = heads = disklabel.d_ntracks;
652 	dos_sectors = sectors = disklabel.d_nsectors;
653 	dos_cylindersectors = cylindersectors = heads * sectors;
654 	disksectors = cylinders * heads * sectors;
655 
656 	return (0);
657 }
658 
659 int
660 read_s0()
661 {
662 
663 	if (read_disk(0, mboot.bootinst) == -1) {
664 		warn("can't read fdisk partition table");
665 		return (-1);
666 	}
667 	if (mboot.signature != BOOT_MAGIC) {
668 		warn("invalid fdisk partition table found");
669 		/* So should we initialize things? */
670 		return (-1);
671 	}
672 	return (0);
673 }
674 
675 int
676 write_s0()
677 {
678 	int flag;
679 
680 	/*
681 	 * write enable label sector before write (if necessary),
682 	 * disable after writing.
683 	 * needed if the disklabel protected area also protects
684 	 * sector 0. (e.g. empty disk)
685 	 */
686 	flag = 1;
687 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
688 		warn("DIOCWLABEL");
689 	if (write_disk(0, mboot.bootinst) == -1) {
690 		warn("can't write fdisk partition table");
691 		return -1;
692 	}
693 	flag = 0;
694 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
695 		warn("DIOCWLABEL");
696 }
697 
698 int
699 yesno(str)
700 	char *str;
701 {
702 	int ch, first;
703 
704 	printf("%s [n] ", str);
705 
706 	first = ch = getchar();
707 	while (ch != '\n' && ch != EOF)
708 		ch = getchar();
709 	return (first == 'y' || first == 'Y');
710 }
711 
712 void
713 decimal(str, num)
714 	char *str;
715 	int *num;
716 {
717 	int acc = 0;
718 	char *cp;
719 
720 	for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
721 		printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
722 
723 		fgets(lbuf, LBUF, stdin);
724 		lbuf[strlen(lbuf)-1] = '\0';
725 		cp = lbuf;
726 
727 		cp += strspn(cp, " \t");
728 		if (*cp == '\0')
729 			return;
730 
731 		if (!isdigit(*cp))
732 			continue;
733 		acc = strtol(lbuf, &cp, 10);
734 
735 		cp += strspn(cp, " \t");
736 		if (*cp != '\0')
737 			continue;
738 
739 		*num = acc;
740 		return;
741 	}
742 
743 }
744 
745 int
746 type_match(key, item)
747 	const void *key, *item;
748 {
749 	const int *typep = key;
750 	const struct part_type *ptr = item;
751 
752 	if (*typep < ptr->type)
753 		return (-1);
754 	if (*typep > ptr->type)
755 		return (1);
756 	return (0);
757 }
758 
759 char *
760 get_type(type)
761 	int type;
762 {
763 	struct part_type *ptr;
764 
765 	ptr = bsearch(&type, part_types,
766 	    sizeof(part_types) / sizeof(struct part_type),
767 	    sizeof(struct part_type), type_match);
768 	if (ptr == 0)
769 		return ("unknown");
770 	else
771 		return (ptr->name);
772 }
773