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