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