1 /* $NetBSD: fdisk.c,v 1.42 2000/07/06 17:22:43 thorpej 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 #include <sys/cdefs.h> 30 31 #ifndef lint 32 __RCSID("$NetBSD: fdisk.c,v 1.42 2000/07/06 17:22:43 thorpej Exp $"); 33 #endif /* not lint */ 34 35 #include <sys/types.h> 36 #include <sys/disklabel.h> 37 #include <sys/disklabel_mbr.h> 38 #include <sys/ioctl.h> 39 #include <sys/param.h> 40 #include <sys/stat.h> 41 42 #include <ctype.h> 43 #include <err.h> 44 #include <errno.h> 45 #include <fcntl.h> 46 #include <paths.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 #include <util.h> 52 53 #ifdef __i386__ 54 #include <ctype.h> 55 #include <machine/cpu.h> 56 #include <sys/sysctl.h> 57 #endif 58 59 #define LBUF 100 60 static char lbuf[LBUF]; 61 62 /* 63 * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University 64 * Copyright (c) 1989 Robert. V. Baron 65 * Created. 66 */ 67 68 #ifndef _PATH_DEFDISK 69 #define _PATH_DEFDISK "/dev/rwd0d" 70 #endif 71 72 char *disk = _PATH_DEFDISK; 73 74 struct disklabel disklabel; /* disk parameters */ 75 76 int cylinders, sectors, heads, cylindersectors, disksectors; 77 78 struct mboot { 79 u_int8_t padding[2]; /* force the longs to be long alligned */ 80 u_int8_t bootinst[MBR_PARTOFF]; 81 struct mbr_partition parts[NMBRPART]; 82 u_int16_t signature; 83 }; 84 struct mboot mboot; 85 86 #ifdef __i386__ 87 88 #define PARTNAMESIZE 8 /* From mbr_bootsel.S */ 89 90 struct mbr_bootsel { 91 u_int8_t defkey; 92 u_int8_t flags; 93 u_int16_t timeo; 94 char nametab[4][PARTNAMESIZE + 1]; 95 u_int16_t magic; 96 } __attribute__((packed)); 97 98 #define BFL_SELACTIVE 0x01 99 #define BFL_EXTINT13 0x02 100 101 #define SCAN_ENTER 0x1c 102 #define SCAN_F1 0x3b 103 104 #define MBR_BOOTSELOFF (MBR_PARTOFF - sizeof (struct mbr_bootsel)) 105 106 #define DEFAULT_BOOTCODE "/usr/mdec/mbr" 107 #define DEFAULT_BOOTSELCODE "/usr/mdec/mbr_bootsel" 108 #define OPTIONS "0123BSafius:b:c:" 109 #else 110 #define OPTIONS "0123Safius:b:c:" 111 #endif 112 113 #define ACTIVE 0x80 114 115 int dos_cylinders; 116 int dos_heads; 117 int dos_sectors; 118 int dos_cylindersectors; 119 120 #define DOSSECT(s,c) (((s) & 0x3f) | (((c) >> 2) & 0xc0)) 121 #define DOSCYL(c) ((c) & 0xff) 122 123 #define MAXCYL 1024 124 int partition = -1; 125 126 int a_flag; /* set active partition */ 127 int i_flag; /* init bootcode */ 128 int u_flag; /* update partition data */ 129 int sh_flag; /* Output data as shell defines */ 130 int f_flag; /* force --not interactive */ 131 int s_flag; /* set id,offset,size */ 132 int b_flag; /* Set cyl, heads, secs (as c/h/s) */ 133 int B_flag; /* Edit/install bootselect code */ 134 int b_cyl, b_head, b_sec; /* b_flag values. */ 135 int bootsel_modified; 136 137 unsigned char bootcode[8192]; /* maximum size of bootcode */ 138 unsigned char tempcode[8192]; 139 int bootsize; /* actual size of bootcode */ 140 141 142 static char reserved[] = "reserved"; 143 144 struct part_type { 145 int type; 146 char *name; 147 } part_types[] = { 148 {0x00, "unused"}, 149 {0x01, "Primary DOS with 12 bit FAT"}, 150 {0x02, "XENIX / filesystem"}, 151 {0x03, "XENIX /usr filesystem"}, 152 {0x04, "Primary DOS with 16 bit FAT <32M"}, 153 {0x05, "Extended partition"}, 154 {0x06, "Primary 'big' DOS, 16-bit FAT (> 32MB)"}, 155 {0x07, "OS/2 HPFS or NTFS or QNX2 or Advanced UNIX"}, 156 {0x08, "AIX filesystem or OS/2 (thru v1.3) or DELL multiple drives" 157 "or Commodore DOS or SplitDrive"}, 158 {0x09, "AIX boot partition or Coherent"}, 159 {0x0A, "OS/2 Boot Manager or Coherent swap or OPUS"}, 160 {0x0b, "Primary DOS with 32 bit FAT"}, 161 {0x0c, "Primary DOS with 32 bit FAT - LBA"}, 162 {0x0d, "Type 7??? - LBA"}, 163 {0x0E, "DOS (16-bit FAT) - LBA"}, 164 {0x0F, "Ext. partition - LBA"}, 165 {0x10, "OPUS"}, 166 {0x11, "OS/2 BM: hidden DOS 12-bit FAT"}, 167 {0x12, "Compaq diagnostics"}, 168 {0x14, "OS/2 BM: hidden DOS 16-bit FAT <32M or Novell DOS 7.0 bug"}, 169 {0x16, "OS/2 BM: hidden DOS 16-bit FAT >=32M"}, 170 {0x17, "OS/2 BM: hidden IFS"}, 171 {0x18, "AST Windows swapfile"}, 172 {0x19, "Willowtech Photon coS"}, 173 {0x1e, "hidden FAT95"}, 174 {0x20, "Willowsoft OFS1"}, 175 {0x21, reserved}, 176 {0x23, reserved}, 177 {0x24, "NEC DOS"}, 178 {0x26, reserved}, 179 {0x31, reserved}, 180 {0x33, reserved}, 181 {0x34, reserved}, 182 {0x36, reserved}, 183 {0x38, "Theos"}, 184 {0x3C, "PartitionMagic recovery"}, 185 {0x40, "VENIX 286 or LynxOS"}, 186 {0x41, "Linux/MINIX (sharing disk with DRDOS) or Personal RISC boot"}, 187 {0x42, "SFS or Linux swap (sharing disk with DRDOS)"}, 188 {0x43, "Linux native (sharing disk with DRDOS)"}, 189 {0x4D, "QNX4.x"}, 190 {0x4E, "QNX4.x 2nd part"}, 191 {0x4F, "QNX4.x 3rd part"}, 192 {0x50, "DM (disk manager)"}, 193 {0x51, "DM6 Aux1 (or Novell)"}, 194 {0x52, "CP/M or Microport SysV/AT"}, 195 {0x53, "DM6 Aux3"}, 196 {0x54, "DM6 DDO"}, 197 {0x55, "EZ-Drive (disk manager)"}, 198 {0x56, "Golden Bow (disk manager)"}, 199 {0x5C, "Priam Edisk (disk manager)"}, 200 {0x61, "SpeedStor"}, 201 {0x63, "GNU HURD or Mach or Sys V/386 (such as ISC UNIX) or MtXinu"}, 202 {0x64, "Novell Netware 2.xx or Speedstore"}, 203 {0x65, "Novell Netware 3.xx"}, 204 {0x66, "Novell 386 Netware"}, 205 {0x67, "Novell"}, 206 {0x68, "Novell"}, 207 {0x69, "Novell"}, 208 {0x70, "DiskSecure Multi-Boot"}, 209 {0x71, reserved}, 210 {0x73, reserved}, 211 {0x74, reserved}, 212 {0x75, "PC/IX"}, 213 {0x76, reserved}, 214 {0x80, "MINIX until 1.4a"}, 215 {0x81, "MINIX since 1.4b, early Linux, Mitac dmgr"}, 216 {0x82, "Linux swap or Prime or Solaris"}, 217 {0x83, "Linux native"}, 218 {0x84, "OS/2 hidden C: drive"}, 219 {0x85, "Linux extended"}, 220 {0x86, "NT FAT volume set"}, 221 {0x87, "NTFS volume set or HPFS mirrored"}, 222 {0x93, "Amoeba filesystem"}, 223 {0x94, "Amoeba bad block table"}, 224 {0x99, "Mylex EISA SCSI"}, 225 {0x9f, "BSDI?"}, 226 {0xA0, "IBM Thinkpad hibernation"}, 227 {0xa1, reserved}, 228 {0xa3, reserved}, 229 {0xa4, reserved}, 230 {0xA5, "FreeBSD or 386BSD or old NetBSD"}, 231 {0xA6, "OpenBSD"}, 232 {0xA7, "NeXTSTEP 486"}, 233 {0xa9, "NetBSD"}, 234 {0xb1, reserved}, 235 {0xb3, reserved}, 236 {0xb4, reserved}, 237 {0xb6, reserved}, 238 {0xB7, "BSDI BSD/386 filesystem"}, 239 {0xB8, "BSDI BSD/386 swap"}, 240 {0xc0, "CTOS"}, 241 {0xC1, "DRDOS/sec (FAT-12)"}, 242 {0xC4, "DRDOS/sec (FAT-16, < 32M)"}, 243 {0xC6, "DRDOS/sec (FAT-16, >= 32M)"}, 244 {0xC7, "Syrinx (Cyrnix?) or HPFS disabled"}, 245 {0xd8, "CP/M 86"}, 246 {0xDB, "CP/M or Concurrent CP/M or Concurrent DOS or CTOS"}, 247 {0xE1, "DOS access or SpeedStor 12-bit FAT extended partition"}, 248 {0xE3, "DOS R/O or SpeedStor or Storage Dimensions"}, 249 {0xE4, "SpeedStor 16-bit FAT extended partition < 1024 cyl."}, 250 {0xe5, reserved}, 251 {0xe6, reserved}, 252 {0xeb, "BeOS"}, 253 {0xF1, "SpeedStor or Storage Dimensions"}, 254 {0xF2, "DOS 3.3+ Secondary"}, 255 {0xf3, reserved}, 256 {0xF4, "SpeedStor large partition or Storage Dimensions"}, 257 {0xf6, reserved}, 258 {0xFE, "SpeedStor >1024 cyl. or LANstep or IBM PS/2 IML"}, 259 {0xFF, "Xenix Bad Block Table"}, 260 }; 261 262 void usage __P((void)); 263 void print_s0 __P((int)); 264 void print_part __P((int)); 265 int read_boot __P((char *, char *, size_t)); 266 void init_sector0 __P((int, int)); 267 void intuit_translated_geometry __P((void)); 268 void get_geometry __P((void)); 269 void get_diskname __P((char *, char *, size_t)); 270 int try_heads __P((quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, 271 quad_t)); 272 int try_sectors __P((quad_t, quad_t, quad_t, quad_t, quad_t)); 273 void change_part __P((int, int, int, int)); 274 void print_params __P((void)); 275 void change_active __P((int)); 276 void get_params_to_use __P((void)); 277 void dos __P((int, unsigned char *, unsigned char *, unsigned char *)); 278 int open_disk __P((int)); 279 int read_disk __P((int, void *)); 280 int write_disk __P((int, void *)); 281 int get_params __P((void)); 282 int read_s0 __P((void)); 283 int write_s0 __P((void)); 284 int yesno __P((char *)); 285 void decimal __P((char *, int *)); 286 int type_match __P((const void *, const void *)); 287 char *get_type __P((int)); 288 int get_mapping __P((int, int *, int *, int *, long *)); 289 #ifdef __i386__ 290 void configure_bootsel __P((void)); 291 #endif 292 293 static inline unsigned short getshort __P((void *)); 294 static inline void putshort __P((void *p, unsigned short)); 295 static inline unsigned long getlong __P((void *)); 296 static inline void putlong __P((void *, unsigned long)); 297 298 299 int main __P((int, char **)); 300 301 int 302 main(argc, argv) 303 int argc; 304 char *argv[]; 305 { 306 int ch; 307 int part; 308 309 int csysid, cstart, csize; /* For the b_flag. */ 310 311 a_flag = i_flag = u_flag = sh_flag = f_flag = s_flag = b_flag = 0; 312 csysid = cstart = csize = 0; 313 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 314 switch (ch) { 315 case '0': 316 partition = 0; 317 break; 318 case '1': 319 partition = 1; 320 break; 321 case '2': 322 partition = 2; 323 break; 324 case '3': 325 partition = 3; 326 break; 327 #ifdef __i386__ 328 case 'B': 329 B_flag = 1; 330 break; 331 #endif 332 case 'S': 333 sh_flag = 1; 334 break; 335 case 'a': 336 a_flag = 1; 337 break; 338 case 'f': 339 f_flag = 1; 340 break; 341 case 'i': 342 i_flag = 1; 343 break; 344 case 'u': 345 u_flag = 1; 346 break; 347 case 's': 348 s_flag = 1; 349 if (sscanf (optarg, "%d/%d/%d", 350 &csysid, &cstart, &csize) != 3) { 351 (void)fprintf (stderr, "%s: Bad argument " 352 "to the -s flag.\n", 353 argv[0]); 354 exit (1); 355 } 356 break; 357 case 'b': 358 b_flag = 1; 359 if (sscanf (optarg, "%d/%d/%d", 360 &b_cyl, &b_head, &b_sec) != 3) { 361 (void)fprintf (stderr, "%s: Bad argument " 362 "to the -b flag.\n", 363 argv[0]); 364 exit (1); 365 } 366 if (b_cyl > MAXCYL) 367 b_cyl = MAXCYL; 368 break; 369 case 'c': 370 bootsize = read_boot(optarg, bootcode, sizeof bootcode); 371 break; 372 default: 373 usage(); 374 } 375 argc -= optind; 376 argv += optind; 377 378 if (sh_flag && (a_flag || i_flag || u_flag || f_flag || s_flag)) 379 usage(); 380 381 if (B_flag && (a_flag || i_flag || u_flag || f_flag || s_flag)) 382 usage(); 383 384 if (partition == -1 && s_flag) { 385 (void) fprintf (stderr, 386 "-s flag requires a partition selected.\n"); 387 usage(); 388 } 389 390 if (argc > 0) 391 disk = argv[0]; 392 393 if (open_disk(B_flag || a_flag || i_flag || u_flag) < 0) 394 exit(1); 395 396 if (read_s0()) 397 init_sector0(sectors > 63 ? 63 : sectors, 1); 398 399 #ifdef __i386__ 400 get_geometry(); 401 #else 402 intuit_translated_geometry(); 403 #endif 404 405 406 if ((i_flag || u_flag) && (!f_flag || b_flag)) 407 get_params_to_use(); 408 409 if (i_flag) 410 init_sector0(dos_sectors > 63 ? 63 : dos_sectors, 0); 411 412 /* Do the update stuff! */ 413 if (u_flag) { 414 if (!f_flag) 415 printf("Partition table:\n"); 416 if (partition == -1) 417 for (part = 0; part < NMBRPART; part++) 418 change_part(part,-1, -1, -1); 419 else 420 change_part(partition, csysid, cstart, csize); 421 } else 422 if (!i_flag) 423 print_s0(partition); 424 425 if (a_flag) 426 change_active(partition); 427 428 #ifdef __i386__ 429 if (B_flag) { 430 configure_bootsel(); 431 if (B_flag && bootsel_modified) 432 write_s0(); 433 } 434 #endif 435 436 if (u_flag || a_flag || i_flag) { 437 if (!f_flag) { 438 printf("\nWe haven't written the MBR back to disk " 439 "yet. This is your last chance.\n"); 440 print_s0(-1); 441 if (yesno("Should we write new partition table?")) 442 write_s0(); 443 } else 444 write_s0(); 445 } 446 447 exit(0); 448 } 449 450 void 451 usage() 452 { 453 (void)fprintf(stderr, "usage: fdisk [-aiufBS] [-0|-1|-2|-3] " 454 "[-b cylinders/heads/sectors]\n" 455 " [-s id/start/size] [-c bootcode] " 456 "[device]\n"); 457 exit(1); 458 } 459 460 void 461 print_s0(which) 462 int which; 463 { 464 int part; 465 466 print_params(); 467 if (!sh_flag) 468 printf("Partition table:\n"); 469 if (which == -1) { 470 for (part = 0; part < NMBRPART; part++) { 471 if (!sh_flag) 472 printf("%d: ", part); 473 print_part(part); 474 } 475 } else 476 print_part(which); 477 } 478 479 static inline unsigned short 480 getshort(p) 481 void *p; 482 { 483 unsigned char *cp = p; 484 485 return cp[0] | (cp[1] << 8); 486 } 487 488 static inline void 489 putshort(p, l) 490 void *p; 491 unsigned short l; 492 { 493 unsigned char *cp = p; 494 495 *cp++ = l; 496 *cp++ = l >> 8; 497 } 498 499 static inline unsigned long 500 getlong(p) 501 void *p; 502 { 503 unsigned char *cp = p; 504 505 return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24); 506 } 507 508 static inline void 509 putlong(p, l) 510 void *p; 511 unsigned long l; 512 { 513 unsigned char *cp = p; 514 515 *cp++ = l; 516 *cp++ = l >> 8; 517 *cp++ = l >> 16; 518 *cp++ = l >> 24; 519 } 520 521 void 522 print_part(part) 523 int part; 524 { 525 struct mbr_partition *partp; 526 int empty; 527 528 partp = &mboot.parts[part]; 529 empty = (partp->mbrp_typ == 0); 530 531 if (sh_flag) { 532 if (empty) { 533 printf("PART%dSIZE=0\n", part); 534 return; 535 } 536 537 printf("PART%dID=%d\n", part, partp->mbrp_typ); 538 printf("PART%dSIZE=%ld\n", part, getlong(&partp->mbrp_size)); 539 printf("PART%dSTART=%ld\n", part, getlong(&partp->mbrp_start)); 540 printf("PART%dFLAG=0x%x\n", part, partp->mbrp_flag); 541 printf("PART%dBCYL=%d\n", part, MBR_PCYL(partp->mbrp_scyl, 542 partp->mbrp_ssect)); 543 printf("PART%dBHEAD=%d\n", part, partp->mbrp_shd); 544 printf("PART%dBSEC=%d\n", part, MBR_PSECT(partp->mbrp_ssect)); 545 printf("PART%dECYL=%d\n", part, MBR_PCYL(partp->mbrp_ecyl, 546 partp->mbrp_esect)); 547 printf("PART%dEHEAD=%d\n", part, partp->mbrp_ehd); 548 printf("PART%dESEC=%d\n", part, MBR_PSECT(partp->mbrp_esect)); 549 return; 550 } 551 552 /* Not sh_flag. */ 553 if (empty) { 554 printf("<UNUSED>\n"); 555 return; 556 } 557 printf("sysid %d (%s)\n", partp->mbrp_typ, get_type(partp->mbrp_typ)); 558 printf(" start %ld, size %ld (%ld MB), flag 0x%x\n", 559 getlong(&partp->mbrp_start), getlong(&partp->mbrp_size), 560 getlong(&partp->mbrp_size) * 512 / (1024 * 1024), partp->mbrp_flag); 561 printf("\tbeg: cylinder %4d, head %3d, sector %2d\n", 562 MBR_PCYL(partp->mbrp_scyl, partp->mbrp_ssect), 563 partp->mbrp_shd, MBR_PSECT(partp->mbrp_ssect)); 564 printf("\tend: cylinder %4d, head %3d, sector %2d\n", 565 MBR_PCYL(partp->mbrp_ecyl, partp->mbrp_esect), 566 partp->mbrp_ehd, MBR_PSECT(partp->mbrp_esect)); 567 } 568 569 int 570 read_boot(name, buf, len) 571 char *name; 572 char *buf; 573 size_t len; 574 { 575 int bfd, ret; 576 struct stat st; 577 578 if ((bfd = open(name, O_RDONLY)) < 0) 579 err(1, "%s", name); 580 if (fstat(bfd, &st) == -1) 581 err(1, "%s", name); 582 if (st.st_size > len) 583 errx(1, "%s: bootcode too large", name); 584 ret = st.st_size; 585 if (ret < 0x200) 586 errx(1, "%s: bootcode too small", name); 587 if (read(bfd, buf, len) != ret) 588 err(1, "%s", name); 589 close(bfd); 590 591 /* 592 * Do some sanity checking here 593 */ 594 if (getshort(bootcode + MBR_MAGICOFF) != MBR_MAGIC) 595 errx(1, "%s: invalid magic", name); 596 ret = (ret + 0x1ff) / 0x200; 597 ret *= 0x200; 598 return ret; 599 } 600 601 void 602 init_sector0(start, dopart) 603 int start, dopart; 604 { 605 int i; 606 607 #ifdef DEFAULT_BOOTCODE 608 if (!bootsize) 609 bootsize = read_boot(DEFAULT_BOOTCODE, bootcode, 610 sizeof bootcode); 611 #endif 612 613 memcpy(mboot.bootinst, bootcode, sizeof(mboot.bootinst)); 614 putshort(&mboot.signature, MBR_MAGIC); 615 616 if (dopart) 617 for (i=0; i<4; i++) 618 memset(&mboot.parts[i], 0, sizeof(struct mbr_partition)); 619 620 } 621 622 #ifdef __i386__ 623 624 void 625 get_diskname(fullname, diskname, size) 626 char *fullname; 627 char *diskname; 628 size_t size; 629 { 630 char *p; 631 char *p2; 632 size_t len; 633 634 p = strrchr(fullname, '/'); 635 if (p == NULL) 636 p = fullname; 637 else 638 p++; 639 640 if (*p == 0) { 641 strncpy(diskname, fullname, size - 1); 642 diskname[size - 1] = '\0'; 643 return; 644 } 645 646 if (*p == 'r') 647 p++; 648 649 for (p2 = p; *p2 != 0; p2++) 650 if (isdigit(*p2)) 651 break; 652 if (*p2 == 0) { 653 /* XXX invalid diskname? */ 654 strncpy(diskname, fullname, size - 1); 655 diskname[size - 1] = '\0'; 656 return; 657 } 658 while (isdigit(*p2)) 659 p2++; 660 661 len = p2 - p; 662 if (len > size) { 663 /* XXX */ 664 strncpy(diskname, fullname, size - 1); 665 diskname[size - 1] = '\0'; 666 return; 667 } 668 669 strncpy(diskname, p, len); 670 diskname[len] = 0; 671 } 672 673 void 674 get_geometry() 675 { 676 int mib[2], i; 677 size_t len; 678 struct disklist *dl; 679 struct biosdisk_info *bip; 680 struct nativedisk_info *nip; 681 char diskname[8]; 682 683 mib[0] = CTL_MACHDEP; 684 mib[1] = CPU_DISKINFO; 685 if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0) { 686 intuit_translated_geometry(); 687 return; 688 } 689 dl = (struct disklist *) malloc(len); 690 sysctl(mib, 2, dl, &len, NULL, 0); 691 692 get_diskname(disk, diskname, sizeof diskname); 693 694 for (i = 0; i < dl->dl_nnativedisks; i++) { 695 nip = &dl->dl_nativedisks[i]; 696 if (strcmp(diskname, nip->ni_devname)) 697 continue; 698 /* 699 * XXX listing possible matches is better. This is ok 700 * for now because the user has a chance to change 701 * it later. 702 */ 703 if (nip->ni_nmatches != 0) { 704 bip = &dl->dl_biosdisks[nip->ni_biosmatches[0]]; 705 dos_cylinders = bip->bi_cyl; 706 dos_heads = bip->bi_head; 707 dos_sectors = bip->bi_sec; 708 dos_cylindersectors = bip->bi_head * bip->bi_sec; 709 return; 710 } 711 } 712 /* Allright, allright, make a stupid guess.. */ 713 intuit_translated_geometry(); 714 } 715 716 void 717 configure_bootsel() 718 { 719 struct mbr_bootsel *mbs = 720 (struct mbr_bootsel *)&mboot.bootinst[MBR_BOOTSELOFF]; 721 int i, nused, firstpart = -1, item; 722 char desc[PARTNAMESIZE + 2], *p; 723 int timo, entry_changed = 0; 724 725 for (i = nused = 0; i < NMBRPART; ++i) { 726 if (mboot.parts[i].mbrp_typ != 0) { 727 if (firstpart == -1) 728 firstpart = i; 729 nused++; 730 } 731 } 732 733 if (nused == 0) { 734 printf("No used partitions found. Partition the disk first.\n"); 735 return; 736 } 737 738 if (mbs->magic != MBR_MAGIC) { 739 if (!yesno("Bootselector not yet installed. Install it now?")) { 740 printf("Bootselector not installed.\n"); 741 return; 742 } 743 bootsize = read_boot(DEFAULT_BOOTSELCODE, bootcode, 744 sizeof bootcode); 745 memcpy(mboot.bootinst, bootcode, sizeof(mboot.bootinst)); 746 bootsel_modified = 1; 747 mbs->flags |= BFL_SELACTIVE; 748 } else { 749 if (mbs->flags & BFL_SELACTIVE) { 750 printf("The bootselector is installed and active.\n"); 751 if (!yesno("Do you want to change its settings?")) { 752 if (yesno("Do you want to deactivate it?")) { 753 mbs->flags &= ~BFL_SELACTIVE; 754 bootsel_modified = 1; 755 goto done; 756 } 757 return; 758 } 759 } else { 760 printf("The bootselector is installed but not active.\n"); 761 if (yesno("Do you want to activate it?")) { 762 mbs->flags |= BFL_SELACTIVE; 763 bootsel_modified = 1; 764 } 765 if (!yesno("Do you want to change its settings?")) 766 goto done; 767 } 768 } 769 770 printf("\n\nPartition table:\n"); 771 for (i = 0; i < NMBRPART; i++) { 772 printf("%d: ", i); 773 print_part(i); 774 } 775 776 printf("\n\nCurrent boot selection menu option names:\n"); 777 for (i = 0; i < NMBRPART; i++) { 778 if (mbs->nametab[i][0] != 0) 779 printf("%d: %s\n", i, &mbs->nametab[i][0]); 780 else 781 printf("%d: <UNUSED>\n", i); 782 } 783 printf("\n"); 784 785 item = firstpart; 786 787 editentries: 788 while (1) { 789 decimal("Change which entry (-1 quits)?", &item); 790 if (item == -1) 791 break; 792 if (item < 0 || item >= NMBRPART) { 793 printf("Invalid entry number\n"); 794 item = -1; 795 continue; 796 } 797 if (mboot.parts[item].mbrp_typ == 0) { 798 printf("The partition entry is unused\n"); 799 item = -1; 800 continue; 801 } 802 803 printf("Enter descriptions (max. 8 characters): "); 804 rewind(stdin); 805 fgets(desc, PARTNAMESIZE + 1, stdin); 806 fpurge(stdin); 807 p = strchr(desc, '\n'); 808 if (p != NULL) 809 *p = 0; 810 strcpy(&mbs->nametab[item][0], desc); 811 entry_changed = bootsel_modified = 1; 812 813 item++; 814 } 815 816 if (entry_changed) 817 printf("Boot selection menu option names are now:\n"); 818 819 firstpart = -1; 820 for (i = 0; i < NMBRPART; i++) { 821 if (mbs->nametab[i][0] != 0) { 822 firstpart = i; 823 if (entry_changed) 824 printf("%d: %s\n", i, &mbs->nametab[i][0]); 825 } else { 826 if (entry_changed) 827 printf("%d: <UNUSED>\n", i); 828 } 829 } 830 if (entry_changed) 831 printf("\n"); 832 833 if (firstpart == -1) { 834 printf("All menu entries are now inactive.\n"); 835 if (!yesno("Are you sure about this?")) 836 goto editentries; 837 } else { 838 if (!(mbs->flags & BFL_SELACTIVE)) { 839 printf("The bootselector is not yet active.\n"); 840 if (yesno("Activate it now?")) 841 mbs->flags |= BFL_SELACTIVE; 842 } 843 } 844 845 /* bootsel is dirty from here on out. */ 846 bootsel_modified = 1; 847 848 /* The timeout value is in ticks, 18.2 Hz. Avoid using floats. */ 849 timo = ((1000 * mbs->timeo) / 18200); 850 do { 851 decimal("Timeout value", &timo); 852 } while (timo < 0 || timo > 3600); 853 mbs->timeo = (u_int16_t)((timo * 18200) / 1000); 854 855 printf("Select the default boot option. Options are:\n\n"); 856 for (i = 0; i < NMBRPART; i++) { 857 if (mbs->nametab[i][0] != 0) 858 printf("%d: %s\n", i, &mbs->nametab[i][0]); 859 } 860 for (i = 4; i < 10; i++) 861 printf("%d: Harddisk %d\n", i, i - 4); 862 printf("10: The first active partition\n"); 863 864 if (mbs->defkey == SCAN_ENTER) 865 item = 10; 866 else 867 item = mbs->defkey - SCAN_F1; 868 869 if (item < 0 || item > 10 || mbs->nametab[item][0] == 0) 870 item = 10; 871 872 do { 873 decimal("Default boot option", &item); 874 } while (item < 0 || item > 10 || 875 (item <= 3 && mbs->nametab[item][0] == 0)); 876 877 if (item == 10) 878 mbs->defkey = SCAN_ENTER; 879 else 880 mbs->defkey = SCAN_F1 + item; 881 882 done: 883 for (i = 0; i < NMBRPART; i++) { 884 if (mboot.parts[i].mbrp_typ != 0 && 885 mboot.parts[i].mbrp_start >= 886 (dos_cylinders * dos_heads * dos_sectors)) { 887 mbs->flags |= BFL_EXTINT13; 888 break; 889 } 890 } 891 892 if (bootsel_modified != 0 && !yesno("Update the bootselector?")) 893 bootsel_modified = 0; 894 } 895 #endif 896 897 898 /* Prerequisite: the disklabel parameters and master boot record must 899 * have been read (i.e. dos_* and mboot are meaningful). 900 * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and 901 * dos_cylindersectors to be consistent with what the 902 * partition table is using, if we can find a geometry 903 * which is consistent with all partition table entries. 904 * We may get the number of cylinders slightly wrong (in 905 * the conservative direction). The idea is to be able 906 * to create a NetBSD partition on a disk we don't know 907 * the translated geometry of. 908 * This whole routine should be replaced with a kernel interface to get 909 * the BIOS geometry (which in turn requires modifications to the i386 910 * boot loader to pass in the BIOS geometry for each disk). */ 911 void 912 intuit_translated_geometry() 913 { 914 915 int cylinders = -1, heads = -1, sectors = -1, i, j; 916 int c1, h1, s1, c2, h2, s2; 917 long a1, a2; 918 quad_t num, denom; 919 920 /* Try to deduce the number of heads from two different mappings. */ 921 for (i = 0; i < NMBRPART * 2; i++) { 922 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0) 923 continue; 924 for (j = 0; j < 8; j++) { 925 if (get_mapping(j, &c2, &h2, &s2, &a2) < 0) 926 continue; 927 num = (quad_t)h1*(a2-s2) - (quad_t)h2*(a1-s1); 928 denom = (quad_t)c2*(a1-s1) - (quad_t)c1*(a2-s2); 929 if (denom != 0 && num % denom == 0) { 930 heads = num / denom; 931 break; 932 } 933 } 934 if (heads != -1) 935 break; 936 } 937 938 if (heads == -1) 939 return; 940 941 /* Now figure out the number of sectors from a single mapping. */ 942 for (i = 0; i < NMBRPART * 2; i++) { 943 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0) 944 continue; 945 num = a1 - s1; 946 denom = c1 * heads + h1; 947 if (denom != 0 && num % denom == 0) { 948 sectors = num / denom; 949 break; 950 } 951 } 952 953 if (sectors == -1) 954 return; 955 956 /* Estimate the number of cylinders. */ 957 cylinders = disklabel.d_secperunit / heads / sectors; 958 959 /* Now verify consistency with each of the partition table entries. 960 * Be willing to shove cylinders up a little bit to make things work, 961 * but translation mismatches are fatal. */ 962 for (i = 0; i < NMBRPART * 2; i++) { 963 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0) 964 continue; 965 if (sectors * (c1 * heads + h1) + s1 != a1) 966 return; 967 if (c1 >= cylinders) 968 cylinders = c1 + 1; 969 } 970 971 /* Everything checks out. Reset the geometry to use for further 972 * calculations. */ 973 dos_cylinders = cylinders; 974 dos_heads = heads; 975 dos_sectors = sectors; 976 dos_cylindersectors = heads * sectors; 977 } 978 979 /* For the purposes of intuit_translated_geometry(), treat the partition 980 * table as a list of eight mapping between (cylinder, head, sector) 981 * triplets and absolute sectors. Get the relevant geometry triplet and 982 * absolute sectors for a given entry, or return -1 if it isn't present. 983 * Note: for simplicity, the returned sector is 0-based. */ 984 int 985 get_mapping(i, cylinder, head, sector, absolute) 986 int i, *cylinder, *head, *sector; 987 long *absolute; 988 { 989 struct mbr_partition *part = &mboot.parts[i / 2]; 990 991 if (part->mbrp_typ == 0) 992 return -1; 993 if (i % 2 == 0) { 994 *cylinder = MBR_PCYL(part->mbrp_scyl, part->mbrp_ssect); 995 *head = part->mbrp_shd; 996 *sector = MBR_PSECT(part->mbrp_ssect) - 1; 997 *absolute = getlong(&part->mbrp_start); 998 } else { 999 *cylinder = MBR_PCYL(part->mbrp_ecyl, part->mbrp_esect); 1000 *head = part->mbrp_ehd; 1001 *sector = MBR_PSECT(part->mbrp_esect) - 1; 1002 *absolute = getlong(&part->mbrp_start) 1003 + getlong(&part->mbrp_size) - 1; 1004 } 1005 return 0; 1006 } 1007 1008 void 1009 change_part(part, csysid, cstart, csize) 1010 int part, csysid, cstart, csize; 1011 { 1012 struct mbr_partition *partp; 1013 1014 partp = &mboot.parts[part]; 1015 1016 if (s_flag) { 1017 if (csysid == 0 && cstart == 0 && csize == 0) 1018 memset(partp, 0, sizeof *partp); 1019 else { 1020 partp->mbrp_typ = csysid; 1021 #if 0 1022 checkcyl(cstart / dos_cylindersectors); 1023 #endif 1024 putlong(&partp->mbrp_start, cstart); 1025 putlong(&partp->mbrp_size, csize); 1026 dos(getlong(&partp->mbrp_start), 1027 &partp->mbrp_scyl, &partp->mbrp_shd, &partp->mbrp_ssect); 1028 dos(getlong(&partp->mbrp_start) 1029 + getlong(&partp->mbrp_size) - 1, 1030 &partp->mbrp_ecyl, &partp->mbrp_ehd, &partp->mbrp_esect); 1031 } 1032 if (f_flag) 1033 return; 1034 } 1035 1036 printf("The data for partition %d is:\n", part); 1037 print_part(part); 1038 if (!u_flag || !yesno("Do you want to change it?")) 1039 return; 1040 1041 do { 1042 { 1043 int sysid, start, size; 1044 1045 sysid = partp->mbrp_typ, 1046 start = getlong(&partp->mbrp_start), 1047 size = getlong(&partp->mbrp_size); 1048 decimal("sysid", &sysid); 1049 decimal("start", &start); 1050 decimal("size", &size); 1051 partp->mbrp_typ = sysid; 1052 putlong(&partp->mbrp_start, start); 1053 putlong(&partp->mbrp_size, size); 1054 } 1055 1056 if (yesno("Explicitly specify beg/end address?")) { 1057 int tsector, tcylinder, thead; 1058 1059 tcylinder = MBR_PCYL(partp->mbrp_scyl, partp->mbrp_ssect); 1060 thead = partp->mbrp_shd; 1061 tsector = MBR_PSECT(partp->mbrp_ssect); 1062 decimal("beginning cylinder", &tcylinder); 1063 #if 0 1064 checkcyl(tcylinder); 1065 #endif 1066 decimal("beginning head", &thead); 1067 decimal("beginning sector", &tsector); 1068 partp->mbrp_scyl = DOSCYL(tcylinder); 1069 partp->mbrp_shd = thead; 1070 partp->mbrp_ssect = DOSSECT(tsector, tcylinder); 1071 1072 tcylinder = MBR_PCYL(partp->mbrp_ecyl, partp->mbrp_esect); 1073 thead = partp->mbrp_ehd; 1074 tsector = MBR_PSECT(partp->mbrp_esect); 1075 decimal("ending cylinder", &tcylinder); 1076 decimal("ending head", &thead); 1077 decimal("ending sector", &tsector); 1078 partp->mbrp_ecyl = DOSCYL(tcylinder); 1079 partp->mbrp_ehd = thead; 1080 partp->mbrp_esect = DOSSECT(tsector, tcylinder); 1081 } else { 1082 1083 if (partp->mbrp_typ == 0 1084 && getlong(&partp->mbrp_start) == 0 1085 && getlong(&partp->mbrp_size) == 0) 1086 memset(partp, 0, sizeof *partp); 1087 else { 1088 #if 0 1089 checkcyl(getlong(&partp->mbrp_start) 1090 / dos_cylindersectors); 1091 #endif 1092 dos(getlong(&partp->mbrp_start), &partp->mbrp_scyl, 1093 &partp->mbrp_shd, &partp->mbrp_ssect); 1094 dos(getlong(&partp->mbrp_start) 1095 + getlong(&partp->mbrp_size) - 1, 1096 &partp->mbrp_ecyl, &partp->mbrp_ehd, 1097 &partp->mbrp_esect); 1098 } 1099 } 1100 1101 print_part(part); 1102 } while (!yesno("Is this entry okay?")); 1103 } 1104 1105 void 1106 print_params() 1107 { 1108 1109 if (sh_flag) { 1110 printf ("DLCYL=%d\nDLHEAD=%d\nDLSEC=%d\nDLSIZE=%d\n", 1111 cylinders, heads, sectors, disksectors); 1112 printf ("BCYL=%d\nBHEAD=%d\nBSEC=%d\n", 1113 dos_cylinders, dos_heads, dos_sectors); 1114 return; 1115 } 1116 1117 /* Not sh_flag */ 1118 printf("NetBSD disklabel disk geometry:\n"); 1119 printf("cylinders: %d heads: %d sectors/track: %d (%d sectors/cylinder)\n\n", 1120 cylinders, heads, sectors, cylindersectors); 1121 printf("BIOS disk geometry:\n"); 1122 printf("cylinders: %d heads: %d sectors/track: %d (%d sectors/cylinder)\n\n", 1123 dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors); 1124 } 1125 1126 void 1127 change_active(which) 1128 int which; 1129 { 1130 struct mbr_partition *partp; 1131 int part; 1132 int active = 4; 1133 1134 partp = &mboot.parts[0]; 1135 1136 if (a_flag && which != -1) 1137 active = which; 1138 else { 1139 for (part = 0; part < NMBRPART; part++) 1140 if (partp[part].mbrp_flag & ACTIVE) 1141 active = part; 1142 } 1143 if (!f_flag) { 1144 if (yesno("Do you want to change the active partition?")) { 1145 printf ("Choosing 4 will make no partition active.\n"); 1146 do { 1147 decimal("active partition", &active); 1148 } while (!yesno("Are you happy with this choice?")); 1149 } else 1150 return; 1151 } else 1152 if (active != 4) 1153 printf ("Making partition %d active.\n", active); 1154 1155 for (part = 0; part < NMBRPART; part++) 1156 partp[part].mbrp_flag &= ~ACTIVE; 1157 if (active < 4) 1158 partp[active].mbrp_flag |= ACTIVE; 1159 } 1160 1161 void 1162 get_params_to_use() 1163 { 1164 if (b_flag) { 1165 dos_cylinders = b_cyl; 1166 dos_heads = b_head; 1167 dos_sectors = b_sec; 1168 dos_cylindersectors = dos_heads * dos_sectors; 1169 return; 1170 } 1171 1172 print_params(); 1173 if (yesno("Do you want to change our idea of what BIOS thinks?")) { 1174 do { 1175 decimal("BIOS's idea of #cylinders", &dos_cylinders); 1176 decimal("BIOS's idea of #heads", &dos_heads); 1177 decimal("BIOS's idea of #sectors", &dos_sectors); 1178 dos_cylindersectors = dos_heads * dos_sectors; 1179 print_params(); 1180 } while (!yesno("Are you happy with this choice?")); 1181 } 1182 } 1183 1184 /***********************************************\ 1185 * Change real numbers into strange dos numbers * 1186 \***********************************************/ 1187 void 1188 dos(sector, cylinderp, headp, sectorp) 1189 int sector; 1190 unsigned char *cylinderp, *headp, *sectorp; 1191 { 1192 int cylinder, head; 1193 int biosmaxsec; 1194 1195 biosmaxsec = dos_cylinders * dos_heads * dos_sectors - 1; 1196 if (sector > biosmaxsec) 1197 sector = biosmaxsec; 1198 1199 cylinder = sector / dos_cylindersectors; 1200 1201 sector -= cylinder * dos_cylindersectors; 1202 1203 head = sector / dos_sectors; 1204 sector -= head * dos_sectors; 1205 1206 *cylinderp = DOSCYL(cylinder); 1207 *headp = head; 1208 *sectorp = DOSSECT(sector + 1, cylinder); 1209 } 1210 1211 #if 0 1212 void 1213 checkcyl(cyl) 1214 int cyl; 1215 { 1216 if (cyl >= MAXCYL) 1217 warnx("partition start beyond BIOS limit"); 1218 } 1219 #endif 1220 1221 int fd; 1222 1223 int 1224 open_disk(u_flag) 1225 int u_flag; 1226 { 1227 static char namebuf[MAXPATHLEN + 1]; 1228 struct stat st; 1229 1230 fd = opendisk(disk, u_flag ? O_RDWR : O_RDONLY, namebuf, 1231 sizeof(namebuf), 0); 1232 if (fd < 0) { 1233 warn("%s", namebuf); 1234 return (-1); 1235 } 1236 disk = namebuf; 1237 if (fstat(fd, &st) == -1) { 1238 close(fd); 1239 warn("%s", disk); 1240 return (-1); 1241 } 1242 if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) { 1243 close(fd); 1244 warnx("%s is not a character device or regular file", disk); 1245 return (-1); 1246 } 1247 if (get_params() == -1) { 1248 close(fd); 1249 return (-1); 1250 } 1251 return (0); 1252 } 1253 1254 int 1255 read_disk(sector, buf) 1256 int sector; 1257 void *buf; 1258 { 1259 1260 if (lseek(fd, (off_t)(sector * 512), 0) == -1) 1261 return (-1); 1262 return (read(fd, buf, 512)); 1263 } 1264 1265 int 1266 write_disk(sector, buf) 1267 int sector; 1268 void *buf; 1269 { 1270 1271 if (lseek(fd, (off_t)(sector * 512), 0) == -1) 1272 return (-1); 1273 return (write(fd, buf, 512)); 1274 } 1275 1276 int 1277 get_params() 1278 { 1279 1280 if (ioctl(fd, DIOCGDEFLABEL, &disklabel) == -1) { 1281 warn("DIOCGDEFLABEL"); 1282 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 1283 warn("DIOCGDINFO"); 1284 return (-1); 1285 } 1286 } 1287 1288 dos_cylinders = cylinders = disklabel.d_ncylinders; 1289 dos_heads = heads = disklabel.d_ntracks; 1290 dos_sectors = sectors = disklabel.d_nsectors; 1291 dos_cylindersectors = cylindersectors = heads * sectors; 1292 disksectors = disklabel.d_secperunit; 1293 1294 return (0); 1295 } 1296 1297 int 1298 read_s0() 1299 { 1300 1301 if (read_disk(0, mboot.bootinst) == -1) { 1302 warn("can't read fdisk partition table"); 1303 return (-1); 1304 } 1305 if (getshort(&mboot.signature) != MBR_MAGIC) { 1306 warnx("invalid fdisk partition table found"); 1307 return (-1); 1308 } 1309 return (0); 1310 } 1311 1312 int 1313 write_s0() 1314 { 1315 int flag, i; 1316 1317 /* 1318 * write enable label sector before write (if necessary), 1319 * disable after writing. 1320 * needed if the disklabel protected area also protects 1321 * sector 0. (e.g. empty disk) 1322 */ 1323 flag = 1; 1324 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 1325 warn("DIOCWLABEL"); 1326 if (write_disk(0, mboot.bootinst) == -1) { 1327 warn("can't write fdisk partition table"); 1328 return -1; 1329 } 1330 for (i = bootsize; (i -= 0x200) > 0;) 1331 if (write_disk(i / 0x200, bootcode + i) == -1) { 1332 warn("can't write bootcode"); 1333 return -1; 1334 } 1335 flag = 0; 1336 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 1337 warn("DIOCWLABEL"); 1338 return 0; 1339 } 1340 1341 int 1342 yesno(str) 1343 char *str; 1344 { 1345 int ch, first; 1346 1347 printf("%s [n] ", str); 1348 1349 first = ch = getchar(); 1350 while (ch != '\n' && ch != EOF) 1351 ch = getchar(); 1352 return (first == 'y' || first == 'Y'); 1353 } 1354 1355 void 1356 decimal(str, num) 1357 char *str; 1358 int *num; 1359 { 1360 int acc = 0; 1361 char *cp; 1362 1363 for (;; printf("%s is not a valid decimal number.\n", lbuf)) { 1364 printf("%s: [%d] ", str, *num); 1365 1366 fgets(lbuf, LBUF, stdin); 1367 lbuf[strlen(lbuf)-1] = '\0'; 1368 cp = lbuf; 1369 1370 cp += strspn(cp, " \t"); 1371 if (*cp == '\0') 1372 return; 1373 1374 if (!isdigit(*cp) && *cp != '-') 1375 continue; 1376 acc = strtol(lbuf, &cp, 10); 1377 1378 cp += strspn(cp, " \t"); 1379 if (*cp != '\0') 1380 continue; 1381 1382 *num = acc; 1383 return; 1384 } 1385 1386 } 1387 1388 int 1389 type_match(key, item) 1390 const void *key, *item; 1391 { 1392 const int *typep = key; 1393 const struct part_type *ptr = item; 1394 1395 if (*typep < ptr->type) 1396 return (-1); 1397 if (*typep > ptr->type) 1398 return (1); 1399 return (0); 1400 } 1401 1402 char * 1403 get_type(type) 1404 int type; 1405 { 1406 struct part_type *ptr; 1407 1408 ptr = bsearch(&type, part_types, 1409 sizeof(part_types) / sizeof(struct part_type), 1410 sizeof(struct part_type), type_match); 1411 if (ptr == 0) 1412 return ("unknown"); 1413 return (ptr->name); 1414 } 1415