summaryrefslogtreecommitdiffstats
path: root/commands
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2024-02-21 07:43:53 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2024-02-21 07:43:53 +0100
commit4928cf0220752bc593f58faecaa4fb932ce7017c (patch)
tree34465dd7cec16a98d4f0d78f0bc60eaefb58ab5b /commands
parentb4186752c6abece215a27bfad014164accfe3e28 (diff)
parent9f868f78bc5473d02a1e85debfa302ba370cbc2e (diff)
downloadbarebox-4928cf0220752bc593f58faecaa4fb932ce7017c.tar.gz
barebox-4928cf0220752bc593f58faecaa4fb932ce7017c.tar.xz
Merge branch 'for-next/partitions'
Diffstat (limited to 'commands')
-rw-r--r--commands/Kconfig21
-rw-r--r--commands/Makefile2
-rw-r--r--commands/loadenv.c3
-rw-r--r--commands/parted.c374
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