summaryrefslogtreecommitdiff
path: root/src/shared/condition.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2019-04-02 08:01:42 +0900
committerGitHub <noreply@github.com>2019-04-02 08:01:42 +0900
commit3f8f021541c58ca2fd8d05b7808c7395b90d6937 (patch)
tree0a82d5bfe1c6066edbe42887d767cefc6f9057a1 /src/shared/condition.c
parent1589231365e9f98270451a19175416cf7699aa0e (diff)
parenta70984c049017d9b58f00dd3e15237a609593df1 (diff)
downloadsystemd-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.c183
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);