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