1 /* 2 * Mach Operating System 3 * Copyright (c) 1992 Carnegie Mellon University 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify and distribute this software and its 7 * documentation is hereby granted, provided that both the copyright 8 * notice and this permission notice appear in all copies of the 9 * software, derivative works or modified versions, and any portions 10 * thereof, and that both notices appear in supporting documentation. 11 * 12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15 * 16 * Carnegie Mellon requests users of this software to return to 17 * 18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19 * School of Computer Science 20 * Carnegie Mellon University 21 * Pittsburgh PA 15213-3890 22 * 23 * any improvements or extensions that they make and grant Carnegie Mellon 24 * the rights to redistribute these changes. 25 */ 26 27 #ifndef lint 28 static const char rcsid[] = 29 "$FreeBSD$"; 30 #endif /* not lint */ 31 32 #include <sys/disklabel.h> 33 #include <sys/stat.h> 34 #include <ctype.h> 35 #include <fcntl.h> 36 #include <err.h> 37 #include <errno.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 43 int iotest; 44 45 #define LBUF 100 46 static char lbuf[LBUF]; 47 48 /* 49 * 50 * Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992 51 * 52 * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University 53 * Copyright (c) 1989 Robert. V. Baron 54 * Created. 55 */ 56 57 #define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp 58 #define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp 59 #define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); } 60 61 #define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs) 62 63 #define MAX_SEC_SIZE 2048 /* maximum section size that is supported */ 64 #define MIN_SEC_SIZE 512 /* the sector size to start sensing at */ 65 int secsize = 0; /* the sensed sector size */ 66 67 const char *disk; 68 const char *disks[] = 69 { 70 "/dev/rad0", "/dev/rwd0", "/dev/rda0", "/dev/rod0", 0 71 }; 72 73 struct disklabel disklabel; /* disk parameters */ 74 75 int cyls, sectors, heads, cylsecs, disksecs; 76 77 struct mboot 78 { 79 unsigned char padding[2]; /* force the longs to be long aligned */ 80 unsigned char bootinst[DOSPARTOFF]; 81 struct dos_partition parts[4]; 82 unsigned short int signature; 83 /* room to read in MBRs that are bigger then DEV_BSIZE */ 84 unsigned char large_sector_overflow[MAX_SEC_SIZE-MIN_SEC_SIZE]; 85 }; 86 struct mboot mboot; 87 88 #define ACTIVE 0x80 89 #define BOOT_MAGIC 0xAA55 90 91 int dos_cyls; 92 int dos_heads; 93 int dos_sectors; 94 int dos_cylsecs; 95 96 #define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0)) 97 #define DOSCYL(c) (c & 0xff) 98 static int partition = -1; 99 100 101 #define MAX_ARGS 10 102 103 static int current_line_number; 104 105 static int geom_processed = 0; 106 static int part_processed = 0; 107 static int active_processed = 0; 108 109 110 typedef struct cmd { 111 char cmd; 112 int n_args; 113 struct arg { 114 char argtype; 115 int arg_val; 116 } args[MAX_ARGS]; 117 } CMD; 118 119 120 static int B_flag = 0; /* replace boot code */ 121 static int a_flag = 0; /* set active partition */ 122 static char *b_flag = NULL; /* path to boot code */ 123 static int e_flag = 0; /* use entire disk for FreeBSD */ 124 static int i_flag = 0; /* replace partition data */ 125 static int u_flag = 0; /* update partition data */ 126 static int t_flag = 0; /* test only, if f_flag is given */ 127 static char *f_flag = NULL; /* Read config info from file */ 128 static int v_flag = 0; /* Be verbose */ 129 130 struct part_type 131 { 132 unsigned char type; 133 char *name; 134 }part_types[] = 135 { 136 {0x00, "unused"} 137 ,{0x01, "Primary DOS with 12 bit FAT"} 138 ,{0x02, "XENIX / filesystem"} 139 ,{0x03, "XENIX /usr filesystem"} 140 ,{0x04, "Primary DOS with 16 bit FAT (<= 32MB)"} 141 ,{0x05, "Extended DOS"} 142 ,{0x06, "Primary 'big' DOS (> 32MB)"} 143 ,{0x07, "OS/2 HPFS, NTFS, QNX or Advanced UNIX"} 144 ,{0x08, "AIX filesystem"} 145 ,{0x09, "AIX boot partition or Coherent"} 146 ,{0x0A, "OS/2 Boot Manager or OPUS"} 147 ,{0x0B, "DOS or Windows 95 with 32 bit FAT"} 148 ,{0x0C, "DOS or Windows 95 with 32 bit FAT, LBA"} 149 ,{0x0E, "Primary 'big' DOS (> 32MB, LBA)"} 150 ,{0x0F, "Extended DOS, LBA"} 151 ,{0x10, "OPUS"} 152 ,{0x40, "VENIX 286"} 153 ,{0x50, "DM"} 154 ,{0x51, "DM"} 155 ,{0x52, "CP/M or Microport SysV/AT"} 156 ,{0x56, "GB"} 157 ,{0x61, "Speed"} 158 ,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"} 159 ,{0x64, "Novell Netware 2.xx"} 160 ,{0x65, "Novell Netware 3.xx"} 161 ,{0x75, "PCIX"} 162 ,{0x80, "Minix 1.1 ... 1.4a"} 163 ,{0x81, "Minix 1.4b ... 1.5.10"} 164 ,{0x82, "Linux swap or Solaris x86"} 165 ,{0x83, "Linux filesystem"} 166 ,{0x93, "Amoeba filesystem"} 167 ,{0x94, "Amoeba bad block table"} 168 ,{0x9F, "BSD/OS"} 169 ,{0xA5, "FreeBSD/NetBSD/386BSD"} 170 ,{0xA6, "OpenBSD"} 171 ,{0xA7, "NEXTSTEP"} 172 ,{0xA9, "NetBSD"} 173 ,{0xB7, "BSDI BSD/386 filesystem"} 174 ,{0xB8, "BSDI BSD/386 swap"} 175 ,{0xDB, "Concurrent CPM or C.DOS or CTOS"} 176 ,{0xE1, "Speed"} 177 ,{0xE3, "Speed"} 178 ,{0xE4, "Speed"} 179 ,{0xF1, "Speed"} 180 ,{0xF2, "DOS 3.3+ Secondary"} 181 ,{0xF4, "Speed"} 182 ,{0xFF, "BBT (Bad Blocks Table)"} 183 }; 184 185 static void print_s0(int which); 186 static void print_part(int i); 187 static void init_sector0(unsigned long start); 188 static void init_boot(void); 189 static void change_part(int i); 190 static void print_params(); 191 static void change_active(int which); 192 static void change_code(); 193 static void get_params_to_use(); 194 static void dos(int sec, int size, unsigned char *c, unsigned char *s, 195 unsigned char *h); 196 static int open_disk(int u_flag); 197 static ssize_t read_disk(off_t sector, void *buf); 198 static ssize_t write_disk(off_t sector, void *buf); 199 static int get_params(); 200 static int read_s0(); 201 static int write_s0(); 202 static int ok(char *str); 203 static int decimal(char *str, int *num, int deflt); 204 static char *get_type(int type); 205 static int read_config(char *config_file); 206 static void reset_boot(void); 207 static void usage(void); 208 #if 0 209 static int hex(char *str, int *num, int deflt); 210 static int string(char *str, char **ans); 211 #endif 212 213 214 int 215 main(int argc, char *argv[]) 216 { 217 int c, i; 218 219 while ((c = getopt(argc, argv, "Bab:ef:ituv1234")) != -1) 220 switch (c) { 221 case 'B': 222 B_flag = 1; 223 break; 224 case 'a': 225 a_flag = 1; 226 break; 227 case 'b': 228 b_flag = optarg; 229 break; 230 case 'e': 231 e_flag = 1; 232 break; 233 case 'f': 234 f_flag = optarg; 235 break; 236 case 'i': 237 i_flag = 1; 238 break; 239 case 't': 240 t_flag = 1; 241 break; 242 case 'u': 243 u_flag = 1; 244 break; 245 case 'v': 246 v_flag = 1; 247 break; 248 case '1': 249 case '2': 250 case '3': 251 case '4': 252 partition = c - '0'; 253 break; 254 default: 255 usage(); 256 } 257 if (f_flag || i_flag) 258 u_flag = 1; 259 if (t_flag) 260 v_flag = 1; 261 argc -= optind; 262 argv += optind; 263 264 if (argc > 0) 265 { 266 static char realname[12]; 267 268 if(strncmp(argv[0], "/dev", 4) == 0) 269 disk = argv[0]; 270 else 271 { 272 snprintf(realname, 12, "/dev/r%s", argv[0]); 273 disk = realname; 274 } 275 276 if (open_disk(u_flag) < 0) 277 err(1, "cannot open disk %s", disk); 278 } 279 else 280 { 281 int rv = 0; 282 283 for(i = 0; disks[i]; i++) 284 { 285 disk = disks[i]; 286 rv = open_disk(u_flag); 287 if(rv != -2) break; 288 } 289 if(rv < 0) 290 err(1, "cannot open any disk"); 291 } 292 293 printf("******* Working on device %s *******\n",disk); 294 295 if (e_flag) 296 { 297 struct dos_partition *partp; 298 299 read_s0(); 300 reset_boot(); 301 partp = (struct dos_partition *) (&mboot.parts[0]); 302 partp->dp_typ = DOSPTYP_386BSD; 303 partp->dp_flag = ACTIVE; 304 partp->dp_start = dos_sectors; 305 partp->dp_size = disksecs - dos_sectors; 306 307 dos(partp->dp_start, partp->dp_size, 308 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 309 dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, 310 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 311 if (v_flag) 312 print_s0(-1); 313 write_s0(); 314 exit(0); 315 } 316 if (f_flag) 317 { 318 if (read_s0() || i_flag) 319 { 320 reset_boot(); 321 } 322 323 if (!read_config(f_flag)) 324 { 325 exit(1); 326 } 327 if (v_flag) 328 { 329 print_s0(-1); 330 } 331 if (!t_flag) 332 { 333 write_s0(); 334 } 335 } 336 else 337 { 338 if(u_flag) 339 { 340 get_params_to_use(); 341 } 342 else 343 { 344 print_params(); 345 } 346 347 if (read_s0()) 348 init_sector0(1); 349 350 printf("Media sector size is %d\n", secsize); 351 printf("Warning: BIOS sector numbering starts with sector 1\n"); 352 printf("Information from DOS bootblock is:\n"); 353 if (partition == -1) 354 for (i = 1; i <= NDOSPART; i++) 355 change_part(i); 356 else 357 change_part(partition); 358 359 if (u_flag || a_flag) 360 change_active(partition); 361 362 if (B_flag) 363 change_code(); 364 365 if (u_flag || a_flag || B_flag) { 366 if (!t_flag) 367 { 368 printf("\nWe haven't changed the partition table yet. "); 369 printf("This is your last chance.\n"); 370 } 371 print_s0(-1); 372 if (!t_flag) 373 { 374 if (ok("Should we write new partition table?")) 375 write_s0(); 376 } 377 else 378 { 379 printf("\n-t flag specified -- partition table not written.\n"); 380 } 381 } 382 } 383 384 exit(0); 385 } 386 387 static void 388 usage() 389 { 390 fprintf(stderr, "%s%s", 391 "usage: fdisk [-Baeitu] [-b bootcode] [-1234] [disk]\n", 392 " fdisk -f configfile [-itv] [disk]\n"); 393 exit(1); 394 } 395 396 static void 397 print_s0(int which) 398 { 399 int i; 400 401 print_params(); 402 printf("Information from DOS bootblock is:\n"); 403 if (which == -1) 404 for (i = 1; i <= NDOSPART; i++) 405 printf("%d: ", i), print_part(i); 406 else 407 print_part(which); 408 } 409 410 static struct dos_partition mtpart = { 0 }; 411 412 static void 413 print_part(int i) 414 { 415 struct dos_partition *partp; 416 u_int64_t part_mb; 417 418 partp = ((struct dos_partition *) &mboot.parts) + i - 1; 419 420 if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) { 421 printf("<UNUSED>\n"); 422 return; 423 } 424 /* 425 * Be careful not to overflow. 426 */ 427 part_mb = partp->dp_size; 428 part_mb *= secsize; 429 part_mb /= (1024 * 1024); 430 printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ)); 431 printf(" start %lu, size %lu (%qd Meg), flag %x%s\n", 432 (u_long)partp->dp_start, 433 (u_long)partp->dp_size, 434 part_mb, 435 partp->dp_flag, 436 partp->dp_flag == ACTIVE ? " (active)" : ""); 437 printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n" 438 ,DPCYL(partp->dp_scyl, partp->dp_ssect) 439 ,DPSECT(partp->dp_ssect) 440 ,partp->dp_shd 441 ,DPCYL(partp->dp_ecyl, partp->dp_esect) 442 ,DPSECT(partp->dp_esect) 443 ,partp->dp_ehd); 444 } 445 446 447 static void 448 init_boot(void) 449 { 450 const char *fname; 451 int fd; 452 453 fname = b_flag ? b_flag : "/boot/mbr"; 454 if ((fd = open(fname, O_RDONLY)) == -1 || 455 read(fd, mboot.bootinst, DOSPARTOFF) == -1 || 456 close(fd)) 457 err(1, "%s", fname); 458 mboot.signature = BOOT_MAGIC; 459 } 460 461 462 static void 463 init_sector0(unsigned long start) 464 { 465 struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]); 466 unsigned long size = disksecs - start; 467 468 init_boot(); 469 470 partp->dp_typ = DOSPTYP_386BSD; 471 partp->dp_flag = ACTIVE; 472 partp->dp_start = start; 473 partp->dp_size = size; 474 475 dos(partp->dp_start, partp->dp_size, 476 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 477 dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, 478 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 479 } 480 481 static void 482 change_part(int i) 483 { 484 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1; 485 486 printf("The data for partition %d is:\n", i); 487 print_part(i); 488 489 if (u_flag && ok("Do you want to change it?")) { 490 int tmp; 491 492 if (i_flag) { 493 bzero((char *)partp, sizeof (struct dos_partition)); 494 if (i == 4) { 495 init_sector0(1); 496 printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n"); 497 print_part(i); 498 } 499 } 500 501 do { 502 Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp); 503 Decimal("start", partp->dp_start, tmp); 504 Decimal("size", partp->dp_size, tmp); 505 506 if (ok("Explicitly specify beg/end address ?")) 507 { 508 int tsec,tcyl,thd; 509 tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect); 510 thd = partp->dp_shd; 511 tsec = DPSECT(partp->dp_ssect); 512 Decimal("beginning cylinder", tcyl, tmp); 513 Decimal("beginning head", thd, tmp); 514 Decimal("beginning sector", tsec, tmp); 515 partp->dp_scyl = DOSCYL(tcyl); 516 partp->dp_ssect = DOSSECT(tsec,tcyl); 517 partp->dp_shd = thd; 518 519 tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect); 520 thd = partp->dp_ehd; 521 tsec = DPSECT(partp->dp_esect); 522 Decimal("ending cylinder", tcyl, tmp); 523 Decimal("ending head", thd, tmp); 524 Decimal("ending sector", tsec, tmp); 525 partp->dp_ecyl = DOSCYL(tcyl); 526 partp->dp_esect = DOSSECT(tsec,tcyl); 527 partp->dp_ehd = thd; 528 } else { 529 dos(partp->dp_start, partp->dp_size, 530 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 531 dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, 532 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 533 } 534 535 print_part(i); 536 } while (!ok("Are we happy with this entry?")); 537 } 538 } 539 540 static void 541 print_params() 542 { 543 printf("parameters extracted from in-core disklabel are:\n"); 544 printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 545 ,cyls,heads,sectors,cylsecs); 546 if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255)) 547 printf("Figures below won't work with BIOS for partitions not in cyl 1\n"); 548 printf("parameters to be used for BIOS calculations are:\n"); 549 printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 550 ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); 551 } 552 553 static void 554 change_active(int which) 555 { 556 int i; 557 int active = 4, tmp; 558 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts); 559 560 if (a_flag && which != -1) 561 active = which; 562 if (!ok("Do you want to change the active partition?")) 563 return; 564 setactive: 565 active = 4; 566 do { 567 Decimal("active partition", active, tmp); 568 if (active < 1 || 4 < active) { 569 printf("Active partition number must be in range 1-4." 570 " Try again.\n"); 571 goto setactive; 572 } 573 } while (!ok("Are you happy with this choice")); 574 for (i = 0; i < NDOSPART; i++) 575 partp[i].dp_flag = 0; 576 if (active > 0 && active <= NDOSPART) 577 partp[active-1].dp_flag = ACTIVE; 578 } 579 580 static void 581 change_code() 582 { 583 if (ok("Do you want to change the boot code?")) 584 init_boot(); 585 586 } 587 588 void 589 get_params_to_use() 590 { 591 int tmp; 592 print_params(); 593 if (ok("Do you want to change our idea of what BIOS thinks ?")) 594 { 595 do 596 { 597 Decimal("BIOS's idea of #cylinders", dos_cyls, tmp); 598 Decimal("BIOS's idea of #heads", dos_heads, tmp); 599 Decimal("BIOS's idea of #sectors", dos_sectors, tmp); 600 dos_cylsecs = dos_heads * dos_sectors; 601 print_params(); 602 } 603 while(!ok("Are you happy with this choice")); 604 } 605 } 606 607 608 /***********************************************\ 609 * Change real numbers into strange dos numbers * 610 \***********************************************/ 611 static void 612 dos(sec, size, c, s, h) 613 int sec, size; 614 unsigned char *c, *s, *h; 615 { 616 int cy; 617 int hd; 618 619 if (sec == 0 && size == 0) { 620 *s = *c = *h = 0; 621 return; 622 } 623 624 cy = sec / ( dos_cylsecs ); 625 sec = sec - cy * ( dos_cylsecs ); 626 627 hd = sec / dos_sectors; 628 sec = (sec - hd * dos_sectors) + 1; 629 630 *h = hd; 631 *c = cy & 0xff; 632 *s = (sec & 0x3f) | ( (cy & 0x300) >> 2); 633 } 634 635 int fd; 636 637 /* Getting device status */ 638 639 static int 640 open_disk(int u_flag) 641 { 642 struct stat st; 643 644 if (stat(disk, &st) == -1) { 645 warnx("can't get file status of %s", disk); 646 return -1; 647 } 648 if ( !(st.st_mode & S_IFCHR) ) 649 warnx("device %s is not character special", disk); 650 if ((fd = open(disk, 651 a_flag || e_flag || B_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) { 652 if(errno == ENXIO) 653 return -2; 654 warnx("can't open device %s", disk); 655 return -1; 656 } 657 if (get_params(0) == -1) { 658 warnx("can't get disk parameters on %s", disk); 659 return -1; 660 } 661 return fd; 662 } 663 664 static ssize_t 665 read_disk(off_t sector, void *buf) 666 { 667 lseek(fd,(sector * 512), 0); 668 if( secsize == 0 ) 669 for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 ) 670 { 671 /* try the read */ 672 int size = read(fd, buf, secsize); 673 if( size == secsize ) 674 /* it worked so return */ 675 return secsize; 676 } 677 else 678 return read( fd, buf, secsize ); 679 680 /* we failed to read at any of the sizes */ 681 return -1; 682 } 683 684 static ssize_t 685 write_disk(off_t sector, void *buf) 686 { 687 lseek(fd,(sector * 512), 0); 688 /* write out in the size that the read_disk found worked */ 689 return write(fd, buf, secsize); 690 } 691 692 static int 693 get_params() 694 { 695 696 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 697 warnx("can't get disk parameters on %s; supplying dummy ones", disk); 698 dos_cyls = cyls = 1; 699 dos_heads = heads = 1; 700 dos_sectors = sectors = 1; 701 dos_cylsecs = cylsecs = heads * sectors; 702 disksecs = cyls * heads * sectors; 703 return disksecs; 704 } 705 706 dos_cyls = cyls = disklabel.d_ncylinders; 707 dos_heads = heads = disklabel.d_ntracks; 708 dos_sectors = sectors = disklabel.d_nsectors; 709 dos_cylsecs = cylsecs = heads * sectors; 710 disksecs = cyls * heads * sectors; 711 712 return (disksecs); 713 } 714 715 716 static int 717 read_s0() 718 { 719 if (read_disk(0, (char *) mboot.bootinst) == -1) { 720 warnx("can't read fdisk partition table"); 721 return -1; 722 } 723 if (mboot.signature != BOOT_MAGIC) { 724 warnx("invalid fdisk partition table found"); 725 /* So should we initialize things */ 726 return -1; 727 } 728 return 0; 729 } 730 731 static int 732 write_s0() 733 { 734 #ifdef NOT_NOW 735 int flag; 736 #endif 737 if (iotest) { 738 print_s0(-1); 739 return 0; 740 } 741 /* 742 * write enable label sector before write (if necessary), 743 * disable after writing. 744 * needed if the disklabel protected area also protects 745 * sector 0. (e.g. empty disk) 746 */ 747 #ifdef NOT_NOW 748 flag = 1; 749 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 750 warn("ioctl DIOCWLABEL"); 751 #endif 752 if (write_disk(0, (char *) mboot.bootinst) == -1) { 753 warn("can't write fdisk partition table"); 754 return -1; 755 #ifdef NOT_NOW 756 flag = 0; 757 (void) ioctl(fd, DIOCWLABEL, &flag); 758 #endif 759 } 760 return(0); 761 } 762 763 764 static int 765 ok(str) 766 char *str; 767 { 768 printf("%s [n] ", str); 769 fgets(lbuf, LBUF, stdin); 770 lbuf[strlen(lbuf)-1] = 0; 771 772 if (*lbuf && 773 (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || 774 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) 775 return 1; 776 else 777 return 0; 778 } 779 780 static int 781 decimal(char *str, int *num, int deflt) 782 { 783 int acc = 0, c; 784 char *cp; 785 786 while (1) { 787 printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); 788 fgets(lbuf, LBUF, stdin); 789 lbuf[strlen(lbuf)-1] = 0; 790 791 if (!*lbuf) 792 return 0; 793 794 cp = lbuf; 795 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 796 if (!c) 797 return 0; 798 while ((c = *cp++)) { 799 if (c <= '9' && c >= '0') 800 acc = acc * 10 + c - '0'; 801 else 802 break; 803 } 804 if (c == ' ' || c == '\t') 805 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 806 if (!c) { 807 *num = acc; 808 return 1; 809 } else 810 printf("%s is an invalid decimal number. Try again.\n", 811 lbuf); 812 } 813 814 } 815 816 #if 0 817 static int 818 hex(char *str, int *num, int deflt) 819 { 820 int acc = 0, c; 821 char *cp; 822 823 while (1) { 824 printf("Supply a hex value for \"%s\" [%x] ", str, deflt); 825 fgets(lbuf, LBUF, stdin); 826 lbuf[strlen(lbuf)-1] = 0; 827 828 if (!*lbuf) 829 return 0; 830 831 cp = lbuf; 832 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 833 if (!c) 834 return 0; 835 while ((c = *cp++)) { 836 if (c <= '9' && c >= '0') 837 acc = (acc << 4) + c - '0'; 838 else if (c <= 'f' && c >= 'a') 839 acc = (acc << 4) + c - 'a' + 10; 840 else if (c <= 'F' && c >= 'A') 841 acc = (acc << 4) + c - 'A' + 10; 842 else 843 break; 844 } 845 if (c == ' ' || c == '\t') 846 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 847 if (!c) { 848 *num = acc; 849 return 1; 850 } else 851 printf("%s is an invalid hex number. Try again.\n", 852 lbuf); 853 } 854 855 } 856 857 static int 858 string(char *str, char **ans) 859 { 860 int c; 861 char *cp = lbuf; 862 863 while (1) { 864 printf("Supply a string value for \"%s\" [%s] ", str, *ans); 865 fgets(lbuf, LBUF, stdin); 866 lbuf[strlen(lbuf)-1] = 0; 867 868 if (!*lbuf) 869 return 0; 870 871 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 872 if (c == '"') { 873 c = *++cp; 874 *ans = cp; 875 while ((c = *cp) && c != '"') cp++; 876 } else { 877 *ans = cp; 878 while ((c = *cp) && c != ' ' && c != '\t') cp++; 879 } 880 881 if (c) 882 *cp = 0; 883 return 1; 884 } 885 } 886 #endif 887 888 static char * 889 get_type(int type) 890 { 891 int numentries = (sizeof(part_types)/sizeof(struct part_type)); 892 int counter = 0; 893 struct part_type *ptr = part_types; 894 895 896 while(counter < numentries) 897 { 898 if(ptr->type == type) 899 { 900 return(ptr->name); 901 } 902 ptr++; 903 counter++; 904 } 905 return("unknown"); 906 } 907 908 909 static void 910 parse_config_line(line, command) 911 char *line; 912 CMD *command; 913 { 914 char *cp, *end; 915 916 cp = line; 917 while (1) /* dirty trick used to insure one exit point for this 918 function */ 919 { 920 memset(command, 0, sizeof(*command)); 921 922 while (isspace(*cp)) ++cp; 923 if (*cp == '\0' || *cp == '#') 924 { 925 break; 926 } 927 command->cmd = *cp++; 928 929 /* 930 * Parse args 931 */ 932 while (1) 933 { 934 while (isspace(*cp)) ++cp; 935 if (*cp == '#') 936 { 937 break; /* found comment */ 938 } 939 if (isalpha(*cp)) 940 { 941 command->args[command->n_args].argtype = *cp++; 942 } 943 if (!isdigit(*cp)) 944 { 945 break; /* assume end of line */ 946 } 947 end = NULL; 948 command->args[command->n_args].arg_val = strtol(cp, &end, 0); 949 if (cp == end) 950 { 951 break; /* couldn't parse number */ 952 } 953 cp = end; 954 command->n_args++; 955 } 956 break; 957 } 958 } 959 960 961 static int 962 process_geometry(command) 963 CMD *command; 964 { 965 int status = 1, i; 966 967 while (1) 968 { 969 geom_processed = 1; 970 if (part_processed) 971 { 972 warnx( 973 "ERROR line %d: the geometry specification line must occur before\n\ 974 all partition specifications", 975 current_line_number); 976 status = 0; 977 break; 978 } 979 if (command->n_args != 3) 980 { 981 warnx("ERROR line %d: incorrect number of geometry args", 982 current_line_number); 983 status = 0; 984 break; 985 } 986 dos_cyls = -1; 987 dos_heads = -1; 988 dos_sectors = -1; 989 for (i = 0; i < 3; ++i) 990 { 991 switch (command->args[i].argtype) 992 { 993 case 'c': 994 dos_cyls = command->args[i].arg_val; 995 break; 996 case 'h': 997 dos_heads = command->args[i].arg_val; 998 break; 999 case 's': 1000 dos_sectors = command->args[i].arg_val; 1001 break; 1002 default: 1003 warnx( 1004 "ERROR line %d: unknown geometry arg type: '%c' (0x%02x)", 1005 current_line_number, command->args[i].argtype, 1006 command->args[i].argtype); 1007 status = 0; 1008 break; 1009 } 1010 } 1011 if (status == 0) 1012 { 1013 break; 1014 } 1015 1016 dos_cylsecs = dos_heads * dos_sectors; 1017 1018 /* 1019 * Do sanity checks on parameter values 1020 */ 1021 if (dos_cyls < 0) 1022 { 1023 warnx("ERROR line %d: number of cylinders not specified", 1024 current_line_number); 1025 status = 0; 1026 } 1027 if (dos_cyls == 0 || dos_cyls > 1024) 1028 { 1029 warnx( 1030 "WARNING line %d: number of cylinders (%d) may be out-of-range\n\ 1031 (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\ 1032 is dedicated to FreeBSD)", 1033 current_line_number, dos_cyls); 1034 } 1035 1036 if (dos_heads < 0) 1037 { 1038 warnx("ERROR line %d: number of heads not specified", 1039 current_line_number); 1040 status = 0; 1041 } 1042 else if (dos_heads < 1 || dos_heads > 256) 1043 { 1044 warnx("ERROR line %d: number of heads must be within (1-256)", 1045 current_line_number); 1046 status = 0; 1047 } 1048 1049 if (dos_sectors < 0) 1050 { 1051 warnx("ERROR line %d: number of sectors not specified", 1052 current_line_number); 1053 status = 0; 1054 } 1055 else if (dos_sectors < 1 || dos_sectors > 63) 1056 { 1057 warnx("ERROR line %d: number of sectors must be within (1-63)", 1058 current_line_number); 1059 status = 0; 1060 } 1061 1062 break; 1063 } 1064 return (status); 1065 } 1066 1067 1068 static int 1069 process_partition(command) 1070 CMD *command; 1071 { 1072 int status = 0, partition; 1073 unsigned long chunks, adj_size, max_end; 1074 struct dos_partition *partp; 1075 1076 while (1) 1077 { 1078 part_processed = 1; 1079 if (command->n_args != 4) 1080 { 1081 warnx("ERROR line %d: incorrect number of partition args", 1082 current_line_number); 1083 break; 1084 } 1085 partition = command->args[0].arg_val; 1086 if (partition < 1 || partition > 4) 1087 { 1088 warnx("ERROR line %d: invalid partition number %d", 1089 current_line_number, partition); 1090 break; 1091 } 1092 partp = ((struct dos_partition *) &mboot.parts) + partition - 1; 1093 bzero((char *)partp, sizeof (struct dos_partition)); 1094 partp->dp_typ = command->args[1].arg_val; 1095 partp->dp_start = command->args[2].arg_val; 1096 partp->dp_size = command->args[3].arg_val; 1097 max_end = partp->dp_start + partp->dp_size; 1098 1099 if (partp->dp_typ == 0) 1100 { 1101 /* 1102 * Get out, the partition is marked as unused. 1103 */ 1104 /* 1105 * Insure that it's unused. 1106 */ 1107 bzero((char *)partp, sizeof (struct dos_partition)); 1108 status = 1; 1109 break; 1110 } 1111 1112 /* 1113 * Adjust start upwards, if necessary, to fall on an head boundary. 1114 */ 1115 if (partp->dp_start % dos_sectors != 0) 1116 { 1117 adj_size = 1118 (partp->dp_start / dos_sectors + 1) * dos_sectors; 1119 if (adj_size > max_end) 1120 { 1121 /* 1122 * Can't go past end of partition 1123 */ 1124 warnx( 1125 "ERROR line %d: unable to adjust start of partition %d to fall on\n\ 1126 a cylinder boundary", 1127 current_line_number, partition); 1128 break; 1129 } 1130 warnx( 1131 "WARNING: adjusting start offset of partition '%d' from %lu\n\ 1132 to %lu, to round to an head boundary", 1133 partition, (u_long)partp->dp_start, adj_size); 1134 partp->dp_start = adj_size; 1135 } 1136 1137 /* 1138 * Adjust size downwards, if necessary, to fall on a cylinder 1139 * boundary. 1140 */ 1141 chunks = 1142 ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; 1143 adj_size = chunks - partp->dp_start; 1144 if (adj_size != partp->dp_size) 1145 { 1146 warnx( 1147 "WARNING: adjusting size of partition '%d' from %lu to %lu,\n\ 1148 to round to a cylinder boundary", 1149 partition, (u_long)partp->dp_size, adj_size); 1150 if (chunks > 0) 1151 { 1152 partp->dp_size = adj_size; 1153 } 1154 else 1155 { 1156 partp->dp_size = 0; 1157 } 1158 } 1159 if (partp->dp_size < 1) 1160 { 1161 warnx("ERROR line %d: size for partition '%d' is zero", 1162 current_line_number, partition); 1163 break; 1164 } 1165 1166 dos(partp->dp_start, partp->dp_size, 1167 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 1168 dos(partp->dp_start+partp->dp_size - 1, partp->dp_size, 1169 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 1170 status = 1; 1171 break; 1172 } 1173 return (status); 1174 } 1175 1176 1177 static int 1178 process_active(command) 1179 CMD *command; 1180 { 1181 int status = 0, partition, i; 1182 struct dos_partition *partp; 1183 1184 while (1) 1185 { 1186 active_processed = 1; 1187 if (command->n_args != 1) 1188 { 1189 warnx("ERROR line %d: incorrect number of active args", 1190 current_line_number); 1191 status = 0; 1192 break; 1193 } 1194 partition = command->args[0].arg_val; 1195 if (partition < 1 || partition > 4) 1196 { 1197 warnx("ERROR line %d: invalid partition number %d", 1198 current_line_number, partition); 1199 break; 1200 } 1201 /* 1202 * Reset active partition 1203 */ 1204 partp = ((struct dos_partition *) &mboot.parts); 1205 for (i = 0; i < NDOSPART; i++) 1206 partp[i].dp_flag = 0; 1207 partp[partition-1].dp_flag = ACTIVE; 1208 1209 status = 1; 1210 break; 1211 } 1212 return (status); 1213 } 1214 1215 1216 static int 1217 process_line(line) 1218 char *line; 1219 { 1220 CMD command; 1221 int status = 1; 1222 1223 while (1) 1224 { 1225 parse_config_line(line, &command); 1226 switch (command.cmd) 1227 { 1228 case 0: 1229 /* 1230 * Comment or blank line 1231 */ 1232 break; 1233 case 'g': 1234 /* 1235 * Set geometry 1236 */ 1237 status = process_geometry(&command); 1238 break; 1239 case 'p': 1240 status = process_partition(&command); 1241 break; 1242 case 'a': 1243 status = process_active(&command); 1244 break; 1245 default: 1246 status = 0; 1247 break; 1248 } 1249 break; 1250 } 1251 return (status); 1252 } 1253 1254 1255 static int 1256 read_config(config_file) 1257 char *config_file; 1258 { 1259 FILE *fp = NULL; 1260 int status = 1; 1261 char buf[1010]; 1262 1263 while (1) /* dirty trick used to insure one exit point for this 1264 function */ 1265 { 1266 if (strcmp(config_file, "-") != 0) 1267 { 1268 /* 1269 * We're not reading from stdin 1270 */ 1271 if ((fp = fopen(config_file, "r")) == NULL) 1272 { 1273 status = 0; 1274 break; 1275 } 1276 } 1277 else 1278 { 1279 fp = stdin; 1280 } 1281 current_line_number = 0; 1282 while (!feof(fp)) 1283 { 1284 if (fgets(buf, sizeof(buf), fp) == NULL) 1285 { 1286 break; 1287 } 1288 ++current_line_number; 1289 status = process_line(buf); 1290 if (status == 0) 1291 { 1292 break; 1293 } 1294 } 1295 break; 1296 } 1297 if (fp) 1298 { 1299 /* 1300 * It doesn't matter if we're reading from stdin, as we've reached EOF 1301 */ 1302 fclose(fp); 1303 } 1304 return (status); 1305 } 1306 1307 1308 static void 1309 reset_boot(void) 1310 { 1311 int i; 1312 struct dos_partition *partp; 1313 1314 init_boot(); 1315 for (i = 0; i < 4; ++i) 1316 { 1317 partp = ((struct dos_partition *) &mboot.parts) + i; 1318 bzero((char *)partp, sizeof (struct dos_partition)); 1319 } 1320 } 1321