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