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 = (disksecs / dos_cylsecs) * 376 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 = (disksecs / dos_cylsecs) * 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 sysctl_name[64]; 782 int trim_enabled = 0; 783 size_t olen = sizeof(trim_enabled); 784 char *dev_name = strdup(disk); 785 786 dev_name = strtok(dev_name + strlen("/dev/da"),"s"); 787 sprintf(sysctl_name, "kern.cam.da.%s.trim_enabled", dev_name); 788 if (sysctlbyname(sysctl_name, &trim_enabled, &olen, NULL, 0) < 0) { 789 printf("Device:%s does not support the TRIM command\n", disk); 790 usage(); 791 } 792 if (!trim_enabled) { 793 printf("Erase device option selected, but sysctl (%s) " 794 "is not enabled\n",sysctl_name); 795 usage(); 796 } 797 partp = ((struct dos_partition *) &mboot.parts) + i; 798 printf("erase sectors:%u %u\n", 799 partp->dp_start, 800 partp->dp_size); 801 802 /* Trim the Device */ 803 ioarg[0] = partp->dp_start; 804 ioarg[0] *=secsize; 805 ioarg[1] = partp->dp_size; 806 ioarg[1] *=secsize; 807 808 if (ioctl(fd, DAIOCTRIM, ioarg) < 0) { 809 printf("Device trim failed\n"); 810 usage (); 811 } 812 } 813 814 /* Getting device status */ 815 816 static int 817 open_disk(void) 818 { 819 struct stat st; 820 821 if (stat(disk, &st) == -1) { 822 if (errno == ENOENT) 823 return -2; 824 warnx("can't get file status of %s", disk); 825 return -1; 826 } 827 if (!(st.st_mode & S_IFCHR) && p_flag == 0) 828 warnx("device %s is not character special", disk); 829 if ((fd = open(disk, 830 a_flag || I_flag || B_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) { 831 if (errno == ENXIO) 832 return -2; 833 warnx("can't open device %s", disk); 834 return -1; 835 } 836 if (get_params() == -1) { 837 warnx("can't get disk parameters on %s", disk); 838 return -1; 839 } 840 return fd; 841 } 842 843 static ssize_t 844 read_disk(off_t sector, void *buf) 845 { 846 lseek(fd,(sector * 512), 0); 847 if (secsize == 0) 848 for(secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2) 849 { 850 /* try the read */ 851 int size = read(fd, buf, secsize); 852 if (size == secsize) 853 /* it worked so return */ 854 return secsize; 855 } 856 else 857 return read(fd, buf, secsize); 858 859 /* we failed to read at any of the sizes */ 860 return -1; 861 } 862 863 static ssize_t 864 write_disk(off_t sector, void *buf) 865 { 866 lseek(fd,(sector * 512), 0); 867 /* write out in the size that the read_disk found worked */ 868 return write(fd, buf, secsize); 869 } 870 871 static int 872 get_params(void) 873 { 874 struct partinfo partinfo; /* disk parameters */ 875 struct stat st; 876 877 /* 878 * NOTE: When faking up the CHS for a file image (e.g. for USB), 879 * we must use max values. If we do not then an overflowed 880 * cylinder count will, by convention, set the CHS fields to 881 * all 1's. The heads and sectors in the CHS fields will then 882 * exceed the basic geometry which can cause BIOSes to brick. 883 */ 884 if (ioctl(fd, DIOCGPART, &partinfo) == -1) { 885 if (p_flag && fstat(fd, &st) == 0 && st.st_size) { 886 sectors = MAX_SECTORS_PER_TRACK; 887 heads = MAX_HEADS; 888 cylsecs = heads * sectors; 889 cyls = st.st_size / 512 / cylsecs; 890 } else { 891 warnx("can't get disk parameters on %s; supplying dummy ones", 892 disk); 893 heads = 1; 894 cylsecs = heads * sectors; 895 } 896 } else { 897 cyls = partinfo.d_ncylinders; 898 heads = partinfo.d_nheads; 899 sectors = partinfo.d_secpertrack; 900 cylsecs = heads * sectors; 901 secsize = partinfo.media_blksize; 902 } 903 dos_cyls = cyls; 904 dos_heads = heads; 905 dos_sectors = sectors; 906 dos_cylsecs = cylsecs; 907 disksecs = (int64_t)cyls * heads * sectors; 908 return (disksecs); 909 } 910 911 912 static int 913 read_s0(void) 914 { 915 mboot.bootinst_size = secsize; 916 if (mboot.bootinst != NULL) 917 free(mboot.bootinst); 918 if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) { 919 warnx("unable to allocate buffer to read fdisk " 920 "partition table"); 921 return -1; 922 } 923 if (read_disk(0, mboot.bootinst) == -1) { 924 warnx("can't read fdisk partition table"); 925 return -1; 926 } 927 if (*(uint16_t *)&mboot.bootinst[DOSMAGICOFFSET] != BOOT_MAGIC) { 928 warnx("invalid fdisk partition table found"); 929 /* So should we initialize things */ 930 return -1; 931 } 932 memcpy(mboot.parts, &mboot.bootinst[DOSPARTOFF], sizeof(mboot.parts)); 933 return 0; 934 } 935 936 static int 937 write_s0(void) 938 { 939 #ifdef NOT_NOW 940 int flag = 1; 941 #endif 942 int sector; 943 944 memcpy(&mboot.bootinst[DOSPARTOFF], mboot.parts, sizeof(mboot.parts)); 945 /* 946 * write enable label sector before write (if necessary), 947 * disable after writing. 948 * needed if the disklabel protected area also protects 949 * sector 0. (e.g. empty disk) 950 */ 951 #ifdef NOT_NOW 952 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 953 warn("ioctl DIOCWLABEL"); 954 #endif 955 for(sector = 0; sector < mboot.bootinst_size / secsize; sector++) 956 if (write_disk(sector, 957 &mboot.bootinst[sector * secsize]) == -1) { 958 warn("can't write fdisk partition table"); 959 #ifdef NOT_NOW 960 flag = 0; 961 ioctl(fd, DIOCWLABEL, &flag); 962 #endif 963 return -1; 964 } 965 #ifdef NOT_NOW 966 flag = 0; 967 ioctl(fd, DIOCWLABEL, &flag); 968 #endif 969 return(0); 970 } 971 972 973 static int 974 ok(const char *str) 975 { 976 printf("%s [n] ", str); 977 fflush(stdout); 978 if (fgets(lbuf, LBUF, stdin) == NULL) 979 exit(1); 980 lbuf[strlen(lbuf)-1] = 0; 981 982 if (*lbuf && 983 (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || 984 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) 985 return 1; 986 else 987 return 0; 988 } 989 990 static int 991 decimal(const char *str, int *num, int deflt) 992 { 993 int acc = 0, c; 994 char *cp; 995 996 while (1) { 997 printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); 998 fflush(stdout); 999 if (fgets(lbuf, LBUF, stdin) == NULL) 1000 exit(1); 1001 lbuf[strlen(lbuf)-1] = 0; 1002 1003 if (!*lbuf) 1004 return 0; 1005 1006 cp = lbuf; 1007 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 1008 if (!c) 1009 return 0; 1010 while ((c = *cp++)) { 1011 if (c <= '9' && c >= '0') 1012 acc = acc * 10 + c - '0'; 1013 else 1014 break; 1015 } 1016 if (c == ' ' || c == '\t') 1017 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 1018 if (!c) { 1019 *num = acc; 1020 return 1; 1021 } else 1022 printf("%s is an invalid decimal number. Try again.\n", 1023 lbuf); 1024 } 1025 1026 } 1027 1028 static const char * 1029 get_type(int type) 1030 { 1031 int numentries = NELEM(part_types); 1032 int counter = 0; 1033 struct part_type *ptr = part_types; 1034 1035 1036 while(counter < numentries) 1037 { 1038 if (ptr->type == type) 1039 { 1040 return(ptr->name); 1041 } 1042 ptr++; 1043 counter++; 1044 } 1045 return("unknown"); 1046 } 1047 1048 1049 static void 1050 parse_config_line(char *line, CMD *command) 1051 { 1052 char *cp, *end; 1053 1054 cp = line; 1055 while (1) /* dirty trick used to insure one exit point for this 1056 function */ 1057 { 1058 memset(command, 0, sizeof(*command)); 1059 1060 while (isspace(*cp)) ++cp; 1061 if (*cp == '\0' || *cp == '#') 1062 { 1063 break; 1064 } 1065 command->cmd = *cp++; 1066 1067 /* 1068 * Parse args 1069 */ 1070 while (1) 1071 { 1072 while (isspace(*cp)) ++cp; 1073 if (*cp == '#') 1074 { 1075 break; /* found comment */ 1076 } 1077 if (isalpha(*cp)) 1078 { 1079 command->args[command->n_args].argtype = *cp++; 1080 } 1081 if (!isdigit(*cp)) 1082 { 1083 break; /* assume end of line */ 1084 } 1085 end = NULL; 1086 command->args[command->n_args].arg_val = strtoll(cp, &end, 0); 1087 if (cp == end) 1088 { 1089 break; /* couldn't parse number */ 1090 } 1091 cp = end; 1092 command->n_args++; 1093 } 1094 break; 1095 } 1096 } 1097 1098 1099 static int 1100 process_geometry(CMD *command) 1101 { 1102 int status = 1, i; 1103 1104 while (1) 1105 { 1106 geom_processed = 1; 1107 if (part_processed) 1108 { 1109 warnx( 1110 "ERROR line %d: the geometry specification line must occur before\n\ 1111 all partition specifications", 1112 current_line_number); 1113 status = 0; 1114 break; 1115 } 1116 if (command->n_args != 3) 1117 { 1118 warnx("ERROR line %d: incorrect number of geometry args", 1119 current_line_number); 1120 status = 0; 1121 break; 1122 } 1123 dos_cyls = -1; 1124 dos_heads = -1; 1125 dos_sectors = -1; 1126 for (i = 0; i < 3; ++i) 1127 { 1128 switch (command->args[i].argtype) 1129 { 1130 case 'c': 1131 dos_cyls = command->args[i].arg_val; 1132 break; 1133 case 'h': 1134 dos_heads = command->args[i].arg_val; 1135 break; 1136 case 's': 1137 dos_sectors = command->args[i].arg_val; 1138 break; 1139 default: 1140 warnx( 1141 "ERROR line %d: unknown geometry arg type: '%c' (0x%02x)", 1142 current_line_number, command->args[i].argtype, 1143 command->args[i].argtype); 1144 status = 0; 1145 break; 1146 } 1147 } 1148 if (status == 0) 1149 { 1150 break; 1151 } 1152 1153 dos_cylsecs = dos_heads * dos_sectors; 1154 1155 /* 1156 * Do sanity checks on parameter values 1157 */ 1158 if (dos_cyls < 0) 1159 { 1160 warnx("ERROR line %d: number of cylinders not specified", 1161 current_line_number); 1162 status = 0; 1163 } 1164 if (dos_cyls == 0 || dos_cyls > 1024) 1165 { 1166 warnx( 1167 "WARNING line %d: number of cylinders (%d) may be out-of-range\n\ 1168 (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\ 1169 is dedicated to DragonFly)", 1170 current_line_number, dos_cyls); 1171 } 1172 1173 if (dos_heads < 0) 1174 { 1175 warnx("ERROR line %d: number of heads not specified", 1176 current_line_number); 1177 status = 0; 1178 } 1179 else if (dos_heads < 1 || dos_heads > 256) 1180 { 1181 warnx("ERROR line %d: number of heads must be within (1-256)", 1182 current_line_number); 1183 status = 0; 1184 } 1185 1186 if (dos_sectors < 0) 1187 { 1188 warnx("ERROR line %d: number of sectors not specified", 1189 current_line_number); 1190 status = 0; 1191 } 1192 else if (dos_sectors < MIN_SECTORS_PER_TRACK || dos_sectors > MAX_SECTORS_PER_TRACK) 1193 { 1194 warnx("ERROR line %d: number of sectors must be within (1-63)", 1195 current_line_number); 1196 status = 0; 1197 } 1198 1199 break; 1200 } 1201 return (status); 1202 } 1203 1204 1205 static int 1206 process_partition(CMD *command) 1207 { 1208 int status = 0, part; 1209 uint32_t prev_head_boundary, prev_cyl_boundary; 1210 uint32_t adj_size, max_end; 1211 struct dos_partition *partp; 1212 1213 while (1) 1214 { 1215 part_processed = 1; 1216 if (command->n_args != 4) 1217 { 1218 warnx("ERROR line %d: incorrect number of partition args", 1219 current_line_number); 1220 break; 1221 } 1222 part = command->args[0].arg_val; 1223 if (part < 1 || part > 4) 1224 { 1225 warnx("ERROR line %d: invalid partition number %d", 1226 current_line_number, part); 1227 break; 1228 } 1229 partp = ((struct dos_partition *) &mboot.parts) + part - 1; 1230 bzero((char *)partp, sizeof (struct dos_partition)); 1231 partp->dp_typ = command->args[1].arg_val; 1232 partp->dp_start = command->args[2].arg_val; 1233 partp->dp_size = command->args[3].arg_val; 1234 max_end = partp->dp_start + partp->dp_size; 1235 1236 if (partp->dp_typ == 0) 1237 { 1238 /* 1239 * Get out, the partition is marked as unused. 1240 */ 1241 /* 1242 * Insure that it's unused. 1243 */ 1244 bzero((char *)partp, sizeof (struct dos_partition)); 1245 status = 1; 1246 break; 1247 } 1248 1249 /* 1250 * Adjust start upwards, if necessary, to fall on an head boundary. 1251 */ 1252 if (partp->dp_start % dos_sectors != 0) 1253 { 1254 prev_head_boundary = partp->dp_start / dos_sectors * dos_sectors; 1255 if (max_end < (uint32_t)dos_sectors || 1256 prev_head_boundary > max_end - dos_sectors) 1257 { 1258 /* 1259 * Can't go past end of partition 1260 */ 1261 warnx( 1262 "ERROR line %d: unable to adjust start of partition %d to fall on\n\ 1263 a head boundary", 1264 current_line_number, part); 1265 break; 1266 } 1267 warnx( 1268 "WARNING: adjusting start offset of partition %d\n\ 1269 from %u to %u, to fall on a head boundary", 1270 part, (u_int)partp->dp_start, 1271 (u_int)(prev_head_boundary + dos_sectors)); 1272 partp->dp_start = prev_head_boundary + dos_sectors; 1273 } 1274 1275 /* 1276 * Adjust size downwards, if necessary, to fall on a cylinder 1277 * boundary. 1278 */ 1279 prev_cyl_boundary = 1280 ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; 1281 if (prev_cyl_boundary > partp->dp_start) 1282 adj_size = prev_cyl_boundary - partp->dp_start; 1283 else 1284 { 1285 warnx( 1286 "ERROR: could not adjust partition to start on a head boundary\n\ 1287 and end on a cylinder boundary."); 1288 return (0); 1289 } 1290 if (adj_size != partp->dp_size) 1291 { 1292 warnx( 1293 "WARNING: adjusting size of partition %d from %u to %u\n\ 1294 to end on a cylinder boundary", 1295 part, (u_int)partp->dp_size, (u_int)adj_size); 1296 partp->dp_size = adj_size; 1297 } 1298 if (partp->dp_size == 0) 1299 { 1300 warnx("ERROR line %d: size of partition %d is zero", 1301 current_line_number, part); 1302 break; 1303 } 1304 1305 dos(partp); 1306 status = 1; 1307 break; 1308 } 1309 return (status); 1310 } 1311 1312 1313 static int 1314 process_active(CMD *command) 1315 { 1316 int status = 0, part, i; 1317 struct dos_partition *partp; 1318 1319 while (1) 1320 { 1321 active_processed = 1; 1322 if (command->n_args != 1) 1323 { 1324 warnx("ERROR line %d: incorrect number of active args", 1325 current_line_number); 1326 status = 0; 1327 break; 1328 } 1329 part = command->args[0].arg_val; 1330 if (part < 1 || part > 4) 1331 { 1332 warnx("ERROR line %d: invalid partition number %d", 1333 current_line_number, part); 1334 break; 1335 } 1336 /* 1337 * Reset active partition 1338 */ 1339 partp = ((struct dos_partition *) &mboot.parts); 1340 for (i = 0; i < NDOSPART; i++) 1341 partp[i].dp_flag = 0; 1342 partp[part-1].dp_flag = ACTIVE; 1343 1344 status = 1; 1345 break; 1346 } 1347 return (status); 1348 } 1349 1350 1351 static int 1352 process_line(char *line) 1353 { 1354 CMD command; 1355 int status = 1; 1356 1357 while (1) 1358 { 1359 parse_config_line(line, &command); 1360 switch (command.cmd) 1361 { 1362 case 0: 1363 /* 1364 * Comment or blank line 1365 */ 1366 break; 1367 case 'g': 1368 /* 1369 * Set geometry 1370 */ 1371 status = process_geometry(&command); 1372 break; 1373 case 'p': 1374 status = process_partition(&command); 1375 break; 1376 case 'a': 1377 status = process_active(&command); 1378 break; 1379 default: 1380 status = 0; 1381 break; 1382 } 1383 break; 1384 } 1385 return (status); 1386 } 1387 1388 1389 static int 1390 read_config(char *config_file) 1391 { 1392 FILE *fp = NULL; 1393 int status = 1; 1394 char buf[1010]; 1395 1396 while (1) /* dirty trick used to insure one exit point for this 1397 function */ 1398 { 1399 if (strcmp(config_file, "-") != 0) 1400 { 1401 /* 1402 * We're not reading from stdin 1403 */ 1404 if ((fp = fopen(config_file, "r")) == NULL) 1405 { 1406 status = 0; 1407 break; 1408 } 1409 } 1410 else 1411 { 1412 fp = stdin; 1413 } 1414 current_line_number = 0; 1415 while (!feof(fp)) 1416 { 1417 if (fgets(buf, sizeof(buf), fp) == NULL) 1418 { 1419 break; 1420 } 1421 ++current_line_number; 1422 status = process_line(buf); 1423 if (status == 0) 1424 { 1425 break; 1426 } 1427 } 1428 break; 1429 } 1430 if (fp) 1431 { 1432 /* 1433 * It doesn't matter if we're reading from stdin, as we've reached EOF 1434 */ 1435 fclose(fp); 1436 } 1437 return (status); 1438 } 1439 1440 1441 static void 1442 reset_boot(void) 1443 { 1444 int i; 1445 struct dos_partition *partp; 1446 1447 init_boot(); 1448 for (i = 0; i < 4; ++i) 1449 { 1450 partp = ((struct dos_partition *) &mboot.parts) + i; 1451 bzero((char *)partp, sizeof (struct dos_partition)); 1452 } 1453 } 1454 1455 static int 1456 sanitize_partition(struct dos_partition *partp) 1457 { 1458 uint32_t prev_head_boundary, prev_cyl_boundary; 1459 uint32_t max_end, size, start; 1460 1461 start = partp->dp_start; 1462 size = partp->dp_size; 1463 max_end = start + size; 1464 /* Only allow a zero size if the partition is being marked unused. */ 1465 if (size == 0) { 1466 if (start == 0 && partp->dp_typ == 0) 1467 return (1); 1468 warnx("ERROR: size of partition is zero"); 1469 return (0); 1470 } 1471 /* Return if no adjustment is necessary. */ 1472 if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0) 1473 return (1); 1474 1475 if (start == 0) { 1476 warnx("WARNING: partition overlaps with partition table"); 1477 if (ok("Correct this automatically?")) 1478 start = dos_sectors; 1479 } 1480 if (start % dos_sectors != 0) 1481 warnx("WARNING: partition does not start on a head boundary"); 1482 if ((start +size) % dos_sectors != 0) 1483 warnx("WARNING: partition does not end on a cylinder boundary"); 1484 warnx("WARNING: this may confuse the BIOS or some operating systems"); 1485 if (!ok("Correct this automatically?")) 1486 return (1); 1487 1488 /* 1489 * Adjust start upwards, if necessary, to fall on an head boundary. 1490 */ 1491 if (start % dos_sectors != 0) { 1492 prev_head_boundary = start / dos_sectors * dos_sectors; 1493 if (max_end < (uint32_t)dos_sectors || 1494 prev_head_boundary >= max_end - dos_sectors) { 1495 /* 1496 * Can't go past end of partition 1497 */ 1498 warnx( 1499 "ERROR: unable to adjust start of partition to fall on a head boundary"); 1500 return (0); 1501 } 1502 start = prev_head_boundary + dos_sectors; 1503 } 1504 1505 /* 1506 * Adjust size downwards, if necessary, to fall on a cylinder 1507 * boundary. 1508 */ 1509 prev_cyl_boundary = ((start + size) / dos_cylsecs) * dos_cylsecs; 1510 if (prev_cyl_boundary > start) 1511 size = prev_cyl_boundary - start; 1512 else { 1513 warnx("ERROR: could not adjust partition to start on a head boundary\n\ 1514 and end on a cylinder boundary."); 1515 return (0); 1516 } 1517 1518 /* Finally, commit any changes to partp and return. */ 1519 if (start != partp->dp_start) { 1520 warnx("WARNING: adjusting start offset of partition to %u", 1521 (u_int)start); 1522 partp->dp_start = start; 1523 } 1524 if (size != partp->dp_size) { 1525 warnx("WARNING: adjusting size of partition to %u", (u_int)size); 1526 partp->dp_size = size; 1527 } 1528 1529 return (1); 1530 } 1531