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