fdisk.c revision 20061
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 MAX_SEC_SIZE 2048	/* maximum section size that is supported */
58#define MIN_SEC_SIZE 512	/* the sector size to start sensing at */
59int secsize = 0;		/* the sensed sector size */
60
61const char *disk;
62const char *disks[] =
63{
64  "/dev/rwd0", "/dev/rsd0", "/dev/rod0", 0
65};
66
67char *name;
68
69struct disklabel disklabel;		/* disk parameters */
70
71int cyls, sectors, heads, cylsecs, disksecs;
72
73struct 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};
82struct mboot mboot;
83
84#define ACTIVE 0x80
85#define BOOT_MAGIC 0xAA55
86
87int dos_cyls;
88int dos_heads;
89int dos_sectors;
90int dos_cylsecs;
91
92#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
93#define DOSCYL(c)	(c & 0xff)
94static int partition = -1;
95
96
97#define MAX_ARGS	10
98
99static int	current_line_number;
100
101static int	geom_processed = 0;
102static int	part_processed = 0;
103static int	active_processed = 0;
104
105
106typedef 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
116static int a_flag  = 0;		/* set active partition */
117static int i_flag  = 0;		/* replace partition data */
118static int u_flag  = 0;		/* update partition data */
119static int t_flag  = 0;		/* test only, if f_flag is given */
120static char *f_flag = NULL;	/* Read config info from file */
121static int v_flag  = 0;		/* Be verbose */
122
123static unsigned char bootcode[] = {
1240x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
1250x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
1260xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
1270x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
1280x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
1290x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
1300x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
1310x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
1320xeb, 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
157struct 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
205static void print_s0(int which);
206static void print_part(int i);
207static void init_sector0(unsigned long start);
208static void init_boot(void);
209static void change_part(int i);
210static void print_params();
211static void change_active(int which);
212static void get_params_to_use();
213static void dos(int sec, int size, unsigned char *c, unsigned char *s,
214		unsigned char *h);
215static int open_disk(int u_flag);
216static ssize_t read_disk(off_t sector, void *buf);
217static ssize_t write_disk(off_t sector, void *buf);
218static int get_params();
219static int read_s0();
220static int write_s0();
221static int ok(char *str);
222static int decimal(char *str, int *num, int deflt);
223static char *get_type(int type);
224static int read_config(char *config_file);
225static void reset_boot(void);
226#if 0
227static int hex(char *str, int *num, int deflt);
228static int string(char *str, char **ans);
229#endif
230
231
232int
233main(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
407usage:
408	printf("fdisk {-a|-i|-u} [-f <config file> [-t] [-v]] [-{0,1,2,3}] [disk]\n");
409	return(1);
410}
411
412static void
413print_s0(int which)
414{
415int	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
426static struct dos_partition mtpart = { 0 };
427
428static void
429print_part(int i)
430{
431struct 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
453static void
454init_boot(void)
455{
456	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
457	mboot.signature = BOOT_MAGIC;
458}
459
460
461static void
462init_sector0(unsigned long start)
463{
464struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
465unsigned 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
480static void
481change_part(int i)
482{
483struct 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
539static void
540print_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
552static void
553change_active(int which)
554{
555int i;
556int active = 3, tmp;
557struct 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
572void
573get_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\***********************************************/
595static void
596dos(sec, size, c, s, h)
597int sec, size;
598unsigned char *c, *s, *h;
599{
600int cy;
601int 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
619int fd;
620
621	/* Getting device status */
622
623static int
624open_disk(int u_flag)
625{
626struct 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
650static ssize_t
651read_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
670static ssize_t
671write_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
678static int
679get_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
704static int
705read_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
720static int
721write_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
752static int
753ok(str)
754char *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
768static int
769decimal(char *str, int *num, int deflt)
770{
771int acc = 0, c;
772char *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
805static int
806hex(char *str, int *num, int deflt)
807{
808int acc = 0, c;
809char *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
845static int
846string(char *str, char **ans)
847{
848int c;
849char *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
876static char *
877get_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
897static void
898parse_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
949static int
950process_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
1061static int
1062process_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
1172static int
1173process_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
1212static int
1213process_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
1251static int
1252read_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
1304static void
1305reset_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