From 689eb7378d5622e5997870ef06f2d9feabd7063c Mon Sep 17 00:00:00 2001 From: Michael McMaster Date: Thu, 29 May 2014 12:03:35 +1000 Subject: [PATCH] Simplied user input, and provided more meaningful defaults. --- dump.c | 17 +-- hfdisk.8 | 26 ++-- hfdisk.c | 117 ++++++++--------- hfdisk.h | 5 + io.c | 326 ++++++++++-------------------------------------- io.h | 6 +- partition_map.c | 44 ++++++- partition_map.h | 2 + 8 files changed, 184 insertions(+), 359 deletions(-) diff --git a/dump.c b/dump.c index 7e9560f..933107b 100644 --- a/dump.c +++ b/dump.c @@ -36,6 +36,7 @@ #include #include +#include "hfdisk.h" #include "io.h" #include "errors.h" #include "partition_map.h" @@ -51,27 +52,11 @@ // // Types // -typedef struct names { - char *abbr; - char *full; -} NAMES; // // Global Constants // -NAMES plist[] = { - {"Drvr", "Apple_Driver"}, - {"Dr43", "Apple_Driver43"}, - {"Free", "Apple_Free"}, - {" HFS", "Apple_HFS"}, - {" MFS", "Apple_MFS"}, - {"PDOS", "Apple_PRODOS"}, - {"junk", "Apple_Scratch"}, - {"unix", "Apple_UNIX_SVR2"}, - {" map", "Apple_partition_map"}, - {0, 0} -}; const char * kStringEmpty = ""; const char * kStringNot = " not"; diff --git a/hfdisk.8 b/hfdisk.8 index 01eaa81..0c9cb54 100644 --- a/hfdisk.8 +++ b/hfdisk.8 @@ -1,15 +1,15 @@ -.TH PDISK 8 "20 December 1996" "MkLinux DR2" "Linux Programmer's Manual" +.TH HFDISK 8 "20 December 1996" "MkLinux DR2" "Linux Programmer's Manual" .SH NAME -pdisk \- Apple partition table editor for Linux +hfdisk \- Apple partition table editor .SH SYNOPSIS -.B pdisk +.B hfdisk .B "[\-h|\--help] [\-v|\--version] [\-l|\--list [name ...]]" .br -.B pdisk +.B hfdisk .B "[\-r|\--readonly]" device ... .SH DESCRIPTION -.B pdisk +.B hfdisk is a menu driven program which partitions disks using the standard Apple disk partitioning scheme described in "Inside Macintosh: Devices". It does not support the intel/dos partitioning scheme supported by @@ -52,12 +52,12 @@ is the partition described by the second entry in the partiton map on /dev/sda. .TP .B \-v | \--version Prints version number of the -.B pdisk +.B hfdisk program. .TP .B \-h | \--help Prints a rather lame set of help messages for the -.B pdisk +.B hfdisk program. .TP .B \-l | \--list @@ -77,13 +77,13 @@ Otherwise, lists the partition tables for the specified .TP .B \-r | \--readonly Prevents -.B pdisk +.B hfdisk from writing to the device. .SH "Editing Partition Tables" An argument which is simply the name of a .I device indicates that -.B pdisk +.B hfdisk should edit the partition table of that device. The current top level editing commands are: @@ -129,12 +129,8 @@ The .B c (create new partition) command is the only one with complicated arguments. The first argument is the base address (in blocks) of the partition. -Besides a raw number, you can also specify a partition number followed -by the letter 'p' to indicate that the first block of the new partition should -be the same as the first block of that existing free space partition. The second argument is the length of the partition in blocks. -This can be a raw number or can be a partition number followed by the -letter 'p' to use the size of that partition or can be a number followed +This can be a raw number or can be a number followed by 'k', 'm', or 'g' to indicate the size in kilobytes, megabytes, or gigabytes respectively. (These are powers of 1024, of course, not powers of 1000.) @@ -170,7 +166,7 @@ In order to use the new partition map you must reboot. .SH BUGS Some people believe there should really be just one disk partitioning utility. .br -.B pdisk +.B hfdisk should be able to create HFS partitions that work. .br Even more help should be available during user input. diff --git a/hfdisk.c b/hfdisk.c index 9b0aba0..ec58652 100644 --- a/hfdisk.c +++ b/hfdisk.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -65,6 +66,19 @@ enum getopt_values { kListOption = 1001 }; +const NAMES plist[] = { + {"Drvr", "Apple_Driver"}, + {"Dr43", "Apple_Driver43"}, + {"Free", "Apple_Free"}, + {" HFS", "Apple_HFS"}, + {" MFS", "Apple_MFS"}, + {"PDOS", "Apple_PRODOS"}, + {"junk", "Apple_Scratch"}, + {"unix", "Apple_UNIX_SVR2"}, + {" map", "Apple_partition_map"}, + {0, 0} +}; + // // Global Variables @@ -90,8 +104,7 @@ void do_reorder(partition_map_header *map); void do_write_partition_map(partition_map_header *map); void edit(char *name); 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_size_argument(uint32_t base, long *number, partition_map_header *map); int get_options(int argc, char **argv); void print_notes(); @@ -270,7 +283,6 @@ edit(char *name) break; case 'Q': case 'q': - flush_to_newline(1); goto finis; break; case 'I': @@ -304,7 +316,6 @@ edit(char *name) if (!dflag) { goto do_error; } else if (do_expert(map)) { - flush_to_newline(0); goto finis; } break; @@ -345,7 +356,7 @@ do_create_partition(partition_map_header *map, int get_type) if (get_base_argument(&base, map) == 0) { return; } - if (get_size_argument(&length, map) == 0) { + if (get_size_argument(base, &length, map) == 0) { return; } @@ -356,17 +367,27 @@ do_create_partition(partition_map_header *map, int get_type) if (get_type == 0) { add_partition_to_map(name, kUnixType, base, length, map); - } else if (get_string_argument("Type of partition: ", &type_name, 1) == 0) { - bad_input("Bad type"); - return; } else { - if (strncmp(type_name, kFreeType, DPISTRLEN) == 0) { - bad_input("Can't create a partition with the Free type"); - return; - } - if (strncmp(type_name, kMapType, DPISTRLEN) == 0) { - bad_input("Can't create a partition with the Map type"); - return; + while (1) { + if (get_string_argument("Type of partition (L for known types): ", &type_name, 1) == 0) { + bad_input("Bad type"); + return; + } else if (strncmp(type_name, kFreeType, DPISTRLEN) == 0) { + bad_input("Can't create a partition with the Free type"); + } else if (strncmp(type_name, kMapType, DPISTRLEN) == 0) { + bad_input("Can't create a partition with the Map type"); + } else if (strncmp(type_name, "L", DPISTRLEN) == 0) { + int i = 0; + while (plist[i].full) { + printf("%s\n", plist[i].full); + ++i; + } + printf("\n"); + } + else + { + break; + } } add_partition_to_map(name, type_name, base, length, map); } @@ -400,62 +421,47 @@ do_create_bootstrap_partition(partition_map_header *map) int get_base_argument(long *number, partition_map_header *map) { - partition_map * entry; - int c; int result = 0; - if (get_number_argument("First block: ", number, kDefault) == 0) { + uint32_t defaultFirstBlock = find_free_space(map); + char prompt[32]; + sprintf(prompt, "First block [%"PRIu32"]: ", defaultFirstBlock); + if (get_number_argument(prompt, number, defaultFirstBlock) == 0) { bad_input("Bad block number"); } else { result = 1; - c = getch(); - - if (c == 'p' || c == 'P') { - 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; - } - } else if (c > 0) { - ungetch(c); - } } return result; } int -get_size_argument(long *number, partition_map_header *map) +get_size_argument(uint32_t base, long *number, partition_map_header *map) { - partition_map * entry; - int c; int result = 0; - long multiple; - if (get_number_argument("Length (in blocks, kB (k), MB (M) or GB (G)): ", number, kDefault) == 0) { + uint32_t defaultSize = 20480; // 10MB + + // Work out how much free-space is available. + partition_map* part = find_entry_by_sector(base, map); + if (part) + { + size_t partEnd = + part->data->dpme_pblock_start + + part->data->dpme_pblocks; + defaultSize = partEnd - base; + } + + char prompt[80]; + sprintf( + prompt, + "Length (in blocks, kB (k), MB (M) or GB (G)) [%"PRIu32"]: ", + defaultSize); + + if (get_number_argument(prompt, number, defaultSize) == 0) { bad_input("Bad length"); } else { result = 1; - multiple = get_multiplier(PBLOCK_SIZE); - if (multiple != 1) { - *number *= multiple; - } else { - c = getch(); - - if (c == 'p' || c == 'P') { - entry = find_entry_by_disk_address(*number, map); - if (entry == NULL) { - bad_input("Bad partition number"); - result = 0; - } else { - *number = entry->data->dpme_pblocks; - } - } else if (c > 0) { - ungetch(c); - } - } } return result; } @@ -536,7 +542,7 @@ do_write_partition_map(partition_map_header *map) printf("the map causes all data on that partition to be LOST FOREVER. \n"); printf("Make sure you have a backup of any data on such partitions you \n"); printf("want to keep before answering 'yes' to the question below! \n\n"); - if (get_okay("Write partition map? [n/y]: ", 0) != 1) { + if (get_okay("Write partition map? [N/y]: ") != 1) { return; } @@ -579,7 +585,6 @@ do_expert(partition_map_header *map) break; case 'X': case 'x': - flush_to_newline(1); goto finis; break; case 'Q': diff --git a/hfdisk.h b/hfdisk.h index b1f9e3b..633eaf6 100644 --- a/hfdisk.h +++ b/hfdisk.h @@ -34,11 +34,16 @@ // // Types // +typedef struct names { + char *abbr; + char *full; +} NAMES; // // Global Constants // +extern const NAMES plist[]; // diff --git a/io.c b/io.c index 6297030..4a3a81a 100644 --- a/io.c +++ b/io.c @@ -60,324 +60,127 @@ const long kDefault = -1; // // Global Variables // -short unget_buf[UNGET_MAX_COUNT+1]; -int unget_count; // // Forward declarations // -long get_number(int first_char); -char* get_string(int eos); // // Routines // -int -getch() -{ - if (unget_count > 0) { - return (unget_buf[--unget_count]); - } else { - return (getc(stdin)); - } -} - - -void -ungetch(int c) -{ - // In practice there is never more than one character in - // the unget_buf, but what's a little overkill among friends? - - if (unget_count < UNGET_MAX_COUNT) { - unget_buf[unget_count++] = c; - } else { - fatal(-1, "Programmer error in ungetch()."); - } -} - - -void -flush_to_newline(int keep_newline) -{ - int c; - - for (;;) { - c = getch(); - - if (c <= 0) { - break; - } else if (c == '\n') { - if (keep_newline) { - ungetch(c); - } - break; - } else { - // skip - } - } - return; -} int -get_okay(char *prompt, int default_value) +get_okay(char *prompt) { - int c; - - flush_to_newline(0); - printf("%s", prompt); - - for (;;) { - c = getch(); - - if (c <= 0) { - break; - } else if (c == ' ' || c == '\t') { - // skip blanks and tabs - } else if (c == '\n') { - ungetch(c); - return default_value; - } else if (c == 'y' || c == 'Y') { - return 1; - } else if (c == 'n' || c == 'N') { - return 0; - } else { - flush_to_newline(0); - printf("%s", prompt); + int result = 0; + char* string = NULL; + if (get_string_argument(prompt, &string, 1)) + { + if (string[0] == 'Y' || string[0] == 'y') + { + result = 1; } } - return -1; + free(string); + return result; } int get_command(char *prompt, int promptBeforeGet, int *command) { - int c; - - if (promptBeforeGet) { - printf("%s", prompt); - } - for (;;) { - c = getch(); - - if (c <= 0) { - break; - } else if (c == ' ' || c == '\t') { - // skip blanks and tabs - } else if (c == '\n') { - printf("%s", prompt); - } else { - *command = c; - return 1; - } + int result = 0; + char* string = NULL; + if (get_string_argument(prompt, &string, 1)) + { + *command = string[0]; + result = 1; } - return 0; + free(string); + return result; + } int get_number_argument(char *prompt, long *number, long default_value) { - int c; int result = 0; - for (;;) { - c = getch(); + char* buf = NULL; + size_t buflen = 0; + char multiplier; + int matched; - if (c <= 0) { + while (result == 0) { + printf("%s", prompt); + + if (getline(&buf, &buflen, stdin) == -1) + { + // EOF break; - } else if (c == ' ' || c == '\t') { - // skip blanks and tabs - } else if (c == '\n') { - if (default_value < 0) { - printf("%s", prompt); - } else { - ungetch(c); - *number = default_value; - result = 1; - break; - } - } else if ('0' <= c && c <= '9') { - *number = get_number(c); + } + else if ((default_value > 0) && (strncmp(buf, "\n", 1) == 0)) + { + *number = default_value; result = 1; break; - } else { - ungetch(c); - *number = 0; - break; + } + else if ((matched = sscanf(buf, "%ld%c", number, &multiplier)) >= 1) + { + result = 1; + if (matched == 2) { + if (multiplier == 'g' || multiplier == 'G') { + *number *= (1024*1024*1024 / PBLOCK_SIZE); + } else if (multiplier == 'm' || multiplier == 'M') { + *number *= (1024*1024 / PBLOCK_SIZE); + } else if (multiplier == 'k' || multiplier == 'K') { + *number *= (1024 / PBLOCK_SIZE); + } else if (multiplier != '\n') { + result = 0; + } + } } } + free(buf); return result; } -long -get_number(int first_char) -{ - register int c; - int base; - int digit; - int ret_value; - - if (first_char != '0') { - c = first_char; - base = 10; - digit = BAD_DIGIT; - } else if ((c=getch()) == 'x' || c == 'X') { - c = getch(); - base = 16; - digit = BAD_DIGIT; - } else { - c = first_char; - base = 8; - digit = 0; - } - ret_value = 0; - for (ret_value = 0; ; c = getch()) { - if (c >= '0' && c <= '9') { - digit = c - '0'; - } else if (c >='A' && c <= 'F') { - digit = 10 + (c - 'A'); - } else if (c >='a' && c <= 'f') { - digit = 10 + (c - 'a'); - } else { - digit = BAD_DIGIT; - } - if (digit >= base) { - break; - } - ret_value = ret_value * base + digit; - } - ungetch(c); - return(ret_value); -} - - int get_string_argument(char *prompt, char **string, int reprompt) { - int c; int result = 0; + size_t buflen = 0; - for (;;) { - c = getch(); + while (result == 0) { + printf("%s", prompt); - if (c <= 0) { - break; - } else if (c == ' ' || c == '\t') { - // skip blanks and tabs - } else if (c == '\n') { - if (reprompt) { - printf("%s", prompt); - } else { - ungetch(c); - *string = NULL; - break; - } - } else if (c == '"' || c == '\'') { - *string = get_string(c); - result = 1; - break; - } else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') - || (c == '-' || c == '/')) { - ungetch(c); - *string = get_string(' '); - result = 1; - break; - } else { - ungetch(c); - *string = NULL; + if (getline(string, &buflen, stdin) == -1) + { + // EOF break; } - } - return result; -} - - -char * -get_string(int eos) -{ - int c; - char *s; - char *ret_value; - char *limit; - int length; - - ret_value = (char *) malloc(STRING_CHUNK); - if (ret_value == NULL) { - error(errno, "can't allocate memory for string buffer"); - return NULL; - } - length = STRING_CHUNK; - limit = ret_value + length; - - c = getch(); - for (s = ret_value; ; c = getch()) { - if (s >= limit) { - // expand string - limit = (char *) malloc(length+STRING_CHUNK); - if (limit == NULL) { - error(errno, "can't allocate memory for string buffer"); - ret_value[length-1] = 0; - break; - } - strncpy(limit, ret_value, length); - free(ret_value); - s = limit + (s - ret_value); - ret_value = limit; - length += STRING_CHUNK; - limit = ret_value + length; - } - if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) { - *s++ = 0; + else if ((strncmp(*string, "\n", 1) == 0) && !reprompt) + { + result = 0; break; - } else if (c == '\n') { - *s++ = 0; - ungetch(c); - break; - } else { - *s++ = c; } - } - return(ret_value); -} - - -long -get_multiplier(long divisor) -{ - int c; - int result; - - c = getch(); - - if (c <= 0 || divisor <= 0) { - result = 0; - } else if (c == 'g' || c == 'G') { - result = 1024*1024*1024; - } else if (c == 'm' || c == 'M') { - result = 1024*1024; - } else if (c == 'k' || c == 'K') { - result = 1024; - } else { - ungetch(c); - result = 1; - } - if (result > 1) { - if (result >= divisor) { - result /= divisor; - } else { + else + { + size_t len = strnlen(*string, buflen); + if ((*string)[len - 1] == '\n') { + (*string)[len - 1] = '\0'; + } result = 1; } } return result; } - int number_of_digits(unsigned long value) { @@ -404,7 +207,6 @@ bad_input(char *fmt, ...) vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); - flush_to_newline(1); } diff --git a/io.h b/io.h index 9561b34..dce3e37 100644 --- a/io.h +++ b/io.h @@ -53,15 +53,11 @@ extern const long kDefault; // void bad_input(char *fmt, ...); int close_device(int fildes); -void flush_to_newline(int keep_newline); int get_command(char *prompt, int promptBeforeGet, int *command); -long get_multiplier(long divisor); int get_number_argument(char *prompt, long *number, long default_value); -int get_okay(char *prompt, int default_value); +int get_okay(char *prompt); int get_string_argument(char *prompt, char **string, int reprompt); -int getch(); int number_of_digits(unsigned long value); int open_device(const char *path, int oflag); int read_block(int fd, unsigned long num, char *buf, int quiet); -void ungetch(int c); int write_block(int fd, unsigned long num, char *buf); diff --git a/partition_map.c b/partition_map.c index d191df9..6703386 100644 --- a/partition_map.c +++ b/partition_map.c @@ -365,7 +365,7 @@ init_partition_map(char *name, partition_map_header* oldmap) if (oldmap != NULL) { printf("map already exists\n"); - if (get_okay("do you want to reinit? [n/y]: ", 0) != 1) { + if (get_okay("do you want to reinit? [N/y]: ") != 1) { return oldmap; } } @@ -414,9 +414,9 @@ create_partition_map(char *name) map->maximum_in_map = -1; number = compute_device_size(fd); - printf("size of 'device' is %lu blocks: ", number); - flush_to_newline(0); - get_number_argument("what should be the size? ", (long *)&number, number); + char prompt[64]; + sprintf(prompt, "Device block size [%lu]: ", number); + get_number_argument(prompt, (long *)&number, number); if (number < 4) { number = 4; } @@ -678,7 +678,6 @@ compute_device_size(int fd) if (valid != 0) { x = x + 1; } - // printf("size in blocks = %d\n", x); free(data); } @@ -1002,3 +1001,38 @@ resize_map(long new_size, partition_map_header *map) delete_partition_from_map(entry); add_partition_to_map("Apple", kMapType, 1, new_size, map); } + +uint32_t +find_free_space(partition_map_header *map) +{ + partition_map * cur; + uint32_t result = -1; + + // find a block that starts includes base and length + cur = map->base_order; + while (cur != NULL) { + if (strncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) == 0) { + result = cur->data->dpme_pblock_start; + break; + } else { + cur = cur->next_by_base; + } + } + return result; +} + +partition_map* +find_entry_by_sector(uint32_t lba, partition_map_header *map) +{ + partition_map* cur = map->base_order; + while (cur != NULL) { + if ((cur->data->dpme_pblock_start <= lba) && + (lba < cur->data->dpme_pblock_start + cur->data->dpme_pblocks)) { + break; + } else { + cur = cur->next_by_base; + } + } + return cur; +} + diff --git a/partition_map.h b/partition_map.h index abf6d13..05e43c2 100644 --- a/partition_map.h +++ b/partition_map.h @@ -75,10 +75,12 @@ int add_partition_to_map(const char *name, const char *dptype, uint32_t base, ui void close_partition_map(partition_map_header *map); void delete_partition_from_map(partition_map *entry); partition_map* find_entry_by_disk_address(long index, partition_map_header *map); +partition_map* find_entry_by_sector(uint32_t lba, partition_map_header *map); partition_map_header* init_partition_map(char *name, partition_map_header* oldmap); void move_entry_in_map(long old_index, long index, partition_map_header *map); partition_map_header* open_partition_map(char *name, int *valid_file); void resize_map(long new_size, partition_map_header *map); void write_partition_map(partition_map_header *map); +uint32_t find_free_space(partition_map_header *map); #endif