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