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