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