From a55654d598c78f8e084aa6a18fec6eff900c9aed Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 13 Jun 2014 12:52:31 +0200 Subject: [PATCH] core: add new ConditionNeedsUpdate= unit condition This new condition allows checking whether /etc or /var are out-of-date relative to /usr. This is the counterpart for the update flag managed by systemd-update-done.service. Services that want to be started once after /usr got updated should use: [Unit] ConditionNeedsUpdate=/etc Before=systemd-update-done.service This makes sure that they are only run if /etc is out-of-date relative to /usr. And that it will be executed after systemd-update-done.service which is responsible for marking /etc up-to-date relative to the current /usr. ConditionNeedsUpdate= will also checks whether /etc is actually writable, and not trigger if it isn't, since no update is possible then. --- src/core/condition.c | 33 +++++++++++++++++++++++++++ src/core/load-fragment-gperf.gperf.m4 | 1 + src/shared/condition-util.c | 1 + src/shared/condition-util.h | 1 + units/systemd-update-done.service.in | 2 ++ 5 files changed, 38 insertions(+) diff --git a/src/core/condition.c b/src/core/condition.c index 833bcdf30..410fb3679 100644 --- a/src/core/condition.c +++ b/src/core/condition.c @@ -90,6 +90,36 @@ static bool condition_test_capability(Condition *c) { return !!(capabilities & (1ULL << value)) == !c->negate; } +static bool condition_test_needs_update(Condition *c) { + const char *p; + struct stat usr, other; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_NEEDS_UPDATE); + + /* If the file system is read-only we shouldn't suggest an update */ + if (path_is_read_only_fs(c->parameter) > 0) + return c->negate; + + /* Any other failure means we should allow the condition to be true, + * so that we rather invoke too many update tools then too + * few. */ + + if (!path_is_absolute(c->parameter)) + return !c->negate; + + p = strappenda(c->parameter, "/.updated"); + if (lstat(p, &other) < 0) + return !c->negate; + + if (lstat("/usr/", &usr) < 0) + return !c->negate; + + return (usr.st_mtim.tv_sec > other.st_mtim.tv_sec || + (usr.st_mtim.tv_sec == other.st_mtim.tv_sec && usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec)) == !c->negate; +} + static bool condition_test(Condition *c) { assert(c); @@ -169,6 +199,9 @@ static bool condition_test(Condition *c) { case CONDITION_ARCHITECTURE: return condition_test_architecture(c); + case CONDITION_NEEDS_UPDATE: + return condition_test_needs_update(c); + case CONDITION_NULL: return !c->negate; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 2d98bba41..d97c5c6f5 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -161,6 +161,7 @@ Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_P Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, 0 Unit.ConditionFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, 0 Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, 0 +Unit.ConditionNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, 0 Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0 Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, 0 Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0 diff --git a/src/shared/condition-util.c b/src/shared/condition-util.c index 1c7d1f6a5..7b89b0fba 100644 --- a/src/shared/condition-util.c +++ b/src/shared/condition-util.c @@ -256,6 +256,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_HOST] = "ConditionHost", [CONDITION_AC_POWER] = "ConditionACPower", [CONDITION_ARCHITECTURE] = "ConditionArchitecture", + [CONDITION_NEEDS_UPDATE] = "ConditionNeedsUpdate", [CONDITION_NULL] = "ConditionNull" }; diff --git a/src/shared/condition-util.h b/src/shared/condition-util.h index 63d945efa..0b09f83f9 100644 --- a/src/shared/condition-util.h +++ b/src/shared/condition-util.h @@ -44,6 +44,7 @@ typedef enum ConditionType { CONDITION_HOST, CONDITION_AC_POWER, CONDITION_ARCHITECTURE, + CONDITION_NEEDS_UPDATE, CONDITION_NULL, _CONDITION_TYPE_MAX, _CONDITION_TYPE_INVALID = -1 diff --git a/units/systemd-update-done.service.in b/units/systemd-update-done.service.in index dccb5137d..1a907f963 100644 --- a/units/systemd-update-done.service.in +++ b/units/systemd-update-done.service.in @@ -14,6 +14,8 @@ After=systemd-readahead-collect.service systemd-readahead-replay.service local-f Before=sysinit.target shutdown.target RefuseManualStart=yes RefuseManualStop=yes +ConditionNeedsUpdate=|/etc +ConditionNeedsUpdate=|/var [Service] Type=oneshot -- 2.30.2