]> sourceware.org Git - lvm2.git/commitdiff
libdm: add dm_bitset_parse_list()
authorBryn M. Reeves <bmr@redhat.com>
Thu, 18 Feb 2016 16:14:43 +0000 (16:14 +0000)
committerBryn M. Reeves <bmr@redhat.com>
Tue, 5 Jul 2016 18:53:16 +0000 (19:53 +0100)
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.

WHATS_NEW_DM
libdm/.exported_symbols.DM_1_02_129 [new file with mode: 0644]
libdm/datastruct/bitset.c
libdm/libdevmapper.h

index 30d6d8267acf0f1d9a933fa98a55d1bbe0964609..28999f117f2145e9909d164df680d35643cd8ad0 100644 (file)
@@ -1,5 +1,6 @@
 Version 1.02.129 - 
 =================================
+  Add dm_bitset_parse_list() to parse a string representation of a bitset.
   Thin dmeventd plugin umounts lvm2 volume only when pool is 95% or more.
 
 Version 1.02.128 - 25th June 2016
diff --git a/libdm/.exported_symbols.DM_1_02_129 b/libdm/.exported_symbols.DM_1_02_129
new file mode 100644 (file)
index 0000000..fbd2a57
--- /dev/null
@@ -0,0 +1 @@
+dm_bitset_parse_list
index 5aaa887269bfb608ffc368dbcdd3694131b4cfd7..2f84ea477ea17dd3102ab251f23371c5122221e9 100644 (file)
@@ -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;
+}
index 7fd765c8e589fc582bde95ced1b7efb2191a6571..36681882d684adf92ec160c6174cffe38872f20c 100644 (file)
@@ -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)
 {
This page took 0.050253 seconds and 5 git commands to generate.