udevd.c revision 9ea28c55a2488e6cd4a44ac5786f12b71ad5bc9f
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * Copyright (C) 2004-2012 Kay Sievers <kay@vrfy.org>
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * Copyright (C) 2009 Canonical Ltd.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * This program is free software: you can redistribute it and/or modify
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * it under the terms of the GNU General Public License as published by
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * the Free Software Foundation, either version 2 of the License, or
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * (at your option) any later version.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * This program is distributed in the hope that it will be useful,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * but WITHOUT ANY WARRANTY; without even the implied warranty of
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * GNU General Public License for more details.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * You should have received a copy of the GNU General Public License
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * along with this program. If not, see <http://www.gnu.org/licenses/>.
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannvoid udev_main_log(struct udev *udev, int priority,
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_metav(priority, file, line, fn, format, args);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann unsigned long long int delaying_seqnum;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann unsigned long long int seqnum;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic inline struct event *node_to_event(struct udev_list_node *node)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return container_of(node, struct event, node);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic void event_queue_cleanup(struct udev *udev, enum event_state type);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann/* passed from worker to main process */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic inline struct worker *node_to_worker(struct udev_list_node *node)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return container_of(node, struct worker, node);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic void event_queue_delete(struct event *event)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic struct worker *worker_ref(struct worker *worker)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic void worker_cleanup(struct worker *worker)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic void worker_unref(struct worker *worker)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("worker [%u] cleaned up", worker->pid);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic void worker_list_cleanup(struct udev *udev)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann udev_list_node_foreach_safe(loop, tmp, &worker_list) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct worker *worker = node_to_worker(loop);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* listen for new events */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann worker_monitor = udev_monitor_new_from_netlink(udev, NULL);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* allow the main daemon netlink address to send devices to the worker */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann udev_monitor_allow_unicast_sender(worker_monitor, monitor);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann udev_monitor_enable_receiving(worker_monitor);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* worker + event reference */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* take initial device from queue */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann memzero(&ep_signal, sizeof(struct epoll_event));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann fd_monitor = udev_monitor_get_fd(worker_monitor);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann memzero(&ep_monitor, sizeof(struct epoll_event));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* request TERM signal if parent exits */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* reset OOM score, we only protect the main daemon */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann write_string_file("/proc/self/oom_score_adj", "0");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("seq %llu running", udev_device_get_seqnum(dev));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* needed for SIGCHLD/SIGTERM in spawn() */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* apply rules, create node, symlinks */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann err = udev_event_execute_rules(udev_event, rules, &sigmask_orig);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann udev_event_execute_run(udev_event, &sigmask_orig);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* apply/restore inotify watch */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* send processed event back to libudev listeners */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann udev_monitor_send_device(worker_monitor, NULL, dev);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* send udevd the result of the event execution */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann memzero(&msg, sizeof(struct worker_message));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("seq %llu processed with %i", udev_device_get_seqnum(dev), err);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* wait for more device messages from main udevd, or term signal */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (i = 0; i < fdcount; i++) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann dev = udev_monitor_receive_device(worker_monitor);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann } else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* close monitor, but keep address around */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann worker->event_start_usec = now(CLOCK_MONOTONIC);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann udev_list_node_append(&worker->node, &worker_list);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("seq %llu forked new worker [%u]", udev_device_get_seqnum(event->dev), pid);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct worker *worker = node_to_worker(loop);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann count = udev_monitor_send_device(monitor, worker->monitor, event->dev);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("worker [%u] did not accept message %zi (%m), kill it", worker->pid, count);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann worker->event_start_usec = now(CLOCK_MONOTONIC);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("maximum number (%i) of children reached", children);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* start new worker and pass initial device */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int event_queue_insert(struct udev_device *dev)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann event->devpath = udev_device_get_devpath(dev);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann event->devpath_old = udev_device_get_devpath_old(dev);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann event->is_block = streq("block", udev_device_get_subsystem(dev));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann event->ifindex = udev_device_get_ifindex(dev);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (streq(udev_device_get_subsystem(dev), "firmware"))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("seq %llu queued, '%s' '%s'", udev_device_get_seqnum(dev),
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann udev_device_get_action(dev), udev_device_get_subsystem(dev));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann udev_list_node_append(&event->node, &event_list);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct worker *worker = node_to_worker(loop);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann/* lookup event for identical, parent, child device */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic bool is_devpath_busy(struct event *event)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* check if queue contains events we depend on */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct event *loop_event = node_to_event(loop);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* we already found a later event, earlier can not block us, no need to check again */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (loop_event->seqnum < event->delaying_seqnum)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* event we checked earlier still exists, no need to check again */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (loop_event->seqnum == event->delaying_seqnum)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* found ourself, no later event can block us */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (major(event->devnum) != 0 && event->devnum == loop_event->devnum && event->is_block == loop_event->is_block)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* check network device ifindex */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (event->ifindex != 0 && event->ifindex == loop_event->ifindex)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* check our old name */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (event->devpath_old != NULL && streq(loop_event->devpath, event->devpath_old)) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* compare devpath */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann common = MIN(loop_event->devpath_len, event->devpath_len);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* one devpath is contained in the other? */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (memcmp(loop_event->devpath, event->devpath, common) != 0)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* identical device event found */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (loop_event->devpath_len == event->devpath_len) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* devices names might have changed/swapped in the meantime */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (major(event->devnum) != 0 && (event->devnum != loop_event->devnum || event->is_block != loop_event->is_block))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (event->ifindex != 0 && event->ifindex != loop_event->ifindex)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* allow to bypass the dependency tracking */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* parent device event found */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* child device event found */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* no matching device */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return false;
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic void event_queue_start(struct udev *udev)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* do not start event if parent or child event is still running */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic void event_queue_cleanup(struct udev *udev, enum event_state match_type)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann udev_list_node_foreach_safe(loop, tmp, &event_list) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (match_type != EVENT_UNDEF && match_type != event->state)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann size = recv(fd_worker, &msg, sizeof(struct worker_message), MSG_DONTWAIT);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* lookup worker who sent the signal */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct worker *worker = node_to_worker(loop);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* worker returned */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann/* receive the udevd message from userspace */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct udev *udev = udev_ctrl_get_udev(uctrl);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (i >= 0) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("udevd message (SET_LOG_LEVEL) received, log_priority=%i", i);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("udevd message (STOP_EXEC_QUEUE) received");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("udevd message (START_EXEC_QUEUE) received");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("udevd message (RELOAD) received");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("udevd message (ENV) received, unset '%s'", key);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("udevd message (ENV) received, set '%s=%s'", key, val);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann i = udev_ctrl_get_set_children_max(ctrl_msg);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (i >= 0) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("udevd message (SET_MAX_CHILDREN) received, children_max=%i", i);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* keep reference to block the client until we exit */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann return udev_ctrl_connection_unref(ctrl_conn);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann/* read inotify messages */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if ((ioctl(fd_inotify, FIONREAD, &nbytes) < 0) || (nbytes <= 0))
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("error getting buffer for inotify");
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (pos = 0; pos < nbytes; pos += sizeof(struct inotify_event) + ev->len) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("inotify event: %x for %s", ev->mask, udev_device_get_devnode(dev));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic void handle_signal(struct udev *udev, int signo)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann udev_list_node_foreach_safe(loop, tmp, &worker_list) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann struct worker *worker = node_to_worker(loop);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("worker [%u] exit with return code %i",
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("worker [%u] terminated by signal %i (%s)",
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("worker [%u] exit with status 0x%04x", pid, status);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_error("worker [%u] failed while handling '%s'",
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann /* drop reference taken for state 'running' */
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink)
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1)) {
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann log_debug("ctrl=%i netlink=%i", ctrl, netlink);
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * read the kernel commandline, in case we need to get into debug mode
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * udev.log-priority=<level> syslog priority
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * udev.children-max=<number of workers> events are fully serialized if set to 1
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmann * udev.exec-delay=<number of seconds> delay execution of every executed program
c0395aeb903cde25bd9e81fba3334f63335fe0efDavid Herrmannstatic void kernel_cmdline_options(struct udev *udev)
char *s, *opt;
s = strndup(w, l);
opt = s;
int prio;
free(s);
int daemonize = false;
goto exit;
log_open();
int option;
switch (option) {
daemonize = true;
debug = true;
resolve_names = 0;
goto exit;
goto exit;
goto exit;
goto exit;
if (getuid() != 0) {
goto exit;
if (daemonize) {
int fd;
if (fd >= 0) {
goto exit;
goto exit;
goto exit;
goto exit;
goto exit;
goto exit;
if (daemonize) {
switch (pid) {
goto exit;
goto exit_daemonize;
setsid();
if (!debug) {
int fd;
if (fd >= 0) {
if (fd_inotify < 0) {
goto exit;
if (fd_signal < 0) {
goto exit;
goto exit;
goto exit;
if (fd_ep < 0) {
goto exit;
goto exit;
if (children_max <= 0) {
if (rc < 0)
int fdcount;
int timeout;
if (udev_exit) {
if (fd_ctrl >= 0) {
if (fd_inotify >= 0) {
if (udev_cgroup)
int fd;
if (fd >= 0)
if (fdcount < 0)
if (fdcount == 0) {
if (udev_exit) {
log_error("seq %llu '%s' killed", udev_device_get_seqnum(worker->event->dev), worker->event->devpath);
for (i = 0; i < fdcount; i++) {
is_worker = true;
is_netlink = true;
is_signal = true;
is_inotify = true;
is_ctrl = true;
reload = true;
reload = true;
if (reload) {
reload = false;
if (is_worker)
if (is_netlink) {
if (is_signal) {
if (udev_exit)
if (is_inotify)
if (is_ctrl)
exit:
if (fd_ep >= 0)
if (fd_signal >= 0)
label_finish();
log_close();
return rc;