udevd.c revision 78d3e041a57b0c790b7c0b01906d9eb19a031029
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt/*
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * Copyright (C) 2004-2012 Kay Sievers <kay@vrfy.org>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * Copyright (C) 2009 Canonical Ltd.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt *
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * This program is free software: you can redistribute it and/or modify
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * it under the terms of the GNU General Public License as published by
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * the Free Software Foundation, either version 2 of the License, or
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * (at your option) any later version.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt *
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * This program is distributed in the hope that it will be useful,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * but WITHOUT ANY WARRANTY; without even the implied warranty of
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * GNU General Public License for more details.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt *
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * You should have received a copy of the GNU General Public License
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * along with this program. If not, see <http://www.gnu.org/licenses/>.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <stddef.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <signal.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <unistd.h>
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt#include <errno.h>
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams#include <stdio.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <stdlib.h>
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include <stdbool.h>
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include <string.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <fcntl.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <getopt.h>
3df3e884ae1237ef0d4d23b0e80f4ffda95ac135Ronny Chevalier#include <sys/file.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <sys/time.h>
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include <sys/prctl.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <sys/socket.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <sys/signalfd.h>
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include <sys/epoll.h>
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt#include <sys/mount.h>
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen#include <sys/wait.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <sys/stat.h>
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams#include <sys/ioctl.h>
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams#include <sys/inotify.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "sd-daemon.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "sd-event.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "terminal-util.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "signal-util.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "event-util.h"
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams#include "netlink-util.h"
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams#include "cgroup-util.h"
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams#include "process-util.h"
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include "dev-setup.h"
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#include "fileio.h"
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt#include "selinux-util.h"
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt#include "udev.h"
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#include "udev-util.h"
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt#include "formats-util.h"
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt#include "hashmap.h"
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flyktstatic bool arg_debug = false;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int arg_daemonize = false;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int arg_resolve_names = 1;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic unsigned arg_children_max;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int arg_exec_delay;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic usec_t arg_event_timeout_warn_usec = 180 * USEC_PER_SEC / 3;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersentypedef struct Manager {
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams struct udev *udev;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt sd_event *event;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Hashmap *workers;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt struct udev_list_node events;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt const char *cgroup;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt pid_t pid; /* the process that originally allocated the manager object */
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt struct udev_rules *rules;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt struct udev_list properties;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt struct udev_monitor *monitor;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt struct udev_ctrl *ctrl;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt struct udev_ctrl_connection *ctrl_conn_blocking;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt int fd_inotify;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt int worker_watch[2];
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt sd_event_source *ctrl_event;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt sd_event_source *uevent_event;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt sd_event_source *inotify_event;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt usec_t last_usec;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt bool stop_exec_queue:1;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt bool exit:1;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt} Manager;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktenum event_state {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt EVENT_UNDEF,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt EVENT_QUEUED,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt EVENT_RUNNING,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt};
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstruct event {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct udev_list_node node;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt Manager *manager;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct udev *udev;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct udev_device *dev;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct udev_device *dev_kernel;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct worker *worker;
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt enum event_state state;
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt unsigned long long int delaying_seqnum;
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt unsigned long long int seqnum;
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt const char *devpath;
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt size_t devpath_len;
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt const char *devpath_old;
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt dev_t devnum;
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt int ifindex;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt bool is_block;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt sd_event_source *timeout_warning;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt sd_event_source *timeout;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt};
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic inline struct event *node_to_event(struct udev_list_node *node) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return container_of(node, struct event, node);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic void event_queue_cleanup(Manager *manager, enum event_state type);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktenum worker_state {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt WORKER_UNDEF,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt WORKER_RUNNING,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt WORKER_IDLE,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt WORKER_KILLED,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt};
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstruct worker {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Manager *manager;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt struct udev_list_node node;
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams int refcount;
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams pid_t pid;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt struct udev_monitor *monitor;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt enum worker_state state;
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams struct event *event;
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams};
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams/* passed from worker to main process */
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williamsstruct worker_message {
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams};
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williamsstatic void event_free(struct event *event) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt int r;
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams if (!event)
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams return;
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams udev_list_node_remove(&event->node);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams udev_device_unref(event->dev);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams udev_device_unref(event->dev_kernel);
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams sd_event_source_unref(event->timeout_warning);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt sd_event_source_unref(event->timeout);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (event->worker)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt event->worker->event = NULL;
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller assert(event->manager);
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller if (udev_list_node_is_empty(&event->manager->events)) {
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller /* only clean up the queue from the process that created it */
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller if (event->manager->pid == getpid()) {
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller r = unlink("/run/udev/queue");
ebe207d4acf38165adbc45298662982eecdb9e9fTom Gundersen if (r < 0)
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams log_warning_errno(errno, "could not unlink /run/udev/queue: %m");
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams }
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams }
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams free(event);
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams}
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersenstatic void worker_free(struct worker *worker) {
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen if (!worker)
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen return;
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen assert(worker->manager);
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen hashmap_remove(worker->manager->workers, UINT_TO_PTR(worker->pid));
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen udev_monitor_unref(worker->monitor);
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen event_free(worker->event);
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen free(worker);
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen}
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersenstatic void manager_workers_free(Manager *manager) {
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen struct worker *worker;
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen Iterator i;
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen assert(manager);
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen HASHMAP_FOREACH(worker, manager->workers, i)
fe4b2156256c5bdf52341576571ce9f095d9f085Tom Gundersen worker_free(worker);
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen
ebe207d4acf38165adbc45298662982eecdb9e9fTom Gundersen manager->workers = hashmap_free(manager->workers);
764aad6258eec3bd4ae62ea341ea507bd69ce628Tom Gundersen}
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williamsstatic int worker_new(struct worker **ret, Manager *manager, struct udev_monitor *worker_monitor, pid_t pid) {
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams _cleanup_free_ struct worker *worker = NULL;
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams int r;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(ret);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(manager);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(worker_monitor);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(pid > 1);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt worker = new0(struct worker, 1);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (!worker)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return -ENOMEM;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt worker->refcount = 1;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt worker->manager = manager;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt /* close monitor, but keep address around */
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt udev_monitor_disconnect(worker_monitor);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt worker->monitor = udev_monitor_ref(worker_monitor);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt worker->pid = pid;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt r = hashmap_ensure_allocated(&manager->workers, NULL);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (r < 0)
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt return r;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt r = hashmap_put(manager->workers, UINT_TO_PTR(pid), worker);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt if (r < 0)
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt return r;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt *ret = worker;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt worker = NULL;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt return 0;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt}
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flyktstatic int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt struct event *event = userdata;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt assert(event);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt assert(event->worker);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt kill_and_sigcont(event->worker->pid, SIGKILL);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt event->worker->state = WORKER_KILLED;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt log_error("seq %llu '%s' killed", udev_device_get_seqnum(event->dev), event->devpath);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt return 1;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt}
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flyktstatic int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt struct event *event = userdata;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt assert(event);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt log_warning("seq %llu '%s' is taking a long time", udev_device_get_seqnum(event->dev), event->devpath);
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt return 1;
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt}
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flyktstatic void worker_attach_event(struct worker *worker, struct event *event) {
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt sd_event *e;
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt uint64_t usec;
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt int r;
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt assert(worker);
ea3b3a75abb3f8b853f7da454b9b8e258a120eeaPatrik Flykt assert(worker->manager);
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt assert(event);
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt assert(!event->worker);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(!worker->event);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt worker->state = WORKER_RUNNING;
c806ffb9592fa9a2b13a1f9f9be4c77cd5b211aaZbigniew Jędrzejewski-Szmek worker->event = event;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt event->state = EVENT_RUNNING;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt event->worker = worker;
4e3e6679e8f73b83d38e4b20d8b025e12991d1cbPatrik Flykt
4e3e6679e8f73b83d38e4b20d8b025e12991d1cbPatrik Flykt e = worker->manager->event;
4e3e6679e8f73b83d38e4b20d8b025e12991d1cbPatrik Flykt
4e3e6679e8f73b83d38e4b20d8b025e12991d1cbPatrik Flykt r = sd_event_now(e, clock_boottime_or_monotonic(), &usec);
4e3e6679e8f73b83d38e4b20d8b025e12991d1cbPatrik Flykt if (r < 0)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt (void) sd_event_add_time(e, &event->timeout_warning, clock_boottime_or_monotonic(),
c806ffb9592fa9a2b13a1f9f9be4c77cd5b211aaZbigniew Jędrzejewski-Szmek usec + arg_event_timeout_warn_usec, USEC_PER_SEC, on_event_timeout_warning, event);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt (void) sd_event_add_time(e, &event->timeout, clock_boottime_or_monotonic(),
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt usec + arg_event_timeout_usec, USEC_PER_SEC, on_event_timeout, event);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt}
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flyktstatic void manager_free(Manager *manager) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (!manager)
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt udev_builtin_exit(manager->udev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt sd_event_source_unref(manager->ctrl_event);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt sd_event_source_unref(manager->uevent_event);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt sd_event_source_unref(manager->inotify_event);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt udev_unref(manager->udev);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt sd_event_unref(manager->event);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt manager_workers_free(manager);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt event_queue_cleanup(manager, EVENT_UNDEF);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt udev_monitor_unref(manager->monitor);
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt udev_ctrl_unref(manager->ctrl);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt udev_list_cleanup(&manager->properties);
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt udev_rules_unref(manager->rules);
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt safe_close(manager->fd_inotify);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt safe_close_pair(manager->worker_watch);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt free(manager);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt}
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik FlyktDEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int worker_send_message(int fd) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt struct worker_message message = {};
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt return loop_write(fd, &message, sizeof(message), false);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt}
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic void worker_spawn(Manager *manager, struct event *event) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt struct udev *udev = event->udev;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt _cleanup_udev_monitor_unref_ struct udev_monitor *worker_monitor = NULL;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt pid_t pid;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt int r = 0;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt /* listen for new events */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt worker_monitor = udev_monitor_new_from_netlink(udev, NULL);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (worker_monitor == NULL)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt /* allow the main daemon netlink address to send devices to the worker */
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt udev_monitor_allow_unicast_sender(worker_monitor, manager->monitor);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt r = udev_monitor_enable_receiving(worker_monitor);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (r < 0)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt log_error_errno(r, "worker: could not enable receiving of device: %m");
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt pid = fork();
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt switch (pid) {
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt case 0: {
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt struct udev_device *dev = NULL;
926695f1b5f9395eeb416cc2f478a9cf75fdbeb4Thomas Hindoe Paaboel Andersen _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
926695f1b5f9395eeb416cc2f478a9cf75fdbeb4Thomas Hindoe Paaboel Andersen int fd_monitor;
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt _cleanup_close_ int fd_signal = -1, fd_ep = -1;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt struct epoll_event ep_signal = { .events = EPOLLIN };
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt struct epoll_event ep_monitor = { .events = EPOLLIN };
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt sigset_t mask;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt /* take initial device from queue */
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt dev = event->dev;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt event->dev = NULL;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt unsetenv("NOTIFY_SOCKET");
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt manager_workers_free(manager);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt event_queue_cleanup(manager, EVENT_UNDEF);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt manager->monitor = udev_monitor_unref(manager->monitor);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt manager->ctrl = udev_ctrl_unref(manager->ctrl);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt manager->uevent_event = sd_event_source_unref(manager->uevent_event);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt manager->inotify_event = sd_event_source_unref(manager->inotify_event);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt manager->event = sd_event_unref(manager->event);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt sigfillset(&mask);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (fd_signal < 0) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt r = log_error_errno(errno, "error creating signalfd %m");
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt goto out;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt }
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt ep_signal.data.fd = fd_signal;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt fd_monitor = udev_monitor_get_fd(worker_monitor);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt ep_monitor.data.fd = fd_monitor;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt fd_ep = epoll_create1(EPOLL_CLOEXEC);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (fd_ep < 0) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt r = log_error_errno(errno, "error creating epoll fd: %m");
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt goto out;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt }
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt r = log_error_errno(errno, "fail to add fds to epoll: %m");
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt goto out;
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller }
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams /* request TERM signal if parent exits */
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt prctl(PR_SET_PDEATHSIG, SIGTERM);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt /* reset OOM score, we only protect the main daemon */
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt write_string_file("/proc/self/oom_score_adj", "0");
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt for (;;) {
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt struct udev_event *udev_event;
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt int fd_lock = -1;
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt assert(dev);
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt log_debug("seq %llu running", udev_device_get_seqnum(dev));
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt udev_event = udev_event_new(dev);
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt if (udev_event == NULL) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt r = -ENOMEM;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt goto out;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt }
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (arg_exec_delay > 0)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt udev_event->exec_delay = arg_exec_delay;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt /*
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt * Take a shared lock on the device node; this establishes
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt * a concept of device "ownership" to serialize device
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt * access. External processes holding an exclusive lock will
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * cause udev to skip the event handling; in the case udev
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * acquired the lock, the external process can block until
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * udev has finished its event handling.
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (!streq_ptr(udev_device_get_action(dev), "remove") &&
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt streq_ptr("block", udev_device_get_subsystem(dev)) &&
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt !startswith(udev_device_get_sysname(dev), "dm-") &&
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt !startswith(udev_device_get_sysname(dev), "md")) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt struct udev_device *d = dev;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (streq_ptr("partition", udev_device_get_devtype(d)))
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt d = udev_device_get_parent(d);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (d) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt fd_lock = open(udev_device_get_devnode(d), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (fd_lock >= 0 && flock(fd_lock, LOCK_SH|LOCK_NB) < 0) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_debug_errno(errno, "Unable to flock(%s), skipping event handling: %m", udev_device_get_devnode(d));
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt fd_lock = safe_close(fd_lock);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt goto skip;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /* needed for renaming netifs */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt udev_event->rtnl = rtnl;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /* apply rules, create node, symlinks */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt udev_event_execute_rules(udev_event,
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt arg_event_timeout_usec, arg_event_timeout_warn_usec,
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt &manager->properties,
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt manager->rules);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt udev_event_execute_run(udev_event,
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt arg_event_timeout_usec, arg_event_timeout_warn_usec);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (udev_event->rtnl)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* in case rtnl was initialized */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt rtnl = sd_netlink_ref(udev_event->rtnl);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt /* apply/restore inotify watch */
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (udev_event->inotify_watch) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt udev_watch_begin(udev, dev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt udev_device_update_db(dev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt safe_close(fd_lock);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt /* send processed event back to libudev listeners */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt udev_monitor_send_device(worker_monitor, NULL, dev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flyktskip:
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt log_debug("seq %llu processed", udev_device_get_seqnum(dev));
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt /* send udevd the result of the event execution */
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt r = worker_send_message(manager->worker_watch[WRITE_END]);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_error_errno(r, "failed to send result of seq %llu to main daemon: %m",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt udev_device_get_seqnum(dev));
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt udev_device_unref(dev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt dev = NULL;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt udev_event_unref(udev_event);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* wait for more device messages from main udevd, or term signal */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt while (dev == NULL) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt struct epoll_event ev[4];
4b4923e65423e60d755841b5b264730e8f3deab3Tom Gundersen int fdcount;
5e91345094a9e983e7abb2313334e7808bcd2cc2Tom Gundersen int i;
513a6fa8679510ea1b55967bdb482dd5f8a39f21Ronny Chevalier
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (fdcount < 0) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (errno == EINTR)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt continue;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = log_error_errno(errno, "failed to poll: %m");
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt goto out;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt for (i = 0; i < fdcount; i++) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt dev = udev_monitor_receive_device(worker_monitor);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt break;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt } else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt struct signalfd_siginfo fdsi;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt ssize_t size;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt if (size != sizeof(struct signalfd_siginfo))
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt continue;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt switch (fdsi.ssi_signo) {
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt case SIGTERM:
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt goto out;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktout:
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt udev_device_unref(dev);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt manager_free(manager);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt log_close();
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt }
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt case -1:
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt event->state = EVENT_QUEUED;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt log_error_errno(errno, "fork of child failed: %m");
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt break;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt default:
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt struct worker *worker;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt r = worker_new(&worker, manager, worker_monitor, pid);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt if (r < 0)
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt return;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt worker_attach_event(worker, event);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt log_debug("seq %llu forked new worker ["PID_FMT"]", udev_device_get_seqnum(event->dev), pid);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt break;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt }
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt }
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt}
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flyktstatic void event_run(Manager *manager, struct event *event) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt struct worker *worker;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt Iterator i;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt assert(manager);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt assert(event);
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt HASHMAP_FOREACH(worker, manager->workers, i) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt ssize_t count;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (worker->state != WORKER_IDLE)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt continue;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt count = udev_monitor_send_device(manager->monitor, worker->monitor, event->dev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (count < 0) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_error_errno(errno, "worker ["PID_FMT"] did not accept message %zi (%m), kill it",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt worker->pid, count);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt kill(worker->pid, SIGKILL);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt worker->state = WORKER_KILLED;
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen continue;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt worker_attach_event(worker, event);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return;
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt }
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt if (hashmap_size(manager->workers) >= arg_children_max) {
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt if (arg_children_max > 1)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_debug("maximum number (%i) of children reached", hashmap_size(manager->workers));
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt /* start new worker and pass initial device */
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt worker_spawn(manager, event);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt}
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int event_queue_insert(Manager *manager, struct udev_device *dev) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt struct event *event;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt int r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(manager);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(dev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* only one process can add events to the queue */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (manager->pid == 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt manager->pid = getpid();
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(manager->pid == getpid());
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt event = new0(struct event, 1);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (!event)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return -ENOMEM;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt event->udev = udev_device_get_udev(dev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt event->manager = manager;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt event->dev = dev;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt event->dev_kernel = udev_device_shallow_clone(dev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt udev_device_copy_properties(event->dev_kernel, dev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt event->seqnum = udev_device_get_seqnum(dev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt event->devpath = udev_device_get_devpath(dev);
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering event->devpath_len = strlen(event->devpath);
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen event->devpath_old = udev_device_get_devpath_old(dev);
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen event->devnum = udev_device_get_devnum(dev);
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen event->is_block = streq("block", udev_device_get_subsystem(dev));
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt event->ifindex = udev_device_get_ifindex(dev);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_debug("seq %llu queued, '%s' '%s'", udev_device_get_seqnum(dev),
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt udev_device_get_action(dev), udev_device_get_subsystem(dev));
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt event->state = EVENT_QUEUED;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen if (udev_list_node_is_empty(&manager->events)) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = touch("/run/udev/queue");
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_warning_errno(r, "could not touch /run/udev/queue: %m");
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt udev_list_node_append(&event->node, &manager->events);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return 0;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt}
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersenstatic void manager_kill_workers(Manager *manager) {
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering struct worker *worker;
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen Iterator i;
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(manager);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt HASHMAP_FOREACH(worker, manager->workers, i) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (worker->state == WORKER_KILLED)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt continue;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt worker->state = WORKER_KILLED;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt kill(worker->pid, SIGTERM);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt}
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt/* lookup event for identical, parent, child device */
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flyktstatic bool is_devpath_busy(Manager *manager, struct event *event) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt struct udev_list_node *loop;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt size_t common;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt /* check if queue contains events we depend on */
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen udev_list_node_foreach(loop, &manager->events) {
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen struct event *loop_event = node_to_event(loop);
cfb5b3805759e63dc5e0cae6e92e1df885b5c5b6Tom Gundersen
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt /* we already found a later event, earlier can not block us, no need to check again */
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (loop_event->seqnum < event->delaying_seqnum)
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt continue;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* event we checked earlier still exists, no need to check again */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (loop_event->seqnum == event->delaying_seqnum)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return true;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek /* found ourself, no later event can block us */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (loop_event->seqnum >= event->seqnum)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt break;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* check major/minor */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (major(event->devnum) != 0 && event->devnum == loop_event->devnum && event->is_block == loop_event->is_block)
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek return true;
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek
44481a8b537839cd9ffead4d261491641f5b5260Zbigniew Jędrzejewski-Szmek /* check network device ifindex */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (event->ifindex != 0 && event->ifindex == loop_event->ifindex)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return true;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* check our old name */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (event->devpath_old != NULL && streq(loop_event->devpath, event->devpath_old)) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt event->delaying_seqnum = loop_event->seqnum;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return true;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* compare devpath */
66eac1201a9c1596f5901f8dbbf24bda7e350878Dan Williams common = MIN(loop_event->devpath_len, event->devpath_len);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* one devpath is contained in the other? */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (memcmp(loop_event->devpath, event->devpath, common) != 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt continue;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* identical device event found */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (loop_event->devpath_len == event->devpath_len) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* devices names might have changed/swapped in the meantime */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (major(event->devnum) != 0 && (event->devnum != loop_event->devnum || event->is_block != loop_event->is_block))
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt continue;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (event->ifindex != 0 && event->ifindex != loop_event->ifindex)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt continue;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt event->delaying_seqnum = loop_event->seqnum;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return true;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* parent device event found */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (event->devpath[common] == '/') {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt event->delaying_seqnum = loop_event->seqnum;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return true;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* child device event found */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (loop_event->devpath[common] == '/') {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt event->delaying_seqnum = loop_event->seqnum;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return true;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* no matching device */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt continue;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return false;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int on_exit_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt Manager *manager = userdata;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(manager);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error_errno(ETIMEDOUT, "giving up waiting for workers to finish");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt sd_event_exit(manager->event, -ETIMEDOUT);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return 1;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic void manager_exit(Manager *manager) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt uint64_t usec;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt int r;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(manager);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt manager->exit = true;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt sd_notify(false,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "STOPPING=1\n"
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "STATUS=Starting shutdown...");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* close sources of new events and discard buffered events */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager->ctrl = udev_ctrl_unref(manager->ctrl);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager->inotify_event = sd_event_source_unref(manager->inotify_event);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager->fd_inotify = safe_close(manager->fd_inotify);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager->uevent_event = sd_event_source_unref(manager->uevent_event);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager->monitor = udev_monitor_unref(manager->monitor);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* discard queued events and kill workers */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt event_queue_cleanup(manager, EVENT_QUEUED);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt manager_kill_workers(manager);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt r = sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt if (r < 0)
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt return;
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt r = sd_event_add_time(manager->event, NULL, clock_boottime_or_monotonic(),
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt usec + 30 * USEC_PER_SEC, USEC_PER_SEC, on_exit_timeout, manager);
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt if (r < 0)
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt return;
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt}
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flykt/* reload requested, HUP signal received, rules changed, builtin changed */
7bd8e95d44977833d0de3fc4e893eb3bc84351d6Patrik Flyktstatic void manager_reload(Manager *manager) {
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt assert(manager);
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt sd_notify(false,
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt "RELOADING=1\n"
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt "STATUS=Flushing configuration...");
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt
5da1b97f3c3d15521f2dcfbc18eccd6580122ebcPatrik Flykt manager_kill_workers(manager);
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt manager->rules = udev_rules_unref(manager->rules);
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt udev_builtin_exit(manager->udev);
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt sd_notify(false,
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt "READY=1\n"
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt "STATUS=Processing...");
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt}
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flyktstatic void event_queue_start(Manager *manager) {
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt struct udev_list_node *loop;
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt usec_t usec;
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt int r;
41e4615d4f4f5c61afa84ba857f23c0ac496687bPatrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(manager);
6599680e2d33597f0f11a99e1c3c957b42418568Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (udev_list_node_is_empty(&manager->events) ||
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager->exit || manager->stop_exec_queue)
c47e8936a43ce546e8a74fa569e9fbfae6c64be7Patrik Flykt return;
c47e8936a43ce546e8a74fa569e9fbfae6c64be7Patrik Flykt
c47e8936a43ce546e8a74fa569e9fbfae6c64be7Patrik Flykt r = sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec);
c47e8936a43ce546e8a74fa569e9fbfae6c64be7Patrik Flykt if (r >= 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* check for changed config, every 3 seconds at most */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (manager->last_usec == 0 ||
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt (usec - manager->last_usec) > 3 * USEC_PER_SEC) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (udev_rules_check_timestamp(manager->rules) ||
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt udev_builtin_validate(manager->udev))
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt manager_reload(manager);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt manager->last_usec = usec;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt }
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt }
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt udev_builtin_init(manager->udev);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!manager->rules) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt manager->rules = udev_rules_new(manager->udev, arg_resolve_names);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (!manager->rules)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt udev_list_node_foreach(loop, &manager->events) {
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt struct event *event = node_to_event(loop);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (event->state != EVENT_QUEUED)
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt continue;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /* do not start event if parent or child event is still running */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (is_devpath_busy(manager, event))
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt continue;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt event_run(manager, event);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt}
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flyktstatic void event_queue_cleanup(Manager *manager, enum event_state match_type) {
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt struct udev_list_node *loop, *tmp;
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt udev_list_node_foreach_safe(loop, tmp, &manager->events) {
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt struct event *event = node_to_event(loop);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt if (match_type != EVENT_UNDEF && match_type != event->state)
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt continue;
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt event_free(event);
5364f729ba9616cd9fdab8d5413fbc25a1af3a57Lennart Poettering }
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt}
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flyktstatic int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
9d89d1ae71cb298218e35a69d6b70e2c94de5271Patrik Flykt Manager *manager = userdata;
9d89d1ae71cb298218e35a69d6b70e2c94de5271Patrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt assert(manager);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt for (;;) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt struct worker_message msg;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct iovec iovec = {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt .iov_base = &msg,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt .iov_len = sizeof(msg),
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt };
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt union {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct cmsghdr cmsghdr;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt } control = {};
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct msghdr msghdr = {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt .msg_iov = &iovec,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt .msg_iovlen = 1,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt .msg_control = &control,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt .msg_controllen = sizeof(control),
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt };
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct cmsghdr *cmsg;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt ssize_t size;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct ucred *ucred = NULL;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct worker *worker;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt size = recvmsg(fd, &msghdr, MSG_DONTWAIT);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (size < 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (errno == EINTR)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt continue;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt else if (errno == EAGAIN)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* nothing more to read */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt break;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return log_error_errno(errno, "failed to receive message: %m");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt } else if (size != sizeof(struct worker_message)) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_warning_errno(EIO, "ignoring worker message with invalid size %zi bytes", size);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt continue;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt }
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt CMSG_FOREACH(cmsg, &msghdr) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (cmsg->cmsg_level == SOL_SOCKET &&
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt cmsg->cmsg_type == SCM_CREDENTIALS &&
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt ucred = (struct ucred*) CMSG_DATA(cmsg);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!ucred || ucred->pid <= 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_warning_errno(EIO, "ignoring worker message without valid PID");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt continue;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* lookup worker who sent the signal */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt worker = hashmap_get(manager->workers, UINT_TO_PTR(ucred->pid));
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!worker) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_debug("worker ["PID_FMT"] returned, but is no longer tracked", ucred->pid);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt continue;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (worker->state != WORKER_KILLED)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt worker->state = WORKER_IDLE;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* worker returned */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt event_free(worker->event);
6ec60d20724d2a32e20d25ef75d2af178c242bc2Ronny Chevalier }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* we have free workers, try to schedule events */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt event_queue_start(manager);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return 1;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int on_uevent(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt Manager *manager = userdata;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct udev_device *dev;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt int r;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(manager);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt dev = udev_monitor_receive_device(manager->monitor);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (dev) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt udev_device_ensure_usec_initialized(dev, NULL);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = event_queue_insert(manager, dev);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r < 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt udev_device_unref(dev);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt else
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* we have fresh events, try to schedule them */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt event_queue_start(manager);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return 1;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt/* receive the udevd message from userspace */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt Manager *manager = userdata;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt _cleanup_udev_ctrl_connection_unref_ struct udev_ctrl_connection *ctrl_conn = NULL;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt _cleanup_udev_ctrl_msg_unref_ struct udev_ctrl_msg *ctrl_msg = NULL;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt const char *str;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt int i;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(manager);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt ctrl_conn = udev_ctrl_get_connection(manager->ctrl);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (!ctrl_conn)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return 1;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt ctrl_msg = udev_ctrl_receive_msg(ctrl_conn);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!ctrl_msg)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return 1;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt i = udev_ctrl_get_set_log_level(ctrl_msg);
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt if (i >= 0) {
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt log_debug("udevd message (SET_LOG_LEVEL) received, log_priority=%i", i);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt log_set_max_level(i);
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt manager_kill_workers(manager);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
ed6ee21953dac9c78383da00bc4514ece6b75ab5Patrik Flykt
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt log_debug("udevd message (STOP_EXEC_QUEUE) received");
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt manager->stop_exec_queue = true;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_debug("udevd message (START_EXEC_QUEUE) received");
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt manager->stop_exec_queue = false;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt event_queue_start(manager);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (udev_ctrl_get_reload(ctrl_msg) > 0) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_debug("udevd message (RELOAD) received");
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt manager_reload(manager);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt str = udev_ctrl_get_set_env(ctrl_msg);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (str != NULL) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt _cleanup_free_ char *key = NULL;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt key = strdup(str);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (key) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt char *val;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt val = strchr(key, '=');
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (val != NULL) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt val[0] = '\0';
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt val = &val[1];
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (val[0] == '\0') {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_debug("udevd message (ENV) received, unset '%s'", key);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt udev_list_entry_add(&manager->properties, key, NULL);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt } else {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_debug("udevd message (ENV) received, set '%s=%s'", key, val);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt udev_list_entry_add(&manager->properties, key, val);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt }
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt } else
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt log_error("wrong key format '%s'", key);
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt manager_kill_workers(manager);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt i = udev_ctrl_get_set_children_max(ctrl_msg);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (i >= 0) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_debug("udevd message (SET_MAX_CHILDREN) received, children_max=%i", i);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt arg_children_max = i;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (udev_ctrl_get_ping(ctrl_msg) > 0)
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt log_debug("udevd message (SYNC) received");
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt if (udev_ctrl_get_exit(ctrl_msg) > 0) {
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt log_debug("udevd message (EXIT) received");
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt manager_exit(manager);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt /* keep reference to block the client until we exit
38a03f06a7393d2721c23f23f0589d2f6d0904afLennart Poettering TODO: deal with several blocking exit requests */
38a03f06a7393d2721c23f23f0589d2f6d0904afLennart Poettering manager->ctrl_conn_blocking = udev_ctrl_connection_ref(ctrl_conn);
38a03f06a7393d2721c23f23f0589d2f6d0904afLennart Poettering }
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt return 1;
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt}
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flyktstatic int synthesize_change(struct udev_device *dev) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt char filename[UTIL_PATH_SIZE];
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt int r;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen if (streq_ptr("block", udev_device_get_subsystem(dev)) &&
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt streq_ptr("disk", udev_device_get_devtype(dev)) &&
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt !startswith(udev_device_get_sysname(dev), "dm-")) {
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt bool part_table_read = false;
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt bool has_partitions = false;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt int fd;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt struct udev *udev = udev_device_get_udev(dev);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt struct udev_list_entry *item;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt /*
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * Try to re-read the partition table. This only succeeds if
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt * none of the devices is busy. The kernel returns 0 if no
7246333cb803b03440d3bd0bdaa233564d09b5aePatrik Flykt * partition table is found, and we will not get an event for
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt * the disk.
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt fd = open(udev_device_get_devnode(dev), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (fd >= 0) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = flock(fd, LOCK_EX|LOCK_NB);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (r >= 0)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = ioctl(fd, BLKRRPART, 0);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt close(fd);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (r >= 0)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt part_table_read = true;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /* search for partitions */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt e = udev_enumerate_new(udev);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (!e)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return -ENOMEM;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = udev_enumerate_add_match_parent(e, dev);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (r < 0)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return r;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = udev_enumerate_add_match_subsystem(e, "block");
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen if (r < 0)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return r;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt r = udev_enumerate_scan_devices(e);
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (r < 0)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return r;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt udev_list_entry_foreach(item, udev_enumerate_get_list_entry(e)) {
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt _cleanup_udev_device_unref_ struct udev_device *d = NULL;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering if (!d)
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen continue;
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen if (!streq_ptr("partition", udev_device_get_devtype(d)))
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt continue;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt has_partitions = true;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt break;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt }
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /*
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * We have partitions and re-read the table, the kernel already sent
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * out a "change" event for the disk, and "remove/add" for all
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen * partitions.
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (part_table_read && has_partitions)
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt return 0;
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt /*
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * We have partitions but re-reading the partition table did not
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt * work, synthesize "change" for the disk and all partitions.
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt */
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev));
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering write_string_file(filename, "change");
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen udev_list_entry_foreach(item, udev_enumerate_get_list_entry(e)) {
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen _cleanup_udev_device_unref_ struct udev_device *d = NULL;
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt
3dc34fcc97b41f8b7b019027225b121dfbb9871dPatrik Flykt d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
a34b57c0d43b8bf819ccd4f62c314b41b625454dPatrik Flykt if (!d)
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt continue;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
c3e2adeaba8e043caed0ef139eeaea016bd152d0Patrik Flykt if (!streq_ptr("partition", udev_device_get_devtype(d)))
346e13a25dc6f76d3bc9d8decd40dc4782b02d2aPatrik Flykt continue;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_debug("device %s closed, synthesising partition '%s' 'change'",
fa94c34b083b5b4019975624453e53d0cbad2a5dTom Gundersen udev_device_get_devnode(dev), udev_device_get_devnode(d));
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt strscpyl(filename, sizeof(filename), udev_device_get_syspath(d), "/uevent", NULL);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt write_string_file(filename, "change");
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return 0;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev));
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
356779df90a2ecab5da2cb310ad0f8ebc9ca9f46Lennart Poettering write_string_file(filename, "change");
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen return 0;
9021bb9f935c93b516b10c88db2a212a9e3a8140Tom Gundersen}
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flyktstatic int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt Manager *manager = userdata;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt union inotify_event_buffer buffer;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt struct inotify_event *e;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt ssize_t l;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(manager);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt l = read(fd, &buffer, sizeof(buffer));
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (l < 0) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (errno == EAGAIN || errno == EINTR)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return 1;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return log_error_errno(errno, "Failed to read inotify fd: %m");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt FOREACH_INOTIFY_EVENT(e, buffer, l) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
c806ffb9592fa9a2b13a1f9f9be4c77cd5b211aaZbigniew Jędrzejewski-Szmek
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt dev = udev_watch_lookup(manager->udev, e->wd);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (!dev)
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt continue;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt log_debug("inotify event: %x for %s", e->mask, udev_device_get_devnode(dev));
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt if (e->mask & IN_CLOSE_WRITE) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt synthesize_change(dev);
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller /* settle might be waiting on us to determine the queue
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller * state. If we just handled an inotify event, we might have
cc22955cfefb4bd6e7a135f1ec95fb5a07ba9ce3Thomas Haller * generated a "change" event, but we won't have queued up
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt * the resultant uevent yet. Do that.
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt */
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt on_uevent(NULL, -1, 0, manager);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt } else if (e->mask & IN_IGNORED)
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt udev_watch_end(manager->udev, dev);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt }
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return 1;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt}
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flyktstatic int on_sigterm(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt Manager *manager = userdata;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(manager);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt manager_exit(manager);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return 1;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt}
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flyktstatic int on_sighup(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt Manager *manager = userdata;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(manager);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt manager_reload(manager);
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt return 1;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt}
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flyktstatic int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt Manager *manager = userdata;
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt
bbfa43ca37df0718287c25a8e39ee7477ebf33f6Patrik Flykt assert(manager);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt for (;;) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt pid_t pid;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt int status;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt struct worker *worker;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt pid = waitpid(-1, &status, WNOHANG);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (pid <= 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt break;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt worker = hashmap_get(manager->workers, UINT_TO_PTR(pid));
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (!worker) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_warning("worker ["PID_FMT"] is unknown, ignoring", pid);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt continue;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (WIFEXITED(status)) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (WEXITSTATUS(status) == 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_debug("worker ["PID_FMT"] exited", pid);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt else
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_warning("worker ["PID_FMT"] exited with return code %i", pid, WEXITSTATUS(status));
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt } else if (WIFSIGNALED(status)) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_warning("worker ["PID_FMT"] terminated by signal %i (%s)", pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt } else if (WIFSTOPPED(status)) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_info("worker ["PID_FMT"] stopped", pid);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt continue;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt } else if (WIFCONTINUED(status)) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_info("worker ["PID_FMT"] continued", pid);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt continue;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt } else
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_warning("worker ["PID_FMT"] exit with status 0x%04x", pid, status);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (worker->event) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_error("worker ["PID_FMT"] failed while handling '%s'", pid, worker->event->devpath);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* delete state from disk */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt udev_device_delete_db(worker->event->dev);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt udev_device_tag_index(worker->event->dev, NULL, false);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* forward kernel event without amending it */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt udev_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt worker_free(worker);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
f0c4b1c3fd827b429ba36aa45fd39e0a023cbf2cTom Gundersen /* we can start new workers, try to schedule events */
c806ffb9592fa9a2b13a1f9f9be4c77cd5b211aaZbigniew Jędrzejewski-Szmek event_queue_start(manager);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return 1;
62e3d1aed512d68cab1fc9b509e813a1fa2b3790Lennart Poettering}
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flyktstatic int on_post(sd_event_source *s, void *userdata) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Manager *manager = userdata;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt int r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(manager);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (udev_list_node_is_empty(&manager->events)) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* no pending events */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (!hashmap_isempty(manager->workers)) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* there are idle workers */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_debug("cleanup idle workers");
3f0c075f8ef3344da5a6bda524540201f9204e61Patrik Flykt manager_kill_workers(manager);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt } else {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* we are idle */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (manager->exit) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = sd_event_exit(manager->event, 0);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r < 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt } else if (manager->cgroup)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* cleanup possible left-over processes in our cgroup */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, false, true, NULL);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return 1;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
c806ffb9592fa9a2b13a1f9f9be4c77cd5b211aaZbigniew Jędrzejewski-Szmek
c806ffb9592fa9a2b13a1f9f9be4c77cd5b211aaZbigniew Jędrzejewski-Szmekstatic int listen_fds(int *rctrl, int *rnetlink) {
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt _cleanup_udev_unref_ struct udev *udev = NULL;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt int ctrl_fd = -1, netlink_fd = -1;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt int fd, n, r;
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt assert(rctrl);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt assert(rnetlink);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt n = sd_listen_fds(true);
da6fe470e17fa02f3adedc779585caf8669252bdPatrik Flykt if (n < 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return n;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (ctrl_fd >= 0)
return -EINVAL;
ctrl_fd = fd;
continue;
}
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1)) {
if (netlink_fd >= 0)
return -EINVAL;
netlink_fd = fd;
continue;
}
return -EINVAL;
}
if (ctrl_fd < 0) {
_cleanup_udev_ctrl_unref_ struct udev_ctrl *ctrl = NULL;
udev = udev_new();
if (!udev)
return -ENOMEM;
ctrl = udev_ctrl_new(udev);
if (!ctrl)
return log_error_errno(EINVAL, "error initializing udev control socket");
r = udev_ctrl_enable_receiving(ctrl);
if (r < 0)
return log_error_errno(EINVAL, "error binding udev control socket");
fd = udev_ctrl_get_fd(ctrl);
if (fd < 0)
return log_error_errno(EIO, "could not get ctrl fd");
ctrl_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (ctrl_fd < 0)
return log_error_errno(errno, "could not dup ctrl fd: %m");
}
if (netlink_fd < 0) {
_cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL;
if (!udev) {
udev = udev_new();
if (!udev)
return -ENOMEM;
}
monitor = udev_monitor_new_from_netlink(udev, "kernel");
if (!monitor)
return log_error_errno(EINVAL, "error initializing netlink socket");
(void) udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
r = udev_monitor_enable_receiving(monitor);
if (r < 0)
return log_error_errno(EINVAL, "error binding netlink socket");
fd = udev_monitor_get_fd(monitor);
if (fd < 0)
return log_error_errno(netlink_fd, "could not get uevent fd: %m");
netlink_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (ctrl_fd < 0)
return log_error_errno(errno, "could not dup netlink fd: %m");
}
*rctrl = ctrl_fd;
*rnetlink = netlink_fd;
return 0;
}
/*
* read the kernel command line, in case we need to get into debug mode
* udev.log-priority=<level> syslog priority
* udev.children-max=<number of workers> events are fully serialized if set to 1
* udev.exec-delay=<number of seconds> delay execution of every executed program
* udev.event-timeout=<number of seconds> seconds to wait before terminating an event
*/
static int parse_proc_cmdline_item(const char *key, const char *value) {
int r;
assert(key);
if (!value)
return 0;
if (startswith(key, "rd."))
key += strlen("rd.");
if (startswith(key, "udev."))
key += strlen("udev.");
else
return 0;
if (streq(key, "log-priority")) {
int prio;
prio = util_log_priority(value);
log_set_max_level(prio);
} else if (streq(key, "children-max")) {
r = safe_atou(value, &arg_children_max);
if (r < 0)
log_warning("invalid udev.children-max ignored: %s", value);
} else if (streq(key, "exec-delay")) {
r = safe_atoi(value, &arg_exec_delay);
if (r < 0)
log_warning("invalid udev.exec-delay ignored: %s", value);
} else if (streq(key, "event-timeout")) {
r = safe_atou64(value, &arg_event_timeout_usec);
if (r < 0)
log_warning("invalid udev.event-timeout ignored: %s", value);
else {
arg_event_timeout_usec *= USEC_PER_SEC;
arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
}
}
return 0;
}
static void help(void) {
printf("%s [OPTIONS...]\n\n"
"Manages devices.\n\n"
" -h --help Print this message\n"
" --version Print version of the program\n"
" --daemon Detach and run in the background\n"
" --debug Enable debug output\n"
" --children-max=INT Set maximum number of workers\n"
" --exec-delay=SECONDS Seconds to wait before executing RUN=\n"
" --event-timeout=SECONDS Seconds to wait before terminating an event\n"
" --resolve-names=early|late|never\n"
" When to resolve users and groups\n"
, program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
static const struct option options[] = {
{ "daemon", no_argument, NULL, 'd' },
{ "debug", no_argument, NULL, 'D' },
{ "children-max", required_argument, NULL, 'c' },
{ "exec-delay", required_argument, NULL, 'e' },
{ "event-timeout", required_argument, NULL, 't' },
{ "resolve-names", required_argument, NULL, 'N' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{}
};
int c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "c:de:DtN:hV", options, NULL)) >= 0) {
int r;
switch (c) {
case 'd':
arg_daemonize = true;
break;
case 'c':
r = safe_atou(optarg, &arg_children_max);
if (r < 0)
log_warning("Invalid --children-max ignored: %s", optarg);
break;
case 'e':
r = safe_atoi(optarg, &arg_exec_delay);
if (r < 0)
log_warning("Invalid --exec-delay ignored: %s", optarg);
break;
case 't':
r = safe_atou64(optarg, &arg_event_timeout_usec);
if (r < 0)
log_warning("Invalid --event-timeout ignored: %s", optarg);
else {
arg_event_timeout_usec *= USEC_PER_SEC;
arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
}
break;
case 'D':
arg_debug = true;
break;
case 'N':
if (streq(optarg, "early")) {
arg_resolve_names = 1;
} else if (streq(optarg, "late")) {
arg_resolve_names = 0;
} else if (streq(optarg, "never")) {
arg_resolve_names = -1;
} else {
log_error("resolve-names must be early, late or never");
return 0;
}
break;
case 'h':
help();
return 0;
case 'V':
printf("%s\n", VERSION);
return 0;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
}
return 1;
}
static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cgroup) {
_cleanup_(manager_freep) Manager *manager = NULL;
int r, fd_worker, one = 1;
assert(ret);
assert(fd_ctrl >= 0);
assert(fd_uevent >= 0);
manager = new0(Manager, 1);
if (!manager)
return log_oom();
manager->fd_inotify = -1;
manager->worker_watch[WRITE_END] = -1;
manager->worker_watch[READ_END] = -1;
manager->udev = udev_new();
if (!manager->udev)
return log_error_errno(errno, "could not allocate udev context: %m");
udev_builtin_init(manager->udev);
manager->rules = udev_rules_new(manager->udev, arg_resolve_names);
if (!manager->rules)
return log_error_errno(ENOMEM, "error reading rules");
udev_list_node_init(&manager->events);
udev_list_init(manager->udev, &manager->properties, true);
manager->cgroup = cgroup;
manager->ctrl = udev_ctrl_new_from_fd(manager->udev, fd_ctrl);
if (!manager->ctrl)
return log_error_errno(EINVAL, "error taking over udev control socket");
manager->monitor = udev_monitor_new_from_netlink_fd(manager->udev, "kernel", fd_uevent);
if (!manager->monitor)
return log_error_errno(EINVAL, "error taking over netlink socket");
/* unnamed socket from workers to the main daemon */
r = socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch);
if (r < 0)
return log_error_errno(errno, "error creating socketpair: %m");
fd_worker = manager->worker_watch[READ_END];
r = setsockopt(fd_worker, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
if (r < 0)
return log_error_errno(errno, "could not enable SO_PASSCRED: %m");
manager->fd_inotify = udev_watch_init(manager->udev);
if (manager->fd_inotify < 0)
return log_error_errno(ENOMEM, "error initializing inotify");
udev_watch_restore(manager->udev);
/* block and listen to all signals on signalfd */
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0);
r = sd_event_default(&manager->event);
if (r < 0)
return log_error_errno(errno, "could not allocate event loop: %m");
r = sd_event_add_signal(manager->event, NULL, SIGINT, on_sigterm, manager);
if (r < 0)
return log_error_errno(r, "error creating sigint event source: %m");
r = sd_event_add_signal(manager->event, NULL, SIGTERM, on_sigterm, manager);
if (r < 0)
return log_error_errno(r, "error creating sigterm event source: %m");
r = sd_event_add_signal(manager->event, NULL, SIGHUP, on_sighup, manager);
if (r < 0)
return log_error_errno(r, "error creating sighup event source: %m");
r = sd_event_add_signal(manager->event, NULL, SIGCHLD, on_sigchld, manager);
if (r < 0)
return log_error_errno(r, "error creating sigchld event source: %m");
r = sd_event_set_watchdog(manager->event, true);
if (r < 0)
return log_error_errno(r, "error creating watchdog event source: %m");
r = sd_event_add_io(manager->event, &manager->ctrl_event, fd_ctrl, EPOLLIN, on_ctrl_msg, manager);
if (r < 0)
return log_error_errno(r, "error creating ctrl event source: %m");
/* This needs to be after the inotify and uevent handling, to make sure
* that the ping is send back after fully processing the pending uevents
* (including the synthetic ones we may create due to inotify events).
*/
r = sd_event_source_set_priority(manager->ctrl_event, SD_EVENT_PRIORITY_IDLE);
if (r < 0)
return log_error_errno(r, "cold not set IDLE event priority for ctrl event source: %m");
r = sd_event_add_io(manager->event, &manager->inotify_event, manager->fd_inotify, EPOLLIN, on_inotify, manager);
if (r < 0)
return log_error_errno(r, "error creating inotify event source: %m");
r = sd_event_add_io(manager->event, &manager->uevent_event, fd_uevent, EPOLLIN, on_uevent, manager);
if (r < 0)
return log_error_errno(r, "error creating uevent event source: %m");
r = sd_event_add_io(manager->event, NULL, fd_worker, EPOLLIN, on_worker, manager);
if (r < 0)
return log_error_errno(r, "error creating worker event source: %m");
r = sd_event_add_post(manager->event, NULL, on_post, manager);
if (r < 0)
return log_error_errno(r, "error creating post event source: %m");
*ret = manager;
manager = NULL;
return 0;
}
int main(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *manager = NULL;
_cleanup_free_ char *cgroup = NULL;
int r, fd_ctrl, fd_uevent;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto exit;
r = parse_proc_cmdline(parse_proc_cmdline_item);
if (r < 0)
log_warning_errno(r, "failed to parse kernel command line, ignoring: %m");
if (arg_debug) {
log_set_target(LOG_TARGET_CONSOLE);
log_set_max_level(LOG_DEBUG);
}
if (getuid() != 0) {
r = log_error_errno(EPERM, "root privileges required");
goto exit;
}
if (arg_children_max == 0) {
cpu_set_t cpu_set;
arg_children_max = 8;
if (sched_getaffinity(0, sizeof (cpu_set), &cpu_set) == 0) {
arg_children_max += CPU_COUNT(&cpu_set) * 2;
}
log_debug("set children_max to %u", arg_children_max);
}
/* set umask before creating any file/directory */
r = chdir("/");
if (r < 0) {
r = log_error_errno(errno, "could not change dir to /: %m");
goto exit;
}
umask(022);
r = mac_selinux_init("/dev");
if (r < 0) {
log_error_errno(r, "could not initialize labelling: %m");
goto exit;
}
r = mkdir("/run/udev", 0755);
if (r < 0 && errno != EEXIST) {
r = log_error_errno(errno, "could not create /run/udev: %m");
goto exit;
}
dev_setup(NULL, UID_INVALID, GID_INVALID);
if (getppid() == 1) {
/* get our own cgroup, we regularly kill everything udev has left behind
we only do this on systemd systems, and only if we are directly spawned
by PID1. otherwise we are not guaranteed to have a dedicated cgroup */
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
if (r < 0) {
if (r == -ENOENT)
log_debug_errno(r, "did not find dedicated cgroup: %m");
else
log_warning_errno(r, "failed to get cgroup: %m");
}
}
r = listen_fds(&fd_ctrl, &fd_uevent);
if (r < 0) {
r = log_error_errno(r, "could not listen on fds: %m");
goto exit;
}
if (arg_daemonize) {
pid_t pid;
log_info("starting version " VERSION);
/* connect /dev/null to stdin, stdout, stderr */
if (log_get_max_level() < LOG_DEBUG)
(void) make_null_stdio();
pid = fork();
switch (pid) {
case 0:
break;
case -1:
r = log_error_errno(errno, "fork of daemon failed: %m");
goto exit;
default:
mac_selinux_finish();
log_close();
_exit(EXIT_SUCCESS);
}
setsid();
write_string_file("/proc/self/oom_score_adj", "-1000");
}
r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup);
if (r < 0) {
r = log_error_errno(r, "failed to allocate manager object: %m");
goto exit;
}
r = udev_rules_apply_static_dev_perms(manager->rules);
if (r < 0)
log_error_errno(r, "failed to apply permissions on static device nodes: %m");
(void) sd_notify(false,
"READY=1\n"
"STATUS=Processing...");
r = sd_event_loop(manager->event);
if (r < 0) {
log_error_errno(r, "event loop failed: %m");
goto exit;
}
sd_event_get_exit_code(manager->event, &r);
exit:
sd_notify(false,
"STOPPING=1\n"
"STATUS=Shutting down...");
if (manager)
udev_ctrl_cleanup(manager->ctrl);
mac_selinux_finish();
log_close();
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}