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