diff options
| author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2019-04-02 08:01:42 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-04-02 08:01:42 +0900 |
| commit | 3f8f021541c58ca2fd8d05b7808c7395b90d6937 (patch) | |
| tree | 0a82d5bfe1c6066edbe42887d767cefc6f9057a1 /src/shared/condition.c | |
| parent | 1589231365e9f98270451a19175416cf7699aa0e (diff) | |
| parent | a70984c049017d9b58f00dd3e15237a609593df1 (diff) | |
| download | systemd-3f8f021541c58ca2fd8d05b7808c7395b90d6937.tar.gz | |
Merge pull request #12030 from poettering/condition-memory
add ConditionCPUs= + ConditionMemory=
Diffstat (limited to 'src/shared/condition.c')
| -rw-r--r-- | src/shared/condition.c | 183 |
1 files changed, 133 insertions, 50 deletions
diff --git a/src/shared/condition.c b/src/shared/condition.c index 32a90bcea3..d1ac9de756 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -22,16 +22,17 @@ #include "cgroup-util.h" #include "condition.h" #include "efivars.h" +#include "env-file.h" #include "extract-word.h" #include "fd-util.h" #include "fileio.h" #include "glob-util.h" #include "hostname-util.h" #include "ima-util.h" +#include "limits-util.h" #include "list.h" #include "macro.h" #include "mountpoint-util.h" -#include "env-file.h" #include "parse-util.h" #include "path-util.h" #include "proc-cmdline.h" @@ -48,23 +49,25 @@ Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) { Condition *c; - int r; assert(type >= 0); assert(type < _CONDITION_TYPE_MAX); assert((!parameter) == (type == CONDITION_NULL)); - c = new0(Condition, 1); + c = new(Condition, 1); if (!c) return NULL; - c->type = type; - c->trigger = trigger; - c->negate = negate; + *c = (Condition) { + .type = type, + .trigger = trigger, + .negate = negate, + }; - r = free_and_strdup(&c->parameter, parameter); - if (r < 0) { - return mfree(c); + if (parameter) { + c->parameter = strdup(parameter); + if (!c->parameter) + return mfree(c); } return c; @@ -132,70 +135,144 @@ static int condition_test_kernel_command_line(Condition *c) { return false; } -static int condition_test_kernel_version(Condition *c) { - enum { - /* Listed in order of checking. Note that some comparators are prefixes of others, hence the longest - * should be listed first. */ - LOWER_OR_EQUAL, - GREATER_OR_EQUAL, - LOWER, - GREATER, - EQUAL, - _ORDER_MAX, - }; +typedef enum { + /* Listed in order of checking. Note that some comparators are prefixes of others, hence the longest + * should be listed first. */ + ORDER_LOWER_OR_EQUAL, + ORDER_GREATER_OR_EQUAL, + ORDER_LOWER, + ORDER_GREATER, + ORDER_EQUAL, + ORDER_UNEQUAL, + _ORDER_MAX, + _ORDER_INVALID = -1 +} OrderOperator; + +static OrderOperator parse_order(const char **s) { static const char *const prefix[_ORDER_MAX] = { - [LOWER_OR_EQUAL] = "<=", - [GREATER_OR_EQUAL] = ">=", - [LOWER] = "<", - [GREATER] = ">", - [EQUAL] = "=", + [ORDER_LOWER_OR_EQUAL] = "<=", + [ORDER_GREATER_OR_EQUAL] = ">=", + [ORDER_LOWER] = "<", + [ORDER_GREATER] = ">", + [ORDER_EQUAL] = "=", + [ORDER_UNEQUAL] = "!=", }; - const char *p = NULL; - struct utsname u; - size_t i; - int k; - assert(c); - assert(c->parameter); - assert(c->type == CONDITION_KERNEL_VERSION); - - assert_se(uname(&u) >= 0); + OrderOperator i; for (i = 0; i < _ORDER_MAX; i++) { - p = startswith(c->parameter, prefix[i]); - if (p) - break; + const char *e; + + e = startswith(*s, prefix[i]); + if (e) { + *s = e; + return i; + } } - /* No prefix? Then treat as glob string */ - if (!p) - return fnmatch(skip_leading_chars(c->parameter, NULL), u.release, 0) == 0; + return _ORDER_INVALID; +} - k = str_verscmp(u.release, skip_leading_chars(p, NULL)); +static bool test_order(int k, OrderOperator p) { - switch (i) { + switch (p) { - case LOWER: + case ORDER_LOWER: return k < 0; - case LOWER_OR_EQUAL: + case ORDER_LOWER_OR_EQUAL: return k <= 0; - case EQUAL: + case ORDER_EQUAL: return k == 0; - case GREATER_OR_EQUAL: + case ORDER_UNEQUAL: + return k != 0; + + case ORDER_GREATER_OR_EQUAL: return k >= 0; - case GREATER: + case ORDER_GREATER: return k > 0; default: - assert_not_reached("Can't compare"); + assert_not_reached("unknown order"); + } } +static int condition_test_kernel_version(Condition *c) { + OrderOperator order; + struct utsname u; + const char *p; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_KERNEL_VERSION); + + assert_se(uname(&u) >= 0); + + p = c->parameter; + order = parse_order(&p); + + /* No prefix? Then treat as glob string */ + if (order < 0) + return fnmatch(skip_leading_chars(c->parameter, NULL), u.release, 0) == 0; + + return test_order(str_verscmp(u.release, skip_leading_chars(p, NULL)), order); +} + +static int condition_test_memory(Condition *c) { + OrderOperator order; + uint64_t m, k; + const char *p; + int r; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_MEMORY); + + m = physical_memory(); + + p = c->parameter; + order = parse_order(&p); + if (order < 0) + order = ORDER_GREATER_OR_EQUAL; /* default to >= check, if nothing is specified. */ + + r = safe_atou64(p, &k); + if (r < 0) + return log_debug_errno(r, "Failed to parse size: %m"); + + return test_order(CMP(m, k), order); +} + +static int condition_test_cpus(Condition *c) { + OrderOperator order; + const char *p; + unsigned k; + int r, n; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_CPUS); + + n = cpus_in_affinity_mask(); + if (n < 0) + return log_debug_errno(n, "Failed to determine CPUs in affinity mask: %m"); + + p = c->parameter; + order = parse_order(&p); + if (order < 0) + order = ORDER_GREATER_OR_EQUAL; /* default to >= check, if nothing is specified. */ + + r = safe_atou(p, &k); + if (r < 0) + return log_debug_errno(r, "Failed to parse number of CPUs: %m"); + + return test_order(CMP((unsigned) n, k), order); +} + static int condition_test_user(Condition *c) { uid_t id; int r; @@ -629,6 +706,8 @@ int condition_test(Condition *c) { [CONDITION_GROUP] = condition_test_group, [CONDITION_CONTROL_GROUP_CONTROLLER] = condition_test_control_group_controller, [CONDITION_NULL] = condition_test_null, + [CONDITION_CPUS] = condition_test_cpus, + [CONDITION_MEMORY] = condition_test_memory, }; int r, b; @@ -740,7 +819,9 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_USER] = "ConditionUser", [CONDITION_GROUP] = "ConditionGroup", [CONDITION_CONTROL_GROUP_CONTROLLER] = "ConditionControlGroupController", - [CONDITION_NULL] = "ConditionNull" + [CONDITION_NULL] = "ConditionNull", + [CONDITION_CPUS] = "ConditionCPUs", + [CONDITION_MEMORY] = "ConditionMemory", }; DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType); @@ -768,7 +849,9 @@ static const char* const assert_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_USER] = "AssertUser", [CONDITION_GROUP] = "AssertGroup", [CONDITION_CONTROL_GROUP_CONTROLLER] = "AssertControlGroupController", - [CONDITION_NULL] = "AssertNull" + [CONDITION_NULL] = "AssertNull", + [CONDITION_CPUS] = "AssertCPUs", + [CONDITION_MEMORY] = "AssertMemory", }; DEFINE_STRING_TABLE_LOOKUP(assert_type, ConditionType); |
