[systemd-devel] [PATCH] path: conditionally depend on the triggered unit

Jouke Witteveen j.witteveen at gmail.com
Mon Dec 29 05:07:02 PST 2014


Path units having either PathExists=, PathExistsGlob=, or
DirectoryNotEmpty= want the service they trigger when the condition is
met. This way it becomes meaningful to include StopWhenUnneeded=true in
the triggered service.
---

This fixes #87287.

 man/systemd.path.xml | 10 ++++++
 src/core/path.c      | 42 +++++++++++++++----------
 src/core/path.h      |  1 +
 src/core/unit.c      | 86 +++++++++++++++++++++++++++++++++++-----------------
 src/core/unit.h      |  2 ++
 5 files changed, 98 insertions(+), 43 deletions(-)

diff --git a/man/systemd.path.xml b/man/systemd.path.xml
index c6d61cf..9b78d45 100644
--- a/man/systemd.path.xml
+++ b/man/systemd.path.xml
@@ -170,6 +170,16 @@
                                 to <varname>PathChanged=</varname> and
                                 <varname>PathModified=</varname>.</para>
 
+                                <para>If the triggered unit has
+                                <varname>StopWhenUnneeded=true</varname>
+                                then it is not stopped as long as a path
+                                exists (in case of
+                                <varname>PathExists=</varname> and
+                                <varname>PathExistsGlob=</varname>) or
+                                a directory is not empty (in case of
+                                <varname>DirectoryNotEmpty=</varname>).
+                                </para>
+
                                 <para>If the path itself or any of the
                                 containing directories are not
                                 accessible, <command>systemd</command>
diff --git a/src/core/path.c b/src/core/path.c
index 0fdf483..5b1bccd 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -467,6 +467,22 @@ static void path_enter_dead(Path *p, PathResult f) {
         path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
 }
 
+static bool path_check_good(Path *p, bool initial) {
+        PathSpec *s;
+        bool good = false;
+
+        assert(p);
+
+        LIST_FOREACH(spec, s, p->specs) {
+                good = path_spec_check_good(s, initial);
+
+                if (good)
+                        break;
+        }
+
+        return good;
+}
+
 static void path_enter_running(Path *p) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
@@ -477,6 +493,11 @@ static void path_enter_running(Path *p) {
         if (unit_stop_pending(UNIT(p)))
                 return;
 
+        if (!p->has_dependency && path_check_good(p, true)) {
+                if (unit_add_dependency(UNIT(p), UNIT_WANTS, UNIT_TRIGGER(UNIT(p)), false) >= 0)
+                        p->has_dependency = true;
+        }
+
         r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)),
                             JOB_REPLACE, true, &error, NULL);
         if (r < 0)
@@ -497,22 +518,6 @@ fail:
         path_enter_dead(p, PATH_FAILURE_RESOURCES);
 }
 
-static bool path_check_good(Path *p, bool initial) {
-        PathSpec *s;
-        bool good = false;
-
-        assert(p);
-
-        LIST_FOREACH(spec, s, p->specs) {
-                good = path_spec_check_good(s, initial);
-
-                if (good)
-                        break;
-        }
-
-        return good;
-}
-
 static void path_enter_waiting(Path *p, bool initial, bool recheck) {
         int r;
 
@@ -538,6 +543,11 @@ static void path_enter_waiting(Path *p, bool initial, bool recheck) {
                         return;
                 }
 
+        if (p->has_dependency) {
+                unit_delete_dependency(UNIT(p), UNIT_WANTS, UNIT_TRIGGER(UNIT(p)), false);
+                p->has_dependency = false;
+        }
+
         path_set_state(p, PATH_WAITING);
         return;
 
diff --git a/src/core/path.h b/src/core/path.h
index d2e91d7..0a9b1cf 100644
--- a/src/core/path.h
+++ b/src/core/path.h
@@ -85,6 +85,7 @@ struct Path {
         PathState state, deserialized_state;
 
         bool inotify_triggered;
+        bool has_dependency;
 
         bool make_directory;
         mode_t directory_mode;
diff --git a/src/core/unit.c b/src/core/unit.c
index a2f3728..e06b41c 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -69,6 +69,33 @@ const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
         [UNIT_SCOPE] = &scope_vtable
 };
 
+const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = {
+        [UNIT_REQUIRES] = UNIT_REQUIRED_BY,
+        [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
+        [UNIT_WANTS] = UNIT_WANTED_BY,
+        [UNIT_REQUISITE] = UNIT_REQUIRED_BY,
+        [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
+        [UNIT_BINDS_TO] = UNIT_BOUND_BY,
+        [UNIT_PART_OF] = UNIT_CONSISTS_OF,
+        [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
+        [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID,
+        [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID,
+        [UNIT_BOUND_BY] = UNIT_BINDS_TO,
+        [UNIT_CONSISTS_OF] = UNIT_PART_OF,
+        [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY,
+        [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS,
+        [UNIT_BEFORE] = UNIT_AFTER,
+        [UNIT_AFTER] = UNIT_BEFORE,
+        [UNIT_ON_FAILURE] = _UNIT_DEPENDENCY_INVALID,
+        [UNIT_REFERENCES] = UNIT_REFERENCED_BY,
+        [UNIT_REFERENCED_BY] = UNIT_REFERENCES,
+        [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY,
+        [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS,
+        [UNIT_PROPAGATES_RELOAD_TO] = UNIT_RELOAD_PROPAGATED_FROM,
+        [UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO,
+        [UNIT_JOINS_NAMESPACE_OF] = UNIT_JOINS_NAMESPACE_OF,
+};
+
 static int maybe_warn_about_dependency(const char *id, const char *other, UnitDependency dependency);
 
 Unit *unit_new(Manager *m, size_t size) {
@@ -2171,33 +2198,6 @@ static int maybe_warn_about_dependency(const char *id, const char *other, UnitDe
 }
 
 int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) {
-
-        static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = {
-                [UNIT_REQUIRES] = UNIT_REQUIRED_BY,
-                [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
-                [UNIT_WANTS] = UNIT_WANTED_BY,
-                [UNIT_REQUISITE] = UNIT_REQUIRED_BY,
-                [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
-                [UNIT_BINDS_TO] = UNIT_BOUND_BY,
-                [UNIT_PART_OF] = UNIT_CONSISTS_OF,
-                [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_BOUND_BY] = UNIT_BINDS_TO,
-                [UNIT_CONSISTS_OF] = UNIT_PART_OF,
-                [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY,
-                [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS,
-                [UNIT_BEFORE] = UNIT_AFTER,
-                [UNIT_AFTER] = UNIT_BEFORE,
-                [UNIT_ON_FAILURE] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_REFERENCES] = UNIT_REFERENCED_BY,
-                [UNIT_REFERENCED_BY] = UNIT_REFERENCES,
-                [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY,
-                [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS,
-                [UNIT_PROPAGATES_RELOAD_TO] = UNIT_RELOAD_PROPAGATED_FROM,
-                [UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO,
-                [UNIT_JOINS_NAMESPACE_OF] = UNIT_JOINS_NAMESPACE_OF,
-        };
         int r, q = 0, v = 0, w = 0;
         Unit *orig_u = u, *orig_other = other;
 
@@ -2405,6 +2405,38 @@ int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDep
         return r;
 }
 
+void unit_delete_dependency(Unit *u, UnitDependency d, Unit *other, bool remove_reference) {
+        Unit *orig_u = u, *orig_other = other;
+
+        assert(u);
+        assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX);
+        assert(other);
+
+        u = unit_follow_merge(u);
+        other = unit_follow_merge(other);
+
+        /* We won't allow dependencies on ourselves. We will not
+         * consider them an error however. */
+        if (u == other) {
+                maybe_warn_about_dependency(orig_u->id, orig_other->id, d);
+                return;
+        }
+
+        set_remove(u->dependencies[d], other);
+
+        if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID && inverse_table[d] != d)
+                set_remove(other->dependencies[inverse_table[d]], u);
+
+        if (remove_reference) {
+                set_remove(u->dependencies[UNIT_REFERENCES], other);
+                set_remove(other->dependencies[UNIT_REFERENCED_BY], u);
+        }
+
+        unit_check_unneeded(other);
+        unit_add_to_dbus_queue(u);
+        return;
+}
+
 int set_unit_path(const char *p) {
         /* This is mostly for debug purposes */
         if (setenv("SYSTEMD_UNIT_PATH", p, 0) < 0)
diff --git a/src/core/unit.h b/src/core/unit.h
index 19fa2f0..6026303 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -468,6 +468,8 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency
 int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
 int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
 
+void unit_delete_dependency(Unit *u, UnitDependency d, Unit *other, bool remove_reference);
+
 int unit_add_exec_dependencies(Unit *u, ExecContext *c);
 
 int unit_choose_id(Unit *u, const char *name);
-- 
2.2.1



More information about the systemd-devel mailing list