summaryrefslogtreecommitdiff
path: root/libdm
diff options
context:
space:
mode:
authorBryn M. Reeves <bmr@redhat.com>2016-02-18 16:14:43 +0000
committerBryn M. Reeves <bmr@redhat.com>2016-07-05 19:53:16 +0100
commit81fad9e853c45a5c3e56b2bede3a3fc7d7bed30b (patch)
treef89210ebf2a4f00693259553a1935ea9a5b6dfb0 /libdm
parentd382e660356f1095040b8a84b54a0c1db0ab78b1 (diff)
downloadlvm2-81fad9e853c45a5c3e56b2bede3a3fc7d7bed30b.tar.gz
libdm: add dm_bitset_parse_list()
Add a function to parse a list of integer values and ranges into a dm_bitset representation. Individual values signify that that bit is set in the resulting mask and ranges are given as a pair of start and end values, M-N, such that M and N are the first and last members of the range (inclusive). The implementation is based on the kernel's __bitmap_parselist() that is used for cpumasks and other set configuration passed in string form from user space.
Diffstat (limited to 'libdm')
-rw-r--r--libdm/.exported_symbols.DM_1_02_1291
-rw-r--r--libdm/datastruct/bitset.c98
-rw-r--r--libdm/libdevmapper.h10
3 files changed, 109 insertions, 0 deletions
diff --git a/libdm/.exported_symbols.DM_1_02_129 b/libdm/.exported_symbols.DM_1_02_129
new file mode 100644
index 000000000..fbd2a57cc
--- /dev/null
+++ b/libdm/.exported_symbols.DM_1_02_129
@@ -0,0 +1 @@
+dm_bitset_parse_list
diff --git a/libdm/datastruct/bitset.c b/libdm/datastruct/bitset.c
index 5aaa88726..2f84ea477 100644
--- a/libdm/datastruct/bitset.c
+++ b/libdm/datastruct/bitset.c
@@ -15,6 +15,8 @@
#include "dmlib.h"
+#include <ctype.h>
+
/* FIXME: calculate this. */
#define INT_SHIFT 5
@@ -103,3 +105,99 @@ int dm_bit_get_first(dm_bitset_t bs)
{
return dm_bit_get_next(bs, -1);
}
+
+/*
+ * Based on the Linux kernel __bitmap_parselist from lib/bitmap.c
+ */
+dm_bitset_t dm_bitset_parse_list(const char *str, struct dm_pool *mem)
+{
+ unsigned a, b;
+ int c, old_c, totaldigits, ndigits, nmaskbits;
+ int at_start, in_range;
+ dm_bitset_t mask = NULL;
+ const char *start = str;
+ size_t len;
+
+scan:
+ len = strlen(str);
+ totaldigits = c = 0;
+ nmaskbits = 0;
+ do {
+ at_start = 1;
+ in_range = 0;
+ a = b = 0;
+ ndigits = totaldigits;
+
+ /* Get the next value or range of values */
+ while (len) {
+ old_c = c;
+ c = *str++;
+ len--;
+ if (isspace(c))
+ continue;
+
+ /* A '\0' or a ',' signal the end of a value or range */
+ if (c == '\0' || c == ',')
+ break;
+ /*
+ * whitespaces between digits are not allowed,
+ * but it's ok if whitespaces are on head or tail.
+ * when old_c is whilespace,
+ * if totaldigits == ndigits, whitespace is on head.
+ * if whitespace is on tail, it should not run here.
+ * as c was ',' or '\0',
+ * the last code line has broken the current loop.
+ */
+ if ((totaldigits != ndigits) && isspace(old_c))
+ goto_bad;
+
+ if (c == '-') {
+ if (at_start || in_range)
+ return_0;
+ b = 0;
+ in_range = 1;
+ at_start = 1;
+ continue;
+ }
+
+ if (!isdigit(c))
+ goto_bad;
+
+ b = b * 10 + (c - '0');
+ if (!in_range)
+ a = b;
+ at_start = 0;
+ totaldigits++;
+ }
+ if (ndigits == totaldigits)
+ continue;
+ /* if no digit is after '-', it's wrong */
+ if (at_start && in_range)
+ goto_bad;
+ if (!(a <= b))
+ goto_bad;
+ if (b >= nmaskbits)
+ nmaskbits = b + 1;
+ while ((a <= b) && mask) {
+ dm_bit_set(mask, a);
+ a++;
+ }
+ } while (len && c == ',');
+
+ if (!mask) {
+ if (!(mask = dm_bitset_create(mem, nmaskbits)))
+ goto_bad;
+ str = start;
+ goto scan;
+ }
+
+ return mask;
+bad:
+ if (mask) {
+ if (mem)
+ dm_pool_free(mem, mask);
+ else
+ dm_bitset_destroy(mask);
+ }
+ return NULL;
+}
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 7fd765c8e..36681882d 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -1843,6 +1843,16 @@ int dm_bit_get_next(dm_bitset_t bs, int last_bit);
#define dm_bit_copy(bs1, bs2) \
memcpy((bs1) + 1, (bs2) + 1, ((*(bs1) / DM_BITS_PER_INT) + 1) * sizeof(int))
+/*
+ * Parse a string representation of a bitset into a dm_bitset_t. The
+ * notation used is identical to the kernel bitmap parser (cpuset etc.)
+ * and supports both lists ("1,2,3") and ranges ("1-2,5-8"). If the mem
+ * parameter is NULL memory for the bitset will be allocated using
+ * dm_malloc(). Otherwise the bitset will be allocated using the supplied
+ * dm_pool.
+ */
+dm_bitset_t dm_bitset_parse_list(const char *str, struct dm_pool *mem);
+
/* Returns number of set bits */
static inline unsigned hweight32(uint32_t i)
{