|
|
ecbff1 |
From 6e00430563108b98230abd7407ac54fde61ae93c Mon Sep 17 00:00:00 2001
|
|
|
ecbff1 |
From: Jan Synacek <jsynacek@redhat.com>
|
|
|
ecbff1 |
Date: Tue, 26 Sep 2017 12:34:19 +0200
|
|
|
ecbff1 |
Subject: [PATCH] support ranges when parsing CPUAffinity
|
|
|
ecbff1 |
|
|
|
ecbff1 |
The functionality was implemented in https://github.com/systemd/systemd/pull/1699/.
|
|
|
ecbff1 |
However, it is not backportable without considerable code changes.
|
|
|
ecbff1 |
|
|
|
ecbff1 |
Implement parse_range() and parse_cpu_set_and_warn() from the upstream master
|
|
|
ecbff1 |
branch and use them in appropriate places. Also introduce relevant tests.
|
|
|
ecbff1 |
|
|
|
ecbff1 |
Resolves: #1493976
|
|
|
ecbff1 |
---
|
|
|
de8967 |
src/core/load-fragment.c | 49 ++-----
|
|
|
de8967 |
src/core/main.c | 48 +------
|
|
|
de8967 |
src/shared/util.c | 91 ++++++++++++
|
|
|
ecbff1 |
src/shared/util.h | 9 ++
|
|
|
de8967 |
src/test/test-util.c | 296 +++++++++++++++++++++++++++++++++++++++
|
|
|
ecbff1 |
5 files changed, 417 insertions(+), 76 deletions(-)
|
|
|
ecbff1 |
|
|
|
ecbff1 |
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
|
|
|
ecbff1 |
index 0c0fa0f50..a10e1903a 100644
|
|
|
ecbff1 |
--- a/src/core/load-fragment.c
|
|
|
ecbff1 |
+++ b/src/core/load-fragment.c
|
|
|
ecbff1 |
@@ -884,50 +884,29 @@ int config_parse_exec_cpu_affinity(const char *unit,
|
|
|
ecbff1 |
void *userdata) {
|
|
|
ecbff1 |
|
|
|
ecbff1 |
ExecContext *c = data;
|
|
|
ecbff1 |
- const char *word, *state;
|
|
|
ecbff1 |
- size_t l;
|
|
|
ecbff1 |
+ _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
|
|
|
ecbff1 |
+ int ncpus;
|
|
|
ecbff1 |
|
|
|
ecbff1 |
assert(filename);
|
|
|
ecbff1 |
assert(lvalue);
|
|
|
ecbff1 |
assert(rvalue);
|
|
|
ecbff1 |
assert(data);
|
|
|
ecbff1 |
|
|
|
ecbff1 |
- if (isempty(rvalue)) {
|
|
|
ecbff1 |
- /* An empty assignment resets the CPU list */
|
|
|
ecbff1 |
- if (c->cpuset)
|
|
|
ecbff1 |
- CPU_FREE(c->cpuset);
|
|
|
ecbff1 |
- c->cpuset = NULL;
|
|
|
ecbff1 |
- return 0;
|
|
|
ecbff1 |
- }
|
|
|
ecbff1 |
-
|
|
|
ecbff1 |
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
|
|
|
ecbff1 |
- _cleanup_free_ char *t = NULL;
|
|
|
ecbff1 |
- int r;
|
|
|
ecbff1 |
- unsigned cpu;
|
|
|
ecbff1 |
-
|
|
|
ecbff1 |
- t = strndup(word, l);
|
|
|
ecbff1 |
- if (!t)
|
|
|
ecbff1 |
- return log_oom();
|
|
|
ecbff1 |
-
|
|
|
ecbff1 |
- r = safe_atou(t, &cpu);
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
|
|
|
ecbff1 |
+ if (ncpus < 0)
|
|
|
ecbff1 |
+ return ncpus;
|
|
|
ecbff1 |
|
|
|
ecbff1 |
- if (!c->cpuset) {
|
|
|
ecbff1 |
- c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
|
|
|
ecbff1 |
- if (!c->cpuset)
|
|
|
ecbff1 |
- return log_oom();
|
|
|
ecbff1 |
- }
|
|
|
ecbff1 |
+ if (c->cpuset)
|
|
|
ecbff1 |
+ CPU_FREE(c->cpuset);
|
|
|
ecbff1 |
|
|
|
ecbff1 |
- if (r < 0 || cpu >= c->cpuset_ncpus) {
|
|
|
ecbff1 |
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
|
|
|
ecbff1 |
- "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
|
|
|
ecbff1 |
- return 0;
|
|
|
ecbff1 |
- }
|
|
|
ecbff1 |
-
|
|
|
ecbff1 |
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
|
|
|
ecbff1 |
+ if (ncpus == 0)
|
|
|
ecbff1 |
+ /* An empty assignment resets the CPU list */
|
|
|
ecbff1 |
+ c->cpuset = NULL;
|
|
|
ecbff1 |
+ else {
|
|
|
ecbff1 |
+ c->cpuset = cpuset;
|
|
|
ecbff1 |
+ cpuset = NULL;
|
|
|
ecbff1 |
}
|
|
|
ecbff1 |
- if (!isempty(state))
|
|
|
ecbff1 |
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
|
|
|
ecbff1 |
- "Trailing garbage, ignoring.");
|
|
|
ecbff1 |
+ c->cpuset_ncpus = ncpus;
|
|
|
ecbff1 |
|
|
|
ecbff1 |
return 0;
|
|
|
ecbff1 |
}
|
|
|
ecbff1 |
diff --git a/src/core/main.c b/src/core/main.c
|
|
|
ecbff1 |
index 66393ed6a..5554ef468 100644
|
|
|
ecbff1 |
--- a/src/core/main.c
|
|
|
ecbff1 |
+++ b/src/core/main.c
|
|
|
ecbff1 |
@@ -438,49 +438,15 @@ static int config_parse_cpu_affinity2(
|
|
|
ecbff1 |
void *data,
|
|
|
ecbff1 |
void *userdata) {
|
|
|
ecbff1 |
|
|
|
ecbff1 |
- const char *word, *state;
|
|
|
ecbff1 |
- size_t l;
|
|
|
ecbff1 |
- cpu_set_t *c = NULL;
|
|
|
ecbff1 |
- unsigned ncpus = 0;
|
|
|
ecbff1 |
-
|
|
|
ecbff1 |
- assert(filename);
|
|
|
ecbff1 |
- assert(lvalue);
|
|
|
ecbff1 |
- assert(rvalue);
|
|
|
ecbff1 |
+ _cleanup_cpu_free_ cpu_set_t *c = NULL;
|
|
|
ecbff1 |
+ int ncpus;
|
|
|
ecbff1 |
|
|
|
ecbff1 |
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
|
|
|
ecbff1 |
- char *t;
|
|
|
ecbff1 |
- int r;
|
|
|
ecbff1 |
- unsigned cpu;
|
|
|
ecbff1 |
-
|
|
|
ecbff1 |
- if (!(t = strndup(word, l)))
|
|
|
ecbff1 |
- return log_oom();
|
|
|
ecbff1 |
-
|
|
|
ecbff1 |
- r = safe_atou(t, &cpu);
|
|
|
ecbff1 |
- free(t);
|
|
|
ecbff1 |
-
|
|
|
ecbff1 |
- if (!c)
|
|
|
ecbff1 |
- if (!(c = cpu_set_malloc(&ncpus)))
|
|
|
ecbff1 |
- return log_oom();
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue);
|
|
|
ecbff1 |
+ if (ncpus < 0)
|
|
|
ecbff1 |
+ return ncpus;
|
|
|
ecbff1 |
|
|
|
ecbff1 |
- if (r < 0 || cpu >= ncpus) {
|
|
|
ecbff1 |
- log_syntax(unit, LOG_ERR, filename, line, -r,
|
|
|
ecbff1 |
- "Failed to parse CPU affinity '%s'", rvalue);
|
|
|
ecbff1 |
- CPU_FREE(c);
|
|
|
ecbff1 |
- return -EBADMSG;
|
|
|
ecbff1 |
- }
|
|
|
ecbff1 |
-
|
|
|
ecbff1 |
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
|
|
|
ecbff1 |
- }
|
|
|
ecbff1 |
- if (!isempty(state))
|
|
|
ecbff1 |
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
|
|
ecbff1 |
- "Trailing garbage, ignoring.");
|
|
|
ecbff1 |
-
|
|
|
ecbff1 |
- if (c) {
|
|
|
ecbff1 |
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
|
|
|
ecbff1 |
- log_unit_warning(unit, "Failed to set CPU affinity: %m");
|
|
|
ecbff1 |
-
|
|
|
ecbff1 |
- CPU_FREE(c);
|
|
|
ecbff1 |
- }
|
|
|
ecbff1 |
+ if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
|
|
|
ecbff1 |
+ log_warning_errno(errno, "Failed to set CPU affinity: %m");
|
|
|
ecbff1 |
|
|
|
ecbff1 |
return 0;
|
|
|
ecbff1 |
}
|
|
|
ecbff1 |
diff --git a/src/shared/util.c b/src/shared/util.c
|
|
|
ecbff1 |
index bbb457759..39359fcc8 100644
|
|
|
ecbff1 |
--- a/src/shared/util.c
|
|
|
ecbff1 |
+++ b/src/shared/util.c
|
|
|
ecbff1 |
@@ -2727,6 +2727,43 @@ int parse_size(const char *t, off_t base, off_t *size) {
|
|
|
ecbff1 |
return 0;
|
|
|
ecbff1 |
}
|
|
|
ecbff1 |
|
|
|
ecbff1 |
+int parse_range(const char *t, unsigned *lower, unsigned *upper) {
|
|
|
ecbff1 |
+ _cleanup_free_ char *word = NULL;
|
|
|
ecbff1 |
+ unsigned l, u;
|
|
|
ecbff1 |
+ int r;
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert(lower);
|
|
|
ecbff1 |
+ assert(upper);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Extract the lower bound. */
|
|
|
ecbff1 |
+ r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
|
|
|
ecbff1 |
+ if (r < 0)
|
|
|
ecbff1 |
+ return r;
|
|
|
ecbff1 |
+ if (r == 0)
|
|
|
ecbff1 |
+ return -EINVAL;
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ r = safe_atou(word, &l);
|
|
|
ecbff1 |
+ if (r < 0)
|
|
|
ecbff1 |
+ return r;
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Check for the upper bound and extract it if needed */
|
|
|
ecbff1 |
+ if (!t)
|
|
|
ecbff1 |
+ /* Single number with no dashes. */
|
|
|
ecbff1 |
+ u = l;
|
|
|
ecbff1 |
+ else if (!*t)
|
|
|
ecbff1 |
+ /* Trailing dash is an error. */
|
|
|
ecbff1 |
+ return -EINVAL;
|
|
|
ecbff1 |
+ else {
|
|
|
ecbff1 |
+ r = safe_atou(t, &u);
|
|
|
ecbff1 |
+ if (r < 0)
|
|
|
ecbff1 |
+ return r;
|
|
|
ecbff1 |
+ }
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ *lower = l;
|
|
|
ecbff1 |
+ *upper = u;
|
|
|
ecbff1 |
+ return 0;
|
|
|
ecbff1 |
+}
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
int make_stdio(int fd) {
|
|
|
ecbff1 |
int r, s, t;
|
|
|
ecbff1 |
|
|
|
ecbff1 |
@@ -3460,6 +3497,60 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
|
|
|
ecbff1 |
}
|
|
|
ecbff1 |
}
|
|
|
ecbff1 |
|
|
|
ecbff1 |
+int parse_cpu_set_and_warn(
|
|
|
ecbff1 |
+ const char *rvalue,
|
|
|
ecbff1 |
+ cpu_set_t **cpu_set,
|
|
|
ecbff1 |
+ const char *unit,
|
|
|
ecbff1 |
+ const char *filename,
|
|
|
ecbff1 |
+ unsigned line,
|
|
|
ecbff1 |
+ const char *lvalue) {
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ const char *whole_rvalue = rvalue;
|
|
|
ecbff1 |
+ _cleanup_cpu_free_ cpu_set_t *c = NULL;
|
|
|
ecbff1 |
+ unsigned ncpus = 0;
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert(lvalue);
|
|
|
ecbff1 |
+ assert(rvalue);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ for (;;) {
|
|
|
ecbff1 |
+ _cleanup_free_ char *word = NULL;
|
|
|
ecbff1 |
+ unsigned cpu, cpu_lower, cpu_upper;
|
|
|
ecbff1 |
+ int r;
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ r = extract_first_word(&rvalue, &word, WHITESPACE ",", EXTRACT_QUOTES);
|
|
|
ecbff1 |
+ if (r < 0)
|
|
|
ecbff1 |
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
|
|
|
ecbff1 |
+ if (r == 0)
|
|
|
ecbff1 |
+ break;
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ if (!c) {
|
|
|
ecbff1 |
+ c = cpu_set_malloc(&ncpus);
|
|
|
ecbff1 |
+ if (!c)
|
|
|
ecbff1 |
+ return log_oom();
|
|
|
ecbff1 |
+ }
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ r = parse_range(word, &cpu_lower, &cpu_upper);
|
|
|
ecbff1 |
+ if (r < 0)
|
|
|
ecbff1 |
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word);
|
|
|
ecbff1 |
+ if (cpu_lower >= ncpus || cpu_upper >= ncpus)
|
|
|
ecbff1 |
+ return log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ if (cpu_lower > cpu_upper)
|
|
|
ecbff1 |
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u", word, cpu_lower, cpu_upper);
|
|
|
ecbff1 |
+ else
|
|
|
ecbff1 |
+ for (cpu = cpu_lower; cpu <= cpu_upper; cpu++)
|
|
|
ecbff1 |
+ CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
|
|
|
ecbff1 |
+ }
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* On success, sets *cpu_set and returns ncpus for the system. */
|
|
|
ecbff1 |
+ if (c) {
|
|
|
ecbff1 |
+ *cpu_set = c;
|
|
|
ecbff1 |
+ c = NULL;
|
|
|
ecbff1 |
+ }
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ return (int) ncpus;
|
|
|
ecbff1 |
+}
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
|
|
|
ecbff1 |
static const char status_indent[] = " "; /* "[" STATUS "] " */
|
|
|
ecbff1 |
_cleanup_free_ char *s = NULL;
|
|
|
ecbff1 |
diff --git a/src/shared/util.h b/src/shared/util.h
|
|
|
ecbff1 |
index 80ad18c0a..526a6fe84 100644
|
|
|
ecbff1 |
--- a/src/shared/util.h
|
|
|
ecbff1 |
+++ b/src/shared/util.h
|
|
|
ecbff1 |
@@ -136,6 +136,11 @@ bool streq_ptr(const char *a, const char *b) _pure_;
|
|
|
ecbff1 |
|
|
|
ecbff1 |
#define malloc0(n) (calloc((n), 1))
|
|
|
ecbff1 |
|
|
|
ecbff1 |
+static inline void *mfree(void *memory) {
|
|
|
ecbff1 |
+ free(memory);
|
|
|
ecbff1 |
+ return NULL;
|
|
|
ecbff1 |
+}
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
static inline const char* yes_no(bool b) {
|
|
|
ecbff1 |
return b ? "yes" : "no";
|
|
|
ecbff1 |
}
|
|
|
ecbff1 |
@@ -195,6 +200,7 @@ void safe_close_pair(int p[]);
|
|
|
ecbff1 |
void close_many(const int fds[], unsigned n_fd);
|
|
|
ecbff1 |
|
|
|
ecbff1 |
int parse_size(const char *t, off_t base, off_t *size);
|
|
|
ecbff1 |
+int parse_range(const char *t, unsigned *lower, unsigned *upper);
|
|
|
ecbff1 |
|
|
|
ecbff1 |
int parse_boolean(const char *v) _pure_;
|
|
|
ecbff1 |
int parse_pid(const char *s, pid_t* ret_pid);
|
|
|
ecbff1 |
@@ -474,6 +480,7 @@ int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool hon
|
|
|
ecbff1 |
int pipe_eof(int fd);
|
|
|
ecbff1 |
|
|
|
ecbff1 |
cpu_set_t* cpu_set_malloc(unsigned *ncpus);
|
|
|
ecbff1 |
+int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue);
|
|
|
ecbff1 |
|
|
|
ecbff1 |
int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
|
|
|
ecbff1 |
int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
|
|
|
ecbff1 |
@@ -692,6 +699,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, fclose);
|
|
|
ecbff1 |
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose);
|
|
|
ecbff1 |
DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
|
|
|
ecbff1 |
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent);
|
|
|
ecbff1 |
+DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
|
|
|
ecbff1 |
|
|
|
ecbff1 |
#define _cleanup_free_ _cleanup_(freep)
|
|
|
ecbff1 |
#define _cleanup_close_ _cleanup_(closep)
|
|
|
ecbff1 |
@@ -702,6 +710,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent);
|
|
|
ecbff1 |
#define _cleanup_closedir_ _cleanup_(closedirp)
|
|
|
ecbff1 |
#define _cleanup_endmntent_ _cleanup_(endmntentp)
|
|
|
ecbff1 |
#define _cleanup_close_pair_ _cleanup_(close_pairp)
|
|
|
ecbff1 |
+#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
|
|
|
ecbff1 |
|
|
|
ecbff1 |
_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) {
|
|
|
ecbff1 |
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
|
|
|
ecbff1 |
diff --git a/src/test/test-util.c b/src/test/test-util.c
|
|
|
ecbff1 |
index 971f97d7c..fcf5416c0 100644
|
|
|
ecbff1 |
--- a/src/test/test-util.c
|
|
|
ecbff1 |
+++ b/src/test/test-util.c
|
|
|
ecbff1 |
@@ -689,6 +689,300 @@ static void test_parse_size(void) {
|
|
|
ecbff1 |
assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE);
|
|
|
ecbff1 |
}
|
|
|
ecbff1 |
|
|
|
ecbff1 |
+static void test_parse_range(void) {
|
|
|
ecbff1 |
+ unsigned lower, upper;
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Successful cases */
|
|
|
ecbff1 |
+ assert_se(parse_range("111", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 111);
|
|
|
ecbff1 |
+ assert_se(upper == 111);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111-123", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 111);
|
|
|
ecbff1 |
+ assert_se(upper == 123);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("123-111", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 123);
|
|
|
ecbff1 |
+ assert_se(upper == 111);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("123-123", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 123);
|
|
|
ecbff1 |
+ assert_se(upper == 123);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("0", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 0);
|
|
|
ecbff1 |
+ assert_se(upper == 0);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("0-15", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 0);
|
|
|
ecbff1 |
+ assert_se(upper == 15);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("15-0", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 15);
|
|
|
ecbff1 |
+ assert_se(upper == 0);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("128-65535", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 128);
|
|
|
ecbff1 |
+ assert_se(upper == 65535);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("1024-4294967295", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 1024);
|
|
|
ecbff1 |
+ assert_se(upper == 4294967295);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Leading whitespace is acceptable */
|
|
|
ecbff1 |
+ assert_se(parse_range(" 111", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 111);
|
|
|
ecbff1 |
+ assert_se(upper == 111);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range(" 111-123", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 111);
|
|
|
ecbff1 |
+ assert_se(upper == 123);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111- 123", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 111);
|
|
|
ecbff1 |
+ assert_se(upper == 123);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("\t111-\t123", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 111);
|
|
|
ecbff1 |
+ assert_se(upper == 123);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range(" \t 111- \t 123", &lower, &upper) == 0);
|
|
|
ecbff1 |
+ assert_se(lower == 111);
|
|
|
ecbff1 |
+ assert_se(upper == 123);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Error cases, make sure they fail as expected */
|
|
|
ecbff1 |
+ lower = upper = 9999;
|
|
|
ecbff1 |
+ assert_se(parse_range("111garbage", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("garbage111", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("garbage", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111-123garbage", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111garbage-123", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Empty string */
|
|
|
ecbff1 |
+ lower = upper = 9999;
|
|
|
ecbff1 |
+ assert_se(parse_range("", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* 111--123 will pass -123 to safe_atou which returns -ERANGE for negative */
|
|
|
ecbff1 |
+ assert_se(parse_range("111--123", &lower, &upper) == -ERANGE);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("-111-123", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111.4-123", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111-123.4", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111,4-123", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111-123,4", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Error on trailing dash */
|
|
|
ecbff1 |
+ assert_se(parse_range("111-", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111--", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111- ", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Whitespace is not a separator */
|
|
|
ecbff1 |
+ assert_se(parse_range("111 123", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111\t123", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111 \t 123", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Trailing whitespace is invalid (from safe_atou) */
|
|
|
ecbff1 |
+ assert_se(parse_range("111 ", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111-123 ", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111 -123", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111 -123 ", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111\t-123\t", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ assert_se(parse_range("111 \t -123 \t ", &lower, &upper) == -EINVAL);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Out of the "unsigned" range, this is 1<<64 */
|
|
|
ecbff1 |
+ assert_se(parse_range("0-18446744073709551616", &lower, &upper) == -ERANGE);
|
|
|
ecbff1 |
+ assert_se(lower == 9999);
|
|
|
ecbff1 |
+ assert_se(upper == 9999);
|
|
|
ecbff1 |
+}
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+static void test_parse_cpu_set(void) {
|
|
|
ecbff1 |
+ cpu_set_t *c = NULL;
|
|
|
ecbff1 |
+ int ncpus;
|
|
|
ecbff1 |
+ int cpu;
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Simple range (from CPUAffinity example) */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus >= 1024);
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2);
|
|
|
ecbff1 |
+ c = mfree(c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* A more interesting range */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus >= 1024);
|
|
|
ecbff1 |
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
|
|
|
ecbff1 |
+ for (cpu = 0; cpu < 4; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ for (cpu = 8; cpu < 12; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ c = mfree(c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Quoted strings */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus >= 1024);
|
|
|
ecbff1 |
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4);
|
|
|
ecbff1 |
+ for (cpu = 8; cpu < 12; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ c = mfree(c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Use commas as separators */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus >= 1024);
|
|
|
ecbff1 |
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
|
|
|
ecbff1 |
+ for (cpu = 0; cpu < 4; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ for (cpu = 8; cpu < 12; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ c = mfree(c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Commas with spaces (and trailing comma, space) */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus >= 1024);
|
|
|
ecbff1 |
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
|
|
|
ecbff1 |
+ for (cpu = 0; cpu < 8; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ c = mfree(c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Ranges */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus >= 1024);
|
|
|
ecbff1 |
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
|
|
|
ecbff1 |
+ for (cpu = 0; cpu < 4; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ for (cpu = 8; cpu < 12; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ c = mfree(c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Ranges with trailing comma, space */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus >= 1024);
|
|
|
ecbff1 |
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
|
|
|
ecbff1 |
+ for (cpu = 0; cpu < 4; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ for (cpu = 8; cpu < 12; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ c = mfree(c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Negative range (returns empty cpu_set) */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus >= 1024);
|
|
|
ecbff1 |
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0);
|
|
|
ecbff1 |
+ c = mfree(c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Overlapping ranges */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus >= 1024);
|
|
|
ecbff1 |
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12);
|
|
|
ecbff1 |
+ for (cpu = 0; cpu < 12; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ c = mfree(c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Mix ranges and individual CPUs */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus >= 1024);
|
|
|
ecbff1 |
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10);
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ for (cpu = 4; cpu < 12; cpu++)
|
|
|
ecbff1 |
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
|
|
|
ecbff1 |
+ c = mfree(c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Garbage */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus < 0);
|
|
|
ecbff1 |
+ assert_se(!c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Range with garbage */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus < 0);
|
|
|
ecbff1 |
+ assert_se(!c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Empty string */
|
|
|
ecbff1 |
+ c = NULL;
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus == 0); /* empty string returns 0 */
|
|
|
ecbff1 |
+ assert_se(!c);
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
+ /* Runaway quoted string */
|
|
|
ecbff1 |
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity");
|
|
|
ecbff1 |
+ assert_se(ncpus < 0);
|
|
|
ecbff1 |
+ assert_se(!c);
|
|
|
ecbff1 |
+}
|
|
|
ecbff1 |
+
|
|
|
ecbff1 |
static void test_config_parse_iec_off(void) {
|
|
|
ecbff1 |
off_t offset = 0;
|
|
|
ecbff1 |
assert_se(config_parse_iec_off(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0);
|
|
|
ecbff1 |
@@ -1605,6 +1899,8 @@ int main(int argc, char *argv[]) {
|
|
|
ecbff1 |
test_get_process_comm();
|
|
|
ecbff1 |
test_protect_errno();
|
|
|
ecbff1 |
test_parse_size();
|
|
|
ecbff1 |
+ test_parse_range();
|
|
|
ecbff1 |
+ test_parse_cpu_set();
|
|
|
ecbff1 |
test_config_parse_iec_off();
|
|
|
ecbff1 |
test_strextend();
|
|
|
ecbff1 |
test_strrep();
|