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