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 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 } 1530