From c0d6e764d107a81a6439c41edbe92790623ed7de Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Aug 2012 01:51:53 +0200 Subject: [PATCH 1/1] unit: add new ConditionHost= condition type --- TODO | 4 +- man/systemd.unit.xml | 112 ++++++++++++++++++-------- src/core/condition.c | 31 +++++++ src/core/condition.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/load-fragment.c | 11 ++- 6 files changed, 120 insertions(+), 40 deletions(-) diff --git a/TODO b/TODO index 7f5353540..28141ec68 100644 --- a/TODO +++ b/TODO @@ -49,6 +49,8 @@ Bugfixes: Features: +* There's something wrong with escaping unit names: http://lists.freedesktop.org/archives/systemd-devel/2012-August/006292.html + * cleanup ellipsation for log output in journalctl and systemctl status: have a sane way to disable ellipsation, and disable it by default when invoked in less/more * enforce limits on fds openened by socket units @@ -59,8 +61,6 @@ Features: * testing tool for socket activation: some binary that listens on a socket and passes it on using the usual socket activation protocol to some server. -* ConditionHost= for filtering services for clusters - * journald: add symlinks and device names to kernel messages * maybe make systemd-detect-virt suid? or use fscaps? diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index da2dba52b..bf22ca9bd 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -586,7 +586,7 @@ RequiresMountsFor= Takes a space - separated list of paths. Automatically + separated list of absolute paths. Automatically adds dependencies of type Requires= and After= for all @@ -760,65 +760,86 @@ ConditionVirtualization= ConditionSecurity= ConditionCapability= + ConditionHost= ConditionNull= Before starting a unit verify that the specified condition is - true. With + true. If it is not true the starting + of the unit will be skipped, however + all ordering dependencies of it are + still respected. A failing condition + will not result in the unit being + moved into a failure state. The + condition is checked at the time the + queued start job is to be + executed. + + With ConditionPathExists= - a file existence condition can be + a file existence condition is checked before a unit is started. If the specified absolute path name does - not exist, startup of a unit will not - actually happen, however the unit is - still useful for ordering purposes in - this case. The condition is checked at - the time the queued start job is to be - executed. If the absolute path name - passed to + not exist the condition will + fail. If the absolute path name passed + to ConditionPathExists= is prefixed with an exclamation mark - (!), the test is negated, and the unit + ('!'), the test is negated, and the unit is only started if the path does not - exist. - ConditionPathExistsGlob= - works in a similar way, but checks for - the existence of at least one file or - directory matching the specified - globbing - pattern. ConditionPathIsDirectory= + exist. + + ConditionPathExistsGlob= + is similar to + ConditionPathExists=, + but checks for the existence of at + least one file or directory matching + the specified globbing pattern. + + ConditionPathIsDirectory= is similar to ConditionPathExists= but verifies whether a certain path exists and is a - directory. ConditionPathIsSymbolicLink= + directory. + + ConditionPathIsSymbolicLink= is similar to ConditionPathExists= but verifies whether a certain path exists and is a symbolic - link. ConditionPathIsMountPoint= + link. + + ConditionPathIsMountPoint= is similar to ConditionPathExists= but verifies whether a certain path exists and is a mount - point. ConditionPathIsReadWrite= + point. + + ConditionPathIsReadWrite= is similar to ConditionPathExists= but verifies whether the underlying - file system is read and writable + file system is readable and writable (i.e. not mounted - read-only). ConditionFileIsExecutable= + read-only). + + ConditionFileIsExecutable= is similar to ConditionPathExists= but verifies whether a certain path exists, is a regular file and marked - executable. - ConditionDirectoryNotEmpty= + executable. + + ConditionDirectoryNotEmpty= is similar to ConditionPathExists= but verifies whether a certain path exists and is a non-empty - directory. Similarly + directory. + + Similarly, ConditionKernelCommandLine= may be used to check whether a specific kernel command line option is @@ -826,14 +847,16 @@ exclamation mark unset). The argument must either be a single word, or an assignment (i.e. two words, separated - by the equality sign). In the former + '='). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case the exact assignment is looked for with right and left hand side - matching. ConditionVirtualization= + matching. + + ConditionVirtualization= may be used to check whether the system is executed in a virtualized environment and optionally test @@ -843,7 +866,7 @@ any virtualized environment, or one of vm and container to test - against a specific type of + against a generic type of virtualization solution, or one of qemu, kvm, @@ -862,15 +885,18 @@ virtualization technologies are nested only the innermost is considered. The test may be negated by prepending an - exclamation mark. - ConditionSecurity= + exclamation mark. + + ConditionSecurity= may be used to check whether the given security module is enabled on the system. Currently the only recognized value is selinux. The test may be negated by prepending an exclamation - mark. ConditionCapability= + mark. + + ConditionCapability= may be used to check whether the given capability exists in the capability bounding set of the service manager @@ -881,14 +907,32 @@ for details). Pass a capability name such as CAP_MKNOD, possibly prefixed with an exclamation - mark to negate the check. Finally, + mark to negate the check. + + ConditionHost= + may be used to match against the + host name or machine ID of the + host. This either takes a host name + string (optionally with shell style + globs) which is tested against the + locally set host name as returned by + gethostname2, + or a machine ID formatted as string + (see + machine-id5). + The test may be negated by prepending + an exclamation mark. + + Finally, ConditionNull= may be used to add a constant condition check value to the unit. It takes a boolean argument. If set to false the condition will always fail, otherwise - succeed. If multiple conditions are + succeed. + + If multiple conditions are specified the unit will be executed if all of them apply (i.e. a logical AND is applied). Condition checks can be diff --git a/src/core/condition.c b/src/core/condition.c index e4080d569..e5cda21c3 100644 --- a/src/core/condition.c +++ b/src/core/condition.c @@ -25,11 +25,13 @@ #include #include #include +#include #ifdef HAVE_SELINUX #include #endif +#include #include "util.h" #include "condition.h" #include "virt.h" @@ -194,6 +196,31 @@ static bool test_capability(const char *parameter) { return !!(capabilities & (1ULL << value)); } +static bool test_host(const char *parameter) { + sd_id128_t x, y; + char *h; + int r; + bool b; + + if (sd_id128_from_string(parameter, &x) >= 0) { + + r = sd_id128_get_machine(&y); + if (r < 0) + return false; + + return sd_id128_equal(x, y); + } + + h = gethostname_malloc(); + if (!h) + return false; + + b = fnmatch(parameter, h, FNM_CASEFOLD) == 0; + free(h); + + return b; +} + bool condition_test(Condition *c) { assert(c); @@ -255,6 +282,9 @@ bool condition_test(Condition *c) { case CONDITION_CAPABILITY: return test_capability(c->parameter) == !c->negate; + case CONDITION_HOST: + return test_host(c->parameter) == !c->negate; + case CONDITION_NULL: return !c->negate; @@ -323,6 +353,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine", [CONDITION_VIRTUALIZATION] = "ConditionVirtualization", [CONDITION_SECURITY] = "ConditionSecurity", + [CONDITION_HOST] = "ConditionHost", [CONDITION_NULL] = "ConditionNull" }; diff --git a/src/core/condition.h b/src/core/condition.h index 3dca432f7..55b331edd 100644 --- a/src/core/condition.h +++ b/src/core/condition.h @@ -38,6 +38,7 @@ typedef enum ConditionType { CONDITION_VIRTUALIZATION, CONDITION_SECURITY, CONDITION_CAPABILITY, + CONDITION_HOST, CONDITION_NULL, _CONDITION_TYPE_MAX, _CONDITION_TYPE_INVALID = -1 diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 84eea1c46..8187cd48c 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -135,6 +135,7 @@ Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_K Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0 Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0 Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 0 +Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, 0 Unit.ConditionNull, config_parse_unit_condition_null, 0, 0 m4_dnl Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 10681307c..9438aa312 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1516,14 +1516,17 @@ int config_parse_unit_condition_string( assert(rvalue); assert(data); - if ((trigger = rvalue[0] == '|')) + trigger = rvalue[0] == '|'; + if (trigger) rvalue++; - if ((negate = rvalue[0] == '!')) + negate = rvalue[0] == '!'; + if (negate) rvalue++; - if (!(c = condition_new(cond, rvalue, trigger, negate))) - return -ENOMEM; + c = condition_new(cond, rvalue, trigger, negate); + if (!c) + return log_oom(); LIST_PREPEND(Condition, conditions, u->conditions, c); return 0; -- 2.30.2