chiark / gitweb /
core/load-fragment: safe_close() protects errno
[elogind.git] / src / core / manager.c
index 79a9d549542b970157197cd50a31974baa60d918..3e87aa969bd3c32e2dd795592f888908600519d9 100644 (file)
@@ -953,7 +953,7 @@ int manager_enumerate(Manager *m) {
                 int q;
 
                 if (unit_vtable[c]->supported && !unit_vtable[c]->supported(m)) {
-                        log_info("Unit type .%s is not supported on this system.", unit_type_to_string(c));
+                        log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
                         continue;
                 }
 
@@ -975,7 +975,28 @@ static int manager_coldplug(Manager *m) {
         Unit *u;
         char *k;
 
-        assert(m);
+        /*
+         * Some unit types tend to spawn jobs or check other units' state
+         * during coldplug. This is wrong because it is undefined whether the
+         * units in question have been already coldplugged (i. e. their state
+         * restored). This way, we can easily re-start an already started unit
+         * or otherwise make a wrong decision based on the unit's state.
+         *
+         * Solve this by providing a way for coldplug functions to defer
+         * such actions until after all units have been coldplugged.
+         *
+         * We store Unit* -> int(*)(Unit*).
+         *
+         * https://bugs.freedesktop.org/show_bug.cgi?id=88401
+         */
+        _cleanup_hashmap_free_ Hashmap *deferred_work = NULL;
+        int(*proc)(Unit*);
+
+        assert(m);
+
+        deferred_work = hashmap_new(&trivial_hash_ops);
+        if (!deferred_work)
+                return -ENOMEM;
 
         /* Then, let's set up their initial state. */
         HASHMAP_FOREACH_KEY(u, k, m->units, i) {
@@ -985,7 +1006,17 @@ static int manager_coldplug(Manager *m) {
                 if (u->id != k)
                         continue;
 
-                q = unit_coldplug(u);
+                q = unit_coldplug(u, deferred_work);
+                if (q < 0)
+                        r = q;
+        }
+
+        /* After coldplugging and setting up initial state of the units,
+         * let's perform operations which spawn jobs or query units' state. */
+        HASHMAP_FOREACH_KEY(proc, u, deferred_work, i) {
+                int q;
+
+                q = proc(u);
                 if (q < 0)
                         r = q;
         }
@@ -3053,6 +3084,23 @@ const char *manager_get_runtime_prefix(Manager *m) {
                getenv("XDG_RUNTIME_DIR");
 }
 
+void manager_update_failed_units(Manager *m, Unit *u, bool failed) {
+        unsigned size;
+
+        assert(m);
+        assert(u->manager == m);
+
+        size = set_size(m->failed_units);
+
+        if (failed)
+                set_put(m->failed_units, u);
+        else
+                set_remove(m->failed_units, u);
+
+        if (set_size(m->failed_units) != size)
+                bus_manager_send_change_signal(m);
+}
+
 ManagerState manager_state(Manager *m) {
         Unit *u;