Modeled on dmsetup(8) from LVM2. This lets the user create/remove arbitrary dm devices using the same table file format used in Linux, and dump information about currently configured devices.
Signed-off-by: Tobias Waldekranz <tob...@waldekranz.com> --- commands/Kconfig | 14 +++++ commands/Makefile | 1 + commands/dmsetup.c | 145 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 commands/dmsetup.c diff --git a/commands/Kconfig b/commands/Kconfig index 1626912c30..219f626c3e 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -732,6 +732,20 @@ config CMD_PARTED unit <unit> change display/input units refresh refresh a partition table +config CMD_DMSETUP + tristate + depends on DM_BLK + prompt "dmsetup" + help + dmsetup - low level interface to the device mapper + + Compose virtual block devices from a table of mappings from + logical block addresses to various data sources, such as + linear ranges from other existing devices. + + commands: + create <name> <table-file> + config CMD_UBI tristate default y if MTD_UBI diff --git a/commands/Makefile b/commands/Makefile index d9403b18d5..6b010fe30c 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -166,4 +166,5 @@ obj-$(CONFIG_CMD_STACKSMASH) += stacksmash.o obj-$(CONFIG_CMD_PARTED) += parted.o obj-$(CONFIG_CMD_EFI_HANDLE_DUMP) += efi_handle_dump.o obj-$(CONFIG_CMD_HOST) += host.o +obj-$(CONFIG_CMD_DMSETUP) += dmsetup.o UBSAN_SANITIZE_ubsan.o := y diff --git a/commands/dmsetup.c b/commands/dmsetup.c new file mode 100644 index 0000000000..722aa6cbf0 --- /dev/null +++ b/commands/dmsetup.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: © 2025 Tobias Waldekranz <tob...@waldekranz.com>, Wires + +#include <command.h> +#include <common.h> +#include <dm.h> +#include <libfile.h> + +static struct dm_device *dmsetup_find(const char *name) +{ + struct dm_device *dm; + + dm = dm_find_by_name(name); + if (IS_ERR_OR_NULL(dm)) { + pr_err("Found no device named \"%s\"\n", name); + return NULL; + } + + return dm; +} + +static int dmsetup_remove(int argc, char *argv[]) +{ + struct dm_device *dm; + + if (argc != 1) + return COMMAND_ERROR_USAGE; + + dm = dmsetup_find(argv[0]); + if (!dm) + return COMMAND_ERROR; + + dm_destroy(dm); + + pr_info("Removed %s\n", argv[0]); + return COMMAND_SUCCESS; +} + +static int dmsetup_info_one(struct dm_device *dm, void *_n) +{ + int *n = _n; + char *str; + + if (*n) + pr_info("\n"); + + str = dm_asprint(dm); + pr_info("%s", str); + free(str); + (*n)++; + return 0; +} + +static int dmsetup_info(int argc, char *argv[]) +{ + struct dm_device *dm; + int n = 0; + + if (argc == 0) { + dm_foreach(dmsetup_info_one, &n); + if (n == 0) + pr_info("No devices found\n"); + return COMMAND_SUCCESS; + } + + if (argc != 1) + return COMMAND_ERROR_USAGE; + + dm = dmsetup_find(argv[0]); + if (!dm) + return COMMAND_ERROR; + + dmsetup_info_one(dm, &n); + return COMMAND_SUCCESS; +} + + +static int dmsetup_create(int argc, char *argv[]) +{ + struct dm_device *dm; + char *table; + + if (argc != 2) + return COMMAND_ERROR_USAGE; + + table = read_file(argv[1], NULL); + if (!table) { + pr_err("Failed to read table from %s: %m\n", argv[1]); + return COMMAND_ERROR; + } + + dm = dm_create(argv[0], table); + free(table); + if (IS_ERR_OR_NULL(dm)) { + pr_err("Failed to create %s: %s\n", + argv[0], strerror(-PTR_ERR(dm))); + return COMMAND_ERROR; + } + + pr_info("Created %s\n", argv[0]); + return COMMAND_SUCCESS; +} + +static int do_dmsetup(int argc, char *argv[]) +{ + const char *cmd; + + if (argc < 2) + return COMMAND_ERROR_USAGE; + + cmd = argv[1]; + argc -= 2; + argv += 2; + + if (!strcmp(cmd, "create")) + return dmsetup_create(argc, argv); + else if (!strcmp(cmd, "info")) + return dmsetup_info(argc, argv); + else if (!strcmp(cmd, "remove")) + return dmsetup_remove(argc, argv); + + printf("Unknown command: %s\n", cmd); + return -EINVAL; +} + +BAREBOX_CMD_HELP_START(dmsetup) +BAREBOX_CMD_HELP_TEXT("dmsetup - low level interface to the device mapper") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Compose virtual block devices from a table of mappings from") +BAREBOX_CMD_HELP_TEXT("logical block addresses to various data sources, such as") +BAREBOX_CMD_HELP_TEXT("linear ranges from other existing devices.") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("commands:") +BAREBOX_CMD_HELP_OPT("create <name> <table-file>", "Create new device") +BAREBOX_CMD_HELP_OPT("info [<name>]", "Show device information") +BAREBOX_CMD_HELP_OPT("remove <name>", "Remove device") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(dmsetup) + .cmd = do_dmsetup, + BAREBOX_CMD_DESC("low level interface to the device mapper") + BAREBOX_CMD_OPTS("<command> [args...]") + BAREBOX_CMD_GROUP(CMD_GRP_PART) + BAREBOX_CMD_HELP(cmd_dmsetup_help) +BAREBOX_CMD_END -- 2.43.0