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