]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/udev/udevd.c
tree-wide: use -EBADF also in pipe initializers
[thirdparty/systemd.git] / src / udev / udevd.c
index 2574844ed763a538077c150c6b70654fc06f4262..4942c852a0b19faf9088f2a20913944c0f0ee3cb 100644 (file)
@@ -66,6 +66,7 @@
 #include "udev-builtin.h"
 #include "udev-ctrl.h"
 #include "udev-event.h"
+#include "udev-node.h"
 #include "udev-util.h"
 #include "udev-watch.h"
 #include "user-util.h"
@@ -112,6 +113,7 @@ typedef struct Manager {
 
         usec_t last_usec;
 
+        bool udev_node_needs_cleanup;
         bool stop_exec_queue;
         bool exit;
 } Manager;
@@ -395,9 +397,7 @@ static void manager_reload(Manager *manager, bool force) {
 }
 
 static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userdata) {
-        Manager *manager = userdata;
-
-        assert(manager);
+        Manager *manager = ASSERT_PTR(userdata);
 
         log_debug("Cleanup idle workers");
         manager_kill_workers(manager, false);
@@ -473,13 +473,6 @@ static int device_get_whole_disk(sd_device *dev, sd_device **ret_device, const c
         if (device_for_action(dev, SD_DEVICE_REMOVE))
                 goto irrelevant;
 
-        r = sd_device_get_subsystem(dev, &val);
-        if (r < 0)
-                return log_device_debug_errno(dev, r, "Failed to get subsystem: %m");
-
-        if (!streq(val, "block"))
-                goto irrelevant;
-
         r = sd_device_get_sysname(dev, &val);
         if (r < 0)
                 return log_device_debug_errno(dev, r, "Failed to get sysname: %m");
@@ -493,20 +486,15 @@ static int device_get_whole_disk(sd_device *dev, sd_device **ret_device, const c
         if (STARTSWITH_SET(val, "dm-", "md", "drbd"))
                 goto irrelevant;
 
-        r = sd_device_get_devtype(dev, &val);
-        if (r < 0 && r != -ENOENT)
-                return log_device_debug_errno(dev, r, "Failed to get devtype: %m");
-        if (r >= 0 && streq(val, "partition")) {
-                r = sd_device_get_parent(dev, &dev);
-                if (r == -ENOENT) /* The device may be already removed. */
-                        goto irrelevant;
-                if (r < 0)
-                        return log_device_debug_errno(dev, r, "Failed to get parent device: %m");
-        }
+        r = block_device_get_whole_disk(dev, &dev);
+        if (IN_SET(r,
+                   -ENOTBLK, /* The device is not a block device. */
+                   -ENODEV   /* The whole disk device was not found, it may already be removed. */))
+                goto irrelevant;
+        if (r < 0)
+                return log_device_debug_errno(dev, r, "Failed to get whole disk device: %m");
 
         r = sd_device_get_devname(dev, &val);
-        if (r == -ENOENT)
-                goto irrelevant;
         if (r < 0)
                 return log_device_debug_errno(dev, r, "Failed to get devname: %m");
 
@@ -525,7 +513,7 @@ irrelevant:
 }
 
 static int worker_lock_whole_disk(sd_device *dev, int *ret_fd) {
-        _cleanup_close_ int fd = -1;
+        _cleanup_close_ int fd = -EBADF;
         sd_device *dev_whole_disk;
         const char *val;
         int r;
@@ -544,7 +532,7 @@ static int worker_lock_whole_disk(sd_device *dev, int *ret_fd) {
         if (r == 0)
                 goto nolock;
 
-        fd = sd_device_open(dev_whole_disk, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+        fd = sd_device_open(dev_whole_disk, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
         if (fd < 0) {
                 bool ignore = ERRNO_IS_DEVICE_ABSENT(fd);
 
@@ -562,12 +550,12 @@ static int worker_lock_whole_disk(sd_device *dev, int *ret_fd) {
         return 1;
 
 nolock:
-        *ret_fd = -1;
+        *ret_fd = -EBADF;
         return 0;
 }
 
 static int worker_mark_block_device_read_only(sd_device *dev) {
-        _cleanup_close_ int fd = -1;
+        _cleanup_close_ int fd = -EBADF;
         const char *val;
         int state = 1, r;
 
@@ -599,7 +587,7 @@ static int worker_mark_block_device_read_only(sd_device *dev) {
         if (STARTSWITH_SET(val, "dm-", "md", "drbd", "loop", "nbd", "zram"))
                 return 0;
 
-        fd = sd_device_open(dev, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+        fd = sd_device_open(dev, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
         if (fd < 0)
                 return log_device_debug_errno(dev, fd, "Failed to open '%s', ignoring: %m", val);
 
@@ -612,7 +600,7 @@ static int worker_mark_block_device_read_only(sd_device *dev) {
 
 static int worker_process_device(Manager *manager, sd_device *dev) {
         _cleanup_(udev_event_freep) UdevEvent *udev_event = NULL;
-        _cleanup_close_ int fd_lock = -1;
+        _cleanup_close_ int fd_lock = -EBADF;
         int r;
 
         assert(manager);
@@ -654,20 +642,21 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
                 /* in case rtnl was initialized */
                 manager->rtnl = sd_netlink_ref(udev_event->rtnl);
 
-        r = udev_event_process_inotify_watch(udev_event, manager->inotify_fd);
-        if (r < 0)
-                return r;
+        if (udev_event->inotify_watch) {
+                r = udev_watch_begin(manager->inotify_fd, dev);
+                if (r < 0 && r != -ENOENT) /* The device may be already removed, ignore -ENOENT. */
+                        log_device_warning_errno(dev, r, "Failed to add inotify watch, ignoring: %m");
+        }
 
         log_device_uevent(dev, "Device processed");
         return 0;
 }
 
 static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
-        Manager *manager = userdata;
+        Manager *manager = ASSERT_PTR(userdata);
         int r;
 
         assert(dev);
-        assert(manager);
 
         r = worker_process_device(manager, dev);
         if (r == EVENT_RESULT_TRY_AGAIN)
@@ -729,8 +718,6 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device
         if (r < 0)
                 return log_error_errno(r, "Failed to start device monitor: %m");
 
-        (void) sd_event_source_set_description(sd_device_monitor_get_event_source(monitor), "worker-device-monitor");
-
         /* Process first device */
         (void) worker_device_monitor_handler(monitor, dev, manager);
 
@@ -742,9 +729,8 @@ static int worker_main(Manager *_manager, sd_device_monitor *monitor, sd_device
 }
 
 static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
-        Event *event = userdata;
+        Event *event = ASSERT_PTR(userdata);
 
-        assert(event);
         assert(event->worker);
 
         kill_and_sigcont(event->worker->pid, arg_timeout_signal);
@@ -756,9 +742,8 @@ static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
 }
 
 static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
-        Event *event = userdata;
+        Event *event = ASSERT_PTR(userdata);
 
-        assert(event);
         assert(event->worker);
 
         log_device_warning(event->dev, "Worker ["PID_FMT"] processing SEQNUM=%"PRIu64" is taking a long time", event->worker->pid, event->seqnum);
@@ -977,6 +962,9 @@ static int event_queue_start(Manager *manager) {
         if (!manager->events || manager->exit || manager->stop_exec_queue)
                 return 0;
 
+        /* To make the stack directory /run/udev/links cleaned up later. */
+        manager->udev_node_needs_cleanup = true;
+
         r = event_source_disable(manager->kill_workers_event);
         if (r < 0)
                 log_warning_errno(r, "Failed to disable event source for cleaning up idle workers, ignoring: %m");
@@ -1159,11 +1147,9 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
 }
 
 static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
-        Manager *manager = userdata;
+        Manager *manager = ASSERT_PTR(userdata);
         int r;
 
-        assert(manager);
-
         DEVICE_TRACE_POINT(kernel_uevent_received, dev);
 
         device_ensure_usec_initialized(dev, NULL);
@@ -1180,9 +1166,7 @@ static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata)
 }
 
 static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        Manager *manager = userdata;
-
-        assert(manager);
+        Manager *manager = ASSERT_PTR(userdata);
 
         for (;;) {
                 EventResult result;
@@ -1247,11 +1231,10 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
 
 /* receive the udevd message from userspace */
 static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrlMessageValue *value, void *userdata) {
-        Manager *manager = userdata;
+        Manager *manager = ASSERT_PTR(userdata);
         int r;
 
         assert(value);
-        assert(manager);
 
         switch (type) {
         case UDEV_CTRL_SET_LOG_LEVEL:
@@ -1381,52 +1364,44 @@ static int synthesize_change_one(sd_device *dev, sd_device *target) {
 }
 
 static int synthesize_change(sd_device *dev) {
-        const char *subsystem, *sysname, *devtype;
-        int r;
+        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+        bool part_table_read;
+        const char *sysname;
+        sd_device *d;
+        int r, k;
 
-        r = sd_device_get_subsystem(dev, &subsystem);
+        r = sd_device_get_sysname(dev, &sysname);
         if (r < 0)
                 return r;
 
-        r = sd_device_get_devtype(dev, &devtype);
+        if (startswith(sysname, "dm-") || block_device_is_whole_disk(dev) <= 0)
+                return synthesize_change_one(dev, dev);
+
+        r = blockdev_reread_partition_table(dev);
         if (r < 0)
-                return r;
+                log_device_debug_errno(dev, r, "Failed to re-read partition table, ignoring: %m");
+        part_table_read = r >= 0;
 
-        r = sd_device_get_sysname(dev, &sysname);
+        /* search for partitions */
+        r = partition_enumerator_new(dev, &e);
         if (r < 0)
                 return r;
 
-        if (streq_ptr(subsystem, "block") &&
-            streq_ptr(devtype, "disk") &&
-            !startswith(sysname, "dm-")) {
-                _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
-                bool part_table_read;
-                sd_device *d;
-
-                r = blockdev_reread_partition_table(dev);
-                if (r < 0)
-                        log_device_debug_errno(dev, r, "Failed to re-read partition table, ignoring: %m");
-                part_table_read = r >= 0;
-
-                /* search for partitions */
-                r = partition_enumerator_new(dev, &e);
-                if (r < 0)
-                        return r;
-
-                /* We have partitions and re-read the table, the kernel already sent out a "change"
-                 * event for the disk, and "remove/add" for all partitions. */
-                if (part_table_read && sd_device_enumerator_get_device_first(e))
-                        return 0;
+        /* We have partitions and re-read the table, the kernel already sent out a "change"
+         * event for the disk, and "remove/add" for all partitions. */
+        if (part_table_read && sd_device_enumerator_get_device_first(e))
+                return 0;
 
-                /* We have partitions but re-reading the partition table did not work, synthesize
-                 * "change" for the disk and all partitions. */
-                (void) synthesize_change_one(dev, dev);
-                FOREACH_DEVICE(e, d)
-                        (void) synthesize_change_one(dev, d);
-        } else
-                (void) synthesize_change_one(dev, dev);
+        /* We have partitions but re-reading the partition table did not work, synthesize
+         * "change" for the disk and all partitions. */
+        r = synthesize_change_one(dev, dev);
+        FOREACH_DEVICE(e, d) {
+                k = synthesize_change_one(dev, d);
+                if (k < 0 && r >= 0)
+                        r = k;
+        }
 
-        return 0;
+        return r;
 }
 
 static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
@@ -1447,32 +1422,40 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda
                 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
                 const char *devnode;
 
+                /* Do not handle IN_IGNORED here. Especially, do not try to call udev_watch_end() from the
+                 * main process. Otherwise, the pair of the symlinks may become inconsistent, and several
+                 * garbage may remain. The old symlinks are removed by a worker that processes the
+                 * corresponding 'remove' uevent;
+                 * udev_event_execute_rules() -> event_execute_rules_on_remove() -> udev_watch_end(). */
+
+                if (!FLAGS_SET(e->mask, IN_CLOSE_WRITE))
+                        continue;
+
                 r = device_new_from_watch_handle(&dev, e->wd);
                 if (r < 0) {
+                        /* Device may be removed just after closed. */
                         log_debug_errno(r, "Failed to create sd_device object from watch handle, ignoring: %m");
                         continue;
                 }
 
-                if (sd_device_get_devname(dev, &devnode) < 0)
+                r = sd_device_get_devname(dev, &devnode);
+                if (r < 0) {
+                        /* Also here, device may be already removed. */
+                        log_device_debug_errno(dev, r, "Failed to get device node, ignoring: %m");
                         continue;
-
-                log_device_debug(dev, "Inotify event: %x for %s", e->mask, devnode);
-                if (e->mask & IN_CLOSE_WRITE) {
-                        (void) event_queue_assume_block_device_unlocked(manager, dev);
-                        (void) synthesize_change(dev);
                 }
 
-                /* Do not handle IN_IGNORED here. It should be handled by worker in 'remove' uevent;
-                 * udev_event_execute_rules() -> event_execute_rules_on_remove() -> udev_watch_end(). */
+                log_device_debug(dev, "Received inotify event for %s.", devnode);
+
+                (void) event_queue_assume_block_device_unlocked(manager, dev);
+                (void) synthesize_change(dev);
         }
 
         return 0;
 }
 
 static int on_sigterm(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
-        Manager *manager = userdata;
-
-        assert(manager);
+        Manager *manager = ASSERT_PTR(userdata);
 
         manager_exit(manager);
 
@@ -1480,9 +1463,7 @@ static int on_sigterm(sd_event_source *s, const struct signalfd_siginfo *si, voi
 }
 
 static int on_sighup(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
-        Manager *manager = userdata;
-
-        assert(manager);
+        Manager *manager = ASSERT_PTR(userdata);
 
         manager_reload(manager, /* force = */ true);
 
@@ -1533,9 +1514,7 @@ static int on_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
 }
 
 static int on_post(sd_event_source *s, void *userdata) {
-        Manager *manager = userdata;
-
-        assert(manager);
+        Manager *manager = ASSERT_PTR(userdata);
 
         if (manager->events) {
                 /* Try to process pending events if idle workers exist. Why is this necessary?
@@ -1566,6 +1545,11 @@ static int on_post(sd_event_source *s, void *userdata) {
 
         /* There are no idle workers. */
 
+        if (manager->udev_node_needs_cleanup) {
+                (void) udev_node_cleanup();
+                manager->udev_node_needs_cleanup = false;
+        }
+
         if (manager->exit)
                 return sd_event_exit(manager->event, 0);
 
@@ -1577,7 +1561,7 @@ static int on_post(sd_event_source *s, void *userdata) {
 }
 
 static int listen_fds(int *ret_ctrl, int *ret_netlink) {
-        int ctrl_fd = -1, netlink_fd = -1;
+        int ctrl_fd = -EBADF, netlink_fd = -EBADF;
         int fd, n;
 
         assert(ret_ctrl);
@@ -1826,7 +1810,7 @@ static int create_subcgroup(char **ret) {
         }
 
         r = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, cgroup, "trusted.delegate");
-        if (IN_SET(r, 0, -ENODATA))
+        if (r == 0 || (r < 0 && ERRNO_IS_XATTR_ABSENT(r)))
                 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "The cgroup %s is not delegated to us.", cgroup);
         if (r < 0)
                 return log_debug_errno(r, "Failed to read trusted.delegate attribute: %m");
@@ -1863,8 +1847,8 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent) {
                 return log_oom();
 
         *manager = (Manager) {
-                .inotify_fd = -1,
-                .worker_watch = { -1, -1 },
+                .inotify_fd = -EBADF,
+                .worker_watch = { -EBADF, -EBADF },
                 .cgroup = TAKE_PTR(cgroup),
         };
 
@@ -1975,8 +1959,6 @@ static int main_loop(Manager *manager) {
         if (r < 0)
                 return log_error_errno(r, "Failed to start device monitor: %m");
 
-        (void) sd_event_source_set_description(sd_device_monitor_get_event_source(manager->monitor), "device-monitor");
-
         r = sd_event_add_io(manager->event, NULL, fd_worker, EPOLLIN, on_worker, manager);
         if (r < 0)
                 return log_error_errno(r, "Failed to create worker event source: %m");
@@ -2011,7 +1993,7 @@ static int main_loop(Manager *manager) {
 
 int run_udevd(int argc, char *argv[]) {
         _cleanup_(manager_freep) Manager *manager = NULL;
-        int fd_ctrl = -1, fd_uevent = -1;
+        int fd_ctrl = -EBADF, fd_uevent = -EBADF;
         int r;
 
         log_set_target(LOG_TARGET_AUTO);