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