]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/unit.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / core / unit.c
index e40ea24be801a068826f87af3199ad84ab9bb024..a054cc79b06c9d4fffe76655e3eb83e634918a60 100644 (file)
 ***/
 
 #include <errno.h>
-#include <string.h>
 #include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
 #include "sd-id128.h"
 #include "sd-messages.h"
-#include "set.h"
-#include "macro.h"
-#include "strv.h"
-#include "path-util.h"
-#include "log.h"
+
+#include "bus-common-errors.h"
+#include "bus-util.h"
 #include "cgroup-util.h"
-#include "missing.h"
-#include "mkdir.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "dropin.h"
+#include "escape.h"
+#include "execute.h"
 #include "fileio-label.h"
 #include "formats-util.h"
+#include "load-dropin.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "path-util.h"
 #include "process-util.h"
-#include "virt.h"
-#include "bus-common-errors.h"
-#include "bus-util.h"
-#include "dropin.h"
-#include "unit-name.h"
+#include "set.h"
 #include "special.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "virt.h"
 #include "unit.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "dbus.h"
-#include "dbus-unit.h"
-#include "execute.h"
 
 const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = &service_vtable,
@@ -125,6 +128,7 @@ static void unit_init(Unit *u) {
                 cc->cpu_accounting = u->manager->default_cpu_accounting;
                 cc->blockio_accounting = u->manager->default_blockio_accounting;
                 cc->memory_accounting = u->manager->default_memory_accounting;
+                cc->tasks_accounting = u->manager->default_tasks_accounting;
         }
 
         ec = unit_get_exec_context(u);
@@ -451,6 +455,7 @@ static void unit_free_requires_mounts_for(Unit *u) {
 static void unit_done(Unit *u) {
         ExecContext *ec;
         CGroupContext *cc;
+        int r;
 
         assert(u);
 
@@ -467,6 +472,10 @@ static void unit_done(Unit *u) {
         cc = unit_get_cgroup_context(u);
         if (cc)
                 cgroup_context_done(cc);
+
+        r = unit_remove_from_netclass_cgroup(u);
+        if (r < 0)
+                log_warning_errno(r, "Unable to remove unit from netclass group: %m");
 }
 
 void unit_free(Unit *u) {
@@ -527,7 +536,7 @@ void unit_free(Unit *u) {
 
         unit_release_cgroup(u);
 
-        manager_update_failed_units(u->manager, u, false);
+        (void) manager_update_failed_units(u->manager, u, false);
         set_remove(u->manager->startup_units, u);
 
         free(u->description);
@@ -1123,12 +1132,12 @@ static int unit_add_slice_dependencies(Unit *u) {
                 return 0;
 
         if (UNIT_ISSET(u->slice))
-                return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, UNIT_DEREF(u->slice), true);
+                return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT_DEREF(u->slice), true);
 
-        if (streq(u->id, SPECIAL_ROOT_SLICE))
+        if (unit_has_name(u, SPECIAL_ROOT_SLICE))
                 return 0;
 
-        return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, SPECIAL_ROOT_SLICE, NULL, true);
+        return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_ROOT_SLICE, NULL, true);
 }
 
 static int unit_add_mount_dependencies(Unit *u) {
@@ -1141,13 +1150,23 @@ static int unit_add_mount_dependencies(Unit *u) {
                 char prefix[strlen(*i) + 1];
 
                 PATH_FOREACH_PREFIX_MORE(prefix, *i) {
+                        _cleanup_free_ char *p = NULL;
                         Unit *m;
 
-                        r = manager_get_unit_by_path(u->manager, prefix, ".mount", &m);
+                        r = unit_name_from_path(prefix, ".mount", &p);
                         if (r < 0)
                                 return r;
-                        if (r == 0)
+
+                        m = manager_get_unit(u->manager, p);
+                        if (!m) {
+                                /* Make sure to load the mount unit if
+                                 * it exists. If so the dependencies
+                                 * on this unit will be added later
+                                 * during the loading of the mount
+                                 * unit. */
+                                (void) manager_load_unit_prepare(u->manager, p, NULL, NULL, &m);
                                 continue;
+                        }
                         if (m == u)
                                 continue;
 
@@ -1171,15 +1190,20 @@ static int unit_add_mount_dependencies(Unit *u) {
 
 static int unit_add_startup_units(Unit *u) {
         CGroupContext *c;
+        int r;
 
         c = unit_get_cgroup_context(u);
         if (!c)
                 return 0;
 
-        if (c->startup_cpu_shares == (unsigned long) -1 &&
-            c->startup_blockio_weight == (unsigned long) -1)
+        if (c->startup_cpu_shares == CGROUP_CPU_SHARES_INVALID &&
+            c->startup_blockio_weight == CGROUP_BLKIO_WEIGHT_INVALID)
                 return 0;
 
+        r = set_ensure_allocated(&u->manager->startup_units, NULL);
+        if (r < 0)
+                return r;
+
         return set_put(u->manager->startup_units, u);
 }
 
@@ -1235,6 +1259,14 @@ int unit_load(Unit *u) {
                 }
 
                 unit_update_cgroup_members_masks(u);
+
+                /* If we are reloading, we need to wait for the deserializer
+                 * to restore the net_cls ids that have been set previously */
+                if (u->manager->n_reloading <= 0) {
+                        r = unit_add_to_netclass_cgroup(u);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         assert((u->load_state != UNIT_MERGED) == !u->merged_into);
@@ -1806,7 +1838,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
         }
 
         /* Keep track of failed units */
-        manager_update_failed_units(u->manager, u, ns == UNIT_FAILED);
+        (void) manager_update_failed_units(u->manager, u, ns == UNIT_FAILED);
 
         /* Make sure the cgroup is always removed when we become inactive */
         if (UNIT_IS_INACTIVE_OR_FAILED(ns))
@@ -2291,44 +2323,6 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency
         return unit_add_two_dependencies(u, d, e, other, add_reference);
 }
 
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
-        _cleanup_free_ char *buf = NULL;
-        Unit *other;
-        int r;
-
-        assert(u);
-        assert(name || path);
-
-        r = resolve_template(u, name, path, &buf, &name);
-        if (r < 0)
-                return r;
-
-        r = manager_load_unit(u->manager, name, path, NULL, &other);
-        if (r < 0)
-                return r;
-
-        return unit_add_dependency(other, d, u, 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) {
-        _cleanup_free_ char *buf = NULL;
-        Unit *other;
-        int r;
-
-        assert(u);
-        assert(name || path);
-
-        r  = resolve_template(u, name, path, &buf, &name);
-        if (r < 0)
-                return r;
-
-        r = manager_load_unit(u->manager, name, path, NULL, &other);
-        if (r < 0)
-                return r;
-
-        return unit_add_two_dependencies(other, d, e, u, add_reference);
-}
-
 int set_unit_path(const char *p) {
         /* This is mostly for debug purposes */
         if (setenv("SYSTEMD_UNIT_PATH", p, 0) < 0)
@@ -2479,26 +2473,23 @@ static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd
         return 0;
 }
 
-int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name) {
-        _cleanup_free_ char *match = NULL;
-        Manager *m = u->manager;
+int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
+        const char *match;
 
-        assert(m);
+        assert(u);
+        assert(bus);
+        assert(name);
 
         if (u->match_bus_slot)
                 return -EBUSY;
 
-        match = strjoin("type='signal',"
+        match = strjoina("type='signal',"
                         "sender='org.freedesktop.DBus',"
                         "path='/org/freedesktop/DBus',"
                         "interface='org.freedesktop.DBus',"
                         "member='NameOwnerChanged',"
-                        "arg0='",
-                        name,
-                        "'",
+                        "arg0='", name, "'",
                         NULL);
-        if (!match)
-                return -ENOMEM;
 
         return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
 }
@@ -2515,7 +2506,7 @@ int unit_watch_bus_name(Unit *u, const char *name) {
         if (u->manager->api_bus) {
                 /* If the bus is already available, install the match directly.
                  * Otherwise, just put the name in the list. bus_setup_api() will take care later. */
-                r = unit_install_bus_match(u->manager->api_bus, u, name);
+                r = unit_install_bus_match(u, u->manager->api_bus, name);
                 if (r < 0)
                         return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
         }
@@ -2585,6 +2576,9 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
                 unit_serialize_item(u, f, "cgroup", u->cgroup_path);
         unit_serialize_item(u, f, "cgroup-realized", yes_no(u->cgroup_realized));
 
+        if (u->cgroup_netclass_id)
+                unit_serialize_item_format(u, f, "netclass-id", "%" PRIu32, u->cgroup_netclass_id);
+
         if (serialize_jobs) {
                 if (u->job) {
                         fprintf(f, "job\n");
@@ -2602,6 +2596,62 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
         return 0;
 }
 
+int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
+        assert(u);
+        assert(f);
+        assert(key);
+
+        if (!value)
+                return 0;
+
+        fputs(key, f);
+        fputc('=', f);
+        fputs(value, f);
+        fputc('\n', f);
+
+        return 1;
+}
+
+int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value) {
+        _cleanup_free_ char *c = NULL;
+
+        assert(u);
+        assert(f);
+        assert(key);
+
+        if (!value)
+                return 0;
+
+        c = cescape(value);
+        if (!c)
+                return -ENOMEM;
+
+        fputs(key, f);
+        fputc('=', f);
+        fputs(c, f);
+        fputc('\n', f);
+
+        return 1;
+}
+
+int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd) {
+        int copy;
+
+        assert(u);
+        assert(f);
+        assert(key);
+
+        if (fd < 0)
+                return 0;
+
+        copy = fdset_put_dup(fds, fd);
+        if (copy < 0)
+                return copy;
+
+        fprintf(f, "%s=%i\n", key, copy);
+        return 1;
+}
+
 void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) {
         va_list ap;
 
@@ -2620,15 +2670,6 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *f
         fputc('\n', f);
 }
 
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
-        assert(u);
-        assert(f);
-        assert(key);
-        assert(value);
-
-        fprintf(f, "%s=%s\n", key, value);
-}
-
 int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
         ExecRuntime **rt = NULL;
         size_t offset;
@@ -2771,6 +2812,17 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
                         else
                                 u->cgroup_realized = b;
 
+                        continue;
+                } else if (streq(l, "netclass-id")) {
+                        r = safe_atou32(v, &u->cgroup_netclass_id);
+                        if (r < 0)
+                                log_unit_debug(u, "Failed to parse netclass ID %s, ignoring.", v);
+                        else {
+                                r = unit_add_to_netclass_cgroup(u);
+                                if (r < 0)
+                                        log_unit_debug_errno(u, r, "Failed to add unit to netclass cgroup, ignoring: %m");
+                        }
+
                         continue;
                 }
 
@@ -3031,32 +3083,39 @@ int unit_kill_common(
                 sd_bus_error *error) {
 
         int r = 0;
+        bool killed = false;
 
-        if (who == KILL_MAIN) {
+        if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL)) {
                 if (main_pid < 0)
                         return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
                 else if (main_pid == 0)
                         return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
         }
 
-        if (who == KILL_CONTROL) {
+        if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL)) {
                 if (control_pid < 0)
                         return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
                 else if (control_pid == 0)
                         return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
         }
 
-        if (who == KILL_CONTROL || who == KILL_ALL)
-                if (control_pid > 0)
+        if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL, KILL_ALL, KILL_ALL_FAIL))
+                if (control_pid > 0) {
                         if (kill(control_pid, signo) < 0)
                                 r = -errno;
+                        else
+                                killed = true;
+                }
 
-        if (who == KILL_MAIN || who == KILL_ALL)
-                if (main_pid > 0)
+        if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL, KILL_ALL, KILL_ALL_FAIL))
+                if (main_pid > 0) {
                         if (kill(main_pid, signo) < 0)
                                 r = -errno;
+                        else
+                                killed = true;
+                }
 
-        if (who == KILL_ALL && u->cgroup_path) {
+        if (IN_SET(who, KILL_ALL, KILL_ALL_FAIL) && u->cgroup_path) {
                 _cleanup_set_free_ Set *pid_set = NULL;
                 int q;
 
@@ -3068,8 +3127,13 @@ int unit_kill_common(
                 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, false, false, pid_set);
                 if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
                         r = q;
+                else
+                        killed = true;
         }
 
+        if (r == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL, KILL_ALL_FAIL))
+                return -ESRCH;
+
         return r;
 }
 
@@ -3266,19 +3330,6 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient,
         return 0;
 }
 
-static int unit_drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **p, char **q) {
-        _cleanup_free_ char *dir = NULL;
-        int r;
-
-        assert(u);
-
-        r = unit_drop_in_dir(u, mode, u->transient, &dir);
-        if (r < 0)
-                return r;
-
-        return drop_in_file(dir, u->id, 50, name, p, q);
-}
-
 int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
 
         _cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL;
@@ -3377,28 +3428,6 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const
         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;
-
-        assert(u);
-
-        if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
-                return 0;
-
-        r = unit_drop_in_file(u, mode, name, &p, &q);
-        if (r < 0)
-                return r;
-
-        if (unlink(q) < 0)
-                r = errno == ENOENT ? 0 : -errno;
-        else
-                r = 1;
-
-        rmdir(p);
-        return r;
-}
-
 int unit_make_transient(Unit *u) {
         assert(u);
 
@@ -3684,14 +3713,3 @@ int unit_fail_if_symlink(Unit *u, const char* where) {
 
         return -ELOOP;
 }
-
-static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
-        [UNIT_ACTIVE] = "active",
-        [UNIT_RELOADING] = "reloading",
-        [UNIT_INACTIVE] = "inactive",
-        [UNIT_FAILED] = "failed",
-        [UNIT_ACTIVATING] = "activating",
-        [UNIT_DEACTIVATING] = "deactivating"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);