diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM index 30d6d8267..28999f117 100644 --- a/WHATS_NEW_DM +++ b/WHATS_NEW_DM @@ -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 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 + /* 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) {