summaryrefslogtreecommitdiff
path: root/sbin/pdisk/pdisk.c
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2001-03-24 00:14:39 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2001-03-24 00:14:39 +0000
commitffb72f990c9933280de104024acf91acee02c1a5 (patch)
tree8312fd465c763b17886e6e1795ab48bde45c2381 /sbin/pdisk/pdisk.c
parentfa5275b22eb94a7d990e643d54768420845d618c (diff)
Import of pdisk from apple, BSD licensed code. Archive dated Feb 18 1998
This is a HFS partition editing tool.
Diffstat (limited to 'sbin/pdisk/pdisk.c')
-rw-r--r--sbin/pdisk/pdisk.c1004
1 files changed, 1004 insertions, 0 deletions
diff --git a/sbin/pdisk/pdisk.c b/sbin/pdisk/pdisk.c
new file mode 100644
index 00000000000..033a16c1fe7
--- /dev/null
+++ b/sbin/pdisk/pdisk.c
@@ -0,0 +1,1004 @@
+//
+// pdisk - an editor for Apple format partition tables
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+// Still under development (as of 15 January 1998)
+//
+
+/*
+ * Copyright 1996,1997,1998 by Apple Computer, Inc.
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+// for printf()
+#include <stdio.h>
+
+#ifdef __linux__
+#include <getopt.h>
+#include <malloc.h>
+#else
+// for malloc() & free()
+#include <stdlib.h>
+// for SIOUXsettings
+#include <SIOUX.h>
+#endif
+
+// for strncpy() & strlen()
+#include <string.h>
+// for O_RDONLY
+#include <fcntl.h>
+// for errno
+#include <errno.h>
+
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#endif
+
+#include "pdisk.h"
+#include "io.h"
+#include "partition_map.h"
+#include "pathname.h"
+#include "errors.h"
+#include "dump.h"
+#include "validate.h"
+#include "version.h"
+#include "util.h"
+
+
+//
+// Defines
+//
+#define ARGV_CHUNK 5
+#define CFLAG_DEFAULT 0
+#define DFLAG_DEFAULT 0
+#define HFLAG_DEFAULT 0
+#define INTERACT_DEFAULT 0
+#define LFLAG_DEFAULT 0
+#define RFLAG_DEFAULT 0
+#define VFLAG_DEFAULT 0
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+enum getopt_values {
+ kLongOption = 0,
+ kBadOption = '?',
+ kOptionArg = 1000,
+ kListOption = 1001,
+ kLogicalOption = 1002
+};
+
+
+//
+// Global Variables
+//
+int lflag = LFLAG_DEFAULT; /* list the device */
+char *lfile; /* list */
+int vflag = VFLAG_DEFAULT; /* show version */
+int hflag = HFLAG_DEFAULT; /* show help */
+int dflag = DFLAG_DEFAULT; /* turn on debugging commands and printout */
+int rflag = RFLAG_DEFAULT; /* open device read Only */
+int interactive = INTERACT_DEFAULT;
+int cflag = CFLAG_DEFAULT; /* compute device size */
+
+static int first_get = 1;
+
+
+//
+// Forward declarations
+//
+void do_change_map_size(partition_map_header *map);
+void do_create_partition(partition_map_header *map, int get_type);
+void do_delete_partition(partition_map_header *map);
+void do_display_block(partition_map_header *map, char *alt_name);
+void do_display_entry(partition_map_header *map);
+void do_examine_patch_partition(partition_map_header *map);
+int do_expert(partition_map_header *map, char *name);
+void do_rename_partition(partition_map_header *map);
+void do_reorder(partition_map_header *map);
+void do_write_partition_map(partition_map_header *map);
+void edit(char *name, int ask_logical_size);
+int get_base_argument(long *number, partition_map_header *map);
+int get_command_line(int *argc, char ***argv);
+int get_size_argument(long *number, partition_map_header *map);
+int get_options(int argc, char **argv);
+void interact();
+void print_edit_notes();
+void print_expert_notes();
+void print_top_notes();
+
+
+//
+// Routines
+//
+int
+main(int argc, char **argv)
+{
+#ifdef __linux__
+ int name_index;
+#else
+ printf("This app uses the SIOUX console library\n");
+ printf("Choose 'Quit' from the file menu to quit.\n\n");
+ printf("Use fake disk names (/dev/scsi<bus>.<id>; i.e. /dev/scsi0.1, /dev/scsi1.3, etc.).\n\n");
+
+ SIOUXSettings.autocloseonquit = 0; /* Do we close the SIOUX window on program termination ... */
+ SIOUXSettings.asktosaveonclose = 0; /* Do we offer to save on a close ... */
+#endif
+
+ init_program_name(argv);
+
+ if (sizeof(DPME) != PBLOCK_SIZE) {
+ fatal(-1, "Size of partion map entry (%d) "
+ "is not equal to block size (%d)\n",
+ sizeof(DPME), PBLOCK_SIZE);
+ }
+ if (sizeof(Block0) != PBLOCK_SIZE) {
+ fatal(-1, "Size of block zero structure (%d) "
+ "is not equal to block size (%d)\n",
+ sizeof(Block0), PBLOCK_SIZE);
+ }
+ if (strcmp(VERSION, get_version_string()) != 0) {
+ fatal(-1, "Version string static form (%s) does not match dynamic form (%s)\n",
+ VERSION, get_version_string());
+ }
+
+#ifdef __linux__
+ name_index = get_options(argc, argv);
+
+ if (vflag) {
+ printf("version " VERSION " (" RELEASE_DATE ")\n");
+ }
+ if (hflag) {
+ do_help();
+ } else if (interactive) {
+ interact();
+ } else if (lflag) {
+ if (lfile != NULL) {
+ dump(lfile);
+ } else if (name_index < argc) {
+ while (name_index < argc) {
+ dump(argv[name_index++]);
+ }
+ } else {
+ list_all_disks();
+ }
+ } else if (name_index < argc) {
+ while (name_index < argc) {
+ edit(argv[name_index++], 0);
+ }
+ } else if (!vflag) {
+ usage("no device argument");
+ do_help();
+ }
+ return 0;
+#else
+ interactive = 1;
+
+ interact();
+
+ SIOUXSettings.autocloseonquit = 1;
+ //printf("Processing stopped: Choose 'Quit' from the file menu to quit.\n\n");
+ exit(0);
+#endif
+}
+
+
+void
+print_top_notes()
+{
+ printf("Notes:\n");
+ printf(" Disks have fake names of the form /dev/scsi<bus>.<id>\n");
+ printf(" For example, /dev/scsi0.1, /dev/scsi1.3, and so on.\n");
+ printf(" MkLinux style names are also allowed (i.e /dev/sda or /dev/hda),\n");
+ printf(" and these names follow the MkLinux DR3 conventions.\n");
+ printf("\n");
+}
+
+
+void
+interact()
+{
+ char *name;
+ int command;
+ int ask_logical_size;
+
+ while (get_command("Top level command (? for help): ", first_get, &command)) {
+ first_get = 0;
+ ask_logical_size = 0;
+
+ switch (command) {
+ case '?':
+ print_top_notes();
+ // fall through
+ case 'H':
+ case 'h':
+ printf("Commands are:\n");
+ printf(" h print help\n");
+ printf(" v print the version number and release date\n");
+ printf(" l list device's map\n");
+ printf(" L list all devices' maps\n");
+ printf(" e edit device's map\n");
+ printf(" E (edit map with specified block size)\n");
+ printf(" r toggle readonly flag\n");
+ if (dflag) {
+ printf(" a toggle abbreviate flag\n");
+ printf(" p toggle physical flag\n");
+ printf(" c toggle compute size flag\n");
+ printf(" d toggle debug flag\n");
+ printf(" x examine block n of device\n");
+ }
+ printf(" q quit the program\n");
+ break;
+ case 'Q':
+ case 'q':
+ return;
+ break;
+ case 'V':
+ case 'v':
+ printf("version " VERSION " (" RELEASE_DATE ")\n");
+ break;
+ case 'L':
+ list_all_disks();
+ break;
+ case 'l':
+ if (get_string_argument("Name of device: ", &name, 1) == 0) {
+ bad_input("Bad name");
+ break;
+ }
+ dump(name);
+ free(name);
+ break;
+ case 'E':
+ ask_logical_size = 1;
+ case 'e':
+ if (get_string_argument("Name of device: ", &name, 1) == 0) {
+ bad_input("Bad name");
+ break;
+ }
+ edit(name, ask_logical_size);
+ free(name);
+ break;
+ case 'R':
+ case 'r':
+ if (rflag) {
+ rflag = 0;
+ } else {
+ rflag = 1;
+ }
+ printf("Now in %s mode.\n", (rflag)?"readonly":"read/write");
+ break;
+ case 'A':
+ case 'a':
+ if (dflag) {
+ if (aflag) {
+ aflag = 0;
+ } else {
+ aflag = 1;
+ }
+ printf("Now in %s mode.\n", (aflag)?"abbreviate":"full type");
+ } else {
+ goto do_error;
+ }
+ break;
+ case 'P':
+ case 'p':
+ if (dflag) {
+ if (pflag) {
+ pflag = 0;
+ } else {
+ pflag = 1;
+ }
+ printf("Now in %s mode.\n", (pflag)?"physical":"logical");
+ } else {
+ goto do_error;
+ }
+ break;
+ case 'D':
+ case 'd':
+ if (dflag) {
+ dflag = 0;
+ } else {
+ dflag = 1;
+ }
+ printf("Now in %s mode.\n", (dflag)?"debug":"normal");
+ break;
+ case 'C':
+ case 'c':
+ if (dflag) {
+ if (cflag) {
+ cflag = 0;
+ } else {
+ cflag = 1;
+ }
+ printf("Now in %s device size mode.\n", (cflag)?"always compute":"use existing");
+ } else {
+ goto do_error;
+ }
+ break;
+ case 'X':
+ case 'x':
+ if (dflag) {
+ do_display_block(0, 0);
+ } else {
+ goto do_error;
+ }
+ break;
+ default:
+ do_error:
+ bad_input("No such command (%c)", command);
+ break;
+ }
+ }
+}
+
+
+#ifdef __linux__
+int
+get_options(int argc, char **argv)
+{
+ int c;
+ static struct option long_options[] =
+ {
+ // name has_arg &flag val
+ {"help", no_argument, 0, 'h'},
+ {"list", optional_argument, 0, kListOption},
+ {"version", no_argument, 0, 'v'},
+ {"debug", no_argument, 0, 'd'},
+ {"readonly", no_argument, 0, 'r'},
+ {"abbr", no_argument, 0, 'a'},
+ {"logical", no_argument, 0, kLogicalOption},
+ {"interactive", no_argument, 0, 'i'},
+ {"compute_size", no_argument, 0, 'c'},
+ {0, 0, 0, 0}
+ };
+ int option_index = 0;
+ extern int optind;
+ extern char *optarg;
+ int flag = 0;
+
+ lflag = LFLAG_DEFAULT;
+ lfile = NULL;
+ vflag = VFLAG_DEFAULT;
+ hflag = HFLAG_DEFAULT;
+ dflag = DFLAG_DEFAULT;
+ rflag = RFLAG_DEFAULT;
+ aflag = AFLAG_DEFAULT;
+ pflag = PFLAG_DEFAULT;
+ interactive = INTERACT_DEFAULT;
+ cflag = CFLAG_DEFAULT;
+
+ optind = 0; // reset option scanner logic
+ while ((c = getopt_long(argc, argv, "hlvdric", long_options,
+ &option_index)) >= 0) {
+ switch (c) {
+ case kLongOption:
+ // option_index would be used here
+ break;
+ case 'h':
+ hflag = (HFLAG_DEFAULT)?0:1;
+ break;
+ case kListOption:
+ if (optarg != NULL) {
+ lfile = optarg;
+ }
+ // fall through
+ case 'l':
+ lflag = (LFLAG_DEFAULT)?0:1;
+ break;
+ case 'v':
+ vflag = (VFLAG_DEFAULT)?0:1;
+ break;
+ case 'd':
+ dflag = (DFLAG_DEFAULT)?0:1;
+ break;
+ case 'c':
+ cflag = (CFLAG_DEFAULT)?0:1;
+ break;
+ case 'r':
+ rflag = (RFLAG_DEFAULT)?0:1;
+ break;
+ case 'i':
+ interactive = (INTERACT_DEFAULT)?0:1;
+ break;
+ case 'a':
+ aflag = (AFLAG_DEFAULT)?0:1;
+ break;
+ case kLogicalOption:
+ pflag = (PFLAG_DEFAULT)?0:1;
+ break;
+ case kBadOption:
+ default:
+ flag = 1;
+ break;
+ }
+ }
+ if (flag) {
+ usage("bad arguments");
+ }
+ return optind;
+}
+#endif
+
+
+void
+print_edit_notes()
+{
+ printf("Notes:\n");
+ printf(" Base and length fields are blocks, which vary in size between media.\n");
+ printf(" The base field can be <nth>p; i.e. use the base of the nth partition.\n");
+ printf(" The length field can be a length followed by k, m, g or t to indicate\n");
+ printf(" kilo, mega, giga, or tera bytes; also the length can be <nth>p; i.e. use\n");
+ printf(" the length of the nth partition.\n");
+ printf(" The name of a partition is descriptive text.\n");
+ printf("\n");
+}
+
+
+//
+// Edit the file
+//
+void
+edit(char *name, int ask_logical_size)
+{
+ partition_map_header *map;
+ int command;
+ int order;
+ int get_type;
+ int valid_file;
+
+ map = open_partition_map(name, &valid_file, ask_logical_size);
+ if (!valid_file) {
+ return;
+ }
+
+ printf("Edit %s -\n", name);
+
+ while (get_command("Command (? for help): ", first_get, &command)) {
+ first_get = 0;
+ order = 1;
+ get_type = 0;
+
+ switch (command) {
+ case '?':
+ print_edit_notes();
+ // fall through
+ case 'H':
+ case 'h':
+ printf("Commands are:\n");
+ printf(" h help\n");
+ printf(" p print the partition table\n");
+ printf(" P (print ordered by base address)\n");
+ printf(" i initialize partition map\n");
+ printf(" s change size of partition map\n");
+ printf(" c create new partition (standard MkLinux type)\n");
+ printf(" C (create with type also specified)\n");
+ printf(" n (re)name a partition\n");
+ printf(" d delete a partition\n");
+ printf(" r reorder partition entry in map\n");
+ if (!rflag) {
+ printf(" w write the partition table\n");
+ }
+ printf(" q quit editing (don't save changes)\n");
+ if (dflag) {
+ printf(" x extra extensions for experts\n");
+ }
+ break;
+ case 'P':
+ order = 0;
+ // fall through
+ case 'p':
+ dump_partition_map(map, order);
+ break;
+ case 'Q':
+ case 'q':
+ flush_to_newline(1);
+ goto finis;
+ break;
+ case 'I':
+ case 'i':
+ map = init_partition_map(name, map);
+ break;
+ case 'C':
+ get_type = 1;
+ // fall through
+ case 'c':
+ do_create_partition(map, get_type);
+ break;
+ case 'N':
+ case 'n':
+ do_rename_partition(map);
+ break;
+ case 'D':
+ case 'd':
+ do_delete_partition(map);
+ break;
+ case 'R':
+ case 'r':
+ do_reorder(map);
+ break;
+ case 'S':
+ case 's':
+ do_change_map_size(map);
+ break;
+ case 'X':
+ case 'x':
+ if (!dflag) {
+ goto do_error;
+ } else if (do_expert(map, name)) {
+ flush_to_newline(1);
+ goto finis;
+ }
+ break;
+ case 'W':
+ case 'w':
+ if (!rflag) {
+ do_write_partition_map(map);
+ } else {
+ goto do_error;
+ }
+ break;
+ default:
+ do_error:
+ bad_input("No such command (%c)", command);
+ break;
+ }
+ }
+finis:
+
+ close_partition_map(map);
+}
+
+
+void
+do_create_partition(partition_map_header *map, int get_type)
+{
+ long base;
+ long length;
+ char *name;
+ char *type_name;
+
+ if (map == NULL) {
+ bad_input("No partition map exists");
+ return;
+ }
+ if (!rflag && map->writeable == 0) {
+ printf("The map is not writeable.\n");
+ }
+// XXX add help feature (i.e. '?' in any argument routine prints help string)
+ if (get_base_argument(&base, map) == 0) {
+ return;
+ }
+ if (get_size_argument(&length, map) == 0) {
+ return;
+ }
+
+ if (get_string_argument("Name of partition: ", &name, 1) == 0) {
+ bad_input("Bad name");
+ return;
+ }
+ if (get_type == 0) {
+ add_partition_to_map(name, kUnixType, base, length, map);
+ goto xit1;
+
+ } else if (get_string_argument("Type of partition: ", &type_name, 1) == 0) {
+ bad_input("Bad type");
+ goto xit1;
+ } else {
+ if (istrncmp(type_name, kFreeType, DPISTRLEN) == 0) {
+ bad_input("Can't create a partition with the Free type");
+ goto xit2;
+ }
+ if (istrncmp(type_name, kMapType, DPISTRLEN) == 0) {
+ bad_input("Can't create a partition with the Map type");
+ goto xit2;
+ }
+ add_partition_to_map(name, type_name, base, length, map);
+ }
+xit2:
+ free(type_name);
+xit1:
+ free(name);
+ return;
+}
+
+
+int
+get_base_argument(long *number, partition_map_header *map)
+{
+ partition_map * entry;
+ int result = 0;
+
+ if (get_number_argument("First block: ", number, kDefault) == 0) {
+ bad_input("Bad block number");
+ } else {
+ result = 1;
+ if (get_partition_modifier()) {
+ entry = find_entry_by_disk_address(*number, map);
+ if (entry == NULL) {
+ bad_input("Bad partition number");
+ result = 0;
+ } else {
+ *number = entry->data->dpme_pblock_start;
+ }
+ }
+ }
+ return result;
+}
+
+
+int
+get_size_argument(long *number, partition_map_header *map)
+{
+ partition_map * entry;
+ int result = 0;
+ unsigned long multiple;
+
+ if (get_number_argument("Length in blocks: ", number, kDefault) == 0) {
+ bad_input("Bad length");
+ } else {
+ multiple = get_multiplier(map->logical_block);
+ if (multiple == 0) {
+ bad_input("Bad multiplier");
+ } else if (multiple != 1) {
+ *number *= multiple;
+ result = 1;
+ } else if (get_partition_modifier()) {
+ entry = find_entry_by_disk_address(*number, map);
+ if (entry == NULL) {
+ bad_input("Bad partition number");
+ } else {
+ *number = entry->data->dpme_pblocks;
+ result = 1;
+ }
+ } else {
+ result = 1;
+ }
+ }
+ return result;
+}
+
+
+void
+do_rename_partition(partition_map_header *map)
+{
+ partition_map * entry;
+ long index;
+ char *name;
+
+ if (map == NULL) {
+ bad_input("No partition map exists");
+ return;
+ }
+ if (!rflag && map->writeable == 0) {
+ printf("The map is not writeable.\n");
+ }
+ if (get_number_argument("Partition number: ", &index, kDefault) == 0) {
+ bad_input("Bad partition number");
+ return;
+ }
+ if (get_string_argument("New name of partition: ", &name, 1) == 0) {
+ bad_input("Bad name");
+ return;
+ }
+
+ // find partition and change it
+ entry = find_entry_by_disk_address(index, map);
+ if (entry == NULL) {
+ printf("No such partition\n");
+ } else {
+ // stuff name into partition map entry data
+ strncpy(entry->data->dpme_name, name, DPISTRLEN);
+ map->changed = 1;
+ }
+ free(name);
+ return;
+}
+
+
+void
+do_delete_partition(partition_map_header *map)
+{
+ partition_map * cur;
+ long index;
+
+ if (map == NULL) {
+ bad_input("No partition map exists");
+ return;
+ }
+ if (!rflag && map->writeable == 0) {
+ printf("The map is not writeable.\n");
+ }
+ if (get_number_argument("Partition number: ", &index, kDefault) == 0) {
+ bad_input("Bad partition number");
+ return;
+ }
+
+ // find partition and delete it
+ cur = find_entry_by_disk_address(index, map);
+ if (cur == NULL) {
+ printf("No such partition\n");
+ } else {
+ delete_partition_from_map(cur);
+ }
+}
+
+
+void
+do_reorder(partition_map_header *map)
+{
+ long old_index;
+ long index;
+
+ if (map == NULL) {
+ bad_input("No partition map exists");
+ return;
+ }
+ if (!rflag && map->writeable == 0) {
+ printf("The map is not writeable.\n");
+ }
+ if (get_number_argument("Partition number: ", &old_index, kDefault) == 0) {
+ bad_input("Bad partition number");
+ return;
+ }
+ if (get_number_argument("New number: ", &index, kDefault) == 0) {
+ bad_input("Bad partition number");
+ return;
+ }
+
+ move_entry_in_map(old_index, index, map);
+}
+
+
+void
+do_write_partition_map(partition_map_header *map)
+{
+ if (map == NULL) {
+ bad_input("No partition map exists");
+ return;
+ }
+ if (map->changed == 0) {
+ bad_input("The map has not been changed.");
+ return;
+ }
+ if (map->writeable == 0) {
+ bad_input("The map is not writeable.");
+ return;
+ }
+ printf("Writing the map destroys what was there before. ");
+ if (get_okay("Is that okay? [n/y]: ", 0) != 1) {
+ return;
+ }
+
+ write_partition_map(map);
+
+ // exit(0);
+}
+
+
+void
+print_expert_notes()
+{
+ printf("Notes:\n");
+ printf(" The expert commands are for low level and experimental features.\n");
+ printf(" These commands are available only when debug mode is on.\n");
+ printf("\n");
+}
+
+
+int
+do_expert(partition_map_header *map, char *name)
+{
+ int command;
+ int quit = 0;
+
+ while (get_command("Expert command (? for help): ", first_get, &command)) {
+ first_get = 0;
+
+ switch (command) {
+ case '?':
+ print_expert_notes();
+ // fall through
+ case 'H':
+ case 'h':
+ printf("Commands are:\n");
+ printf(" h print help\n");
+ printf(" d dump block n\n");
+ printf(" p print the partition table\n");
+ if (dflag) {
+ printf(" P (show data structures - debugging)\n");
+ }
+ printf(" f full display of nth entry\n");
+ printf(" v validate map\n");
+ printf(" e examine patch partition\n");
+ printf(" q return to main edit menu\n");
+ printf(" Q quit without saving changes\n");
+ break;
+ case 'q':
+ flush_to_newline(1);
+ goto finis;
+ break;
+ case 'Q':
+ quit = 1;
+ goto finis;
+ break;
+ case 'P':
+ if (dflag) {
+ show_data_structures(map);
+ break;
+ }
+ // fall through
+ case 'p':
+ dump_partition_map(map, 1);
+ break;
+ case 'D':
+ case 'd':
+ do_display_block(map, name);
+ break;
+ case 'F':
+ case 'f':
+ do_display_entry(map);
+ break;
+ case 'V':
+ case 'v':
+ validate_map(map);
+ break;
+ case 'E':
+ case 'e':
+ do_examine_patch_partition(map);
+ break;
+ default:
+ do_error:
+ bad_input("No such command (%c)", command);
+ break;
+ }
+ }
+finis:
+ return quit;
+}
+
+void
+do_change_map_size(partition_map_header *map)
+{
+ long size;
+
+ if (map == NULL) {
+ bad_input("No partition map exists");
+ return;
+ }
+ if (!rflag && map->writeable == 0) {
+ printf("The map is not writeable.\n");
+ }
+ if (get_number_argument("New size: ", &size, kDefault) == 0) {
+ bad_input("Bad size");
+ return;
+ }
+ resize_map(size, map);
+}
+
+
+void
+do_display_block(partition_map_header *map, char *alt_name)
+{
+ MEDIA m;
+ long number;
+ char *name;
+ static unsigned char *display_block;
+ static int display_g;
+ int g;
+
+ if (map != NULL) {
+ name = 0;
+ m = map->m;
+ g = map->logical_block;
+ } else {
+ if (alt_name == 0) {
+ if (get_string_argument("Name of device: ", &name, 1) == 0) {
+ bad_input("Bad name");
+ return;
+ }
+ } else {
+ name = malloc(strlen(alt_name)+1);
+ strcpy(name, alt_name);
+ }
+ m = open_pathname_as_media(name, O_RDONLY);
+ if (m == 0) {
+ error(errno, "can't open file '%s'", name);
+ free(name);
+ return;
+ }
+ g = media_granularity(m);
+ if (g < PBLOCK_SIZE) {
+ g = PBLOCK_SIZE;
+ }
+ }
+ if (get_number_argument("Block number: ", &number, kDefault) == 0) {
+ bad_input("Bad block number");
+ goto xit;
+ }
+ if (display_block == NULL || display_g < g) {
+ if (display_block != NULL) {
+ free(display_block);
+ display_g = 0;
+ }
+ display_block = (unsigned char *) malloc(g);
+ if (display_block == NULL) {
+ error(errno, "can't allocate memory for display block buffer");
+ goto xit;
+ }
+ display_g = g;
+ }
+ if (read_media(m, ((long long)number) * g, g, (char *)display_block) != 0) {
+ dump_block((unsigned char*) display_block, g);
+ }
+
+xit:
+ if (name) {
+ close_media(m);
+ free(name);
+ }
+ return;
+}
+
+
+void
+do_display_entry(partition_map_header *map)
+{
+ long number;
+
+ if (map == NULL) {
+ bad_input("No partition map exists");
+ return;
+ }
+ if (get_number_argument("Partition number: ", &number, kDefault) == 0) {
+ bad_input("Bad partition number");
+ return;
+ }
+ if (number == 0) {
+ full_dump_block_zero(map);
+ } else {
+ full_dump_partition_entry(map, number);
+ }
+}
+
+
+void
+do_examine_patch_partition(partition_map_header *map)
+{
+ partition_map * entry;
+
+ if (map == NULL) {
+ bad_input("No partition map exists");
+ return;
+ }
+ entry = find_entry_by_type(kPatchType, map);
+ if (entry == NULL) {
+ printf("No patch partition\n");
+ } else {
+ display_patches(entry);
+ }
+}