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