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#include <sys/cdefs.h> 28__FBSDID("$FreeBSD$"); 29 30#include <sys/disk.h> 31#include <sys/disklabel.h> 32#include <sys/diskpc98.h> 33#include <sys/param.h> 34#include <sys/stat.h> 35#include <sys/mount.h> 36#include <ctype.h> 37#include <fcntl.h> 38#include <err.h> 39#include <errno.h> 40#include <libgeom.h> 41#include <paths.h> 42#include <regex.h> 43#include <stdint.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <string.h> 47#include <unistd.h> 48 49int iotest; 50 51#define LBUF 100 52static char lbuf[LBUF]; 53 54/* 55 * 56 * Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992 57 * 58 * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University 59 * Copyright (c) 1989 Robert. V. Baron 60 * Created. 61 */ 62 63#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp 64#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); } 65 66#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs) 67 68#define MAX_SEC_SIZE 2048 /* maximum section size that is supported */ 69#define MIN_SEC_SIZE 512 /* the sector size to start sensing at */ 70static int secsize = 0; /* the sensed sector size */ 71 72static char *disk; 73 74static int cyls, sectors, heads, cylsecs, disksecs; 75 76struct mboot { 77 unsigned char padding[2]; /* force the longs to be long aligned */ 78 unsigned char bootinst[510]; 79 unsigned short int signature; 80 struct pc98_partition parts[8]; 81 unsigned char large_sector_overflow[MAX_SEC_SIZE-MIN_SEC_SIZE]; 82}; 83 84static struct mboot mboot; 85static int fd; 86 87static uint dos_cyls; 88static uint dos_heads; 89static uint dos_sectors; 90static uint dos_cylsecs; 91 92#define MAX_ARGS 10 93 94typedef struct cmd { 95 char cmd; 96 int n_args; 97 struct arg { 98 char argtype; 99 int arg_val; 100 } args[MAX_ARGS]; 101} CMD; 102 103static int B_flag = 0; /* replace boot code */ 104static int I_flag = 0; /* Inizialize disk to defaults */ 105static int a_flag = 0; /* set active partition */ 106static int i_flag = 0; /* replace partition data */ 107static int u_flag = 0; /* update partition data */ 108static int s_flag = 0; /* Print a summary and exit */ 109static int t_flag = 0; /* test only */ 110static char *f_flag = NULL; /* Read config info from file */ 111static int v_flag = 0; /* Be verbose */ 112 113static struct part_type 114{ 115 unsigned char type; 116 const char *name; 117} part_types[] = { 118 {0x00, "unused"} 119 ,{0x01, "Primary DOS with 12 bit FAT"} 120 ,{0x11, "MSDOS"} 121 ,{0x20, "MSDOS"} 122 ,{0x21, "MSDOS"} 123 ,{0x22, "MSDOS"} 124 ,{0x23, "MSDOS"} 125 ,{0x02, "XENIX / file system"} 126 ,{0x03, "XENIX /usr file system"} 127 ,{0x04, "PC-UX"} 128 ,{0x05, "Extended DOS"} 129 ,{0x06, "Primary 'big' DOS (> 32MB)"} 130 ,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"} 131 ,{0x08, "AIX file system"} 132 ,{0x09, "AIX boot partition or Coherent"} 133 ,{0x0A, "OS/2 Boot Manager or OPUS"} 134 ,{0x10, "OPUS"} 135 ,{0x14, "FreeBSD/NetBSD/386BSD"} 136 ,{0x94, "FreeBSD/NetBSD/386BSD"} 137 ,{0x40, "VENIX 286"} 138 ,{0x50, "DM"} 139 ,{0x51, "DM"} 140 ,{0x52, "CP/M or Microport SysV/AT"} 141 ,{0x56, "GB"} 142 ,{0x61, "Speed"} 143 ,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"} 144 ,{0x64, "Novell Netware 2.xx"} 145 ,{0x65, "Novell Netware 3.xx"} 146 ,{0x75, "PCIX"} 147 ,{0x40, "Minix"} 148}; 149 150static void print_s0(int which); 151static void print_part(int i); 152static void init_sector0(unsigned long start); 153static void init_boot(void); 154static void change_part(int i, int force); 155static void print_params(void); 156static void change_active(int which); 157static void change_code(void); 158static void get_params_to_use(void); 159static char *get_rootdisk(void); 160static void dos(u_int32_t start, u_int32_t size, struct pc98_partition *partp); 161static int open_disk(int flag); 162static ssize_t read_disk(off_t sector, void *buf); 163static int write_disk(off_t sector, void *buf); 164static int get_params(void); 165static int read_s0(void); 166static int write_s0(void); 167static int ok(const char *str); 168static int decimal(const char *str, int *num, int deflt); 169static const char *get_type(int type); 170static void usage(void); 171static int string(const char *str, char **ans); 172static void reset_boot(void); 173 174int 175main(int argc, char *argv[]) 176{ 177 struct stat sb; 178 int c, i; 179 int partition = -1; 180 struct pc98_partition *partp; 181 182 while ((c = getopt(argc, argv, "BIa:f:istuv12345678")) != -1) 183 switch (c) { 184 case 'B': 185 B_flag = 1; 186 break; 187 case 'I': 188 I_flag = 1; 189 break; 190 case 'a': 191 a_flag = 1; 192 break; 193 case 'f': 194 f_flag = optarg; 195 break; 196 case 'i': 197 i_flag = 1; 198 break; 199 case 's': 200 s_flag = 1; 201 break; 202 case 't': 203 t_flag = 1; 204 break; 205 case 'u': 206 u_flag = 1; 207 break; 208 case 'v': 209 v_flag = 1; 210 break; 211 case '1': 212 case '2': 213 case '3': 214 case '4': 215 case '5': 216 case '6': 217 case '7': 218 case '8': 219 partition = c - '0'; 220 break; 221 default: 222 usage(); 223 } 224 if (f_flag || i_flag) 225 u_flag = 1; 226 if (t_flag) 227 v_flag = 1; 228 argc -= optind; 229 argv += optind; 230 231 if (argc == 0) { 232 disk = get_rootdisk(); 233 } else { 234 if (stat(argv[0], &sb) == 0) { 235 /* OK, full pathname given */ 236 disk = argv[0]; 237 } else if (errno == ENOENT && argv[0][0] != '/') { 238 /* Try prepending "/dev" */ 239 asprintf(&disk, "%s%s", _PATH_DEV, argv[0]); 240 if (disk == NULL) 241 errx(1, "out of memory"); 242 } else { 243 /* other stat error, let it fail below */ 244 disk = argv[0]; 245 } 246 } 247 if (open_disk(u_flag) < 0) 248 err(1, "cannot open disk %s", disk); 249 250 if (s_flag) { 251 if (read_s0()) 252 err(1, "read_s0"); 253 printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads, 254 dos_sectors); 255 printf("Part %11s %11s %4s %4s %-16s\n", "Start", "Size", "MID", 256 "SID", "Name"); 257 for (i = 0; i < PC98_NPARTS; i++) { 258 partp = ((struct pc98_partition *) &mboot.parts) + i; 259 if (partp->dp_sid == 0) 260 continue; 261 printf("%4d: %11u %11u 0x%02x 0x%02x %-16.16s\n", i + 1, 262 partp->dp_scyl * cylsecs, 263 (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs, 264 partp->dp_mid, partp->dp_sid, partp->dp_name); 265 } 266 exit(0); 267 } 268 269 printf("******* Working on device %s *******\n",disk); 270 271 if (I_flag) { 272 read_s0(); 273 reset_boot(); 274 partp = (struct pc98_partition *) (&mboot.parts[0]); 275 partp->dp_mid = DOSMID_386BSD; 276 partp->dp_sid = DOSSID_386BSD; 277 strncpy(partp->dp_name, "FreeBSD", sizeof(partp->dp_name)); 278 /* Start c/h/s. */ 279 partp->dp_scyl = partp->dp_ipl_cyl = 1; 280 partp->dp_shd = partp->dp_ipl_head = 1; 281 partp->dp_ssect = partp->dp_ipl_sct = 0; 282 283 /* End c/h/s. */ 284 partp->dp_ecyl = dos_cyls - 1; 285 partp->dp_ehd = dos_cylsecs / dos_sectors; 286 partp->dp_esect = dos_sectors; 287 288 if (v_flag) 289 print_s0(-1); 290 if (!t_flag) 291 write_s0(); 292 exit(0); 293 } 294 295 if (f_flag) { 296 if (v_flag) 297 print_s0(-1); 298 if (!t_flag) 299 write_s0(); 300 } else { 301 if(u_flag) 302 get_params_to_use(); 303 else 304 print_params(); 305 306 if (read_s0()) 307 init_sector0(dos_sectors); 308 309 printf("Media sector size is %d\n", secsize); 310 printf("Warning: BIOS sector numbering starts with sector 1\n"); 311 printf("Information from DOS bootblock is:\n"); 312 if (partition == -1) 313 for (i = 1; i <= PC98_NPARTS; i++) 314 change_part(i, v_flag); 315 else 316 change_part(partition, 1); 317 318 if (u_flag || a_flag) 319 change_active(partition); 320 321 if (B_flag) 322 change_code(); 323 324 if (u_flag || a_flag || B_flag) { 325 if (!t_flag) { 326 printf("\nWe haven't changed the partition table yet. "); 327 printf("This is your last chance.\n"); 328 } 329 print_s0(-1); 330 if (!t_flag) { 331 if (ok("Should we write new partition table?")) 332 write_s0(); 333 } else { 334 printf("\n-t flag specified -- partition table not written.\n"); 335 } 336 } 337 } 338 339 exit(0); 340} 341 342static void 343usage() 344{ 345 fprintf(stderr, "%s%s", 346 "usage: fdisk [-BIaistu] [-12345678] [disk]\n", 347 " fdisk -f configfile [-itv] [disk]\n"); 348 exit(1); 349} 350 351static struct pc98_partition mtpart; 352 353static int 354part_unused(int i) 355{ 356 struct pc98_partition *partp; 357 358 partp = ((struct pc98_partition *) &mboot.parts) + i - 1; 359 return (bcmp(partp, &mtpart, sizeof (struct pc98_partition)) == 0); 360} 361 362static void 363print_s0(int which) 364{ 365 int i; 366 367 print_params(); 368 printf("Information from DOS bootblock is:\n"); 369 if (which == -1) { 370 for (i = 1; i <= PC98_NPARTS; i++) 371 if (v_flag || !part_unused(i)) { 372 printf("%d: ", i); 373 print_part(i); 374 } 375 } 376 else 377 print_part(which); 378} 379 380static void 381print_part(int i) 382{ 383 struct pc98_partition *partp; 384 u_int64_t part_sz, part_mb; 385 386 if (part_unused(i)) { 387 printf("<UNUSED>\n"); 388 return; 389 } 390 /* 391 * Be careful not to overflow. 392 */ 393 partp = ((struct pc98_partition *) &mboot.parts) + i - 1; 394 part_sz = (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs; 395 part_mb = part_sz * secsize; 396 part_mb /= (1024 * 1024); 397 printf("sysmid %d (%#04x),(%s)\n", partp->dp_mid, partp->dp_mid, 398 get_type(partp->dp_mid)); 399 printf(" start %lu, size %lu (%ju Meg), sid %d\n", 400 (u_long)(partp->dp_scyl * cylsecs), (u_long)part_sz, 401 (uintmax_t)part_mb, partp->dp_sid); 402 printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n" 403 ,partp->dp_scyl 404 ,partp->dp_shd 405 ,partp->dp_ssect 406 ,partp->dp_ecyl 407 ,partp->dp_ehd 408 ,partp->dp_esect); 409 printf ("\tsystem Name %.16s\n", partp->dp_name); 410} 411 412 413static void 414init_boot(void) 415{ 416 417 mboot.signature = PC98_MAGIC; 418} 419 420 421static void 422init_sector0(unsigned long start) 423{ 424 struct pc98_partition *partp = 425 (struct pc98_partition *)(&mboot.parts[0]); 426 427 init_boot(); 428 429 partp->dp_mid = DOSMID_386BSD; 430 partp->dp_sid = DOSSID_386BSD; 431 432 dos(start, disksecs - start, partp); 433} 434 435static void 436change_part(int i, int force) 437{ 438 struct pc98_partition *partp = 439 ((struct pc98_partition *) &mboot.parts) + i - 1; 440 441 if (!force && part_unused(i)) 442 return; 443 444 printf("The data for partition %d is:\n", i); 445 print_part(i); 446 447 if (u_flag && ok("Do you want to change it?")) { 448 int tmp; 449 450 if (i_flag) { 451 bzero((char *)partp, sizeof (struct pc98_partition)); 452 if (i == 1) { 453 init_sector0(1); 454 printf("\nThe static data for the slice 1 has been reinitialized to:\n"); 455 print_part(i); 456 } 457 } 458 do { 459 int x_start = partp->dp_scyl * cylsecs ; 460 int x_size = (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs; 461 Decimal("sysmid", partp->dp_mid, tmp); 462 Decimal("syssid", partp->dp_sid, tmp); 463 String ("system name", partp->dp_name, 16); 464 Decimal("start", x_start, tmp); 465 Decimal("size", x_size, tmp); 466 467 if (ok("Explicitly specify beg/end address ?")) 468 { 469 int tsec,tcyl,thd; 470 tcyl = partp->dp_scyl; 471 thd = partp->dp_shd; 472 tsec = partp->dp_ssect; 473 Decimal("beginning cylinder", tcyl, tmp); 474 Decimal("beginning head", thd, tmp); 475 Decimal("beginning sector", tsec, tmp); 476 partp->dp_scyl = tcyl; 477 partp->dp_ssect = tsec; 478 partp->dp_shd = thd; 479 partp->dp_ipl_cyl = partp->dp_scyl; 480 partp->dp_ipl_sct = partp->dp_ssect; 481 partp->dp_ipl_head = partp->dp_shd; 482 483 tcyl = partp->dp_ecyl; 484 thd = partp->dp_ehd; 485 tsec = partp->dp_esect; 486 Decimal("ending cylinder", tcyl, tmp); 487 Decimal("ending head", thd, tmp); 488 Decimal("ending sector", tsec, tmp); 489 partp->dp_ecyl = tcyl; 490 partp->dp_esect = tsec; 491 partp->dp_ehd = thd; 492 } else 493 dos(x_start, x_size, partp); 494 495 print_part(i); 496 } while (!ok("Are we happy with this entry?")); 497 } 498} 499 500static void 501print_params() 502{ 503 printf("parameters extracted from in-core disklabel are:\n"); 504 printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 505 ,cyls,heads,sectors,cylsecs); 506 if (dos_cyls > 65535 || dos_heads > 255 || dos_sectors > 255) 507 printf("Figures below won't work with BIOS for partitions not in cyl 1\n"); 508 printf("parameters to be used for BIOS calculations are:\n"); 509 printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 510 ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); 511} 512 513static void 514change_active(int which) 515{ 516 struct pc98_partition *partp = &mboot.parts[0]; 517 int active, i, new, tmp; 518 519 active = -1; 520 for (i = 0; i < PC98_NPARTS; i++) { 521 if ((partp[i].dp_sid & PC98_SID_ACTIVE) == 0) 522 continue; 523 printf("Partition %d is marked active\n", i + 1); 524 if (active == -1) 525 active = i + 1; 526 } 527 if (a_flag && which != -1) 528 active = which; 529 else if (active == -1) 530 active = 1; 531 532 if (!ok("Do you want to change the active partition?")) 533 return; 534setactive: 535 do { 536 new = active; 537 Decimal("active partition", new, tmp); 538 if (new < 1 || new > 8) { 539 printf("Active partition number must be in range 1-8." 540 " Try again.\n"); 541 goto setactive; 542 } 543 active = new; 544 } while (!ok("Are you happy with this choice")); 545 if (active > 0 && active <= 8) 546 partp[active-1].dp_sid |= PC98_SID_ACTIVE; 547} 548 549static void 550change_code() 551{ 552 if (ok("Do you want to change the boot code?")) 553 init_boot(); 554} 555 556void 557get_params_to_use() 558{ 559 int tmp; 560 print_params(); 561 if (ok("Do you want to change our idea of what BIOS thinks ?")) 562 { 563 do 564 { 565 Decimal("BIOS's idea of #cylinders", dos_cyls, tmp); 566 Decimal("BIOS's idea of #heads", dos_heads, tmp); 567 Decimal("BIOS's idea of #sectors", dos_sectors, tmp); 568 dos_cylsecs = dos_heads * dos_sectors; 569 print_params(); 570 } 571 while(!ok("Are you happy with this choice")); 572 } 573} 574 575 576/***********************************************\ 577* Change real numbers into strange dos numbers * 578\***********************************************/ 579static void 580dos(u_int32_t start, u_int32_t size, struct pc98_partition *partp) 581{ 582 u_int32_t end; 583 584 if (partp->dp_mid == 0 && partp->dp_sid == 0 && 585 start == 0 && size == 0) { 586 memcpy(partp, &mtpart, sizeof(*partp)); 587 return; 588 } 589 590 /* Start c/h/s. */ 591 partp->dp_scyl = partp->dp_ipl_cyl = start / dos_cylsecs; 592 partp->dp_shd = partp->dp_ipl_head = start % dos_cylsecs / dos_sectors; 593 partp->dp_ssect = partp->dp_ipl_sct = start % dos_sectors; 594 595 /* End c/h/s. */ 596 end = start + size - cylsecs; 597 partp->dp_ecyl = end / dos_cylsecs; 598 partp->dp_ehd = end % dos_cylsecs / dos_sectors; 599 partp->dp_esect = end % dos_sectors; 600} 601 602static int 603open_disk(int flag) 604{ 605 struct stat st; 606 int rwmode; 607 608 if (stat(disk, &st) == -1) { 609 if (errno == ENOENT) 610 return -2; 611 warnx("can't get file status of %s", disk); 612 return -1; 613 } 614 if ( !(st.st_mode & S_IFCHR) ) 615 warnx("device %s is not character special", disk); 616 rwmode = I_flag || a_flag || B_flag || flag ? O_RDWR : O_RDONLY; 617 fd = open(disk, rwmode); 618 if (fd == -1 && errno == EPERM && rwmode == O_RDWR) 619 fd = open(disk, O_RDONLY); 620 if (fd == -1 && errno == ENXIO) 621 return -2; 622 if (fd == -1) { 623 warnx("can't open device %s", disk); 624 return -1; 625 } 626 if (get_params() == -1) { 627 warnx("can't get disk parameters on %s", disk); 628 return -1; 629 } 630 return fd; 631} 632 633static ssize_t 634read_disk(off_t sector, void *buf) 635{ 636 637 lseek(fd, (sector * 512), 0); 638 return read(fd, buf, 639 secsize > MIN_SEC_SIZE ? secsize : MIN_SEC_SIZE * 2); 640} 641 642static int 643write_disk(off_t sector, void *buf) 644{ 645 int error; 646 struct gctl_req *grq; 647 const char *q; 648 char fbuf[BUFSIZ]; 649 int i, fdw, sz; 650 651 sz = secsize > MIN_SEC_SIZE ? secsize : MIN_SEC_SIZE * 2; 652 grq = gctl_get_handle(); 653 gctl_ro_param(grq, "verb", -1, "write PC98"); 654 gctl_ro_param(grq, "class", -1, "PC98"); 655 q = strrchr(disk, '/'); 656 if (q == NULL) 657 q = disk; 658 else 659 q++; 660 gctl_ro_param(grq, "geom", -1, q); 661 gctl_ro_param(grq, "data", sz, buf); 662 q = gctl_issue(grq); 663 if (q == NULL) { 664 gctl_free(grq); 665 return(0); 666 } 667 warnx("Geom problem: %s", q); 668 gctl_free(grq); 669 670 warnx("Warning: Partitioning via geom failed, trying raw write"); 671 error = pwrite(fd, buf, sz, sector * 512); 672 if (error == sz) 673 return (0); 674 675 for (i = 0; i < PC98_NPARTS; i++) { 676 sprintf(fbuf, "%ss%d", disk, i + 1); 677 fdw = open(fbuf, O_RDWR, 0); 678 if (fdw < 0) 679 continue; 680 error = ioctl(fdw, DIOCSPC98, buf); 681 close(fdw); 682 if (error == 0) 683 return (0); 684 } 685 warnx("Failed to write sector zero"); 686 return(EINVAL); 687} 688 689static int 690get_params() 691{ 692 int error; 693 u_int u; 694 off_t o; 695 696 error = ioctl(fd, DIOCGFWSECTORS, &u); 697 if (error == 0) 698 sectors = dos_sectors = u; 699 else 700 sectors = dos_sectors = 17; 701 702 error = ioctl(fd, DIOCGFWHEADS, &u); 703 if (error == 0) 704 heads = dos_heads = u; 705 else 706 heads = dos_heads = 8; 707 708 dos_cylsecs = cylsecs = heads * sectors; 709 disksecs = cyls * heads * sectors; 710 711 error = ioctl(fd, DIOCGSECTORSIZE, &u); 712 if (error != 0 || u == 0) 713 u = 512; 714 secsize = u; 715 716 error = ioctl(fd, DIOCGMEDIASIZE, &o); 717 if (error == 0) { 718 disksecs = o / u; 719 cyls = dos_cyls = o / (u * dos_heads * dos_sectors); 720 } 721 722 return (disksecs); 723} 724 725 726static int 727read_s0() 728{ 729 730 if (read_disk(0, (char *) mboot.bootinst) == -1) { 731 warnx("can't read fdisk partition table"); 732 return -1; 733 } 734 if (mboot.signature != PC98_MAGIC) { 735 warnx("invalid fdisk partition table found"); 736 /* So should we initialize things */ 737 return -1; 738 } 739 740 return 0; 741} 742 743static int 744write_s0() 745{ 746 747 if (iotest) { 748 print_s0(-1); 749 return 0; 750 } 751 752 /* 753 * write enable label sector before write (if necessary), 754 * disable after writing. 755 * needed if the disklabel protected area also protects 756 * sector 0. (e.g. empty disk) 757 */ 758 if (write_disk(0, (char *) mboot.bootinst) == -1) { 759 warn("can't write fdisk partition table"); 760 return -1; 761 } 762 763 return(0); 764} 765 766 767static int 768ok(const char *str) 769{ 770 printf("%s [n] ", str); 771 fflush(stdout); 772 if (fgets(lbuf, LBUF, stdin) == NULL) 773 exit(1); 774 lbuf[strlen(lbuf)-1] = 0; 775 776 if (*lbuf && 777 (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || 778 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) 779 return 1; 780 else 781 return 0; 782} 783 784static int 785decimal(const char *str, int *num, int deflt) 786{ 787 int acc = 0, c; 788 char *cp; 789 790 while (1) { 791 printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); 792 fflush(stdout); 793 if (fgets(lbuf, LBUF, stdin) == NULL) 794 exit(1); 795 lbuf[strlen(lbuf)-1] = 0; 796 797 if (!*lbuf) 798 return 0; 799 800 cp = lbuf; 801 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 802 if (!c) 803 return 0; 804 while ((c = *cp++)) { 805 if (c <= '9' && c >= '0') 806 acc = acc * 10 + c - '0'; 807 else 808 break; 809 } 810 if (c == ' ' || c == '\t') 811 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 812 if (!c) { 813 *num = acc; 814 return 1; 815 } else 816 printf("%s is an invalid decimal number. Try again.\n", 817 lbuf); 818 } 819 820} 821 822static int 823string(const char *str, char **ans) 824{ 825 int i, c; 826 char *cp = lbuf; 827 828 while (1) { 829 printf("Supply a string value for \"%s\" [%s] ", str, *ans); 830 fgets(lbuf, LBUF, stdin); 831 lbuf[strlen(lbuf)-1] = 0; 832 833 if (!*lbuf) 834 return 0; 835 836 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 837 if (c == '"') { 838 c = *++cp; 839 *ans = cp; 840 while ((c = *cp) && c != '"') cp++; 841 } else { 842 *ans = cp; 843 while ((c = *cp) && c != ' ' && c != '\t') cp++; 844 } 845 846 for (i = strlen(*ans); i < 16; i++) 847 (*ans)[i] = ' '; 848 (*ans)[16] = 0; 849 850 return 1; 851 } 852} 853 854static const char * 855get_type(int type) 856{ 857 int numentries = (sizeof(part_types)/sizeof(struct part_type)); 858 int counter = 0; 859 struct part_type *ptr = part_types; 860 861 862 while(counter < numentries) { 863 if(ptr->type == (type & 0x7f)) 864 return(ptr->name); 865 ptr++; 866 counter++; 867 } 868 return("unknown"); 869} 870 871/* 872 * Try figuring out the root device's canonical disk name. 873 * The following choices are considered: 874 * /dev/ad0s1a => /dev/ad0 875 * /dev/da0a => /dev/da0 876 * /dev/vinum/root => /dev/vinum/root 877 */ 878static char * 879get_rootdisk(void) 880{ 881 struct statfs rootfs; 882 regex_t re; 883#define NMATCHES 2 884 regmatch_t rm[NMATCHES]; 885 char *s; 886 int rv; 887 888 if (statfs("/", &rootfs) == -1) 889 err(1, "statfs(\"/\")"); 890 891 if ((rv = regcomp(&re, "^(/dev/[a-z]+[0-9]+)([sp][0-9]+)?[a-h]?$", 892 REG_EXTENDED)) != 0) 893 errx(1, "regcomp() failed (%d)", rv); 894 if ((rv = regexec(&re, rootfs.f_mntfromname, NMATCHES, rm, 0)) != 0) 895 errx(1, 896"mounted root fs resource doesn't match expectations (regexec returned %d)", 897 rv); 898 if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL) 899 errx(1, "out of memory"); 900 memcpy(s, rootfs.f_mntfromname + rm[1].rm_so, 901 rm[1].rm_eo - rm[1].rm_so); 902 s[rm[1].rm_eo - rm[1].rm_so] = 0; 903 904 return s; 905} 906 907static void 908reset_boot(void) 909{ 910 int i; 911 struct pc98_partition *partp; 912 913 init_boot(); 914 for (i = 1; i <= PC98_NPARTS; i++) { 915 partp = ((struct pc98_partition *) &mboot.parts) + i - 1; 916 bzero((char *)partp, sizeof (struct pc98_partition)); 917 } 918} 919