parse-util: Introduce new parse_range function
This function will be useful for CPUAffinity settings that involve ranges of CPUs. Make it generic and include test coverage to prevent regressions.
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "extract-word.h"
|
||||
#include "parse-util.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
@@ -207,6 +209,43 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_range(const char *t, unsigned *lower, unsigned *upper) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
unsigned l, u;
|
||||
int r;
|
||||
|
||||
assert(lower);
|
||||
assert(upper);
|
||||
|
||||
/* Extract the lower bound. */
|
||||
r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = safe_atou(word, &l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Check for the upper bound and extract it if needed */
|
||||
if (!t)
|
||||
/* Single number with no dashes. */
|
||||
u = l;
|
||||
else if (!*t)
|
||||
/* Trailing dash is an error. */
|
||||
return -EINVAL;
|
||||
else {
|
||||
r = safe_atou(t, &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*lower = l;
|
||||
*upper = u;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *format_bytes(char *buf, size_t l, uint64_t t) {
|
||||
unsigned i;
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ int parse_pid(const char *s, pid_t* ret_pid);
|
||||
int parse_mode(const char *s, mode_t *ret);
|
||||
|
||||
int parse_size(const char *t, uint64_t base, uint64_t *size);
|
||||
int parse_range(const char *t, unsigned *lower, unsigned *upper);
|
||||
|
||||
#define FORMAT_BYTES_MAX 8
|
||||
char *format_bytes(char *buf, size_t l, uint64_t t);
|
||||
|
||||
@@ -979,6 +979,185 @@ static void test_parse_size(void) {
|
||||
assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE);
|
||||
}
|
||||
|
||||
static void test_parse_range(void) {
|
||||
unsigned lower, upper;
|
||||
|
||||
/* Successful cases */
|
||||
assert_se(parse_range("111", &lower, &upper) == 0);
|
||||
assert_se(lower == 111);
|
||||
assert_se(upper == 111);
|
||||
|
||||
assert_se(parse_range("111-123", &lower, &upper) == 0);
|
||||
assert_se(lower == 111);
|
||||
assert_se(upper == 123);
|
||||
|
||||
assert_se(parse_range("123-111", &lower, &upper) == 0);
|
||||
assert_se(lower == 123);
|
||||
assert_se(upper == 111);
|
||||
|
||||
assert_se(parse_range("123-123", &lower, &upper) == 0);
|
||||
assert_se(lower == 123);
|
||||
assert_se(upper == 123);
|
||||
|
||||
assert_se(parse_range("0", &lower, &upper) == 0);
|
||||
assert_se(lower == 0);
|
||||
assert_se(upper == 0);
|
||||
|
||||
assert_se(parse_range("0-15", &lower, &upper) == 0);
|
||||
assert_se(lower == 0);
|
||||
assert_se(upper == 15);
|
||||
|
||||
assert_se(parse_range("15-0", &lower, &upper) == 0);
|
||||
assert_se(lower == 15);
|
||||
assert_se(upper == 0);
|
||||
|
||||
assert_se(parse_range("128-65535", &lower, &upper) == 0);
|
||||
assert_se(lower == 128);
|
||||
assert_se(upper == 65535);
|
||||
|
||||
assert_se(parse_range("1024-4294967295", &lower, &upper) == 0);
|
||||
assert_se(lower == 1024);
|
||||
assert_se(upper == 4294967295);
|
||||
|
||||
/* Leading whitespace is acceptable */
|
||||
assert_se(parse_range(" 111", &lower, &upper) == 0);
|
||||
assert_se(lower == 111);
|
||||
assert_se(upper == 111);
|
||||
|
||||
assert_se(parse_range(" 111-123", &lower, &upper) == 0);
|
||||
assert_se(lower == 111);
|
||||
assert_se(upper == 123);
|
||||
|
||||
assert_se(parse_range("111- 123", &lower, &upper) == 0);
|
||||
assert_se(lower == 111);
|
||||
assert_se(upper == 123);
|
||||
|
||||
assert_se(parse_range("\t111-\t123", &lower, &upper) == 0);
|
||||
assert_se(lower == 111);
|
||||
assert_se(upper == 123);
|
||||
|
||||
assert_se(parse_range(" \t 111- \t 123", &lower, &upper) == 0);
|
||||
assert_se(lower == 111);
|
||||
assert_se(upper == 123);
|
||||
|
||||
/* Error cases, make sure they fail as expected */
|
||||
lower = upper = 9999;
|
||||
assert_se(parse_range("111garbage", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("garbage111", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("garbage", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111-123garbage", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111garbage-123", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
/* Empty string */
|
||||
lower = upper = 9999;
|
||||
assert_se(parse_range("", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
/* 111--123 will pass -123 to safe_atou which returns -ERANGE for negative */
|
||||
assert_se(parse_range("111--123", &lower, &upper) == -ERANGE);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("-111-123", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111.4-123", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111-123.4", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111,4-123", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111-123,4", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
/* Error on trailing dash */
|
||||
assert_se(parse_range("111-", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111--", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111- ", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
/* Whitespace is not a separator */
|
||||
assert_se(parse_range("111 123", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111\t123", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111 \t 123", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
/* Trailing whitespace is invalid (from safe_atou) */
|
||||
assert_se(parse_range("111 ", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111-123 ", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111 -123", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111 -123 ", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111\t-123\t", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
assert_se(parse_range("111 \t -123 \t ", &lower, &upper) == -EINVAL);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
|
||||
/* Out of the "unsigned" range, this is 1<<64 */
|
||||
assert_se(parse_range("0-18446744073709551616", &lower, &upper) == -ERANGE);
|
||||
assert_se(lower == 9999);
|
||||
assert_se(upper == 9999);
|
||||
}
|
||||
|
||||
static void test_parse_cpu_set(void) {
|
||||
cpu_set_t *c = NULL;
|
||||
int ncpus;
|
||||
@@ -2378,6 +2557,7 @@ int main(int argc, char *argv[]) {
|
||||
test_u64log2();
|
||||
test_protect_errno();
|
||||
test_parse_size();
|
||||
test_parse_range();
|
||||
test_parse_cpu_set();
|
||||
test_config_parse_iec_uint64();
|
||||
test_strextend();
|
||||
|
||||
Reference in New Issue
Block a user