sbin/fdisk: cleanups
[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         sysctlbyname(sysctl_name, &trim_enabled, &olen, NULL, 0);
787         if (errno == ENOENT) {
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 = (sizeof(part_types)/sizeof(struct part_type));
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 }