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/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 int flag; 735 if (iotest) { 736 print_s0(-1); 737 return 0; 738 } 739 /* 740 * write enable label sector before write (if necessary), 741 * disable after writing. 742 * needed if the disklabel protected area also protects 743 * sector 0. (e.g. empty disk) 744 */ 745 #ifdef NOT_NOW 746 flag = 1; 747 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 748 warn("ioctl DIOCWLABEL"); 749 #endif 750 if (write_disk(0, (char *) mboot.bootinst) == -1) { 751 warn("can't write fdisk partition table"); 752 return -1; 753 #ifdef NOT_NOW 754 flag = 0; 755 (void) ioctl(fd, DIOCWLABEL, &flag); 756 #endif 757 } 758 return(0); 759 } 760 761 762 static int 763 ok(str) 764 char *str; 765 { 766 printf("%s [n] ", str); 767 fgets(lbuf, LBUF, stdin); 768 lbuf[strlen(lbuf)-1] = 0; 769 770 if (*lbuf && 771 (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || 772 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) 773 return 1; 774 else 775 return 0; 776 } 777 778 static int 779 decimal(char *str, int *num, int deflt) 780 { 781 int acc = 0, c; 782 char *cp; 783 784 while (1) { 785 printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); 786 fgets(lbuf, LBUF, stdin); 787 lbuf[strlen(lbuf)-1] = 0; 788 789 if (!*lbuf) 790 return 0; 791 792 cp = lbuf; 793 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 794 if (!c) 795 return 0; 796 while ((c = *cp++)) { 797 if (c <= '9' && c >= '0') 798 acc = acc * 10 + c - '0'; 799 else 800 break; 801 } 802 if (c == ' ' || c == '\t') 803 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 804 if (!c) { 805 *num = acc; 806 return 1; 807 } else 808 printf("%s is an invalid decimal number. Try again.\n", 809 lbuf); 810 } 811 812 } 813 814 #if 0 815 static int 816 hex(char *str, int *num, int deflt) 817 { 818 int acc = 0, c; 819 char *cp; 820 821 while (1) { 822 printf("Supply a hex value for \"%s\" [%x] ", str, deflt); 823 fgets(lbuf, LBUF, stdin); 824 lbuf[strlen(lbuf)-1] = 0; 825 826 if (!*lbuf) 827 return 0; 828 829 cp = lbuf; 830 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 831 if (!c) 832 return 0; 833 while ((c = *cp++)) { 834 if (c <= '9' && c >= '0') 835 acc = (acc << 4) + c - '0'; 836 else if (c <= 'f' && c >= 'a') 837 acc = (acc << 4) + c - 'a' + 10; 838 else if (c <= 'F' && c >= 'A') 839 acc = (acc << 4) + c - 'A' + 10; 840 else 841 break; 842 } 843 if (c == ' ' || c == '\t') 844 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 845 if (!c) { 846 *num = acc; 847 return 1; 848 } else 849 printf("%s is an invalid hex number. Try again.\n", 850 lbuf); 851 } 852 853 } 854 855 static int 856 string(char *str, char **ans) 857 { 858 int c; 859 char *cp = lbuf; 860 861 while (1) { 862 printf("Supply a string value for \"%s\" [%s] ", str, *ans); 863 fgets(lbuf, LBUF, stdin); 864 lbuf[strlen(lbuf)-1] = 0; 865 866 if (!*lbuf) 867 return 0; 868 869 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 870 if (c == '"') { 871 c = *++cp; 872 *ans = cp; 873 while ((c = *cp) && c != '"') cp++; 874 } else { 875 *ans = cp; 876 while ((c = *cp) && c != ' ' && c != '\t') cp++; 877 } 878 879 if (c) 880 *cp = 0; 881 return 1; 882 } 883 } 884 #endif 885 886 static char * 887 get_type(int type) 888 { 889 int numentries = (sizeof(part_types)/sizeof(struct part_type)); 890 int counter = 0; 891 struct part_type *ptr = part_types; 892 893 894 while(counter < numentries) 895 { 896 if(ptr->type == type) 897 { 898 return(ptr->name); 899 } 900 ptr++; 901 counter++; 902 } 903 return("unknown"); 904 } 905 906 907 static void 908 parse_config_line(line, command) 909 char *line; 910 CMD *command; 911 { 912 char *cp, *end; 913 914 cp = line; 915 while (1) /* dirty trick used to insure one exit point for this 916 function */ 917 { 918 memset(command, 0, sizeof(*command)); 919 920 while (isspace(*cp)) ++cp; 921 if (*cp == '\0' || *cp == '#') 922 { 923 break; 924 } 925 command->cmd = *cp++; 926 927 /* 928 * Parse args 929 */ 930 while (1) 931 { 932 while (isspace(*cp)) ++cp; 933 if (*cp == '#') 934 { 935 break; /* found comment */ 936 } 937 if (isalpha(*cp)) 938 { 939 command->args[command->n_args].argtype = *cp++; 940 } 941 if (!isdigit(*cp)) 942 { 943 break; /* assume end of line */ 944 } 945 end = NULL; 946 command->args[command->n_args].arg_val = strtol(cp, &end, 0); 947 if (cp == end) 948 { 949 break; /* couldn't parse number */ 950 } 951 cp = end; 952 command->n_args++; 953 } 954 break; 955 } 956 } 957 958 959 static int 960 process_geometry(command) 961 CMD *command; 962 { 963 int status = 1, i; 964 965 while (1) 966 { 967 geom_processed = 1; 968 if (part_processed) 969 { 970 warnx( 971 "ERROR line %d: the geometry specification line must occur before\n\ 972 all partition specifications", 973 current_line_number); 974 status = 0; 975 break; 976 } 977 if (command->n_args != 3) 978 { 979 warnx("ERROR line %d: incorrect number of geometry args", 980 current_line_number); 981 status = 0; 982 break; 983 } 984 dos_cyls = -1; 985 dos_heads = -1; 986 dos_sectors = -1; 987 for (i = 0; i < 3; ++i) 988 { 989 switch (command->args[i].argtype) 990 { 991 case 'c': 992 dos_cyls = command->args[i].arg_val; 993 break; 994 case 'h': 995 dos_heads = command->args[i].arg_val; 996 break; 997 case 's': 998 dos_sectors = command->args[i].arg_val; 999 break; 1000 default: 1001 warnx( 1002 "ERROR line %d: unknown geometry arg type: '%c' (0x%02x)", 1003 current_line_number, command->args[i].argtype, 1004 command->args[i].argtype); 1005 status = 0; 1006 break; 1007 } 1008 } 1009 if (status == 0) 1010 { 1011 break; 1012 } 1013 1014 dos_cylsecs = dos_heads * dos_sectors; 1015 1016 /* 1017 * Do sanity checks on parameter values 1018 */ 1019 if (dos_cyls < 0) 1020 { 1021 warnx("ERROR line %d: number of cylinders not specified", 1022 current_line_number); 1023 status = 0; 1024 } 1025 if (dos_cyls == 0 || dos_cyls > 1024) 1026 { 1027 warnx( 1028 "WARNING line %d: number of cylinders (%d) may be out-of-range\n\ 1029 (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\ 1030 is dedicated to FreeBSD)", 1031 current_line_number, dos_cyls); 1032 } 1033 1034 if (dos_heads < 0) 1035 { 1036 warnx("ERROR line %d: number of heads not specified", 1037 current_line_number); 1038 status = 0; 1039 } 1040 else if (dos_heads < 1 || dos_heads > 256) 1041 { 1042 warnx("ERROR line %d: number of heads must be within (1-256)", 1043 current_line_number); 1044 status = 0; 1045 } 1046 1047 if (dos_sectors < 0) 1048 { 1049 warnx("ERROR line %d: number of sectors not specified", 1050 current_line_number); 1051 status = 0; 1052 } 1053 else if (dos_sectors < 1 || dos_sectors > 63) 1054 { 1055 warnx("ERROR line %d: number of sectors must be within (1-63)", 1056 current_line_number); 1057 status = 0; 1058 } 1059 1060 break; 1061 } 1062 return (status); 1063 } 1064 1065 1066 static int 1067 process_partition(command) 1068 CMD *command; 1069 { 1070 int status = 0, partition; 1071 unsigned long chunks, adj_size, max_end; 1072 struct dos_partition *partp; 1073 1074 while (1) 1075 { 1076 part_processed = 1; 1077 if (command->n_args != 4) 1078 { 1079 warnx("ERROR line %d: incorrect number of partition args", 1080 current_line_number); 1081 break; 1082 } 1083 partition = command->args[0].arg_val; 1084 if (partition < 1 || partition > 4) 1085 { 1086 warnx("ERROR line %d: invalid partition number %d", 1087 current_line_number, partition); 1088 break; 1089 } 1090 partp = ((struct dos_partition *) &mboot.parts) + partition - 1; 1091 bzero((char *)partp, sizeof (struct dos_partition)); 1092 partp->dp_typ = command->args[1].arg_val; 1093 partp->dp_start = command->args[2].arg_val; 1094 partp->dp_size = command->args[3].arg_val; 1095 max_end = partp->dp_start + partp->dp_size; 1096 1097 if (partp->dp_typ == 0) 1098 { 1099 /* 1100 * Get out, the partition is marked as unused. 1101 */ 1102 /* 1103 * Insure that it's unused. 1104 */ 1105 bzero((char *)partp, sizeof (struct dos_partition)); 1106 status = 1; 1107 break; 1108 } 1109 1110 /* 1111 * Adjust start upwards, if necessary, to fall on an head boundary. 1112 */ 1113 if (partp->dp_start % dos_sectors != 0) 1114 { 1115 adj_size = 1116 (partp->dp_start / dos_sectors + 1) * dos_sectors; 1117 if (adj_size > max_end) 1118 { 1119 /* 1120 * Can't go past end of partition 1121 */ 1122 warnx( 1123 "ERROR line %d: unable to adjust start of partition %d to fall on\n\ 1124 a cylinder boundary", 1125 current_line_number, partition); 1126 break; 1127 } 1128 warnx( 1129 "WARNING: adjusting start offset of partition '%d' from %lu\n\ 1130 to %lu, to round to an head boundary", 1131 partition, (u_long)partp->dp_start, adj_size); 1132 partp->dp_start = adj_size; 1133 } 1134 1135 /* 1136 * Adjust size downwards, if necessary, to fall on a cylinder 1137 * boundary. 1138 */ 1139 chunks = 1140 ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; 1141 adj_size = chunks - partp->dp_start; 1142 if (adj_size != partp->dp_size) 1143 { 1144 warnx( 1145 "WARNING: adjusting size of partition '%d' from %lu to %lu,\n\ 1146 to round to a cylinder boundary", 1147 partition, (u_long)partp->dp_size, adj_size); 1148 if (chunks > 0) 1149 { 1150 partp->dp_size = adj_size; 1151 } 1152 else 1153 { 1154 partp->dp_size = 0; 1155 } 1156 } 1157 if (partp->dp_size < 1) 1158 { 1159 warnx("ERROR line %d: size for partition '%d' is zero", 1160 current_line_number, partition); 1161 break; 1162 } 1163 1164 dos(partp->dp_start, partp->dp_size, 1165 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 1166 dos(partp->dp_start+partp->dp_size - 1, partp->dp_size, 1167 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 1168 status = 1; 1169 break; 1170 } 1171 return (status); 1172 } 1173 1174 1175 static int 1176 process_active(command) 1177 CMD *command; 1178 { 1179 int status = 0, partition, i; 1180 struct dos_partition *partp; 1181 1182 while (1) 1183 { 1184 active_processed = 1; 1185 if (command->n_args != 1) 1186 { 1187 warnx("ERROR line %d: incorrect number of active args", 1188 current_line_number); 1189 status = 0; 1190 break; 1191 } 1192 partition = command->args[0].arg_val; 1193 if (partition < 1 || partition > 4) 1194 { 1195 warnx("ERROR line %d: invalid partition number %d", 1196 current_line_number, partition); 1197 break; 1198 } 1199 /* 1200 * Reset active partition 1201 */ 1202 partp = ((struct dos_partition *) &mboot.parts); 1203 for (i = 0; i < NDOSPART; i++) 1204 partp[i].dp_flag = 0; 1205 partp[partition-1].dp_flag = ACTIVE; 1206 1207 status = 1; 1208 break; 1209 } 1210 return (status); 1211 } 1212 1213 1214 static int 1215 process_line(line) 1216 char *line; 1217 { 1218 CMD command; 1219 int status = 1; 1220 1221 while (1) 1222 { 1223 parse_config_line(line, &command); 1224 switch (command.cmd) 1225 { 1226 case 0: 1227 /* 1228 * Comment or blank line 1229 */ 1230 break; 1231 case 'g': 1232 /* 1233 * Set geometry 1234 */ 1235 status = process_geometry(&command); 1236 break; 1237 case 'p': 1238 status = process_partition(&command); 1239 break; 1240 case 'a': 1241 status = process_active(&command); 1242 break; 1243 default: 1244 status = 0; 1245 break; 1246 } 1247 break; 1248 } 1249 return (status); 1250 } 1251 1252 1253 static int 1254 read_config(config_file) 1255 char *config_file; 1256 { 1257 FILE *fp = NULL; 1258 int status = 1; 1259 char buf[1010]; 1260 1261 while (1) /* dirty trick used to insure one exit point for this 1262 function */ 1263 { 1264 if (strcmp(config_file, "-") != 0) 1265 { 1266 /* 1267 * We're not reading from stdin 1268 */ 1269 if ((fp = fopen(config_file, "r")) == NULL) 1270 { 1271 status = 0; 1272 break; 1273 } 1274 } 1275 else 1276 { 1277 fp = stdin; 1278 } 1279 current_line_number = 0; 1280 while (!feof(fp)) 1281 { 1282 if (fgets(buf, sizeof(buf), fp) == NULL) 1283 { 1284 break; 1285 } 1286 ++current_line_number; 1287 status = process_line(buf); 1288 if (status == 0) 1289 { 1290 break; 1291 } 1292 } 1293 break; 1294 } 1295 if (fp) 1296 { 1297 /* 1298 * It doesn't matter if we're reading from stdin, as we've reached EOF 1299 */ 1300 fclose(fp); 1301 } 1302 return (status); 1303 } 1304 1305 1306 static void 1307 reset_boot(void) 1308 { 1309 int i; 1310 struct dos_partition *partp; 1311 1312 init_boot(); 1313 for (i = 0; i < 4; ++i) 1314 { 1315 partp = ((struct dos_partition *) &mboot.parts) + i; 1316 bzero((char *)partp, sizeof (struct dos_partition)); 1317 } 1318 } 1319