]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/swap.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / core / swap.c
index 6cd703c61dd6c40819c78040949fb3146ce0017b..2d8463b8b1812173ec019b0274eaf4d39799cff0 100644 (file)
@@ -1,19 +1,17 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-***/
 
 #include <errno.h>
 #include <sys/epoll.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
-#include "libudev.h"
+#include "sd-device.h"
 
 #include "alloc-util.h"
 #include "dbus-swap.h"
+#include "dbus-unit.h"
+#include "device-private.h"
+#include "device-util.h"
 #include "device.h"
 #include "escape.h"
 #include "exit-status.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "serialize.h"
 #include "special.h"
 #include "string-table.h"
 #include "string-util.h"
 #include "swap.h"
-#include "udev-util.h"
 #include "unit-name.h"
 #include "unit.h"
 #include "virt.h"
@@ -201,7 +199,7 @@ static int swap_add_device_dependencies(Swap *s) {
                 /* File based swap devices need to be ordered after
                  * systemd-remount-fs.service, since they might need a
                  * writable file system. */
-                return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true, UNIT_DEPENDENCY_FILE);
+                return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, true, UNIT_DEPENDENCY_FILE);
 }
 
 static int swap_add_default_dependencies(Swap *s) {
@@ -220,11 +218,11 @@ static int swap_add_default_dependencies(Swap *s) {
 
         /* swap units generated for the swap dev links are missing the
          * ordering dep against the swap target. */
-        r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+        r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
         if (r < 0)
                 return r;
 
-        return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
+        return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
 }
 
 static int swap_verify(Swap *s) {
@@ -240,109 +238,127 @@ static int swap_verify(Swap *s) {
 
         if (!unit_has_name(UNIT(s), e)) {
                 log_unit_error(UNIT(s), "Value of What= and unit name do not match, not loading.");
-                return -EINVAL;
+                return -ENOEXEC;
         }
 
         if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
                 log_unit_error(UNIT(s), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.");
-                return -EINVAL;
+                return -ENOEXEC;
         }
 
         return 0;
 }
 
 static int swap_load_devnode(Swap *s) {
-        _cleanup_(udev_device_unrefp) struct udev_device *d = NULL;
+        _cleanup_(sd_device_unrefp) sd_device *d = NULL;
         struct stat st;
         const char *p;
+        int r;
 
         assert(s);
 
         if (stat(s->what, &st) < 0 || !S_ISBLK(st.st_mode))
                 return 0;
 
-        d = udev_device_new_from_devnum(UNIT(s)->manager->udev, 'b', st.st_rdev);
-        if (!d)
+        r = device_new_from_stat_rdev(&d, &st);
+        if (r < 0) {
+                log_unit_full(UNIT(s), r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+                              "Failed to allocate device for swap %s: %m", s->what);
                 return 0;
+        }
 
-        p = udev_device_get_devnode(d);
-        if (!p)
+        if (sd_device_get_devname(d, &p) < 0)
                 return 0;
 
         return swap_set_devnode(s, p);
 }
 
-static int swap_load(Unit *u) {
+static int swap_add_extras(Swap *s) {
         int r;
-        Swap *s = SWAP(u);
 
         assert(s);
-        assert(u->load_state == UNIT_STUB);
 
-        /* Load a .swap file */
-        if (SWAP(u)->from_proc_swaps)
-                r = unit_load_fragment_and_dropin_optional(u);
-        else
-                r = unit_load_fragment_and_dropin(u);
+        if (UNIT(s)->fragment_path)
+                s->from_fragment = true;
+
+        if (!s->what) {
+                if (s->parameters_fragment.what)
+                        s->what = strdup(s->parameters_fragment.what);
+                else if (s->parameters_proc_swaps.what)
+                        s->what = strdup(s->parameters_proc_swaps.what);
+                else {
+                        r = unit_name_to_path(UNIT(s)->id, &s->what);
+                        if (r < 0)
+                                return r;
+                }
+
+                if (!s->what)
+                        return -ENOMEM;
+        }
+
+        path_simplify(s->what, false);
+
+        if (!UNIT(s)->description) {
+                r = unit_set_description(UNIT(s), s->what);
+                if (r < 0)
+                        return r;
+        }
+
+        r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT);
         if (r < 0)
                 return r;
 
-        if (u->load_state == UNIT_LOADED) {
-
-                if (UNIT(s)->fragment_path)
-                        s->from_fragment = true;
+        r = swap_add_device_dependencies(s);
+        if (r < 0)
+                return r;
 
-                if (!s->what) {
-                        if (s->parameters_fragment.what)
-                                s->what = strdup(s->parameters_fragment.what);
-                        else if (s->parameters_proc_swaps.what)
-                                s->what = strdup(s->parameters_proc_swaps.what);
-                        else {
-                                r = unit_name_to_path(u->id, &s->what);
-                                if (r < 0)
-                                        return r;
-                        }
+        r = swap_load_devnode(s);
+        if (r < 0)
+                return r;
 
-                        if (!s->what)
-                                return -ENOMEM;
-                }
+        r = unit_patch_contexts(UNIT(s));
+        if (r < 0)
+                return r;
 
-                path_simplify(s->what, false);
+        r = unit_add_exec_dependencies(UNIT(s), &s->exec_context);
+        if (r < 0)
+                return r;
 
-                if (!UNIT(s)->description) {
-                        r = unit_set_description(u, s->what);
-                        if (r < 0)
-                                return r;
-                }
+        r = unit_set_default_slice(UNIT(s));
+        if (r < 0)
+                return r;
 
-                r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT);
-                if (r < 0)
-                        return r;
+        r = swap_add_default_dependencies(s);
+        if (r < 0)
+                return r;
 
-                r = swap_add_device_dependencies(s);
-                if (r < 0)
-                        return r;
+        return 0;
+}
 
-                r = swap_load_devnode(s);
-                if (r < 0)
-                        return r;
+static int swap_load(Unit *u) {
+        Swap *s = SWAP(u);
+        int r, q;
 
-                r = unit_patch_contexts(u);
-                if (r < 0)
-                        return r;
+        assert(s);
+        assert(u->load_state == UNIT_STUB);
 
-                r = unit_add_exec_dependencies(u, &s->exec_context);
-                if (r < 0)
-                        return r;
+        /* Load a .swap file */
+        if (SWAP(u)->from_proc_swaps)
+                r = unit_load_fragment_and_dropin_optional(u);
+        else
+                r = unit_load_fragment_and_dropin(u);
 
-                r = unit_set_default_slice(u);
-                if (r < 0)
-                        return r;
+        /* Add in some extras, and do so either when we successfully loaded something or when /proc/swaps is already
+         * active. */
+        if (u->load_state == UNIT_LOADED || s->from_proc_swaps)
+                q = swap_add_extras(s);
+        else
+                q = 0;
 
-                r = swap_add_default_dependencies(s);
-                if (r < 0)
-                        return r;
-        }
+        if (r < 0)
+                return r;
+        if (q < 0)
+                return q;
 
         return swap_verify(s);
 }
@@ -369,13 +385,12 @@ static int swap_setup_unit(
                 return log_unit_error_errno(u, r, "Failed to generate unit name from path: %m");
 
         u = manager_get_unit(m, e);
-
         if (u &&
             SWAP(u)->from_proc_swaps &&
-            !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps)) {
-                log_error("Swap %s appeared twice with different device paths %s and %s", e, SWAP(u)->parameters_proc_swaps.what, what_proc_swaps);
-                return -EEXIST;
-        }
+            !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
+                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                       "Swap %s appeared twice with different device paths %s and %s",
+                                       e, SWAP(u)->parameters_proc_swaps.what, what_proc_swaps);
 
         if (!u) {
                 delete = true;
@@ -404,6 +419,13 @@ static int swap_setup_unit(
                 }
         }
 
+        /* The unit is definitely around now, mark it as loaded if it was previously referenced but could not be
+         * loaded. After all we can load it now, from the data in /proc/swaps. */
+        if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) {
+                u->load_state = UNIT_LOADED;
+                u->load_error = 0;
+        }
+
         if (set_flags) {
                 SWAP(u)->is_active = true;
                 SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps;
@@ -426,10 +448,9 @@ fail:
 }
 
 static int swap_process_new(Manager *m, const char *device, int prio, bool set_flags) {
-        _cleanup_(udev_device_unrefp) struct udev_device *d = NULL;
-        struct udev_list_entry *item = NULL, *first = NULL;
-        const char *dn;
-        struct stat st;
+        _cleanup_(sd_device_unrefp) sd_device *d = NULL;
+        const char *dn, *devlink;
+        struct stat st, st_link;
         int r;
 
         assert(m);
@@ -443,38 +464,36 @@ static int swap_process_new(Manager *m, const char *device, int prio, bool set_f
         if (stat(device, &st) < 0 || !S_ISBLK(st.st_mode))
                 return 0;
 
-        d = udev_device_new_from_devnum(m->udev, 'b', st.st_rdev);
-        if (!d)
+        r = device_new_from_stat_rdev(&d, &st);
+        if (r < 0) {
+                log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+                               "Failed to allocate device for swap %s: %m", device);
                 return 0;
+        }
 
         /* Add the main device node */
-        dn = udev_device_get_devnode(d);
-        if (dn && !streq(dn, device))
+        if (sd_device_get_devname(d, &dn) >= 0 && !streq(dn, device))
                 swap_setup_unit(m, dn, device, prio, set_flags);
 
         /* Add additional units for all symlinks */
-        first = udev_device_get_devlinks_list_entry(d);
-        udev_list_entry_foreach(item, first) {
-                const char *p;
+        FOREACH_DEVICE_DEVLINK(d, devlink) {
 
                 /* Don't bother with the /dev/block links */
-                p = udev_list_entry_get_name(item);
-
-                if (streq(p, device))
+                if (streq(devlink, device))
                         continue;
 
-                if (path_startswith(p, "/dev/block/"))
+                if (path_startswith(devlink, "/dev/block/"))
                         continue;
 
-                if (stat(p, &st) >= 0)
-                        if (!S_ISBLK(st.st_mode) ||
-                            st.st_rdev != udev_device_get_devnum(d))
-                                continue;
+                if (stat(devlink, &st_link) >= 0 &&
+                    (!S_ISBLK(st_link.st_mode) ||
+                     st_link.st_rdev != st.st_rdev))
+                        continue;
 
-                swap_setup_unit(m, p, device, prio, set_flags);
+                swap_setup_unit(m, devlink, device, prio, set_flags);
         }
 
-        return r;
+        return 0;
 }
 
 static void swap_set_state(Swap *s, SwapState state) {
@@ -483,6 +502,9 @@ static void swap_set_state(Swap *s, SwapState state) {
 
         assert(s);
 
+        if (s->state != state)
+                bus_unit_send_pending_change_signal(UNIT(s), false);
+
         old_state = s->state;
         s->state = state;
 
@@ -599,11 +621,12 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) {
 
 static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
 
-        ExecParameters exec_params = {
+        _cleanup_(exec_params_clear) ExecParameters exec_params = {
                 .flags     = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
                 .stdin_fd  = -1,
                 .stdout_fd = -1,
                 .stderr_fd = -1,
+                .exec_fd   = -1,
         };
         pid_t pid;
         int r;
@@ -620,7 +643,9 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
         if (r < 0)
                 goto fail;
 
-        unit_set_exec_params(UNIT(s), &exec_params);
+        r = unit_set_exec_params(UNIT(s), &exec_params);
+        if (r < 0)
+                goto fail;
 
         r = exec_spawn(UNIT(s),
                        c,
@@ -653,9 +678,7 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
         if (s->result == SWAP_SUCCESS)
                 s->result = f;
 
-        if (s->result != SWAP_SUCCESS)
-                log_unit_warning(UNIT(s), "Failed with result '%s'.", swap_result_to_string(s->result));
-
+        unit_log_result(UNIT(s), s->result == SWAP_SUCCESS, swap_result_to_string(s->result));
         swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
 
         s->exec_runtime = exec_runtime_unref(s->exec_runtime, true);
@@ -811,6 +834,14 @@ fail:
         swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES);
 }
 
+static void swap_cycle_clear(Swap *s) {
+        assert(s);
+
+        s->result = SWAP_SUCCESS;
+        exec_command_reset_status_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
+        UNIT(s)->reset_accounting = true;
+}
+
 static int swap_start(Unit *u) {
         Swap *s = SWAP(u), *other;
         int r;
@@ -850,10 +881,7 @@ static int swap_start(Unit *u) {
         if (r < 0)
                 return r;
 
-        s->result = SWAP_SUCCESS;
-
-        u->reset_accounting = true;
-
+        swap_cycle_clear(s);
         swap_enter_activating(s);
         return 1;
 }
@@ -896,14 +924,14 @@ static int swap_serialize(Unit *u, FILE *f, FDSet *fds) {
         assert(f);
         assert(fds);
 
-        unit_serialize_item(u, f, "state", swap_state_to_string(s->state));
-        unit_serialize_item(u, f, "result", swap_result_to_string(s->result));
+        (void) serialize_item(f, "state", swap_state_to_string(s->state));
+        (void) serialize_item(f, "result", swap_result_to_string(s->result));
 
         if (s->control_pid > 0)
-                unit_serialize_item_format(u, f, "control-pid", PID_FMT, s->control_pid);
+                (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid);
 
         if (s->control_command_id >= 0)
-                unit_serialize_item(u, f, "control-command", swap_exec_command_to_string(s->control_command_id));
+                (void) serialize_item(f, "control-command", swap_exec_command_to_string(s->control_command_id));
 
         return 0;
 }
@@ -1010,8 +1038,11 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                 s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
         }
 
-        log_unit_full(u, f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
-                      "Swap process exited, code=%s status=%i", sigchld_code_to_string(code), status);
+        unit_log_process_exit(
+                        u, f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
+                        "Swap process",
+                        swap_exec_command_to_string(s->control_command_id),
+                        code, status);
 
         switch (s->state) {
 
@@ -1082,7 +1113,6 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd
 
 static int swap_load_proc_swaps(Manager *m, bool set_flags) {
         unsigned i;
-        int r = 0;
 
         assert(m);
 
@@ -1112,14 +1142,12 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) {
                 if (cunescape(dev, UNESCAPE_RELAX, &d) < 0)
                         return log_oom();
 
-                device_found_node(m, d, true, DEVICE_FOUND_SWAP, set_flags);
+                device_found_node(m, d, DEVICE_FOUND_SWAP, DEVICE_FOUND_SWAP);
 
-                k = swap_process_new(m, d, prio, set_flags);
-                if (k < 0)
-                        r = k;
+                (void) swap_process_new(m, d, prio, set_flags);
         }
 
-        return r;
+        return 0;
 }
 
 static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
@@ -1150,13 +1178,13 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
                 Swap *swap = SWAP(u);
 
                 if (!swap->is_active) {
-                        /* This has just been deactivated */
 
                         swap_unset_proc_swaps(swap);
 
                         switch (swap->state) {
 
                         case SWAP_ACTIVE:
+                                /* This has just been deactivated */
                                 swap_enter_dead(swap, SWAP_SUCCESS);
                                 break;
 
@@ -1167,7 +1195,7 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
                         }
 
                         if (swap->what)
-                                device_found_node(m, swap->what, false, DEVICE_FOUND_SWAP, true);
+                                device_found_node(m, swap->what, 0, DEVICE_FOUND_SWAP);
 
                 } else if (swap->just_activated) {
 
@@ -1177,7 +1205,8 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
 
                         case SWAP_DEAD:
                         case SWAP_FAILED:
-                                (void) unit_acquire_invocation_id(UNIT(swap));
+                                (void) unit_acquire_invocation_id(u);
+                                swap_cycle_clear(swap);
                                 swap_enter_active(swap, SWAP_SUCCESS);
                                 break;
 
@@ -1270,9 +1299,7 @@ static void swap_shutdown(Manager *m) {
         assert(m);
 
         m->swap_event_source = sd_event_source_unref(m->swap_event_source);
-
         m->proc_swaps = safe_fclose(m->proc_swaps);
-
         m->swaps_by_devnode = hashmap_free(m->swaps_by_devnode);
 }
 
@@ -1285,9 +1312,9 @@ static void swap_enumerate(Manager *m) {
                 m->proc_swaps = fopen("/proc/swaps", "re");
                 if (!m->proc_swaps) {
                         if (errno == ENOENT)
-                                log_debug("Not swap enabled, skipping enumeration");
+                                log_debug_errno(errno, "Not swap enabled, skipping enumeration.");
                         else
-                                log_error_errno(errno, "Failed to open /proc/swaps: %m");
+                                log_warning_errno(errno, "Failed to open /proc/swaps, ignoring: %m");
 
                         return;
                 }
@@ -1320,18 +1347,17 @@ fail:
         swap_shutdown(m);
 }
 
-int swap_process_device_new(Manager *m, struct udev_device *dev) {
-        struct udev_list_entry *item = NULL, *first = NULL;
+int swap_process_device_new(Manager *m, sd_device *dev) {
         _cleanup_free_ char *e = NULL;
-        const char *dn;
+        const char *dn, *devlink;
         Unit *u;
         int r = 0;
 
         assert(m);
         assert(dev);
 
-        dn = udev_device_get_devnode(dev);
-        if (!dn)
+        r = sd_device_get_devname(dev, &dn);
+        if (r < 0)
                 return 0;
 
         r = unit_name_from_path(dn, ".swap", &e);
@@ -1342,12 +1368,11 @@ int swap_process_device_new(Manager *m, struct udev_device *dev) {
         if (u)
                 r = swap_set_devnode(SWAP(u), dn);
 
-        first = udev_device_get_devlinks_list_entry(dev);
-        udev_list_entry_foreach(item, first) {
+        FOREACH_DEVICE_DEVLINK(dev, devlink) {
                 _cleanup_free_ char *n = NULL;
                 int q;
 
-                q = unit_name_from_path(udev_list_entry_get_name(item), ".swap", &n);
+                q = unit_name_from_path(devlink, ".swap", &n);
                 if (q < 0)
                         return q;
 
@@ -1362,13 +1387,13 @@ int swap_process_device_new(Manager *m, struct udev_device *dev) {
         return r;
 }
 
-int swap_process_device_remove(Manager *m, struct udev_device *dev) {
+int swap_process_device_remove(Manager *m, sd_device *dev) {
         const char *dn;
         int r = 0;
         Swap *s;
 
-        dn = udev_device_get_devnode(dev);
-        if (!dn)
+        r = sd_device_get_devname(dev, &dn);
+        if (r < 0)
                 return 0;
 
         while ((s = hashmap_get(m->swaps_by_devnode, dn))) {