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 28 static char rcsid[] = "$Id: fdisk.c,v 1.8 1994/12/05 20:15:41 cgd Exp $"; 29 #endif /* not lint */ 30 31 #include <sys/types.h> 32 #include <sys/disklabel.h> 33 #include <sys/ioctl.h> 34 #include <sys/stat.h> 35 36 #include <ctype.h> 37 #include <err.h> 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #define LBUF 100 45 static char lbuf[LBUF]; 46 47 /* 48 * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University 49 * Copyright (c) 1989 Robert. V. Baron 50 * Created. 51 */ 52 53 char *disk = "/dev/rwd0d"; 54 55 struct disklabel disklabel; /* disk parameters */ 56 57 int cylinders, sectors, heads, cylindersectors, disksectors; 58 59 struct mboot { 60 unsigned char padding[2]; /* force the longs to be long alligned */ 61 unsigned char bootinst[DOSPARTOFF]; 62 struct dos_partition parts[4]; 63 unsigned short int signature; 64 }; 65 struct mboot mboot; 66 67 #define ACTIVE 0x80 68 #define BOOT_MAGIC 0xAA55 69 70 int dos_cylinders; 71 int dos_heads; 72 int dos_sectors; 73 int dos_cylindersectors; 74 75 #define DOSSECT(s,c) (((s) & 0x3f) | (((c) >> 2) & 0xc0)) 76 #define DOSCYL(c) ((c) & 0xff) 77 int partition = -1; 78 79 int a_flag; /* set active partition */ 80 int i_flag; /* replace partition data */ 81 int u_flag; /* update partition data */ 82 83 unsigned char bootcode[] = { 84 0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf, 85 0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe, 86 0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd, 87 0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74, 88 0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00, 89 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe, 90 0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00, 91 0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10, 92 0xeb, 0xf4, 0xfb, 0xeb, 0xfe, 93 'M', 'i', 's', 's', 'i', 'n', 'g', ' ', 94 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0, 95 'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ', 96 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0, 97 'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ', 98 'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0, 99 'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ', 100 'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0, 101 102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 115 }; 116 117 struct part_type { 118 int type; 119 char *name; 120 } part_types[] = { 121 {0x00, "unused"}, 122 {0x01, "Primary DOS with 12 bit FAT"}, 123 {0x02, "XENIX / filesystem"}, 124 {0x03, "XENIX /usr filesystem"}, 125 {0x04, "Primary DOS with 16 bit FAT"}, 126 {0x05, "Extended DOS"}, 127 {0x06, "Primary 'big' DOS (> 32MB)"}, 128 {0x07, "OS/2 HPFS, QNX or Advanced UNIX"}, 129 {0x08, "AIX filesystem"}, 130 {0x09, "AIX boot partition or Coherent"}, 131 {0x0A, "OS/2 Boot Manager or OPUS"}, 132 {0x10, "OPUS"}, 133 {0x40, "VENIX 286"}, 134 {0x50, "DM"}, 135 {0x51, "DM"}, 136 {0x52, "CP/M or Microport SysV/AT"}, 137 {0x56, "GB"}, 138 {0x61, "Speed"}, 139 {0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}, 140 {0x64, "Novell Netware 2.xx"}, 141 {0x65, "Novell Netware 3.xx"}, 142 {0x75, "PCIX"}, 143 {0x80, "Minix 1.1 ... 1.4a"}, 144 {0x81, "Minix 1.4b ... 1.5.10"}, 145 {0x82, "Linux"}, 146 {0x93, "Amoeba filesystem"}, 147 {0x94, "Amoeba bad block table"}, 148 {0xA5, "NetBSD"}, 149 {0xB7, "BSDI BSD/386 filesystem"}, 150 {0xB8, "BSDI BSD/386 swap"}, 151 {0xDB, "Concurrent CPM or C.DOS or CTOS"}, 152 {0xE1, "Speed"}, 153 {0xE3, "Speed"}, 154 {0xE4, "Speed"}, 155 {0xF1, "Speed"}, 156 {0xF2, "DOS 3.3+ Secondary"}, 157 {0xF4, "Speed"}, 158 {0xFF, "BBT (Bad Blocks Table)"}, 159 }; 160 161 void usage __P((void)); 162 void print_s0 __P((int)); 163 void print_part __P((int)); 164 void init_sector0 __P((int)); 165 void change_part __P((int)); 166 void print_params __P((void)); 167 void change_active __P((int)); 168 void get_params_to_use __P((void)); 169 void dos __P((int, unsigned char *, unsigned char *, unsigned char *)); 170 int open_disk __P((int)); 171 int read_disk __P((int, void *)); 172 int write_disk __P((int, void *)); 173 int get_params __P((void)); 174 int read_s0 __P((void)); 175 int write_s0 __P((void)); 176 int yesno __P((char *)); 177 void decimal __P((char *, int *)); 178 int type_match __P((const void *, const void *)); 179 char *get_type __P((int)); 180 181 int 182 main(argc, argv) 183 int argc; 184 char *argv[]; 185 { 186 int ch; 187 int part; 188 189 a_flag = i_flag = u_flag = 0; 190 while ((ch = getopt(argc, argv, "0123aiu")) != -1) 191 switch (ch) { 192 case '0': 193 partition = 0; 194 break; 195 case '1': 196 partition = 1; 197 break; 198 case '2': 199 partition = 2; 200 break; 201 case '3': 202 partition = 3; 203 break; 204 case 'a': 205 a_flag = 1; 206 break; 207 case 'i': 208 i_flag = 1; 209 case 'u': 210 u_flag = 1; 211 break; 212 default: 213 usage(); 214 } 215 argc -= optind; 216 argv += optind; 217 218 if (argc > 0) 219 disk = argv[0]; 220 221 if (open_disk(a_flag || i_flag || u_flag) < 0) 222 exit(1); 223 224 printf("******* Working on device %s *******\n", disk); 225 if (u_flag) 226 get_params_to_use(); 227 else 228 print_params(); 229 230 if (read_s0()) 231 init_sector0(1); 232 233 printf("Warning: BIOS sector numbering starts with sector 1\n"); 234 printf("Information from DOS bootblock is:\n"); 235 if (partition == -1) { 236 for (part = 0; part < NDOSPART; part++) 237 change_part(part); 238 } else 239 change_part(partition); 240 241 if (u_flag || a_flag) 242 change_active(partition); 243 244 if (u_flag || a_flag) { 245 printf("\nWe haven't changed the partition table yet. "); 246 printf("This is your last chance.\n"); 247 print_s0(-1); 248 if (yesno("Should we write new partition table?")) 249 write_s0(); 250 } 251 252 exit(0); 253 } 254 255 void 256 usage() 257 { 258 259 (void)fprintf(stderr, "usage: fdisk [-aiu] [-0|-1|-2|-3] [device]\n"); 260 exit(1); 261 } 262 263 void 264 print_s0(which) 265 int which; 266 { 267 int part; 268 269 print_params(); 270 printf("Information from DOS bootblock is:\n"); 271 if (which == -1) { 272 for (part = 0; part < NDOSPART; part++) 273 printf("%d: ", part), print_part(part); 274 } else 275 print_part(which); 276 } 277 278 static struct dos_partition mtpart = { 0 }; 279 280 void 281 print_part(part) 282 int part; 283 { 284 struct dos_partition *partp; 285 286 partp = &mboot.parts[part]; 287 if (!memcmp(partp, &mtpart, sizeof(struct dos_partition))) { 288 printf("<UNUSED>\n"); 289 return; 290 } 291 printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ)); 292 printf(" start %d, size %d (%d MB), flag %x\n", 293 partp->dp_start, partp->dp_size, 294 partp->dp_size * 512 / (1024 * 1024), partp->dp_flag); 295 printf("\tbeg: cylinder %4d, head %3d, sector %2d\n", 296 DPCYL(partp->dp_scyl, partp->dp_ssect), 297 partp->dp_shd, DPSECT(partp->dp_ssect)); 298 printf("\tend: cylinder %4d, head %3d, sector %2d\n", 299 DPCYL(partp->dp_ecyl, partp->dp_esect), 300 partp->dp_ehd, DPSECT(partp->dp_esect)); 301 } 302 303 void 304 init_sector0(start) 305 int start; 306 { 307 struct dos_partition *partp; 308 309 memcpy(mboot.bootinst, bootcode, sizeof(bootcode)); 310 mboot.signature = BOOT_MAGIC; 311 312 partp = &mboot.parts[3]; 313 partp->dp_typ = DOSPTYP_386BSD; 314 partp->dp_flag = ACTIVE; 315 partp->dp_start = start; 316 partp->dp_size = disksectors - start; 317 318 dos(partp->dp_start, 319 &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect); 320 dos(partp->dp_start + partp->dp_size - 1, 321 &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect); 322 } 323 324 void 325 change_part(part) 326 int part; 327 { 328 struct dos_partition *partp; 329 330 partp = &mboot.parts[part]; 331 332 printf("The data for partition %d is:\n", part); 333 print_part(part); 334 335 if (!u_flag || !yesno("Do you want to change it?")) 336 return; 337 338 if (i_flag) { 339 memset(partp, 0, sizeof(*partp)); 340 if (part == 3) { 341 init_sector0(1); 342 printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n"); 343 print_part(part); 344 } 345 } 346 347 do { 348 { 349 int sysid, start, size; 350 351 sysid = partp->dp_typ, 352 start = partp->dp_start, 353 size = partp->dp_size; 354 decimal("sysid", &sysid); 355 decimal("start", &start); 356 decimal("size", &size); 357 partp->dp_typ = sysid; 358 partp->dp_start = start; 359 partp->dp_size = size; 360 } 361 362 if (yesno("Explicitly specify beg/end address?")) { 363 int tsector, tcylinder, thead; 364 365 tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect); 366 thead = partp->dp_shd; 367 tsector = DPSECT(partp->dp_ssect); 368 decimal("beginning cylinder", &tcylinder); 369 decimal("beginning head", &thead); 370 decimal("beginning sector", &tsector); 371 partp->dp_scyl = DOSCYL(tcylinder); 372 partp->dp_shd = thead; 373 partp->dp_ssect = DOSSECT(tsector, tcylinder); 374 375 tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect); 376 thead = partp->dp_ehd; 377 tsector = DPSECT(partp->dp_esect); 378 decimal("ending cylinder", &tcylinder); 379 decimal("ending head", &thead); 380 decimal("ending sector", &tsector); 381 partp->dp_ecyl = DOSCYL(tcylinder); 382 partp->dp_ehd = thead; 383 partp->dp_esect = DOSSECT(tsector, tcylinder); 384 } else { 385 dos(partp->dp_start, 386 &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect); 387 dos(partp->dp_start + partp->dp_size - 1, 388 &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect); 389 } 390 391 print_part(part); 392 } while (!yesno("Is this entry okay?")); 393 } 394 395 void 396 print_params() 397 { 398 399 printf("parameters extracted from in-core disklabel are:\n"); 400 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n", 401 cylinders, heads, sectors, cylindersectors); 402 if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255) 403 printf("Figures below won't work with BIOS for partitions not in cylinder 1\n"); 404 printf("parameters to be used for BIOS calculations are:\n"); 405 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n", 406 dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors); 407 } 408 409 void 410 change_active(which) 411 int which; 412 { 413 struct dos_partition *partp; 414 int part; 415 int active = 3; 416 417 partp = &mboot.parts[0]; 418 419 if (a_flag && which != -1) 420 active = which; 421 else { 422 for (part = 0; part < NDOSPART; part++) 423 if (partp[part].dp_flag & ACTIVE) 424 active = part; 425 } 426 if (yesno("Do you want to change the active partition?")) { 427 do { 428 decimal("active partition", &active); 429 } while (!yesno("Are you happy with this choice?")); 430 } 431 for (part = 0; part < NDOSPART; part++) 432 partp[part].dp_flag &= ~ACTIVE; 433 partp[active].dp_flag |= ACTIVE; 434 } 435 436 void 437 get_params_to_use() 438 { 439 440 print_params(); 441 if (yesno("Do you want to change our idea of what BIOS thinks?")) { 442 do { 443 decimal("BIOS's idea of #cylinders", &dos_cylinders); 444 decimal("BIOS's idea of #heads", &dos_heads); 445 decimal("BIOS's idea of #sectors", &dos_sectors); 446 dos_cylindersectors = dos_heads * dos_sectors; 447 print_params(); 448 } while (!yesno("Are you happy with this choice?")); 449 } 450 } 451 452 /***********************************************\ 453 * Change real numbers into strange dos numbers * 454 \***********************************************/ 455 void 456 dos(sector, cylinderp, headp, sectorp) 457 int sector; 458 unsigned char *cylinderp, *headp, *sectorp; 459 { 460 int cylinder, head; 461 462 cylinder = sector / dos_cylindersectors; 463 sector -= cylinder * dos_cylindersectors; 464 465 head = sector / dos_sectors; 466 sector -= head * dos_sectors; 467 468 *cylinderp = DOSCYL(cylinder); 469 *headp = head; 470 *sectorp = DOSSECT(sector + 1, cylinder); 471 } 472 473 int fd; 474 475 int 476 open_disk(u_flag) 477 int u_flag; 478 { 479 struct stat st; 480 481 if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) { 482 warn("%s", disk); 483 return (-1); 484 } 485 if (fstat(fd, &st) == -1) { 486 close(fd); 487 warn("%s", disk); 488 return (-1); 489 } 490 if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) { 491 close(fd); 492 warnx("%s is not a character device or regular file", disk); 493 return (-1); 494 } 495 if (get_params() == -1) { 496 close(fd); 497 return (-1); 498 } 499 return (0); 500 } 501 502 int 503 read_disk(sector, buf) 504 int sector; 505 void *buf; 506 { 507 508 if (lseek(fd, (off_t)(sector * 512), 0) == -1) 509 return (-1); 510 return (read(fd, buf, 512)); 511 } 512 513 int 514 write_disk(sector, buf) 515 int sector; 516 void *buf; 517 { 518 519 if (lseek(fd, (off_t)(sector * 512), 0) == -1) 520 return (-1); 521 return (write(fd, buf, 512)); 522 } 523 524 int 525 get_params() 526 { 527 528 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 529 warn("DIOCGDINFO"); 530 return (-1); 531 } 532 533 dos_cylinders = cylinders = disklabel.d_ncylinders; 534 dos_heads = heads = disklabel.d_ntracks; 535 dos_sectors = sectors = disklabel.d_nsectors; 536 dos_cylindersectors = cylindersectors = heads * sectors; 537 disksectors = cylinders * heads * sectors; 538 539 return (0); 540 } 541 542 int 543 read_s0() 544 { 545 546 if (read_disk(0, mboot.bootinst) == -1) { 547 warn("can't read fdisk partition table"); 548 return (-1); 549 } 550 if (mboot.signature != BOOT_MAGIC) { 551 warn("invalid fdisk partition table found"); 552 /* So should we initialize things? */ 553 return (-1); 554 } 555 return (0); 556 } 557 558 int 559 write_s0() 560 { 561 int flag; 562 563 /* 564 * write enable label sector before write (if necessary), 565 * disable after writing. 566 * needed if the disklabel protected area also protects 567 * sector 0. (e.g. empty disk) 568 */ 569 flag = 1; 570 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 571 warn("DIOCWLABEL"); 572 if (write_disk(0, mboot.bootinst) == -1) { 573 warn("can't write fdisk partition table"); 574 return -1; 575 } 576 flag = 0; 577 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 578 warn("DIOCWLABEL"); 579 } 580 581 int 582 yesno(str) 583 char *str; 584 { 585 int ch, first; 586 587 printf("%s [n] ", str); 588 589 first = ch = getchar(); 590 while (ch != '\n' && ch != EOF) 591 ch = getchar(); 592 return (first == 'y' || first == 'Y'); 593 } 594 595 void 596 decimal(str, num) 597 char *str; 598 int *num; 599 { 600 int acc = 0; 601 char *cp; 602 603 for (;; printf("%s is not a valid decimal number.\n", lbuf)) { 604 printf("Supply a decimal value for \"%s\" [%d] ", str, *num); 605 606 fgets(lbuf, LBUF, stdin); 607 lbuf[strlen(lbuf)-1] = '\0'; 608 cp = lbuf; 609 610 cp += strspn(cp, " \t"); 611 if (*cp == '\0') 612 return; 613 614 if (!isdigit(*cp)) 615 continue; 616 acc = strtol(lbuf, &cp, 10); 617 618 cp += strspn(cp, " \t"); 619 if (*cp != '\0') 620 continue; 621 622 *num = acc; 623 return; 624 } 625 626 } 627 628 int 629 type_match(key, item) 630 const void *key, *item; 631 { 632 const int *typep = key; 633 const struct part_type *ptr = item; 634 635 if (*typep < ptr->type) 636 return (-1); 637 if (*typep > ptr->type) 638 return (1); 639 return (0); 640 } 641 642 char * 643 get_type(type) 644 int type; 645 { 646 struct part_type *ptr; 647 648 ptr = bsearch(&type, part_types, 649 sizeof(part_types) / sizeof(struct part_type), 650 sizeof(struct part_type), type_match); 651 if (ptr == 0) 652 return ("unknown"); 653 else 654 return (ptr->name); 655 } 656