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