chiark / gitweb /
core: optionally send SIGHUP in addition to the configured kill signal
[elogind.git] / src / core / unit.c
index 991111ab31facaad6fcf4c8f9e29f7ca41e3986e..b56be83a318684b2ef8626804b1cab69d3e0b247 100644 (file)
@@ -231,8 +231,13 @@ int unit_set_description(Unit *u, const char *description) {
 
         assert(u);
 
-        if (!(s = strdup(description)))
-                return -ENOMEM;
+        if (isempty(description))
+                s = NULL;
+        else {
+                s = strdup(description);
+                if (!s)
+                        return -ENOMEM;
+        }
 
         free(u->description);
         u->description = s;
@@ -306,9 +311,6 @@ void unit_add_to_gc_queue(Unit *u) {
         u->in_gc_queue = true;
 
         u->manager->n_in_gc_queue ++;
-
-        if (u->manager->gc_queue_timestamp <= 0)
-                u->manager->gc_queue_timestamp = now(CLOCK_MONOTONIC);
 }
 
 void unit_add_to_dbus_queue(Unit *u) {
@@ -431,7 +433,11 @@ void unit_free(Unit *u) {
         if (u->in_cgroup_queue)
                 LIST_REMOVE(Unit, cgroup_queue, u->manager->cgroup_queue, u);
 
-        free(u->cgroup_path);
+        if (u->cgroup_path) {
+                hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
+                free(u->cgroup_path);
+        }
+
         free(u->description);
         strv_free(u->documentation);
         free(u->fragment_path);
@@ -990,7 +996,7 @@ bool unit_condition_test(Unit *u) {
         assert(u);
 
         dual_timestamp_get(&u->condition_timestamp);
-        u->condition_result = condition_test_list(u->conditions);
+        u->condition_result = condition_test_list(u->id, u->conditions);
 
         return u->condition_result;
 }
@@ -1119,7 +1125,8 @@ int unit_start(Unit *u) {
         }
 
         /* Forward to the main object, if we aren't it. */
-        if ((following = unit_following(u))) {
+        following = unit_following(u);
+        if (following) {
                 log_debug_unit(u->id, "Redirecting start request from %s to %s.",
                                u->id, following->id);
                 return unit_start(following);
@@ -1419,10 +1426,14 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
         if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) {
                 ExecContext *ec = unit_get_exec_context(u);
                 if (ec && exec_context_may_touch_console(ec)) {
-                        if (UNIT_IS_INACTIVE_OR_FAILED(ns))
-                                m->n_on_console--;
-                        else
-                                m->n_on_console++;
+                        if (UNIT_IS_INACTIVE_OR_FAILED(ns)) {
+                                m->n_on_console --;
+
+                                if (m->n_on_console == 0)
+                                        /* unset no_console_output flag, since the console is free */
+                                        m->no_console_output = 0;
+                        } else
+                                m->n_on_console ++;
                 }
         }
 
@@ -1985,7 +1996,7 @@ char *unit_dbus_path(Unit *u) {
 }
 
 char *unit_default_cgroup_path(Unit *u) {
-        _cleanup_free_ char *escaped_instance = NULL, *slice = NULL;
+        _cleanup_free_ char *escaped = NULL, *slice = NULL;
         int r;
 
         assert(u);
@@ -1999,31 +2010,19 @@ char *unit_default_cgroup_path(Unit *u) {
                         return NULL;
         }
 
-        escaped_instance = cg_escape(u->id);
-        if (!escaped_instance)
+        escaped = cg_escape(u->id);
+        if (!escaped)
                 return NULL;
 
-        if (u->instance) {
-                _cleanup_free_ char *t = NULL, *escaped_template = NULL;
-
-                t = unit_name_template(u->id);
-                if (!t)
-                        return NULL;
-
-                escaped_template = cg_escape(t);
-                if (!escaped_template)
-                        return NULL;
-
-                return strjoin(u->manager->cgroup_root, "/",
-                               slice ? slice : "", slice ? "/" : "",
-                               escaped_template, "/", escaped_instance, NULL);
-        } else
-                return strjoin(u->manager->cgroup_root, "/",
-                               slice ? slice : "", slice ? "/" : "",
-                               escaped_instance, NULL);
+        if (slice)
+                return strjoin(u->manager->cgroup_root, "/", slice, "/", escaped, NULL);
+        else
+                return strjoin(u->manager->cgroup_root, "/", escaped, NULL);
 }
 
 int unit_add_default_slice(Unit *u) {
+        _cleanup_free_ char *b = NULL;
+        const char *slice_name;
         Unit *slice;
         int r;
 
@@ -2035,7 +2034,38 @@ int unit_add_default_slice(Unit *u) {
         if (!unit_get_cgroup_context(u))
                 return 0;
 
-        r = manager_load_unit(u->manager, u->manager->running_as == SYSTEMD_SYSTEM ? SPECIAL_SYSTEM_SLICE : SPECIAL_ROOT_SLICE, NULL, NULL, &slice);
+        if (u->instance) {
+                _cleanup_free_ char *prefix = NULL, *escaped = NULL;
+                        ;
+                /* Implicitly place all instantiated units in their
+                 * own per-template slice */
+
+                prefix = unit_name_to_prefix(u->id);
+                if (!prefix)
+                        return -ENOMEM;
+
+                /* The prefix is already escaped, but it might include
+                 * "-" which has a special meaning for slice units,
+                 * hence escape it here extra. */
+                escaped = strreplace(prefix, "-", "\\x2d");
+                if (!escaped)
+                        return -ENOMEM;
+
+                if (u->manager->running_as == SYSTEMD_SYSTEM)
+                        b = strjoin("system-", escaped, ".slice", NULL);
+                else
+                        b = strappend(escaped, ".slice");
+                if (!b)
+                        return -ENOMEM;
+
+                slice_name = b;
+        } else
+                slice_name =
+                        u->manager->running_as == SYSTEMD_SYSTEM
+                        ? SPECIAL_SYSTEM_SLICE
+                        : SPECIAL_ROOT_SLICE;
+
+        r = manager_load_unit(u->manager, slice_name, NULL, NULL, &slice);
         if (r < 0)
                 return r;
 
@@ -2126,7 +2156,8 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
         if (!unit_can_serialize(u))
                 return 0;
 
-        if ((r = UNIT_VTABLE(u)->serialize(u, f, fds)) < 0)
+        r = UNIT_VTABLE(u)->serialize(u, f, fds);
+        if (r < 0)
                 return r;
 
 
@@ -2300,11 +2331,13 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
                         char *s;
 
                         s = strdup(v);
-                        if (!v)
+                        if (!s)
                                 return -ENOMEM;
 
                         free(u->cgroup_path);
                         u->cgroup_path = s;
+
+                        hashmap_put(u->manager->cgroup_unit, s, u);
                         continue;
                 }
 
@@ -2509,6 +2542,34 @@ int unit_kill(Unit *u, KillWho w, int signo, DBusError *error) {
         return UNIT_VTABLE(u)->kill(u, w, signo, error);
 }
 
+static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) {
+        Set *pid_set;
+        int r;
+
+        pid_set = set_new(trivial_hash_func, trivial_compare_func);
+        if (!pid_set)
+                return NULL;
+
+        /* Exclude the main/control pids from being killed via the cgroup */
+        if (main_pid > 0) {
+                r = set_put(pid_set, LONG_TO_PTR(main_pid));
+                if (r < 0)
+                        goto fail;
+        }
+
+        if (control_pid > 0) {
+                r = set_put(pid_set, LONG_TO_PTR(control_pid));
+                if (r < 0)
+                        goto fail;
+        }
+
+        return pid_set;
+
+fail:
+        set_free(pid_set);
+        return NULL;
+}
+
 int unit_kill_common(
                 Unit *u,
                 KillWho who,
@@ -2549,23 +2610,11 @@ int unit_kill_common(
                 _cleanup_set_free_ Set *pid_set = NULL;
                 int q;
 
-                pid_set = set_new(trivial_hash_func, trivial_compare_func);
+                /* Exclude the main/control pids from being killed via the cgroup */
+                pid_set = unit_pid_set(main_pid, control_pid);
                 if (!pid_set)
                         return -ENOMEM;
 
-                /* Exclude the control/main pid from being killed via the cgroup */
-                if (control_pid > 0) {
-                        q = set_put(pid_set, LONG_TO_PTR(control_pid));
-                        if (q < 0)
-                                return q;
-                }
-
-                if (main_pid > 0) {
-                        q = set_put(pid_set, LONG_TO_PTR(main_pid));
-                        if (q < 0)
-                                return q;
-                }
-
                 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
                 if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
                         r = q;
@@ -2705,6 +2754,7 @@ CGroupContext *unit_get_cgroup_context(Unit *u) {
 }
 
 static int drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **_p, char **_q) {
+        _cleanup_free_ char *b = NULL;
         char *p, *q;
         int r;
 
@@ -2714,7 +2764,11 @@ static int drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, c
         assert(_q);
         assert(mode & (UNIT_PERSISTENT|UNIT_RUNTIME));
 
-        if (!filename_is_safe(name))
+        b = xescape(name, "/.");
+        if (!b)
+                return -ENOMEM;
+
+        if (!filename_is_safe(b))
                 return -EINVAL;
 
         if (u->manager->running_as == SYSTEMD_USER) {
@@ -2734,7 +2788,7 @@ static int drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, c
         if (!p)
                 return -ENOMEM;
 
-        q = strjoin(p, "/90-", name, ".conf", NULL);
+        q = strjoin(p, "/90-", b, ".conf", NULL);
         if (!q) {
                 free(p);
                 return -ENOMEM;
@@ -2764,7 +2818,29 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co
         return write_string_file_atomic_label(q, data);
 }
 
-int unit_write_drop_in_private_section(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
+int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) {
+        _cleanup_free_ char *p = NULL;
+        va_list ap;
+        int r;
+
+        assert(u);
+        assert(name);
+        assert(format);
+
+        if (!(mode & (UNIT_PERSISTENT|UNIT_RUNTIME)))
+                return 0;
+
+        va_start(ap, format);
+        r = vasprintf(&p, format, ap);
+        va_end(ap);
+
+        if (r < 0)
+                return -ENOMEM;
+
+        return unit_write_drop_in(u, mode, name, p);
+}
+
+int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
         _cleanup_free_ char *ndata = NULL;
 
         assert(u);
@@ -2774,6 +2850,9 @@ int unit_write_drop_in_private_section(Unit *u, UnitSetPropertiesMode mode, cons
         if (!UNIT_VTABLE(u)->private_section)
                 return -EINVAL;
 
+        if (!(mode & (UNIT_PERSISTENT|UNIT_RUNTIME)))
+                return 0;
+
         ndata = strjoin("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL);
         if (!ndata)
                 return -ENOMEM;
@@ -2781,6 +2860,28 @@ int unit_write_drop_in_private_section(Unit *u, UnitSetPropertiesMode mode, cons
         return unit_write_drop_in(u, mode, name, ndata);
 }
 
+int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) {
+        _cleanup_free_ char *p = NULL;
+        va_list ap;
+        int r;
+
+        assert(u);
+        assert(name);
+        assert(format);
+
+        if (!(mode & (UNIT_PERSISTENT|UNIT_RUNTIME)))
+                return 0;
+
+        va_start(ap, format);
+        r = vasprintf(&p, format, ap);
+        va_end(ap);
+
+        if (r < 0)
+                return -ENOMEM;
+
+        return unit_write_drop_in_private(u, mode, name, p);
+}
+
 int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) {
         _cleanup_free_ char *p = NULL, *q = NULL;
         int r;
@@ -2864,8 +2965,12 @@ int unit_kill_context(
 
                         log_warning_unit(u->id, "Failed to kill main process %li (%s): %s",
                                          (long) main_pid, strna(comm), strerror(-r));
-                } else
+                } else {
                         wait_for_exit = !main_pid_alien;
+
+                        if (c->send_sighup)
+                                kill(main_pid, SIGHUP);
+                }
         }
 
         if (control_pid > 0) {
@@ -2878,36 +2983,38 @@ int unit_kill_context(
                         log_warning_unit(u->id,
                                          "Failed to kill control process %li (%s): %s",
                                          (long) control_pid, strna(comm), strerror(-r));
-                } else
+                } else {
                         wait_for_exit = true;
+
+                        if (c->send_sighup)
+                                kill(control_pid, SIGHUP);
+                }
         }
 
         if (c->kill_mode == KILL_CONTROL_GROUP && u->cgroup_path) {
                 _cleanup_set_free_ Set *pid_set = NULL;
 
-                pid_set = set_new(trivial_hash_func, trivial_compare_func);
+                /* Exclude the main/control pids from being killed via the cgroup */
+                pid_set = unit_pid_set(main_pid, control_pid);
                 if (!pid_set)
                         return -ENOMEM;
 
-                /* Exclude the main/control pids from being killed via the cgroup */
-                if (main_pid > 0) {
-                        r = set_put(pid_set, LONG_TO_PTR(main_pid));
-                        if (r < 0)
-                                return r;
-                }
-
-                if (control_pid > 0) {
-                        r = set_put(pid_set, LONG_TO_PTR(control_pid));
-                        if (r < 0)
-                                return r;
-                }
-
                 r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, true, false, pid_set);
                 if (r < 0) {
                         if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
                                 log_warning_unit(u->id, "Failed to kill control group: %s", strerror(-r));
-                } else if (r > 0)
+                } else if (r > 0) {
                         wait_for_exit = true;
+                        if (c->send_sighup) {
+                                set_free(pid_set);
+
+                                pid_set = unit_pid_set(main_pid, control_pid);
+                                if (!pid_set)
+                                        return -ENOMEM;
+
+                                cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, SIGHUP, true, true, false, pid_set);
+                        }
+                }
         }
 
         return wait_for_exit;