diff options
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | man/systemd.unit.xml | 24 | ||||
-rw-r--r-- | src/condition.c | 34 | ||||
-rw-r--r-- | src/condition.h | 1 | ||||
-rw-r--r-- | src/load-fragment-gperf.gperf.m4 | 1 |
5 files changed, 56 insertions, 6 deletions
@@ -19,7 +19,7 @@ Bugfixes: Features: -* ConditionCapability= +* unset container= in PID1? * if we can not get user quota for tmpfs, mount a separate tmpfs instance for every user in /run/user/$USER with a configured maximum size diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index e47c14679e..897f99f24c 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -673,6 +673,7 @@ <term><varname>ConditionKernelCommandLine=</varname></term> <term><varname>ConditionVirtualization=</varname></term> <term><varname>ConditionSecurity=</varname></term> + <term><varname>ConditionCapability=</varname></term> <term><varname>ConditionNull=</varname></term> <listitem><para>Before starting a unit @@ -749,9 +750,9 @@ value to check if being executed in any virtualized environment, or one of <varname>vm</varname> and - <varname>container</varname> to test against - a specific type of virtualization - solution, or one of + <varname>container</varname> to test + against a specific type of + virtualization solution, or one of <varname>qemu</varname>, <varname>kvm</varname>, <varname>vmware</varname>, @@ -775,7 +776,19 @@ system. Currently the only recognized value is <varname>selinux</varname>. The test may be negated by prepending - an exclamation mark. Finally, + an exclamation + mark. <varname>ConditionCapability=</varname> + may be used to check whether the given + capability exists in the capability + bounding set of the service manager + (i.e. this does not check whether + capability is actually available in + the permitted or effective sets, see + <citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry> + for details). Pass a capability name + such as <literal>CAP_MKNOD</literal>, + possibly prefixed with an exclamation + mark to negate the check. Finally, <varname>ConditionNull=</varname> may be used to add a constant condition check value to the unit. It takes a @@ -932,7 +945,8 @@ <citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.path</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry> + <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry> </para> </refsect1> diff --git a/src/condition.c b/src/condition.c index 07624c841d..f18c45421a 100644 --- a/src/condition.c +++ b/src/condition.c @@ -23,6 +23,7 @@ #include <errno.h> #include <string.h> #include <unistd.h> +#include <sys/capability.h> #ifdef HAVE_SELINUX #include <selinux/selinux.h> @@ -159,6 +160,36 @@ static bool test_security(const char *parameter) { return false; } +static bool test_capability(const char *parameter) { + cap_value_t value; + FILE *f; + char line[LINE_MAX]; + unsigned long long capabilities = (unsigned long long) -1; + + /* If it's an invalid capability, we don't have it */ + + if (cap_from_name(parameter, &value) < 0) + return false; + + /* If it's a valid capability we default to assume + * that we have it */ + + f = fopen("/proc/self/status", "re"); + if (!f) + return true; + + while (fgets(line, sizeof(line), f)) { + truncate_nl(line); + + if (startswith(line, "CapBnd:")) { + (void) sscanf(line+7, "%llx", &capabilities); + break; + } + } + + return !!(capabilities & (1ULL << value)); +} + bool condition_test(Condition *c) { assert(c); @@ -214,6 +245,9 @@ bool condition_test(Condition *c) { case CONDITION_SECURITY: return test_security(c->parameter) == !c->negate; + case CONDITION_CAPABILITY: + return test_capability(c->parameter) == !c->negate; + case CONDITION_NULL: return !c->negate; diff --git a/src/condition.h b/src/condition.h index dd65aa6054..71b1c6761e 100644 --- a/src/condition.h +++ b/src/condition.h @@ -37,6 +37,7 @@ typedef enum ConditionType { CONDITION_KERNEL_COMMAND_LINE, CONDITION_VIRTUALIZATION, CONDITION_SECURITY, + CONDITION_CAPABILITY, CONDITION_NULL, _CONDITION_TYPE_MAX, _CONDITION_TYPE_INVALID = -1 diff --git a/src/load-fragment-gperf.gperf.m4 b/src/load-fragment-gperf.gperf.m4 index 7749b88dfb..41797d20c0 100644 --- a/src/load-fragment-gperf.gperf.m4 +++ b/src/load-fragment-gperf.gperf.m4 @@ -119,6 +119,7 @@ Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_F Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0 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.ConditionNull, config_parse_unit_condition_null, 0, 0 m4_dnl Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file) |