fdisk.c revision 34582
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, 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\n",
453		partp->dp_start,
454		partp->dp_size,
455		part_mb,
456		partp->dp_flag);
457	printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n"
458		,DPCYL(partp->dp_scyl, partp->dp_ssect)
459		,DPSECT(partp->dp_ssect)
460		,partp->dp_shd
461		,DPCYL(partp->dp_ecyl, partp->dp_esect)
462		,DPSECT(partp->dp_esect)
463		,partp->dp_ehd);
464}
465
466
467static void
468init_boot(void)
469{
470	memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
471	mboot.signature = BOOT_MAGIC;
472}
473
474
475static void
476init_sector0(unsigned long start)
477{
478struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
479unsigned long size = disksecs - start;
480
481	init_boot();
482
483	partp->dp_typ = DOSPTYP_386BSD;
484	partp->dp_flag = ACTIVE;
485	partp->dp_start = start;
486	partp->dp_size = size;
487
488	dos(partp->dp_start, partp->dp_size,
489	    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
490	dos(partp->dp_start + partp->dp_size - 1, partp->dp_size,
491	    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
492}
493
494static void
495change_part(int i)
496{
497struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1;
498
499    printf("The data for partition %d is:\n", i);
500    print_part(i);
501
502    if (u_flag && ok("Do you want to change it?")) {
503	int tmp;
504
505	if (i_flag) {
506		bzero((char *)partp, sizeof (struct dos_partition));
507		if (i == 4) {
508			init_sector0(1);
509			printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n");
510			print_part(i);
511		}
512	}
513
514	do {
515		Decimal("sysid", partp->dp_typ, tmp);
516		Decimal("start", partp->dp_start, tmp);
517		Decimal("size", partp->dp_size, tmp);
518
519		if (ok("Explicitly specifiy beg/end address ?"))
520		{
521			int	tsec,tcyl,thd;
522			tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
523			thd = partp->dp_shd;
524			tsec = DPSECT(partp->dp_ssect);
525			Decimal("beginning cylinder", tcyl, tmp);
526			Decimal("beginning head", thd, tmp);
527			Decimal("beginning sector", tsec, tmp);
528			partp->dp_scyl = DOSCYL(tcyl);
529			partp->dp_ssect = DOSSECT(tsec,tcyl);
530			partp->dp_shd = thd;
531
532			tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
533			thd = partp->dp_ehd;
534			tsec = DPSECT(partp->dp_esect);
535			Decimal("ending cylinder", tcyl, tmp);
536			Decimal("ending head", thd, tmp);
537			Decimal("ending sector", tsec, tmp);
538			partp->dp_ecyl = DOSCYL(tcyl);
539			partp->dp_esect = DOSSECT(tsec,tcyl);
540			partp->dp_ehd = thd;
541		} else {
542			dos(partp->dp_start, partp->dp_size,
543			    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
544			dos(partp->dp_start + partp->dp_size - 1, partp->dp_size,
545			    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
546		}
547
548		print_part(i);
549	} while (!ok("Are we happy with this entry?"));
550    }
551}
552
553static void
554print_params()
555{
556	printf("parameters extracted from in-core disklabel are:\n");
557	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
558			,cyls,heads,sectors,cylsecs);
559	if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
560		printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
561	printf("parameters to be used for BIOS calculations are:\n");
562	printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
563		,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
564}
565
566static void
567change_active(int which)
568{
569int i;
570int active = 4, tmp;
571struct dos_partition *partp = ((struct dos_partition *) &mboot.parts);
572
573	if (a_flag && which != -1)
574		active = which;
575	if (!ok("Do you want to change the active partition?"))
576		return;
577	do
578		Decimal("active partition", active, tmp);
579	while (!ok("Are you happy with this choice"));
580	for (i = 0; i < NDOSPART; i++)
581		partp[i].dp_flag = 0;
582	if (active > 0 && active <= NDOSPART)
583		partp[active-1].dp_flag = ACTIVE;
584}
585
586void
587get_params_to_use()
588{
589	int	tmp;
590	print_params();
591	if (ok("Do you want to change our idea of what BIOS thinks ?"))
592	{
593		do
594		{
595			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
596			Decimal("BIOS's idea of #heads", dos_heads, tmp);
597			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
598			dos_cylsecs = dos_heads * dos_sectors;
599			print_params();
600		}
601		while(!ok("Are you happy with this choice"));
602	}
603}
604
605
606/***********************************************\
607* Change real numbers into strange dos numbers	*
608\***********************************************/
609static void
610dos(sec, size, c, s, h)
611int sec, size;
612unsigned char *c, *s, *h;
613{
614int cy;
615int hd;
616
617	if (sec == 0 && size == 0) {
618		*s = *c = *h = 0;
619		return;
620	}
621
622	cy = sec / ( dos_cylsecs );
623	sec = sec - cy * ( dos_cylsecs );
624
625	hd = sec / dos_sectors;
626	sec = (sec - hd * dos_sectors) + 1;
627
628	*h = hd;
629	*c = cy & 0xff;
630	*s = (sec & 0x3f) | ( (cy & 0x300) >> 2);
631}
632
633int fd;
634
635	/* Getting device status */
636
637static int
638open_disk(int u_flag)
639{
640struct stat 	st;
641
642	if (stat(disk, &st) == -1) {
643		fprintf(stderr, "%s: Can't get file status of %s\n",
644			name, disk);
645		return -1;
646	}
647	if ( !(st.st_mode & S_IFCHR) )
648		fprintf(stderr,"%s: Device %s is not character special\n",
649			name, disk);
650	if ((fd = open(disk, a_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) {
651		if(errno == ENXIO)
652			return -2;
653		fprintf(stderr,"%s: Can't open device %s\n", name, disk);
654		return -1;
655	}
656	if (get_params(0) == -1) {
657		fprintf(stderr, "%s: Can't get disk parameters on %s\n",
658			name, disk);
659		return -1;
660	}
661	return fd;
662}
663
664static ssize_t
665read_disk(off_t sector, void *buf)
666{
667	lseek(fd,(sector * 512), 0);
668	if( secsize == 0 )
669		for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 )
670			{
671			/* try the read */
672			int size = read(fd, buf, secsize);
673			if( size == secsize )
674				/* it worked so return */
675				return secsize;
676			}
677	else
678		return read( fd, buf, secsize );
679
680	/* we failed to read at any of the sizes */
681	return -1;
682}
683
684static ssize_t
685write_disk(off_t sector, void *buf)
686{
687	lseek(fd,(sector * 512), 0);
688	/* write out in the size that the read_disk found worked */
689	return write(fd, buf, secsize);
690}
691
692static int
693get_params()
694{
695
696    if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
697	fprintf(stderr,
698		"%s: Can't get disk parameters on %s; supplying dummy ones\n",
699		name, disk);
700	dos_cyls = cyls = 1;
701	dos_heads = heads = 1;
702	dos_sectors = sectors = 1;
703	dos_cylsecs = cylsecs = heads * sectors;
704	disksecs = cyls * heads * sectors;
705	return disksecs;
706    }
707
708    dos_cyls = cyls = disklabel.d_ncylinders;
709    dos_heads = heads = disklabel.d_ntracks;
710    dos_sectors = sectors = disklabel.d_nsectors;
711    dos_cylsecs = cylsecs = heads * sectors;
712    disksecs = cyls * heads * sectors;
713
714    return (disksecs);
715}
716
717
718static int
719read_s0()
720{
721	if (read_disk(0, (char *) mboot.bootinst) == -1) {
722		fprintf(stderr, "%s: Can't read fdisk partition table\n", name);
723		return -1;
724	}
725	if (mboot.signature != BOOT_MAGIC) {
726		fprintf(stderr, "%s: Invalid fdisk partition table found\n",
727			name);
728		/* So should we initialize things */
729		return -1;
730	}
731	return 0;
732}
733
734static int
735write_s0()
736{
737	int	flag;
738	if (iotest) {
739		print_s0(-1);
740		return 0;
741	}
742	/*
743	 * write enable label sector before write (if necessary),
744	 * disable after writing.
745	 * needed if the disklabel protected area also protects
746	 * sector 0. (e.g. empty disk)
747	 */
748	flag = 1;
749#ifdef NOT_NOW
750	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
751		perror("ioctl DIOCWLABEL");
752#endif
753	if (write_disk(0, (char *) mboot.bootinst) == -1) {
754		fprintf(stderr, "%s: Can't write fdisk partition table\n",
755			name);
756		return -1;
757	flag = 0;
758#ifdef NOT_NOW
759	(void) ioctl(fd, DIOCWLABEL, &flag);
760#endif
761	}
762	return(0);
763}
764
765
766static int
767ok(str)
768char *str;
769{
770	printf("%s [n] ", str);
771	fgets(lbuf, LBUF, stdin);
772	lbuf[strlen(lbuf)-1] = 0;
773
774	if (*lbuf &&
775		(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
776		 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
777		return 1;
778	else
779		return 0;
780}
781
782static int
783decimal(char *str, int *num, int deflt)
784{
785int acc = 0, c;
786char *cp;
787
788	while (1) {
789		printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
790		fgets(lbuf, LBUF, stdin);
791		lbuf[strlen(lbuf)-1] = 0;
792
793		if (!*lbuf)
794			return 0;
795
796		cp = lbuf;
797		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
798		if (!c)
799			return 0;
800		while ((c = *cp++)) {
801			if (c <= '9' && c >= '0')
802				acc = acc * 10 + c - '0';
803			else
804				break;
805		}
806		if (c == ' ' || c == '\t')
807			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
808		if (!c) {
809			*num = acc;
810			return 1;
811		} else
812			printf("%s is an invalid decimal number.  Try again\n",
813				lbuf);
814	}
815
816}
817
818#if 0
819static int
820hex(char *str, int *num, int deflt)
821{
822int acc = 0, c;
823char *cp;
824
825	while (1) {
826		printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
827		fgets(lbuf, LBUF, stdin);
828		lbuf[strlen(lbuf)-1] = 0;
829
830		if (!*lbuf)
831			return 0;
832
833		cp = lbuf;
834		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
835		if (!c)
836			return 0;
837		while ((c = *cp++)) {
838			if (c <= '9' && c >= '0')
839				acc = (acc << 4) + c - '0';
840			else if (c <= 'f' && c >= 'a')
841				acc = (acc << 4) + c - 'a' + 10;
842			else if (c <= 'F' && c >= 'A')
843				acc = (acc << 4) + c - 'A' + 10;
844			else
845				break;
846		}
847		if (c == ' ' || c == '\t')
848			while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
849		if (!c) {
850			*num = acc;
851			return 1;
852		} else
853			printf("%s is an invalid hex number.  Try again\n",
854				lbuf);
855	}
856
857}
858
859static int
860string(char *str, char **ans)
861{
862int c;
863char *cp = lbuf;
864
865	while (1) {
866		printf("Supply a string value for \"%s\" [%s] ", str, *ans);
867		fgets(lbuf, LBUF, stdin);
868		lbuf[strlen(lbuf)-1] = 0;
869
870		if (!*lbuf)
871			return 0;
872
873		while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
874		if (c == '"') {
875			c = *++cp;
876			*ans = cp;
877			while ((c = *cp) && c != '"') cp++;
878		} else {
879			*ans = cp;
880			while ((c = *cp) && c != ' ' && c != '\t') cp++;
881		}
882
883		if (c)
884			*cp = 0;
885		return 1;
886	}
887}
888#endif
889
890static char *
891get_type(int type)
892{
893	int	numentries = (sizeof(part_types)/sizeof(struct part_type));
894	int	counter = 0;
895	struct	part_type *ptr = part_types;
896
897
898	while(counter < numentries)
899	{
900		if(ptr->type == type)
901		{
902			return(ptr->name);
903		}
904		ptr++;
905		counter++;
906	}
907	return("unknown");
908}
909
910
911static void
912parse_config_line(line, command)
913    char	*line;
914    CMD		*command;
915{
916    char	*cp, *end;
917
918    cp = line;
919    while (1)	/* dirty trick used to insure one exit point for this
920		   function */
921    {
922	memset(command, 0, sizeof(*command));
923
924	while (isspace(*cp)) ++cp;
925	if (*cp == '\0' || *cp == '#')
926	{
927	    break;
928	}
929	command->cmd = *cp++;
930
931	/*
932	 * Parse args
933	 */
934	while (1)
935	{
936	    while (isspace(*cp)) ++cp;
937	    if (*cp == '#')
938	    {
939		break;		/* found comment */
940	    }
941	    if (isalpha(*cp))
942	    {
943		command->args[command->n_args].argtype = *cp++;
944	    }
945	    if (!isdigit(*cp))
946	    {
947		break;		/* assume end of line */
948	    }
949	    end = NULL;
950	    command->args[command->n_args].arg_val = strtol(cp, &end, 0);
951	    if (cp == end)
952	    {
953		break;		/* couldn't parse number */
954	    }
955	    cp = end;
956	    command->n_args++;
957	}
958	break;
959    }
960}
961
962
963static int
964process_geometry(command)
965    CMD		*command;
966{
967    int		status = 1, i;
968
969    while (1)
970    {
971	geom_processed = 1;
972	if (part_processed)
973	{
974	    fprintf(stderr,
975		    "%s: ERROR line %d: the geometry specification line must occur before\n\
976    all partition specifications.\n",
977		    name, current_line_number);
978	    status = 0;
979	    break;
980	}
981	if (command->n_args != 3)
982	{
983	    fprintf(stderr,
984		    "%s: ERROR line %d: incorrect number of geometry args\n",
985		    name, current_line_number);
986	    status = 0;
987	    break;
988	}
989	dos_cyls = -1;
990	dos_heads = -1;
991	dos_sectors = -1;
992	for (i = 0; i < 3; ++i)
993	{
994	    switch (command->args[i].argtype)
995	    {
996	    case 'c':
997		dos_cyls = command->args[i].arg_val;
998		break;
999	    case 'h':
1000		dos_heads = command->args[i].arg_val;
1001		break;
1002	    case 's':
1003		dos_sectors = command->args[i].arg_val;
1004		break;
1005	    default:
1006		fprintf(stderr,
1007			"%s: ERROR line %d: unknown geometry arg type: '%c' (0x%02x)\n",
1008			name, current_line_number, command->args[i].argtype,
1009			command->args[i].argtype);
1010		status = 0;
1011		break;
1012	    }
1013	}
1014	if (status == 0)
1015	{
1016	    break;
1017	}
1018
1019	dos_cylsecs = dos_heads * dos_sectors;
1020
1021	/*
1022	 * Do sanity checks on parameter values
1023	 */
1024	if (dos_cyls < 0)
1025	{
1026	    fprintf(stderr,
1027		    "%s: ERROR line %d: number of cylinders not specified\n",
1028		    name, current_line_number);
1029	    status = 0;
1030	}
1031	if (dos_cyls == 0 || dos_cyls > 1024)
1032	{
1033	    fprintf(stderr,
1034		    "%s: WARNING line %d: number of cylinders (%d) may be out-of-range\n\
1035    (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\
1036    is dedicated to FreeBSD).\n",
1037		    name, current_line_number, dos_cyls);
1038	}
1039
1040	if (dos_heads < 0)
1041	{
1042	    fprintf(stderr,
1043		    "%s: ERROR line %d: number of heads not specified\n",
1044		    name, current_line_number);
1045	    status = 0;
1046	}
1047	else if (dos_heads < 1 || dos_heads > 256)
1048	{
1049	    fprintf(stderr,
1050		    "%s: ERROR line %d: number of heads must be within (1-256)\n",
1051		    name, current_line_number);
1052	    status = 0;
1053	}
1054
1055	if (dos_sectors < 0)
1056	{
1057	    fprintf(stderr, "%s: ERROR line %d: number of sectors not specified\n",
1058		    name, current_line_number);
1059	    status = 0;
1060	}
1061	else if (dos_sectors < 1 || dos_sectors > 63)
1062	{
1063	    fprintf(stderr,
1064		    "%s: ERROR line %d: number of sectors must be within (1-63)\n",
1065		    name, current_line_number);
1066	    status = 0;
1067	}
1068
1069	break;
1070    }
1071    return (status);
1072}
1073
1074
1075static int
1076process_partition(command)
1077    CMD		*command;
1078{
1079    int				status = 0, partition;
1080    unsigned long		chunks, adj_size, max_end;
1081    struct dos_partition	*partp;
1082
1083    while (1)
1084    {
1085	part_processed = 1;
1086	if (command->n_args != 4)
1087	{
1088	    fprintf(stderr,
1089		    "%s: ERROR line %d: incorrect number of partition args\n",
1090		    name, current_line_number);
1091	    break;
1092	}
1093	partition = command->args[0].arg_val;
1094	if (partition < 1 || partition > 4)
1095	{
1096	    fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n",
1097		    name, current_line_number, partition);
1098	    break;
1099	}
1100	partp = ((struct dos_partition *) &mboot.parts) + partition - 1;
1101	bzero((char *)partp, sizeof (struct dos_partition));
1102	partp->dp_typ = command->args[1].arg_val;
1103	partp->dp_start = command->args[2].arg_val;
1104	partp->dp_size = command->args[3].arg_val;
1105	max_end = partp->dp_start + partp->dp_size;
1106
1107	if (partp->dp_typ == 0)
1108	{
1109	    /*
1110	     * Get out, the partition is marked as unused.
1111	     */
1112	    /*
1113	     * Insure that it's unused.
1114	     */
1115	    bzero((char *)partp, sizeof (struct dos_partition));
1116	    status = 1;
1117	    break;
1118	}
1119
1120	/*
1121	 * Adjust start upwards, if necessary, to fall on an head boundary.
1122	 */
1123	if (partp->dp_start % dos_sectors != 0)
1124	{
1125	    adj_size =
1126		(partp->dp_start / dos_sectors + 1) * dos_sectors;
1127	    if (adj_size > max_end)
1128	    {
1129		/*
1130		 * Can't go past end of partition
1131		 */
1132		fprintf(stderr,
1133			"%s: ERROR line %d: unable to adjust start of partition %d to fall on\n\
1134    a cylinder boundary.\n",
1135			name, current_line_number, partition);
1136		break;
1137	    }
1138	    fprintf(stderr,
1139		    "%s: WARNING: adjusting start offset of partition '%d' from %d\n\
1140    to %d, to round to an head boundary.\n",
1141		    name, partition, partp->dp_start, adj_size);
1142	    partp->dp_start = adj_size;
1143	}
1144
1145	/*
1146	 * Adjust size downwards, if necessary, to fall on a cylinder
1147	 * boundary.
1148	 */
1149	chunks =
1150	    ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs;
1151	adj_size = chunks - partp->dp_start;
1152	if (adj_size != partp->dp_size)
1153	{
1154	    fprintf(stderr,
1155		    "%s: WARNING: adjusting size of partition '%d' from %d to %d,\n\
1156    to round to a cylinder boundary.\n",
1157		    name, partition, partp->dp_size, adj_size);
1158	    if (chunks > 0)
1159	    {
1160		partp->dp_size = adj_size;
1161	    }
1162	    else
1163	    {
1164		partp->dp_size = 0;
1165	    }
1166	}
1167	if (partp->dp_size < 1)
1168	{
1169	    fprintf(stderr,
1170		    "%s: ERROR line %d: size for partition '%d' is zero.\n",
1171		    name, current_line_number, partition);
1172	    break;
1173	}
1174
1175	dos(partp->dp_start, partp->dp_size,
1176	    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
1177	dos(partp->dp_start+partp->dp_size - 1, partp->dp_size,
1178	    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
1179	status = 1;
1180	break;
1181    }
1182    return (status);
1183}
1184
1185
1186static int
1187process_active(command)
1188    CMD		*command;
1189{
1190    int				status = 0, partition, i;
1191    struct dos_partition	*partp;
1192
1193    while (1)
1194    {
1195	active_processed = 1;
1196	if (command->n_args != 1)
1197	{
1198	    fprintf(stderr,
1199		    "%s: ERROR line %d: incorrect number of active args\n",
1200		    name, current_line_number);
1201	    status = 0;
1202	    break;
1203	}
1204	partition = command->args[0].arg_val;
1205	if (partition < 1 || partition > 4)
1206	{
1207	    fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n",
1208		    name, current_line_number, partition);
1209	    break;
1210	}
1211	/*
1212	 * Reset active partition
1213	 */
1214	partp = ((struct dos_partition *) &mboot.parts);
1215	for (i = 0; i < NDOSPART; i++)
1216	    partp[i].dp_flag = 0;
1217	partp[partition-1].dp_flag = ACTIVE;
1218
1219	status = 1;
1220	break;
1221    }
1222    return (status);
1223}
1224
1225
1226static int
1227process_line(line)
1228    char	*line;
1229{
1230    CMD		command;
1231    int		status = 1;
1232
1233    while (1)
1234    {
1235	parse_config_line(line, &command);
1236	switch (command.cmd)
1237	{
1238	case 0:
1239	    /*
1240	     * Comment or blank line
1241	     */
1242	    break;
1243	case 'g':
1244	    /*
1245	     * Set geometry
1246	     */
1247	    status = process_geometry(&command);
1248	    break;
1249	case 'p':
1250	    status = process_partition(&command);
1251	    break;
1252	case 'a':
1253	    status = process_active(&command);
1254	    break;
1255	default:
1256	    status = 0;
1257	    break;
1258	}
1259	break;
1260    }
1261    return (status);
1262}
1263
1264
1265static int
1266read_config(config_file)
1267    char *config_file;
1268{
1269    FILE	*fp = NULL;
1270    int		status = 1;
1271    char	buf[1010];
1272
1273    while (1)	/* dirty trick used to insure one exit point for this
1274		   function */
1275    {
1276	if (strcmp(config_file, "-") != 0)
1277	{
1278	    /*
1279	     * We're not reading from stdin
1280	     */
1281	    if ((fp = fopen(config_file, "r")) == NULL)
1282	    {
1283		status = 0;
1284		break;
1285	    }
1286	}
1287	else
1288	{
1289	    fp = stdin;
1290	}
1291	current_line_number = 0;
1292	while (!feof(fp))
1293	{
1294	    if (fgets(buf, sizeof(buf), fp) == NULL)
1295	    {
1296		break;
1297	    }
1298	    ++current_line_number;
1299	    status = process_line(buf);
1300	    if (status == 0)
1301	    {
1302		break;
1303	    }
1304	}
1305	break;
1306    }
1307    if (fp)
1308    {
1309	/*
1310	 * It doesn't matter if we're reading from stdin, as we've reached EOF
1311	 */
1312	fclose(fp);
1313    }
1314    return (status);
1315}
1316
1317
1318static void
1319reset_boot(void)
1320{
1321    int				i;
1322    struct dos_partition	*partp;
1323
1324    init_boot();
1325    for (i = 0; i < 4; ++i)
1326    {
1327	partp = ((struct dos_partition *) &mboot.parts) + i;
1328	bzero((char *)partp, sizeof (struct dos_partition));
1329    }
1330}
1331