chiark / gitweb /
core: add new ConditionNeedsUpdate= unit condition
authorLennart Poettering <lennart@poettering.net>
Fri, 13 Jun 2014 10:52:31 +0000 (12:52 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 13 Jun 2014 11:26:32 +0000 (13:26 +0200)
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
src/core/load-fragment-gperf.gperf.m4
src/shared/condition-util.c
src/shared/condition-util.h
units/systemd-update-done.service.in

index 833bcdf3028d2b5e88694b4f8218857c97baf13b..410fb36797808757f39bcf71fca52af994a6629f 100644 (file)
@@ -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;
 
index 2d98bba419b0c01f783069cb011c626d3e4337a5..d97c5c6f5bccf0f28b1d91175306385c9f31b0e1 100644 (file)
@@ -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
index 1c7d1f6a5e4b2e137dc9505119146250a14b90ed..7b89b0fbafe1e3eebd1832ca01f79e5f4c9f99b0 100644 (file)
@@ -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"
 };
 
index 63d945efacb26d23cc38da9708f02217c1e41786..0b09f83f90969dc2fc731f5e38be7cf76b67359d 100644 (file)
@@ -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
index dccb5137d2cdc55cbdc4a1abf4d8098013f65de0..1a907f9637d69be0b877f083a2287f2d18c8e565 100644 (file)
@@ -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