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