fdisk.c revision 34148
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	,{0x0B, "Primary DOS with 32 bit FAT"}
175	,{0x10, "OPUS"}
176	,{0x40, "VENIX 286"}
177	,{0x50, "DM"}
178	,{0x51, "DM"}
179	,{0x52, "CP/M or Microport SysV/AT"}
180	,{0x56, "GB"}
181	,{0x61, "Speed"}
182	,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
183	,{0x64, "Novell Netware 2.xx"}
184	,{0x65, "Novell Netware 3.xx"}
185	,{0x75, "PCIX"}
186	,{0x80, "Minix 1.1 ... 1.4a"}
187	,{0x81, "Minix 1.4b ... 1.5.10"}
188	,{0x82, "Linux swap"}
189	,{0x83, "Linux filesystem"}
190	,{0x93, "Amoeba filesystem"}
191	,{0x94, "Amoeba bad block table"}
192	,{0xA5, "FreeBSD/NetBSD/386BSD"}
193	,{0xA6, "OpenBSD"}
194	,{0xA7, "NEXTSTEP"}
195	,{0xB7, "BSDI BSD/386 filesystem"}
196	,{0xB8, "BSDI BSD/386 swap"}
197	,{0xDB, "Concurrent CPM or C.DOS or CTOS"}
198	,{0xE1, "Speed"}
199	,{0xE3, "Speed"}
200	,{0xE4, "Speed"}
201	,{0xF1, "Speed"}
202	,{0xF2, "DOS 3.3+ Secondary"}
203	,{0xF4, "Speed"}
204	,{0xFF, "BBT (Bad Blocks Table)"}
205};
206
207static void print_s0(int which);
208static void print_part(int i);
209static void init_sector0(unsigned long start);
210static void init_boot(void);
211static void change_part(int i);
212static void print_params();
213static void change_active(int which);
214static void get_params_to_use();
215static void dos(int sec, int size, unsigned char *c, unsigned char *s,
216		unsigned char *h);
217static int open_disk(int u_flag);
218static ssize_t read_disk(off_t sector, void *buf);
219static ssize_t write_disk(off_t sector, void *buf);
220static int get_params();
221static int read_s0();
222static int write_s0();
223static int ok(char *str);
224static int decimal(char *str, int *num, int deflt);
225static char *get_type(int type);
226static int read_config(char *config_file);
227static void reset_boot(void);
228#if 0
229static int hex(char *str, int *num, int deflt);
230static int string(char *str, char **ans);
231#endif
232
233
234int
235main(int argc, char *argv[])
236{
237	int	i;
238
239	name = *argv;
240	{register char *cp = name;
241		while (*cp) if (*cp++ == '/') name = cp;
242	}
243
244	for ( argv++ ; --argc ; argv++ ) { register char *token = *argv;
245		if (*token++ != '-' || !*token)
246			break;
247		else { register int flag;
248			for ( ; (flag = *token++) ; ) {
249				switch (flag) {
250				case '1':
251					partition = 1;
252					break;
253				case '2':
254					partition = 2;
255					break;
256				case '3':
257					partition = 3;
258					break;
259				case '4':
260					partition = 4;
261					break;
262				case 'a':
263					a_flag = 1;
264					break;
265				case 'f':
266					if (*token)
267					{
268					    f_flag = token;
269					    token = "";
270					}
271					else
272					{
273					    if (argc == 1)
274					    {
275						goto usage;
276					    }
277					    --argc;
278					    f_flag = *++argv;
279					}
280					/*
281					 * u_flag is needed, because we're
282					 * writing to the disk.
283					 */
284					u_flag = 1;
285					break;
286				case 'i':
287					i_flag = 1;
288				case 'u':
289					u_flag = 1;
290					break;
291				case 't':
292					t_flag = 1;
293				case 'v':
294					v_flag = 1;
295					break;
296				default:
297					goto usage;
298				}
299			}
300		}
301	}
302
303	if (argc > 0)
304	{
305		static char realname[12];
306
307		if(strncmp(argv[0], "/dev", 4) == 0)
308			disk = argv[0];
309		else
310		{
311			snprintf(realname, 12, "/dev/r%s", argv[0]);
312			disk = realname;
313		}
314
315		if (open_disk(u_flag) < 0)
316		{
317			fprintf(stderr, "Cannot open disk %s (%s)\n",
318				disk, sys_errlist[errno]);
319			exit(1);
320		}
321	}
322	else
323	{
324		int i, rv = 0;
325
326		for(i = 0; disks[i]; i++)
327		{
328			disk = disks[i];
329			rv = open_disk(u_flag);
330			if(rv != -2) break;
331		}
332		if(rv < 0)
333		{
334			fprintf(stderr, "Cannot open any disk (%s)\n",
335				sys_errlist[errno]);
336			exit(1);
337		}
338	}
339
340	printf("******* Working on device %s *******\n",disk);
341
342	if (f_flag)
343	{
344	    if (read_s0() || i_flag)
345	    {
346		reset_boot();
347	    }
348
349	    if (!read_config(f_flag))
350	    {
351		exit(1);
352	    }
353	    if (v_flag)
354	    {
355		print_s0(-1);
356	    }
357	    if (!t_flag)
358	    {
359		write_s0();
360	    }
361	}
362	else
363	{
364	    if(u_flag)
365	    {
366		get_params_to_use();
367	    }
368	    else
369	    {
370		print_params();
371	    }
372
373	    if (read_s0())
374		init_sector0(1);
375
376	    printf("Media sector size is %d\n", secsize);
377	    printf("Warning: BIOS sector numbering starts with sector 1\n");
378	    printf("Information from DOS bootblock is:\n");
379	    if (partition == -1)
380		for (i = 1; i <= NDOSPART; i++)
381		    change_part(i);
382	    else
383		change_part(partition);
384
385	    if (u_flag || a_flag)
386		change_active(partition);
387
388	    if (u_flag || a_flag) {
389		if (!t_flag)
390		{
391		    printf("\nWe haven't changed the partition table yet.  ");
392		    printf("This is your last chance.\n");
393		}
394		print_s0(-1);
395		if (!t_flag)
396		{
397		    if (ok("Should we write new partition table?"))
398			write_s0();
399		}
400		else
401		{
402		    printf("\n-t flag specified -- partition table not written.\n");
403		}
404	    }
405	}
406
407	exit(0);
408
409usage:
410	printf("fdisk {-a|-i|-u} [-f <config file> [-t] [-v]] [-{1,2,3,4}] [disk]\n");
411	return(1);
412}
413
414static void
415print_s0(int which)
416{
417int	i;
418
419	print_params();
420	printf("Information from DOS bootblock is:\n");
421	if (which == -1)
422		for (i = 1; i <= NDOSPART; i++)
423			printf("%d: ", i), print_part(i);
424	else
425		print_part(which);
426}
427
428static struct dos_partition mtpart = { 0 };
429
430static void
431print_part(int i)
432{
433	struct	  dos_partition *partp;
434	u_int64_t part_mb;
435
436	partp = ((struct dos_partition *) &mboot.parts) + i - 1;
437
438	if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
439		printf("<UNUSED>\n");
440		return;
441	}
442	/*
443	 * Be careful not to overflow.
444	 */
445	part_mb = partp->dp_size;
446	part_mb *= secsize;
447	part_mb /= (1024 * 1024);
448	printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ));
449	printf("    start %ld, size %ld (%qd Meg), flag %x\n",
450		partp->dp_start,
451		partp->dp_size,
452		part_mb,
453		partp->dp_flag);
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", partp->dp_typ, tmp);
513		Decimal("start", partp->dp_start, tmp);
514		Decimal("size", partp->dp_size, tmp);
515
516		if (ok("Explicitly specifiy 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;
574	do
575		Decimal("active partition", active, tmp);
576	while (!ok("Are you happy with this choice"));
577	for (i = 0; i < NDOSPART; i++)
578		partp[i].dp_flag = 0;
579	if (active > 0 && active <= NDOSPART)
580		partp[active-1].dp_flag = ACTIVE;
581}
582
583void
584get_params_to_use()
585{
586	int	tmp;
587	print_params();
588	if (ok("Do you want to change our idea of what BIOS thinks ?"))
589	{
590		do
591		{
592			Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
593			Decimal("BIOS's idea of #heads", dos_heads, tmp);
594			Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
595			dos_cylsecs = dos_heads * dos_sectors;
596			print_params();
597		}
598		while(!ok("Are you happy with this choice"));
599	}
600}
601
602
603/***********************************************\
604* Change real numbers into strange dos numbers	*
605\***********************************************/
606static void
607dos(sec, size, c, s, h)
608int sec, size;
609unsigned char *c, *s, *h;
610{
611int cy;
612int hd;
613
614	if (sec == 0 && size == 0) {
615		*s = *c = *h = 0;
616		return;
617	}
618
619	cy = sec / ( dos_cylsecs );
620	sec = sec - cy * ( dos_cylsecs );
621
622	hd = sec / dos_sectors;
623	sec = (sec - hd * dos_sectors) + 1;
624
625	*h = hd;
626	*c = cy & 0xff;
627	*s = (sec & 0x3f) | ( (cy & 0x300) >> 2);
628}
629
630int fd;
631
632	/* Getting device status */
633
634static int
635open_disk(int u_flag)
636{
637struct stat 	st;
638
639	if (stat(disk, &st) == -1) {
640		fprintf(stderr, "%s: Can't get file status of %s\n",
641			name, disk);
642		return -1;
643	}
644	if ( !(st.st_mode & S_IFCHR) )
645		fprintf(stderr,"%s: Device %s is not character special\n",
646			name, disk);
647	if ((fd = open(disk, a_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) {
648		if(errno == ENXIO)
649			return -2;
650		fprintf(stderr,"%s: Can't open device %s\n", name, disk);
651		return -1;
652	}
653	if (get_params(0) == -1) {
654		fprintf(stderr, "%s: Can't get disk parameters on %s\n",
655			name, disk);
656		return -1;
657	}
658	return fd;
659}
660
661static ssize_t
662read_disk(off_t sector, void *buf)
663{
664	lseek(fd,(sector * 512), 0);
665	if( secsize == 0 )
666		for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 )
667			{
668			/* try the read */
669			int size = read(fd, buf, secsize);
670			if( size == secsize )
671				/* it worked so return */
672				return secsize;
673			}
674	else
675		return read( fd, buf, secsize );
676
677	/* we failed to read at any of the sizes */
678	return -1;
679}
680
681static ssize_t
682write_disk(off_t sector, void *buf)
683{
684	lseek(fd,(sector * 512), 0);
685	/* write out in the size that the read_disk found worked */
686	return write(fd, buf, secsize);
687}
688
689static int
690get_params()
691{
692
693    if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
694	fprintf(stderr,
695		"%s: Can't get disk parameters on %s; supplying dummy ones\n",
696		name, disk);
697	dos_cyls = cyls = 1;
698	dos_heads = heads = 1;
699	dos_sectors = sectors = 1;
700	dos_cylsecs = cylsecs = heads * sectors;
701	disksecs = cyls * heads * sectors;
702	return disksecs;
703    }
704
705    dos_cyls = cyls = disklabel.d_ncylinders;
706    dos_heads = heads = disklabel.d_ntracks;
707    dos_sectors = sectors = disklabel.d_nsectors;
708    dos_cylsecs = cylsecs = heads * sectors;
709    disksecs = cyls * heads * sectors;
710
711    return (disksecs);
712}
713
714
715static int
716read_s0()
717{
718	if (read_disk(0, (char *) mboot.bootinst) == -1) {
719		fprintf(stderr, "%s: Can't read fdisk partition table\n", name);
720		return -1;
721	}
722	if (mboot.signature != BOOT_MAGIC) {
723		fprintf(stderr, "%s: Invalid fdisk partition table found\n",
724			name);
725		/* So should we initialize things */
726		return -1;
727	}
728	return 0;
729}
730
731static int
732write_s0()
733{
734	int	flag;
735	if (iotest) {
736		print_s0(-1);
737		return 0;
738	}
739	/*
740	 * write enable label sector before write (if necessary),
741	 * disable after writing.
742	 * needed if the disklabel protected area also protects
743	 * sector 0. (e.g. empty disk)
744	 */
745	flag = 1;
746#ifdef NOT_NOW
747	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
748		perror("ioctl DIOCWLABEL");
749#endif
750	if (write_disk(0, (char *) mboot.bootinst) == -1) {
751		fprintf(stderr, "%s: Can't write fdisk partition table\n",
752			name);
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	    fprintf(stderr,
972		    "%s: ERROR line %d: the geometry specification line must occur before\n\
973    all partition specifications.\n",
974		    name, current_line_number);
975	    status = 0;
976	    break;
977	}
978	if (command->n_args != 3)
979	{
980	    fprintf(stderr,
981		    "%s: ERROR line %d: incorrect number of geometry args\n",
982		    name, current_line_number);
983	    status = 0;
984	    break;
985	}
986	dos_cyls = -1;
987	dos_heads = -1;
988	dos_sectors = -1;
989	for (i = 0; i < 3; ++i)
990	{
991	    switch (command->args[i].argtype)
992	    {
993	    case 'c':
994		dos_cyls = command->args[i].arg_val;
995		break;
996	    case 'h':
997		dos_heads = command->args[i].arg_val;
998		break;
999	    case 's':
1000		dos_sectors = command->args[i].arg_val;
1001		break;
1002	    default:
1003		fprintf(stderr,
1004			"%s: ERROR line %d: unknown geometry arg type: '%c' (0x%02x)\n",
1005			name, current_line_number, command->args[i].argtype,
1006			command->args[i].argtype);
1007		status = 0;
1008		break;
1009	    }
1010	}
1011	if (status == 0)
1012	{
1013	    break;
1014	}
1015
1016	dos_cylsecs = dos_heads * dos_sectors;
1017
1018	/*
1019	 * Do sanity checks on parameter values
1020	 */
1021	if (dos_cyls < 0)
1022	{
1023	    fprintf(stderr,
1024		    "%s: ERROR line %d: number of cylinders not specified\n",
1025		    name, current_line_number);
1026	    status = 0;
1027	}
1028	if (dos_cyls == 0 || dos_cyls > 1024)
1029	{
1030	    fprintf(stderr,
1031		    "%s: WARNING line %d: number of cylinders (%d) may be out-of-range\n\
1032    (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\
1033    is dedicated to FreeBSD).\n",
1034		    name, current_line_number, dos_cyls);
1035	}
1036
1037	if (dos_heads < 0)
1038	{
1039	    fprintf(stderr,
1040		    "%s: ERROR line %d: number of heads not specified\n",
1041		    name, current_line_number);
1042	    status = 0;
1043	}
1044	else if (dos_heads < 1 || dos_heads > 256)
1045	{
1046	    fprintf(stderr,
1047		    "%s: ERROR line %d: number of heads must be within (1-256)\n",
1048		    name, current_line_number);
1049	    status = 0;
1050	}
1051
1052	if (dos_sectors < 0)
1053	{
1054	    fprintf(stderr, "%s: ERROR line %d: number of sectors not specified\n",
1055		    name, current_line_number);
1056	    status = 0;
1057	}
1058	else if (dos_sectors < 1 || dos_sectors > 63)
1059	{
1060	    fprintf(stderr,
1061		    "%s: ERROR line %d: number of sectors must be within (1-63)\n",
1062		    name, current_line_number);
1063	    status = 0;
1064	}
1065
1066	break;
1067    }
1068    return (status);
1069}
1070
1071
1072static int
1073process_partition(command)
1074    CMD		*command;
1075{
1076    int				status = 0, partition;
1077    unsigned long		chunks, adj_size, max_end;
1078    struct dos_partition	*partp;
1079
1080    while (1)
1081    {
1082	part_processed = 1;
1083	if (command->n_args != 4)
1084	{
1085	    fprintf(stderr,
1086		    "%s: ERROR line %d: incorrect number of partition args\n",
1087		    name, current_line_number);
1088	    break;
1089	}
1090	partition = command->args[0].arg_val;
1091	if (partition < 1 || partition > 4)
1092	{
1093	    fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n",
1094		    name, current_line_number, partition);
1095	    break;
1096	}
1097	partp = ((struct dos_partition *) &mboot.parts) + partition - 1;
1098	bzero((char *)partp, sizeof (struct dos_partition));
1099	partp->dp_typ = command->args[1].arg_val;
1100	partp->dp_start = command->args[2].arg_val;
1101	partp->dp_size = command->args[3].arg_val;
1102	max_end = partp->dp_start + partp->dp_size;
1103
1104	if (partp->dp_typ == 0)
1105	{
1106	    /*
1107	     * Get out, the partition is marked as unused.
1108	     */
1109	    /*
1110	     * Insure that it's unused.
1111	     */
1112	    bzero((char *)partp, sizeof (struct dos_partition));
1113	    status = 1;
1114	    break;
1115	}
1116
1117	/*
1118	 * Adjust start upwards, if necessary, to fall on an head boundary.
1119	 */
1120	if (partp->dp_start % dos_sectors != 0)
1121	{
1122	    adj_size =
1123		(partp->dp_start / dos_sectors + 1) * dos_sectors;
1124	    if (adj_size > max_end)
1125	    {
1126		/*
1127		 * Can't go past end of partition
1128		 */
1129		fprintf(stderr,
1130			"%s: ERROR line %d: unable to adjust start of partition %d to fall on\n\
1131    a cylinder boundary.\n",
1132			name, current_line_number, partition);
1133		break;
1134	    }
1135	    fprintf(stderr,
1136		    "%s: WARNING: adjusting start offset of partition '%d' from %d\n\
1137    to %d, to round to an head boundary.\n",
1138		    name, partition, partp->dp_start, adj_size);
1139	    partp->dp_start = adj_size;
1140	}
1141
1142	/*
1143	 * Adjust size downwards, if necessary, to fall on a cylinder
1144	 * boundary.
1145	 */
1146	chunks =
1147	    ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs;
1148	adj_size = chunks - partp->dp_start;
1149	if (adj_size != partp->dp_size)
1150	{
1151	    fprintf(stderr,
1152		    "%s: WARNING: adjusting size of partition '%d' from %d to %d,\n\
1153    to round to a cylinder boundary.\n",
1154		    name, partition, partp->dp_size, adj_size);
1155	    if (chunks > 0)
1156	    {
1157		partp->dp_size = adj_size;
1158	    }
1159	    else
1160	    {
1161		partp->dp_size = 0;
1162	    }
1163	}
1164	if (partp->dp_size < 1)
1165	{
1166	    fprintf(stderr,
1167		    "%s: ERROR line %d: size for partition '%d' is zero.\n",
1168		    name, current_line_number, partition);
1169	    break;
1170	}
1171
1172	dos(partp->dp_start, partp->dp_size,
1173	    &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
1174	dos(partp->dp_start+partp->dp_size - 1, partp->dp_size,
1175	    &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
1176	status = 1;
1177	break;
1178    }
1179    return (status);
1180}
1181
1182
1183static int
1184process_active(command)
1185    CMD		*command;
1186{
1187    int				status = 0, partition, i;
1188    struct dos_partition	*partp;
1189
1190    while (1)
1191    {
1192	active_processed = 1;
1193	if (command->n_args != 1)
1194	{
1195	    fprintf(stderr,
1196		    "%s: ERROR line %d: incorrect number of active args\n",
1197		    name, current_line_number);
1198	    status = 0;
1199	    break;
1200	}
1201	partition = command->args[0].arg_val;
1202	if (partition < 1 || partition > 4)
1203	{
1204	    fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n",
1205		    name, current_line_number, partition);
1206	    break;
1207	}
1208	/*
1209	 * Reset active partition
1210	 */
1211	partp = ((struct dos_partition *) &mboot.parts);
1212	for (i = 0; i < NDOSPART; i++)
1213	    partp[i].dp_flag = 0;
1214	partp[partition-1].dp_flag = ACTIVE;
1215
1216	status = 1;
1217	break;
1218    }
1219    return (status);
1220}
1221
1222
1223static int
1224process_line(line)
1225    char	*line;
1226{
1227    CMD		command;
1228    int		status = 1;
1229
1230    while (1)
1231    {
1232	parse_config_line(line, &command);
1233	switch (command.cmd)
1234	{
1235	case 0:
1236	    /*
1237	     * Comment or blank line
1238	     */
1239	    break;
1240	case 'g':
1241	    /*
1242	     * Set geometry
1243	     */
1244	    status = process_geometry(&command);
1245	    break;
1246	case 'p':
1247	    status = process_partition(&command);
1248	    break;
1249	case 'a':
1250	    status = process_active(&command);
1251	    break;
1252	default:
1253	    status = 0;
1254	    break;
1255	}
1256	break;
1257    }
1258    return (status);
1259}
1260
1261
1262static int
1263read_config(config_file)
1264    char *config_file;
1265{
1266    FILE	*fp = NULL;
1267    int		status = 1;
1268    char	buf[1010];
1269
1270    while (1)	/* dirty trick used to insure one exit point for this
1271		   function */
1272    {
1273	if (strcmp(config_file, "-") != 0)
1274	{
1275	    /*
1276	     * We're not reading from stdin
1277	     */
1278	    if ((fp = fopen(config_file, "r")) == NULL)
1279	    {
1280		status = 0;
1281		break;
1282	    }
1283	}
1284	else
1285	{
1286	    fp = stdin;
1287	}
1288	current_line_number = 0;
1289	while (!feof(fp))
1290	{
1291	    if (fgets(buf, sizeof(buf), fp) == NULL)
1292	    {
1293		break;
1294	    }
1295	    ++current_line_number;
1296	    status = process_line(buf);
1297	    if (status == 0)
1298	    {
1299		break;
1300	    }
1301	}
1302	break;
1303    }
1304    if (fp)
1305    {
1306	/*
1307	 * It doesn't matter if we're reading from stdin, as we've reached EOF
1308	 */
1309	fclose(fp);
1310    }
1311    return (status);
1312}
1313
1314
1315static void
1316reset_boot(void)
1317{
1318    int				i;
1319    struct dos_partition	*partp;
1320
1321    init_boot();
1322    for (i = 0; i < 4; ++i)
1323    {
1324	partp = ((struct dos_partition *) &mboot.parts) + i;
1325	bzero((char *)partp, sizeof (struct dos_partition));
1326    }
1327}
1328