1 // 2 // pdisk - an editor for Apple format partition tables 3 // 4 // Written by Eryk Vershen (eryk@apple.com) 5 // 6 // Still under development (as of 15 January 1998) 7 // 8 9 /* 10 * Copyright 1996,1997,1998 by Apple Computer, Inc. 11 * All Rights Reserved 12 * 13 * Permission to use, copy, modify, and distribute this software and 14 * its documentation for any purpose and without fee is hereby granted, 15 * provided that the above copyright notice appears in all copies and 16 * that both the copyright notice and this permission notice appear in 17 * supporting documentation. 18 * 19 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 20 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 * FOR A PARTICULAR PURPOSE. 22 * 23 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 24 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 25 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 26 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 27 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 28 */ 29 30 // for printf() 31 #include <stdio.h> 32 33 #ifdef __linux__ 34 #include <getopt.h> 35 #include <malloc.h> 36 #elif defined(__OpenBSD__) 37 #include <stdlib.h> 38 #else 39 // for malloc() & free() 40 #include <stdlib.h> 41 // for SIOUXsettings 42 #include <SIOUX.h> 43 #endif 44 45 // for strncpy() & strlen() 46 #include <string.h> 47 // for O_RDONLY 48 #include <fcntl.h> 49 // for errno 50 #include <errno.h> 51 52 #ifdef __linux__ 53 #include <sys/ioctl.h> 54 #include <linux/fs.h> 55 #include <linux/hdreg.h> 56 #endif 57 58 #include "pdisk.h" 59 #include "io.h" 60 #include "partition_map.h" 61 #include "pathname.h" 62 #include "errors.h" 63 #include "dump.h" 64 #include "validate.h" 65 #include "version.h" 66 #include "util.h" 67 68 69 // 70 // Defines 71 // 72 #define ARGV_CHUNK 5 73 #define CFLAG_DEFAULT 0 74 #define DFLAG_DEFAULT 0 75 #define HFLAG_DEFAULT 0 76 #define INTERACT_DEFAULT 0 77 #define LFLAG_DEFAULT 0 78 #define RFLAG_DEFAULT 0 79 #define VFLAG_DEFAULT 0 80 81 82 // 83 // Types 84 // 85 86 87 // 88 // Global Constants 89 // 90 enum getopt_values { 91 kLongOption = 0, 92 kBadOption = '?', 93 kOptionArg = 1000, 94 kListOption = 1001, 95 kLogicalOption = 1002 96 }; 97 98 99 // 100 // Global Variables 101 // 102 int lflag = LFLAG_DEFAULT; /* list the device */ 103 char *lfile; /* list */ 104 int vflag = VFLAG_DEFAULT; /* show version */ 105 int hflag = HFLAG_DEFAULT; /* show help */ 106 int dflag = DFLAG_DEFAULT; /* turn on debugging commands and printout */ 107 int rflag = RFLAG_DEFAULT; /* open device read Only */ 108 int interactive = INTERACT_DEFAULT; 109 int cflag = CFLAG_DEFAULT; /* compute device size */ 110 111 static int first_get = 1; 112 113 114 // 115 // Forward declarations 116 // 117 void do_change_map_size(partition_map_header *map); 118 void do_create_partition(partition_map_header *map, int get_type); 119 void do_delete_partition(partition_map_header *map); 120 void do_display_block(partition_map_header *map, char *alt_name); 121 void do_display_entry(partition_map_header *map); 122 void do_examine_patch_partition(partition_map_header *map); 123 int do_expert(partition_map_header *map, char *name); 124 void do_rename_partition(partition_map_header *map); 125 void do_reorder(partition_map_header *map); 126 void do_write_partition_map(partition_map_header *map); 127 void edit(char *name, int ask_logical_size); 128 int get_base_argument(long *number, partition_map_header *map); 129 int get_command_line(int *argc, char ***argv); 130 int get_size_argument(long *number, partition_map_header *map); 131 int get_options(int argc, char **argv); 132 void interact(); 133 void print_edit_notes(); 134 void print_expert_notes(); 135 void print_top_notes(); 136 137 138 // 139 // Routines 140 // 141 int 142 main(int argc, char **argv) 143 { 144 #if defined(__linux__) || defined (__OpenBSD__) 145 int name_index; 146 #else 147 printf("This app uses the SIOUX console library\n"); 148 printf("Choose 'Quit' from the file menu to quit.\n\n"); 149 printf("Use fake disk names (/dev/scsi<bus>.<id>; i.e. /dev/scsi0.1, /dev/scsi1.3, etc.).\n\n"); 150 151 SIOUXSettings.autocloseonquit = 0; /* Do we close the SIOUX window on program termination ... */ 152 SIOUXSettings.asktosaveonclose = 0; /* Do we offer to save on a close ... */ 153 #endif 154 155 init_program_name(argv); 156 157 if (sizeof(DPME) != PBLOCK_SIZE) { 158 fatal(-1, "Size of partion map entry (%d) " 159 "is not equal to block size (%d)\n", 160 sizeof(DPME), PBLOCK_SIZE); 161 } 162 if (sizeof(Block0) != PBLOCK_SIZE) { 163 fatal(-1, "Size of block zero structure (%d) " 164 "is not equal to block size (%d)\n", 165 sizeof(Block0), PBLOCK_SIZE); 166 } 167 if (strcmp(VERSION, get_version_string()) != 0) { 168 fatal(-1, "Version string static form (%s) does not match dynamic form (%s)\n", 169 VERSION, get_version_string()); 170 } 171 172 #if defined(__linux__) || defined(__OpenBSD__) 173 name_index = get_options(argc, argv); 174 175 if (vflag) { 176 printf("version " VERSION " (" RELEASE_DATE ")\n"); 177 } 178 if (hflag) { 179 do_help(); 180 } else if (interactive) { 181 interact(); 182 } else if (lflag) { 183 if (lfile != NULL) { 184 dump(lfile); 185 } else if (name_index < argc) { 186 while (name_index < argc) { 187 dump(argv[name_index++]); 188 } 189 } else { 190 list_all_disks(); 191 } 192 } else if (name_index < argc) { 193 while (name_index < argc) { 194 edit(argv[name_index++], 0); 195 } 196 } else if (!vflag) { 197 usage("no device argument"); 198 do_help(); 199 } 200 return 0; 201 #else 202 interactive = 1; 203 204 interact(); 205 206 SIOUXSettings.autocloseonquit = 1; 207 //printf("Processing stopped: Choose 'Quit' from the file menu to quit.\n\n"); 208 return (0); 209 #endif 210 } 211 212 213 void 214 print_top_notes() 215 { 216 printf("Notes:\n"); 217 printf(" Disks have fake names of the form /dev/scsi<bus>.<id>\n"); 218 printf(" For example, /dev/scsi0.1, /dev/scsi1.3, and so on.\n"); 219 printf(" MkLinux style names are also allowed (i.e /dev/sda or /dev/hda),\n"); 220 printf(" and these names follow the MkLinux DR3 conventions.\n"); 221 printf("\n"); 222 } 223 224 225 void 226 interact() 227 { 228 char *name; 229 int command; 230 int ask_logical_size; 231 232 while (get_command("Top level command (? for help): ", first_get, &command)) { 233 first_get = 0; 234 ask_logical_size = 0; 235 236 switch (command) { 237 case '?': 238 print_top_notes(); 239 // fall through 240 case 'H': 241 case 'h': 242 printf("Commands are:\n"); 243 printf(" h print help\n"); 244 printf(" v print the version number and release date\n"); 245 printf(" l list device's map\n"); 246 printf(" L list all devices' maps\n"); 247 printf(" e edit device's map\n"); 248 printf(" E (edit map with specified block size)\n"); 249 printf(" r toggle readonly flag\n"); 250 if (dflag) { 251 printf(" a toggle abbreviate flag\n"); 252 printf(" p toggle physical flag\n"); 253 printf(" c toggle compute size flag\n"); 254 printf(" d toggle debug flag\n"); 255 printf(" x examine block n of device\n"); 256 } 257 printf(" q quit the program\n"); 258 break; 259 case 'Q': 260 case 'q': 261 return; 262 break; 263 case 'V': 264 case 'v': 265 printf("version " VERSION " (" RELEASE_DATE ")\n"); 266 break; 267 case 'L': 268 list_all_disks(); 269 break; 270 case 'l': 271 if (get_string_argument("Name of device: ", &name, 1) == 0) { 272 bad_input("Bad name"); 273 break; 274 } 275 dump(name); 276 free(name); 277 break; 278 case 'E': 279 ask_logical_size = 1; 280 case 'e': 281 if (get_string_argument("Name of device: ", &name, 1) == 0) { 282 bad_input("Bad name"); 283 break; 284 } 285 edit(name, ask_logical_size); 286 free(name); 287 break; 288 case 'R': 289 case 'r': 290 if (rflag) { 291 rflag = 0; 292 } else { 293 rflag = 1; 294 } 295 printf("Now in %s mode.\n", (rflag)?"readonly":"read/write"); 296 break; 297 case 'A': 298 case 'a': 299 if (dflag) { 300 if (aflag) { 301 aflag = 0; 302 } else { 303 aflag = 1; 304 } 305 printf("Now in %s mode.\n", (aflag)?"abbreviate":"full type"); 306 } else { 307 goto do_error; 308 } 309 break; 310 case 'P': 311 case 'p': 312 if (dflag) { 313 if (pflag) { 314 pflag = 0; 315 } else { 316 pflag = 1; 317 } 318 printf("Now in %s mode.\n", (pflag)?"physical":"logical"); 319 } else { 320 goto do_error; 321 } 322 break; 323 case 'D': 324 case 'd': 325 if (dflag) { 326 dflag = 0; 327 } else { 328 dflag = 1; 329 } 330 printf("Now in %s mode.\n", (dflag)?"debug":"normal"); 331 break; 332 case 'C': 333 case 'c': 334 if (dflag) { 335 if (cflag) { 336 cflag = 0; 337 } else { 338 cflag = 1; 339 } 340 printf("Now in %s device size mode.\n", (cflag)?"always compute":"use existing"); 341 } else { 342 goto do_error; 343 } 344 break; 345 case 'X': 346 case 'x': 347 if (dflag) { 348 do_display_block(0, 0); 349 } else { 350 goto do_error; 351 } 352 break; 353 default: 354 do_error: 355 bad_input("No such command (%c)", command); 356 break; 357 } 358 } 359 } 360 361 362 #ifdef __linux__ 363 int 364 get_options(int argc, char **argv) 365 { 366 int c; 367 static struct option long_options[] = 368 { 369 // name has_arg &flag val 370 {"help", no_argument, 0, 'h'}, 371 {"list", optional_argument, 0, kListOption}, 372 {"version", no_argument, 0, 'v'}, 373 {"debug", no_argument, 0, 'd'}, 374 {"readonly", no_argument, 0, 'r'}, 375 {"abbr", no_argument, 0, 'a'}, 376 {"logical", no_argument, 0, kLogicalOption}, 377 {"interactive", no_argument, 0, 'i'}, 378 {"compute_size", no_argument, 0, 'c'}, 379 {0, 0, 0, 0} 380 }; 381 int option_index = 0; 382 extern int optind; 383 extern char *optarg; 384 int flag = 0; 385 386 lflag = LFLAG_DEFAULT; 387 lfile = NULL; 388 vflag = VFLAG_DEFAULT; 389 hflag = HFLAG_DEFAULT; 390 dflag = DFLAG_DEFAULT; 391 rflag = RFLAG_DEFAULT; 392 aflag = AFLAG_DEFAULT; 393 pflag = PFLAG_DEFAULT; 394 interactive = INTERACT_DEFAULT; 395 cflag = CFLAG_DEFAULT; 396 397 optind = 0; // reset option scanner logic 398 while ((c = getopt_long(argc, argv, "hlvdric", long_options, 399 &option_index)) >= 0) { 400 switch (c) { 401 case kLongOption: 402 // option_index would be used here 403 break; 404 case 'h': 405 hflag = (HFLAG_DEFAULT)?0:1; 406 break; 407 case kListOption: 408 if (optarg != NULL) { 409 lfile = optarg; 410 } 411 // fall through 412 case 'l': 413 lflag = (LFLAG_DEFAULT)?0:1; 414 break; 415 case 'v': 416 vflag = (VFLAG_DEFAULT)?0:1; 417 break; 418 case 'd': 419 dflag = (DFLAG_DEFAULT)?0:1; 420 break; 421 case 'c': 422 cflag = (CFLAG_DEFAULT)?0:1; 423 break; 424 case 'r': 425 rflag = (RFLAG_DEFAULT)?0:1; 426 break; 427 case 'i': 428 interactive = (INTERACT_DEFAULT)?0:1; 429 break; 430 case 'a': 431 aflag = (AFLAG_DEFAULT)?0:1; 432 break; 433 case kLogicalOption: 434 pflag = (PFLAG_DEFAULT)?0:1; 435 break; 436 case kBadOption: 437 default: 438 flag = 1; 439 break; 440 } 441 } 442 if (flag) { 443 usage("bad arguments"); 444 } 445 return optind; 446 } 447 #endif 448 449 #ifdef __OpenBSD__ 450 int 451 get_options(int argc, char **argv) 452 { 453 int c; 454 extern int optind; 455 extern char *optarg; 456 int flag = 0; 457 458 lflag = LFLAG_DEFAULT; 459 lfile = NULL; 460 vflag = VFLAG_DEFAULT; 461 hflag = HFLAG_DEFAULT; 462 dflag = DFLAG_DEFAULT; 463 rflag = RFLAG_DEFAULT; 464 aflag = AFLAG_DEFAULT; 465 pflag = PFLAG_DEFAULT; 466 interactive = INTERACT_DEFAULT; 467 cflag = CFLAG_DEFAULT; 468 469 optind = 1; // reset option scanner logic 470 while ((c = getopt(argc, argv, "hlvdric")) != -1) { 471 switch (c) { 472 case 'h': 473 hflag = (HFLAG_DEFAULT)?0:1; 474 break; 475 case 'l': 476 lflag = (LFLAG_DEFAULT)?0:1; 477 break; 478 case 'v': 479 vflag = (VFLAG_DEFAULT)?0:1; 480 break; 481 case 'd': 482 dflag = (DFLAG_DEFAULT)?0:1; 483 break; 484 case 'c': 485 cflag = (CFLAG_DEFAULT)?0:1; 486 break; 487 case 'r': 488 rflag = (RFLAG_DEFAULT)?0:1; 489 break; 490 case 'i': 491 interactive = (INTERACT_DEFAULT)?0:1; 492 break; 493 case 'a': 494 aflag = (AFLAG_DEFAULT)?0:1; 495 break; 496 case kLogicalOption: 497 pflag = (PFLAG_DEFAULT)?0:1; 498 break; 499 default: 500 flag = 1; 501 break; 502 } 503 } 504 if (flag) { 505 usage("bad arguments"); 506 } 507 return optind; 508 } 509 #endif 510 511 512 void 513 print_edit_notes() 514 { 515 printf("Notes:\n"); 516 printf(" Base and length fields are blocks, which vary in size between media.\n"); 517 printf(" The base field can be <nth>p; i.e. use the base of the nth partition.\n"); 518 printf(" The length field can be a length followed by k, m, g or t to indicate\n"); 519 printf(" kilo, mega, giga, or tera bytes; also the length can be <nth>p; i.e. use\n"); 520 printf(" the length of the nth partition.\n"); 521 printf(" The name of a partition is descriptive text.\n"); 522 printf("\n"); 523 } 524 525 526 // 527 // Edit the file 528 // 529 void 530 edit(char *name, int ask_logical_size) 531 { 532 partition_map_header *map; 533 int command; 534 int order; 535 int get_type; 536 int valid_file; 537 538 map = open_partition_map(name, &valid_file, ask_logical_size); 539 if (!valid_file) { 540 return; 541 } 542 543 printf("Edit %s -\n", name); 544 545 while (get_command("Command (? for help): ", first_get, &command)) { 546 first_get = 0; 547 order = 1; 548 get_type = 0; 549 550 switch (command) { 551 case '?': 552 print_edit_notes(); 553 // fall through 554 case 'H': 555 case 'h': 556 printf("Commands are:\n"); 557 printf(" h help\n"); 558 printf(" p print the partition table\n"); 559 printf(" P (print ordered by base address)\n"); 560 printf(" i initialize partition map\n"); 561 printf(" s change size of partition map\n"); 562 printf(" c create new partition (standard MkLinux type)\n"); 563 printf(" C (create with type also specified)\n"); 564 printf(" n (re)name a partition\n"); 565 printf(" d delete a partition\n"); 566 printf(" r reorder partition entry in map\n"); 567 if (!rflag) { 568 printf(" w write the partition table\n"); 569 } 570 printf(" q quit editing (don't save changes)\n"); 571 if (dflag) { 572 printf(" x extra extensions for experts\n"); 573 } 574 break; 575 case 'P': 576 order = 0; 577 // fall through 578 case 'p': 579 dump_partition_map(map, order); 580 break; 581 case 'Q': 582 case 'q': 583 flush_to_newline(1); 584 goto finis; 585 break; 586 case 'I': 587 case 'i': 588 map = init_partition_map(name, map); 589 break; 590 case 'C': 591 get_type = 1; 592 // fall through 593 case 'c': 594 do_create_partition(map, get_type); 595 break; 596 case 'N': 597 case 'n': 598 do_rename_partition(map); 599 break; 600 case 'D': 601 case 'd': 602 do_delete_partition(map); 603 break; 604 case 'R': 605 case 'r': 606 do_reorder(map); 607 break; 608 case 'S': 609 case 's': 610 do_change_map_size(map); 611 break; 612 case 'X': 613 case 'x': 614 if (!dflag) { 615 goto do_error; 616 } else if (do_expert(map, name)) { 617 flush_to_newline(1); 618 goto finis; 619 } 620 break; 621 case 'W': 622 case 'w': 623 if (!rflag) { 624 do_write_partition_map(map); 625 } else { 626 goto do_error; 627 } 628 break; 629 default: 630 do_error: 631 bad_input("No such command (%c)", command); 632 break; 633 } 634 } 635 finis: 636 637 close_partition_map(map); 638 } 639 640 641 void 642 do_create_partition(partition_map_header *map, int get_type) 643 { 644 long base; 645 long length; 646 char *name; 647 char *type_name; 648 649 if (map == NULL) { 650 bad_input("No partition map exists"); 651 return; 652 } 653 if (!rflag && map->writeable == 0) { 654 printf("The map is not writeable.\n"); 655 } 656 // XXX add help feature (i.e. '?' in any argument routine prints help string) 657 if (get_base_argument(&base, map) == 0) { 658 return; 659 } 660 if (get_size_argument(&length, map) == 0) { 661 return; 662 } 663 664 if (get_string_argument("Name of partition: ", &name, 1) == 0) { 665 bad_input("Bad name"); 666 return; 667 } 668 if (get_type == 0) { 669 add_partition_to_map(name, kUnixType, base, length, map); 670 goto xit1; 671 672 } else if (get_string_argument("Type of partition: ", &type_name, 1) == 0) { 673 bad_input("Bad type"); 674 goto xit1; 675 } else { 676 if (istrncmp(type_name, kFreeType, DPISTRLEN) == 0) { 677 bad_input("Can't create a partition with the Free type"); 678 goto xit2; 679 } 680 if (istrncmp(type_name, kMapType, DPISTRLEN) == 0) { 681 bad_input("Can't create a partition with the Map type"); 682 goto xit2; 683 } 684 add_partition_to_map(name, type_name, base, length, map); 685 } 686 xit2: 687 free(type_name); 688 xit1: 689 free(name); 690 return; 691 } 692 693 694 int 695 get_base_argument(long *number, partition_map_header *map) 696 { 697 partition_map * entry; 698 int result = 0; 699 700 if (get_number_argument("First block: ", number, kDefault) == 0) { 701 bad_input("Bad block number"); 702 } else { 703 result = 1; 704 if (get_partition_modifier()) { 705 entry = find_entry_by_disk_address(*number, map); 706 if (entry == NULL) { 707 bad_input("Bad partition number"); 708 result = 0; 709 } else { 710 *number = entry->data->dpme_pblock_start; 711 } 712 } 713 } 714 return result; 715 } 716 717 718 int 719 get_size_argument(long *number, partition_map_header *map) 720 { 721 partition_map * entry; 722 int result = 0; 723 unsigned long multiple; 724 725 if (get_number_argument("Length in blocks: ", number, kDefault) == 0) { 726 bad_input("Bad length"); 727 } else { 728 multiple = get_multiplier(map->logical_block); 729 if (multiple == 0) { 730 bad_input("Bad multiplier"); 731 } else if (multiple != 1) { 732 *number *= multiple; 733 result = 1; 734 } else if (get_partition_modifier()) { 735 entry = find_entry_by_disk_address(*number, map); 736 if (entry == NULL) { 737 bad_input("Bad partition number"); 738 } else { 739 *number = entry->data->dpme_pblocks; 740 result = 1; 741 } 742 } else { 743 result = 1; 744 } 745 } 746 return result; 747 } 748 749 750 void 751 do_rename_partition(partition_map_header *map) 752 { 753 partition_map * entry; 754 long index; 755 char *name; 756 757 if (map == NULL) { 758 bad_input("No partition map exists"); 759 return; 760 } 761 if (!rflag && map->writeable == 0) { 762 printf("The map is not writeable.\n"); 763 } 764 if (get_number_argument("Partition number: ", &index, kDefault) == 0) { 765 bad_input("Bad partition number"); 766 return; 767 } 768 if (get_string_argument("New name of partition: ", &name, 1) == 0) { 769 bad_input("Bad name"); 770 return; 771 } 772 773 // find partition and change it 774 entry = find_entry_by_disk_address(index, map); 775 if (entry == NULL) { 776 printf("No such partition\n"); 777 } else { 778 // stuff name into partition map entry data 779 strncpy(entry->data->dpme_name, name, DPISTRLEN); 780 map->changed = 1; 781 } 782 free(name); 783 return; 784 } 785 786 787 void 788 do_delete_partition(partition_map_header *map) 789 { 790 partition_map * cur; 791 long index; 792 793 if (map == NULL) { 794 bad_input("No partition map exists"); 795 return; 796 } 797 if (!rflag && map->writeable == 0) { 798 printf("The map is not writeable.\n"); 799 } 800 if (get_number_argument("Partition number: ", &index, kDefault) == 0) { 801 bad_input("Bad partition number"); 802 return; 803 } 804 805 // find partition and delete it 806 cur = find_entry_by_disk_address(index, map); 807 if (cur == NULL) { 808 printf("No such partition\n"); 809 } else { 810 delete_partition_from_map(cur); 811 } 812 } 813 814 815 void 816 do_reorder(partition_map_header *map) 817 { 818 long old_index; 819 long index; 820 821 if (map == NULL) { 822 bad_input("No partition map exists"); 823 return; 824 } 825 if (!rflag && map->writeable == 0) { 826 printf("The map is not writeable.\n"); 827 } 828 if (get_number_argument("Partition number: ", &old_index, kDefault) == 0) { 829 bad_input("Bad partition number"); 830 return; 831 } 832 if (get_number_argument("New number: ", &index, kDefault) == 0) { 833 bad_input("Bad partition number"); 834 return; 835 } 836 837 move_entry_in_map(old_index, index, map); 838 } 839 840 841 void 842 do_write_partition_map(partition_map_header *map) 843 { 844 if (map == NULL) { 845 bad_input("No partition map exists"); 846 return; 847 } 848 if (map->changed == 0) { 849 bad_input("The map has not been changed."); 850 return; 851 } 852 if (map->writeable == 0) { 853 bad_input("The map is not writeable."); 854 return; 855 } 856 printf("Writing the map destroys what was there before. "); 857 if (get_okay("Is that okay? [n/y]: ", 0) != 1) { 858 return; 859 } 860 861 write_partition_map(map); 862 863 // exit(0); 864 } 865 866 867 void 868 print_expert_notes() 869 { 870 printf("Notes:\n"); 871 printf(" The expert commands are for low level and experimental features.\n"); 872 printf(" These commands are available only when debug mode is on.\n"); 873 printf("\n"); 874 } 875 876 877 int 878 do_expert(partition_map_header *map, char *name) 879 { 880 int command; 881 int quit = 0; 882 883 while (get_command("Expert command (? for help): ", first_get, &command)) { 884 first_get = 0; 885 886 switch (command) { 887 case '?': 888 print_expert_notes(); 889 // fall through 890 case 'H': 891 case 'h': 892 printf("Commands are:\n"); 893 printf(" h print help\n"); 894 printf(" d dump block n\n"); 895 printf(" p print the partition table\n"); 896 if (dflag) { 897 printf(" P (show data structures - debugging)\n"); 898 } 899 printf(" f full display of nth entry\n"); 900 printf(" v validate map\n"); 901 printf(" e examine patch partition\n"); 902 printf(" q return to main edit menu\n"); 903 printf(" Q quit without saving changes\n"); 904 break; 905 case 'q': 906 flush_to_newline(1); 907 goto finis; 908 break; 909 case 'Q': 910 quit = 1; 911 goto finis; 912 break; 913 case 'P': 914 if (dflag) { 915 show_data_structures(map); 916 break; 917 } 918 // fall through 919 case 'p': 920 dump_partition_map(map, 1); 921 break; 922 case 'D': 923 case 'd': 924 do_display_block(map, name); 925 break; 926 case 'F': 927 case 'f': 928 do_display_entry(map); 929 break; 930 case 'V': 931 case 'v': 932 validate_map(map); 933 break; 934 case 'E': 935 case 'e': 936 do_examine_patch_partition(map); 937 break; 938 default: 939 #ifndef __OpenBSD__ 940 do_error: 941 #endif 942 bad_input("No such command (%c)", command); 943 break; 944 } 945 } 946 finis: 947 return quit; 948 } 949 950 void 951 do_change_map_size(partition_map_header *map) 952 { 953 long size; 954 955 if (map == NULL) { 956 bad_input("No partition map exists"); 957 return; 958 } 959 if (!rflag && map->writeable == 0) { 960 printf("The map is not writeable.\n"); 961 } 962 if (get_number_argument("New size: ", &size, kDefault) == 0) { 963 bad_input("Bad size"); 964 return; 965 } 966 resize_map(size, map); 967 } 968 969 970 void 971 do_display_block(partition_map_header *map, char *alt_name) 972 { 973 MEDIA m; 974 long number; 975 char *name; 976 static unsigned char *display_block; 977 static int display_g; 978 int g; 979 980 if (map != NULL) { 981 name = 0; 982 m = map->m; 983 g = map->logical_block; 984 } else { 985 if (alt_name == 0) { 986 if (get_string_argument("Name of device: ", &name, 1) == 0) { 987 bad_input("Bad name"); 988 return; 989 } 990 } else { 991 name = malloc(strlen(alt_name)+1); 992 strcpy(name, alt_name); 993 } 994 m = open_pathname_as_media(name, O_RDONLY); 995 if (m == 0) { 996 error(errno, "can't open file '%s'", name); 997 free(name); 998 return; 999 } 1000 g = media_granularity(m); 1001 if (g < PBLOCK_SIZE) { 1002 g = PBLOCK_SIZE; 1003 } 1004 } 1005 if (get_number_argument("Block number: ", &number, kDefault) == 0) { 1006 bad_input("Bad block number"); 1007 goto xit; 1008 } 1009 if (display_block == NULL || display_g < g) { 1010 if (display_block != NULL) { 1011 free(display_block); 1012 display_g = 0; 1013 } 1014 display_block = (unsigned char *) malloc(g); 1015 if (display_block == NULL) { 1016 error(errno, "can't allocate memory for display block buffer"); 1017 goto xit; 1018 } 1019 display_g = g; 1020 } 1021 if (read_media(m, ((long long)number) * g, g, (char *)display_block) != 0) { 1022 dump_block((unsigned char*) display_block, g); 1023 } 1024 1025 xit: 1026 if (name) { 1027 close_media(m); 1028 free(name); 1029 } 1030 return; 1031 } 1032 1033 1034 void 1035 do_display_entry(partition_map_header *map) 1036 { 1037 long number; 1038 1039 if (map == NULL) { 1040 bad_input("No partition map exists"); 1041 return; 1042 } 1043 if (get_number_argument("Partition number: ", &number, kDefault) == 0) { 1044 bad_input("Bad partition number"); 1045 return; 1046 } 1047 if (number == 0) { 1048 full_dump_block_zero(map); 1049 } else { 1050 full_dump_partition_entry(map, number); 1051 } 1052 } 1053 1054 1055 void 1056 do_examine_patch_partition(partition_map_header *map) 1057 { 1058 partition_map * entry; 1059 1060 if (map == NULL) { 1061 bad_input("No partition map exists"); 1062 return; 1063 } 1064 entry = find_entry_by_type(kPatchType, map); 1065 if (entry == NULL) { 1066 printf("No patch partition\n"); 1067 } else { 1068 display_patches(entry); 1069 } 1070 } 1071