xref: /freebsd/sbin/fdisk/fdisk.c (revision ce834215a70ff69e7e222827437116eee2f9ac6f)
1 /*
2  * Mach Operating System
3  * Copyright (c) 1992 Carnegie Mellon University
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  *
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie Mellon
24  * the rights to redistribute these changes.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/disklabel.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/stat.h>
33 #include <sys/ioctl.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 
37 int iotest;
38 
39 #define LBUF 100
40 static char lbuf[LBUF];
41 
42 /*
43  *
44  * Ported to 386bsd by Julian Elischer  Thu Oct 15 20:26:46 PDT 1992
45  *
46  * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
47  *	Copyright (c) 1989	Robert. V. Baron
48  *	Created.
49  */
50 
51 #define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp
52 #define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp
53 #define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); }
54 
55 #define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
56 
57 #define MAX_SEC_SIZE 2048	/* maximum section size that is supported */
58 #define MIN_SEC_SIZE 512	/* the sector size to start sensing at */
59 int secsize = 0;		/* the sensed sector size */
60 
61 const char *disk;
62 const char *disks[] =
63 {
64   "/dev/rwd0", "/dev/rsd0", "/dev/rod0", 0
65 };
66 
67 char *name;
68 
69 struct disklabel disklabel;		/* disk parameters */
70 
71 int cyls, sectors, heads, cylsecs, disksecs;
72 
73 struct mboot
74 {
75 	unsigned char padding[2]; /* force the longs to be long alligned */
76 	unsigned char bootinst[DOSPARTOFF];
77 	struct	dos_partition parts[4];
78 	unsigned short int	signature;
79 	/* room to read in MBRs that are bigger then DEV_BSIZE */
80 	unsigned char large_sector_overflow[MAX_SEC_SIZE-MIN_SEC_SIZE];
81 };
82 struct mboot mboot;
83 
84 #define ACTIVE 0x80
85 #define BOOT_MAGIC 0xAA55
86 
87 int dos_cyls;
88 int dos_heads;
89 int dos_sectors;
90 int dos_cylsecs;
91 
92 #define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
93 #define DOSCYL(c)	(c & 0xff)
94 static int partition = -1;
95 
96 
97 #define MAX_ARGS	10
98 
99 static int	current_line_number;
100 
101 static int	geom_processed = 0;
102 static int	part_processed = 0;
103 static int	active_processed = 0;
104 
105 
106 typedef struct cmd {
107     char		cmd;
108     int			n_args;
109     struct arg {
110 	char	argtype;
111 	int	arg_val;
112     }			args[MAX_ARGS];
113 } CMD;
114 
115 
116 static int a_flag  = 0;		/* set active partition */
117 static int i_flag  = 0;		/* replace partition data */
118 static int u_flag  = 0;		/* update partition data */
119 static int t_flag  = 0;		/* test only, if f_flag is given */
120 static char *f_flag = NULL;	/* Read config info from file */
121 static int v_flag  = 0;		/* Be verbose */
122 
123 static unsigned char bootcode[] = {
124 0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
125 0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
126 0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
127 0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
128 0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
129 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
130 0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
131 0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
132 0xeb, 0xf4, 0xfb, 0xeb, 0xfe,
133 'M', 'i', 's', 's', 'i', 'n', 'g', ' ',
134 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
135 'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ',
136 	'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
137 'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ',
138 	'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0,
139 'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ',
140 	'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0,
141 
142   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
143   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
144   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
145   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
146   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
147   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
148   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
149   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
150   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
151   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
152   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
153   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
154   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
155 };
156 
157 struct part_type
158 {
159  unsigned char type;
160  char *name;
161 }part_types[] =
162 {
163 	 {0x00, "unused"}
164 	,{0x01, "Primary DOS with 12 bit FAT"}
165 	,{0x02, "XENIX / filesystem"}
166 	,{0x03, "XENIX /usr filesystem"}
167 	,{0x04, "Primary DOS with 16 bit FAT"}
168 	,{0x05, "Extended DOS"}
169 	,{0x06, "Primary 'big' DOS (> 32MB)"}
170 	,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"}
171 	,{0x08, "AIX filesystem"}
172 	,{0x09, "AIX boot partition or Coherent"}
173 	,{0x0A, "OS/2 Boot Manager or OPUS"}
174 	,{0x10, "OPUS"}
175 	,{0x40, "VENIX 286"}
176 	,{0x50, "DM"}
177 	,{0x51, "DM"}
178 	,{0x52, "CP/M or Microport SysV/AT"}
179 	,{0x56, "GB"}
180 	,{0x61, "Speed"}
181 	,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
182 	,{0x64, "Novell Netware 2.xx"}
183 	,{0x65, "Novell Netware 3.xx"}
184 	,{0x75, "PCIX"}
185 	,{0x80, "Minix 1.1 ... 1.4a"}
186 	,{0x81, "Minix 1.4b ... 1.5.10"}
187 	,{0x82, "Linux swap"}
188 	,{0x83, "Linux filesystem"}
189 	,{0x93, "Amoeba filesystem"}
190 	,{0x94, "Amoeba bad block table"}
191 	,{0xA5, "FreeBSD/NetBSD/386BSD"}
192 	,{0xA6, "OpenBSD"}
193 	,{0xA7, "NEXTSTEP"}
194 	,{0xB7, "BSDI BSD/386 filesystem"}
195 	,{0xB8, "BSDI BSD/386 swap"}
196 	,{0xDB, "Concurrent CPM or C.DOS or CTOS"}
197 	,{0xE1, "Speed"}
198 	,{0xE3, "Speed"}
199 	,{0xE4, "Speed"}
200 	,{0xF1, "Speed"}
201 	,{0xF2, "DOS 3.3+ Secondary"}
202 	,{0xF4, "Speed"}
203 	,{0xFF, "BBT (Bad Blocks Table)"}
204 };
205 
206 static void print_s0(int which);
207 static void print_part(int i);
208 static void init_sector0(unsigned long start);
209 static void init_boot(void);
210 static void change_part(int i);
211 static void print_params();
212 static void change_active(int which);
213 static void get_params_to_use();
214 static void dos(int sec, int size, unsigned char *c, unsigned char *s,
215 		unsigned char *h);
216 static int open_disk(int u_flag);
217 static ssize_t read_disk(off_t sector, void *buf);
218 static ssize_t write_disk(off_t sector, void *buf);
219 static int get_params();
220 static int read_s0();
221 static int write_s0();
222 static int ok(char *str);
223 static int decimal(char *str, int *num, int deflt);
224 static char *get_type(int type);
225 static int read_config(char *config_file);
226 static void reset_boot(void);
227 #if 0
228 static int hex(char *str, int *num, int deflt);
229 static int string(char *str, char **ans);
230 #endif
231 
232 
233 int
234 main(int argc, char *argv[])
235 {
236 	int	i;
237 
238 	name = *argv;
239 	{register char *cp = name;
240 		while (*cp) if (*cp++ == '/') name = cp;
241 	}
242 
243 	for ( argv++ ; --argc ; argv++ ) { register char *token = *argv;
244 		if (*token++ != '-' || !*token)
245 			break;
246 		else { register int flag;
247 			for ( ; (flag = *token++) ; ) {
248 				switch (flag) {
249 				case '1':
250 					partition = 1;
251 					break;
252 				case '2':
253 					partition = 2;
254 					break;
255 				case '3':
256 					partition = 3;
257 					break;
258 				case '4':
259 					partition = 4;
260 					break;
261 				case 'a':
262 					a_flag = 1;
263 					break;
264 				case 'f':
265 					if (*token)
266 					{
267 					    f_flag = token;
268 					    token = "";
269 					}
270 					else
271 					{
272 					    if (argc == 1)
273 					    {
274 						goto usage;
275 					    }
276 					    --argc;
277 					    f_flag = *++argv;
278 					}
279 					/*
280 					 * u_flag is needed, because we're
281 					 * writing to the disk.
282 					 */
283 					u_flag = 1;
284 					break;
285 				case 'i':
286 					i_flag = 1;
287 				case 'u':
288 					u_flag = 1;
289 					break;
290 				case 't':
291 					t_flag = 1;
292 				case 'v':
293 					v_flag = 1;
294 					break;
295 				default:
296 					goto usage;
297 				}
298 			}
299 		}
300 	}
301 
302 	if (argc > 0)
303 	{
304 		static char realname[12];
305 
306 		if(strncmp(argv[0], "/dev", 4) == 0)
307 			disk = argv[0];
308 		else
309 		{
310 			snprintf(realname, 12, "/dev/r%s", argv[0]);
311 			disk = realname;
312 		}
313 
314 		if (open_disk(u_flag) < 0)
315 		{
316 			fprintf(stderr, "Cannot open disk %s (%s)\n",
317 				disk, sys_errlist[errno]);
318 			exit(1);
319 		}
320 	}
321 	else
322 	{
323 		int i, rv = 0;
324 
325 		for(i = 0; disks[i]; i++)
326 		{
327 			disk = disks[i];
328 			rv = open_disk(u_flag);
329 			if(rv != -2) break;
330 		}
331 		if(rv < 0)
332 		{
333 			fprintf(stderr, "Cannot open any disk (%s)\n",
334 				sys_errlist[errno]);
335 			exit(1);
336 		}
337 	}
338 
339 	printf("******* Working on device %s *******\n",disk);
340 
341 	if (f_flag)
342 	{
343 	    if (read_s0() || i_flag)
344 	    {
345 		reset_boot();
346 	    }
347 
348 	    if (!read_config(f_flag))
349 	    {
350 		exit(1);
351 	    }
352 	    if (v_flag)
353 	    {
354 		print_s0(-1);
355 	    }
356 	    if (!t_flag)
357 	    {
358 		write_s0();
359 	    }
360 	}
361 	else
362 	{
363 	    if(u_flag)
364 	    {
365 		get_params_to_use();
366 	    }
367 	    else
368 	    {
369 		print_params();
370 	    }
371 
372 	    if (read_s0())
373 		init_sector0(1);
374 
375 	    printf("Media sector size is %d\n", secsize);
376 	    printf("Warning: BIOS sector numbering starts with sector 1\n");
377 	    printf("Information from DOS bootblock is:\n");
378 	    if (partition == -1)
379 		for (i = 1; i <= NDOSPART; i++)
380 		    change_part(i);
381 	    else
382 		change_part(partition);
383 
384 	    if (u_flag || a_flag)
385 		change_active(partition);
386 
387 	    if (u_flag || a_flag) {
388 		if (!t_flag)
389 		{
390 		    printf("\nWe haven't changed the partition table yet.  ");
391 		    printf("This is your last chance.\n");
392 		}
393 		print_s0(-1);
394 		if (!t_flag)
395 		{
396 		    if (ok("Should we write new partition table?"))
397 			write_s0();
398 		}
399 		else
400 		{
401 		    printf("\n-t flag specified -- partition table not written.\n");
402 		}
403 	    }
404 	}
405 
406 	exit(0);
407 
408 usage:
409 	printf("fdisk {-a|-i|-u} [-f <config file> [-t] [-v]] [-{1,2,3,4}] [disk]\n");
410 	return(1);
411 }
412 
413 static void
414 print_s0(int which)
415 {
416 int	i;
417 
418 	print_params();
419 	printf("Information from DOS bootblock is:\n");
420 	if (which == -1)
421 		for (i = 1; i <= NDOSPART; i++)
422 			printf("%d: ", i), print_part(i);
423 	else
424 		print_part(which);
425 }
426 
427 static struct dos_partition mtpart = { 0 };
428 
429 static void
430 print_part(int i)
431 {
432 	struct	  dos_partition *partp;
433 	u_int64_t part_mb;
434 
435 	partp = ((struct dos_partition *) &mboot.parts) + i - 1;
436 
437 	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
438 		printf("<UNUSED>\n");
439 		return;
440 	}
441 	/*
442 	 * Be careful not to overflow.
443 	 */
444 	part_mb = partp->dp_size;
445 	part_mb *= secsize;
446 	part_mb /= (1024 * 1024);
447 	printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ));
448 	printf("    start %ld, size %ld (%qd Meg), flag %x\n",
449 		partp->dp_start,
450 		partp->dp_size,
451 		part_mb,
452 		partp->dp_flag);
453 	printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n"
454 		,DPCYL(partp->dp_scyl, partp->dp_ssect)
455 		,DPSECT(partp->dp_ssect)
456 		,partp->dp_shd
457 		,DPCYL(partp->dp_ecyl, partp->dp_esect)
458 		,DPSECT(partp->dp_esect)
459 		,partp->dp_ehd);
460 }
461 
462 
463 static void
464 init_boot(void)
465 {
466 	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
467 	mboot.signature = BOOT_MAGIC;
468 }
469 
470 
471 static void
472 init_sector0(unsigned long start)
473 {
474 struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
475 unsigned long size = disksecs - start;
476 
477 	init_boot();
478 
479 	partp->dp_typ = DOSPTYP_386BSD;
480 	partp->dp_flag = ACTIVE;
481 	partp->dp_start = start;
482 	partp->dp_size = size;
483 
484 	dos(partp->dp_start, partp->dp_size,
485 	    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
486 	dos(partp->dp_start + partp->dp_size - 1, partp->dp_size,
487 	    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
488 }
489 
490 static void
491 change_part(int i)
492 {
493 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1;
494 
495     printf("The data for partition %d is:\n", i);
496     print_part(i);
497 
498     if (u_flag && ok("Do you want to change it?")) {
499 	int tmp;
500 
501 	if (i_flag) {
502 		bzero((char *)partp, sizeof (struct dos_partition));
503 		if (i == 4) {
504 			init_sector0(1);
505 			printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n");
506 			print_part(i);
507 		}
508 	}
509 
510 	do {
511 		Decimal("sysid", partp->dp_typ, tmp);
512 		Decimal("start", partp->dp_start, tmp);
513 		Decimal("size", partp->dp_size, tmp);
514 
515 		if (ok("Explicitly specifiy beg/end address ?"))
516 		{
517 			int	tsec,tcyl,thd;
518 			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
519 			thd = partp->dp_shd;
520 			tsec = DPSECT(partp->dp_ssect);
521 			Decimal("beginning cylinder", tcyl, tmp);
522 			Decimal("beginning head", thd, tmp);
523 			Decimal("beginning sector", tsec, tmp);
524 			partp->dp_scyl = DOSCYL(tcyl);
525 			partp->dp_ssect = DOSSECT(tsec,tcyl);
526 			partp->dp_shd = thd;
527 
528 			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
529 			thd = partp->dp_ehd;
530 			tsec = DPSECT(partp->dp_esect);
531 			Decimal("ending cylinder", tcyl, tmp);
532 			Decimal("ending head", thd, tmp);
533 			Decimal("ending sector", tsec, tmp);
534 			partp->dp_ecyl = DOSCYL(tcyl);
535 			partp->dp_esect = DOSSECT(tsec,tcyl);
536 			partp->dp_ehd = thd;
537 		} else {
538 			dos(partp->dp_start, partp->dp_size,
539 			    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
540 			dos(partp->dp_start + partp->dp_size - 1, partp->dp_size,
541 			    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
542 		}
543 
544 		print_part(i);
545 	} while (!ok("Are we happy with this entry?"));
546     }
547 }
548 
549 static void
550 print_params()
551 {
552 	printf("parameters extracted from in-core disklabel are:\n");
553 	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
554 			,cyls,heads,sectors,cylsecs);
555 	if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
556 		printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
557 	printf("parameters to be used for BIOS calculations are:\n");
558 	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
559 		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
560 }
561 
562 static void
563 change_active(int which)
564 {
565 int i;
566 int active = 4, tmp;
567 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts);
568 
569 	if (a_flag && which != -1)
570 		active = which;
571 	if (!ok("Do you want to change the active partition?"))
572 		return;
573 	do
574 		Decimal("active partition", active, tmp);
575 	while (!ok("Are you happy with this choice"));
576 	for (i = 0; i < NDOSPART; i++)
577 		partp[i].dp_flag = 0;
578 	if (active > 0 && active <= NDOSPART)
579 		partp[active-1].dp_flag = ACTIVE;
580 }
581 
582 void
583 get_params_to_use()
584 {
585 	int	tmp;
586 	print_params();
587 	if (ok("Do you want to change our idea of what BIOS thinks ?"))
588 	{
589 		do
590 		{
591 			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
592 			Decimal("BIOS's idea of #heads", dos_heads, tmp);
593 			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
594 			dos_cylsecs = dos_heads * dos_sectors;
595 			print_params();
596 		}
597 		while(!ok("Are you happy with this choice"));
598 	}
599 }
600 
601 
602 /***********************************************\
603 * Change real numbers into strange dos numbers	*
604 \***********************************************/
605 static void
606 dos(sec, size, c, s, h)
607 int sec, size;
608 unsigned char *c, *s, *h;
609 {
610 int cy;
611 int hd;
612 
613 	if (sec == 0 && size == 0) {
614 		*s = *c = *h = 0;
615 		return;
616 	}
617 
618 	cy = sec / ( dos_cylsecs );
619 	sec = sec - cy * ( dos_cylsecs );
620 
621 	hd = sec / dos_sectors;
622 	sec = (sec - hd * dos_sectors) + 1;
623 
624 	*h = hd;
625 	*c = cy & 0xff;
626 	*s = (sec & 0x3f) | ( (cy & 0x300) >> 2);
627 }
628 
629 int fd;
630 
631 	/* Getting device status */
632 
633 static int
634 open_disk(int u_flag)
635 {
636 struct stat 	st;
637 
638 	if (stat(disk, &st) == -1) {
639 		fprintf(stderr, "%s: Can't get file status of %s\n",
640 			name, disk);
641 		return -1;
642 	}
643 	if ( !(st.st_mode & S_IFCHR) )
644 		fprintf(stderr,"%s: Device %s is not character special\n",
645 			name, disk);
646 	if ((fd = open(disk, a_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) {
647 		if(errno == ENXIO)
648 			return -2;
649 		fprintf(stderr,"%s: Can't open device %s\n", name, disk);
650 		return -1;
651 	}
652 	if (get_params(0) == -1) {
653 		fprintf(stderr, "%s: Can't get disk parameters on %s\n",
654 			name, disk);
655 		return -1;
656 	}
657 	return fd;
658 }
659 
660 static ssize_t
661 read_disk(off_t sector, void *buf)
662 {
663 	lseek(fd,(sector * 512), 0);
664 	if( secsize == 0 )
665 		for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 )
666 			{
667 			/* try the read */
668 			int size = read(fd, buf, secsize);
669 			if( size == secsize )
670 				/* it worked so return */
671 				return secsize;
672 			}
673 	else
674 		return read( fd, buf, secsize );
675 
676 	/* we failed to read at any of the sizes */
677 	return -1;
678 }
679 
680 static ssize_t
681 write_disk(off_t sector, void *buf)
682 {
683 	lseek(fd,(sector * 512), 0);
684 	/* write out in the size that the read_disk found worked */
685 	return write(fd, buf, secsize);
686 }
687 
688 static int
689 get_params()
690 {
691 
692     if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
693 	fprintf(stderr,
694 		"%s: Can't get disk parameters on %s; supplying dummy ones\n",
695 		name, disk);
696 	dos_cyls = cyls = 1;
697 	dos_heads = heads = 1;
698 	dos_sectors = sectors = 1;
699 	dos_cylsecs = cylsecs = heads * sectors;
700 	disksecs = cyls * heads * sectors;
701 	return disksecs;
702     }
703 
704     dos_cyls = cyls = disklabel.d_ncylinders;
705     dos_heads = heads = disklabel.d_ntracks;
706     dos_sectors = sectors = disklabel.d_nsectors;
707     dos_cylsecs = cylsecs = heads * sectors;
708     disksecs = cyls * heads * sectors;
709 
710     return (disksecs);
711 }
712 
713 
714 static int
715 read_s0()
716 {
717 	if (read_disk(0, (char *) mboot.bootinst) == -1) {
718 		fprintf(stderr, "%s: Can't read fdisk partition table\n", name);
719 		return -1;
720 	}
721 	if (mboot.signature != BOOT_MAGIC) {
722 		fprintf(stderr, "%s: Invalid fdisk partition table found\n",
723 			name);
724 		/* So should we initialize things */
725 		return -1;
726 	}
727 	return 0;
728 }
729 
730 static int
731 write_s0()
732 {
733 	int	flag;
734 	if (iotest) {
735 		print_s0(-1);
736 		return 0;
737 	}
738 	/*
739 	 * write enable label sector before write (if necessary),
740 	 * disable after writing.
741 	 * needed if the disklabel protected area also protects
742 	 * sector 0. (e.g. empty disk)
743 	 */
744 	flag = 1;
745 #ifdef NOT_NOW
746 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
747 		perror("ioctl DIOCWLABEL");
748 #endif
749 	if (write_disk(0, (char *) mboot.bootinst) == -1) {
750 		fprintf(stderr, "%s: Can't write fdisk partition table\n",
751 			name);
752 		return -1;
753 	flag = 0;
754 #ifdef NOT_NOW
755 	(void) ioctl(fd, DIOCWLABEL, &flag);
756 #endif
757 	}
758 	return(0);
759 }
760 
761 
762 static int
763 ok(str)
764 char *str;
765 {
766 	printf("%s [n] ", str);
767 	fgets(lbuf, LBUF, stdin);
768 	lbuf[strlen(lbuf)-1] = 0;
769 
770 	if (*lbuf &&
771 		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
772 		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
773 		return 1;
774 	else
775 		return 0;
776 }
777 
778 static int
779 decimal(char *str, int *num, int deflt)
780 {
781 int acc = 0, c;
782 char *cp;
783 
784 	while (1) {
785 		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
786 		fgets(lbuf, LBUF, stdin);
787 		lbuf[strlen(lbuf)-1] = 0;
788 
789 		if (!*lbuf)
790 			return 0;
791 
792 		cp = lbuf;
793 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
794 		if (!c)
795 			return 0;
796 		while ((c = *cp++)) {
797 			if (c <= '9' && c >= '0')
798 				acc = acc * 10 + c - '0';
799 			else
800 				break;
801 		}
802 		if (c == ' ' || c == '\t')
803 			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
804 		if (!c) {
805 			*num = acc;
806 			return 1;
807 		} else
808 			printf("%s is an invalid decimal number.  Try again\n",
809 				lbuf);
810 	}
811 
812 }
813 
814 #if 0
815 static int
816 hex(char *str, int *num, int deflt)
817 {
818 int acc = 0, c;
819 char *cp;
820 
821 	while (1) {
822 		printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
823 		fgets(lbuf, LBUF, stdin);
824 		lbuf[strlen(lbuf)-1] = 0;
825 
826 		if (!*lbuf)
827 			return 0;
828 
829 		cp = lbuf;
830 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
831 		if (!c)
832 			return 0;
833 		while ((c = *cp++)) {
834 			if (c <= '9' && c >= '0')
835 				acc = (acc << 4) + c - '0';
836 			else if (c <= 'f' && c >= 'a')
837 				acc = (acc << 4) + c - 'a' + 10;
838 			else if (c <= 'F' && c >= 'A')
839 				acc = (acc << 4) + c - 'A' + 10;
840 			else
841 				break;
842 		}
843 		if (c == ' ' || c == '\t')
844 			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
845 		if (!c) {
846 			*num = acc;
847 			return 1;
848 		} else
849 			printf("%s is an invalid hex number.  Try again\n",
850 				lbuf);
851 	}
852 
853 }
854 
855 static int
856 string(char *str, char **ans)
857 {
858 int c;
859 char *cp = lbuf;
860 
861 	while (1) {
862 		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
863 		fgets(lbuf, LBUF, stdin);
864 		lbuf[strlen(lbuf)-1] = 0;
865 
866 		if (!*lbuf)
867 			return 0;
868 
869 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
870 		if (c == '"') {
871 			c = *++cp;
872 			*ans = cp;
873 			while ((c = *cp) && c != '"') cp++;
874 		} else {
875 			*ans = cp;
876 			while ((c = *cp) && c != ' ' && c != '\t') cp++;
877 		}
878 
879 		if (c)
880 			*cp = 0;
881 		return 1;
882 	}
883 }
884 #endif
885 
886 static char *
887 get_type(int type)
888 {
889 	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
890 	int	counter = 0;
891 	struct	part_type *ptr = part_types;
892 
893 
894 	while(counter < numentries)
895 	{
896 		if(ptr->type == type)
897 		{
898 			return(ptr->name);
899 		}
900 		ptr++;
901 		counter++;
902 	}
903 	return("unknown");
904 }
905 
906 
907 static void
908 parse_config_line(line, command)
909     char	*line;
910     CMD		*command;
911 {
912     char	*cp, *end;
913 
914     cp = line;
915     while (1)	/* dirty trick used to insure one exit point for this
916 		   function */
917     {
918 	memset(command, 0, sizeof(*command));
919 
920 	while (isspace(*cp)) ++cp;
921 	if (*cp == '\0' || *cp == '#')
922 	{
923 	    break;
924 	}
925 	command->cmd = *cp++;
926 
927 	/*
928 	 * Parse args
929 	 */
930 	while (1)
931 	{
932 	    while (isspace(*cp)) ++cp;
933 	    if (*cp == '#')
934 	    {
935 		break;		/* found comment */
936 	    }
937 	    if (isalpha(*cp))
938 	    {
939 		command->args[command->n_args].argtype = *cp++;
940 	    }
941 	    if (!isdigit(*cp))
942 	    {
943 		break;		/* assume end of line */
944 	    }
945 	    end = NULL;
946 	    command->args[command->n_args].arg_val = strtol(cp, &end, 0);
947 	    if (cp == end)
948 	    {
949 		break;		/* couldn't parse number */
950 	    }
951 	    cp = end;
952 	    command->n_args++;
953 	}
954 	break;
955     }
956 }
957 
958 
959 static int
960 process_geometry(command)
961     CMD		*command;
962 {
963     int		status = 1, i;
964 
965     while (1)
966     {
967 	geom_processed = 1;
968 	if (part_processed)
969 	{
970 	    fprintf(stderr,
971 		    "%s: ERROR line %d: the geometry specification line must occur before\n\
972     all partition specifications.\n",
973 		    name, current_line_number);
974 	    status = 0;
975 	    break;
976 	}
977 	if (command->n_args != 3)
978 	{
979 	    fprintf(stderr,
980 		    "%s: ERROR line %d: incorrect number of geometry args\n",
981 		    name, current_line_number);
982 	    status = 0;
983 	    break;
984 	}
985 	dos_cyls = -1;
986 	dos_heads = -1;
987 	dos_sectors = -1;
988 	for (i = 0; i < 3; ++i)
989 	{
990 	    switch (command->args[i].argtype)
991 	    {
992 	    case 'c':
993 		dos_cyls = command->args[i].arg_val;
994 		break;
995 	    case 'h':
996 		dos_heads = command->args[i].arg_val;
997 		break;
998 	    case 's':
999 		dos_sectors = command->args[i].arg_val;
1000 		break;
1001 	    default:
1002 		fprintf(stderr,
1003 			"%s: ERROR line %d: unknown geometry arg type: '%c' (0x%02x)\n",
1004 			name, current_line_number, command->args[i].argtype,
1005 			command->args[i].argtype);
1006 		status = 0;
1007 		break;
1008 	    }
1009 	}
1010 	if (status == 0)
1011 	{
1012 	    break;
1013 	}
1014 
1015 	dos_cylsecs = dos_heads * dos_sectors;
1016 
1017 	/*
1018 	 * Do sanity checks on parameter values
1019 	 */
1020 	if (dos_cyls < 0)
1021 	{
1022 	    fprintf(stderr,
1023 		    "%s: ERROR line %d: number of cylinders not specified\n",
1024 		    name, current_line_number);
1025 	    status = 0;
1026 	}
1027 	if (dos_cyls == 0 || dos_cyls > 1024)
1028 	{
1029 	    fprintf(stderr,
1030 		    "%s: WARNING line %d: number of cylinders (%d) may be out-of-range\n\
1031     (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\
1032     is dedicated to FreeBSD).\n",
1033 		    name, current_line_number, dos_cyls);
1034 	}
1035 
1036 	if (dos_heads < 0)
1037 	{
1038 	    fprintf(stderr,
1039 		    "%s: ERROR line %d: number of heads not specified\n",
1040 		    name, current_line_number);
1041 	    status = 0;
1042 	}
1043 	else if (dos_heads < 1 || dos_heads > 256)
1044 	{
1045 	    fprintf(stderr,
1046 		    "%s: ERROR line %d: number of heads must be within (1-256)\n",
1047 		    name, current_line_number);
1048 	    status = 0;
1049 	}
1050 
1051 	if (dos_sectors < 0)
1052 	{
1053 	    fprintf(stderr, "%s: ERROR line %d: number of sectors not specified\n",
1054 		    name, current_line_number);
1055 	    status = 0;
1056 	}
1057 	else if (dos_sectors < 1 || dos_sectors > 63)
1058 	{
1059 	    fprintf(stderr,
1060 		    "%s: ERROR line %d: number of sectors must be within (1-63)\n",
1061 		    name, current_line_number);
1062 	    status = 0;
1063 	}
1064 
1065 	break;
1066     }
1067     return (status);
1068 }
1069 
1070 
1071 static int
1072 process_partition(command)
1073     CMD		*command;
1074 {
1075     int				status = 0, partition;
1076     unsigned long		chunks, adj_size, max_end;
1077     struct dos_partition	*partp;
1078 
1079     while (1)
1080     {
1081 	part_processed = 1;
1082 	if (command->n_args != 4)
1083 	{
1084 	    fprintf(stderr,
1085 		    "%s: ERROR line %d: incorrect number of partition args\n",
1086 		    name, current_line_number);
1087 	    break;
1088 	}
1089 	partition = command->args[0].arg_val;
1090 	if (partition < 1 || partition > 4)
1091 	{
1092 	    fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n",
1093 		    name, current_line_number, partition);
1094 	    break;
1095 	}
1096 	partp = ((struct dos_partition *) &mboot.parts) + partition - 1;
1097 	bzero((char *)partp, sizeof (struct dos_partition));
1098 	partp->dp_typ = command->args[1].arg_val;
1099 	partp->dp_start = command->args[2].arg_val;
1100 	partp->dp_size = command->args[3].arg_val;
1101 	max_end = partp->dp_start + partp->dp_size;
1102 
1103 	if (partp->dp_typ == 0)
1104 	{
1105 	    /*
1106 	     * Get out, the partition is marked as unused.
1107 	     */
1108 	    /*
1109 	     * Insure that it's unused.
1110 	     */
1111 	    bzero((char *)partp, sizeof (struct dos_partition));
1112 	    status = 1;
1113 	    break;
1114 	}
1115 
1116 	/*
1117 	 * Adjust start upwards, if necessary, to fall on an head boundary.
1118 	 */
1119 	if (partp->dp_start % dos_sectors != 0)
1120 	{
1121 	    adj_size =
1122 		(partp->dp_start / dos_sectors + 1) * dos_sectors;
1123 	    if (adj_size > max_end)
1124 	    {
1125 		/*
1126 		 * Can't go past end of partition
1127 		 */
1128 		fprintf(stderr,
1129 			"%s: ERROR line %d: unable to adjust start of partition %d to fall on\n\
1130     a cylinder boundary.\n",
1131 			name, current_line_number, partition);
1132 		break;
1133 	    }
1134 	    fprintf(stderr,
1135 		    "%s: WARNING: adjusting start offset of partition '%d' from %d\n\
1136     to %d, to round to an head boundary.\n",
1137 		    name, partition, partp->dp_start, adj_size);
1138 	    partp->dp_start = adj_size;
1139 	}
1140 
1141 	/*
1142 	 * Adjust size downwards, if necessary, to fall on a cylinder
1143 	 * boundary.
1144 	 */
1145 	chunks =
1146 	    ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs;
1147 	adj_size = chunks - partp->dp_start;
1148 	if (adj_size != partp->dp_size)
1149 	{
1150 	    fprintf(stderr,
1151 		    "%s: WARNING: adjusting size of partition '%d' from %d to %d,\n\
1152     to round to a cylinder boundary.\n",
1153 		    name, partition, partp->dp_size, adj_size);
1154 	    if (chunks > 0)
1155 	    {
1156 		partp->dp_size = adj_size;
1157 	    }
1158 	    else
1159 	    {
1160 		partp->dp_size = 0;
1161 	    }
1162 	}
1163 	if (partp->dp_size < 1)
1164 	{
1165 	    fprintf(stderr,
1166 		    "%s: ERROR line %d: size for partition '%d' is zero.\n",
1167 		    name, current_line_number, partition);
1168 	    break;
1169 	}
1170 
1171 	dos(partp->dp_start, partp->dp_size,
1172 	    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
1173 	dos(partp->dp_start+partp->dp_size - 1, partp->dp_size,
1174 	    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
1175 	status = 1;
1176 	break;
1177     }
1178     return (status);
1179 }
1180 
1181 
1182 static int
1183 process_active(command)
1184     CMD		*command;
1185 {
1186     int				status = 0, partition, i;
1187     struct dos_partition	*partp;
1188 
1189     while (1)
1190     {
1191 	active_processed = 1;
1192 	if (command->n_args != 1)
1193 	{
1194 	    fprintf(stderr,
1195 		    "%s: ERROR line %d: incorrect number of active args\n",
1196 		    name, current_line_number);
1197 	    status = 0;
1198 	    break;
1199 	}
1200 	partition = command->args[0].arg_val;
1201 	if (partition < 1 || partition > 4)
1202 	{
1203 	    fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n",
1204 		    name, current_line_number, partition);
1205 	    break;
1206 	}
1207 	/*
1208 	 * Reset active partition
1209 	 */
1210 	partp = ((struct dos_partition *) &mboot.parts);
1211 	for (i = 0; i < NDOSPART; i++)
1212 	    partp[i].dp_flag = 0;
1213 	partp[partition-1].dp_flag = ACTIVE;
1214 
1215 	status = 1;
1216 	break;
1217     }
1218     return (status);
1219 }
1220 
1221 
1222 static int
1223 process_line(line)
1224     char	*line;
1225 {
1226     CMD		command;
1227     int		status = 1;
1228 
1229     while (1)
1230     {
1231 	parse_config_line(line, &command);
1232 	switch (command.cmd)
1233 	{
1234 	case 0:
1235 	    /*
1236 	     * Comment or blank line
1237 	     */
1238 	    break;
1239 	case 'g':
1240 	    /*
1241 	     * Set geometry
1242 	     */
1243 	    status = process_geometry(&command);
1244 	    break;
1245 	case 'p':
1246 	    status = process_partition(&command);
1247 	    break;
1248 	case 'a':
1249 	    status = process_active(&command);
1250 	    break;
1251 	default:
1252 	    status = 0;
1253 	    break;
1254 	}
1255 	break;
1256     }
1257     return (status);
1258 }
1259 
1260 
1261 static int
1262 read_config(config_file)
1263     char *config_file;
1264 {
1265     FILE	*fp = NULL;
1266     int		status = 1;
1267     char	buf[1010];
1268 
1269     while (1)	/* dirty trick used to insure one exit point for this
1270 		   function */
1271     {
1272 	if (strcmp(config_file, "-") != 0)
1273 	{
1274 	    /*
1275 	     * We're not reading from stdin
1276 	     */
1277 	    if ((fp = fopen(config_file, "r")) == NULL)
1278 	    {
1279 		status = 0;
1280 		break;
1281 	    }
1282 	}
1283 	else
1284 	{
1285 	    fp = stdin;
1286 	}
1287 	current_line_number = 0;
1288 	while (!feof(fp))
1289 	{
1290 	    if (fgets(buf, sizeof(buf), fp) == NULL)
1291 	    {
1292 		break;
1293 	    }
1294 	    ++current_line_number;
1295 	    status = process_line(buf);
1296 	    if (status == 0)
1297 	    {
1298 		break;
1299 	    }
1300 	}
1301 	break;
1302     }
1303     if (fp)
1304     {
1305 	/*
1306 	 * It doesn't matter if we're reading from stdin, as we've reached EOF
1307 	 */
1308 	fclose(fp);
1309     }
1310     return (status);
1311 }
1312 
1313 
1314 static void
1315 reset_boot(void)
1316 {
1317     int				i;
1318     struct dos_partition	*partp;
1319 
1320     init_boot();
1321     for (i = 0; i < 4; ++i)
1322     {
1323 	partp = ((struct dos_partition *) &mboot.parts) + i;
1324 	bzero((char *)partp, sizeof (struct dos_partition));
1325     }
1326 }
1327