fdisk.c revision 34952
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, NTFS, 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%s\n", 453 partp->dp_start, 454 partp->dp_size, 455 part_mb, 456 partp->dp_flag, 457 partp->dp_flag == ACTIVE ? " (active)" : ""); 458 printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n" 459 ,DPCYL(partp->dp_scyl, partp->dp_ssect) 460 ,DPSECT(partp->dp_ssect) 461 ,partp->dp_shd 462 ,DPCYL(partp->dp_ecyl, partp->dp_esect) 463 ,DPSECT(partp->dp_esect) 464 ,partp->dp_ehd); 465} 466 467 468static void 469init_boot(void) 470{ 471 memcpy(mboot.bootinst, bootcode, sizeof(bootcode)); 472 mboot.signature = BOOT_MAGIC; 473} 474 475 476static void 477init_sector0(unsigned long start) 478{ 479struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]); 480unsigned long size = disksecs - start; 481 482 init_boot(); 483 484 partp->dp_typ = DOSPTYP_386BSD; 485 partp->dp_flag = ACTIVE; 486 partp->dp_start = start; 487 partp->dp_size = size; 488 489 dos(partp->dp_start, partp->dp_size, 490 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 491 dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, 492 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 493} 494 495static void 496change_part(int i) 497{ 498struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1; 499 500 printf("The data for partition %d is:\n", i); 501 print_part(i); 502 503 if (u_flag && ok("Do you want to change it?")) { 504 int tmp; 505 506 if (i_flag) { 507 bzero((char *)partp, sizeof (struct dos_partition)); 508 if (i == 4) { 509 init_sector0(1); 510 printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n"); 511 print_part(i); 512 } 513 } 514 515 do { 516 Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp); 517 Decimal("start", partp->dp_start, tmp); 518 Decimal("size", partp->dp_size, tmp); 519 520 if (ok("Explicitly specifiy beg/end address ?")) 521 { 522 int tsec,tcyl,thd; 523 tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect); 524 thd = partp->dp_shd; 525 tsec = DPSECT(partp->dp_ssect); 526 Decimal("beginning cylinder", tcyl, tmp); 527 Decimal("beginning head", thd, tmp); 528 Decimal("beginning sector", tsec, tmp); 529 partp->dp_scyl = DOSCYL(tcyl); 530 partp->dp_ssect = DOSSECT(tsec,tcyl); 531 partp->dp_shd = thd; 532 533 tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect); 534 thd = partp->dp_ehd; 535 tsec = DPSECT(partp->dp_esect); 536 Decimal("ending cylinder", tcyl, tmp); 537 Decimal("ending head", thd, tmp); 538 Decimal("ending sector", tsec, tmp); 539 partp->dp_ecyl = DOSCYL(tcyl); 540 partp->dp_esect = DOSSECT(tsec,tcyl); 541 partp->dp_ehd = thd; 542 } else { 543 dos(partp->dp_start, partp->dp_size, 544 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 545 dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, 546 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 547 } 548 549 print_part(i); 550 } while (!ok("Are we happy with this entry?")); 551 } 552} 553 554static void 555print_params() 556{ 557 printf("parameters extracted from in-core disklabel are:\n"); 558 printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 559 ,cyls,heads,sectors,cylsecs); 560 if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255)) 561 printf("Figures below won't work with BIOS for partitions not in cyl 1\n"); 562 printf("parameters to be used for BIOS calculations are:\n"); 563 printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 564 ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); 565} 566 567static void 568change_active(int which) 569{ 570int i; 571int active = 4, tmp; 572struct dos_partition *partp = ((struct dos_partition *) &mboot.parts); 573 574 if (a_flag && which != -1) 575 active = which; 576 if (!ok("Do you want to change the active partition?")) 577 return; 578setactive: 579 active = 4; 580 do { 581 Decimal("active partition", active, tmp); 582 if (active < 1 || 4 < active) { 583 printf("Active partition number must be in range 1-4." 584 " Try again.\n"); 585 goto setactive; 586 } 587 } while (!ok("Are you happy with this choice")); 588 for (i = 0; i < NDOSPART; i++) 589 partp[i].dp_flag = 0; 590 if (active > 0 && active <= NDOSPART) 591 partp[active-1].dp_flag = ACTIVE; 592} 593 594void 595get_params_to_use() 596{ 597 int tmp; 598 print_params(); 599 if (ok("Do you want to change our idea of what BIOS thinks ?")) 600 { 601 do 602 { 603 Decimal("BIOS's idea of #cylinders", dos_cyls, tmp); 604 Decimal("BIOS's idea of #heads", dos_heads, tmp); 605 Decimal("BIOS's idea of #sectors", dos_sectors, tmp); 606 dos_cylsecs = dos_heads * dos_sectors; 607 print_params(); 608 } 609 while(!ok("Are you happy with this choice")); 610 } 611} 612 613 614/***********************************************\ 615* Change real numbers into strange dos numbers * 616\***********************************************/ 617static void 618dos(sec, size, c, s, h) 619int sec, size; 620unsigned char *c, *s, *h; 621{ 622int cy; 623int hd; 624 625 if (sec == 0 && size == 0) { 626 *s = *c = *h = 0; 627 return; 628 } 629 630 cy = sec / ( dos_cylsecs ); 631 sec = sec - cy * ( dos_cylsecs ); 632 633 hd = sec / dos_sectors; 634 sec = (sec - hd * dos_sectors) + 1; 635 636 *h = hd; 637 *c = cy & 0xff; 638 *s = (sec & 0x3f) | ( (cy & 0x300) >> 2); 639} 640 641int fd; 642 643 /* Getting device status */ 644 645static int 646open_disk(int u_flag) 647{ 648struct stat st; 649 650 if (stat(disk, &st) == -1) { 651 fprintf(stderr, "%s: Can't get file status of %s\n", 652 name, disk); 653 return -1; 654 } 655 if ( !(st.st_mode & S_IFCHR) ) 656 fprintf(stderr,"%s: Device %s is not character special\n", 657 name, disk); 658 if ((fd = open(disk, a_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) { 659 if(errno == ENXIO) 660 return -2; 661 fprintf(stderr,"%s: Can't open device %s\n", name, disk); 662 return -1; 663 } 664 if (get_params(0) == -1) { 665 fprintf(stderr, "%s: Can't get disk parameters on %s\n", 666 name, disk); 667 return -1; 668 } 669 return fd; 670} 671 672static ssize_t 673read_disk(off_t sector, void *buf) 674{ 675 lseek(fd,(sector * 512), 0); 676 if( secsize == 0 ) 677 for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 ) 678 { 679 /* try the read */ 680 int size = read(fd, buf, secsize); 681 if( size == secsize ) 682 /* it worked so return */ 683 return secsize; 684 } 685 else 686 return read( fd, buf, secsize ); 687 688 /* we failed to read at any of the sizes */ 689 return -1; 690} 691 692static ssize_t 693write_disk(off_t sector, void *buf) 694{ 695 lseek(fd,(sector * 512), 0); 696 /* write out in the size that the read_disk found worked */ 697 return write(fd, buf, secsize); 698} 699 700static int 701get_params() 702{ 703 704 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 705 fprintf(stderr, 706 "%s: Can't get disk parameters on %s; supplying dummy ones\n", 707 name, disk); 708 dos_cyls = cyls = 1; 709 dos_heads = heads = 1; 710 dos_sectors = sectors = 1; 711 dos_cylsecs = cylsecs = heads * sectors; 712 disksecs = cyls * heads * sectors; 713 return disksecs; 714 } 715 716 dos_cyls = cyls = disklabel.d_ncylinders; 717 dos_heads = heads = disklabel.d_ntracks; 718 dos_sectors = sectors = disklabel.d_nsectors; 719 dos_cylsecs = cylsecs = heads * sectors; 720 disksecs = cyls * heads * sectors; 721 722 return (disksecs); 723} 724 725 726static int 727read_s0() 728{ 729 if (read_disk(0, (char *) mboot.bootinst) == -1) { 730 fprintf(stderr, "%s: Can't read fdisk partition table\n", name); 731 return -1; 732 } 733 if (mboot.signature != BOOT_MAGIC) { 734 fprintf(stderr, "%s: Invalid fdisk partition table found\n", 735 name); 736 /* So should we initialize things */ 737 return -1; 738 } 739 return 0; 740} 741 742static int 743write_s0() 744{ 745 int flag; 746 if (iotest) { 747 print_s0(-1); 748 return 0; 749 } 750 /* 751 * write enable label sector before write (if necessary), 752 * disable after writing. 753 * needed if the disklabel protected area also protects 754 * sector 0. (e.g. empty disk) 755 */ 756 flag = 1; 757#ifdef NOT_NOW 758 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 759 perror("ioctl DIOCWLABEL"); 760#endif 761 if (write_disk(0, (char *) mboot.bootinst) == -1) { 762 fprintf(stderr, "%s: Can't write fdisk partition table\n", 763 name); 764 return -1; 765 flag = 0; 766#ifdef NOT_NOW 767 (void) ioctl(fd, DIOCWLABEL, &flag); 768#endif 769 } 770 return(0); 771} 772 773 774static int 775ok(str) 776char *str; 777{ 778 printf("%s [n] ", str); 779 fgets(lbuf, LBUF, stdin); 780 lbuf[strlen(lbuf)-1] = 0; 781 782 if (*lbuf && 783 (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || 784 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) 785 return 1; 786 else 787 return 0; 788} 789 790static int 791decimal(char *str, int *num, int deflt) 792{ 793int acc = 0, c; 794char *cp; 795 796 while (1) { 797 printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); 798 fgets(lbuf, LBUF, stdin); 799 lbuf[strlen(lbuf)-1] = 0; 800 801 if (!*lbuf) 802 return 0; 803 804 cp = lbuf; 805 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 806 if (!c) 807 return 0; 808 while ((c = *cp++)) { 809 if (c <= '9' && c >= '0') 810 acc = acc * 10 + c - '0'; 811 else 812 break; 813 } 814 if (c == ' ' || c == '\t') 815 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 816 if (!c) { 817 *num = acc; 818 return 1; 819 } else 820 printf("%s is an invalid decimal number. Try again.\n", 821 lbuf); 822 } 823 824} 825 826#if 0 827static int 828hex(char *str, int *num, int deflt) 829{ 830int acc = 0, c; 831char *cp; 832 833 while (1) { 834 printf("Supply a hex value for \"%s\" [%x] ", str, deflt); 835 fgets(lbuf, LBUF, stdin); 836 lbuf[strlen(lbuf)-1] = 0; 837 838 if (!*lbuf) 839 return 0; 840 841 cp = lbuf; 842 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 843 if (!c) 844 return 0; 845 while ((c = *cp++)) { 846 if (c <= '9' && c >= '0') 847 acc = (acc << 4) + c - '0'; 848 else if (c <= 'f' && c >= 'a') 849 acc = (acc << 4) + c - 'a' + 10; 850 else if (c <= 'F' && c >= 'A') 851 acc = (acc << 4) + c - 'A' + 10; 852 else 853 break; 854 } 855 if (c == ' ' || c == '\t') 856 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 857 if (!c) { 858 *num = acc; 859 return 1; 860 } else 861 printf("%s is an invalid hex number. Try again.\n", 862 lbuf); 863 } 864 865} 866 867static int 868string(char *str, char **ans) 869{ 870int c; 871char *cp = lbuf; 872 873 while (1) { 874 printf("Supply a string value for \"%s\" [%s] ", str, *ans); 875 fgets(lbuf, LBUF, stdin); 876 lbuf[strlen(lbuf)-1] = 0; 877 878 if (!*lbuf) 879 return 0; 880 881 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 882 if (c == '"') { 883 c = *++cp; 884 *ans = cp; 885 while ((c = *cp) && c != '"') cp++; 886 } else { 887 *ans = cp; 888 while ((c = *cp) && c != ' ' && c != '\t') cp++; 889 } 890 891 if (c) 892 *cp = 0; 893 return 1; 894 } 895} 896#endif 897 898static char * 899get_type(int type) 900{ 901 int numentries = (sizeof(part_types)/sizeof(struct part_type)); 902 int counter = 0; 903 struct part_type *ptr = part_types; 904 905 906 while(counter < numentries) 907 { 908 if(ptr->type == type) 909 { 910 return(ptr->name); 911 } 912 ptr++; 913 counter++; 914 } 915 return("unknown"); 916} 917 918 919static void 920parse_config_line(line, command) 921 char *line; 922 CMD *command; 923{ 924 char *cp, *end; 925 926 cp = line; 927 while (1) /* dirty trick used to insure one exit point for this 928 function */ 929 { 930 memset(command, 0, sizeof(*command)); 931 932 while (isspace(*cp)) ++cp; 933 if (*cp == '\0' || *cp == '#') 934 { 935 break; 936 } 937 command->cmd = *cp++; 938 939 /* 940 * Parse args 941 */ 942 while (1) 943 { 944 while (isspace(*cp)) ++cp; 945 if (*cp == '#') 946 { 947 break; /* found comment */ 948 } 949 if (isalpha(*cp)) 950 { 951 command->args[command->n_args].argtype = *cp++; 952 } 953 if (!isdigit(*cp)) 954 { 955 break; /* assume end of line */ 956 } 957 end = NULL; 958 command->args[command->n_args].arg_val = strtol(cp, &end, 0); 959 if (cp == end) 960 { 961 break; /* couldn't parse number */ 962 } 963 cp = end; 964 command->n_args++; 965 } 966 break; 967 } 968} 969 970 971static int 972process_geometry(command) 973 CMD *command; 974{ 975 int status = 1, i; 976 977 while (1) 978 { 979 geom_processed = 1; 980 if (part_processed) 981 { 982 fprintf(stderr, 983 "%s: ERROR line %d: the geometry specification line must occur before\n\ 984 all partition specifications.\n", 985 name, current_line_number); 986 status = 0; 987 break; 988 } 989 if (command->n_args != 3) 990 { 991 fprintf(stderr, 992 "%s: ERROR line %d: incorrect number of geometry args\n", 993 name, current_line_number); 994 status = 0; 995 break; 996 } 997 dos_cyls = -1; 998 dos_heads = -1; 999 dos_sectors = -1; 1000 for (i = 0; i < 3; ++i) 1001 { 1002 switch (command->args[i].argtype) 1003 { 1004 case 'c': 1005 dos_cyls = command->args[i].arg_val; 1006 break; 1007 case 'h': 1008 dos_heads = command->args[i].arg_val; 1009 break; 1010 case 's': 1011 dos_sectors = command->args[i].arg_val; 1012 break; 1013 default: 1014 fprintf(stderr, 1015 "%s: ERROR line %d: unknown geometry arg type: '%c' (0x%02x)\n", 1016 name, current_line_number, command->args[i].argtype, 1017 command->args[i].argtype); 1018 status = 0; 1019 break; 1020 } 1021 } 1022 if (status == 0) 1023 { 1024 break; 1025 } 1026 1027 dos_cylsecs = dos_heads * dos_sectors; 1028 1029 /* 1030 * Do sanity checks on parameter values 1031 */ 1032 if (dos_cyls < 0) 1033 { 1034 fprintf(stderr, 1035 "%s: ERROR line %d: number of cylinders not specified\n", 1036 name, current_line_number); 1037 status = 0; 1038 } 1039 if (dos_cyls == 0 || dos_cyls > 1024) 1040 { 1041 fprintf(stderr, 1042 "%s: WARNING line %d: number of cylinders (%d) may be out-of-range\n\ 1043 (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\ 1044 is dedicated to FreeBSD).\n", 1045 name, current_line_number, dos_cyls); 1046 } 1047 1048 if (dos_heads < 0) 1049 { 1050 fprintf(stderr, 1051 "%s: ERROR line %d: number of heads not specified\n", 1052 name, current_line_number); 1053 status = 0; 1054 } 1055 else if (dos_heads < 1 || dos_heads > 256) 1056 { 1057 fprintf(stderr, 1058 "%s: ERROR line %d: number of heads must be within (1-256)\n", 1059 name, current_line_number); 1060 status = 0; 1061 } 1062 1063 if (dos_sectors < 0) 1064 { 1065 fprintf(stderr, "%s: ERROR line %d: number of sectors not specified\n", 1066 name, current_line_number); 1067 status = 0; 1068 } 1069 else if (dos_sectors < 1 || dos_sectors > 63) 1070 { 1071 fprintf(stderr, 1072 "%s: ERROR line %d: number of sectors must be within (1-63)\n", 1073 name, current_line_number); 1074 status = 0; 1075 } 1076 1077 break; 1078 } 1079 return (status); 1080} 1081 1082 1083static int 1084process_partition(command) 1085 CMD *command; 1086{ 1087 int status = 0, partition; 1088 unsigned long chunks, adj_size, max_end; 1089 struct dos_partition *partp; 1090 1091 while (1) 1092 { 1093 part_processed = 1; 1094 if (command->n_args != 4) 1095 { 1096 fprintf(stderr, 1097 "%s: ERROR line %d: incorrect number of partition args\n", 1098 name, current_line_number); 1099 break; 1100 } 1101 partition = command->args[0].arg_val; 1102 if (partition < 1 || partition > 4) 1103 { 1104 fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n", 1105 name, current_line_number, partition); 1106 break; 1107 } 1108 partp = ((struct dos_partition *) &mboot.parts) + partition - 1; 1109 bzero((char *)partp, sizeof (struct dos_partition)); 1110 partp->dp_typ = command->args[1].arg_val; 1111 partp->dp_start = command->args[2].arg_val; 1112 partp->dp_size = command->args[3].arg_val; 1113 max_end = partp->dp_start + partp->dp_size; 1114 1115 if (partp->dp_typ == 0) 1116 { 1117 /* 1118 * Get out, the partition is marked as unused. 1119 */ 1120 /* 1121 * Insure that it's unused. 1122 */ 1123 bzero((char *)partp, sizeof (struct dos_partition)); 1124 status = 1; 1125 break; 1126 } 1127 1128 /* 1129 * Adjust start upwards, if necessary, to fall on an head boundary. 1130 */ 1131 if (partp->dp_start % dos_sectors != 0) 1132 { 1133 adj_size = 1134 (partp->dp_start / dos_sectors + 1) * dos_sectors; 1135 if (adj_size > max_end) 1136 { 1137 /* 1138 * Can't go past end of partition 1139 */ 1140 fprintf(stderr, 1141 "%s: ERROR line %d: unable to adjust start of partition %d to fall on\n\ 1142 a cylinder boundary.\n", 1143 name, current_line_number, partition); 1144 break; 1145 } 1146 fprintf(stderr, 1147 "%s: WARNING: adjusting start offset of partition '%d' from %d\n\ 1148 to %d, to round to an head boundary.\n", 1149 name, partition, partp->dp_start, adj_size); 1150 partp->dp_start = adj_size; 1151 } 1152 1153 /* 1154 * Adjust size downwards, if necessary, to fall on a cylinder 1155 * boundary. 1156 */ 1157 chunks = 1158 ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; 1159 adj_size = chunks - partp->dp_start; 1160 if (adj_size != partp->dp_size) 1161 { 1162 fprintf(stderr, 1163 "%s: WARNING: adjusting size of partition '%d' from %d to %d,\n\ 1164 to round to a cylinder boundary.\n", 1165 name, partition, partp->dp_size, adj_size); 1166 if (chunks > 0) 1167 { 1168 partp->dp_size = adj_size; 1169 } 1170 else 1171 { 1172 partp->dp_size = 0; 1173 } 1174 } 1175 if (partp->dp_size < 1) 1176 { 1177 fprintf(stderr, 1178 "%s: ERROR line %d: size for partition '%d' is zero.\n", 1179 name, current_line_number, partition); 1180 break; 1181 } 1182 1183 dos(partp->dp_start, partp->dp_size, 1184 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 1185 dos(partp->dp_start+partp->dp_size - 1, partp->dp_size, 1186 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 1187 status = 1; 1188 break; 1189 } 1190 return (status); 1191} 1192 1193 1194static int 1195process_active(command) 1196 CMD *command; 1197{ 1198 int status = 0, partition, i; 1199 struct dos_partition *partp; 1200 1201 while (1) 1202 { 1203 active_processed = 1; 1204 if (command->n_args != 1) 1205 { 1206 fprintf(stderr, 1207 "%s: ERROR line %d: incorrect number of active args\n", 1208 name, current_line_number); 1209 status = 0; 1210 break; 1211 } 1212 partition = command->args[0].arg_val; 1213 if (partition < 1 || partition > 4) 1214 { 1215 fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n", 1216 name, current_line_number, partition); 1217 break; 1218 } 1219 /* 1220 * Reset active partition 1221 */ 1222 partp = ((struct dos_partition *) &mboot.parts); 1223 for (i = 0; i < NDOSPART; i++) 1224 partp[i].dp_flag = 0; 1225 partp[partition-1].dp_flag = ACTIVE; 1226 1227 status = 1; 1228 break; 1229 } 1230 return (status); 1231} 1232 1233 1234static int 1235process_line(line) 1236 char *line; 1237{ 1238 CMD command; 1239 int status = 1; 1240 1241 while (1) 1242 { 1243 parse_config_line(line, &command); 1244 switch (command.cmd) 1245 { 1246 case 0: 1247 /* 1248 * Comment or blank line 1249 */ 1250 break; 1251 case 'g': 1252 /* 1253 * Set geometry 1254 */ 1255 status = process_geometry(&command); 1256 break; 1257 case 'p': 1258 status = process_partition(&command); 1259 break; 1260 case 'a': 1261 status = process_active(&command); 1262 break; 1263 default: 1264 status = 0; 1265 break; 1266 } 1267 break; 1268 } 1269 return (status); 1270} 1271 1272 1273static int 1274read_config(config_file) 1275 char *config_file; 1276{ 1277 FILE *fp = NULL; 1278 int status = 1; 1279 char buf[1010]; 1280 1281 while (1) /* dirty trick used to insure one exit point for this 1282 function */ 1283 { 1284 if (strcmp(config_file, "-") != 0) 1285 { 1286 /* 1287 * We're not reading from stdin 1288 */ 1289 if ((fp = fopen(config_file, "r")) == NULL) 1290 { 1291 status = 0; 1292 break; 1293 } 1294 } 1295 else 1296 { 1297 fp = stdin; 1298 } 1299 current_line_number = 0; 1300 while (!feof(fp)) 1301 { 1302 if (fgets(buf, sizeof(buf), fp) == NULL) 1303 { 1304 break; 1305 } 1306 ++current_line_number; 1307 status = process_line(buf); 1308 if (status == 0) 1309 { 1310 break; 1311 } 1312 } 1313 break; 1314 } 1315 if (fp) 1316 { 1317 /* 1318 * It doesn't matter if we're reading from stdin, as we've reached EOF 1319 */ 1320 fclose(fp); 1321 } 1322 return (status); 1323} 1324 1325 1326static void 1327reset_boot(void) 1328{ 1329 int i; 1330 struct dos_partition *partp; 1331 1332 init_boot(); 1333 for (i = 0; i < 4; ++i) 1334 { 1335 partp = ((struct dos_partition *) &mboot.parts) + i; 1336 bzero((char *)partp, sizeof (struct dos_partition)); 1337 } 1338} 1339