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