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