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 ,{0xA6, "OpenBSD"} 193 ,{0xA7, "NEXTSTEP"} 194 ,{0xB7, "BSDI BSD/386 filesystem"} 195 ,{0xB8, "BSDI BSD/386 swap"} 196 ,{0xDB, "Concurrent CPM or C.DOS or CTOS"} 197 ,{0xE1, "Speed"} 198 ,{0xE3, "Speed"} 199 ,{0xE4, "Speed"} 200 ,{0xF1, "Speed"} 201 ,{0xF2, "DOS 3.3+ Secondary"} 202 ,{0xF4, "Speed"} 203 ,{0xFF, "BBT (Bad Blocks Table)"} 204 }; 205 206 static void print_s0(int which); 207 static void print_part(int i); 208 static void init_sector0(unsigned long start); 209 static void init_boot(void); 210 static void change_part(int i); 211 static void print_params(); 212 static void change_active(int which); 213 static void get_params_to_use(); 214 static void dos(int sec, int size, unsigned char *c, unsigned char *s, 215 unsigned char *h); 216 static int open_disk(int u_flag); 217 static ssize_t read_disk(off_t sector, void *buf); 218 static ssize_t write_disk(off_t sector, void *buf); 219 static int get_params(); 220 static int read_s0(); 221 static int write_s0(); 222 static int ok(char *str); 223 static int decimal(char *str, int *num, int deflt); 224 static char *get_type(int type); 225 static int read_config(char *config_file); 226 static void reset_boot(void); 227 #if 0 228 static int hex(char *str, int *num, int deflt); 229 static int string(char *str, char **ans); 230 #endif 231 232 233 int 234 main(int argc, char *argv[]) 235 { 236 int i; 237 238 name = *argv; 239 {register char *cp = name; 240 while (*cp) if (*cp++ == '/') name = cp; 241 } 242 243 for ( argv++ ; --argc ; argv++ ) { register char *token = *argv; 244 if (*token++ != '-' || !*token) 245 break; 246 else { register int flag; 247 for ( ; (flag = *token++) ; ) { 248 switch (flag) { 249 case '1': 250 partition = 1; 251 break; 252 case '2': 253 partition = 2; 254 break; 255 case '3': 256 partition = 3; 257 break; 258 case '4': 259 partition = 4; 260 break; 261 case 'a': 262 a_flag = 1; 263 break; 264 case 'f': 265 if (*token) 266 { 267 f_flag = token; 268 token = ""; 269 } 270 else 271 { 272 if (argc == 1) 273 { 274 goto usage; 275 } 276 --argc; 277 f_flag = *++argv; 278 } 279 /* 280 * u_flag is needed, because we're 281 * writing to the disk. 282 */ 283 u_flag = 1; 284 break; 285 case 'i': 286 i_flag = 1; 287 case 'u': 288 u_flag = 1; 289 break; 290 case 't': 291 t_flag = 1; 292 case 'v': 293 v_flag = 1; 294 break; 295 default: 296 goto usage; 297 } 298 } 299 } 300 } 301 302 if (argc > 0) 303 { 304 static char realname[12]; 305 306 if(strncmp(argv[0], "/dev", 4) == 0) 307 disk = argv[0]; 308 else 309 { 310 snprintf(realname, 12, "/dev/r%s", argv[0]); 311 disk = realname; 312 } 313 314 if (open_disk(u_flag) < 0) 315 { 316 fprintf(stderr, "Cannot open disk %s (%s)\n", 317 disk, sys_errlist[errno]); 318 exit(1); 319 } 320 } 321 else 322 { 323 int i, rv = 0; 324 325 for(i = 0; disks[i]; i++) 326 { 327 disk = disks[i]; 328 rv = open_disk(u_flag); 329 if(rv != -2) break; 330 } 331 if(rv < 0) 332 { 333 fprintf(stderr, "Cannot open any disk (%s)\n", 334 sys_errlist[errno]); 335 exit(1); 336 } 337 } 338 339 printf("******* Working on device %s *******\n",disk); 340 341 if (f_flag) 342 { 343 if (read_s0() || i_flag) 344 { 345 reset_boot(); 346 } 347 348 if (!read_config(f_flag)) 349 { 350 exit(1); 351 } 352 if (v_flag) 353 { 354 print_s0(-1); 355 } 356 if (!t_flag) 357 { 358 write_s0(); 359 } 360 } 361 else 362 { 363 if(u_flag) 364 { 365 get_params_to_use(); 366 } 367 else 368 { 369 print_params(); 370 } 371 372 if (read_s0()) 373 init_sector0(1); 374 375 printf("Media sector size is %d\n", secsize); 376 printf("Warning: BIOS sector numbering starts with sector 1\n"); 377 printf("Information from DOS bootblock is:\n"); 378 if (partition == -1) 379 for (i = 1; i <= NDOSPART; i++) 380 change_part(i); 381 else 382 change_part(partition); 383 384 if (u_flag || a_flag) 385 change_active(partition); 386 387 if (u_flag || a_flag) { 388 if (!t_flag) 389 { 390 printf("\nWe haven't changed the partition table yet. "); 391 printf("This is your last chance.\n"); 392 } 393 print_s0(-1); 394 if (!t_flag) 395 { 396 if (ok("Should we write new partition table?")) 397 write_s0(); 398 } 399 else 400 { 401 printf("\n-t flag specified -- partition table not written.\n"); 402 } 403 } 404 } 405 406 exit(0); 407 408 usage: 409 printf("fdisk {-a|-i|-u} [-f <config file> [-t] [-v]] [-{1,2,3,4}] [disk]\n"); 410 return(1); 411 } 412 413 static void 414 print_s0(int which) 415 { 416 int i; 417 418 print_params(); 419 printf("Information from DOS bootblock is:\n"); 420 if (which == -1) 421 for (i = 1; i <= NDOSPART; i++) 422 printf("%d: ", i), print_part(i); 423 else 424 print_part(which); 425 } 426 427 static struct dos_partition mtpart = { 0 }; 428 429 static void 430 print_part(int i) 431 { 432 struct dos_partition *partp; 433 u_int64_t part_mb; 434 435 partp = ((struct dos_partition *) &mboot.parts) + i - 1; 436 437 if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) { 438 printf("<UNUSED>\n"); 439 return; 440 } 441 /* 442 * Be careful not to overflow. 443 */ 444 part_mb = partp->dp_size; 445 part_mb *= secsize; 446 part_mb /= (1024 * 1024); 447 printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ)); 448 printf(" start %ld, size %ld (%qd Meg), flag %x\n", 449 partp->dp_start, 450 partp->dp_size, 451 part_mb, 452 partp->dp_flag); 453 printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n" 454 ,DPCYL(partp->dp_scyl, partp->dp_ssect) 455 ,DPSECT(partp->dp_ssect) 456 ,partp->dp_shd 457 ,DPCYL(partp->dp_ecyl, partp->dp_esect) 458 ,DPSECT(partp->dp_esect) 459 ,partp->dp_ehd); 460 } 461 462 463 static void 464 init_boot(void) 465 { 466 memcpy(mboot.bootinst, bootcode, sizeof(bootcode)); 467 mboot.signature = BOOT_MAGIC; 468 } 469 470 471 static void 472 init_sector0(unsigned long start) 473 { 474 struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]); 475 unsigned long size = disksecs - start; 476 477 init_boot(); 478 479 partp->dp_typ = DOSPTYP_386BSD; 480 partp->dp_flag = ACTIVE; 481 partp->dp_start = start; 482 partp->dp_size = size; 483 484 dos(partp->dp_start, partp->dp_size, 485 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 486 dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, 487 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 488 } 489 490 static void 491 change_part(int i) 492 { 493 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1; 494 495 printf("The data for partition %d is:\n", i); 496 print_part(i); 497 498 if (u_flag && ok("Do you want to change it?")) { 499 int tmp; 500 501 if (i_flag) { 502 bzero((char *)partp, sizeof (struct dos_partition)); 503 if (i == 4) { 504 init_sector0(1); 505 printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n"); 506 print_part(i); 507 } 508 } 509 510 do { 511 Decimal("sysid", partp->dp_typ, tmp); 512 Decimal("start", partp->dp_start, tmp); 513 Decimal("size", partp->dp_size, tmp); 514 515 if (ok("Explicitly specifiy beg/end address ?")) 516 { 517 int tsec,tcyl,thd; 518 tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect); 519 thd = partp->dp_shd; 520 tsec = DPSECT(partp->dp_ssect); 521 Decimal("beginning cylinder", tcyl, tmp); 522 Decimal("beginning head", thd, tmp); 523 Decimal("beginning sector", tsec, tmp); 524 partp->dp_scyl = DOSCYL(tcyl); 525 partp->dp_ssect = DOSSECT(tsec,tcyl); 526 partp->dp_shd = thd; 527 528 tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect); 529 thd = partp->dp_ehd; 530 tsec = DPSECT(partp->dp_esect); 531 Decimal("ending cylinder", tcyl, tmp); 532 Decimal("ending head", thd, tmp); 533 Decimal("ending sector", tsec, tmp); 534 partp->dp_ecyl = DOSCYL(tcyl); 535 partp->dp_esect = DOSSECT(tsec,tcyl); 536 partp->dp_ehd = thd; 537 } else { 538 dos(partp->dp_start, partp->dp_size, 539 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 540 dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, 541 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 542 } 543 544 print_part(i); 545 } while (!ok("Are we happy with this entry?")); 546 } 547 } 548 549 static void 550 print_params() 551 { 552 printf("parameters extracted from in-core disklabel are:\n"); 553 printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 554 ,cyls,heads,sectors,cylsecs); 555 if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255)) 556 printf("Figures below won't work with BIOS for partitions not in cyl 1\n"); 557 printf("parameters to be used for BIOS calculations are:\n"); 558 printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 559 ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); 560 } 561 562 static void 563 change_active(int which) 564 { 565 int i; 566 int active = 4, tmp; 567 struct dos_partition *partp = ((struct dos_partition *) &mboot.parts); 568 569 if (a_flag && which != -1) 570 active = which; 571 if (!ok("Do you want to change the active partition?")) 572 return; 573 do 574 Decimal("active partition", active, tmp); 575 while (!ok("Are you happy with this choice")); 576 for (i = 0; i < NDOSPART; i++) 577 partp[i].dp_flag = 0; 578 if (active > 0 && active <= NDOSPART) 579 partp[active-1].dp_flag = ACTIVE; 580 } 581 582 void 583 get_params_to_use() 584 { 585 int tmp; 586 print_params(); 587 if (ok("Do you want to change our idea of what BIOS thinks ?")) 588 { 589 do 590 { 591 Decimal("BIOS's idea of #cylinders", dos_cyls, tmp); 592 Decimal("BIOS's idea of #heads", dos_heads, tmp); 593 Decimal("BIOS's idea of #sectors", dos_sectors, tmp); 594 dos_cylsecs = dos_heads * dos_sectors; 595 print_params(); 596 } 597 while(!ok("Are you happy with this choice")); 598 } 599 } 600 601 602 /***********************************************\ 603 * Change real numbers into strange dos numbers * 604 \***********************************************/ 605 static void 606 dos(sec, size, c, s, h) 607 int sec, size; 608 unsigned char *c, *s, *h; 609 { 610 int cy; 611 int hd; 612 613 if (sec == 0 && size == 0) { 614 *s = *c = *h = 0; 615 return; 616 } 617 618 cy = sec / ( dos_cylsecs ); 619 sec = sec - cy * ( dos_cylsecs ); 620 621 hd = sec / dos_sectors; 622 sec = (sec - hd * dos_sectors) + 1; 623 624 *h = hd; 625 *c = cy & 0xff; 626 *s = (sec & 0x3f) | ( (cy & 0x300) >> 2); 627 } 628 629 int fd; 630 631 /* Getting device status */ 632 633 static int 634 open_disk(int u_flag) 635 { 636 struct stat st; 637 638 if (stat(disk, &st) == -1) { 639 fprintf(stderr, "%s: Can't get file status of %s\n", 640 name, disk); 641 return -1; 642 } 643 if ( !(st.st_mode & S_IFCHR) ) 644 fprintf(stderr,"%s: Device %s is not character special\n", 645 name, disk); 646 if ((fd = open(disk, a_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) { 647 if(errno == ENXIO) 648 return -2; 649 fprintf(stderr,"%s: Can't open device %s\n", name, disk); 650 return -1; 651 } 652 if (get_params(0) == -1) { 653 fprintf(stderr, "%s: Can't get disk parameters on %s\n", 654 name, disk); 655 return -1; 656 } 657 return fd; 658 } 659 660 static ssize_t 661 read_disk(off_t sector, void *buf) 662 { 663 lseek(fd,(sector * 512), 0); 664 if( secsize == 0 ) 665 for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 ) 666 { 667 /* try the read */ 668 int size = read(fd, buf, secsize); 669 if( size == secsize ) 670 /* it worked so return */ 671 return secsize; 672 } 673 else 674 return read( fd, buf, secsize ); 675 676 /* we failed to read at any of the sizes */ 677 return -1; 678 } 679 680 static ssize_t 681 write_disk(off_t sector, void *buf) 682 { 683 lseek(fd,(sector * 512), 0); 684 /* write out in the size that the read_disk found worked */ 685 return write(fd, buf, secsize); 686 } 687 688 static int 689 get_params() 690 { 691 692 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 693 fprintf(stderr, 694 "%s: Can't get disk parameters on %s; supplying dummy ones\n", 695 name, disk); 696 dos_cyls = cyls = 1; 697 dos_heads = heads = 1; 698 dos_sectors = sectors = 1; 699 dos_cylsecs = cylsecs = heads * sectors; 700 disksecs = cyls * heads * sectors; 701 return disksecs; 702 } 703 704 dos_cyls = cyls = disklabel.d_ncylinders; 705 dos_heads = heads = disklabel.d_ntracks; 706 dos_sectors = sectors = disklabel.d_nsectors; 707 dos_cylsecs = cylsecs = heads * sectors; 708 disksecs = cyls * heads * sectors; 709 710 return (disksecs); 711 } 712 713 714 static int 715 read_s0() 716 { 717 if (read_disk(0, (char *) mboot.bootinst) == -1) { 718 fprintf(stderr, "%s: Can't read fdisk partition table\n", name); 719 return -1; 720 } 721 if (mboot.signature != BOOT_MAGIC) { 722 fprintf(stderr, "%s: Invalid fdisk partition table found\n", 723 name); 724 /* So should we initialize things */ 725 return -1; 726 } 727 return 0; 728 } 729 730 static int 731 write_s0() 732 { 733 int flag; 734 if (iotest) { 735 print_s0(-1); 736 return 0; 737 } 738 /* 739 * write enable label sector before write (if necessary), 740 * disable after writing. 741 * needed if the disklabel protected area also protects 742 * sector 0. (e.g. empty disk) 743 */ 744 flag = 1; 745 #ifdef NOT_NOW 746 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 747 perror("ioctl DIOCWLABEL"); 748 #endif 749 if (write_disk(0, (char *) mboot.bootinst) == -1) { 750 fprintf(stderr, "%s: Can't write fdisk partition table\n", 751 name); 752 return -1; 753 flag = 0; 754 #ifdef NOT_NOW 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 fprintf(stderr, 971 "%s: ERROR line %d: the geometry specification line must occur before\n\ 972 all partition specifications.\n", 973 name, current_line_number); 974 status = 0; 975 break; 976 } 977 if (command->n_args != 3) 978 { 979 fprintf(stderr, 980 "%s: ERROR line %d: incorrect number of geometry args\n", 981 name, current_line_number); 982 status = 0; 983 break; 984 } 985 dos_cyls = -1; 986 dos_heads = -1; 987 dos_sectors = -1; 988 for (i = 0; i < 3; ++i) 989 { 990 switch (command->args[i].argtype) 991 { 992 case 'c': 993 dos_cyls = command->args[i].arg_val; 994 break; 995 case 'h': 996 dos_heads = command->args[i].arg_val; 997 break; 998 case 's': 999 dos_sectors = command->args[i].arg_val; 1000 break; 1001 default: 1002 fprintf(stderr, 1003 "%s: ERROR line %d: unknown geometry arg type: '%c' (0x%02x)\n", 1004 name, current_line_number, command->args[i].argtype, 1005 command->args[i].argtype); 1006 status = 0; 1007 break; 1008 } 1009 } 1010 if (status == 0) 1011 { 1012 break; 1013 } 1014 1015 dos_cylsecs = dos_heads * dos_sectors; 1016 1017 /* 1018 * Do sanity checks on parameter values 1019 */ 1020 if (dos_cyls < 0) 1021 { 1022 fprintf(stderr, 1023 "%s: ERROR line %d: number of cylinders not specified\n", 1024 name, current_line_number); 1025 status = 0; 1026 } 1027 if (dos_cyls == 0 || dos_cyls > 1024) 1028 { 1029 fprintf(stderr, 1030 "%s: 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).\n", 1033 name, current_line_number, dos_cyls); 1034 } 1035 1036 if (dos_heads < 0) 1037 { 1038 fprintf(stderr, 1039 "%s: ERROR line %d: number of heads not specified\n", 1040 name, current_line_number); 1041 status = 0; 1042 } 1043 else if (dos_heads < 1 || dos_heads > 256) 1044 { 1045 fprintf(stderr, 1046 "%s: ERROR line %d: number of heads must be within (1-256)\n", 1047 name, current_line_number); 1048 status = 0; 1049 } 1050 1051 if (dos_sectors < 0) 1052 { 1053 fprintf(stderr, "%s: ERROR line %d: number of sectors not specified\n", 1054 name, current_line_number); 1055 status = 0; 1056 } 1057 else if (dos_sectors < 1 || dos_sectors > 63) 1058 { 1059 fprintf(stderr, 1060 "%s: ERROR line %d: number of sectors must be within (1-63)\n", 1061 name, current_line_number); 1062 status = 0; 1063 } 1064 1065 break; 1066 } 1067 return (status); 1068 } 1069 1070 1071 static int 1072 process_partition(command) 1073 CMD *command; 1074 { 1075 int status = 0, partition; 1076 unsigned long chunks, adj_size, max_end; 1077 struct dos_partition *partp; 1078 1079 while (1) 1080 { 1081 part_processed = 1; 1082 if (command->n_args != 4) 1083 { 1084 fprintf(stderr, 1085 "%s: ERROR line %d: incorrect number of partition args\n", 1086 name, current_line_number); 1087 break; 1088 } 1089 partition = command->args[0].arg_val; 1090 if (partition < 1 || partition > 4) 1091 { 1092 fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n", 1093 name, current_line_number, partition); 1094 break; 1095 } 1096 partp = ((struct dos_partition *) &mboot.parts) + partition - 1; 1097 bzero((char *)partp, sizeof (struct dos_partition)); 1098 partp->dp_typ = command->args[1].arg_val; 1099 partp->dp_start = command->args[2].arg_val; 1100 partp->dp_size = command->args[3].arg_val; 1101 max_end = partp->dp_start + partp->dp_size; 1102 1103 if (partp->dp_typ == 0) 1104 { 1105 /* 1106 * Get out, the partition is marked as unused. 1107 */ 1108 /* 1109 * Insure that it's unused. 1110 */ 1111 bzero((char *)partp, sizeof (struct dos_partition)); 1112 status = 1; 1113 break; 1114 } 1115 1116 /* 1117 * Adjust start upwards, if necessary, to fall on an head boundary. 1118 */ 1119 if (partp->dp_start % dos_sectors != 0) 1120 { 1121 adj_size = 1122 (partp->dp_start / dos_sectors + 1) * dos_sectors; 1123 if (adj_size > max_end) 1124 { 1125 /* 1126 * Can't go past end of partition 1127 */ 1128 fprintf(stderr, 1129 "%s: ERROR line %d: unable to adjust start of partition %d to fall on\n\ 1130 a cylinder boundary.\n", 1131 name, current_line_number, partition); 1132 break; 1133 } 1134 fprintf(stderr, 1135 "%s: WARNING: adjusting start offset of partition '%d' from %d\n\ 1136 to %d, to round to an head boundary.\n", 1137 name, partition, partp->dp_start, adj_size); 1138 partp->dp_start = adj_size; 1139 } 1140 1141 /* 1142 * Adjust size downwards, if necessary, to fall on a cylinder 1143 * boundary. 1144 */ 1145 chunks = 1146 ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; 1147 adj_size = chunks - partp->dp_start; 1148 if (adj_size != partp->dp_size) 1149 { 1150 fprintf(stderr, 1151 "%s: WARNING: adjusting size of partition '%d' from %d to %d,\n\ 1152 to round to a cylinder boundary.\n", 1153 name, partition, partp->dp_size, adj_size); 1154 if (chunks > 0) 1155 { 1156 partp->dp_size = adj_size; 1157 } 1158 else 1159 { 1160 partp->dp_size = 0; 1161 } 1162 } 1163 if (partp->dp_size < 1) 1164 { 1165 fprintf(stderr, 1166 "%s: ERROR line %d: size for partition '%d' is zero.\n", 1167 name, current_line_number, partition); 1168 break; 1169 } 1170 1171 dos(partp->dp_start, partp->dp_size, 1172 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 1173 dos(partp->dp_start+partp->dp_size - 1, partp->dp_size, 1174 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 1175 status = 1; 1176 break; 1177 } 1178 return (status); 1179 } 1180 1181 1182 static int 1183 process_active(command) 1184 CMD *command; 1185 { 1186 int status = 0, partition, i; 1187 struct dos_partition *partp; 1188 1189 while (1) 1190 { 1191 active_processed = 1; 1192 if (command->n_args != 1) 1193 { 1194 fprintf(stderr, 1195 "%s: ERROR line %d: incorrect number of active args\n", 1196 name, current_line_number); 1197 status = 0; 1198 break; 1199 } 1200 partition = command->args[0].arg_val; 1201 if (partition < 1 || partition > 4) 1202 { 1203 fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n", 1204 name, current_line_number, partition); 1205 break; 1206 } 1207 /* 1208 * Reset active partition 1209 */ 1210 partp = ((struct dos_partition *) &mboot.parts); 1211 for (i = 0; i < NDOSPART; i++) 1212 partp[i].dp_flag = 0; 1213 partp[partition-1].dp_flag = ACTIVE; 1214 1215 status = 1; 1216 break; 1217 } 1218 return (status); 1219 } 1220 1221 1222 static int 1223 process_line(line) 1224 char *line; 1225 { 1226 CMD command; 1227 int status = 1; 1228 1229 while (1) 1230 { 1231 parse_config_line(line, &command); 1232 switch (command.cmd) 1233 { 1234 case 0: 1235 /* 1236 * Comment or blank line 1237 */ 1238 break; 1239 case 'g': 1240 /* 1241 * Set geometry 1242 */ 1243 status = process_geometry(&command); 1244 break; 1245 case 'p': 1246 status = process_partition(&command); 1247 break; 1248 case 'a': 1249 status = process_active(&command); 1250 break; 1251 default: 1252 status = 0; 1253 break; 1254 } 1255 break; 1256 } 1257 return (status); 1258 } 1259 1260 1261 static int 1262 read_config(config_file) 1263 char *config_file; 1264 { 1265 FILE *fp = NULL; 1266 int status = 1; 1267 char buf[1010]; 1268 1269 while (1) /* dirty trick used to insure one exit point for this 1270 function */ 1271 { 1272 if (strcmp(config_file, "-") != 0) 1273 { 1274 /* 1275 * We're not reading from stdin 1276 */ 1277 if ((fp = fopen(config_file, "r")) == NULL) 1278 { 1279 status = 0; 1280 break; 1281 } 1282 } 1283 else 1284 { 1285 fp = stdin; 1286 } 1287 current_line_number = 0; 1288 while (!feof(fp)) 1289 { 1290 if (fgets(buf, sizeof(buf), fp) == NULL) 1291 { 1292 break; 1293 } 1294 ++current_line_number; 1295 status = process_line(buf); 1296 if (status == 0) 1297 { 1298 break; 1299 } 1300 } 1301 break; 1302 } 1303 if (fp) 1304 { 1305 /* 1306 * It doesn't matter if we're reading from stdin, as we've reached EOF 1307 */ 1308 fclose(fp); 1309 } 1310 return (status); 1311 } 1312 1313 1314 static void 1315 reset_boot(void) 1316 { 1317 int i; 1318 struct dos_partition *partp; 1319 1320 init_boot(); 1321 for (i = 0; i < 4; ++i) 1322 { 1323 partp = ((struct dos_partition *) &mboot.parts) + i; 1324 bzero((char *)partp, sizeof (struct dos_partition)); 1325 } 1326 } 1327