chiark / gitweb /
config_parse_set_status: put signals in the correct set
[elogind.git] / src / core / device.c
index 63d0302d3b48de0367aaa1721dee8c7c5cd15618..d3deac393649667a89a676d2f1c570bfa45f34b2 100644 (file)
@@ -23,8 +23,6 @@
 #include <sys/epoll.h>
 #include <libudev.h>
 
-#include "unit.h"
-#include "device.h"
 #include "strv.h"
 #include "log.h"
 #include "unit-name.h"
@@ -32,6 +30,9 @@
 #include "def.h"
 #include "path-util.h"
 #include "udev-util.h"
+#include "unit.h"
+#include "swap.h"
+#include "device.h"
 
 static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
         [DEVICE_DEAD] = UNIT_INACTIVE,
@@ -97,7 +98,7 @@ static void device_set_state(Device *d, DeviceState state) {
         d->state = state;
 
         if (state != old_state)
-                log_debug_unit(UNIT(d)->id,
+                log_unit_debug(UNIT(d)->id,
                                "%s changed %s -> %s", UNIT(d)->id,
                                device_state_to_string(old_state),
                                device_state_to_string(state));
@@ -182,13 +183,87 @@ static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) {
         return 0;
 }
 
+static int device_make_description(Unit *u, struct udev_device *dev, const char *path) {
+        const char *model;
+
+        assert(u);
+        assert(dev);
+        assert(path);
+
+        model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
+        if (!model)
+                model = udev_device_get_property_value(dev, "ID_MODEL");
+
+        if (model) {
+                const char *label;
+
+                /* Try to concatenate the device model string with a label, if there is one */
+                label = udev_device_get_property_value(dev, "ID_FS_LABEL");
+                if (!label)
+                        label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NAME");
+                if (!label)
+                        label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NUMBER");
+
+                if (label) {
+                        _cleanup_free_ char *j;
+
+                        j = strjoin(model, " ", label, NULL);
+                        if (j)
+                                return unit_set_description(u, j);
+                }
+
+                return unit_set_description(u, model);
+        }
+
+        return unit_set_description(u, path);
+}
+
+static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
+        const char *wants;
+        const char *word, *state;
+        size_t l;
+        int r;
+        const char *property;
+
+        assert(u);
+        assert(dev);
+
+        property = u->manager->running_as == SYSTEMD_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
+        wants = udev_device_get_property_value(dev, property);
+        if (!wants)
+                return 0;
+
+        FOREACH_WORD_QUOTED(word, l, wants, state) {
+                _cleanup_free_ char *n = NULL;
+                char e[l+1];
+
+                memcpy(e, word, l);
+                e[l] = 0;
+
+                n = unit_name_mangle(e, MANGLE_NOGLOB);
+                if (!n)
+                        return -ENOMEM;
+
+                r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
+                if (r < 0)
+                        return r;
+        }
+        if (!isempty(state))
+                log_unit_warning(u->id, "Property %s on %s has trailing garbage, ignoring.",
+                                 property, strna(udev_device_get_syspath(dev)));
+
+        return 0;
+}
+
 static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
-        const char *sysfs, *model;
+        const char *sysfs;
         Unit *u = NULL;
-        int r;
         bool delete;
+        int r;
 
         assert(m);
+        assert(dev);
+        assert(path);
 
         sysfs = udev_device_get_syspath(dev);
         if (!sysfs)
@@ -229,7 +304,7 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
                         goto fail;
                 }
 
-                r = hashmap_ensure_allocated(&m->devices_by_sysfs, string_hash_func, string_compare_func);
+                r = hashmap_ensure_allocated(&m->devices_by_sysfs, &string_hash_ops);
                 if (r < 0)
                         goto fail;
 
@@ -241,43 +316,15 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
                         goto fail;
         }
 
-        if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) ||
-            (model = udev_device_get_property_value(dev, "ID_MODEL")))
-                r = unit_set_description(u, model);
-        else
-                r = unit_set_description(u, path);
-        if (r < 0)
-                goto fail;
+        device_make_description(u, dev, path);
 
         if (main) {
-                const char *wants;
-
                 /* The additional systemd udev properties we only
                  * interpret for the main object */
 
-                wants = udev_device_get_property_value(dev, m->running_as == SYSTEMD_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS");
-                if (wants) {
-                        char *state, *w;
-                        size_t l;
-
-                        FOREACH_WORD_QUOTED(w, l, wants, state) {
-                                _cleanup_free_ char *n = NULL;
-                                char e[l+1];
-
-                                memcpy(e, w, l);
-                                e[l] = 0;
-
-                                n = unit_name_mangle(e);
-                                if (!n) {
-                                        r = -ENOMEM;
-                                        goto fail;
-                                }
-
-                                r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
-                                if (r < 0)
-                                        goto fail;
-                        }
-                }
+                r = device_add_udev_wants(u, dev);
+                if (r < 0)
+                        goto fail;
         }
 
         /* Note that this won't dispatch the load queue, the caller
@@ -287,7 +334,7 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
         return 0;
 
 fail:
-        log_warning("Failed to load device unit: %s", strerror(-r));
+        log_warning_errno(r, "Failed to load device unit: %m");
 
         if (delete && u)
                 unit_free(u);
@@ -335,7 +382,7 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) {
                  * same /dev/disk/by-label/xxx link because they have
                  * the same label. We want to make sure that the same
                  * device that won the symlink wins in systemd, so we
-                 * check the device node major/minor*/
+                 * check the device node major/minor */
                 if (stat(p, &st) >= 0)
                         if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
                             st.st_rdev != udev_device_get_devnum(dev))
@@ -348,13 +395,13 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) {
          * aliases */
         alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
         if (alias) {
-                char *state, *w;
+                const char *word, *state;
                 size_t l;
 
-                FOREACH_WORD_QUOTED(w, l, alias, state) {
+                FOREACH_WORD_QUOTED(word, l, alias, state) {
                         char e[l+1];
 
-                        memcpy(e, w, l);
+                        memcpy(e, word, l);
                         e[l] = 0;
 
                         if (path_is_absolute(e))
@@ -362,6 +409,8 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) {
                         else
                                 log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, e);
                 }
+                if (!isempty(state))
+                        log_warning("SYSTEMD_ALIAS for %s has trailing garbage, ignoring.", sysfs);
         }
 
         return 0;
@@ -468,7 +517,7 @@ static int device_following_set(Unit *u, Set **_set) {
                 return 0;
         }
 
-        set = set_new(NULL, NULL);
+        set = set_new(NULL);
         if (!set)
                 return -ENOMEM;
 
@@ -502,11 +551,6 @@ static void device_shutdown(Manager *m) {
                 m->udev_monitor = NULL;
         }
 
-        if (m->udev) {
-                udev_unref(m->udev);
-                m->udev = NULL;
-        }
-
         hashmap_free(m->devices_by_sysfs);
         m->devices_by_sysfs = NULL;
 }
@@ -518,11 +562,7 @@ static int device_enumerate(Manager *m) {
 
         assert(m);
 
-        if (!m->udev) {
-                m->udev = udev_new();
-                if (!m->udev)
-                        return -ENOMEM;
-
+        if (!m->udev_monitor) {
                 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
                 if (!m->udev_monitor) {
                         r = -ENOMEM;
@@ -542,7 +582,7 @@ static int device_enumerate(Manager *m) {
                 if (r < 0)
                         goto fail;
 
-                r = sd_event_add_io(m->event, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m, &m->udev_event_source);
+                r = sd_event_add_io(m->event, &m->udev_event_source, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m);
                 if (r < 0)
                         goto fail;
         }
@@ -557,6 +597,10 @@ static int device_enumerate(Manager *m) {
         if (r < 0)
                 goto fail;
 
+        r = udev_enumerate_add_match_is_initialized(e);
+        if (r < 0)
+                goto fail;
+
         r = udev_enumerate_scan_devices(e);
         if (r < 0)
                 goto fail;
@@ -584,7 +628,7 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
                 static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
 
                 if (!ratelimit_test(&limit))
-                        log_error("Failed to get udev event: %m");
+                        log_error_errno(errno, "Failed to get udev event: %m");
                 if (!(revents & EPOLLIN))
                         return 0;
         }
@@ -606,11 +650,20 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
         if (streq(action, "remove") || !device_is_ready(dev))  {
                 r = device_process_removed_device(m, dev);
                 if (r < 0)
-                        log_error("Failed to process device remove event: %s", strerror(-r));
+                        log_error_errno(r, "Failed to process device remove event: %m");
+
+                r = swap_process_removed_device(m, dev);
+                if (r < 0)
+                        log_error_errno(r, "Failed to process swap device remove event: %m");
+
         } else {
                 r = device_process_new_device(m, dev);
                 if (r < 0)
-                        log_error("Failed to process device new event: %s", strerror(-r));
+                        log_error_errno(r, "Failed to process device new event: %m");
+
+                r = swap_process_new_device(m, dev);
+                if (r < 0)
+                        log_error_errno(r, "Failed to process swap device new event: %m");
 
                 manager_dispatch_load_queue(m);
 
@@ -620,6 +673,19 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
         return 0;
 }
 
+static bool device_supported(Manager *m) {
+        static int read_only = -1;
+        assert(m);
+
+        /* If /sys is read-only we don't support device units, and any
+         * attempts to start one should fail immediately. */
+
+        if (read_only < 0)
+                read_only = path_is_read_only_fs("/sys");
+
+        return read_only <= 0;
+}
+
 static const char* const device_state_table[_DEVICE_STATE_MAX] = {
         [DEVICE_DEAD] = "dead",
         [DEVICE_PLUGGED] = "plugged"
@@ -648,7 +714,6 @@ const UnitVTable device_vtable = {
         .sub_state_to_string = device_sub_state_to_string,
 
         .bus_interface = "org.freedesktop.systemd1.Device",
-        .bus_changing_properties = bus_device_changing_properties,
         .bus_vtable = bus_device_vtable,
 
         .following = device_following,
@@ -656,6 +721,7 @@ const UnitVTable device_vtable = {
 
         .enumerate = device_enumerate,
         .shutdown = device_shutdown,
+        .supported = device_supported,
 
         .status_message_formats = {
                 .starting_stopping = {