linux-lvm.redhat.com archive mirror
 help / color / mirror / Atom feed
* [linux-lvm] [PATCH v2 0/3] dmsetup: add bootformat support
@ 2017-05-16 15:20 Enric Balletbo i Serra
  2017-05-16 15:20 ` [linux-lvm] [PATCH v2 1/3] libdm: Add dm_find_unescaped_char to libdevmapper Enric Balletbo i Serra
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Enric Balletbo i Serra @ 2017-05-16 15:20 UTC (permalink / raw)
  To: Alasdair Kergon, linux-lvm; +Cc: Kees Cook, Mike Snitzer

Dear all,

Based on the comments received in the IRC this is a second patchet to add boot format
support.

Bootformat is specified as a simple string of data separated by commas and
optionally semi-colons, where:
 - a comma is used to separate fields like name, uuid, mode and table (specifies
   one device)
 - a semi-colon is used to separate devices.

So the format will look like this:

 <dev_name>,<uuid>,<flags>,<table>[,<table>+][;<dev_name>,<uuid>,<flags>,<table>[,<table>+]]+

See the following example.

To supply the new format to dmsetup (splitted in multiple lines for readibility)

 $ dmsetup -v create --bootformat "lroot,,rw, \
    0 2097152 linear 7:0 0,\
    2097152 2097152 linear 7:1 0,\
    4194304 2097152 linear 7:2 0;\
    mroot,,rw,\
    0 2097152 linear 7:3 0;\
    kroot,,rw,\
    0 2097152 linear 7:4 0"

Name:              lroot
State:             ACTIVE
Read Ahead:        256
Tables present:    LIVE
Open count:        0
Event number:      0
Major, minor:      253, 3
Number of targets: 3

Name:              mroot
State:             ACTIVE
Read Ahead:        256
Tables present:    LIVE
Open count:        0
Event number:      0
Major, minor:      253, 4
Number of targets: 1

Name:              kroot
State:             ACTIVE
Read Ahead:        256
Tables present:    LIVE
Open count:        0
Event number:      0
Major, minor:      253, 5
Number of targets: 1

To ask dmsetup to display your existing devices in this format:

 $ dmsetup table --bootformat lroot mroot kroot

lroot,,rw,4194304 2097152 linear 7:2 0;mroot,,rw,0 2097152 linear 7:3 0;kroot,,rw,0 2097152 linear 7:4 0;

Changes since v1 (suggested by Alasdair):
 - Add support for embedded '\,' and '\;'
 - Rename mode to flags
 - Added a man page
 - Added dmsetup-bootformat.sh test script

Enric Balletbo i Serra (3):
  libdm: Add dm_find_unescaped_char to libdevmapper.
  dmsetup: add support to output devices in bootformat style
  dmsetup: add support to create devices when bootformat is used

 libdm/.exported_symbols.Base     |   3 +
 libdm/libdevmapper.h             |  17 +++++
 libdm/libdm-string.c             |  82 +++++++++++++++++++++
 man/dmsetup.8_main               |  77 ++++++++++++++++++--
 test/shell/dmsetup-bootformat.sh |  77 ++++++++++++++++++++
 tools/dmsetup.c                  | 149 ++++++++++++++++++++++++++++++++++++++-
 6 files changed, 396 insertions(+), 9 deletions(-)
 create mode 100644 test/shell/dmsetup-bootformat.sh

-- 
2.9.3

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [linux-lvm] [PATCH v2 1/3] libdm: Add dm_find_unescaped_char to libdevmapper.
  2017-05-16 15:20 [linux-lvm] [PATCH v2 0/3] dmsetup: add bootformat support Enric Balletbo i Serra
@ 2017-05-16 15:20 ` Enric Balletbo i Serra
  2017-05-16 15:20 ` [linux-lvm] [PATCH v2 2/3] dmsetup: add support to output devices in bootformat style Enric Balletbo i Serra
  2017-05-16 15:20 ` [linux-lvm] [PATCH v2 3/3] dmsetup: add support to create devices when bootformat is used Enric Balletbo i Serra
  2 siblings, 0 replies; 4+ messages in thread
From: Enric Balletbo i Serra @ 2017-05-16 15:20 UTC (permalink / raw)
  To: Alasdair Kergon, linux-lvm; +Cc: Kees Cook, Mike Snitzer

Add helper functions to split a string into tokens ignoring escaped
chars. The function finds the first token in the string that is delimited
by one non escaped char. In case it founds an escaped token finds next
token.

When a token is found the string is terminated by overwriting the
delimiter with a null byte ('\0') and the pointer to the search string
is updated to point past the token ready for the next call.

In case no delimiter was found, the token is taken to be the entire
string.

Aditionally there is dm_unescape_colons and dm_unescape_semicolons
helpers to unescape these characters in situ, it replaces all occurrences
of "\," or "\;" with ',' or ';'. This is normally used to unescape colons
and semi-colons used in boot format.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
 libdm/.exported_symbols.Base |  3 ++
 libdm/libdevmapper.h         | 17 +++++++++
 libdm/libdm-string.c         | 82 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 102 insertions(+)

diff --git a/libdm/.exported_symbols.Base b/libdm/.exported_symbols.Base
index 4dc5c93..51c21de 100644
--- a/libdm/.exported_symbols.Base
+++ b/libdm/.exported_symbols.Base
@@ -66,6 +66,7 @@ dm_dump_memory_debug
 dm_escaped_len
 dm_escape_double_quotes
 dm_fclose
+dm_find_unescaped_char
 dm_format_dev
 dm_free_aux
 dm_get_library_version
@@ -279,8 +280,10 @@ dm_udev_get_sync_support
 dm_udev_set_checking
 dm_udev_set_sync_support
 dm_udev_wait
+dm_unescape_colons
 dm_unescape_colons_and_at_signs
 dm_unescape_double_quotes
+dm_unescape_semicolons
 dm_units_to_factor
 dm_uuid_prefix
 dm_vasprintf
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 4bd32b4..7b6c1c0 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -2662,6 +2662,23 @@ void dm_unescape_colons_and_at_signs(char *src,
  */
 int dm_strncpy(char *dest, const char *src, size_t n);
 
+char *dm_unescape_colons(char *str);
+
+char *dm_unescape_semicolons(char *str);
+
+/*
+ * Splits a string into tokens ignoring escaped chars
+ *
+ * Updates @s to point after the token, ready for the next call.
+ *
+ * @s: The string to be searched
+ * @c: The character to search for
+ *
+ * Returns:
+ *   The string found or NULL.
+ */
+char *dm_find_unescaped_char(char **str, const char c);
+
 /*
  * Recognize unit specifier in the 'units' arg and return a factor
  * representing that unit. If the 'units' contains a prefix with digits,
diff --git a/libdm/libdm-string.c b/libdm/libdm-string.c
index 2085aa8..667f8dd 100644
--- a/libdm/libdm-string.c
+++ b/libdm/libdm-string.c
@@ -444,6 +444,88 @@ int dm_strncpy(char *dest, const char *src, size_t n)
 	return 0;
 }
 
+/*
+ * Unescape characters in situ, it replaces all occurrences of "\c"
+ * with 'c'. This is normally used to unescape colons and semi-colons used
+ * in boot format.
+ */
+static char *_unescape_char(char *str, const char c)
+{
+	int i = 0, j = 0;
+	int len = strlen(str);
+
+	if (len < 2)
+		return str;
+
+	while (j < len - 1) {
+		if (str[j] == '\\' && str[j + 1] == c) {
+			j = j + 2;
+			str[i++] = c;
+			continue;
+		}
+		str[i++] = str[j++];
+	}
+
+	if (j == len - 1)
+		str[i++] = str[j];
+
+	str[i] = '\0';
+
+	return str;
+}
+
+char *dm_unescape_colons(char *str)
+{
+	return _unescape_char(str, ',');
+}
+
+char *dm_unescape_semicolons(char *str)
+{
+	return _unescape_char(str, ';');
+}
+
+#define is_even(a) (((a) & 1) == 0)
+
+/*
+ * Splits a string into tokens ignoring escaped chars
+ *
+ * Updates @s to point after the token, ready for the next call.
+ *
+ * @str: The string to be searched
+ * @c: The character to search for
+ *
+ * Returns:
+ *   The string found or NULL.
+ */
+char *dm_find_unescaped_char(char **str, const char c)
+{
+	char *s = *str;
+	char *p = strchr(*str, c);
+
+	/* loop through all the characters */
+	while (p != NULL) {
+		/* scan backwards through preceding escapes */
+		char* q = p;
+		while (q > s && *(q - 1) == '\\')
+			--q;
+		/* even number of escapes so c is a token */
+		if (is_even( p - q )) {
+			*p = '\0';
+			*str = p + 1;
+			return s;
+		}
+		/* else odd escapes so c is escaped, keep going */
+		p = strchr(p + 1, c);
+	}
+
+	if (strlen(*str)) {
+		*str += strlen(*str);
+		return s;
+	}
+
+	return NULL;
+}
+
 /* Test if the doubles are close enough to be considered equal */
 static int _close_enough(double d1, double d2)
 {
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [linux-lvm] [PATCH v2 2/3] dmsetup: add support to output devices in bootformat style
  2017-05-16 15:20 [linux-lvm] [PATCH v2 0/3] dmsetup: add bootformat support Enric Balletbo i Serra
  2017-05-16 15:20 ` [linux-lvm] [PATCH v2 1/3] libdm: Add dm_find_unescaped_char to libdevmapper Enric Balletbo i Serra
@ 2017-05-16 15:20 ` Enric Balletbo i Serra
  2017-05-16 15:20 ` [linux-lvm] [PATCH v2 3/3] dmsetup: add support to create devices when bootformat is used Enric Balletbo i Serra
  2 siblings, 0 replies; 4+ messages in thread
From: Enric Balletbo i Serra @ 2017-05-16 15:20 UTC (permalink / raw)
  To: Alasdair Kergon, linux-lvm; +Cc: Kees Cook, Mike Snitzer

Add a new parameter to be able to output the bootformat of one or more
devices. The bootformat for a device can be obtained by doing a:

 dmsetup table <device...> --bootformat

where device can be a specific device, a list of the devices or empty
for all devices. The output will look like this:

 <dev_name>,<uuid>,<flags>,<table>[,<table>+][;<dev_name>,<uuid>,<flags>,<table>[,<table>+]]+

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
 tools/dmsetup.c | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index 5c5c14c..fc99145 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -163,6 +163,7 @@ enum {
 	AREA_ARG,
 	AREAS_ARG,
 	AREA_SIZE_ARG,
+	BOOTFORMAT_ARG,
 	BOUNDS_ARG,
 	CHECKS_ARG,
 	CLEAR_ARG,
@@ -2127,6 +2128,9 @@ static int _status(CMD_ARGS)
 	int matched = 0;
 	int ls_only = 0;
 	struct dm_info info;
+	const char *uuid = NULL;
+	char bootstr[LINE_SIZE] = {0};
+	int len;
 
 	if (names)
 		name = names->name;
@@ -2171,6 +2175,9 @@ static int _status(CMD_ARGS)
 	if (!name)
 		name = dm_task_get_name(dmt);
 
+	if (!uuid)
+		uuid = dm_task_get_uuid(dmt);
+
 	/* Fetch targets and print 'em */
 	do {
 		next = dm_get_next_target(dmt, next, &start, &length,
@@ -2184,6 +2191,20 @@ static int _status(CMD_ARGS)
 			    _switches[VERBOSE_ARG])
 				_display_dev(dmt, name);
 			next = NULL;
+		} else if (_switches[BOOTFORMAT_ARG]) {
+			if (!dm_snprintf(bootstr, sizeof(bootstr), "%s,%s,%s",
+					 dm_task_get_name(dmt), uuid,
+					 info.read_only ? "ro" : "rw"))
+				goto_out;
+			if (target_type) {
+				len = strlen(bootstr);
+				if (!dm_snprintf(bootstr + len,
+						 sizeof(bootstr) - len,
+						 "," FMTu64 " " FMTu64 " %s %s",
+						 start, length, target_type,
+						 params))
+					goto_out;
+			}
 		} else if (!_switches[EXEC_ARG] || !_command_to_exec ||
 			   _switches[VERBOSE_ARG]) {
 			if (!matched && _switches[VERBOSE_ARG])
@@ -2218,6 +2239,9 @@ static int _status(CMD_ARGS)
 		matched = 1;
 	} while (next);
 
+	if (matched && _switches[BOOTFORMAT_ARG])
+		printf("%s;", bootstr);
+
 	if (multiple_devices && _switches[VERBOSE_ARG] && matched && !ls_only)
 		putchar('\n');
 
@@ -5903,7 +5927,9 @@ static struct command _dmsetup_commands[] = {
 	{"deps", "[-o <options>] [<device>...]", 0, -1, 1, 0, _deps},
 	{"stats", "<command> [<options>] [<device>...]", 1, -1, 1, 1, _stats},
 	{"status", "[<device>...] [--noflush] [--target <target_type>]", 0, -1, 1, 0, _status},
-	{"table", "[<device>...] [--target <target_type>] [--showkeys]", 0, -1, 1, 0, _status},
+	{"table", "[<device>...]\n"
+	   "\t    [--target <target_type>] [--showkeys]\n"
+	   "\t    [--bootformat]", 0, -1, 1, 0, _status},
 	{"wait", "<device> [<event_nr>] [--noflush]", 0, 2, 0, 0, _wait},
 	{"mknodes", "[<device>...]", 0, -1, 1, 0, _mknodes},
 	{"mangle", "[<device>...]", 0, -1, 1, 0, _mangle},
@@ -6468,6 +6494,7 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 		{"area", 0, &ind, AREA_ARG},
 		{"areas", 1, &ind, AREAS_ARG},
 		{"areasize", 1, &ind, AREA_SIZE_ARG},
+		{"bootformat", 0, &ind, BOOTFORMAT_ARG},
 		{"bounds", 1, &ind, BOUNDS_ARG},
 		{"checks", 0, &ind, CHECKS_ARG},
 		{"clear", 0, &ind, CLEAR_ARG},
@@ -6636,6 +6663,8 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
 			return_0;
 		if (c == 'h' || ind == HELP_ARG)
 			_switches[HELP_ARG]++;
+		if (ind == BOOTFORMAT_ARG)
+			_switches[BOOTFORMAT_ARG]++;
 		if (ind == BOUNDS_ARG) {
 			_switches[BOUNDS_ARG]++;
 			_string_args[BOUNDS_ARG] = optarg;
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [linux-lvm] [PATCH v2 3/3] dmsetup: add support to create devices when bootformat is used
  2017-05-16 15:20 [linux-lvm] [PATCH v2 0/3] dmsetup: add bootformat support Enric Balletbo i Serra
  2017-05-16 15:20 ` [linux-lvm] [PATCH v2 1/3] libdm: Add dm_find_unescaped_char to libdevmapper Enric Balletbo i Serra
  2017-05-16 15:20 ` [linux-lvm] [PATCH v2 2/3] dmsetup: add support to output devices in bootformat style Enric Balletbo i Serra
@ 2017-05-16 15:20 ` Enric Balletbo i Serra
  2 siblings, 0 replies; 4+ messages in thread
From: Enric Balletbo i Serra @ 2017-05-16 15:20 UTC (permalink / raw)
  To: Alasdair Kergon, linux-lvm; +Cc: Kees Cook, Mike Snitzer

Add a new switch to supply a bootformated string to dmsetup, we
support create one or multiple devices in one line provided to
the create command. E.g.

  dmsetup create --bootformat <multi_dev_info>|<multi_dev_info_file>

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
 man/dmsetup.8_main               |  77 ++++++++++++++++++++++---
 test/shell/dmsetup-bootformat.sh |  77 +++++++++++++++++++++++++
 tools/dmsetup.c                  | 118 ++++++++++++++++++++++++++++++++++++++-
 3 files changed, 264 insertions(+), 8 deletions(-)
 create mode 100644 test/shell/dmsetup-bootformat.sh

diff --git a/man/dmsetup.8_main b/man/dmsetup.8_main
index 4421882..dad58b1 100644
--- a/man/dmsetup.8_main
+++ b/man/dmsetup.8_main
@@ -22,14 +22,17 @@ dmsetup \(em low level logical volume management
 .de CMD_CREATE
 .  ad l
 .  BR create
-.  IR device_name
+.  IR [[device_name]
 .  RB [ -u | --uuid
 .  IR uuid ]
 .  RB \%[ --addnodeoncreate | --addnodeonresume ]
 .  RB \%[ -n | --notable | --table
 .  IR \%table | table_file ]
 .  RB [ --readahead
-.  RB \%[ + ] \fIsectors | auto | none ]
+.  RB \%[ + ] \fIsectors | auto | none ]]
+.  RB |
+.  RB \%[ --bootformat
+.  IR \%multi_dev_info | multi_dev_info_file]
 .  ad b
 ..
 .CMD_CREATE
@@ -269,9 +272,11 @@ dmsetup \(em low level logical volume management
 .de CMD_TABLE
 .  ad l
 .  BR table
-.  RB [ --target
+.  RB [[ --target
 .  IR target_type ]
-.  RB [ --showkeys ]
+.  RB [ --showkeys ]]
+.  RB |
+.  RB [ --bootformat ]
 .  RI [ device_name ...]
 .  ad b
 ..
@@ -400,6 +405,12 @@ Ensure \fI/dev/mapper\fP node exists after \fBdmsetup create\fP.
 Ensure \fI/dev/mapper\fP node exists after \fBdmsetup resume\fP (default with udev).
 .
 .HP
+.BR --bootformat
+.br
+Specify a one-line multi device setup information directly on the command line.
+See below for more information on the boot format.
+.
+.HP
 .BR --checks
 .br
 Perform additional checks on the operations requested and report
@@ -610,9 +621,12 @@ Destroys the table in the inactive table slot for device_name.
 .HP
 .CMD_CREATE
 .br
-Creates a device with the given name.
-If \fItable\fP or \fItable_file\fP is supplied, the table is loaded and made live.
-Otherwise a table is read from standard input unless \fB--notable\fP is used.
+Creates a device with the given name or multiple devices if boot format is used.
+If boot format is used we must supply a multiple device setup information
+from cmdline or standard input. See below for more information on the boot format.
+Otherwise, if \fItable\fP or \fItable_file\fP is supplied, the table is loaded
+and made live. Otherwise a table is read from standard input unless \fB--notable\fP
+is used.
 The optional \fIuuid\fP can be used in place of
 device_name in subsequent dmsetup commands.
 If successful the device will appear in table and for live
@@ -824,6 +838,8 @@ Real encryption keys are suppressed in the table output for the crypt
 target unless the \fB--showkeys\fP parameter is supplied. Kernel key
 references prefixed with \fB:\fP are not affected by the parameter and get
 displayed always.
+With \fB--bootformat\fP, the information relating to the specified targets
+is displayed in boot format style.
 .
 .HP
 .CMD_TARGETS
@@ -996,6 +1012,53 @@ documentation directory for the device-mapper package.)
 .br
 2056320 2875602 linear /dev/hdb 1028160
 .
+.SH BOOT FORMAT
+.
+Simple string of data separated by commas and optionally semi-colons, where:
+.br
+- A comma is used to separate the fields for one device.
+.br
+- A semi-colon is used to separate devices.
+.TP
+The string is of the form:
+.sp
+<name>,<uuid>,<flags>,<table>[,<table>+][;<dev_name>,<uuid>,<flags>,<table>[,<table>+]]
+.sp
+.TP
+One device args include:
+.
+.TP
+.B name
+The name of the device.
+.TP
+.B uuid
+The UUID of the device or empty
+.TP
+.B flags
+Supported flags are:
+.sp
+.B ro
+Sets the table being loaded for the device read-only (default)
+.br
+.B rw
+Sets the table being loaded for the device read-write
+.sp
+.TP
+.B table
+See table format above.
+.TP
+.
+.SH EXAMPLES
+.
+# A simple linear device
+.br
+test-linear-small,,ro,0 2097152 linear /dev/loop0 0, 2097152 2097152 linear /dev/loop1 0'
+.br
+# Two linear devices
+.br
+test-linear-small,,ro,0 2097152 linear /dev/loop0 0;test-linear-large,,rw, 0 2097152 linear /dev/loop1 0, 2097152 2097152 linear /dev/loop2 0
+.br
+.
 .SH ENVIRONMENT VARIABLES
 .
 .TP
diff --git a/test/shell/dmsetup-bootformat.sh b/test/shell/dmsetup-bootformat.sh
new file mode 100644
index 0000000..8174ef4
--- /dev/null
+++ b/test/shell/dmsetup-bootformat.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+# Copyright (C) 2017 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# unrelated to lvm2 daemons
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_CLVMD=1
+SKIP_WITH_LVMETAD=1
+
+. lib/inittest
+
+LOOP="/dev/loop"
+
+for i in 0 1 2 3; do
+	[ -b /dev/loop${i} ] || skip "test requires /dev/loop${i}"
+done;
+
+# some constants
+UUID_A="457f0e3b-dc4b-4d39-81d4-2423a8ec0fa3"
+UUID_B="34e08a5b-8108-4939-b7e8-ba90b0b7d767"
+TABLES_A="0 2097152 linear ${LOOP}0 0, 2097152 2097152 linear ${LOOP}1 0"
+TABLES_B="0 2097152 linear ${LOOP}2 0, 2097152 2097152 linear ${LOOP}3 0"
+
+# test create/remove a single device
+dmsetup create --bootformat "test-linear-small,${UUID_A},rw,${TABLES_A}"
+dmsetup remove test-linear-small
+
+# test create/remove multiple devices
+dmsetup create --bootformat "test-linear-small,${UUID_A},rw,${TABLES_A};test-linear-large,${UUID_B},rw,${TABLES_B}"
+dmsetup remove test-linear-small test-linear-large
+
+# test empty fields
+dmsetup create --bootformat "test-linear-small,,,${TABLES_A}"
+dmsetup remove test-linear-small
+
+# test flags options (rw | ro | <empty>)
+# flag : rw
+dmsetup create --bootformat "test-linear-small,${UUID_A},rw,${TABLES_A}"
+# check that READ-ONLY string is not in State line
+str=`dmsetup info test-linear-small | grep 'State:'`
+test "${str#*READ-ONLY}" == "$str"
+dmsetup remove test-linear-small
+# flag : ro
+dmsetup create --bootformat "test-linear-small,${UUID_A},ro,${TABLES_A}"
+# check that READ-ONLY string is in State line
+str=`dmsetup info test-linear-small | grep 'State:'`
+test "${str#*READ-ONLY}" != "$str"
+dmsetup remove test-linear-small
+# flag : <emtpy>
+dmsetup create --bootformat "test-linear-small,${UUID_A},,${TABLES_A}"
+# check that READ-ONLY string is in State line
+str=`dmsetup info test-linear-small | grep 'State:'`
+test "${str#*READ-ONLY}" != "$str"
+dmsetup remove test-linear-small
+
+# let's try some scaped names
+declare -A escaped_names=(
+    ["test,linear,small"]="test\,linear\,small"
+    [",test,,linear,"]="\,test\,\,linear\,"
+    ["test;linear;small"]="test\;linear\;small"
+    [";test;;linear;"]="\;test\;\;linear\;"
+    [";test,linear;small,"]="\;test\,linear\;small\,"
+)
+
+for name in "${!escaped_names[@]}"
+do
+    dmsetup create --bootformat "${escaped_names[$name]},,ro,${TABLES_A}"
+    dmsetup remove "${name}"
+done
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index fc99145..dec3c84 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -1097,6 +1097,110 @@ out:
 	return r;
 }
 
+static int _parse_device(char *dev_info)
+{
+	int r = 0;
+	struct dm_task *dmt;
+	uint32_t cookie = 0;
+	uint16_t udev_flags = 0;
+	int line = 0, field = 0;
+	char *str = dev_info, *ptr = dev_info;
+
+	if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
+		return_0;
+
+	while ((str = dm_find_unescaped_char(&ptr, ',')) != NULL ) {
+                str = dm_unescape_colons(str);
+		switch (field) {
+		case 0: /* set device name */
+			if (!dm_task_set_name(dmt, str))
+				goto_out;
+                        break;
+		case 1: /* set uuid if any */
+			if (strlen(str) && !dm_task_set_uuid(dmt, str))
+				goto_out;
+			break;
+		case 2:
+			/* set as read-only if flags = "ro" | "" */
+			if (!strncmp(str, "ro", strlen(str)) || !strlen(str)) {
+				if (!dm_task_set_ro(dmt))
+					goto_out;
+			} else if (!strncmp(str, "rw", strlen(str))) {
+                                break;
+                        } else
+                                goto_out;
+			break;
+		default:
+			if (!_parse_line(dmt, str, "", line++))
+				goto_out;
+			break;
+		}
+		field++;
+	}
+
+	if (field < 4)
+		goto_out;
+
+	if (!_set_task_add_node(dmt))
+		goto_out;
+
+	if (_udev_cookie)
+		cookie = _udev_cookie;
+
+	if (_udev_only)
+		udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
+
+	if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
+	    !_task_run(dmt))
+		goto_out;
+
+	r = 1;
+
+out:
+	if (!_udev_cookie)
+		(void) dm_udev_wait(cookie);
+
+	if (r && _switches[VERBOSE_ARG])
+		r = _display_info(dmt);
+
+	dm_task_destroy(dmt);
+
+	return r;
+}
+
+static int _create_multi_devices(const char *multi_dev_info)
+{
+	char *buffer = NULL, *dev_info, *ptr;
+	size_t buffer_size = LINE_SIZE;
+	int r = 0;
+
+	if (!(buffer = dm_malloc(buffer_size))) {
+		err("Failed to malloc line buffer.");
+		return 0;
+	}
+
+	if (!multi_dev_info) {	/* get info from stdin */
+		if (!(getline(&buffer, &buffer_size, stdin) > 0))
+			goto_out;
+	} else if (!dm_strncpy(buffer, multi_dev_info, LINE_SIZE))
+		goto_out;
+
+	dev_info = ptr = buffer;
+
+	while ((dev_info = dm_find_unescaped_char(&ptr, ';')) != NULL ) {
+                dev_info = dm_unescape_semicolons(dev_info);
+		if (!_parse_device(dev_info))
+			goto_out;
+        }
+
+	r = 1;
+out:
+	memset(buffer, 0, buffer_size);
+	dm_free(buffer);
+
+	return r;
+}
+
 static int _create(CMD_ARGS)
 {
 	int r = 0;
@@ -1105,6 +1209,16 @@ static int _create(CMD_ARGS)
 	uint32_t cookie = 0;
 	uint16_t udev_flags = 0;
 
+	/* arguments are in bootformat style */
+	if (_switches[BOOTFORMAT_ARG]) {
+		if (argc > 1)
+			return 0;
+		if (argc == 1)
+			file = argv[0];
+		return _create_multi_devices(file);
+	}
+
+	/* otherwise  */
 	if (argc == 2)
 		file = argv[1];
 
@@ -5909,7 +6023,8 @@ static struct command _dmsetup_commands[] = {
 	  "\t    [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
 	  "\t    [-u|uuid <uuid>] [--addnodeonresume|--addnodeoncreate]\n"
 	  "\t    [--readahead {[+]<sectors>|auto|none}]\n"
-	  "\t    [-n|--notable|--table {<table>|<table_file>}]", 1, 2, 0, 0, _create},
+	  "\t    [-n|--notable|--table {<table>|<table_file>}]\n"
+	  "\t    [--bootformat {<multi_dev_info>|<multi_dev_info_file>}]", 0, 2, 0, 0, _create},
 	{"remove", "[--deferred] [-f|--force] [--retry] <device>...", 0, -1, 1, 0, _remove},
 	{"remove_all", "[-f|--force]", 0, 0, 0, 0, _remove_all},
 	{"suspend", "[--noflush] [--nolockfs] <device>...", 0, -1, 1, 0, _suspend},
@@ -6004,6 +6119,7 @@ static void _dmsetup_usage(FILE *out)
 	fprintf(out, "<mangling_mode> is one of 'none', 'auto' and 'hex'.\n");
 	fprintf(out, "<fields> are comma-separated.  Use 'help -c' for list.\n");
 	fprintf(out, "Table_file contents may be supplied on stdin.\n");
+	fprintf(out, "Multi_dev_info_file contents may be supplied on stdin.\n");
 	fprintf(out, "Options are: devno, devname, blkdevname.\n");
 	fprintf(out, "Tree specific options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
 		     "                           blkdevname, [no]device, active, open, rw and uuid.\n");
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-05-16 15:20 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-16 15:20 [linux-lvm] [PATCH v2 0/3] dmsetup: add bootformat support Enric Balletbo i Serra
2017-05-16 15:20 ` [linux-lvm] [PATCH v2 1/3] libdm: Add dm_find_unescaped_char to libdevmapper Enric Balletbo i Serra
2017-05-16 15:20 ` [linux-lvm] [PATCH v2 2/3] dmsetup: add support to output devices in bootformat style Enric Balletbo i Serra
2017-05-16 15:20 ` [linux-lvm] [PATCH v2 3/3] dmsetup: add support to create devices when bootformat is used Enric Balletbo i Serra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).