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