diff options
Diffstat (limited to 'mtdpart.c')
-rw-r--r-- | mtdpart.c | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/mtdpart.c b/mtdpart.c new file mode 100644 index 0000000..0016e34 --- /dev/null +++ b/mtdpart.c @@ -0,0 +1,194 @@ +/* + * mtdpart.c + * + * Copyright 2015 The Chromium OS Authors. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Overview: + * This utility adds or removes a partition from an MTD device. + */ + +#define PROGRAM_NAME "mtdpart" + +#include <fcntl.h> +#include <getopt.h> +#include <limits.h> +#include <linux/blkpg.h> +#include <stdio.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "common.h" + +static void display_help(int status) +{ + fprintf(status == EXIT_SUCCESS ? stdout : stderr, +"Usage: %1$s add [OPTION] <MTD_DEVICE> <PART_NAME> <START> <SIZE>\n" +" %1$s del [OPTION] <MTD_DEVICE> <PART_NUMBER>\n" +"Adds a partition to an MTD device, or remove an existing partition from it.\n" +"\n" +" -h, --help Display this help and exit\n" +" --version Output version information and exit\n" +"\n" +"START location and SIZE of the partition are in bytes. They should align on\n" +"eraseblock size.\n", + PROGRAM_NAME + ); + exit(status); +} + +static void display_version(void) +{ + printf("%1$s " VERSION "\n" + "\n" + "%1$s comes with NO WARRANTY\n" + "to the extent permitted by law.\n" + "\n" + "You may redistribute copies of %1$s\n" + "under the terms of the GNU General Public Licence.\n" + "See the file `COPYING' for more information.\n", + PROGRAM_NAME); + exit(EXIT_SUCCESS); +} + +/* Command arguments */ + +typedef enum { + COMMAND_ADD, + COMMAND_DEL +} command_type; + +static command_type command; /* add or del */ +static const char *mtddev; /* mtd device name */ +static const char *part_name; /* partition name */ +static int part_no; /* partition number */ +static long long start_addr; /* start address */ +static long long length; /* partition size */ + +static void process_options(int argc, char * const argv[]) +{ + int error = 0; + + for (;;) { + int option_index = 0; + static const char short_options[] = "h"; + static const struct option long_options[] = { + {"version", no_argument, 0, 0}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}, + }; + + int c = getopt_long(argc, argv, short_options, + long_options, &option_index); + if (c == EOF) { + break; + } + + switch (c) { + case 0: + display_version(); + break; + case 'h': + display_help(EXIT_SUCCESS); + break; + case '?': + error++; + break; + } + } + + if ((argc - optind) < 3 || error) + display_help(EXIT_FAILURE); + + const char *s_command = argv[optind++]; + mtddev = argv[optind++]; + + if (strcmp(s_command, "del") == 0 && (argc - optind) == 1) { + const char *s_part_no = argv[optind++]; + + long tmp = simple_strtol(s_part_no, &error); + if (tmp < 0) + errmsg_die("Can't specify negative partition number: %ld", + tmp); + if (tmp > INT_MAX) + errmsg_die("Partition number exceeds INT_MAX: %ld", + tmp); + + part_no = tmp; + command = COMMAND_DEL; + } else if (strcmp(s_command, "add") == 0 && (argc - optind) == 3) { + const char *s_start; + const char *s_length; + + part_name = argv[optind++]; + s_start = argv[optind++]; + s_length = argv[optind++]; + + if (strlen(part_name) >= BLKPG_DEVNAMELTH) + errmsg_die("Partition name (%s) should be less than %d characters", + part_name, BLKPG_DEVNAMELTH); + + start_addr = simple_strtoll(s_start, &error); + if (start_addr < 0) + errmsg_die("Can't specify negative start offset: %lld", + start_addr); + + length = simple_strtoll(s_length, &error); + if (length < 0) + errmsg_die("Can't specify negative length: %lld", + length); + + command = COMMAND_ADD; + } else + display_help(EXIT_FAILURE); + + if (error) + display_help(EXIT_FAILURE); +} + + +int main(int argc, char * const argv[]) +{ + int fd; + struct blkpg_partition part; + struct blkpg_ioctl_arg arg; + + process_options(argc, argv); + + fd = open(mtddev, O_RDWR | O_CLOEXEC); + if (fd == -1) + sys_errmsg_die("Cannot open %s", mtddev); + + memset(&part, 0, sizeof(part)); + + memset(&arg, 0, sizeof(arg)); + arg.datalen = sizeof(part); + arg.data = ∂ + + switch (command) { + case COMMAND_ADD: + part.start = start_addr; + part.length = length; + strncpy(part.devname, part_name, sizeof(part.devname)); + arg.op = BLKPG_ADD_PARTITION; + break; + case COMMAND_DEL: + part.pno = part_no; + arg.op = BLKPG_DEL_PARTITION; + break; + } + + if (ioctl(fd, BLKPG, &arg)) + sys_errmsg_die("Failed to issue BLKPG ioctl"); + + close(fd); + + /* Exit happy */ + return EXIT_SUCCESS; +} |