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