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