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