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