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