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