udevd.c revision e859aa9e993453be321450148d45d08fcc55c3f5
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen/*
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * Copyright (C) 2004-2012 Kay Sievers <kay@vrfy.org>
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * Copyright (C) 2009 Canonical Ltd.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen *
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * This program is free software: you can redistribute it and/or modify
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * it under the terms of the GNU General Public License as published by
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * the Free Software Foundation, either version 2 of the License, or
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * (at your option) any later version.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen *
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * This program is distributed in the hope that it will be useful,
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * but WITHOUT ANY WARRANTY; without even the implied warranty of
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * GNU General Public License for more details.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen *
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * You should have received a copy of the GNU General Public License
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen * along with this program. If not, see <http://www.gnu.org/licenses/>.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen */
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include <stddef.h>
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include <signal.h>
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen#include <unistd.h>
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen#include <errno.h>
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include <stdio.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <stdlib.h>
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include <stdbool.h>
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen#include <string.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <fcntl.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <getopt.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/file.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/time.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <sys/prctl.h>
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen#include <sys/socket.h>
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering#include <sys/signalfd.h>
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering#include <sys/epoll.h>
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen#include <sys/mount.h>
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include <sys/wait.h>
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include <sys/stat.h>
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include <sys/ioctl.h>
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include <sys/inotify.h>
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "sd-daemon.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "sd-event.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "terminal-util.h"
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#include "signal-util.h"
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen#include "event-util.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "netlink-util.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "cgroup-util.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "process-util.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "dev-setup.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "fileio.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "selinux-util.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "udev.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "udev-util.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "formats-util.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen#include "hashmap.h"
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersenstatic bool arg_debug = false;
99634696183dfabae20104e58157c69029a11594Tom Gundersenstatic int arg_daemonize = false;
99634696183dfabae20104e58157c69029a11594Tom Gundersenstatic int arg_resolve_names = 1;
99634696183dfabae20104e58157c69029a11594Tom Gundersenstatic unsigned arg_children_max;
99634696183dfabae20104e58157c69029a11594Tom Gundersenstatic int arg_exec_delay;
99634696183dfabae20104e58157c69029a11594Tom Gundersenstatic usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
99634696183dfabae20104e58157c69029a11594Tom Gundersenstatic usec_t arg_event_timeout_warn_usec = 180 * USEC_PER_SEC / 3;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersentypedef struct Manager {
99634696183dfabae20104e58157c69029a11594Tom Gundersen struct udev *udev;
99634696183dfabae20104e58157c69029a11594Tom Gundersen sd_event *event;
99634696183dfabae20104e58157c69029a11594Tom Gundersen Hashmap *workers;
99634696183dfabae20104e58157c69029a11594Tom Gundersen struct udev_list_node events;
99634696183dfabae20104e58157c69029a11594Tom Gundersen const char *cgroup;
99634696183dfabae20104e58157c69029a11594Tom Gundersen pid_t pid; /* the process that originally allocated the manager object */
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen struct udev_rules *rules;
99634696183dfabae20104e58157c69029a11594Tom Gundersen struct udev_list properties;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen struct udev_monitor *monitor;
99634696183dfabae20104e58157c69029a11594Tom Gundersen struct udev_ctrl *ctrl;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen struct udev_ctrl_connection *ctrl_conn_blocking;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen int fd_inotify;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen int worker_watch[2];
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen sd_event_source *ctrl_event;
99634696183dfabae20104e58157c69029a11594Tom Gundersen sd_event_source *uevent_event;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen sd_event_source *inotify_event;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen usec_t last_usec;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen bool stop_exec_queue:1;
99634696183dfabae20104e58157c69029a11594Tom Gundersen bool exit:1;
99634696183dfabae20104e58157c69029a11594Tom Gundersen} Manager;
99634696183dfabae20104e58157c69029a11594Tom Gundersen
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersenenum event_state {
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen EVENT_UNDEF,
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen EVENT_QUEUED,
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen EVENT_RUNNING,
04c0136989b7eb896bfb0fb176e11233d69e1453Lennart Poettering};
756775814cf69471f74ce853745bba69f2ba94efThomas Hindoe Paaboel Andersen
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersenstruct event {
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen struct udev_list_node node;
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen Manager *manager;
7c16313f11e3953f3fe4dbf544f2d36f58d14138Tom Gundersen struct udev *udev;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen struct udev_device *dev;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering struct udev_device *dev_kernel;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering struct worker *worker;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering enum event_state state;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering unsigned long long int delaying_seqnum;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering unsigned long long int seqnum;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering const char *devpath;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen size_t devpath_len;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen const char *devpath_old;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen dev_t devnum;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen int ifindex;
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen bool is_block;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen sd_event_source *timeout_warning;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen sd_event_source *timeout;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen};
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenstatic inline struct event *node_to_event(struct udev_list_node *node) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return container_of(node, struct event, node);
1e2527a6fede996a429bd44b30a15e76ee293437Tom Gundersen}
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenstatic void event_queue_cleanup(Manager *manager, enum event_state type);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenenum worker_state {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen WORKER_UNDEF,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen WORKER_RUNNING,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen WORKER_IDLE,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen WORKER_KILLED,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen};
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenstruct worker {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen Manager *manager;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen struct udev_list_node node;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen int refcount;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen pid_t pid;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen struct udev_monitor *monitor;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen enum worker_state state;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen struct event *event;
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt};
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt/* passed from worker to main process */
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidtstruct worker_message {
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt};
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenstatic void event_free(struct event *event) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen int r;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (!event)
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen udev_list_node_remove(&event->node);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen udev_device_unref(event->dev);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering udev_device_unref(event->dev_kernel);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering sd_event_source_unref(event->timeout_warning);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering sd_event_source_unref(event->timeout);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering if (event->worker)
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering event->worker->event = NULL;
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering assert(event->manager);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (udev_list_node_is_empty(&event->manager->events)) {
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering /* only clean up the queue from the process that created it */
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (event->manager->pid == getpid()) {
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering r = unlink("/run/udev/queue");
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (r < 0)
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering log_warning_errno(errno, "could not unlink /run/udev/queue: %m");
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering }
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering free(event);
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering}
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poetteringstatic void worker_free(struct worker *worker) {
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering if (!worker)
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering return;
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering assert(worker->manager);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen hashmap_remove(worker->manager->workers, UINT_TO_PTR(worker->pid));
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen udev_monitor_unref(worker->monitor);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen event_free(worker->event);
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering free(worker);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen}
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersenstatic void manager_workers_free(Manager *manager) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen struct worker *worker;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen Iterator i;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(manager);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8Lennart Poettering HASHMAP_FOREACH(worker, manager->workers, i)
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen worker_free(worker);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen manager->workers = hashmap_free(manager->workers);
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen}
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidtstatic int worker_new(struct worker **ret, Manager *manager, struct udev_monitor *worker_monitor, pid_t pid) {
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering _cleanup_free_ struct worker *worker = NULL;
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering int r;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(ret);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(manager);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(worker_monitor);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(pid > 1);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen worker = new0(struct worker, 1);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if (!worker)
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen return -ENOMEM;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen worker->refcount = 1;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen worker->manager = manager;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen /* close monitor, but keep address around */
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen udev_monitor_disconnect(worker_monitor);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen worker->monitor = udev_monitor_ref(worker_monitor);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen worker->pid = pid;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen r = hashmap_ensure_allocated(&manager->workers, NULL);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (r < 0)
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return r;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen r = hashmap_put(manager->workers, UINT_TO_PTR(pid), worker);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen if (r < 0)
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return r;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen *ret = worker;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen worker = NULL;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen return 0;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen}
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersenstatic int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen struct event *event = userdata;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(event);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert(event->worker);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen kill_and_sigcont(event->worker->pid, SIGKILL);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen event->worker->state = WORKER_KILLED;
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen log_error("seq %llu '%s' killed", udev_device_get_seqnum(event->dev), event->devpath);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen return 1;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen}
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersenstatic int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen struct event *event = userdata;
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen assert(event);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen log_warning("seq %llu '%s' is taking a long time", udev_device_get_seqnum(event->dev), event->devpath);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen return 1;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen}
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersenstatic void worker_attach_event(struct worker *worker, struct event *event) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen sd_event *e;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen uint64_t usec;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(worker);
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering assert(worker->manager);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(event);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(!event->worker);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(!worker->event);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering worker->state = WORKER_RUNNING;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen worker->event = event;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen event->state = EVENT_RUNNING;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen event->worker = worker;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen e = worker->manager->event;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert_se(sd_event_now(e, clock_boottime_or_monotonic(), &usec) >= 0);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen (void) sd_event_add_time(e, &event->timeout_warning, clock_boottime_or_monotonic(),
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen usec + arg_event_timeout_warn_usec, USEC_PER_SEC, on_event_timeout_warning, event);
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen (void) sd_event_add_time(e, &event->timeout, clock_boottime_or_monotonic(),
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen usec + arg_event_timeout_usec, USEC_PER_SEC, on_event_timeout, event);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic void manager_free(Manager *manager) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (!manager)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen udev_builtin_exit(manager->udev);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen sd_event_source_unref(manager->ctrl_event);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen sd_event_source_unref(manager->uevent_event);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen sd_event_source_unref(manager->inotify_event);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen udev_unref(manager->udev);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen sd_event_unref(manager->event);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen manager_workers_free(manager);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen event_queue_cleanup(manager, EVENT_UNDEF);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen udev_monitor_unref(manager->monitor);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen udev_ctrl_unref(manager->ctrl);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen udev_list_cleanup(&manager->properties);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen udev_rules_unref(manager->rules);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen safe_close(manager->fd_inotify);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen safe_close_pair(manager->worker_watch);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen free(manager);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom GundersenDEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int worker_send_message(int fd) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen struct worker_message message = {};
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return loop_write(fd, &message, sizeof(message), false);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen}
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic void worker_spawn(Manager *manager, struct event *event) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen struct udev *udev = event->udev;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_udev_monitor_unref_ struct udev_monitor *worker_monitor = NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen pid_t pid;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int r = 0;
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen /* listen for new events */
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen worker_monitor = udev_monitor_new_from_netlink(udev, NULL);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (worker_monitor == NULL)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen return;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen /* allow the main daemon netlink address to send devices to the worker */
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen udev_monitor_allow_unicast_sender(worker_monitor, manager->monitor);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = udev_monitor_enable_receiving(worker_monitor);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (r < 0)
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error_errno(r, "worker: could not enable receiving of device: %m");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen pid = fork();
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen switch (pid) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen case 0: {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen struct udev_device *dev = NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen int fd_monitor;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_close_ int fd_signal = -1, fd_ep = -1;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen struct epoll_event ep_signal = { .events = EPOLLIN };
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen struct epoll_event ep_monitor = { .events = EPOLLIN };
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen sigset_t mask;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen /* take initial device from queue */
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen dev = event->dev;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen event->dev = NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen unsetenv("NOTIFY_SOCKET");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen manager_workers_free(manager);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen event_queue_cleanup(manager, EVENT_UNDEF);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen manager->monitor = udev_monitor_unref(manager->monitor);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen manager->ctrl = udev_ctrl_unref(manager->ctrl);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen manager->uevent_event = sd_event_source_unref(manager->uevent_event);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen manager->inotify_event = sd_event_source_unref(manager->inotify_event);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen manager->event = sd_event_unref(manager->event);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen sigfillset(&mask);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (fd_signal < 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = log_error_errno(errno, "error creating signalfd %m");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto out;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen ep_signal.data.fd = fd_signal;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen fd_monitor = udev_monitor_get_fd(worker_monitor);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen ep_monitor.data.fd = fd_monitor;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen fd_ep = epoll_create1(EPOLL_CLOEXEC);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (fd_ep < 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = log_error_errno(errno, "error creating epoll fd: %m");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto out;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = log_error_errno(errno, "fail to add fds to epoll: %m");
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto out;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen /* request TERM signal if parent exits */
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen prctl(PR_SET_PDEATHSIG, SIGTERM);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen /* reset OOM score, we only protect the main daemon */
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen write_string_file("/proc/self/oom_score_adj", "0", 0);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen for (;;) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen struct udev_event *udev_event;
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen int fd_lock = -1;
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen assert(dev);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen log_debug("seq %llu running", udev_device_get_seqnum(dev));
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen udev_event = udev_event_new(dev);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen if (udev_event == NULL) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = -ENOMEM;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen goto out;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if (arg_exec_delay > 0)
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen udev_event->exec_delay = arg_exec_delay;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
1231c4d238844e77018caf5b5852f01d96373c47Tom Gundersen /*
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen * Take a shared lock on the device node; this establishes
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen * a concept of device "ownership" to serialize device
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen * access. External processes holding an exclusive lock will
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen * cause udev to skip the event handling; in the case udev
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen * acquired the lock, the external process can block until
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen * udev has finished its event handling.
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen */
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (!streq_ptr(udev_device_get_action(dev), "remove") &&
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen streq_ptr("block", udev_device_get_subsystem(dev)) &&
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen !startswith(udev_device_get_sysname(dev), "dm-") &&
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen !startswith(udev_device_get_sysname(dev), "md")) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen struct udev_device *d = dev;
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams if (streq_ptr("partition", udev_device_get_devtype(d)))
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen d = udev_device_get_parent(d);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (d) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen fd_lock = open(udev_device_get_devnode(d), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (fd_lock >= 0 && flock(fd_lock, LOCK_SH|LOCK_NB) < 0) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_debug_errno(errno, "Unable to flock(%s), skipping event handling: %m", udev_device_get_devnode(d));
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen fd_lock = safe_close(fd_lock);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen goto skip;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen /* needed for renaming netifs */
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen udev_event->rtnl = rtnl;
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen /* apply rules, create node, symlinks */
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen udev_event_execute_rules(udev_event,
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen arg_event_timeout_usec, arg_event_timeout_warn_usec,
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen &manager->properties,
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen manager->rules);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen udev_event_execute_run(udev_event,
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen arg_event_timeout_usec, arg_event_timeout_warn_usec);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (udev_event->rtnl)
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen /* in case rtnl was initialized */
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen rtnl = sd_netlink_ref(udev_event->rtnl);
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen /* apply/restore inotify watch */
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if (udev_event->inotify_watch) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen udev_watch_begin(udev, dev);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen udev_device_update_db(dev);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen }
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen safe_close(fd_lock);
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen /* send processed event back to libudev listeners */
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen udev_monitor_send_device(worker_monitor, NULL, dev);
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersenskip:
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen log_debug("seq %llu processed", udev_device_get_seqnum(dev));
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen /* send udevd the result of the event execution */
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen r = worker_send_message(manager->worker_watch[WRITE_END]);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (r < 0)
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_error_errno(r, "failed to send result of seq %llu to main daemon: %m",
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen udev_device_get_seqnum(dev));
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen udev_device_unref(dev);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen dev = NULL;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen udev_event_unref(udev_event);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen /* wait for more device messages from main udevd, or term signal */
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen while (dev == NULL) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen struct epoll_event ev[4];
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen int fdcount;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen int i;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (fdcount < 0) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (errno == EINTR)
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen continue;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen r = log_error_errno(errno, "failed to poll: %m");
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen goto out;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen }
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen for (i = 0; i < fdcount; i++) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen dev = udev_monitor_receive_device(worker_monitor);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen break;
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen } else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) {
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen struct signalfd_siginfo fdsi;
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen ssize_t size;
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen if (size != sizeof(struct signalfd_siginfo))
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen continue;
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen switch (fdsi.ssi_signo) {
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen case SIGTERM:
59b8f6b628145586e87b8a4f6e29c755ad7d61edTom Gundersen goto out;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poetteringout:
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering udev_device_unref(dev);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering manager_free(manager);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering log_close();
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering case -1:
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering event->state = EVENT_QUEUED;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering log_error_errno(errno, "fork of child failed: %m");
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering break;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering default:
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering {
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering struct worker *worker;
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering r = worker_new(&worker, manager, worker_monitor, pid);
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering if (r < 0)
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering return;
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering worker_attach_event(worker, event);
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering log_debug("seq %llu forked new worker ["PID_FMT"]", udev_device_get_seqnum(event->dev), pid);
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering break;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen }
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen }
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen}
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersenstatic void event_run(Manager *manager, struct event *event) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen struct worker *worker;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen Iterator i;
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen assert(manager);
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen assert(event);
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen HASHMAP_FOREACH(worker, manager->workers, i) {
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen ssize_t count;
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen if (worker->state != WORKER_IDLE)
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen continue;
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen count = udev_monitor_send_device(manager->monitor, worker->monitor, event->dev);
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen if (count < 0) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen log_error_errno(errno, "worker ["PID_FMT"] did not accept message %zi (%m), kill it",
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen worker->pid, count);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen kill(worker->pid, SIGKILL);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen worker->state = WORKER_KILLED;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen continue;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen }
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen worker_attach_event(worker, event);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen return;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen }
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (hashmap_size(manager->workers) >= arg_children_max) {
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (arg_children_max > 1)
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen log_debug("maximum number (%i) of children reached", hashmap_size(manager->workers));
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen return;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen }
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams
76253e73f9c9c24fec755e485516f3b55d0707b4Dan Williams /* start new worker and pass initial device */
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen worker_spawn(manager, event);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen}
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersenstatic int event_queue_insert(Manager *manager, struct udev_device *dev) {
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen struct event *event;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen int r;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen assert(manager);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen assert(dev);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen /* only one process can add events to the queue */
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (manager->pid == 0)
c15fb62a731f1a457af94e60ac6a4d23f219a8f6Thomas Hindoe Paaboel Andersen manager->pid = getpid();
c15fb62a731f1a457af94e60ac6a4d23f219a8f6Thomas Hindoe Paaboel Andersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen assert(manager->pid == getpid());
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen event = new0(struct event, 1);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (!event)
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering return -ENOMEM;
89ca10c6a61309d84d54c5dc5a295387ce39e610Lennart Poettering
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen event->udev = udev_device_get_udev(dev);
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen event->manager = manager;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen event->dev = dev;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen event->dev_kernel = udev_device_shallow_clone(dev);
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen udev_device_copy_properties(event->dev_kernel, dev);
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen event->seqnum = udev_device_get_seqnum(dev);
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen event->devpath = udev_device_get_devpath(dev);
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen event->devpath_len = strlen(event->devpath);
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen event->devpath_old = udev_device_get_devpath_old(dev);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen event->devnum = udev_device_get_devnum(dev);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen event->is_block = streq("block", udev_device_get_subsystem(dev));
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen event->ifindex = udev_device_get_ifindex(dev);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen log_debug("seq %llu queued, '%s' '%s'", udev_device_get_seqnum(dev),
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen udev_device_get_action(dev), udev_device_get_subsystem(dev));
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen event->state = EVENT_QUEUED;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (udev_list_node_is_empty(&manager->events)) {
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen r = touch("/run/udev/queue");
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (r < 0)
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen log_warning_errno(r, "could not touch /run/udev/queue: %m");
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen }
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen udev_list_node_append(&event->node, &manager->events);
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen return 0;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen}
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersenstatic void manager_kill_workers(Manager *manager) {
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen struct worker *worker;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen Iterator i;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen assert(manager);
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen HASHMAP_FOREACH(worker, manager->workers, i) {
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (worker->state == WORKER_KILLED)
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen continue;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen worker->state = WORKER_KILLED;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen kill(worker->pid, SIGTERM);
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen }
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen}
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen/* lookup event for identical, parent, child device */
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersenstatic bool is_devpath_busy(Manager *manager, struct event *event) {
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen struct udev_list_node *loop;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen size_t common;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* check if queue contains events we depend on */
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen udev_list_node_foreach(loop, &manager->events) {
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen struct event *loop_event = node_to_event(loop);
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* we already found a later event, earlier can not block us, no need to check again */
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (loop_event->seqnum < event->delaying_seqnum)
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering continue;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* event we checked earlier still exists, no need to check again */
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (loop_event->seqnum == event->delaying_seqnum)
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen return true;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
e2acdb6b0f68d9b4152708a9f21bf9e11f8b9e7eTorstein Husebø /* found ourself, no later event can block us */
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if (loop_event->seqnum >= event->seqnum)
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen break;
9a0f246fcdb1238e6b3397169a10095f4df89210Lennart Poettering
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* check major/minor */
9a0f246fcdb1238e6b3397169a10095f4df89210Lennart Poettering if (major(event->devnum) != 0 && event->devnum == loop_event->devnum && event->is_block == loop_event->is_block)
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen return true;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* check network device ifindex */
9a0f246fcdb1238e6b3397169a10095f4df89210Lennart Poettering if (event->ifindex != 0 && event->ifindex == loop_event->ifindex)
9a0f246fcdb1238e6b3397169a10095f4df89210Lennart Poettering return true;
9a0f246fcdb1238e6b3397169a10095f4df89210Lennart Poettering
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* check our old name */
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (event->devpath_old != NULL && streq(loop_event->devpath, event->devpath_old)) {
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen event->delaying_seqnum = loop_event->seqnum;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen return true;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen }
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* compare devpath */
9a0f246fcdb1238e6b3397169a10095f4df89210Lennart Poettering common = MIN(loop_event->devpath_len, event->devpath_len);
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering /* one devpath is contained in the other? */
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering if (memcmp(loop_event->devpath, event->devpath, common) != 0)
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering continue;
c7d9ffe6d629cb5b34dd749e4a88b190b11a0f48Tom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* identical device event found */
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen if (loop_event->devpath_len == event->devpath_len) {
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* devices names might have changed/swapped in the meantime */
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (major(event->devnum) != 0 && (event->devnum != loop_event->devnum || event->is_block != loop_event->is_block))
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen continue;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (event->ifindex != 0 && event->ifindex != loop_event->ifindex)
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen continue;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen event->delaying_seqnum = loop_event->seqnum;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return true;
99634696183dfabae20104e58157c69029a11594Tom Gundersen }
99634696183dfabae20104e58157c69029a11594Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen /* parent device event found */
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (event->devpath[common] == '/') {
99634696183dfabae20104e58157c69029a11594Tom Gundersen event->delaying_seqnum = loop_event->seqnum;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return true;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen }
83cedf7ae28925e37931e7e92d22be9c936a1defTom Gundersen
83cedf7ae28925e37931e7e92d22be9c936a1defTom Gundersen /* child device event found */
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen if (loop_event->devpath[common] == '/') {
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen event->delaying_seqnum = loop_event->seqnum;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen return true;
f693e9b38f13575b988335e3324a50dcc8772d48Tom Gundersen }
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* no matching device */
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen continue;
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen }
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen return false;
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen}
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen
be077570f779664ed87b50f60608df9fbe258821Tom Gundersenstatic int on_exit_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen Manager *manager = userdata;
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen assert(manager);
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen log_error_errno(ETIMEDOUT, "giving up waiting for workers to finish");
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
f693e9b38f13575b988335e3324a50dcc8772d48Tom Gundersen sd_event_exit(manager->event, -ETIMEDOUT);
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen return 1;
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen}
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersenstatic void manager_exit(Manager *manager) {
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen uint64_t usec;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen int r;
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen assert(manager);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen manager->exit = true;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
9a0f246fcdb1238e6b3397169a10095f4df89210Lennart Poettering sd_notify(false,
9a0f246fcdb1238e6b3397169a10095f4df89210Lennart Poettering "STOPPING=1\n"
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen "STATUS=Starting shutdown...");
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen /* close sources of new events and discard buffered events */
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen manager->ctrl = udev_ctrl_unref(manager->ctrl);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen manager->inotify_event = sd_event_source_unref(manager->inotify_event);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen manager->fd_inotify = safe_close(manager->fd_inotify);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen manager->uevent_event = sd_event_source_unref(manager->uevent_event);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen manager->monitor = udev_monitor_unref(manager->monitor);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen /* discard queued events and kill workers */
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen event_queue_cleanup(manager, EVENT_QUEUED);
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen manager_kill_workers(manager);
0cb3c286883b694fc52a18a3b559ff98931641f3Tom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen assert_se(sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec) >= 0);
83cedf7ae28925e37931e7e92d22be9c936a1defTom Gundersen
83cedf7ae28925e37931e7e92d22be9c936a1defTom Gundersen r = sd_event_add_time(manager->event, NULL, clock_boottime_or_monotonic(),
83cedf7ae28925e37931e7e92d22be9c936a1defTom Gundersen usec + 30 * USEC_PER_SEC, USEC_PER_SEC, on_exit_timeout, manager);
83cedf7ae28925e37931e7e92d22be9c936a1defTom Gundersen if (r < 0)
83cedf7ae28925e37931e7e92d22be9c936a1defTom Gundersen return;
0cb3c286883b694fc52a18a3b559ff98931641f3Tom Gundersen}
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen
933f9caeeb2b3c1b951d330e04beb04226e5a890Daniel Mack/* reload requested, HUP signal received, rules changed, builtin changed */
0cb3c286883b694fc52a18a3b559ff98931641f3Tom Gundersenstatic void manager_reload(Manager *manager) {
83cedf7ae28925e37931e7e92d22be9c936a1defTom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen assert(manager);
83cedf7ae28925e37931e7e92d22be9c936a1defTom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen sd_notify(false,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen "RELOADING=1\n"
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen "STATUS=Flushing configuration...");
83cedf7ae28925e37931e7e92d22be9c936a1defTom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen manager_kill_workers(manager);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen manager->rules = udev_rules_unref(manager->rules);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen udev_builtin_exit(manager->udev);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen sd_notify(false,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen "READY=1\n"
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen "STATUS=Processing...");
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen}
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersenstatic void event_queue_start(Manager *manager) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen struct udev_list_node *loop;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen usec_t usec;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen assert(manager);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (udev_list_node_is_empty(&manager->events) ||
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen manager->exit || manager->stop_exec_queue)
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen return;
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen assert_se(sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec) >= 0);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen /* check for changed config, every 3 seconds at most */
5b34277c2015e32e51d10cfa076df2c7106b4537Tom Gundersen if (manager->last_usec == 0 ||
f693e9b38f13575b988335e3324a50dcc8772d48Tom Gundersen (usec - manager->last_usec) > 3 * USEC_PER_SEC) {
5b34277c2015e32e51d10cfa076df2c7106b4537Tom Gundersen if (udev_rules_check_timestamp(manager->rules) ||
5b34277c2015e32e51d10cfa076df2c7106b4537Tom Gundersen udev_builtin_validate(manager->udev))
5b34277c2015e32e51d10cfa076df2c7106b4537Tom Gundersen manager_reload(manager);
5b34277c2015e32e51d10cfa076df2c7106b4537Tom Gundersen
5b34277c2015e32e51d10cfa076df2c7106b4537Tom Gundersen manager->last_usec = usec;
9a0f246fcdb1238e6b3397169a10095f4df89210Lennart Poettering }
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen udev_builtin_init(manager->udev);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (!manager->rules) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen manager->rules = udev_rules_new(manager->udev, arg_resolve_names);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (!manager->rules)
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen return;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen }
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen udev_list_node_foreach(loop, &manager->events) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen struct event *event = node_to_event(loop);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (event->state != EVENT_QUEUED)
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen continue;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen /* do not start event if parent or child event is still running */
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (is_devpath_busy(manager, event))
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen continue;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen event_run(manager, event);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen }
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen}
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersenstatic void event_queue_cleanup(Manager *manager, enum event_state match_type) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen struct udev_list_node *loop, *tmp;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen udev_list_node_foreach_safe(loop, tmp, &manager->events) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen struct event *event = node_to_event(loop);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (match_type != EVENT_UNDEF && match_type != event->state)
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen continue;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen event_free(event);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen }
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen}
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersenstatic int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen Manager *manager = userdata;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen assert(manager);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen for (;;) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen struct worker_message msg;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen struct iovec iovec = {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen .iov_base = &msg,
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen .iov_len = sizeof(msg),
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen };
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen union {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen struct cmsghdr cmsghdr;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen } control = {};
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen struct msghdr msghdr = {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen .msg_iov = &iovec,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen .msg_iovlen = 1,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen .msg_control = &control,
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen .msg_controllen = sizeof(control),
a7f7d1bde43fc825c49afea3f946f5b4b3d563e0Harald Hoyer };
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen struct cmsghdr *cmsg;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen ssize_t size;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen struct ucred *ucred = NULL;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen struct worker *worker;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen size = recvmsg(fd, &msghdr, MSG_DONTWAIT);
02557f973aed0fed7154fefe53d67e2935f918dcThomas Hindoe Paaboel Andersen if (size < 0) {
02557f973aed0fed7154fefe53d67e2935f918dcThomas Hindoe Paaboel Andersen if (errno == EINTR)
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen continue;
02557f973aed0fed7154fefe53d67e2935f918dcThomas Hindoe Paaboel Andersen else if (errno == EAGAIN)
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen /* nothing more to read */
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen break;
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen return log_error_errno(errno, "failed to receive message: %m");
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen } else if (size != sizeof(struct worker_message)) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_warning_errno(EIO, "ignoring worker message with invalid size %zi bytes", size);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen continue;
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen }
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen CMSG_FOREACH(cmsg, &msghdr) {
bff92d2c2f913c368d80066ee89855665818edc8Susant Sahani if (cmsg->cmsg_level == SOL_SOCKET &&
bff92d2c2f913c368d80066ee89855665818edc8Susant Sahani cmsg->cmsg_type == SCM_CREDENTIALS &&
bff92d2c2f913c368d80066ee89855665818edc8Susant Sahani cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
38a03f06a7393d2721c23f23f0589d2f6d0904afLennart Poettering ucred = (struct ucred*) CMSG_DATA(cmsg);
bff92d2c2f913c368d80066ee89855665818edc8Susant Sahani }
bff92d2c2f913c368d80066ee89855665818edc8Susant Sahani
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (!ucred || ucred->pid <= 0) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_warning_errno(EIO, "ignoring worker message without valid PID");
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen continue;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen }
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen /* lookup worker who sent the signal */
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen worker = hashmap_get(manager->workers, UINT_TO_PTR(ucred->pid));
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen if (!worker) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen log_debug("worker ["PID_FMT"] returned, but is no longer tracked", ucred->pid);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen continue;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen }
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (worker->state != WORKER_KILLED)
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen worker->state = WORKER_IDLE;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen /* worker returned */
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen event_free(worker->event);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen }
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen /* we have free workers, try to schedule events */
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen event_queue_start(manager);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen return 1;
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen}
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersenstatic int on_uevent(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen Manager *manager = userdata;
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen struct udev_device *dev;
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen int r;
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen assert(manager);
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen dev = udev_monitor_receive_device(manager->monitor);
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen if (dev) {
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen udev_device_ensure_usec_initialized(dev, NULL);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen r = event_queue_insert(manager, dev);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (r < 0)
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen udev_device_unref(dev);
9a0f246fcdb1238e6b3397169a10095f4df89210Lennart Poettering else
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen /* we have fresh events, try to schedule them */
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen event_queue_start(manager);
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen }
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen return 1;
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen}
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen/* receive the udevd message from userspace */
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersenstatic int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen Manager *manager = userdata;
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen _cleanup_udev_ctrl_connection_unref_ struct udev_ctrl_connection *ctrl_conn = NULL;
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen _cleanup_udev_ctrl_msg_unref_ struct udev_ctrl_msg *ctrl_msg = NULL;
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen const char *str;
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen int i;
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen assert(manager);
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen ctrl_conn = udev_ctrl_get_connection(manager->ctrl);
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen if (!ctrl_conn)
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen return 1;
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen ctrl_msg = udev_ctrl_receive_msg(ctrl_conn);
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen if (!ctrl_msg)
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen return 1;
500792d8180c9a11d65f107cdc79dea21b2964c4Tom Gundersen
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen i = udev_ctrl_get_set_log_level(ctrl_msg);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen if (i >= 0) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_debug("udevd message (SET_LOG_LEVEL) received, log_priority=%i", i);
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen log_set_max_level(i);
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen manager_kill_workers(manager);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen }
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen log_debug("udevd message (STOP_EXEC_QUEUE) received");
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen manager->stop_exec_queue = true;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen }
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen log_debug("udevd message (START_EXEC_QUEUE) received");
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen manager->stop_exec_queue = false;
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen event_queue_start(manager);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen }
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen
966d74c043098e12d4d5b101aa7650244c14b815Lennart Poettering if (udev_ctrl_get_reload(ctrl_msg) > 0) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen log_debug("udevd message (RELOAD) received");
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen manager_reload(manager);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen }
966d74c043098e12d4d5b101aa7650244c14b815Lennart Poettering
966d74c043098e12d4d5b101aa7650244c14b815Lennart Poettering str = udev_ctrl_get_set_env(ctrl_msg);
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen if (str != NULL) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen _cleanup_free_ char *key = NULL;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen key = strdup(str);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (key) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen char *val;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen val = strchr(key, '=');
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (val != NULL) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen val[0] = '\0';
a38d99451f2bf8026ec51aee91662292e823c6a8Lennart Poettering val = &val[1];
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen if (val[0] == '\0') {
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen log_debug("udevd message (ENV) received, unset '%s'", key);
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen udev_list_entry_add(&manager->properties, key, NULL);
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen } else {
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen log_debug("udevd message (ENV) received, set '%s=%s'", key, val);
0d43d2fcb7ac5264c739dc2f67f93ed0985a418aTom Gundersen udev_list_entry_add(&manager->properties, key, val);
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen }
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen } else
2a1288ff89322a2f49c79f6d1832c8164c14a05cLennart Poettering log_error("wrong key format '%s'", key);
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen }
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen manager_kill_workers(manager);
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen }
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen i = udev_ctrl_get_set_children_max(ctrl_msg);
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen if (i >= 0) {
a6f1e036de8f212f33ead7f5387c297afd8be26eTom Gundersen log_debug("udevd message (SET_MAX_CHILDREN) received, children_max=%i", i);
b3ec603ce8053ba3f95da1d36f15ea762c83d1e1Lennart Poettering arg_children_max = i;
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen }
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen if (udev_ctrl_get_ping(ctrl_msg) > 0)
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen log_debug("udevd message (SYNC) received");
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen if (udev_ctrl_get_exit(ctrl_msg) > 0) {
be077570f779664ed87b50f60608df9fbe258821Tom Gundersen log_debug("udevd message (EXIT) received");
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen manager_exit(manager);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen /* keep reference to block the client until we exit
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen TODO: deal with several blocking exit requests */
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen manager->ctrl_conn_blocking = udev_ctrl_connection_ref(ctrl_conn);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen }
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen return 1;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen}
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersenstatic int synthesize_change(struct udev_device *dev) {
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen char filename[UTIL_PATH_SIZE];
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen int r;
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen if (streq_ptr("block", udev_device_get_subsystem(dev)) &&
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen streq_ptr("disk", udev_device_get_devtype(dev)) &&
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen !startswith(udev_device_get_sysname(dev), "dm-")) {
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen bool part_table_read = false;
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen bool has_partitions = false;
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen int fd;
8de4a226c71ef43e652274b33b5d19211a44ac7bTom Gundersen struct udev *udev = udev_device_get_udev(dev);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen struct udev_list_entry *item;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen /*
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen * Try to re-read the partition table. This only succeeds if
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen * none of the devices is busy. The kernel returns 0 if no
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen * partition table is found, and we will not get an event for
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen * the disk.
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen */
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen fd = open(udev_device_get_devnode(dev), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (fd >= 0) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen r = flock(fd, LOCK_EX|LOCK_NB);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (r >= 0)
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen r = ioctl(fd, BLKRRPART, 0);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen close(fd);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (r >= 0)
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen part_table_read = true;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen }
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen /* search for partitions */
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen e = udev_enumerate_new(udev);
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen if (!e)
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen return -ENOMEM;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen r = udev_enumerate_add_match_parent(e, dev);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (r < 0)
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen return r;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
621ac3d2cc8f37169166df9c7f379b0cb6b17e36Thomas Hindoe Paaboel Andersen r = udev_enumerate_add_match_subsystem(e, "block");
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (r < 0)
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen return r;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen r = udev_enumerate_scan_devices(e);
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (r < 0)
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen return r;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
99634696183dfabae20104e58157c69029a11594Tom Gundersen udev_list_entry_foreach(item, udev_enumerate_get_list_entry(e)) {
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen _cleanup_udev_device_unref_ struct udev_device *d = NULL;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (!d)
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen continue;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen if (!streq_ptr("partition", udev_device_get_devtype(d)))
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen continue;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen has_partitions = true;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen break;
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen }
527503444ef24ae03c73cf85128c7acbb1146f3cTom Gundersen
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering /*
64d6c22905e94b02e760747c6c143dc9893083d9Thomas Hindoe Paaboel Andersen * We have partitions and re-read the table, the kernel already sent
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering * out a "change" event for the disk, and "remove/add" for all
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering * partitions.
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering */
64d6c22905e94b02e760747c6c143dc9893083d9Thomas Hindoe Paaboel Andersen if (part_table_read && has_partitions)
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering return 0;
64d6c22905e94b02e760747c6c143dc9893083d9Thomas Hindoe Paaboel Andersen
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering /*
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering * We have partitions but re-reading the partition table did not
64d6c22905e94b02e760747c6c143dc9893083d9Thomas Hindoe Paaboel Andersen * work, synthesize "change" for the disk and all partitions.
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering */
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev));
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering write_string_file(filename, "change", WRITE_STRING_FILE_CREATE);
8eb9058dc1f99a5eb9b8726a978fcc0720837a10Lennart Poettering
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering udev_list_entry_foreach(item, udev_enumerate_get_list_entry(e)) {
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering _cleanup_udev_device_unref_ struct udev_device *d = NULL;
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering if (!d)
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering continue;
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering if (!streq_ptr("partition", udev_device_get_devtype(d)))
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering continue;
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering log_debug("device %s closed, synthesising partition '%s' 'change'",
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering udev_device_get_devnode(dev), udev_device_get_devnode(d));
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering strscpyl(filename, sizeof(filename), udev_device_get_syspath(d), "/uevent", NULL);
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering write_string_file(filename, "change", WRITE_STRING_FILE_CREATE);
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering }
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering return 0;
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering }
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering
586ac6f711e2eccceb12421df22fca4f117226c4Lennart Poettering log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev));
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering write_string_file(filename, "change", WRITE_STRING_FILE_CREATE);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering return 0;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering}
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poetteringstatic int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering Manager *manager = userdata;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering union inotify_event_buffer buffer;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering struct inotify_event *e;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering ssize_t l;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering assert(manager);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering l = read(fd, &buffer, sizeof(buffer));
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering if (l < 0) {
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering if (errno == EAGAIN || errno == EINTR)
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering return 1;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering return log_error_errno(errno, "Failed to read inotify fd: %m");
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering FOREACH_INOTIFY_EVENT(e, buffer, l) {
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering dev = udev_watch_lookup(manager->udev, e->wd);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering if (!dev)
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering continue;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering log_debug("inotify event: %x for %s", e->mask, udev_device_get_devnode(dev));
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering if (e->mask & IN_CLOSE_WRITE) {
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering synthesize_change(dev);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering /* settle might be waiting on us to determine the queue
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering * state. If we just handled an inotify event, we might have
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering * generated a "change" event, but we won't have queued up
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering * the resultant uevent yet. Do that.
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering */
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering on_uevent(NULL, -1, 0, manager);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering } else if (e->mask & IN_IGNORED)
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering udev_watch_end(manager->udev, dev);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering }
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering return 1;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering}
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poetteringstatic int on_sigterm(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering Manager *manager = userdata;
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering assert(manager);
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering
1a04db0fc9d08fffe80d6d7b5b60459295922b11Lennart Poettering manager_exit(manager);
return 1;
}
static int on_sighup(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
Manager *manager = userdata;
assert(manager);
manager_reload(manager);
return 1;
}
static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
Manager *manager = userdata;
assert(manager);
for (;;) {
pid_t pid;
int status;
struct worker *worker;
pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0)
break;
worker = hashmap_get(manager->workers, UINT_TO_PTR(pid));
if (!worker) {
log_warning("worker ["PID_FMT"] is unknown, ignoring", pid);
continue;
}
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) == 0)
log_debug("worker ["PID_FMT"] exited", pid);
else
log_warning("worker ["PID_FMT"] exited with return code %i", pid, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
log_warning("worker ["PID_FMT"] terminated by signal %i (%s)", pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
} else if (WIFSTOPPED(status)) {
log_info("worker ["PID_FMT"] stopped", pid);
continue;
} else if (WIFCONTINUED(status)) {
log_info("worker ["PID_FMT"] continued", pid);
continue;
} else
log_warning("worker ["PID_FMT"] exit with status 0x%04x", pid, status);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
if (worker->event) {
log_error("worker ["PID_FMT"] failed while handling '%s'", pid, worker->event->devpath);
/* delete state from disk */
udev_device_delete_db(worker->event->dev);
udev_device_tag_index(worker->event->dev, NULL, false);
/* forward kernel event without amending it */
udev_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel);
}
}
worker_free(worker);
}
/* we can start new workers, try to schedule events */
event_queue_start(manager);
return 1;
}
static int on_post(sd_event_source *s, void *userdata) {
Manager *manager = userdata;
int r;
assert(manager);
if (udev_list_node_is_empty(&manager->events)) {
/* no pending events */
if (!hashmap_isempty(manager->workers)) {
/* there are idle workers */
log_debug("cleanup idle workers");
manager_kill_workers(manager);
} else {
/* we are idle */
if (manager->exit) {
r = sd_event_exit(manager->event, 0);
if (r < 0)
return r;
} else if (manager->cgroup)
/* cleanup possible left-over processes in our cgroup */
cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, false, true, NULL);
}
}
return 1;
}
static int listen_fds(int *rctrl, int *rnetlink) {
_cleanup_udev_unref_ struct udev *udev = NULL;
int ctrl_fd = -1, netlink_fd = -1;
int fd, n, r;
assert(rctrl);
assert(rnetlink);
n = sd_listen_fds(true);
if (n < 0)
return n;
for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) {
if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) {
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) {
const char *full_key = key;
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);
if (prio < 0)
goto invalid;
log_set_max_level(prio);
} else if (streq(key, "children-max")) {
r = safe_atou(value, &arg_children_max);
if (r < 0)
goto invalid;
} else if (streq(key, "exec-delay")) {
r = safe_atoi(value, &arg_exec_delay);
if (r < 0)
goto invalid;
} else if (streq(key, "event-timeout")) {
r = safe_atou64(value, &arg_event_timeout_usec);
if (r < 0)
goto invalid;
arg_event_timeout_usec *= USEC_PER_SEC;
arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
}
return 0;
invalid:
log_warning("invalid %s ignored: %s", full_key, value);
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:Dt:N: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;
}
static int run(int fd_ctrl, int fd_uevent, const char *cgroup) {
_cleanup_(manager_freep) Manager *manager = NULL;
int r;
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);
return r;
}
int main(int argc, char *argv[]) {
_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 || r == -ENOEXEC)
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", 0);
}
r = run(fd_ctrl, fd_uevent, cgroup);
exit:
mac_selinux_finish();
log_close();
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}