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