Home | History | Annotate | Line # | Download | only in dist
pdisk.c revision 1.2.4.2
      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