xref: /freebsd/sbin/fdisk/fdisk.c (revision 61afd5bb22d787b0641523e7b9b95c964d669bd5)
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 	,{0xA7, "NEXTSTEP"}
193 	,{0xB7, "BSDI BSD/386 filesystem"}
194 	,{0xB8, "BSDI BSD/386 swap"}
195 	,{0xDB, "Concurrent CPM or C.DOS or CTOS"}
196 	,{0xE1, "Speed"}
197 	,{0xE3, "Speed"}
198 	,{0xE4, "Speed"}
199 	,{0xF1, "Speed"}
200 	,{0xF2, "DOS 3.3+ Secondary"}
201 	,{0xF4, "Speed"}
202 	,{0xFF, "BBT (Bad Blocks Table)"}
203 };
204 
205 static void print_s0(int which);
206 static void print_part(int i);
207 static void init_sector0(unsigned long start);
208 static void init_boot(void);
209 static void change_part(int i);
210 static void print_params();
211 static void change_active(int which);
212 static void get_params_to_use();
213 static void dos(int sec, int size, unsigned char *c, unsigned char *s,
214 		unsigned char *h);
215 static int open_disk(int u_flag);
216 static ssize_t read_disk(off_t sector, void *buf);
217 static ssize_t write_disk(off_t sector, void *buf);
218 static int get_params();
219 static int read_s0();
220 static int write_s0();
221 static int ok(char *str);
222 static int decimal(char *str, int *num, int deflt);
223 static char *get_type(int type);
224 static int read_config(char *config_file);
225 static void reset_boot(void);
226 #if 0
227 static int hex(char *str, int *num, int deflt);
228 static int string(char *str, char **ans);
229 #endif
230 
231 
232 int
233 main(int argc, char *argv[])
234 {
235 	int	i;
236 
237 	name = *argv;
238 	{register char *cp = name;
239 		while (*cp) if (*cp++ == '/') name = cp;
240 	}
241 
242 	for ( argv++ ; --argc ; argv++ ) { register char *token = *argv;
243 		if (*token++ != '-' || !*token)
244 			break;
245 		else { register int flag;
246 			for ( ; (flag = *token++) ; ) {
247 				switch (flag) {
248 				case '0':
249 					partition = 0;
250 					break;
251 				case '1':
252 					partition = 1;
253 					break;
254 				case '2':
255 					partition = 2;
256 					break;
257 				case '3':
258 					partition = 3;
259 					break;
260 				case 'a':
261 					a_flag = 1;
262 					break;
263 				case 'f':
264 					if (*token)
265 					{
266 					    f_flag = token;
267 					    token = "";
268 					}
269 					else
270 					{
271 					    if (argc == 1)
272 					    {
273 						goto usage;
274 					    }
275 					    --argc;
276 					    f_flag = *++argv;
277 					}
278 					/*
279 					 * u_flag is needed, because we're
280 					 * writing to the disk.
281 					 */
282 					u_flag = 1;
283 					break;
284 				case 'i':
285 					i_flag = 1;
286 				case 'u':
287 					u_flag = 1;
288 					break;
289 				case 't':
290 					t_flag = 1;
291 				case 'v':
292 					v_flag = 1;
293 					break;
294 				default:
295 					goto usage;
296 				}
297 			}
298 		}
299 	}
300 
301 	if (argc > 0)
302 	{
303 		static char realname[12];
304 
305 		if(strncmp(argv[0], "/dev", 4) == 0)
306 			disk = argv[0];
307 		else
308 		{
309 			snprintf(realname, 12, "/dev/r%s", argv[0]);
310 			disk = realname;
311 		}
312 
313 		if (open_disk(u_flag) < 0)
314 		{
315 			fprintf(stderr, "Cannot open disk %s (%s)\n",
316 				disk, sys_errlist[errno]);
317 			exit(1);
318 		}
319 	}
320 	else
321 	{
322 		int i, rv = 0;
323 
324 		for(i = 0; disks[i]; i++)
325 		{
326 			disk = disks[i];
327 			rv = open_disk(u_flag);
328 			if(rv != -2) break;
329 		}
330 		if(rv < 0)
331 		{
332 			fprintf(stderr, "Cannot open any disk (%s)\n",
333 				sys_errlist[errno]);
334 			exit(1);
335 		}
336 	}
337 
338 	printf("******* Working on device %s *******\n",disk);
339 
340 	if (f_flag)
341 	{
342 	    if (read_s0() || i_flag)
343 	    {
344 		reset_boot();
345 	    }
346 
347 	    if (!read_config(f_flag))
348 	    {
349 		exit(1);
350 	    }
351 	    if (v_flag)
352 	    {
353 		print_s0(-1);
354 	    }
355 	    if (!t_flag)
356 	    {
357 		write_s0();
358 	    }
359 	}
360 	else
361 	{
362 	    if(u_flag)
363 	    {
364 		get_params_to_use();
365 	    }
366 	    else
367 	    {
368 		print_params();
369 	    }
370 
371 	    if (read_s0())
372 		init_sector0(1);
373 
374 	    printf("Media sector size is %d\n", secsize);
375 	    printf("Warning: BIOS sector numbering starts with sector 1\n");
376 	    printf("Information from DOS bootblock is:\n");
377 	    if (partition == -1)
378 		for (i = 0; i < NDOSPART; i++)
379 		    change_part(i);
380 	    else
381 		change_part(partition);
382 
383 	    if (u_flag || a_flag)
384 		change_active(partition);
385 
386 	    if (u_flag || a_flag) {
387 		if (!t_flag)
388 		{
389 		    printf("\nWe haven't changed the partition table yet.  ");
390 		    printf("This is your last chance.\n");
391 		}
392 		print_s0(-1);
393 		if (!t_flag)
394 		{
395 		    if (ok("Should we write new partition table?"))
396 			write_s0();
397 		}
398 		else
399 		{
400 		    printf("\n-t flag specified -- partition table not written.\n");
401 		}
402 	    }
403 	}
404 
405 	exit(0);
406 
407 usage:
408 	printf("fdisk {-a|-i|-u} [-f <config file> [-t] [-v]] [-{0,1,2,3}] [disk]\n");
409 	return(1);
410 }
411 
412 static void
413 print_s0(int which)
414 {
415 int	i;
416 
417 	print_params();
418 	printf("Information from DOS bootblock is:\n");
419 	if (which == -1)
420 		for (i = 0; i < NDOSPART; i++)
421 			printf("%d: ", i), print_part(i);
422 	else
423 		print_part(which);
424 }
425 
426 static struct dos_partition mtpart = { 0 };
427 
428 static void
429 print_part(int i)
430 {
431 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
432 
433 
434 	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
435 		printf("<UNUSED>\n");
436 		return;
437 	}
438 	printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ));
439 	printf("    start %ld, size %ld (%ld Meg), flag %x\n",
440 		partp->dp_start,
441 		partp->dp_size, partp->dp_size * secsize / (1024 * 1024),
442 		partp->dp_flag);
443 	printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n"
444 		,DPCYL(partp->dp_scyl, partp->dp_ssect)
445 		,DPSECT(partp->dp_ssect)
446 		,partp->dp_shd
447 		,DPCYL(partp->dp_ecyl, partp->dp_esect)
448 		,DPSECT(partp->dp_esect)
449 		,partp->dp_ehd);
450 }
451 
452 
453 static void
454 init_boot(void)
455 {
456 	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
457 	mboot.signature = BOOT_MAGIC;
458 }
459 
460 
461 static void
462 init_sector0(unsigned long start)
463 {
464 struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
465 unsigned long size = disksecs - start;
466 
467 	init_boot();
468 
469 	partp->dp_typ = DOSPTYP_386BSD;
470 	partp->dp_flag = ACTIVE;
471 	partp->dp_start = start;
472 	partp->dp_size = size;
473 
474 	dos(partp->dp_start, partp->dp_size,
475 	    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
476 	dos(partp->dp_start + partp->dp_size - 1, partp->dp_size,
477 	    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
478 }
479 
480 static void
481 change_part(int i)
482 {
483 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
484 
485     printf("The data for partition %d is:\n", i);
486     print_part(i);
487 
488     if (u_flag && ok("Do you want to change it?")) {
489 	int tmp;
490 
491 	if (i_flag) {
492 		bzero((char *)partp, sizeof (struct dos_partition));
493 		if (i == 3) {
494 			init_sector0(1);
495 			printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
496 			print_part(i);
497 		}
498 	}
499 
500 	do {
501 		Decimal("sysid", partp->dp_typ, tmp);
502 		Decimal("start", partp->dp_start, tmp);
503 		Decimal("size", partp->dp_size, tmp);
504 
505 		if (ok("Explicitly specifiy beg/end address ?"))
506 		{
507 			int	tsec,tcyl,thd;
508 			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
509 			thd = partp->dp_shd;
510 			tsec = DPSECT(partp->dp_ssect);
511 			Decimal("beginning cylinder", tcyl, tmp);
512 			Decimal("beginning head", thd, tmp);
513 			Decimal("beginning sector", tsec, tmp);
514 			partp->dp_scyl = DOSCYL(tcyl);
515 			partp->dp_ssect = DOSSECT(tsec,tcyl);
516 			partp->dp_shd = thd;
517 
518 			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
519 			thd = partp->dp_ehd;
520 			tsec = DPSECT(partp->dp_esect);
521 			Decimal("ending cylinder", tcyl, tmp);
522 			Decimal("ending head", thd, tmp);
523 			Decimal("ending sector", tsec, tmp);
524 			partp->dp_ecyl = DOSCYL(tcyl);
525 			partp->dp_esect = DOSSECT(tsec,tcyl);
526 			partp->dp_ehd = thd;
527 		} else {
528 			dos(partp->dp_start, partp->dp_size,
529 			    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
530 			dos(partp->dp_start + partp->dp_size - 1, partp->dp_size,
531 			    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
532 		}
533 
534 		print_part(i);
535 	} while (!ok("Are we happy with this entry?"));
536     }
537 }
538 
539 static void
540 print_params()
541 {
542 	printf("parameters extracted from in-core disklabel are:\n");
543 	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
544 			,cyls,heads,sectors,cylsecs);
545 	if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
546 		printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
547 	printf("parameters to be used for BIOS calculations are:\n");
548 	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
549 		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
550 }
551 
552 static void
553 change_active(int which)
554 {
555 int i;
556 int active = 3, tmp;
557 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts);
558 
559 	if (a_flag && which != -1)
560 		active = which;
561 	if (!ok("Do you want to change the active partition?"))
562 		return;
563 	do
564 		Decimal("active partition", active, tmp);
565 	while (!ok("Are you happy with this choice"));
566 	for (i = 0; i < NDOSPART; i++)
567 		partp[i].dp_flag = 0;
568 	if (active >= 0 && active < NDOSPART)
569 		partp[active].dp_flag = ACTIVE;
570 }
571 
572 void
573 get_params_to_use()
574 {
575 	int	tmp;
576 	print_params();
577 	if (ok("Do you want to change our idea of what BIOS thinks ?"))
578 	{
579 		do
580 		{
581 			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
582 			Decimal("BIOS's idea of #heads", dos_heads, tmp);
583 			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
584 			dos_cylsecs = dos_heads * dos_sectors;
585 			print_params();
586 		}
587 		while(!ok("Are you happy with this choice"));
588 	}
589 }
590 
591 
592 /***********************************************\
593 * Change real numbers into strange dos numbers	*
594 \***********************************************/
595 static void
596 dos(sec, size, c, s, h)
597 int sec, size;
598 unsigned char *c, *s, *h;
599 {
600 int cy;
601 int hd;
602 
603 	if (sec == 0 && size == 0) {
604 		*s = *c = *h = 0;
605 		return;
606 	}
607 
608 	cy = sec / ( dos_cylsecs );
609 	sec = sec - cy * ( dos_cylsecs );
610 
611 	hd = sec / dos_sectors;
612 	sec = (sec - hd * dos_sectors) + 1;
613 
614 	*h = hd;
615 	*c = cy & 0xff;
616 	*s = (sec & 0x3f) | ( (cy & 0x300) >> 2);
617 }
618 
619 int fd;
620 
621 	/* Getting device status */
622 
623 static int
624 open_disk(int u_flag)
625 {
626 struct stat 	st;
627 
628 	if (stat(disk, &st) == -1) {
629 		fprintf(stderr, "%s: Can't get file status of %s\n",
630 			name, disk);
631 		return -1;
632 	}
633 	if ( !(st.st_mode & S_IFCHR) )
634 		fprintf(stderr,"%s: Device %s is not character special\n",
635 			name, disk);
636 	if ((fd = open(disk, a_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) {
637 		if(errno == ENXIO)
638 			return -2;
639 		fprintf(stderr,"%s: Can't open device %s\n", name, disk);
640 		return -1;
641 	}
642 	if (get_params(0) == -1) {
643 		fprintf(stderr, "%s: Can't get disk parameters on %s\n",
644 			name, disk);
645 		return -1;
646 	}
647 	return fd;
648 }
649 
650 static ssize_t
651 read_disk(off_t sector, void *buf)
652 {
653 	lseek(fd,(sector * 512), 0);
654 	if( secsize == 0 )
655 		for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 )
656 			{
657 			/* try the read */
658 			int size = read(fd, buf, secsize);
659 			if( size == secsize )
660 				/* it worked so return */
661 				return secsize;
662 			}
663 	else
664 		return read( fd, buf, secsize );
665 
666 	/* we failed to read at any of the sizes */
667 	return -1;
668 }
669 
670 static ssize_t
671 write_disk(off_t sector, void *buf)
672 {
673 	lseek(fd,(sector * 512), 0);
674 	/* write out in the size that the read_disk found worked */
675 	return write(fd, buf, secsize);
676 }
677 
678 static int
679 get_params()
680 {
681 
682     if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
683 	fprintf(stderr,
684 		"%s: Can't get disk parameters on %s; supplying dummy ones\n",
685 		name, disk);
686 	dos_cyls = cyls = 1;
687 	dos_heads = heads = 1;
688 	dos_sectors = sectors = 1;
689 	dos_cylsecs = cylsecs = heads * sectors;
690 	disksecs = cyls * heads * sectors;
691 	return disksecs;
692     }
693 
694     dos_cyls = cyls = disklabel.d_ncylinders;
695     dos_heads = heads = disklabel.d_ntracks;
696     dos_sectors = sectors = disklabel.d_nsectors;
697     dos_cylsecs = cylsecs = heads * sectors;
698     disksecs = cyls * heads * sectors;
699 
700     return (disksecs);
701 }
702 
703 
704 static int
705 read_s0()
706 {
707 	if (read_disk(0, (char *) mboot.bootinst) == -1) {
708 		fprintf(stderr, "%s: Can't read fdisk partition table\n", name);
709 		return -1;
710 	}
711 	if (mboot.signature != BOOT_MAGIC) {
712 		fprintf(stderr, "%s: Invalid fdisk partition table found\n",
713 			name);
714 		/* So should we initialize things */
715 		return -1;
716 	}
717 	return 0;
718 }
719 
720 static int
721 write_s0()
722 {
723 	int	flag;
724 	if (iotest) {
725 		print_s0(-1);
726 		return 0;
727 	}
728 	/*
729 	 * write enable label sector before write (if necessary),
730 	 * disable after writing.
731 	 * needed if the disklabel protected area also protects
732 	 * sector 0. (e.g. empty disk)
733 	 */
734 	flag = 1;
735 #ifdef NOT_NOW
736 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
737 		perror("ioctl DIOCWLABEL");
738 #endif
739 	if (write_disk(0, (char *) mboot.bootinst) == -1) {
740 		fprintf(stderr, "%s: Can't write fdisk partition table\n",
741 			name);
742 		return -1;
743 	flag = 0;
744 #ifdef NOT_NOW
745 	(void) ioctl(fd, DIOCWLABEL, &flag);
746 #endif
747 	}
748 	return(0);
749 }
750 
751 
752 static int
753 ok(str)
754 char *str;
755 {
756 	printf("%s [n] ", str);
757 	fgets(lbuf, LBUF, stdin);
758 	lbuf[strlen(lbuf)-1] = 0;
759 
760 	if (*lbuf &&
761 		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
762 		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
763 		return 1;
764 	else
765 		return 0;
766 }
767 
768 static int
769 decimal(char *str, int *num, int deflt)
770 {
771 int acc = 0, c;
772 char *cp;
773 
774 	while (1) {
775 		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
776 		fgets(lbuf, LBUF, stdin);
777 		lbuf[strlen(lbuf)-1] = 0;
778 
779 		if (!*lbuf)
780 			return 0;
781 
782 		cp = lbuf;
783 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
784 		if (!c)
785 			return 0;
786 		while ((c = *cp++)) {
787 			if (c <= '9' && c >= '0')
788 				acc = acc * 10 + c - '0';
789 			else
790 				break;
791 		}
792 		if (c == ' ' || c == '\t')
793 			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
794 		if (!c) {
795 			*num = acc;
796 			return 1;
797 		} else
798 			printf("%s is an invalid decimal number.  Try again\n",
799 				lbuf);
800 	}
801 
802 }
803 
804 #if 0
805 static int
806 hex(char *str, int *num, int deflt)
807 {
808 int acc = 0, c;
809 char *cp;
810 
811 	while (1) {
812 		printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
813 		fgets(lbuf, LBUF, stdin);
814 		lbuf[strlen(lbuf)-1] = 0;
815 
816 		if (!*lbuf)
817 			return 0;
818 
819 		cp = lbuf;
820 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
821 		if (!c)
822 			return 0;
823 		while ((c = *cp++)) {
824 			if (c <= '9' && c >= '0')
825 				acc = (acc << 4) + c - '0';
826 			else if (c <= 'f' && c >= 'a')
827 				acc = (acc << 4) + c - 'a' + 10;
828 			else if (c <= 'F' && c >= 'A')
829 				acc = (acc << 4) + c - 'A' + 10;
830 			else
831 				break;
832 		}
833 		if (c == ' ' || c == '\t')
834 			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
835 		if (!c) {
836 			*num = acc;
837 			return 1;
838 		} else
839 			printf("%s is an invalid hex number.  Try again\n",
840 				lbuf);
841 	}
842 
843 }
844 
845 static int
846 string(char *str, char **ans)
847 {
848 int c;
849 char *cp = lbuf;
850 
851 	while (1) {
852 		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
853 		fgets(lbuf, LBUF, stdin);
854 		lbuf[strlen(lbuf)-1] = 0;
855 
856 		if (!*lbuf)
857 			return 0;
858 
859 		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
860 		if (c == '"') {
861 			c = *++cp;
862 			*ans = cp;
863 			while ((c = *cp) && c != '"') cp++;
864 		} else {
865 			*ans = cp;
866 			while ((c = *cp) && c != ' ' && c != '\t') cp++;
867 		}
868 
869 		if (c)
870 			*cp = 0;
871 		return 1;
872 	}
873 }
874 #endif
875 
876 static char *
877 get_type(int type)
878 {
879 	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
880 	int	counter = 0;
881 	struct	part_type *ptr = part_types;
882 
883 
884 	while(counter < numentries)
885 	{
886 		if(ptr->type == type)
887 		{
888 			return(ptr->name);
889 		}
890 		ptr++;
891 		counter++;
892 	}
893 	return("unknown");
894 }
895 
896 
897 static void
898 parse_config_line(line, command)
899     char	*line;
900     CMD		*command;
901 {
902     char	*cp, *end;
903 
904     cp = line;
905     while (1)	/* dirty trick used to insure one exit point for this
906 		   function */
907     {
908 	memset(command, 0, sizeof(*command));
909 
910 	while (isspace(*cp)) ++cp;
911 	if (*cp == '\0' || *cp == '#')
912 	{
913 	    break;
914 	}
915 	command->cmd = *cp++;
916 
917 	/*
918 	 * Parse args
919 	 */
920 	while (1)
921 	{
922 	    while (isspace(*cp)) ++cp;
923 	    if (*cp == '#')
924 	    {
925 		break;		/* found comment */
926 	    }
927 	    if (isalpha(*cp))
928 	    {
929 		command->args[command->n_args].argtype = *cp++;
930 	    }
931 	    if (!isdigit(*cp))
932 	    {
933 		break;		/* assume end of line */
934 	    }
935 	    end = NULL;
936 	    command->args[command->n_args].arg_val = strtol(cp, &end, 0);
937 	    if (cp == end)
938 	    {
939 		break;		/* couldn't parse number */
940 	    }
941 	    cp = end;
942 	    command->n_args++;
943 	}
944 	break;
945     }
946 }
947 
948 
949 static int
950 process_geometry(command)
951     CMD		*command;
952 {
953     int		status = 1, i;
954 
955     while (1)
956     {
957 	geom_processed = 1;
958 	if (part_processed)
959 	{
960 	    fprintf(stderr,
961 		    "%s: ERROR line %d: the geometry specification line must occur before\n\
962     all partition specifications.\n",
963 		    name, current_line_number);
964 	    status = 0;
965 	    break;
966 	}
967 	if (command->n_args != 3)
968 	{
969 	    fprintf(stderr,
970 		    "%s: ERROR line %d: incorrect number of geometry args\n",
971 		    name, current_line_number);
972 	    status = 0;
973 	    break;
974 	}
975 	dos_cyls = -1;
976 	dos_heads = -1;
977 	dos_sectors = -1;
978 	for (i = 0; i < 3; ++i)
979 	{
980 	    switch (command->args[i].argtype)
981 	    {
982 	    case 'c':
983 		dos_cyls = command->args[i].arg_val;
984 		break;
985 	    case 'h':
986 		dos_heads = command->args[i].arg_val;
987 		break;
988 	    case 's':
989 		dos_sectors = command->args[i].arg_val;
990 		break;
991 	    default:
992 		fprintf(stderr,
993 			"%s: ERROR line %d: unknown geometry arg type: '%c' (0x%02x)\n",
994 			name, current_line_number, command->args[i].argtype,
995 			command->args[i].argtype);
996 		status = 0;
997 		break;
998 	    }
999 	}
1000 	if (status == 0)
1001 	{
1002 	    break;
1003 	}
1004 
1005 	dos_cylsecs = dos_heads * dos_sectors;
1006 
1007 	/*
1008 	 * Do sanity checks on parameter values
1009 	 */
1010 	if (dos_cyls < 0)
1011 	{
1012 	    fprintf(stderr,
1013 		    "%s: ERROR line %d: number of cylinders not specified\n",
1014 		    name, current_line_number);
1015 	    status = 0;
1016 	}
1017 	if (dos_cyls == 0 || dos_cyls > 1024)
1018 	{
1019 	    fprintf(stderr,
1020 		    "%s: WARNING line %d: number of cylinders (%d) may be out-of-range\n\
1021     (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\
1022     is dedicated to FreeBSD).\n",
1023 		    name, current_line_number, dos_cyls);
1024 	}
1025 
1026 	if (dos_heads < 0)
1027 	{
1028 	    fprintf(stderr,
1029 		    "%s: ERROR line %d: number of heads not specified\n",
1030 		    name, current_line_number);
1031 	    status = 0;
1032 	}
1033 	else if (dos_heads < 1 || dos_heads > 256)
1034 	{
1035 	    fprintf(stderr,
1036 		    "%s: ERROR line %d: number of heads must be within (1-256)\n",
1037 		    name, current_line_number);
1038 	    status = 0;
1039 	}
1040 
1041 	if (dos_sectors < 0)
1042 	{
1043 	    fprintf(stderr, "%s: ERROR line %d: number of sectors not specified\n",
1044 		    name, current_line_number);
1045 	    status = 0;
1046 	}
1047 	else if (dos_sectors < 1 || dos_sectors > 63)
1048 	{
1049 	    fprintf(stderr,
1050 		    "%s: ERROR line %d: number of sectors must be within (1-63)\n",
1051 		    name, current_line_number);
1052 	    status = 0;
1053 	}
1054 
1055 	break;
1056     }
1057     return (status);
1058 }
1059 
1060 
1061 static int
1062 process_partition(command)
1063     CMD		*command;
1064 {
1065     int				status = 0, partition;
1066     unsigned long		chunks, adj_size, max_end;
1067     struct dos_partition	*partp;
1068 
1069     while (1)
1070     {
1071 	part_processed = 1;
1072 	if (command->n_args != 4)
1073 	{
1074 	    fprintf(stderr,
1075 		    "%s: ERROR line %d: incorrect number of partition args\n",
1076 		    name, current_line_number);
1077 	    break;
1078 	}
1079 	partition = command->args[0].arg_val;
1080 	if (partition < 0 || partition > 3)
1081 	{
1082 	    fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n",
1083 		    name, current_line_number, partition);
1084 	    break;
1085 	}
1086 	partp = ((struct dos_partition *) &mboot.parts) + partition;
1087 	bzero((char *)partp, sizeof (struct dos_partition));
1088 	partp->dp_typ = command->args[1].arg_val;
1089 	partp->dp_start = command->args[2].arg_val;
1090 	partp->dp_size = command->args[3].arg_val;
1091 	max_end = partp->dp_start + partp->dp_size;
1092 
1093 	if (partp->dp_typ == 0)
1094 	{
1095 	    /*
1096 	     * Get out, the partition is marked as unused.
1097 	     */
1098 	    /*
1099 	     * Insure that it's unused.
1100 	     */
1101 	    bzero((char *)partp, sizeof (struct dos_partition));
1102 	    status = 1;
1103 	    break;
1104 	}
1105 
1106 	/*
1107 	 * Adjust start upwards, if necessary, to fall on an head boundary.
1108 	 */
1109 	if (partp->dp_start % dos_sectors != 0)
1110 	{
1111 	    adj_size =
1112 		(partp->dp_start / dos_sectors + 1) * dos_sectors;
1113 	    if (adj_size > max_end)
1114 	    {
1115 		/*
1116 		 * Can't go past end of partition
1117 		 */
1118 		fprintf(stderr,
1119 			"%s: ERROR line %d: unable to adjust start of partition %d to fall on\n\
1120     a cylinder boundary.\n",
1121 			name, current_line_number, partition);
1122 		break;
1123 	    }
1124 	    fprintf(stderr,
1125 		    "%s: WARNING: adjusting start offset of partition '%d' from %d\n\
1126     to %d, to round to an head boundary.\n",
1127 		    name, partition, partp->dp_start, adj_size);
1128 	    partp->dp_start = adj_size;
1129 	}
1130 
1131 	/*
1132 	 * Adjust size downwards, if necessary, to fall on a cylinder
1133 	 * boundary.
1134 	 */
1135 	chunks =
1136 	    ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs;
1137 	adj_size = chunks - partp->dp_start;
1138 	if (adj_size != partp->dp_size)
1139 	{
1140 	    fprintf(stderr,
1141 		    "%s: WARNING: adjusting size of partition '%d' from %d to %d,\n\
1142     to round to a cylinder boundary.\n",
1143 		    name, partition, partp->dp_size, adj_size);
1144 	    if (chunks > 0)
1145 	    {
1146 		partp->dp_size = adj_size;
1147 	    }
1148 	    else
1149 	    {
1150 		partp->dp_size = 0;
1151 	    }
1152 	}
1153 	if (partp->dp_size < 1)
1154 	{
1155 	    fprintf(stderr,
1156 		    "%s: ERROR line %d: size for partition '%d' is zero.\n",
1157 		    name, current_line_number, partition);
1158 	    break;
1159 	}
1160 
1161 	dos(partp->dp_start, partp->dp_size,
1162 	    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
1163 	dos(partp->dp_start+partp->dp_size - 1, partp->dp_size,
1164 	    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
1165 	status = 1;
1166 	break;
1167     }
1168     return (status);
1169 }
1170 
1171 
1172 static int
1173 process_active(command)
1174     CMD		*command;
1175 {
1176     int				status = 0, partition, i;
1177     struct dos_partition	*partp;
1178 
1179     while (1)
1180     {
1181 	active_processed = 1;
1182 	if (command->n_args != 1)
1183 	{
1184 	    fprintf(stderr,
1185 		    "%s: ERROR line %d: incorrect number of active args\n",
1186 		    name, current_line_number);
1187 	    status = 0;
1188 	    break;
1189 	}
1190 	partition = command->args[0].arg_val;
1191 	if (partition < 0 || partition > 3)
1192 	{
1193 	    fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n",
1194 		    name, current_line_number, partition);
1195 	    break;
1196 	}
1197 	/*
1198 	 * Reset active partition
1199 	 */
1200 	partp = ((struct dos_partition *) &mboot.parts);
1201 	for (i = 0; i < NDOSPART; i++)
1202 	    partp[i].dp_flag = 0;
1203 	partp[partition].dp_flag = ACTIVE;
1204 
1205 	status = 1;
1206 	break;
1207     }
1208     return (status);
1209 }
1210 
1211 
1212 static int
1213 process_line(line)
1214     char	*line;
1215 {
1216     CMD		command;
1217     int		status = 1;
1218 
1219     while (1)
1220     {
1221 	parse_config_line(line, &command);
1222 	switch (command.cmd)
1223 	{
1224 	case 0:
1225 	    /*
1226 	     * Comment or blank line
1227 	     */
1228 	    break;
1229 	case 'g':
1230 	    /*
1231 	     * Set geometry
1232 	     */
1233 	    status = process_geometry(&command);
1234 	    break;
1235 	case 'p':
1236 	    status = process_partition(&command);
1237 	    break;
1238 	case 'a':
1239 	    status = process_active(&command);
1240 	    break;
1241 	default:
1242 	    status = 0;
1243 	    break;
1244 	}
1245 	break;
1246     }
1247     return (status);
1248 }
1249 
1250 
1251 static int
1252 read_config(config_file)
1253     char *config_file;
1254 {
1255     FILE	*fp = NULL;
1256     int		status = 1;
1257     char	buf[1010];
1258 
1259     while (1)	/* dirty trick used to insure one exit point for this
1260 		   function */
1261     {
1262 	if (strcmp(config_file, "-") != 0)
1263 	{
1264 	    /*
1265 	     * We're not reading from stdin
1266 	     */
1267 	    if ((fp = fopen(config_file, "r")) == NULL)
1268 	    {
1269 		status = 0;
1270 		break;
1271 	    }
1272 	}
1273 	else
1274 	{
1275 	    fp = stdin;
1276 	}
1277 	current_line_number = 0;
1278 	while (!feof(fp))
1279 	{
1280 	    if (fgets(buf, sizeof(buf), fp) == NULL)
1281 	    {
1282 		break;
1283 	    }
1284 	    ++current_line_number;
1285 	    status = process_line(buf);
1286 	    if (status == 0)
1287 	    {
1288 		break;
1289 	    }
1290 	}
1291 	break;
1292     }
1293     if (fp)
1294     {
1295 	/*
1296 	 * It doesn't matter if we're reading from stdin, as we've reached EOF
1297 	 */
1298 	fclose(fp);
1299     }
1300     return (status);
1301 }
1302 
1303 
1304 static void
1305 reset_boot(void)
1306 {
1307     int				i;
1308     struct dos_partition	*partp;
1309 
1310     init_boot();
1311     for (i = 0; i < 4; ++i)
1312     {
1313 	partp = ((struct dos_partition *) &mboot.parts) + i;
1314 	bzero((char *)partp, sizeof (struct dos_partition));
1315     }
1316 }
1317