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