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