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