diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2024-02-21 07:43:53 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2024-02-21 07:43:53 +0100 |
commit | 4928cf0220752bc593f58faecaa4fb932ce7017c (patch) | |
tree | 34465dd7cec16a98d4f0d78f0bc60eaefb58ab5b /commands | |
parent | b4186752c6abece215a27bfad014164accfe3e28 (diff) | |
parent | 9f868f78bc5473d02a1e85debfa302ba370cbc2e (diff) | |
download | barebox-4928cf0220752bc593f58faecaa4fb932ce7017c.tar.gz barebox-4928cf0220752bc593f58faecaa4fb932ce7017c.tar.xz |
Merge branch 'for-next/partitions'
Diffstat (limited to 'commands')
-rw-r--r-- | commands/Kconfig | 21 | ||||
-rw-r--r-- | commands/Makefile | 2 | ||||
-rw-r--r-- | commands/loadenv.c | 3 | ||||
-rw-r--r-- | commands/parted.c | 374 |
4 files changed, 398 insertions, 2 deletions
diff --git a/commands/Kconfig b/commands/Kconfig index a6806f198e..d8bcb573fd 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -655,6 +655,27 @@ config CMD_MOUNT -o OPTIONS set file system OPTIONS -v verbose +config CMD_PARTED + tristate + depends on PARTITION + select PARTITION_MANIPULATION + prompt "parted" + help + parted - edit partition tables + + Usage: parted <device> [command [options...]...] + + parted is a partition manipulation program with a behaviour similar to + GNU Parted + + commands: + print print partitions + mklabel <type> create a new partition table + rm <num> remove a partition + mkpart <name> <fstype> <start> <end> create a new partition + unit <unit> change display/input units + refresh refresh a partition table + config CMD_UBI tristate default y if MTD_UBI diff --git a/commands/Makefile b/commands/Makefile index 4924755500..b311410276 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -146,5 +146,5 @@ obj-$(CONFIG_CMD_UBSAN) += ubsan.o obj-$(CONFIG_CMD_SELFTEST) += selftest.o obj-$(CONFIG_CMD_TUTORIAL) += tutorial.o obj-$(CONFIG_CMD_STACKSMASH) += stacksmash.o - +obj-$(CONFIG_CMD_PARTED) += parted.o UBSAN_SANITIZE_ubsan.o := y diff --git a/commands/loadenv.c b/commands/loadenv.c index 279ee52da5..ddbf66b764 100644 --- a/commands/loadenv.c +++ b/commands/loadenv.c @@ -18,7 +18,8 @@ static int do_loadenv(int argc, char *argv[]) { - char *filename = NULL, *dirname; + const char *filename = NULL; + char *dirname; unsigned flags = 0; int opt, ret; int scrub = 0; diff --git a/commands/parted.c b/commands/parted.c new file mode 100644 index 0000000000..6af18cdc57 --- /dev/null +++ b/commands/parted.c @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <common.h> +#include <command.h> +#include <block.h> +#include <getopt.h> +#include <fcntl.h> +#include <disks.h> +#include <linux/sizes.h> +#include <partitions.h> +#include <linux/math64.h> + +static struct partition_desc *gpdesc; +static bool table_needs_write; +static const char *gunit_str = "KiB"; +static uint64_t gunit = 1024; + +struct unit { + const char *str; + uint64_t size; +}; + +static struct unit units[] = { + { .str = "B", .size = 1 }, + { .str = "s", .size = 512 }, + { .str = "KiB", .size = SZ_1K }, + { .str = "MiB", .size = SZ_1M }, + { .str = "GiB", .size = SZ_1G }, + { .str = "TiB", .size = SZ_1T }, + { .str = "KB", .size = 1000ULL }, + { .str = "MB", .size = 1000ULL * 1000 }, + { .str = "GB", .size = 1000ULL * 1000 * 1000 }, + { .str = "TB", .size = 1000ULL * 1000 * 1000 * 1000 }, + { .str = "k", .size = SZ_1K }, + { .str = "K", .size = SZ_1K }, + { .str = "M", .size = SZ_1M }, + { .str = "G", .size = SZ_1G }, +}; + +static int parted_strtoull(const char *str, uint64_t *val, uint64_t *mult) +{ + char *end; + int i; + + *val = simple_strtoull(str, &end, 0); + + if (!*end) { + *mult = 0; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(units); i++) { + if (!strcmp(end, units[i].str)) { + *mult = units[i].size; + return 0; + } + } + + printf("Error: Cannot read \"%s\" as number\n", str); + + return -EINVAL; +} + +static struct partition_desc *pdesc_get(struct block_device *blk) +{ + if (gpdesc) + return gpdesc; + + gpdesc = partition_table_read(blk); + if (!gpdesc) { + printf("Cannot read partition table\n"); + return NULL; + } + + return gpdesc; +} + +static int do_unit(struct block_device *blk, int argc, char *argv[]) +{ + int i; + + if (argc < 2) { + printf("Error: missing unit\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(units); i++) { + if (!strcmp(units[i].str, argv[1])) { + gunit_str = units[i].str; + gunit = units[i].size; + return 2; + } + } + + printf("invalid unit: %s\n", argv[1]); + + return -EINVAL; +} + +static int do_print(struct block_device *blk, int argc, char *argv[]) +{ + struct partition_desc *pdesc; + struct partition *part; + + pdesc = pdesc_get(blk); + if (!pdesc) { + printf("Error: Cannot get partition table from %s\n", blk->cdev.name); + return -EINVAL; + } + + printf("Disk /dev/%s: %s\n", blk->cdev.name, + size_human_readable(blk->num_blocks << SECTOR_SHIFT)); + printf("Partition Table: %s\n", pdesc->parser->name); + + printf("Number Start End Size Name\n"); + + list_for_each_entry(part, &pdesc->partitions, list) { + uint64_t start = part->first_sec << SECTOR_SHIFT; + uint64_t size = part->size << SECTOR_SHIFT; + uint64_t end = start + size - SECTOR_SIZE; + + printf(" %3d %10llu%-3s %10llu%-3s %10llu%-3s %-36s\n", + part->num, + div64_u64(start, gunit), gunit_str, + div64_u64(end, gunit), gunit_str, + div64_u64(size, gunit), gunit_str, + part->name); + } + + return 1; +} + +static int do_mkpart(struct block_device *blk, int argc, char *argv[]) +{ + struct partition_desc *pdesc; + uint64_t start, end; + const char *name, *fs_type; + int ret; + uint64_t mult; + + if (argc < 5) { + printf("Error: Missing required arguments\n"); + return -EINVAL; + } + + name = argv[1]; + fs_type = argv[2]; + + ret = parted_strtoull(argv[3], &start, &mult); + if (ret) + return ret; + + ret = parted_strtoull(argv[4], &end, &mult); + if (ret) + return ret; + + if (!mult) + mult = gunit; + + start *= mult; + end *= mult; + + /* If not on sector boundaries move start up and end down */ + start = ALIGN(start, SECTOR_SIZE); + end = ALIGN_DOWN(end, SECTOR_SIZE); + + /* convert to LBA */ + start >>= SECTOR_SHIFT; + end >>= SECTOR_SHIFT; + + /* + * When unit is >= KB then substract one sector for user convenience. + * It allows to start the next partition where the previous ends + */ + if (mult >= 1000) + end -= 1; + + pdesc = pdesc_get(blk); + if (!pdesc) + return -EINVAL; + + ret = partition_create(pdesc, name, fs_type, start, end); + + if (!ret) + table_needs_write = true; + + return ret < 0 ? ret : 5; +} + +static int do_rmpart(struct block_device *blk, int argc, char *argv[]) +{ + struct partition_desc *pdesc; + unsigned long num; + int ret; + + if (argc < 2) { + printf("Error: Expecting a partition number.\n"); + return -EINVAL; + } + + ret = kstrtoul(argv[1], 0, &num); + if (ret) + return ret; + + pdesc = pdesc_get(blk); + if (!pdesc) + return -EINVAL; + + ret = partition_remove(pdesc, num); + if (ret) + return ret; + + table_needs_write = true; + + return 2; +} + +static int do_mklabel(struct block_device *blk, int argc, char *argv[]) +{ + struct partition_desc *pdesc; + + if (argc < 2) { + printf("Error: Expecting a disk label type.\n"); + return -EINVAL; + } + + pdesc = partition_table_new(blk, argv[1]); + if (IS_ERR(pdesc)) { + printf("Error: Cannot create partition table: %pe\n", pdesc); + return PTR_ERR(pdesc); + } + + table_needs_write = true; + + if (gpdesc) + partition_table_free(gpdesc); + gpdesc = pdesc; + + return 2; +} + +static int do_refresh(struct block_device *blk, int argc, char *argv[]) +{ + struct partition_desc *pdesc; + + pdesc = pdesc_get(blk); + if (!pdesc) + return -EINVAL; + + table_needs_write = true; + + return 1; +} + +struct parted_command { + const char *name; + int (*command)(struct block_device *blk, int argc, char *argv[]); +}; + +struct parted_command parted_commands[] = { + { + .name = "mkpart", + .command = do_mkpart, + }, { + .name = "print", + .command = do_print, + }, { + .name = "rm", + .command = do_rmpart, + }, { + .name = "mklabel", + .command = do_mklabel, + }, { + .name = "unit", + .command = do_unit, + }, { + .name = "refresh", + .command = do_refresh, + }, +}; + +static int parted_run_command(struct block_device *blk, int argc, char *argv[]) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(parted_commands); i++) { + struct parted_command *cmd = &parted_commands[i]; + + if (!strcmp(argv[0], cmd->name)) + return cmd->command(blk, argc, argv); + } + + printf("No such command: %s\n", argv[0]); + + return COMMAND_ERROR; +} + +static int do_parted(int argc, char *argv[]) +{ + struct cdev *cdev; + struct block_device *blk; + int ret = 0; + + table_needs_write = false; + gpdesc = NULL; + + if (argc < 3) + return COMMAND_ERROR_USAGE; + + cdev = cdev_open_by_name(argv[1], O_RDWR); + if (!cdev) { + printf("Cannot open %s\n", argv[1]); + return COMMAND_ERROR; + } + + blk = cdev_get_block_device(cdev); + if (!blk) { + ret = -EINVAL; + goto err; + } + + argc -= 2; + argv += 2; + + while (argc) { + debug("---> run command %s\n", argv[0]); + ret = parted_run_command(blk, argc, argv); + if (ret < 0) + break; + + argc -= ret; + argv += ret; + + ret = 0; + } + + if (!ret && gpdesc && table_needs_write) + ret = partition_table_write(gpdesc); + +err: + if (gpdesc) + partition_table_free(gpdesc); + + cdev_close(cdev); + + return ret; +} + +BAREBOX_CMD_HELP_START(parted) +BAREBOX_CMD_HELP_TEXT("parted is a partition manipulation program with a behaviour similar to") +BAREBOX_CMD_HELP_TEXT("GNU Parted") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("commands:") +BAREBOX_CMD_HELP_OPT ("print", "print partitions") +BAREBOX_CMD_HELP_OPT ("mklabel <type>", "create a new partition table") +BAREBOX_CMD_HELP_OPT ("rm <num>", "remove a partition") +BAREBOX_CMD_HELP_OPT ("mkpart <name> <fstype> <start> <end>", "create a new partition") +BAREBOX_CMD_HELP_OPT ("unit <unit>", "change display/input units") +BAREBOX_CMD_HELP_OPT ("refresh", "refresh a partition table") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("<unit> can be one of \"s\" (sectors), \"B\" (bytes), \"kB\", \"MB\", \"GB\", \"TB\",") +BAREBOX_CMD_HELP_TEXT("\"KiB\", \"MiB\", \"GiB\" or \"TiB\"") +BAREBOX_CMD_HELP_TEXT("<type> must be \"gpt\"") +BAREBOX_CMD_HELP_TEXT("<fstype> can be one of \"ext2\", \"ext3\", \"ext4\", \"fat16\", \"fat32\" or \"bbenv\"") +BAREBOX_CMD_HELP_TEXT("<name> for MBR partition tables can be one of \"primary\", \"extended\" or") +BAREBOX_CMD_HELP_TEXT("\"logical\". For GPT this is a name string.") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(parted) + .cmd = do_parted, + BAREBOX_CMD_DESC("edit partition tables") + BAREBOX_CMD_OPTS("<device> [command [options...]...]") + BAREBOX_CMD_GROUP(CMD_GRP_FILE) + BAREBOX_CMD_HELP(cmd_parted_help) +BAREBOX_CMD_END |