1 /* $NetBSD: fdisk.c,v 1.110 2007/11/29 23:19:25 dsl Exp $ */ 2 3 /* 4 * Mach Operating System 5 * Copyright (c) 1992 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie Mellon 26 * the rights to redistribute these changes. 27 */ 28 29 /* 30 * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University 31 * Copyright (c) 1989 Robert. V. Baron 32 * Created. 33 */ 34 35 #if HAVE_NBTOOL_CONFIG_H 36 #include "nbtool_config.h" 37 #endif 38 39 #include <sys/cdefs.h> 40 41 #ifndef lint 42 __RCSID("$NetBSD: fdisk.c,v 1.110 2007/11/29 23:19:25 dsl Exp $"); 43 #endif /* not lint */ 44 45 #define MBRPTYPENAMES 46 #include <sys/types.h> 47 #include <sys/param.h> 48 #include <sys/stat.h> 49 #include <ctype.h> 50 #include <err.h> 51 #include <errno.h> 52 #include <fcntl.h> 53 #include <paths.h> 54 #include <stdarg.h> 55 #include <stddef.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <unistd.h> 60 #include <vis.h> 61 62 #if !HAVE_NBTOOL_CONFIG_H 63 #include <sys/disklabel.h> 64 #include <sys/bootblock.h> 65 #include <sys/ioctl.h> 66 #include <sys/sysctl.h> 67 #include <disktab.h> 68 #include <util.h> 69 #else 70 #include <nbinclude/sys/disklabel.h> 71 #include <nbinclude/sys/bootblock.h> 72 #include "../../include/disktab.h" 73 /* We enforce -F, so none of these possibly undefined items can be needed */ 74 #define opendisk(path, fl, buf, buflen, cooked) (-1) 75 #ifndef DIOCGDEFLABEL 76 #define DIOCGDEFLABEL 0 77 #endif 78 #ifndef DIOCGDINFO 79 #define DIOCGDINFO 0 80 #endif 81 #ifndef DIOCWLABEL 82 #define DIOCWLABEL 0 83 #endif 84 #endif /* HAVE_NBTOOL_CONFIG_H */ 85 86 #define DEFAULT_BOOTDIR "/usr/mdec" 87 88 #define LE_MBR_MAGIC htole16(MBR_MAGIC) 89 #define LE_MBR_BS_MAGIC htole16(MBR_BS_MAGIC) 90 91 #if defined(__i386__) || defined(__x86_64__) 92 #if !HAVE_NBTOOL_CONFIG_H 93 #include <machine/cpu.h> 94 #endif /* !HAVE_NBTOOL_CONFIG_H */ 95 #define BOOTSEL 96 #endif 97 98 #ifdef BOOTSEL 99 100 #define DEFAULT_BOOTCODE "mbr" 101 #define DEFAULT_BOOTSELCODE "mbr_bootsel" 102 #define DEFAULT_BOOTEXTCODE "mbr_ext" 103 104 /* Scan values for the various keys we use, as returned by the BIOS */ 105 #define SCAN_ENTER 0x1c 106 #define SCAN_F1 0x3b 107 #define SCAN_1 0x2 108 109 #endif 110 111 #define LBUF 100 112 static char lbuf[LBUF]; 113 114 #ifndef PRIdaddr 115 #define PRIdaddr PRId64 116 #endif 117 118 #ifndef PRId64 119 #if HAVE_LONG_LONG 120 #define PRId64 "lld" 121 #endif 122 #endif 123 124 #ifndef PRId32 125 #define PRId32 "ld" 126 #endif 127 128 #ifndef _PATH_DEFDISK 129 #define _PATH_DEFDISK "/dev/rwd0d" 130 #endif 131 132 const char *disk = _PATH_DEFDISK; 133 134 struct disklabel disklabel; /* disk parameters */ 135 136 unsigned int cylinders, sectors, heads; 137 daddr_t disksectors; 138 #define cylindersectors (heads * sectors) 139 140 struct mbr_sector mboot; 141 142 143 struct { 144 struct mbr_sector *ptn; /* array of pbrs */ 145 daddr_t base; /* first sector of ext. ptn */ 146 daddr_t limit; /* last sector of ext. ptn */ 147 int num_ptn; /* number of contained partitions */ 148 int ptn_id; /* entry in mbr */ 149 int is_corrupt; /* 1 if extended chain illegal */ 150 } ext; 151 152 const char *boot_dir = DEFAULT_BOOTDIR; 153 char *boot_path = 0; /* name of file we actually opened */ 154 155 #ifdef BOOTSEL 156 157 #define DEFAULT_ACTIVE (~(daddr_t)0) 158 159 #define OPTIONS "0123BFSafiluvs:b:c:E:r:w:t:T:" 160 #else 161 #define change_part(e, p, id, st, sz, bm) change__part(e, p, id, st, sz) 162 #define OPTIONS "0123FSafiluvs:b:c:E:r:w:" 163 #endif 164 165 unsigned int dos_cylinders; 166 unsigned int dos_heads; 167 unsigned int dos_sectors; 168 daddr_t dos_disksectors; 169 #define dos_cylindersectors (dos_heads * dos_sectors) 170 #define dos_totalsectors (dos_heads * dos_sectors * dos_cylinders) 171 172 #define DOSSECT(s,c) (((s) & 0x3f) | (((c) >> 2) & 0xc0)) 173 #define DOSCYL(c) ((c) & 0xff) 174 #define SEC_IN_1M (1024 * 1024 / 512) 175 #define SEC_TO_MB(sec) ((unsigned int)(((sec) + SEC_IN_1M / 2) / SEC_IN_1M)) 176 #define SEC_TO_CYL(sec) (((sec) + dos_cylindersectors/2) / dos_cylindersectors) 177 178 #define MAXCYL 1024 /* Usual limit is 1023 */ 179 #define MAXHEAD 256 /* Usual limit is 255 */ 180 #define MAXSECTOR 63 181 int partition = -1; 182 183 int fd = -1, wfd = -1, *rfd = &fd; 184 char *disk_file = NULL; 185 char *disk_type = NULL; 186 187 int a_flag; /* set active partition */ 188 int i_flag; /* init bootcode */ 189 int u_flag; /* update partition data */ 190 int v_flag; /* more verbose */ 191 int sh_flag; /* Output data as shell defines */ 192 int f_flag; /* force --not interactive */ 193 int s_flag; /* set id,offset,size */ 194 int b_flag; /* Set cyl, heads, secs (as c/h/s) */ 195 int B_flag; /* Edit/install bootselect code */ 196 int E_flag; /* extended partition number */ 197 int b_cyl, b_head, b_sec; /* b_flag values. */ 198 199 #if !HAVE_NBTOOL_CONFIG_H 200 int F_flag = 0; 201 #else 202 /* Tool - force 'file' mode to avoid unsupported functions and ioctls */ 203 int F_flag = 1; 204 #endif 205 206 struct mbr_sector bootcode[8192 / sizeof (struct mbr_sector)]; 207 int bootsize; /* actual size of bootcode */ 208 int boot_installed; /* 1 if we've copied code into the mbr */ 209 210 #if (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H 211 struct disklist *dl; 212 #endif 213 214 215 #define KNOWN_SYSIDS (sizeof(mbr_ptypes)/sizeof(mbr_ptypes[0])) 216 217 void usage(void); 218 void print_s0(int); 219 void print_part(struct mbr_sector *, int, daddr_t); 220 void print_mbr_partition(struct mbr_sector *, int, daddr_t, daddr_t, int); 221 void print_pbr(daddr_t, int, uint8_t); 222 int is_all_zero(const unsigned char *, size_t); 223 void printvis(int, const char *, const char *, size_t); 224 int read_boot(const char *, void *, size_t, int); 225 void init_sector0(int); 226 void intuit_translated_geometry(void); 227 void get_geometry(void); 228 void get_extended_ptn(void); 229 #if (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H 230 void get_diskname(const char *, char *, size_t); 231 #endif /* (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H */ 232 int change_part(int, int, int, daddr_t, daddr_t, char *); 233 void print_params(void); 234 void change_active(int); 235 void get_params_to_use(void); 236 void dos(int, unsigned char *, unsigned char *, unsigned char *); 237 int open_disk(int); 238 int read_disk(daddr_t, void *); 239 int write_disk(daddr_t, void *); 240 int get_params(void); 241 int read_s0(daddr_t, struct mbr_sector *); 242 int write_mbr(void); 243 int yesno(const char *, ...); 244 int decimal(const char *, int, int, int, int); 245 #define DEC_SEC 1 /* asking for a sector number */ 246 #define DEC_RND 2 /* round to end of first track */ 247 #define DEC_RND_0 4 /* round 0 to size of a track */ 248 #define DEC_RND_DOWN 8 /* subtract 1 track */ 249 #define DEC_RND_DOWN_2 16 /* subtract 2 tracks */ 250 void string(const char *, int, char *); 251 int ptn_id(const char *, int *); 252 int type_match(const void *, const void *); 253 const char *get_type(int); 254 int get_mapping(int, unsigned int *, unsigned int *, unsigned int *, unsigned long *); 255 #ifdef BOOTSEL 256 daddr_t configure_bootsel(daddr_t); 257 void install_bootsel(int); 258 daddr_t get_default_boot(void); 259 void set_default_boot(daddr_t); 260 #endif 261 262 static void 263 initvar_disk(const char **diskp) 264 { 265 #if !HAVE_NBTOOL_CONFIG_H 266 int mib[2]; 267 size_t len; 268 char *root_device; 269 270 mib[0] = CTL_KERN; 271 mib[1] = KERN_ROOT_DEVICE; 272 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1 || 273 (root_device = malloc(len)) == NULL || 274 sysctl(mib, 2, root_device, &len, NULL, 0) == -1) 275 return; 276 277 *diskp = root_device; 278 #endif /* HAVE_NBTOOL_CONFIG_H */ 279 } 280 281 int 282 main(int argc, char *argv[]) 283 { 284 struct stat sb; 285 int ch; 286 size_t len; 287 char *cp; 288 int n; 289 #ifdef BOOTSEL 290 daddr_t default_ptn; /* start sector of default ptn */ 291 char *cbootmenu = 0; 292 #endif 293 294 int csysid, cstart, csize; /* For the b_flag. */ 295 296 a_flag = i_flag = u_flag = sh_flag = f_flag = s_flag = b_flag = 0; 297 v_flag = 0; 298 E_flag = 0; 299 csysid = cstart = csize = 0; 300 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 301 switch (ch) { 302 case '0': 303 partition = 0; 304 break; 305 case '1': 306 partition = 1; 307 break; 308 case '2': 309 partition = 2; 310 break; 311 case '3': 312 partition = 3; 313 break; 314 case 'E': /* Extended partition number */ 315 E_flag = 1; 316 partition = strtoul(optarg, &cp, 0); 317 if (*cp || partition < 0) 318 errx(1, "Bad partition number -E %s.", optarg); 319 break; 320 #ifdef BOOTSEL 321 case 'B': /* Bootselect parameters */ 322 B_flag = 1; 323 break; 324 #endif 325 case 'F': /* device argument is really a file */ 326 F_flag = 1; 327 break; 328 case 'S': /* Output as shell variables */ 329 sh_flag = 1; 330 break; 331 case 'a': /* Set active partition */ 332 a_flag = 1; 333 break; 334 case 'f': /* Non interactive */ 335 f_flag = 1; 336 break; 337 case 'i': /* Always update bootcode */ 338 i_flag = 1; 339 break; 340 case 'l': /* List known partition types */ 341 for (len = 0; len < KNOWN_SYSIDS; len++) 342 printf("%03d %s\n", mbr_ptypes[len].id, 343 mbr_ptypes[len].name); 344 return 0; 345 case 'u': /* Update partition details */ 346 u_flag = 1; 347 break; 348 case 'v': /* Be verbose */ 349 v_flag++; 350 break; 351 case 's': /* Partition details */ 352 s_flag = 1; 353 if (sscanf(optarg, "%d/%d/%d%n", &csysid, &cstart, 354 &csize, &n) == 3) { 355 if (optarg[n] == 0) 356 break; 357 #ifdef BOOTSEL 358 if (optarg[n] == '/') { 359 cbootmenu = optarg + n + 1; 360 break; 361 } 362 #endif 363 } 364 errx(1, "Bad argument to the -s flag."); 365 break; 366 case 'b': /* BIOS geometry */ 367 b_flag = 1; 368 if (sscanf(optarg, "%d/%d/%d%n", &b_cyl, &b_head, 369 &b_sec, &n) != 3 || optarg[n] != 0) 370 errx(1, "Bad argument to the -b flag."); 371 if (b_cyl > MAXCYL) 372 b_cyl = MAXCYL; 373 break; 374 case 'c': /* file/directory containing boot code */ 375 if (strchr(optarg, '/') != NULL && 376 stat(optarg, &sb) == 0 && 377 (sb.st_mode & S_IFMT) == S_IFDIR) { 378 boot_dir = optarg; 379 break; 380 } 381 bootsize = read_boot(optarg, bootcode, 382 sizeof bootcode, 1); 383 i_flag = 1; 384 break; 385 case 'r': /* read data from disk_file (not raw disk) */ 386 rfd = &wfd; 387 /* FALLTHROUGH */ 388 case 'w': /* write data to disk_file */ 389 disk_file = optarg; 390 break; 391 case 't': 392 if (setdisktab(optarg) == -1) 393 errx(EXIT_FAILURE, "bad disktab"); 394 break; 395 case 'T': 396 disk_type = optarg; 397 break; 398 default: 399 usage(); 400 } 401 argc -= optind; 402 argv += optind; 403 404 if (disk_type != NULL && getdiskbyname(disk_type) == NULL) 405 errx(EXIT_FAILURE, "bad disktype"); 406 407 if (sh_flag && (a_flag || i_flag || u_flag || f_flag || s_flag)) 408 usage(); 409 410 if (B_flag && f_flag) { 411 warnx("Bootselector may only be configured interactively"); 412 usage(); 413 } 414 415 if (f_flag && u_flag && !s_flag) { 416 warnx("Partition data not specified"); 417 usage(); 418 } 419 420 if (s_flag && partition == -1) { 421 warnx("-s flag requires a partition selected."); 422 usage(); 423 } 424 425 if (argc > 1) 426 usage(); 427 428 if (argc > 0) 429 disk = argv[0]; 430 else if (!F_flag) { 431 /* Default to boot device */ 432 initvar_disk(&disk); 433 } 434 435 if (open_disk(B_flag || a_flag || i_flag || u_flag) < 0) 436 exit(1); 437 438 if (read_s0(0, &mboot)) 439 /* must have been a blank disk */ 440 init_sector0(1); 441 442 #if (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H 443 get_geometry(); 444 #else 445 intuit_translated_geometry(); 446 #endif 447 get_extended_ptn(); 448 449 #ifdef BOOTSEL 450 default_ptn = get_default_boot(); 451 #endif 452 453 if (E_flag && !u_flag && partition >= ext.num_ptn) 454 errx(1, "Extended partition %d is not defined.", partition); 455 456 if (u_flag && (!f_flag || b_flag)) 457 get_params_to_use(); 458 459 /* Do the update stuff! */ 460 if (u_flag) { 461 if (s_flag) 462 change_part(E_flag, partition, csysid, cstart, csize, 463 cbootmenu); 464 else { 465 int part = partition, chg_ext = E_flag, prompt = 1; 466 do { 467 if (prompt) { 468 printf("\n"); 469 print_s0(partition); 470 } 471 if (partition == -1) 472 part = ptn_id( 473 "Which partition do you want to change?", 474 &chg_ext); 475 if (part < 0) 476 break; 477 prompt = change_part(chg_ext, part, 0, 0, 0, 0); 478 } while (partition == -1); 479 } 480 } else 481 if (!i_flag && !B_flag) { 482 print_params(); 483 print_s0(partition); 484 } 485 486 if (a_flag && !E_flag) 487 change_active(partition); 488 489 #ifdef BOOTSEL 490 if (B_flag || u_flag || i_flag) 491 /* Ensure the mbr code supports this configuration */ 492 install_bootsel(0); 493 if (B_flag) 494 default_ptn = configure_bootsel(default_ptn); 495 set_default_boot(default_ptn); 496 #else 497 if (i_flag) 498 init_sector0(0); 499 #endif 500 501 if (u_flag || a_flag || i_flag || B_flag) { 502 if (!f_flag) { 503 printf("\nWe haven't written the MBR back to disk " 504 "yet. This is your last chance.\n"); 505 if (u_flag) 506 print_s0(-1); 507 if (yesno("Should we write new partition table?")) 508 write_mbr(); 509 } else 510 write_mbr(); 511 } 512 513 exit(0); 514 } 515 516 void 517 usage(void) 518 { 519 int indent = 7 + (int)strlen(getprogname()) + 1; 520 521 (void)fprintf(stderr, "usage: %s [-afiluvBS] " 522 "[-b cylinders/heads/sectors] \\\n" 523 "%*s[-0123 | -E num " 524 "[-s id/start/size[/bootmenu]]] \\\n" 525 "%*s[-t disktab] [-T disktype] \\\n" 526 "%*s[-c bootcode] " 527 "[-r|-w file] [device]\n" 528 "\t-a change active partition\n" 529 "\t-f force - not interactive\n" 530 "\t-i initialise MBR code\n" 531 "\t-l list partition types\n" 532 "\t-u update partition data\n" 533 "\t-v verbose output, -v -v more verbose still\n" 534 "\t-B update bootselect options\n" 535 "\t-F treat device as a regular file\n" 536 "\t-S output as shell defines\n" 537 "\t-r and -w access 'file' for non-destructive testing\n", 538 getprogname(), indent, "", indent, "", indent, ""); 539 exit(1); 540 } 541 542 static daddr_t 543 ext_offset(int part) 544 { 545 daddr_t offset = ext.base; 546 547 if (part != 0) 548 offset += le32toh(ext.ptn[part - 1].mbr_parts[1].mbrp_start); 549 return offset; 550 } 551 552 void 553 print_s0(int which) 554 { 555 int part; 556 557 if (which == -1) { 558 if (!sh_flag) 559 printf("Partition table:\n"); 560 for (part = 0; part < MBR_PART_COUNT; part++) { 561 if (!sh_flag) 562 printf("%d: ", part); 563 print_part(&mboot, part, 0); 564 } 565 if (!sh_flag) { 566 if (ext.is_corrupt) 567 printf("Extended partition table is corrupt\n"); 568 else 569 if (ext.num_ptn != 0) 570 printf("Extended partition table:\n"); 571 } 572 for (part = 0; part < ext.num_ptn; part++) { 573 if (!sh_flag) 574 printf("E%d: ", part); 575 print_part(&ext.ptn[part], 0, ext_offset(part)); 576 if (!sh_flag && v_flag >= 2) { 577 printf("link: "); 578 print_mbr_partition(&ext.ptn[part], 1, 579 ext_offset(part), ext.base, 0); 580 } 581 } 582 #ifdef BOOTSEL 583 if (!sh_flag && mboot.mbr_bootsel_magic == LE_MBR_BS_MAGIC) { 584 int tmo; 585 586 printf("Bootselector "); 587 if (mboot.mbr_bootsel.mbrbs_flags & MBR_BS_ACTIVE) { 588 printf("enabled"); 589 tmo = le16toh(mboot.mbr_bootsel.mbrbs_timeo); 590 if (tmo == 0xffff) 591 printf(", infinite timeout"); 592 else 593 printf(", timeout %d seconds", 594 (10 * tmo + 9) / 182); 595 } else 596 printf("disabled"); 597 printf(".\n"); 598 } 599 #endif 600 601 if (!sh_flag && mboot.mbr_dsn != 0) 602 printf("Drive serial number: %"PRId32" (0x%08x)\n", 603 le32toh(mboot.mbr_dsn), 604 le32toh(mboot.mbr_dsn)); 605 return; 606 } 607 608 if (E_flag) { 609 if (!sh_flag) 610 printf("Extended partition E%d:\n", which); 611 if (which > ext.num_ptn) 612 printf("Undefined\n"); 613 else 614 print_part(&ext.ptn[which], 0, ext_offset(which)); 615 } else { 616 if (!sh_flag) 617 printf("Partition %d:\n", which); 618 print_part(&mboot, which, 0); 619 } 620 } 621 622 void 623 print_part(struct mbr_sector *boot, int part, daddr_t offset) 624 { 625 struct mbr_partition *partp; 626 const char *e; 627 628 if (!sh_flag) { 629 print_mbr_partition(boot, part, offset, 0, 0); 630 return; 631 } 632 633 partp = &boot->mbr_parts[part]; 634 if (boot != &mboot) { 635 part = boot - ext.ptn; 636 e = "E"; 637 } else 638 e = ""; 639 640 if (partp->mbrp_type == 0) { 641 printf("PART%s%dSIZE=0\n", e, part); 642 return; 643 } 644 645 printf("PART%s%dID=%d\n", e, part, partp->mbrp_type); 646 printf("PART%s%dSIZE=%u\n", e, part, le32toh(partp->mbrp_size)); 647 printf("PART%s%dSTART=%"PRIdaddr"\n", e, part, 648 offset + le32toh(partp->mbrp_start)); 649 printf("PART%s%dFLAG=0x%x\n", e, part, partp->mbrp_flag); 650 printf("PART%s%dBCYL=%d\n", e, part, 651 MBR_PCYL(partp->mbrp_scyl, partp->mbrp_ssect)); 652 printf("PART%s%dBHEAD=%d\n", e, part, partp->mbrp_shd); 653 printf("PART%s%dBSEC=%d\n", e, part, MBR_PSECT(partp->mbrp_ssect)); 654 printf("PART%s%dECYL=%d\n", e, part, 655 MBR_PCYL(partp->mbrp_ecyl, partp->mbrp_esect)); 656 printf("PART%s%dEHEAD=%d\n", e, part, partp->mbrp_ehd); 657 printf("PART%s%dESEC=%d\n", e, part, MBR_PSECT(partp->mbrp_esect)); 658 } 659 660 static void 661 pr_cyls(daddr_t sector, int is_end) 662 { 663 unsigned long cyl, head, sect; 664 cyl = sector / dos_cylindersectors; 665 sect = sector - cyl * dos_cylindersectors; 666 head = sect / dos_sectors; 667 sect -= head * dos_sectors; 668 669 printf("%lu", cyl); 670 671 if (is_end) { 672 if (head == dos_heads - 1 && sect == dos_sectors - 1) 673 return; 674 } else { 675 if (head == 0 && sect == 0) 676 return; 677 } 678 679 printf("/%lu/%lu", head, sect + 1); 680 } 681 682 void 683 print_mbr_partition(struct mbr_sector *boot, int part, 684 daddr_t offset, daddr_t exoffset, int indent) 685 { 686 daddr_t start; 687 daddr_t size; 688 struct mbr_partition *partp = &boot->mbr_parts[part]; 689 struct mbr_sector eboot; 690 int p; 691 static int dumped = 0; 692 693 if (partp->mbrp_type == 0 && v_flag < 2) { 694 printf("<UNUSED>\n"); 695 return; 696 } 697 698 start = le32toh(partp->mbrp_start); 699 size = le32toh(partp->mbrp_size); 700 if (MBR_IS_EXTENDED(partp->mbrp_type)) 701 start += exoffset; 702 else 703 start += offset; 704 705 printf("%s (sysid %d)\n", get_type(partp->mbrp_type), partp->mbrp_type); 706 #ifdef BOOTSEL 707 if (boot->mbr_bootsel_magic == LE_MBR_BS_MAGIC && 708 boot->mbr_bootsel.mbrbs_nametab[part][0]) 709 printf("%*s bootmenu: %s\n", indent, "", 710 boot->mbr_bootsel.mbrbs_nametab[part]); 711 #endif 712 713 printf("%*s start %"PRIdaddr", size %"PRIdaddr, 714 indent, "", start, size); 715 if (size != 0) { 716 printf(" (%u MB, Cyls ", SEC_TO_MB(size)); 717 if (v_flag == 0 && le32toh(partp->mbrp_start) == dos_sectors) 718 pr_cyls(start - dos_sectors, 0); 719 else 720 pr_cyls(start, 0); 721 printf("-"); 722 pr_cyls(start + size - 1, 1); 723 printf(")"); 724 } 725 726 switch (partp->mbrp_flag) { 727 case 0: 728 break; 729 case MBR_PFLAG_ACTIVE: 730 printf(", Active"); 731 break; 732 default: 733 printf(", flag 0x%x", partp->mbrp_flag); 734 break; 735 } 736 printf("\n"); 737 738 if (v_flag) { 739 printf("%*s beg: cylinder %4d, head %3d, sector %2d\n", 740 indent, "", 741 MBR_PCYL(partp->mbrp_scyl, partp->mbrp_ssect), 742 partp->mbrp_shd, MBR_PSECT(partp->mbrp_ssect)); 743 printf("%*s end: cylinder %4d, head %3d, sector %2d\n", 744 indent, "", 745 MBR_PCYL(partp->mbrp_ecyl, partp->mbrp_esect), 746 partp->mbrp_ehd, MBR_PSECT(partp->mbrp_esect)); 747 } 748 749 if (! MBR_IS_EXTENDED(partp->mbrp_type)) 750 print_pbr(start, indent + 8, partp->mbrp_type); 751 752 if (!MBR_IS_EXTENDED(partp->mbrp_type) || 753 (v_flag <= 2 && !ext.is_corrupt)) 754 return; 755 756 /* 757 * Recursive dump extended table, 758 * This is read from the disk - so is wrong during editing. 759 * Just ensure we only show it once. 760 */ 761 if (dumped) 762 return; 763 764 printf("%*s Extended partition table:\n", indent, ""); 765 indent += 4; 766 if (read_s0(start, &eboot) == -1) 767 return; 768 for (p = 0; p < MBR_PART_COUNT; p++) { 769 printf("%*s%d: ", indent, "", p); 770 print_mbr_partition(&eboot, p, start, 771 exoffset ? exoffset : start, indent); 772 } 773 774 if (exoffset == 0) 775 dumped = 1; 776 } 777 778 /* Print a line with a label and a vis-encoded string */ 779 void 780 printvis(int indent, const char *label, const char *buf, size_t size) 781 { 782 char *visbuf; 783 784 if ((visbuf = malloc(size * 4 + 1)) == NULL) 785 err(1, "Malloc failed"); 786 strsvisx(visbuf, buf, size, VIS_TAB|VIS_NL|VIS_OCTAL, "\""); 787 printf("%*s%s: \"%s\"\n", 788 indent, "", 789 label, visbuf); 790 free(visbuf); 791 } 792 793 /* Check whether a buffer contains all bytes zero */ 794 int 795 is_all_zero(const unsigned char *p, size_t size) 796 { 797 798 while (size-- > 0) { 799 if (*p++ != 0) 800 return 0; 801 } 802 return 1; 803 } 804 805 /* 806 * Report on the contents of a PBR sector. 807 * 808 * We first perform several sanity checks. If vflag >= 2, we report all 809 * failing tests, but for smaller values of v_flag we stop after the 810 * first failing test. Tests are ordered in an attempt to get the most 811 * useful error message from the first failing test. 812 * 813 * If v_flag >= 2, we also report some decoded values from the PBR. 814 * These results may be meaningless, if the PBR doesn't follow common 815 * conventions. 816 * 817 * Trying to decode anything more than the magic number in the last 818 * two bytes is a layering violation, but it can be very useful in 819 * diagnosing boot failures. 820 */ 821 void 822 print_pbr(daddr_t sector, int indent, uint8_t part_type) 823 { 824 struct mbr_sector pboot; 825 unsigned char *p, *endp; 826 unsigned char val; 827 int ok; 828 int errcount = 0; 829 830 #define PBR_ERROR(...) \ 831 do { \ 832 ++errcount; \ 833 printf("%*s%s: ", indent, "", \ 834 (v_flag < 2 ? "PBR is not bootable" : "Not bootable")); \ 835 printf(__VA_ARGS__); \ 836 if (v_flag < 2) \ 837 return; \ 838 } while (/*CONSTCOND*/ 0) 839 840 if (v_flag >= 2) { 841 printf("%*sInformation from PBR:\n", 842 indent, ""); 843 indent += 4; 844 } 845 846 if (read_disk(sector, &pboot) == -1) { 847 PBR_ERROR("Sector %"PRIdaddr" is unreadable (%s)\n", 848 sector, strerror(errno)); 849 return; 850 } 851 852 /* all bytes identical? */ 853 p = (unsigned char *)&pboot; 854 endp = p + sizeof(pboot); 855 val = *p; 856 ok = 0; 857 for (; p < endp; p++) { 858 if (*p != val) { 859 ok = 1; 860 break; 861 } 862 } 863 if (! ok) 864 PBR_ERROR("All bytes are identical (0x%02x)\n", val); 865 866 if (pboot.mbr_magic != LE_MBR_MAGIC) 867 PBR_ERROR("Bad magic number (0x%04x)\n", 868 le16toh(pboot.mbr_magic)); 869 870 #if 0 871 /* Some i386 OS might fail this test. All non-i386 will fail. */ 872 if (pboot.mbr_jmpboot[0] != 0xE9 873 && pboot.mbr_jmpboot[0] != 0xEB) { 874 PBR_ERROR("Does not begin with i386 JMP instruction" 875 " (0x%02x 0x%02x0 0x%02x)\n", 876 pboot.mbr_jmpboot[0], pboot.mbr_jmpboot[1], 877 pboot.mbr_jmpboot[2]); 878 } 879 #endif 880 881 if (v_flag > 0 && errcount == 0) 882 printf("%*sPBR appears to be bootable\n", 883 indent, ""); 884 if (v_flag < 2) 885 return; 886 887 if (! is_all_zero(pboot.mbr_oemname, sizeof(pboot.mbr_oemname))) { 888 printvis(indent, "OEM name", (char *)pboot.mbr_oemname, 889 sizeof(pboot.mbr_oemname)); 890 } 891 892 if (pboot.mbr_bpb.bpb16.bsBootSig == 0x29) 893 printf("%*sBPB FAT16 boot signature found\n", 894 indent, ""); 895 if (pboot.mbr_bpb.bpb32.bsBootSig == 0x29) 896 printf("%*sBPB FAT32 boot signature found\n", 897 indent, ""); 898 899 #undef PBR_ERROR 900 } 901 902 int 903 read_boot(const char *name, void *buf, size_t len, int err_exit) 904 { 905 int bfd, ret; 906 struct stat st; 907 908 if (boot_path != NULL) 909 free(boot_path); 910 if (strchr(name, '/') == 0) 911 asprintf(&boot_path, "%s/%s", boot_dir, name); 912 else 913 boot_path = strdup(name); 914 if (boot_path == NULL) 915 err(1, "Malloc failed"); 916 917 if ((bfd = open(boot_path, O_RDONLY)) < 0 || fstat(bfd, &st) == -1) { 918 warn("%s", boot_path); 919 goto fail; 920 } 921 922 if (st.st_size > (off_t)len) { 923 warnx("%s: bootcode too large", boot_path); 924 goto fail; 925 } 926 ret = st.st_size; 927 if (ret < 0x200) { 928 warnx("%s: bootcode too small", boot_path); 929 goto fail; 930 } 931 if (read(bfd, buf, len) != ret) { 932 warn("%s", boot_path); 933 goto fail; 934 } 935 936 /* 937 * Do some sanity checking here 938 */ 939 if (((struct mbr_sector *)buf)->mbr_magic != LE_MBR_MAGIC) { 940 warnx("%s: invalid magic", boot_path); 941 goto fail; 942 } 943 944 close(bfd); 945 ret = (ret + 0x1ff) & ~0x1ff; 946 return ret; 947 948 fail: 949 if (bfd >= 0) 950 close(bfd); 951 if (err_exit) 952 exit(1); 953 return 0; 954 } 955 956 void 957 init_sector0(int zappart) 958 { 959 int i; 960 int copy_size = offsetof(struct mbr_sector, mbr_dsn); 961 962 #ifdef DEFAULT_BOOTCODE 963 if (bootsize == 0) 964 bootsize = read_boot(DEFAULT_BOOTCODE, bootcode, 965 sizeof bootcode, 1); 966 #endif 967 #ifdef BOOTSEL 968 if (mboot.mbr_bootsel_magic == LE_MBR_BS_MAGIC 969 && bootcode[0].mbr_bootsel_magic == LE_MBR_BS_MAGIC) 970 copy_size = MBR_BS_OFFSET; 971 #endif 972 973 if (bootsize != 0) { 974 boot_installed = 1; 975 memcpy(&mboot, bootcode, copy_size); 976 mboot.mbr_bootsel_magic = bootcode[0].mbr_bootsel_magic; 977 } 978 mboot.mbr_magic = LE_MBR_MAGIC; 979 980 if (!zappart) 981 return; 982 for (i = 0; i < MBR_PART_COUNT; i++) 983 memset(&mboot.mbr_parts[i], 0, sizeof(mboot.mbr_parts[i])); 984 } 985 986 void 987 get_extended_ptn(void) 988 { 989 struct mbr_partition *mp; 990 struct mbr_sector *boot; 991 daddr_t offset; 992 struct mbr_sector *nptn; 993 994 /* find first (there should only be one) extended partition */ 995 for (mp = mboot.mbr_parts; !MBR_IS_EXTENDED(mp->mbrp_type); mp++) 996 if (mp >= &mboot.mbr_parts[MBR_PART_COUNT]) 997 return; 998 999 /* 1000 * The extended partition should be structured as a linked list 1001 * (even though it appears, at first glance, to be a tree). 1002 */ 1003 ext.base = le32toh(mp->mbrp_start); 1004 ext.limit = ext.base + le32toh(mp->mbrp_size); 1005 ext.ptn_id = mp - mboot.mbr_parts; 1006 for (offset = 0;; offset = le32toh(boot->mbr_parts[1].mbrp_start)) { 1007 nptn = realloc(ext.ptn, (ext.num_ptn + 1) * sizeof *ext.ptn); 1008 if (nptn == NULL) 1009 err(1, "Malloc failed"); 1010 ext.ptn = nptn; 1011 boot = ext.ptn + ext.num_ptn; 1012 if (read_s0(offset + ext.base, boot) == -1) 1013 break; 1014 /* expect p0 to be valid and p1 to be another extended ptn */ 1015 if (MBR_IS_EXTENDED(boot->mbr_parts[0].mbrp_type)) 1016 break; 1017 if (boot->mbr_parts[1].mbrp_type != 0 && 1018 !MBR_IS_EXTENDED(boot->mbr_parts[1].mbrp_type)) 1019 break; 1020 /* p2 and p3 should be unallocated */ 1021 if (boot->mbr_parts[2].mbrp_type != 0 || 1022 boot->mbr_parts[3].mbrp_type != 0) 1023 break; 1024 /* data ptn inside extended one */ 1025 if (boot->mbr_parts[0].mbrp_type != 0 && 1026 offset + le32toh(boot->mbr_parts[0].mbrp_start) 1027 + le32toh(boot->mbr_parts[0].mbrp_size) > ext.limit) 1028 break; 1029 1030 ext.num_ptn++; 1031 1032 if (boot->mbr_parts[1].mbrp_type == 0) 1033 /* end of extended partition chain */ 1034 return; 1035 /* must be in sector order */ 1036 if (offset >= le32toh(boot->mbr_parts[1].mbrp_start)) 1037 break; 1038 } 1039 1040 warnx("Extended partition table is corrupt\n"); 1041 ext.is_corrupt = 1; 1042 ext.num_ptn = 0; 1043 } 1044 1045 #if (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H 1046 void 1047 get_diskname(const char *fullname, char *diskname, size_t size) 1048 { 1049 const char *p, *p2; 1050 size_t len; 1051 1052 p = strrchr(fullname, '/'); 1053 if (p == NULL) 1054 p = fullname; 1055 else 1056 p++; 1057 1058 if (*p == 0) { 1059 strlcpy(diskname, fullname, size); 1060 return; 1061 } 1062 1063 if (*p == 'r') 1064 p++; 1065 1066 for (p2 = p; *p2 != 0; p2++) 1067 if (isdigit((unsigned char)*p2)) 1068 break; 1069 if (*p2 == 0) { 1070 /* XXX invalid diskname? */ 1071 strlcpy(diskname, fullname, size); 1072 return; 1073 } 1074 while (isdigit((unsigned char)*p2)) 1075 p2++; 1076 1077 len = p2 - p; 1078 if (len > size) { 1079 /* XXX */ 1080 strlcpy(diskname, fullname, size); 1081 return; 1082 } 1083 1084 memcpy(diskname, p, len); 1085 diskname[len] = 0; 1086 } 1087 1088 void 1089 get_geometry(void) 1090 { 1091 int mib[2], i; 1092 size_t len; 1093 struct biosdisk_info *bip; 1094 struct nativedisk_info *nip; 1095 char diskname[8]; 1096 1097 mib[0] = CTL_MACHDEP; 1098 mib[1] = CPU_DISKINFO; 1099 if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0) { 1100 goto out; 1101 } 1102 dl = (struct disklist *) malloc(len); 1103 if (dl == NULL) 1104 err(1, "Malloc failed"); 1105 if (sysctl(mib, 2, dl, &len, NULL, 0) < 0) { 1106 free(dl); 1107 dl = 0; 1108 goto out; 1109 } 1110 1111 get_diskname(disk, diskname, sizeof diskname); 1112 1113 for (i = 0; i < dl->dl_nnativedisks; i++) { 1114 nip = &dl->dl_nativedisks[i]; 1115 if (strcmp(diskname, nip->ni_devname)) 1116 continue; 1117 /* 1118 * XXX listing possible matches is better. This is ok for 1119 * now because the user has a chance to change it later. 1120 * Also, if all the disks have the same parameters then we can 1121 * just use them, we don't need to know which disk is which. 1122 */ 1123 if (nip->ni_nmatches != 0) { 1124 bip = &dl->dl_biosdisks[nip->ni_biosmatches[0]]; 1125 dos_cylinders = bip->bi_cyl; 1126 dos_heads = bip->bi_head; 1127 dos_sectors = bip->bi_sec; 1128 if (bip->bi_lbasecs) 1129 dos_disksectors = bip->bi_lbasecs; 1130 return; 1131 } 1132 } 1133 out: 1134 /* Allright, allright, make a stupid guess.. */ 1135 intuit_translated_geometry(); 1136 } 1137 #endif /* (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H */ 1138 1139 #ifdef BOOTSEL 1140 daddr_t 1141 get_default_boot(void) 1142 { 1143 unsigned int id; 1144 int p; 1145 1146 if (mboot.mbr_bootsel_magic != LE_MBR_BS_MAGIC) 1147 /* default to first active partition */ 1148 return DEFAULT_ACTIVE; 1149 1150 if (mboot.mbr_bootsel.mbrbs_defkey == SCAN_ENTER) 1151 return DEFAULT_ACTIVE; 1152 1153 id = mboot.mbr_bootsel.mbrbs_defkey; 1154 1155 /* 1+ => allocated partition id, F1+ => disk 0+ */ 1156 if (id >= SCAN_F1) 1157 return id - SCAN_F1; 1158 id -= SCAN_1; 1159 1160 for (p = 0; p < MBR_PART_COUNT; p++) { 1161 if (mboot.mbr_parts[p].mbrp_type == 0) 1162 continue; 1163 if (mboot.mbr_bootsel.mbrbs_nametab[p][0] == 0) 1164 continue; 1165 if (id-- == 0) 1166 return le32toh(mboot.mbr_parts[p].mbrp_start); 1167 } 1168 1169 for (p = 0; p < ext.num_ptn; p++) { 1170 if (ext.ptn[p].mbr_parts[0].mbrp_type == 0) 1171 continue; 1172 if (ext.ptn[p].mbr_bootsel.mbrbs_nametab[0][0] == 0) 1173 continue; 1174 if (id-- == 0) 1175 return ext_offset(p) 1176 + le32toh(ext.ptn[p].mbr_parts[0].mbrp_start); 1177 } 1178 1179 return DEFAULT_ACTIVE; 1180 } 1181 1182 void 1183 set_default_boot(daddr_t default_ptn) 1184 { 1185 int p; 1186 int key = SCAN_1; 1187 1188 if (mboot.mbr_bootsel_magic != LE_MBR_BS_MAGIC) 1189 /* sanity */ 1190 return; 1191 1192 if (default_ptn == DEFAULT_ACTIVE) { 1193 mboot.mbr_bootsel.mbrbs_defkey = SCAN_ENTER; 1194 return; 1195 } 1196 1197 for (p = 0; p < MBR_PART_COUNT; p++) { 1198 if (mboot.mbr_parts[p].mbrp_type == 0) 1199 continue; 1200 if (mboot.mbr_bootsel.mbrbs_nametab[p][0] == 0) 1201 continue; 1202 if (le32toh(mboot.mbr_parts[p].mbrp_start) == default_ptn) { 1203 mboot.mbr_bootsel.mbrbs_defkey = key; 1204 return; 1205 } 1206 key++; 1207 } 1208 1209 if (mboot.mbr_bootsel.mbrbs_flags & MBR_BS_EXTLBA) { 1210 for (p = 0; p < ext.num_ptn; p++) { 1211 if (ext.ptn[p].mbr_parts[0].mbrp_type == 0) 1212 continue; 1213 if (ext.ptn[p].mbr_bootsel.mbrbs_nametab[0][0] == 0) 1214 continue; 1215 if (le32toh(ext.ptn[p].mbr_parts[0].mbrp_start) + 1216 ext_offset(p) == default_ptn) { 1217 mboot.mbr_bootsel.mbrbs_defkey = key; 1218 return; 1219 } 1220 key++; 1221 } 1222 } 1223 1224 if (default_ptn < 8) { 1225 key = SCAN_F1; 1226 mboot.mbr_bootsel.mbrbs_defkey = key + default_ptn; 1227 return; 1228 } 1229 1230 /* Default to first active partition */ 1231 mboot.mbr_bootsel.mbrbs_defkey = SCAN_ENTER; 1232 } 1233 1234 void 1235 install_bootsel(int needed) 1236 { 1237 struct mbr_bootsel *mbs = &mboot.mbr_bootsel; 1238 int p; 1239 int ext13 = 0; 1240 const char *code; 1241 1242 needed |= MBR_BS_NEWMBR; /* need new bootsel code */ 1243 1244 /* Work out which boot code we need for this configuration */ 1245 for (p = 0; p < MBR_PART_COUNT; p++) { 1246 if (mboot.mbr_parts[p].mbrp_type == 0) 1247 continue; 1248 if (mboot.mbr_bootsel_magic != LE_MBR_BS_MAGIC) 1249 break; 1250 if (mbs->mbrbs_nametab[p][0] == 0) 1251 continue; 1252 needed |= MBR_BS_ACTIVE; 1253 if (le32toh(mboot.mbr_parts[p].mbrp_start) >= dos_totalsectors) 1254 ext13 = MBR_BS_EXTINT13; 1255 } 1256 1257 for (p = 0; p < ext.num_ptn; p++) { 1258 if (ext.ptn[p].mbr_bootsel_magic != LE_MBR_BS_MAGIC) 1259 continue; 1260 if (ext.ptn[p].mbr_parts[0].mbrp_type == 0) 1261 continue; 1262 if (ext.ptn[p].mbr_bootsel.mbrbs_nametab[p][0] == 0) 1263 continue; 1264 needed |= MBR_BS_EXTLBA | MBR_BS_ACTIVE; 1265 } 1266 1267 if (B_flag) 1268 needed |= MBR_BS_ACTIVE; 1269 1270 /* Is the installed code good enough ? */ 1271 if (!i_flag && (needed == 0 || 1272 (mboot.mbr_bootsel_magic == LE_MBR_BS_MAGIC 1273 && (mbs->mbrbs_flags & needed) == needed))) { 1274 /* yes - just set flags */ 1275 mbs->mbrbs_flags |= ext13; 1276 return; 1277 } 1278 1279 /* ok - we need to replace the bootcode */ 1280 1281 if (f_flag && !(i_flag || B_flag)) { 1282 warnx("Installed bootfile doesn't support required options."); 1283 return; 1284 } 1285 1286 if (!f_flag && bootsize == 0 && !i_flag) 1287 /* Output an explanation for the 'update bootcode' prompt. */ 1288 printf("\n%s\n", 1289 "Installed bootfile doesn't support required options."); 1290 1291 /* Were we told a specific file ? (which we have already read) */ 1292 /* If so check that it supports what we need. */ 1293 if (bootsize != 0 && needed != 0 1294 && (bootcode[0].mbr_bootsel_magic != LE_MBR_BS_MAGIC 1295 || ((bootcode[0].mbr_bootsel.mbrbs_flags & needed) != needed))) { 1296 /* No it doesn't... */ 1297 if (f_flag) 1298 warnx("Bootfile %s doesn't support " 1299 "required bootsel options", boot_path ); 1300 /* But install it anyway */ 1301 else 1302 if (yesno("Bootfile %s doesn't support the required " 1303 "options,\ninstall default bootfile instead?", 1304 boot_path)) 1305 bootsize = 0; 1306 } 1307 1308 if (bootsize == 0) { 1309 /* Get name of bootfile that supports the required facilities */ 1310 code = DEFAULT_BOOTCODE; 1311 if (needed & MBR_BS_ACTIVE) 1312 code = DEFAULT_BOOTSELCODE; 1313 #ifdef DEFAULT_BOOTEXTCODE 1314 if (needed & MBR_BS_EXTLBA) 1315 code = DEFAULT_BOOTEXTCODE; 1316 #endif 1317 1318 bootsize = read_boot(code, bootcode, sizeof bootcode, 0); 1319 if (bootsize == 0) 1320 /* The old bootcode is better than no bootcode at all */ 1321 return; 1322 if ((bootcode[0].mbr_bootsel.mbrbs_flags & needed) != needed) 1323 warnx("Default bootfile %s doesn't support required " 1324 "options. Got flags 0x%x, wanted 0x%x\n", 1325 boot_path, bootcode[0].mbr_bootsel.mbrbs_flags, 1326 needed); 1327 } 1328 1329 if (!f_flag && !yesno("Update the bootcode from %s?", boot_path)) 1330 return; 1331 1332 init_sector0(0); 1333 1334 if (mboot.mbr_bootsel_magic == LE_MBR_BS_MAGIC) 1335 mbs->mbrbs_flags = bootcode[0].mbr_bootsel.mbrbs_flags | ext13; 1336 } 1337 1338 daddr_t 1339 configure_bootsel(daddr_t default_ptn) 1340 { 1341 struct mbr_bootsel *mbs = &mboot.mbr_bootsel; 1342 int i, item, opt; 1343 int tmo; 1344 daddr_t *off; 1345 int num_bios_disks; 1346 1347 #if (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H 1348 if (dl != NULL) { 1349 num_bios_disks = dl->dl_nbiosdisks; 1350 if (num_bios_disks > 8) 1351 num_bios_disks = 8; 1352 } else 1353 #endif 1354 num_bios_disks = 8; 1355 1356 printf("\nBoot selector configuration:\n"); 1357 1358 /* The timeout value is in ticks, ~18.2 Hz. Avoid using floats. 1359 * Ticks are nearly 64k/3600 - so our long timers are sligtly out! 1360 * Newer bootcode always waits for 1 tick, so treats 0xffff 1361 * as wait forever. 1362 */ 1363 tmo = le16toh(mbs->mbrbs_timeo); 1364 tmo = tmo == 0xffff ? -1 : (10 * tmo + 9) / 182; 1365 tmo = decimal("Timeout value (0 to 3600 seconds, -1 => never)", 1366 tmo, 0, -1, 3600); 1367 mbs->mbrbs_timeo = htole16(tmo == -1 ? 0xffff : (tmo * 182) / 10); 1368 1369 off = calloc(1 + MBR_PART_COUNT + ext.num_ptn + num_bios_disks, sizeof *off); 1370 if (off == NULL) 1371 err(1, "Malloc failed"); 1372 1373 printf("Select the default boot option. Options are:\n\n"); 1374 item = 0; 1375 opt = 0; 1376 off[opt] = DEFAULT_ACTIVE; 1377 printf("%d: The first active partition\n", opt); 1378 for (i = 0; i < MBR_PART_COUNT; i++) { 1379 if (mboot.mbr_parts[i].mbrp_type == 0) 1380 continue; 1381 if (mbs->mbrbs_nametab[i][0] == 0) 1382 continue; 1383 printf("%d: %s\n", ++opt, &mbs->mbrbs_nametab[i][0]); 1384 off[opt] = le32toh(mboot.mbr_parts[i].mbrp_start); 1385 if (off[opt] == default_ptn) 1386 item = opt; 1387 } 1388 if (mbs->mbrbs_flags & MBR_BS_EXTLBA) { 1389 for (i = 0; i < ext.num_ptn; i++) { 1390 if (ext.ptn[i].mbr_parts[0].mbrp_type == 0) 1391 continue; 1392 if (ext.ptn[i].mbr_bootsel.mbrbs_nametab[0][0] == 0) 1393 continue; 1394 printf("%d: %s\n", 1395 ++opt, ext.ptn[i].mbr_bootsel.mbrbs_nametab[0]); 1396 off[opt] = ext_offset(i) + 1397 le32toh(ext.ptn[i].mbr_parts[0].mbrp_start); 1398 if (off[opt] == default_ptn) 1399 item = opt; 1400 } 1401 } 1402 for (i = 0; i < num_bios_disks; i++) { 1403 printf("%d: Harddisk %d\n", ++opt, i); 1404 off[opt] = i; 1405 if (i == default_ptn) 1406 item = opt; 1407 } 1408 1409 item = decimal("Default boot option", item, 0, 0, opt); 1410 1411 default_ptn = off[item]; 1412 free(off); 1413 return default_ptn; 1414 } 1415 #endif /* BOOTSEL */ 1416 1417 1418 /* Prerequisite: the disklabel parameters and master boot record must 1419 * have been read (i.e. dos_* and mboot are meaningful). 1420 * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and 1421 * dos_cylindersectors to be consistent with what the 1422 * partition table is using, if we can find a geometry 1423 * which is consistent with all partition table entries. 1424 * We may get the number of cylinders slightly wrong (in 1425 * the conservative direction). The idea is to be able 1426 * to create a NetBSD partition on a disk we don't know 1427 * the translated geometry of. 1428 * This routine is only used for non-x86 systems or when we fail to 1429 * get the BIOS geometry from the kernel. 1430 */ 1431 void 1432 intuit_translated_geometry(void) 1433 { 1434 int xcylinders = -1, xheads = -1, xsectors = -1, i, j; 1435 unsigned int c1, h1, s1, c2, h2, s2; 1436 unsigned long a1, a2; 1437 uint64_t num, denom; 1438 1439 /* 1440 * The physical parameters may be invalid as bios geometry. 1441 * If we cannot determine the actual bios geometry, we are 1442 * better off picking a likely 'faked' geometry than leaving 1443 * the invalid physical one. 1444 */ 1445 1446 if (dos_cylinders > MAXCYL || dos_heads > MAXHEAD || 1447 dos_sectors > MAXSECTOR) { 1448 h1 = MAXHEAD - 1; 1449 c1 = MAXCYL - 1; 1450 #if (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H 1451 if (dl != NULL) { 1452 /* BIOS may use 256 heads or 1024 cylinders */ 1453 for (i = 0; i < dl->dl_nbiosdisks; i++) { 1454 if (h1 < dl->dl_biosdisks[i].bi_head) 1455 h1 = dl->dl_biosdisks[i].bi_head; 1456 if (c1 < dl->dl_biosdisks[i].bi_cyl) 1457 c1 = dl->dl_biosdisks[i].bi_cyl; 1458 } 1459 } 1460 #endif 1461 dos_sectors = MAXSECTOR; 1462 dos_heads = h1; 1463 dos_cylinders = disklabel.d_secperunit / (MAXSECTOR * h1); 1464 if (dos_cylinders > c1) 1465 dos_cylinders = c1; 1466 } 1467 1468 /* Try to deduce the number of heads from two different mappings. */ 1469 for (i = 0; i < MBR_PART_COUNT * 2 - 1; i++) { 1470 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0) 1471 continue; 1472 a1 -= s1; 1473 for (j = i + 1; j < MBR_PART_COUNT * 2; j++) { 1474 if (get_mapping(j, &c2, &h2, &s2, &a2) < 0) 1475 continue; 1476 a2 -= s2; 1477 num = (uint64_t)h1 * a2 - (uint64_t)h2 * a1; 1478 denom = (uint64_t)c2 * a1 - (uint64_t)c1 * a2; 1479 if (denom != 0 && num % denom == 0) { 1480 xheads = num / denom; 1481 xsectors = a1 / (c1 * xheads + h1); 1482 break; 1483 } 1484 } 1485 if (xheads != -1) 1486 break; 1487 } 1488 1489 if (xheads == -1) { 1490 warnx("Cannot determine the number of heads"); 1491 return; 1492 } 1493 1494 /* Estimate the number of cylinders. */ 1495 xcylinders = disklabel.d_secperunit / xheads / xsectors; 1496 if (disklabel.d_secperunit > xcylinders * xheads * xsectors) 1497 xcylinders++; 1498 1499 /* 1500 * Now verify consistency with each of the partition table entries. 1501 * Be willing to shove cylinders up a little bit to make things work, 1502 * but translation mismatches are fatal. 1503 */ 1504 for (i = 0; i < MBR_PART_COUNT * 2; i++) { 1505 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0) 1506 continue; 1507 if (c1 >= MAXCYL - 2) 1508 continue; 1509 if (xsectors * (c1 * xheads + h1) + s1 != a1) 1510 return; 1511 } 1512 1513 1514 /* Everything checks out. 1515 * Reset the geometry to use for further calculations. 1516 * But cylinders cannot be > 1024. 1517 */ 1518 if (xcylinders > MAXCYL) 1519 dos_cylinders = MAXCYL; 1520 else 1521 dos_cylinders = xcylinders; 1522 dos_heads = xheads; 1523 dos_sectors = xsectors; 1524 } 1525 1526 /* 1527 * For the purposes of intuit_translated_geometry(), treat the partition 1528 * table as a list of eight mapping between (cylinder, head, sector) 1529 * triplets and absolute sectors. Get the relevant geometry triplet and 1530 * absolute sectors for a given entry, or return -1 if it isn't present. 1531 * Note: for simplicity, the returned sector is 0-based. 1532 */ 1533 int 1534 get_mapping(int i, unsigned int *cylinder, unsigned int *head, unsigned int *sector, 1535 unsigned long *absolute) 1536 { 1537 struct mbr_partition *part = &mboot.mbr_parts[i / 2]; 1538 1539 if (part->mbrp_type == 0) 1540 return -1; 1541 if (i % 2 == 0) { 1542 *cylinder = MBR_PCYL(part->mbrp_scyl, part->mbrp_ssect); 1543 *head = part->mbrp_shd; 1544 *sector = MBR_PSECT(part->mbrp_ssect) - 1; 1545 *absolute = le32toh(part->mbrp_start); 1546 } else { 1547 *cylinder = MBR_PCYL(part->mbrp_ecyl, part->mbrp_esect); 1548 *head = part->mbrp_ehd; 1549 *sector = MBR_PSECT(part->mbrp_esect) - 1; 1550 *absolute = le32toh(part->mbrp_start) 1551 + le32toh(part->mbrp_size) - 1; 1552 } 1553 /* Sanity check the data against all zeroes */ 1554 if ((*cylinder == 0) && (*sector == 0) && (*head == 0)) 1555 return -1; 1556 /* Sanity check the data against max values */ 1557 if ((((*cylinder * MAXHEAD) + *head) * MAXSECTOR + *sector) < *absolute) 1558 /* cannot be a CHS mapping */ 1559 return -1; 1560 return 0; 1561 } 1562 1563 static void 1564 delete_ptn(int part) 1565 { 1566 if (part == ext.ptn_id) { 1567 /* forget all about the extended partition */ 1568 free(ext.ptn); 1569 memset(&ext, 0, sizeof ext); 1570 } 1571 1572 mboot.mbr_parts[part].mbrp_type = 0; 1573 } 1574 1575 static void 1576 delete_ext_ptn(int part) 1577 { 1578 1579 if (part == 0) { 1580 ext.ptn[0].mbr_parts[0].mbrp_type = 0; 1581 return; 1582 } 1583 ext.ptn[part - 1].mbr_parts[1] = ext.ptn[part].mbr_parts[1]; 1584 memmove(&ext.ptn[part], &ext.ptn[part + 1], 1585 (ext.num_ptn - part - 1) * sizeof ext.ptn[0]); 1586 ext.num_ptn--; 1587 } 1588 1589 static int 1590 add_ext_ptn(daddr_t start, daddr_t size) 1591 { 1592 int part; 1593 struct mbr_partition *partp; 1594 struct mbr_sector *nptn; 1595 1596 nptn = realloc(ext.ptn, (ext.num_ptn + 1) * sizeof *ext.ptn); 1597 if (!nptn) 1598 err(1, "realloc"); 1599 ext.ptn = nptn; 1600 for (part = 0; part < ext.num_ptn; part++) 1601 if (ext_offset(part) > start) 1602 break; 1603 /* insert before 'part' - make space... */ 1604 memmove(&ext.ptn[part + 1], &ext.ptn[part], 1605 (ext.num_ptn - part) * sizeof ext.ptn[0]); 1606 memset(&ext.ptn[part], 0, sizeof ext.ptn[0]); 1607 ext.ptn[part].mbr_magic = LE_MBR_MAGIC; 1608 /* we will be 'part' */ 1609 if (part == 0) { 1610 /* link us to 'next' */ 1611 partp = &ext.ptn[0].mbr_parts[1]; 1612 /* offset will be fixed by caller */ 1613 partp->mbrp_size = htole32( 1614 le32toh(ext.ptn[1].mbr_parts[0].mbrp_start) + 1615 le32toh(ext.ptn[1].mbr_parts[0].mbrp_size)); 1616 } else { 1617 /* link us to prev's next */ 1618 partp = &ext.ptn[part - 1].mbr_parts[1]; 1619 ext.ptn[part].mbr_parts[1] = *partp; 1620 /* and prev onto us */ 1621 partp->mbrp_start = htole32(start - dos_sectors - ext.base); 1622 partp->mbrp_size = htole32(size + dos_sectors); 1623 } 1624 partp->mbrp_type = 5; /* as used by win98 */ 1625 partp->mbrp_flag = 0; 1626 /* wallop in some CHS values - win98 doesn't saturate them */ 1627 dos(le32toh(partp->mbrp_start), 1628 &partp->mbrp_scyl, &partp->mbrp_shd, &partp->mbrp_ssect); 1629 dos(le32toh(partp->mbrp_start) + le32toh(partp->mbrp_size) - 1, 1630 &partp->mbrp_ecyl, &partp->mbrp_ehd, &partp->mbrp_esect); 1631 ext.num_ptn++; 1632 1633 return part; 1634 } 1635 1636 static const char * 1637 check_overlap(int part, int sysid, daddr_t start, daddr_t size, int fix) 1638 { 1639 int p; 1640 unsigned int p_s, p_e; 1641 1642 if (sysid != 0) { 1643 if (start < dos_sectors) 1644 return "Track zero is reserved for the BIOS"; 1645 if (start + size > disksectors) 1646 return "Partition exceeds size of disk"; 1647 for (p = 0; p < MBR_PART_COUNT; p++) { 1648 if (p == part || mboot.mbr_parts[p].mbrp_type == 0) 1649 continue; 1650 p_s = le32toh(mboot.mbr_parts[p].mbrp_start); 1651 p_e = p_s + le32toh(mboot.mbr_parts[p].mbrp_size); 1652 if (start + size <= p_s || start >= p_e) 1653 continue; 1654 if (f_flag) { 1655 if (fix) 1656 delete_ptn(p); 1657 return 0; 1658 } 1659 return "Overlaps another partition"; 1660 } 1661 } 1662 1663 /* Are we trying to create an extended partition */ 1664 if (!MBR_IS_EXTENDED(mboot.mbr_parts[part].mbrp_type)) { 1665 /* this wasn't the extended partition */ 1666 if (!MBR_IS_EXTENDED(sysid)) 1667 return 0; 1668 /* making an extended partition */ 1669 if (ext.base != 0) { 1670 if (!f_flag) 1671 return "There cannot be 2 extended partitions"; 1672 if (fix) 1673 delete_ptn(ext.ptn_id); 1674 } 1675 if (fix) { 1676 /* allocate a new extended partition */ 1677 ext.ptn = calloc(1, sizeof ext.ptn[0]); 1678 if (ext.ptn == NULL) 1679 err(1, "Malloc failed"); 1680 ext.ptn[0].mbr_magic = LE_MBR_MAGIC; 1681 ext.ptn_id = part; 1682 ext.base = start; 1683 ext.limit = start + size; 1684 ext.num_ptn = 1; 1685 } 1686 return 0; 1687 } 1688 1689 /* Check we haven't cut space allocated to an extended ptn */ 1690 1691 if (!MBR_IS_EXTENDED(sysid)) { 1692 /* no longer an extended partition */ 1693 if (fix) { 1694 /* Kill all memory of the extended partitions */ 1695 delete_ptn(part); 1696 return 0; 1697 } 1698 if (ext.num_ptn == 0 || 1699 (ext.num_ptn == 1 && ext.ptn[0].mbr_parts[0].mbrp_type == 0)) 1700 /* nothing in extended partition */ 1701 return 0; 1702 if (f_flag) 1703 return 0; 1704 if (yesno("Do you really want to delete all the extended partitions?")) 1705 return 0; 1706 return "Extended partition busy"; 1707 } 1708 1709 if (le32toh(mboot.mbr_parts[part].mbrp_start) != ext.base) 1710 /* maybe impossible, but an extra sanity check */ 1711 return 0; 1712 1713 for (p = ext.num_ptn; --p >= 0;) { 1714 if (ext.ptn[p].mbr_parts[0].mbrp_type == 0) 1715 continue; 1716 p_s = ext_offset(p); 1717 p_e = p_s + le32toh(ext.ptn[p].mbr_parts[0].mbrp_start) 1718 + le32toh(ext.ptn[p].mbr_parts[0].mbrp_size); 1719 if (p_s >= start && p_e <= start + size) 1720 continue; 1721 if (!f_flag) 1722 return "Extended partition outside main partition"; 1723 if (fix) 1724 delete_ext_ptn(p); 1725 } 1726 1727 if (fix && start != ext.base) { 1728 /* The internal offsets need to be fixed up */ 1729 for (p = 0; p < ext.num_ptn - 1; p++) 1730 ext.ptn[p].mbr_parts[1].mbrp_start = htole32( 1731 le32toh(ext.ptn[p].mbr_parts[1].mbrp_start) 1732 + ext.base - start); 1733 /* and maybe an empty partition at the start */ 1734 if (ext.ptn[0].mbr_parts[0].mbrp_type == 0) { 1735 if (le32toh(ext.ptn[0].mbr_parts[1].mbrp_start) == 0) { 1736 /* don't need the empty slot */ 1737 memmove(&ext.ptn[0], &ext.ptn[1], 1738 (ext.num_ptn - 1) * sizeof ext.ptn[0]); 1739 ext.num_ptn--; 1740 } 1741 } else { 1742 /* must create an empty slot */ 1743 add_ext_ptn(start, dos_sectors); 1744 ext.ptn[0].mbr_parts[1].mbrp_start = htole32(ext.base 1745 - start); 1746 } 1747 } 1748 if (fix) { 1749 ext.base = start; 1750 ext.limit = start + size; 1751 } 1752 return 0; 1753 } 1754 1755 static const char * 1756 check_ext_overlap(int part, int sysid, daddr_t start, daddr_t size, int fix) 1757 { 1758 int p; 1759 unsigned int p_s, p_e; 1760 1761 if (sysid == 0) 1762 return 0; 1763 1764 if (MBR_IS_EXTENDED(sysid)) 1765 return "Nested extended partitions are not allowed"; 1766 1767 /* allow one track at start for extended partition header */ 1768 start -= dos_sectors; 1769 size += dos_sectors; 1770 if (start < ext.base || start + size > ext.limit) 1771 return "Outside bounds of extended partition"; 1772 1773 if (f_flag && !fix) 1774 return 0; 1775 1776 for (p = ext.num_ptn; --p >= 0;) { 1777 if (p == part || ext.ptn[p].mbr_parts[0].mbrp_type == 0) 1778 continue; 1779 p_s = ext_offset(p); 1780 p_e = p_s + le32toh(ext.ptn[p].mbr_parts[0].mbrp_start) 1781 + le32toh(ext.ptn[p].mbr_parts[0].mbrp_size); 1782 if (p == 0) 1783 p_s += le32toh(ext.ptn[p].mbr_parts[0].mbrp_start) 1784 - dos_sectors; 1785 if (start < p_e && start + size > p_s) { 1786 if (!f_flag) 1787 return "Overlaps another extended partition"; 1788 if (fix) { 1789 if (part == -1) 1790 delete_ext_ptn(p); 1791 else 1792 /* must not change numbering yet */ 1793 ext.ptn[p].mbr_parts[0].mbrp_type = 0; 1794 } 1795 } 1796 } 1797 return 0; 1798 } 1799 1800 int 1801 change_part(int extended, int part, int sysid, daddr_t start, daddr_t size, 1802 char *bootmenu) 1803 { 1804 struct mbr_partition *partp; 1805 struct mbr_sector *boot; 1806 daddr_t offset; 1807 const char *e; 1808 int upart = part; 1809 int p; 1810 int fl; 1811 daddr_t n_s, n_e; 1812 const char *errtext; 1813 #ifdef BOOTSEL 1814 char tmp_bootmenu[MBR_PART_COUNT * (MBR_BS_PARTNAMESIZE + 1)]; 1815 int bootmenu_len = (extended ? MBR_PART_COUNT : 1) * (MBR_BS_PARTNAMESIZE + 1); 1816 #endif 1817 1818 if (extended) { 1819 if (part != -1 && part < ext.num_ptn) { 1820 boot = &ext.ptn[part]; 1821 partp = &boot->mbr_parts[0]; 1822 offset = ext_offset(part); 1823 } else { 1824 part = -1; 1825 boot = 0; 1826 partp = 0; 1827 offset = 0; 1828 } 1829 upart = 0; 1830 e = "E"; 1831 } else { 1832 boot = &mboot; 1833 partp = &boot->mbr_parts[part]; 1834 offset = 0; 1835 e = ""; 1836 } 1837 1838 if (!f_flag && part != -1) { 1839 printf("The data for partition %s%d is:\n", e, part); 1840 print_part(boot, upart, offset); 1841 } 1842 1843 #ifdef BOOTSEL 1844 if (bootmenu != NULL) 1845 strlcpy(tmp_bootmenu, bootmenu, bootmenu_len); 1846 else 1847 if (boot != NULL && boot->mbr_bootsel_magic == LE_MBR_BS_MAGIC) 1848 strlcpy(tmp_bootmenu, 1849 boot->mbr_bootsel.mbrbs_nametab[upart], 1850 bootmenu_len); 1851 else 1852 tmp_bootmenu[0] = 0; 1853 #endif 1854 1855 if (!s_flag && partp != NULL) { 1856 /* values not specified, default to current ones */ 1857 sysid = partp->mbrp_type; 1858 start = offset + le32toh(partp->mbrp_start); 1859 size = le32toh(partp->mbrp_size); 1860 } 1861 1862 /* creating a new partition, default to free space */ 1863 if (!s_flag && sysid == 0 && extended) { 1864 /* non-extended partition */ 1865 start = ext.base; 1866 for (p = 0; p < ext.num_ptn; p++) { 1867 if (ext.ptn[p].mbr_parts[0].mbrp_type == 0) 1868 continue; 1869 n_s = ext_offset(p); 1870 if (n_s > start + dos_sectors) 1871 break; 1872 start = ext_offset(p) 1873 + le32toh(ext.ptn[p].mbr_parts[0].mbrp_start) 1874 + le32toh(ext.ptn[p].mbr_parts[0].mbrp_size); 1875 } 1876 if (ext.limit - start <= dos_sectors) { 1877 printf("No space in extended partition\n"); 1878 return 0; 1879 } 1880 start += dos_sectors; 1881 } 1882 1883 if (!s_flag && sysid == 0 && !extended) { 1884 /* same for non-extended partition */ 1885 /* first see if old start is free */ 1886 if (start < dos_sectors) 1887 start = 0; 1888 for (p = 0; start != 0 && p < MBR_PART_COUNT; p++) { 1889 if (mboot.mbr_parts[p].mbrp_type == 0) 1890 continue; 1891 n_s = le32toh(mboot.mbr_parts[p].mbrp_start); 1892 if (start >= n_s && 1893 start < n_s + le32toh(mboot.mbr_parts[p].mbrp_size)) 1894 start = 0; 1895 } 1896 if (start == 0) { 1897 /* Look for first gap */ 1898 start = dos_sectors; 1899 for (p = 0; p < MBR_PART_COUNT; p++) { 1900 if (mboot.mbr_parts[p].mbrp_type == 0) 1901 continue; 1902 n_s = le32toh(mboot.mbr_parts[p].mbrp_start); 1903 n_e = n_s + le32toh(mboot.mbr_parts[p].mbrp_size); 1904 if (start >= n_s && start < n_e) { 1905 start = n_e; 1906 p = -1; 1907 } 1908 } 1909 if (start >= disksectors) { 1910 printf("No free space\n"); 1911 return 0; 1912 } 1913 } 1914 } 1915 1916 if (!f_flag) { 1917 /* request new values from user */ 1918 if (sysid == 0) 1919 sysid = 169; 1920 sysid = decimal("sysid", sysid, 0, 0, 255); 1921 if (sysid == 0 && !v_flag) { 1922 start = 0; 1923 size = 0; 1924 #ifdef BOOTSEL 1925 tmp_bootmenu[0] = 0; 1926 #endif 1927 } else { 1928 daddr_t old = start; 1929 daddr_t lim = extended ? ext.limit : disksectors; 1930 start = decimal("start", start, 1931 DEC_SEC | DEC_RND_0 | (extended ? DEC_RND : 0), 1932 extended ? ext.base : 0, lim); 1933 /* Adjust 'size' so that end doesn't move when 'start' 1934 * is only changed slightly. 1935 */ 1936 if (size > start - old) 1937 size -= start - old; 1938 else 1939 size = 0; 1940 /* Find end of available space from this start point */ 1941 if (extended) { 1942 for (p = 0; p < ext.num_ptn; p++) { 1943 if (p == part) 1944 continue; 1945 if (ext.ptn[p].mbr_parts[0].mbrp_type == 0) 1946 continue; 1947 n_s = ext_offset(p); 1948 if (n_s > start && n_s < lim) 1949 lim = n_s; 1950 if (start >= n_s && start < n_s 1951 + le32toh(ext.ptn[p].mbr_parts[0].mbrp_start) 1952 + le32toh(ext.ptn[p].mbr_parts[0].mbrp_size)) { 1953 lim = start; 1954 break; 1955 } 1956 } 1957 } else { 1958 for (p = 0; p < MBR_PART_COUNT; p++) { 1959 if (p == part) 1960 continue; 1961 if (mboot.mbr_parts[p].mbrp_type == 0) 1962 continue; 1963 n_s = le32toh(mboot.mbr_parts[p].mbrp_start); 1964 if (n_s > start && n_s < lim) 1965 lim = n_s; 1966 if (start >= n_s && start < n_s 1967 + le32toh(mboot.mbr_parts[p].mbrp_size)) { 1968 lim = start; 1969 break; 1970 } 1971 } 1972 } 1973 lim -= start; 1974 if (lim == 0) { 1975 printf("Start sector already allocated\n"); 1976 return 0; 1977 } 1978 if (size == 0 || size > lim) 1979 size = lim; 1980 fl = DEC_SEC; 1981 if (start % dos_cylindersectors == dos_sectors) 1982 fl |= DEC_RND_DOWN; 1983 if (start == 2 * dos_sectors) 1984 fl |= DEC_RND_DOWN | DEC_RND_DOWN_2; 1985 size = decimal("size", size, fl, 0, lim); 1986 #ifdef BOOTSEL 1987 #ifndef DEFAULT_BOOTEXTCODE 1988 if (!extended) 1989 #endif 1990 string("bootmenu", bootmenu_len, tmp_bootmenu); 1991 #endif 1992 } 1993 } 1994 1995 /* 1996 * Before we write these away, we must verify that nothing 1997 * untoward has been requested. 1998 */ 1999 2000 if (extended) 2001 errtext = check_ext_overlap(part, sysid, start, size, 0); 2002 else 2003 errtext = check_overlap(part, sysid, start, size, 0); 2004 if (errtext != NULL) { 2005 if (f_flag) 2006 errx(2, "%s\n", errtext); 2007 printf("%s\n", errtext); 2008 return 0; 2009 } 2010 2011 /* 2012 * Before proceeding, delete any overlapped partitions. 2013 * This can only happen if '-f' was supplied on the command line. 2014 * Just hope the caller knows what they are doing. 2015 * This also fixes the base of each extended partition if the 2016 * partition itself has moved. 2017 */ 2018 2019 if (extended) 2020 errtext = check_ext_overlap(part, sysid, start, size, 1); 2021 else 2022 errtext = check_overlap(part, sysid, start, size, 1); 2023 2024 if (errtext) 2025 errx(1, "%s\n", errtext); 2026 2027 if (sysid == 0) { 2028 /* delete this partition - save info though */ 2029 if (partp == NULL) 2030 /* must have been trying to create an extended ptn */ 2031 return 0; 2032 if (start == 0 && size == 0) 2033 memset(partp, 0, sizeof *partp); 2034 #ifdef BOOTSEL 2035 if (boot->mbr_bootsel_magic == LE_MBR_BS_MAGIC) 2036 memset(boot->mbr_bootsel.mbrbs_nametab[upart], 0, 2037 sizeof boot->mbr_bootsel.mbrbs_nametab[0]); 2038 #endif 2039 if (extended) 2040 delete_ext_ptn(part); 2041 else 2042 delete_ptn(part); 2043 return 1; 2044 } 2045 2046 2047 if (extended) { 2048 if (part != -1) 2049 delete_ext_ptn(part); 2050 if (start == ext.base + dos_sectors) 2051 /* First one must have been free */ 2052 part = 0; 2053 else 2054 part = add_ext_ptn(start, size); 2055 2056 /* These must be re-calculated because of the realloc */ 2057 boot = &ext.ptn[part]; 2058 partp = &boot->mbr_parts[0]; 2059 offset = ext_offset(part); 2060 } 2061 2062 partp->mbrp_type = sysid; 2063 partp->mbrp_start = htole32( start - offset); 2064 partp->mbrp_size = htole32( size); 2065 dos(start, &partp->mbrp_scyl, &partp->mbrp_shd, &partp->mbrp_ssect); 2066 dos(start + size - 1, 2067 &partp->mbrp_ecyl, &partp->mbrp_ehd, &partp->mbrp_esect); 2068 #ifdef BOOTSEL 2069 if (extended) { 2070 boot->mbr_bootsel_magic = LE_MBR_BS_MAGIC; 2071 strncpy(boot->mbr_bootsel.mbrbs_nametab[upart], tmp_bootmenu, 2072 bootmenu_len); 2073 } else { 2074 /* We need to bootselect code installed in order to have 2075 * somewhere to safely write the menu tag. 2076 */ 2077 if (boot->mbr_bootsel_magic != LE_MBR_BS_MAGIC) { 2078 if (f_flag || 2079 yesno("The bootselect code is not installed, " 2080 "do you want to install it now?")) 2081 install_bootsel(MBR_BS_ACTIVE); 2082 } 2083 if (boot->mbr_bootsel_magic == LE_MBR_BS_MAGIC) { 2084 strncpy(boot->mbr_bootsel.mbrbs_nametab[upart], 2085 tmp_bootmenu, bootmenu_len); 2086 } 2087 } 2088 #endif 2089 2090 if (v_flag && !f_flag && yesno("Explicitly specify beg/end address?")) { 2091 /* this really isn't a good idea.... */ 2092 int tsector, tcylinder, thead; 2093 2094 tcylinder = MBR_PCYL(partp->mbrp_scyl, partp->mbrp_ssect); 2095 thead = partp->mbrp_shd; 2096 tsector = MBR_PSECT(partp->mbrp_ssect); 2097 tcylinder = decimal("beginning cylinder", 2098 tcylinder, 0, 0, dos_cylinders - 1); 2099 thead = decimal("beginning head", 2100 thead, 0, 0, dos_heads - 1); 2101 tsector = decimal("beginning sector", 2102 tsector, 0, 1, dos_sectors); 2103 partp->mbrp_scyl = DOSCYL(tcylinder); 2104 partp->mbrp_shd = thead; 2105 partp->mbrp_ssect = DOSSECT(tsector, tcylinder); 2106 2107 tcylinder = MBR_PCYL(partp->mbrp_ecyl, partp->mbrp_esect); 2108 thead = partp->mbrp_ehd; 2109 tsector = MBR_PSECT(partp->mbrp_esect); 2110 tcylinder = decimal("ending cylinder", 2111 tcylinder, 0, 0, dos_cylinders - 1); 2112 thead = decimal("ending head", 2113 thead, 0, 0, dos_heads - 1); 2114 tsector = decimal("ending sector", 2115 tsector, 0, 1, dos_sectors); 2116 partp->mbrp_ecyl = DOSCYL(tcylinder); 2117 partp->mbrp_ehd = thead; 2118 partp->mbrp_esect = DOSSECT(tsector, tcylinder); 2119 } 2120 2121 /* If we had to mark an extended partition as deleted because 2122 * another request would have overlapped it, now is the time 2123 * to do the actual delete. 2124 */ 2125 if (extended && f_flag) { 2126 for (p = ext.num_ptn; --p >= 0;) 2127 if (ext.ptn[p].mbr_parts[0].mbrp_type == 0) 2128 delete_ext_ptn(p); 2129 } 2130 return 1; 2131 } 2132 2133 void 2134 print_params(void) 2135 { 2136 2137 if (sh_flag) { 2138 printf("DISK=%s\n", disk); 2139 printf("DLCYL=%d\nDLHEAD=%d\nDLSEC=%d\nDLSIZE=%"PRIdaddr"\n", 2140 cylinders, heads, sectors, disksectors); 2141 printf("BCYL=%d\nBHEAD=%d\nBSEC=%d\nBDLSIZE=%"PRIdaddr"\n", 2142 dos_cylinders, dos_heads, dos_sectors, dos_disksectors); 2143 printf("NUMEXTPTN=%d\n", ext.num_ptn); 2144 return; 2145 } 2146 2147 /* Not sh_flag */ 2148 printf("Disk: %s\n", disk); 2149 printf("NetBSD disklabel disk geometry:\n"); 2150 printf("cylinders: %d, heads: %d, sectors/track: %d " 2151 "(%d sectors/cylinder)\ntotal sectors: %"PRIdaddr"\n\n", 2152 cylinders, heads, sectors, cylindersectors, disksectors); 2153 printf("BIOS disk geometry:\n"); 2154 printf("cylinders: %d, heads: %d, sectors/track: %d " 2155 "(%d sectors/cylinder)\ntotal sectors: %"PRIdaddr"\n\n", 2156 dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors, 2157 dos_disksectors); 2158 } 2159 2160 void 2161 change_active(int which) 2162 { 2163 struct mbr_partition *partp; 2164 int part; 2165 int active = MBR_PART_COUNT; 2166 2167 partp = &mboot.mbr_parts[0]; 2168 2169 if (a_flag && which != -1) 2170 active = which; 2171 else { 2172 for (part = 0; part < MBR_PART_COUNT; part++) 2173 if (partp[part].mbrp_flag & MBR_PFLAG_ACTIVE) 2174 active = part; 2175 } 2176 if (!f_flag) { 2177 if (yesno("Do you want to change the active partition?")) { 2178 printf ("Choosing %d will make no partition active.\n", 2179 MBR_PART_COUNT); 2180 do { 2181 active = decimal("active partition", 2182 active, 0, 0, MBR_PART_COUNT); 2183 } while (!yesno("Are you happy with this choice?")); 2184 } else 2185 return; 2186 } else 2187 if (active != MBR_PART_COUNT) 2188 printf ("Making partition %d active.\n", active); 2189 2190 for (part = 0; part < MBR_PART_COUNT; part++) 2191 partp[part].mbrp_flag &= ~MBR_PFLAG_ACTIVE; 2192 if (active < MBR_PART_COUNT) 2193 partp[active].mbrp_flag |= MBR_PFLAG_ACTIVE; 2194 } 2195 2196 void 2197 get_params_to_use(void) 2198 { 2199 #if defined(__i386__) || defined(__x86_64__) 2200 struct biosdisk_info *bip; 2201 int i; 2202 #endif 2203 2204 if (b_flag) { 2205 dos_cylinders = b_cyl; 2206 dos_heads = b_head; 2207 dos_sectors = b_sec; 2208 return; 2209 } 2210 2211 print_params(); 2212 if (!yesno("Do you want to change our idea of what BIOS thinks?")) 2213 return; 2214 2215 #if (defined(__i386__) || defined(__x86_64__)) && !HAVE_NBTOOL_CONFIG_H 2216 if (dl != NULL) { 2217 for (i = 0; i < dl->dl_nbiosdisks; i++) { 2218 if (i == 0) 2219 printf("\nGeometries of known disks:\n"); 2220 bip = &dl->dl_biosdisks[i]; 2221 printf("Disk %d: cylinders %u, heads %u, sectors %u" 2222 " (%"PRIdaddr" sectors, %dMB)\n", 2223 i, bip->bi_cyl, bip->bi_head, bip->bi_sec, 2224 bip->bi_lbasecs, SEC_TO_MB(bip->bi_lbasecs)); 2225 2226 } 2227 printf("\n"); 2228 } 2229 #endif 2230 do { 2231 dos_cylinders = decimal("BIOS's idea of #cylinders", 2232 dos_cylinders, 0, 0, MAXCYL); 2233 dos_heads = decimal("BIOS's idea of #heads", 2234 dos_heads, 0, 0, MAXHEAD); 2235 dos_sectors = decimal("BIOS's idea of #sectors", 2236 dos_sectors, 0, 1, MAXSECTOR); 2237 print_params(); 2238 } while (!yesno("Are you happy with this choice?")); 2239 } 2240 2241 2242 /***********************************************\ 2243 * Change real numbers into strange dos numbers * 2244 \***********************************************/ 2245 void 2246 dos(int sector, unsigned char *cylinderp, unsigned char *headp, 2247 unsigned char *sectorp) 2248 { 2249 int cylinder, head; 2250 2251 cylinder = sector / dos_cylindersectors; 2252 sector -= cylinder * dos_cylindersectors; 2253 2254 head = sector / dos_sectors; 2255 sector -= head * dos_sectors; 2256 if (cylinder > 1023) 2257 cylinder = 1023; 2258 2259 *cylinderp = DOSCYL(cylinder); 2260 *headp = head; 2261 *sectorp = DOSSECT(sector + 1, cylinder); 2262 } 2263 2264 int 2265 open_disk(int update) 2266 { 2267 static char namebuf[MAXPATHLEN + 1]; 2268 int flags = update && disk_file == NULL ? O_RDWR : O_RDONLY; 2269 2270 if (!F_flag) { 2271 fd = opendisk(disk, flags, namebuf, sizeof(namebuf), 0); 2272 if (fd < 0) { 2273 if (errno == ENODEV) 2274 warnx("%s is not a character device", namebuf); 2275 else 2276 warn("cannot opendisk %s", namebuf); 2277 return (-1); 2278 } 2279 disk = namebuf; 2280 } else { 2281 fd = open(disk, flags, 0); 2282 if (fd == -1) { 2283 warn("cannot open %s", disk); 2284 return -1; 2285 } 2286 } 2287 2288 if (get_params() == -1) { 2289 close(fd); 2290 fd = -1; 2291 return (-1); 2292 } 2293 if (disk_file != NULL) { 2294 /* for testing: read/write data from a disk file */ 2295 wfd = open(disk_file, update ? O_RDWR|O_CREAT : O_RDONLY, 0777); 2296 if (wfd == -1) { 2297 warn("%s", disk_file); 2298 close(fd); 2299 fd = -1; 2300 return -1; 2301 } 2302 } else 2303 wfd = fd; 2304 return (0); 2305 } 2306 2307 int 2308 read_disk(daddr_t sector, void *buf) 2309 { 2310 2311 if (*rfd == -1) 2312 errx(1, "read_disk(); fd == -1"); 2313 if (lseek(*rfd, sector * (off_t)512, 0) == -1) 2314 return (-1); 2315 return (read(*rfd, buf, 512)); 2316 } 2317 2318 int 2319 write_disk(daddr_t sector, void *buf) 2320 { 2321 2322 if (wfd == -1) 2323 errx(1, "write_disk(); wfd == -1"); 2324 if (lseek(wfd, sector * (off_t)512, 0) == -1) 2325 return (-1); 2326 return (write(wfd, buf, 512)); 2327 } 2328 2329 static void 2330 guess_geometry(daddr_t _sectors) 2331 { 2332 dos_sectors = MAXSECTOR; 2333 dos_heads = MAXHEAD - 1; /* some BIOS might use 256 */ 2334 dos_cylinders = _sectors / (MAXSECTOR * (MAXHEAD - 1)); 2335 if (dos_cylinders < 1) 2336 dos_cylinders = 1; 2337 else if (dos_cylinders > MAXCYL - 1) 2338 dos_cylinders = MAXCYL - 1; 2339 } 2340 2341 int 2342 get_params(void) 2343 { 2344 if (disk_type != NULL) { 2345 struct disklabel *tmplabel; 2346 2347 if ((tmplabel = getdiskbyname(disk_type)) == NULL) { 2348 warn("bad disktype"); 2349 return (-1); 2350 } 2351 disklabel = *tmplabel; 2352 } else if (F_flag) { 2353 struct stat st; 2354 if (fstat(fd, &st) == -1) { 2355 warn("fstat"); 2356 return (-1); 2357 } 2358 if (st.st_size % 512 != 0) { 2359 warnx("%s size (%lld) is not divisible " 2360 "by sector size (%d)", disk, (long long)st.st_size, 2361 512); 2362 } 2363 disklabel.d_secperunit = st.st_size / 512; 2364 guess_geometry(disklabel.d_secperunit); 2365 disklabel.d_ncylinders = dos_cylinders; 2366 disklabel.d_ntracks = dos_heads; 2367 disklabel.d_nsectors = dos_sectors; 2368 } else if (ioctl(fd, DIOCGDEFLABEL, &disklabel) == -1) { 2369 warn("DIOCGDEFLABEL"); 2370 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 2371 warn("DIOCGDINFO"); 2372 return (-1); 2373 } 2374 } 2375 2376 disksectors = disklabel.d_secperunit; 2377 cylinders = disklabel.d_ncylinders; 2378 heads = disklabel.d_ntracks; 2379 sectors = disklabel.d_nsectors; 2380 2381 /* pick up some defaults for the BIOS sizes */ 2382 if (sectors <= MAXSECTOR) { 2383 dos_cylinders = cylinders; 2384 dos_heads = heads; 2385 dos_sectors = sectors; 2386 } else { 2387 /* guess - has to better than the above */ 2388 guess_geometry(disksectors); 2389 } 2390 dos_disksectors = disksectors; 2391 2392 return (0); 2393 } 2394 2395 #ifdef BOOTSEL 2396 /* 2397 * Rather unfortunately the bootsel 'magic' number is at the end of the 2398 * the structure, and there is no checksum. So when other operating 2399 * systems install mbr code by only writing the length of their code they 2400 * can overwrite part of the structure but keeping the magic number intact. 2401 * This code attempts to empirically detect this problem. 2402 */ 2403 static int 2404 validate_bootsel(struct mbr_bootsel *mbs) 2405 { 2406 unsigned int key = mbs->mbrbs_defkey; 2407 unsigned int tmo; 2408 int i; 2409 2410 if (v_flag) 2411 return 0; 2412 2413 /* 2414 * Check default key is sane 2415 * - this is the most likely field to be stuffed 2416 * 12 disks and 12 bootable partitions seems enough! 2417 * (the keymap decode starts falling apart at that point) 2418 */ 2419 if (key != 0 && !(key == SCAN_ENTER 2420 || (key >= SCAN_1 && key < SCAN_1 + 12) 2421 || (key >= SCAN_F1 && key < SCAN_F1 + 12))) 2422 return 1; 2423 2424 /* Checking the flags will lead to breakage... */ 2425 2426 /* Timeout value is expecyed to be a multiple of a second */ 2427 tmo = htole16(mbs->mbrbs_timeo); 2428 if (tmo != 0 && tmo != 0xffff && tmo != (10 * tmo + 9) / 182 * 182 / 10) 2429 return 2; 2430 2431 /* Check the menu strings are printable */ 2432 /* Unfortunately they aren't zero filled... */ 2433 for (i = 0; i < sizeof(mbs->mbrbs_nametab); i++) { 2434 int c = (uint8_t)mbs->mbrbs_nametab[0][i]; 2435 if (c == 0 || isprint(c)) 2436 continue; 2437 return 3; 2438 } 2439 2440 return 0; 2441 } 2442 #endif 2443 2444 int 2445 read_s0(daddr_t offset, struct mbr_sector *boot) 2446 { 2447 const char *tabletype = offset ? "extended" : "primary"; 2448 #ifdef BOOTSEL 2449 static int reported; 2450 #endif 2451 2452 if (read_disk(offset, boot) == -1) { 2453 warn("Can't read %s partition table", tabletype); 2454 return -1; 2455 } 2456 if (boot->mbr_magic != LE_MBR_MAGIC) { 2457 warnx("%s partition table invalid, " 2458 "no magic in sector %"PRIdaddr, tabletype, offset); 2459 return -1; 2460 2461 } 2462 #ifdef BOOTSEL 2463 if (boot->mbr_bootsel_magic == LE_MBR_BS_MAGIC) { 2464 /* mbr_bootsel in new location */ 2465 if (validate_bootsel(&boot->mbr_bootsel)) { 2466 warnx("removing corrupt bootsel information"); 2467 boot->mbr_bootsel_magic = 0; 2468 } 2469 return 0; 2470 } 2471 if (boot->mbr_bootsel_magic != LE_MBR_MAGIC) 2472 return 0; 2473 2474 /* mbr_bootsel in old location */ 2475 if (!reported) 2476 warnx("%s partition table: using old-style bootsel information", 2477 tabletype); 2478 reported = 1; 2479 if (validate_bootsel((void *)((uint8_t *)boot + MBR_BS_OFFSET + 4))) { 2480 warnx("%s bootsel information corrupt - ignoring", tabletype); 2481 return 0; 2482 } 2483 memmove((uint8_t *)boot + MBR_BS_OFFSET, 2484 (uint8_t *)boot + MBR_BS_OFFSET + 4, 2485 sizeof(struct mbr_bootsel)); 2486 if ( ! (boot->mbr_bootsel.mbrbs_flags & MBR_BS_NEWMBR)) { 2487 /* old style default key */ 2488 int id; 2489 /* F1..F4 => ptn 0..3, F5+ => disk 0+ */ 2490 id = boot->mbr_bootsel.mbrbs_defkey; 2491 id -= SCAN_F1; 2492 if (id >= MBR_PART_COUNT) 2493 id -= MBR_PART_COUNT; /* Use number of disk */ 2494 else if (mboot.mbr_parts[id].mbrp_type != 0) 2495 id = le32toh(boot->mbr_parts[id].mbrp_start); 2496 else 2497 id = DEFAULT_ACTIVE; 2498 boot->mbr_bootsel.mbrbs_defkey = id; 2499 } 2500 boot->mbr_bootsel_magic = LE_MBR_BS_MAGIC; 2501 /* highlight that new bootsel code is necessary */ 2502 boot->mbr_bootsel.mbrbs_flags &= ~MBR_BS_NEWMBR; 2503 #endif /* BOOTSEL */ 2504 return 0; 2505 } 2506 2507 int 2508 write_mbr(void) 2509 { 2510 int flag, i; 2511 daddr_t offset; 2512 int rval = -1; 2513 2514 /* 2515 * write enable label sector before write (if necessary), 2516 * disable after writing. 2517 * needed if the disklabel protected area also protects 2518 * sector 0. (e.g. empty disk) 2519 */ 2520 flag = 1; 2521 if (wfd == fd && F_flag == 0 && ioctl(wfd, DIOCWLABEL, &flag) < 0) 2522 warn("DIOCWLABEL"); 2523 if (write_disk(0, &mboot) == -1) { 2524 warn("Can't write fdisk partition table"); 2525 goto protect_label; 2526 } 2527 if (boot_installed) 2528 for (i = bootsize; (i -= 0x200) > 0;) 2529 if (write_disk(i / 0x200, &bootcode[i / 0x200]) == -1) { 2530 warn("Can't write bootcode"); 2531 goto protect_label; 2532 } 2533 for (offset = 0, i = 0; i < ext.num_ptn; i++) { 2534 if (write_disk(ext.base + offset, ext.ptn + i) == -1) { 2535 warn("Can't write %dth extended partition", i); 2536 goto protect_label; 2537 } 2538 offset = le32toh(ext.ptn[i].mbr_parts[1].mbrp_start); 2539 } 2540 rval = 0; 2541 protect_label: 2542 flag = 0; 2543 if (wfd == fd && F_flag == 0 && ioctl(wfd, DIOCWLABEL, &flag) < 0) 2544 warn("DIOCWLABEL"); 2545 return rval; 2546 } 2547 2548 int 2549 yesno(const char *str, ...) 2550 { 2551 int ch, first; 2552 va_list ap; 2553 2554 va_start(ap, str); 2555 2556 vprintf(str, ap); 2557 printf(" [n] "); 2558 2559 first = ch = getchar(); 2560 while (ch != '\n' && ch != EOF) 2561 ch = getchar(); 2562 if (ch == EOF) 2563 errx(1, "EOF"); 2564 return (first == 'y' || first == 'Y'); 2565 } 2566 2567 int 2568 decimal(const char *prompt, int dflt, int flags, int minval, int maxval) 2569 { 2570 int acc = 0; 2571 char *cp; 2572 char ch; 2573 2574 for (;;) { 2575 if (flags & DEC_SEC) { 2576 printf("%s: [%d..%dcyl default: %d, %dcyl, %uMB] ", 2577 prompt, SEC_TO_CYL(minval), SEC_TO_CYL(maxval), 2578 dflt, SEC_TO_CYL(dflt), SEC_TO_MB(dflt)); 2579 } else 2580 printf("%s: [%d..%d default: %d] ", 2581 prompt, minval, maxval, dflt); 2582 2583 if (!fgets(lbuf, LBUF, stdin)) 2584 errx(1, "EOF"); 2585 lbuf[strlen(lbuf)-1] = '\0'; 2586 cp = lbuf; 2587 2588 cp += strspn(cp, " \t"); 2589 if (*cp == '\0') 2590 return dflt; 2591 2592 if (cp[0] == '$' && cp[1] == 0) 2593 return maxval; 2594 2595 if (isdigit((unsigned char)*cp) || *cp == '-') { 2596 acc = strtol(lbuf, &cp, 10); 2597 if (flags & DEC_SEC) { 2598 ch = *cp; 2599 if (ch == 'g' || ch == 'G') { 2600 acc *= 1024; 2601 ch = 'm'; 2602 } 2603 if (ch == 'm' || ch == 'M') { 2604 acc *= SEC_IN_1M; 2605 /* round to whole number of cylinders */ 2606 acc += dos_cylindersectors / 2; 2607 acc /= dos_cylindersectors; 2608 ch = 'c'; 2609 } 2610 if (ch == 'c' || ch == 'C') { 2611 cp++; 2612 acc *= dos_cylindersectors; 2613 /* adjustments for cylinder boundary */ 2614 if (acc == 0 && flags & DEC_RND_0) 2615 acc += dos_sectors; 2616 if (flags & DEC_RND) 2617 acc += dos_sectors; 2618 if (flags & DEC_RND_DOWN) 2619 acc -= dos_sectors; 2620 if (flags & DEC_RND_DOWN_2) 2621 acc -= dos_sectors; 2622 } 2623 } 2624 } 2625 2626 cp += strspn(cp, " \t"); 2627 if (*cp != '\0') { 2628 printf("%s is not a valid %s number.\n", lbuf, 2629 flags & DEC_SEC ? "sector" : "decimal"); 2630 continue; 2631 } 2632 2633 if (acc >= minval && acc <= maxval) 2634 return acc; 2635 printf("%d is not between %d and %d.\n", acc, minval, maxval); 2636 } 2637 } 2638 2639 int 2640 ptn_id(const char *prompt, int *extended) 2641 { 2642 unsigned int acc = 0; 2643 char *cp; 2644 2645 for (;; printf("%s is not a valid partition number.\n", lbuf)) { 2646 printf("%s: [none] ", prompt); 2647 2648 if (!fgets(lbuf, LBUF, stdin)) 2649 errx(1, "EOF"); 2650 lbuf[strlen(lbuf)-1] = '\0'; 2651 cp = lbuf; 2652 2653 cp += strspn(cp, " \t"); 2654 *extended = 0; 2655 if (*cp == 0) 2656 return -1; 2657 2658 if (*cp == 'E' || *cp == 'e') { 2659 cp++; 2660 *extended = 1; 2661 } 2662 2663 acc = strtoul(cp, &cp, 10); 2664 2665 cp += strspn(cp, " \t"); 2666 if (*cp != '\0') 2667 continue; 2668 2669 if (*extended || acc < MBR_PART_COUNT) 2670 return acc; 2671 } 2672 } 2673 2674 #ifdef BOOTSEL 2675 void 2676 string(const char *prompt, int length, char *buf) 2677 { 2678 int len; 2679 2680 for (;;) { 2681 printf("%s: [%.*s] ", prompt, length, buf); 2682 2683 if (!fgets(lbuf, LBUF, stdin)) 2684 errx(1, "EOF"); 2685 len = strlen(lbuf); 2686 if (len <= 1) 2687 /* unchanged if just <enter> */ 2688 return; 2689 /* now strip trailing spaces, <space><enter> deletes string */ 2690 do 2691 lbuf[--len] = 0; 2692 while (len != 0 && lbuf[len - 1] == ' '); 2693 if (len < length) 2694 break; 2695 printf("'%s' is longer than %d characters.\n", 2696 lbuf, length - 1); 2697 } 2698 strncpy(buf, lbuf, length); 2699 } 2700 #endif 2701 2702 int 2703 type_match(const void *key, const void *item) 2704 { 2705 const int *idp = key; 2706 const struct mbr_ptype *ptr = item; 2707 2708 if (*idp < ptr->id) 2709 return (-1); 2710 if (*idp > ptr->id) 2711 return (1); 2712 return (0); 2713 } 2714 2715 const char * 2716 get_type(int type) 2717 { 2718 struct mbr_ptype *ptr; 2719 2720 ptr = bsearch(&type, mbr_ptypes, KNOWN_SYSIDS, 2721 sizeof(mbr_ptypes[0]), type_match); 2722 if (ptr == 0) 2723 return ("unknown"); 2724 return (ptr->name); 2725 } 2726