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