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