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