udevadm: control - add --exit

This commit is contained in:
Kay Sievers 2011-04-13 01:17:09 +02:00
parent 9602509521
commit ff2c503df0
8 changed files with 534 additions and 264 deletions

4
TODO
View file

@ -1,4 +1,6 @@
- bind control socket in systemd
- use inotify() in settle
- do not write age/configured in initramfs
- remove deprecated trigger --type=failed logic

View file

@ -3,4 +3,4 @@ Description=udev Kernel Device Manager Socket
DefaultDependencies=no
[Socket]
ListenDatagram=@/org/kernel/udev/udevd
ListenSequentialPacket=@/org/kernel/udev/udevd

View file

@ -16,6 +16,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/un.h>
@ -33,7 +34,8 @@ enum udev_ctrl_msg_type {
UDEV_CTRL_RELOAD_RULES,
UDEV_CTRL_SET_ENV,
UDEV_CTRL_SET_CHILDREN_MAX,
UDEV_CTRL_SETTLE,
UDEV_CTRL_PING,
UDEV_CTRL_EXIT,
};
struct udev_ctrl_msg_wire {
@ -48,9 +50,8 @@ struct udev_ctrl_msg_wire {
struct udev_ctrl_msg {
int refcount;
struct udev_ctrl *uctrl;
struct udev_ctrl_connection *conn;
struct udev_ctrl_msg_wire ctrl_msg_wire;
pid_t pid;
};
struct udev_ctrl {
@ -59,6 +60,13 @@ struct udev_ctrl {
int sock;
struct sockaddr_un saddr;
socklen_t addrlen;
bool connected;
};
struct udev_ctrl_connection {
int refcount;
struct udev_ctrl *uctrl;
int sock;
};
static struct udev_ctrl *udev_ctrl_new(struct udev *udev)
@ -81,7 +89,7 @@ struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socke
if (uctrl == NULL)
return NULL;
uctrl->sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
if (uctrl->sock < 0) {
err(udev, "error getting socket: %m\n");
udev_ctrl_unref(uctrl);
@ -112,18 +120,21 @@ struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd)
int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl)
{
int err;
const int on = 1;
if (uctrl->addrlen > 0) {
err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
if (err < 0) {
err = -errno;
err(uctrl->udev, "bind failed: %m\n");
return err;
}
err = listen(uctrl->sock, 0);
if (err < 0) {
err = -errno;
err(uctrl->udev, "listen failed: %m\n");
return err;
}
}
/* enable receiving of the sender credentials */
setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
return 0;
}
@ -140,16 +151,17 @@ struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl)
return uctrl;
}
void udev_ctrl_unref(struct udev_ctrl *uctrl)
struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl)
{
if (uctrl == NULL)
return;
return NULL;
uctrl->refcount--;
if (uctrl->refcount > 0)
return;
return uctrl;
if (uctrl->sock >= 0)
close(uctrl->sock);
free(uctrl);
return NULL;
}
int udev_ctrl_get_fd(struct udev_ctrl *uctrl)
@ -159,10 +171,55 @@ int udev_ctrl_get_fd(struct udev_ctrl *uctrl)
return uctrl->sock;
}
static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf)
struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl)
{
struct udev_ctrl_connection *conn;
const int on = 1;
conn = calloc(1, sizeof(struct udev_ctrl_connection));
if (conn == NULL)
return NULL;
conn->refcount = 1;
conn->uctrl = uctrl;
conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC);
if (conn->sock < 0) {
free(conn);
return NULL;
}
/* enable receiving of the sender credentials */
setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
udev_ctrl_ref(uctrl);
return conn;
}
struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn)
{
if (conn == NULL)
return NULL;
conn->refcount++;
return conn;
}
struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn)
{
if (conn == NULL)
return NULL;
conn->refcount--;
if (conn->refcount > 0)
return conn;
if (conn->sock >= 0)
close(conn->sock);
udev_ctrl_unref(conn->uctrl);
free(conn);
return NULL;
}
static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout)
{
struct udev_ctrl_msg_wire ctrl_msg_wire;
int err;
int err = 0;
memset(&ctrl_msg_wire, 0x00, sizeof(struct udev_ctrl_msg_wire));
strcpy(ctrl_msg_wire.version, "udev-" VERSION);
@ -174,51 +231,89 @@ static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int
else
ctrl_msg_wire.intval = intval;
err = sendto(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0,
(struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
if (err == -1) {
err(uctrl->udev, "error sending message: %m\n");
if (!uctrl->connected) {
if (connect(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen) < 0) {
err = -errno;
goto out;
}
uctrl->connected = true;
}
if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) {
err = -errno;
goto out;
}
/* wait for peer message handling or disconnect */
for (;;) {
struct pollfd pfd[1];
int r;
pfd[0].fd = uctrl->sock;
pfd[0].events = POLLIN;
r = poll(pfd, 1, timeout * 1000);
if (r < 0) {
if (errno == EINTR)
continue;
err = -errno;
break;
}
if (r > 0 && pfd[0].revents & POLLERR) {
err = -EIO;
break;
}
if (r == 0)
err = -ETIMEDOUT;
break;
}
out:
return err;
}
int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority)
int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout)
{
return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL);
return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout);
}
int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl)
int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout)
{
return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL);
return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout);
}
int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl)
int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout)
{
return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL);
return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout);
}
int udev_ctrl_send_reload_rules(struct udev_ctrl *uctrl)
int udev_ctrl_send_reload_rules(struct udev_ctrl *uctrl, int timeout)
{
return ctrl_send(uctrl, UDEV_CTRL_RELOAD_RULES, 0, NULL);
return ctrl_send(uctrl, UDEV_CTRL_RELOAD_RULES, 0, NULL, timeout);
}
int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key)
int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout)
{
return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key);
return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout);
}
int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count)
int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout)
{
return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL);
return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout);
}
int udev_ctrl_send_settle(struct udev_ctrl *uctrl)
int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout)
{
return ctrl_send(uctrl, UDEV_CTRL_SETTLE, 0, NULL);
return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
}
struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl *uctrl)
int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout)
{
return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
}
struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn)
{
struct udev *udev = conn->uctrl->udev;
struct udev_ctrl_msg *uctrl_msg;
ssize_t size;
struct msghdr smsg;
@ -231,7 +326,7 @@ struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl *uctrl)
if (uctrl_msg == NULL)
return NULL;
uctrl_msg->refcount = 1;
uctrl_msg->uctrl = uctrl;
uctrl_msg->conn = conn;
iov.iov_base = &uctrl_msg->ctrl_msg_wire;
iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
@ -242,32 +337,31 @@ struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl *uctrl)
smsg.msg_control = cred_msg;
smsg.msg_controllen = sizeof(cred_msg);
size = recvmsg(uctrl->sock, &smsg, 0);
size = recvmsg(conn->sock, &smsg, 0);
if (size < 0) {
err(uctrl->udev, "unable to receive user udevd message: %m\n");
err(udev, "unable to receive user udevd message: %m\n");
goto err;
}
cmsg = CMSG_FIRSTHDR(&smsg);
cred = (struct ucred *) CMSG_DATA(cmsg);
if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
err(uctrl->udev, "no sender credentials received, message ignored\n");
err(udev, "no sender credentials received, message ignored\n");
goto err;
}
if (cred->uid != 0) {
err(uctrl->udev, "sender uid=%i, message ignored\n", cred->uid);
err(udev, "sender uid=%i, message ignored\n", cred->uid);
goto err;
}
uctrl_msg->pid = cred->pid;
if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
err(uctrl->udev, "message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
err(udev, "message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
goto err;
}
dbg(uctrl->udev, "created ctrl_msg %p (%i)\n", uctrl_msg, uctrl_msg->ctrl_msg_wire.type);
dbg(udev, "created ctrl_msg %p (%i)\n", uctrl_msg, uctrl_msg->ctrl_msg_wire.type);
udev_ctrl_connection_ref(conn);
return uctrl_msg;
err:
udev_ctrl_msg_unref(uctrl_msg);
@ -282,15 +376,17 @@ struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg)
return ctrl_msg;
}
void udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg)
struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg)
{
if (ctrl_msg == NULL)
return;
return NULL;
ctrl_msg->refcount--;
if (ctrl_msg->refcount > 0)
return;
dbg(ctrl_msg->uctrl->udev, "release ctrl_msg %p\n", ctrl_msg);
return ctrl_msg;
dbg(ctrl_msg->conn->uctrl->udev, "release ctrl_msg %p\n", ctrl_msg);
udev_ctrl_connection_unref(ctrl_msg->conn);
free(ctrl_msg);
return NULL;
}
int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg)
@ -335,9 +431,16 @@ int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg)
return -1;
}
pid_t udev_ctrl_get_settle(struct udev_ctrl_msg *ctrl_msg)
int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg)
{
if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SETTLE)
return ctrl_msg->pid;
if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING)
return 1;
return -1;
}
int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg)
{
if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT)
return 1;
return -1;
}

View file

@ -127,26 +127,31 @@ struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socke
struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd);
int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl);
void udev_ctrl_unref(struct udev_ctrl *uctrl);
struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl);
struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl);
int udev_ctrl_get_fd(struct udev_ctrl *uctrl);
int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority);
int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl);
int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl);
int udev_ctrl_send_reload_rules(struct udev_ctrl *uctrl);
int udev_ctrl_send_settle(struct udev_ctrl *uctrl);
int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key);
int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count);
int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout);
int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout);
int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout);
int udev_ctrl_send_reload_rules(struct udev_ctrl *uctrl, int timeout);
int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout);
int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout);
int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout);
int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout);
struct udev_ctrl_connection;
struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl);
struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn);
struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn);
struct udev_ctrl_msg;
struct udev_ctrl_msg *udev_ctrl_msg(struct udev_ctrl *uctrl);
struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl *uctrl);
struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn);
struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg);
void udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg);
struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg);
int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg);
int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg);
int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg);
int udev_ctrl_get_reload_rules(struct udev_ctrl_msg *ctrl_msg);
pid_t udev_ctrl_get_settle(struct udev_ctrl_msg *ctrl_msg);
int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg);
int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg);
const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg);
int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg);
@ -154,6 +159,7 @@ int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg);
struct udev_list_node {
struct udev_list_node *next, *prev;
};
#define UDEV_LIST(list) struct udev_list_node list = { &(list), &(list) }
void udev_list_init(struct udev_list_node *list);
int udev_list_is_empty(struct udev_list_node *list);
void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list);

View file

@ -30,21 +30,25 @@
static void print_help(void)
{
printf("Usage: udevadm control COMMAND\n"
" --exit instruct the daemon to cleanup and exit\n"
" --log-priority=<level> set the udev log level for the daemon\n"
" --stop-exec-queue keep udevd from executing events, queue only\n"
" --start-exec-queue execute events, flush queue\n"
" --reload-rules reloads the rules files\n"
" --property=<KEY>=<value> set a global property for all events\n"
" --children-max=<N> maximum number of children\n"
" --timeout=<seconds> maximum time to block for a reply\n"
" --help print this help text\n\n");
}
int udevadm_control(struct udev *udev, int argc, char *argv[])
{
struct udev_ctrl *uctrl = NULL;
int timeout = 60;
int rc = 1;
static const struct option options[] = {
{ "exit", no_argument, NULL, 'e' },
{ "log-priority", required_argument, NULL, 'l' },
{ "stop-exec-queue", no_argument, NULL, 's' },
{ "start-exec-queue", no_argument, NULL, 'S' },
@ -52,6 +56,7 @@ int udevadm_control(struct udev *udev, int argc, char *argv[])
{ "property", required_argument, NULL, 'p' },
{ "env", required_argument, NULL, 'p' },
{ "children-max", required_argument, NULL, 'm' },
{ "timeout", required_argument, NULL, 't' },
{ "help", no_argument, NULL, 'h' },
{}
};
@ -67,39 +72,46 @@ int udevadm_control(struct udev *udev, int argc, char *argv[])
for (;;) {
int option;
int i;
char *endp;
option = getopt_long(argc, argv, "l:sSRp:m:h", options, NULL);
option = getopt_long(argc, argv, "el:sSRp:m:h", options, NULL);
if (option == -1)
break;
switch (option) {
case 'l':
i = util_log_priority(optarg);
if (i < 0) {
fprintf(stderr, "invalid number '%s'\n", optarg);
goto exit;
}
if (udev_ctrl_send_set_log_level(uctrl, util_log_priority(optarg)) < 0)
case 'e':
if (udev_ctrl_send_exit(uctrl, timeout) < 0)
rc = 2;
else
rc = 0;
break;
case 'l': {
int i;
i = util_log_priority(optarg);
if (i < 0) {
fprintf(stderr, "invalid number '%s'\n", optarg);
goto out;
}
if (udev_ctrl_send_set_log_level(uctrl, util_log_priority(optarg), timeout) < 0)
rc = 2;
else
rc = 0;
break;
}
case 's':
if (udev_ctrl_send_stop_exec_queue(uctrl) < 0)
if (udev_ctrl_send_stop_exec_queue(uctrl, timeout) < 0)
rc = 2;
else
rc = 0;
break;
case 'S':
if (udev_ctrl_send_start_exec_queue(uctrl) < 0)
if (udev_ctrl_send_start_exec_queue(uctrl, timeout) < 0)
rc = 2;
else
rc = 0;
break;
case 'R':
if (udev_ctrl_send_reload_rules(uctrl) < 0)
if (udev_ctrl_send_reload_rules(uctrl, timeout) < 0)
rc = 2;
else
rc = 0;
@ -107,34 +119,45 @@ int udevadm_control(struct udev *udev, int argc, char *argv[])
case 'p':
if (strchr(optarg, '=') == NULL) {
fprintf(stderr, "expect <KEY>=<value> instead of '%s'\n", optarg);
goto exit;
goto out;
}
if (udev_ctrl_send_set_env(uctrl, optarg) < 0)
if (udev_ctrl_send_set_env(uctrl, optarg, timeout) < 0)
rc = 2;
else
rc = 0;
break;
case 'm':
case 'm': {
char *endp;
int i;
i = strtoul(optarg, &endp, 0);
if (endp[0] != '\0' || i < 1) {
fprintf(stderr, "invalid number '%s'\n", optarg);
goto exit;
goto out;
}
if (udev_ctrl_send_set_children_max(uctrl, i) < 0)
if (udev_ctrl_send_set_children_max(uctrl, i, timeout) < 0)
rc = 2;
else
rc = 0;
break;
}
case 't': {
int seconds;
seconds = atoi(optarg);
if (seconds >= 0)
timeout = seconds;
else
fprintf(stderr, "invalid timeout value\n");
break;
}
case 'h':
print_help();
rc = 0;
break;
}
}
if (rc == 1)
err(udev, "unrecognized command\n");
exit:
out:
udev_ctrl_unref(uctrl);
return rc;
}

View file

@ -44,8 +44,6 @@ static void sig_handler(int signum)
switch (signum) {
case SIGALRM:
is_timeout = 1;
case SIGUSR1:
;
}
}
@ -78,9 +76,7 @@ int udevadm_settle(struct udev *udev, int argc, char *argv[])
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
sigaction(SIGUSR1, &act, NULL);
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
@ -168,15 +164,12 @@ int udevadm_settle(struct udev *udev, int argc, char *argv[])
uctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH);
if (uctrl != NULL) {
sigset_t oldmask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_BLOCK, &mask, &oldmask);
if (udev_ctrl_send_settle(uctrl) > 0)
sigsuspend(&oldmask);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
if (udev_ctrl_send_ping(uctrl, timeout) < 0) {
info(udev, "no connection to daemon\n");
udev_ctrl_unref(uctrl);
rc = 0;
goto out;
}
udev_ctrl_unref(uctrl);
}
}
@ -223,7 +216,7 @@ int udevadm_settle(struct udev *udev, int argc, char *argv[])
udev_list_entry_get_value(list_entry));
}
}
out:
udev_queue_unref(udev_queue);
return rc;
}

View file

@ -296,6 +296,12 @@
<refsect2><title>udevadm control <replaceable>command</replaceable></title>
<para>Modify the internal state of the running udev daemon.</para>
<variablelist>
<varlistentry>
<term><option>--exit</option></term>
<listitem>
<para>Signal and wait for udevd to exit.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--log-priority=<replaceable>value</replaceable></option></term>
<listitem>
@ -339,6 +345,12 @@
same time.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--timeout=</option><replaceable>seconds</replaceable></term>
<listitem>
<para>The maximum number seonds to wait for a reply from udevd.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--help</option></term>
<listitem>

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2004-2009 Kay Sievers <kay.sievers@vrfy.org>
* Copyright (C) 2004-2011 Kay Sievers <kay.sievers@vrfy.org>
* Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
* Copyright (C) 2009 Canonical Ltd.
* Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
@ -36,7 +36,7 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/signalfd.h>
#include <sys/select.h>
#include <sys/epoll.h>
#include <sys/poll.h>
#include <sys/wait.h>
#include <sys/stat.h>
@ -76,34 +76,20 @@ static struct udev_queue_export *udev_queue_export;
static struct udev_ctrl *udev_ctrl;
static struct udev_monitor *monitor;
static int worker_watch[2] = { -1, -1 };
static pid_t settle_pid;
static int fd_signal = -1;
static int fd_ep = -1;
static int fd_inotify = -1;
static bool stop_exec_queue;
static bool reload_config;
static int children;
static int children_max;
static int exec_delay;
static sigset_t orig_sigmask;
static struct udev_list_node event_list;
static struct udev_list_node worker_list;
static UDEV_LIST(event_list);
static UDEV_LIST(worker_list);
static bool udev_exit;
static volatile sig_atomic_t worker_exit;
enum poll_fd {
FD_CONTROL,
FD_NETLINK,
FD_INOTIFY,
FD_SIGNAL,
FD_WORKER,
};
static struct pollfd pfd[] = {
[FD_NETLINK] = { .events = POLLIN, .fd = -1 },
[FD_WORKER] = { .events = POLLIN, .fd = -1 },
[FD_SIGNAL] = { .events = POLLIN, .fd = -1 },
[FD_INOTIFY] = { .events = POLLIN, .fd = -1 },
[FD_CONTROL] = { .events = POLLIN, .fd = -1 },
};
enum event_state {
EVENT_UNDEF,
EVENT_QUEUED,
@ -135,6 +121,8 @@ static struct event *node_to_event(struct udev_list_node *node)
return (struct event *)event;
}
static void event_queue_cleanup(struct udev *udev, enum event_state type);
enum worker_state {
WORKER_UNDEF,
WORKER_RUNNING,
@ -167,17 +155,18 @@ static struct worker *node_to_worker(struct udev_list_node *node)
return (struct worker *)worker;
}
static void event_queue_delete(struct event *event)
static void event_queue_delete(struct event *event, bool export)
{
udev_list_node_remove(&event->node);
/* mark as failed, if "add" event returns non-zero */
if (event->exitcode != 0 && strcmp(udev_device_get_action(event->dev), "remove") != 0)
udev_queue_export_device_failed(udev_queue_export, event->dev);
else
udev_queue_export_device_finished(udev_queue_export, event->dev);
info(event->udev, "seq %llu done with %i\n", udev_device_get_seqnum(event->dev), event->exitcode);
if (export) {
/* mark as failed, if "add" event returns non-zero */
if (event->exitcode != 0 && strcmp(udev_device_get_action(event->dev), "remove") != 0)
udev_queue_export_device_failed(udev_queue_export, event->dev);
else
udev_queue_export_device_finished(udev_queue_export, event->dev);
info(event->udev, "seq %llu done with %i\n", udev_device_get_seqnum(event->dev), event->exitcode);
}
udev_device_unref(event->dev);
free(event);
}
@ -200,28 +189,44 @@ static struct worker *worker_ref(struct worker *worker)
return worker;
}
static void worker_cleanup(struct worker *worker)
{
udev_list_node_remove(&worker->node);
udev_monitor_unref(worker->monitor);
children--;
free(worker);
}
static void worker_unref(struct worker *worker)
{
worker->refcount--;
if (worker->refcount > 0)
return;
udev_list_node_remove(&worker->node);
udev_monitor_unref(worker->monitor);
children--;
info(worker->udev, "worker [%u] cleaned up\n", worker->pid);
free(worker);
worker_cleanup(worker);
}
static void worker_list_cleanup(struct udev *udev)
{
struct udev_list_node *loop, *tmp;
udev_list_node_foreach_safe(loop, tmp, &worker_list) {
struct worker *worker = node_to_worker(loop);
worker_cleanup(worker);
}
}
static void worker_new(struct event *event)
{
struct udev *udev = event->udev;
struct worker *worker;
struct udev_monitor *worker_monitor;
pid_t pid;
struct sigaction act;
/* listen for new events */
worker_monitor = udev_monitor_new_from_netlink(event->udev, NULL);
worker_monitor = udev_monitor_new_from_netlink(udev, NULL);
if (worker_monitor == NULL)
return;
/* allow the main daemon netlink address to send devices to the worker */
@ -235,7 +240,7 @@ static void worker_new(struct event *event)
}
/* worker + event reference */
worker->refcount = 2;
worker->udev = event->udev;
worker->udev = udev;
pid = fork();
switch (pid) {
@ -247,10 +252,18 @@ static void worker_new(struct event *event)
.events = POLLIN,
};
/* move initial device from queue */
dev = event->dev;
event->dev = NULL;
free(worker);
worker_list_cleanup(udev);
event_queue_cleanup(udev, EVENT_UNDEF);
udev_queue_export_unref(udev_queue_export);
udev_monitor_unref(monitor);
udev_ctrl_unref(udev_ctrl);
close(pfd[FD_SIGNAL].fd);
close(fd_signal);
close(fd_ep);
close(worker_watch[READ_END]);
udev_log_close();
udev_log_init("udevd-work");
@ -274,16 +287,13 @@ static void worker_new(struct event *event)
/* request TERM signal if parent exits */
prctl(PR_SET_PDEATHSIG, SIGTERM);
/* initial device */
dev = event->dev;
do {
struct udev_event *udev_event;
struct worker_message msg = {};
int err;
int failed = 0;
info(event->udev, "seq %llu running\n", udev_device_get_seqnum(dev));
info(udev, "seq %llu running\n", udev_device_get_seqnum(dev));
udev_event = udev_event_new(dev);
if (udev_event == NULL)
_exit(3);
@ -308,7 +318,7 @@ static void worker_new(struct event *event)
/* apply/restore inotify watch */
if (err == 0 && udev_event->inotify_watch) {
udev_watch_begin(udev_event->udev, dev);
udev_watch_begin(udev, dev);
udev_device_update_db(dev);
}
@ -323,7 +333,7 @@ static void worker_new(struct event *event)
msg.pid = getpid();
send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0);
info(event->udev, "seq %llu processed with %i\n", udev_device_get_seqnum(dev), err);
info(udev, "seq %llu processed with %i\n", udev_device_get_seqnum(dev), err);
udev_event_unref(udev_event);
udev_device_unref(dev);
dev = NULL;
@ -344,15 +354,19 @@ static void worker_new(struct event *event)
}
} while (dev != NULL);
close(fd_inotify);
close(worker_watch[WRITE_END]);
udev_rules_unref(rules);
udev_monitor_unref(worker_monitor);
udev_unref(udev);
udev_log_close();
exit(0);
exit(EXIT_SUCCESS);
}
case -1:
udev_monitor_unref(worker_monitor);
event->state = EVENT_QUEUED;
free(worker);
err(event->udev, "fork of child failed: %m\n");
err(udev, "fork of child failed: %m\n");
break;
default:
/* close monitor, but keep address around */
@ -364,7 +378,7 @@ static void worker_new(struct event *event)
event->state = EVENT_RUNNING;
udev_list_node_append(&worker->node, &worker_list);
children++;
info(event->udev, "seq %llu forked new worker [%u]\n", udev_device_get_seqnum(event->dev), pid);
info(udev, "seq %llu forked new worker [%u]\n", udev_device_get_seqnum(event->dev), pid);
break;
}
}
@ -535,7 +549,7 @@ static bool is_devpath_busy(struct event *event)
return false;
}
static void events_start(struct udev *udev)
static void event_queue_start(struct udev *udev)
{
struct udev_list_node *loop;
@ -555,14 +569,28 @@ static void events_start(struct udev *udev)
}
}
static void worker_returned(void)
static void event_queue_cleanup(struct udev *udev, enum event_state match_type)
{
struct udev_list_node *loop, *tmp;
udev_list_node_foreach_safe(loop, tmp, &event_list) {
struct event *event = node_to_event(loop);
if (match_type != EVENT_UNDEF && match_type != event->state)
continue;
event_queue_delete(event, false);
}
}
static void worker_returned(int fd_worker)
{
for (;;) {
struct worker_message msg;
ssize_t size;
struct udev_list_node *loop;
size = recv(pfd[FD_WORKER].fd, &msg, sizeof(struct worker_message), MSG_DONTWAIT);
size = recv(fd_worker, &msg, sizeof(struct worker_message), MSG_DONTWAIT);
if (size != sizeof(struct worker_message))
break;
@ -575,7 +603,7 @@ static void worker_returned(void)
/* worker returned */
worker->event->exitcode = msg.exitcode;
event_queue_delete(worker->event);
event_queue_delete(worker->event, true);
worker->event = NULL;
if (worker->state != WORKER_KILLED)
worker->state = WORKER_IDLE;
@ -586,16 +614,21 @@ static void worker_returned(void)
}
/* receive the udevd message from userspace */
static void handle_ctrl_msg(struct udev_ctrl *uctrl)
static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl)
{
struct udev *udev = udev_ctrl_get_udev(uctrl);
struct udev_ctrl_msg *ctrl_msg;
struct udev_ctrl_connection *ctrl_conn;
struct udev_ctrl_msg *ctrl_msg = NULL;
const char *str;
int i;
ctrl_msg = udev_ctrl_receive_msg(uctrl);
ctrl_conn = udev_ctrl_get_connection(uctrl);
if (ctrl_conn == NULL)
goto out;
ctrl_msg = udev_ctrl_receive_msg(ctrl_conn);
if (ctrl_msg == NULL)
return;
goto out;
i = udev_ctrl_get_set_log_level(ctrl_msg);
if (i >= 0) {
@ -652,13 +685,18 @@ static void handle_ctrl_msg(struct udev_ctrl *uctrl)
children_max = i;
}
settle_pid = udev_ctrl_get_settle(ctrl_msg);
if (settle_pid > 0) {
info(udev, "udevd message (SETTLE) received\n");
kill(settle_pid, SIGUSR1);
settle_pid = 0;
if (udev_ctrl_get_ping(ctrl_msg) > 0)
info(udev, "udevd message (SYNC) received\n");
if (udev_ctrl_get_exit(ctrl_msg) > 0) {
info(udev, "udevd message (EXIT) received\n");
udev_exit = true;
/* keep reference to block the client until we exit */
udev_ctrl_connection_ref(ctrl_conn);
}
out:
udev_ctrl_msg_unref(ctrl_msg);
return udev_ctrl_connection_unref(ctrl_conn);
}
/* read inotify messages */
@ -668,7 +706,7 @@ static int handle_inotify(struct udev *udev)
char *buf;
struct inotify_event *ev;
if ((ioctl(pfd[FD_INOTIFY].fd, FIONREAD, &nbytes) < 0) || (nbytes <= 0))
if ((ioctl(fd_inotify, FIONREAD, &nbytes) < 0) || (nbytes <= 0))
return 0;
buf = malloc(nbytes);
@ -677,7 +715,7 @@ static int handle_inotify(struct udev *udev)
return -1;
}
nbytes = read(pfd[FD_INOTIFY].fd, buf, nbytes);
nbytes = read(fd_inotify, buf, nbytes);
for (pos = 0; pos < nbytes; pos += sizeof(struct inotify_event) + ev->len) {
struct udev_device *dev;
@ -751,7 +789,7 @@ static void handle_signal(struct udev *udev, int signo)
if (worker->event != NULL) {
err(udev, "worker [%u] failed while handling '%s'\n", pid, worker->event->devpath);
worker->event->exitcode = -32;
event_queue_delete(worker->event);
event_queue_delete(worker->event, true);
/* drop reference from running event */
worker_unref(worker);
}
@ -1081,6 +1119,11 @@ int main(int argc, char *argv[])
{ "version", no_argument, NULL, 'V' },
{}
};
int fd_ctrl = -1;
int fd_netlink = -1;
int fd_worker = -1;
struct epoll_event ep_ctrl, ep_inotify, ep_signal, ep_netlink, ep_worker;
struct udev_ctrl_connection *ctrl_conn = NULL;
int rc = 1;
udev = udev_new();
@ -1229,7 +1272,7 @@ int main(int argc, char *argv[])
dup2(fd, STDERR_FILENO);
/* udevadm control socket */
if (sd_listen_fds(true) == 1 && sd_is_socket(SD_LISTEN_FDS_START, AF_LOCAL, SOCK_DGRAM, -1))
if (sd_listen_fds(true) == 1 && sd_is_socket(SD_LISTEN_FDS_START, AF_LOCAL, SOCK_SEQPACKET, -1))
udev_ctrl = udev_ctrl_new_from_fd(udev, SD_LISTEN_FDS_START);
else
udev_ctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH);
@ -1245,7 +1288,7 @@ int main(int argc, char *argv[])
rc = 1;
goto exit;
}
pfd[FD_CONTROL].fd = udev_ctrl_get_fd(udev_ctrl);
fd_ctrl = udev_ctrl_get_fd(udev_ctrl);
monitor = udev_monitor_new_from_netlink(udev, "kernel");
if (monitor == NULL || udev_monitor_enable_receiving(monitor) < 0) {
@ -1255,81 +1298,7 @@ int main(int argc, char *argv[])
goto exit;
}
udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024);
pfd[FD_NETLINK].fd = udev_monitor_get_fd(monitor);
pfd[FD_INOTIFY].fd = udev_watch_init(udev);
if (pfd[FD_INOTIFY].fd < 0) {
fprintf(stderr, "error initializing inotify\n");
err(udev, "error initializing inotify\n");
rc = 4;
goto exit;
}
if (udev_get_rules_path(udev) != NULL) {
inotify_add_watch(pfd[FD_INOTIFY].fd, udev_get_rules_path(udev),
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
} else {
char filename[UTIL_PATH_SIZE];
struct stat statbuf;
inotify_add_watch(pfd[FD_INOTIFY].fd, LIBEXECDIR "/rules.d",
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
inotify_add_watch(pfd[FD_INOTIFY].fd, SYSCONFDIR "/udev/rules.d",
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
/* watch dynamic rules directory */
util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/rules.d", NULL);
if (stat(filename, &statbuf) != 0) {
util_create_path(udev, filename);
mkdir(filename, 0755);
}
inotify_add_watch(pfd[FD_INOTIFY].fd, filename,
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
}
udev_watch_restore(udev);
/* block and listen to all signals on signalfd */
sigfillset(&mask);
sigprocmask(SIG_SETMASK, &mask, &orig_sigmask);
pfd[FD_SIGNAL].fd = signalfd(-1, &mask, 0);
if (pfd[FD_SIGNAL].fd < 0) {
fprintf(stderr, "error getting signalfd\n");
err(udev, "error getting signalfd\n");
rc = 5;
goto exit;
}
/* unnamed socket from workers to the main daemon */
if (socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, worker_watch) < 0) {
fprintf(stderr, "error getting socketpair\n");
err(udev, "error getting socketpair\n");
rc = 6;
goto exit;
}
pfd[FD_WORKER].fd = worker_watch[READ_END];
rules = udev_rules_new(udev, resolve_names);
if (rules == NULL) {
err(udev, "error reading rules\n");
goto exit;
}
udev_queue_export = udev_queue_export_new(udev);
if (udev_queue_export == NULL) {
err(udev, "error creating queue file\n");
goto exit;
}
/* if needed, convert old database from earlier udev version */
convert_db(udev);
if (!debug) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
}
if (fd > STDERR_FILENO)
close(fd);
fd_netlink = udev_monitor_get_fd(monitor);
if (daemonize) {
pid_t pid;
@ -1350,6 +1319,109 @@ int main(int argc, char *argv[])
sd_notify(1, "READY=1");
}
fd_inotify = udev_watch_init(udev);
if (fd_inotify < 0) {
fprintf(stderr, "error initializing inotify\n");
err(udev, "error initializing inotify\n");
rc = 4;
goto exit;
}
if (udev_get_rules_path(udev) != NULL) {
inotify_add_watch(fd_inotify, udev_get_rules_path(udev),
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
} else {
char filename[UTIL_PATH_SIZE];
struct stat statbuf;
inotify_add_watch(fd_inotify, LIBEXECDIR "/rules.d",
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
inotify_add_watch(fd_inotify, SYSCONFDIR "/udev/rules.d",
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
/* watch dynamic rules directory */
util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/rules.d", NULL);
if (stat(filename, &statbuf) != 0) {
util_create_path(udev, filename);
mkdir(filename, 0755);
}
inotify_add_watch(fd_inotify, filename,
IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
}
udev_watch_restore(udev);
/* block and listen to all signals on signalfd */
sigfillset(&mask);
sigprocmask(SIG_SETMASK, &mask, &orig_sigmask);
fd_signal = signalfd(-1, &mask, SFD_CLOEXEC);
if (fd_signal < 0) {
fprintf(stderr, "error getting signalfd\n");
err(udev, "error getting signalfd\n");
rc = 5;
goto exit;
}
/* unnamed socket from workers to the main daemon */
if (socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, worker_watch) < 0) {
fprintf(stderr, "error getting socketpair\n");
err(udev, "error getting socketpair\n");
rc = 6;
goto exit;
}
fd_worker = worker_watch[READ_END];
rules = udev_rules_new(udev, resolve_names);
if (rules == NULL) {
err(udev, "error reading rules\n");
goto exit;
}
udev_queue_export = udev_queue_export_new(udev);
if (udev_queue_export == NULL) {
err(udev, "error creating queue file\n");
goto exit;
}
memset(&ep_ctrl, 0, sizeof(struct epoll_event));
ep_ctrl.events = EPOLLIN;
ep_ctrl.data.fd = fd_ctrl;
memset(&ep_inotify, 0, sizeof(struct epoll_event));
ep_inotify.events = EPOLLIN;
ep_inotify.data.fd = fd_inotify;
memset(&ep_signal, 0, sizeof(struct epoll_event));
ep_signal.events = EPOLLIN;
ep_signal.data.fd = fd_signal;
memset(&ep_netlink, 0, sizeof(struct epoll_event));
ep_netlink.events = EPOLLIN;
ep_netlink.data.fd = fd_netlink;
memset(&ep_worker, 0, sizeof(struct epoll_event));
ep_worker.events = EPOLLIN;
ep_worker.data.fd = fd_worker;
fd_ep = epoll_create1(EPOLL_CLOEXEC);
if (fd_ep < 0) {
err(udev, "error creating epoll fd: %m\n");
goto exit;
}
if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_ctrl, &ep_ctrl) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_inotify, &ep_inotify) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_netlink, &ep_netlink) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_worker, &ep_worker) < 0) {
err(udev, "fail to add fds to epoll: %m\n");
goto exit;
}
/* if needed, convert old database from earlier udev version */
convert_db(udev);
if (!debug) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
}
if (fd > STDERR_FILENO)
close(fd);
/* set scheduling priority for the main daemon process */
setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY);
@ -1393,30 +1465,79 @@ int main(int argc, char *argv[])
udev_list_init(&event_list);
udev_list_init(&worker_list);
while (!udev_exit) {
for (;;) {
struct epoll_event ev[8];
int fdcount;
int timeout;
bool is_worker, is_signal, is_inotify, is_netlink, is_ctrl;
int i;
/* set timeout to kill idle workers */
if (udev_list_is_empty(&event_list) && children > 2)
if (udev_exit) {
/* close sources of new events and discard buffered events */
if (fd_ctrl >= 0) {
epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_ctrl, NULL);
fd_ctrl = -1;
}
if (monitor != NULL) {
epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_netlink, NULL);
udev_monitor_unref(monitor);
monitor = NULL;
}
if (fd_inotify >= 0) {
epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_inotify, NULL);
close(fd_inotify);
fd_inotify = -1;
}
/* discard queued events and kill workers */
event_queue_cleanup(udev, EVENT_QUEUED);
worker_kill(udev, 0);
/* exit after all has cleaned up */
if (udev_list_is_empty(&event_list) && udev_list_is_empty(&worker_list))
break;
/* timeout at exit for workers to finish */
timeout = 60 * 1000;
} else if (udev_list_is_empty(&event_list) && children > 2) {
/* set timeout to kill idle workers */
timeout = 3 * 1000;
else
} else {
timeout = -1;
/* wait for events */
fdcount = poll(pfd, ARRAY_SIZE(pfd), timeout);
}
fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), timeout);
if (fdcount < 0)
continue;
/* timeout - kill idle workers */
if (fdcount == 0)
if (fdcount == 0) {
if (udev_exit) {
info(udev, "timeout, giving up waiting for workers to finish\n");
break;
}
/* timeout - kill idle workers */
worker_kill(udev, 2);
}
is_worker = is_signal = is_inotify = is_netlink = is_ctrl = false;
for (i = 0; i < fdcount; i++) {
if (ev[i].data.fd == fd_worker && ev[i].events & EPOLLIN)
is_worker = true;
else if (ev[i].data.fd == fd_netlink && ev[i].events & EPOLLIN)
is_netlink = true;
else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN)
is_signal = true;
else if (ev[i].data.fd == fd_inotify && ev[i].events & EPOLLIN)
is_inotify = true;
else if (ev[i].data.fd == fd_ctrl && ev[i].events & EPOLLIN)
is_ctrl = true;
}
/* event has finished */
if (pfd[FD_WORKER].revents & POLLIN)
worker_returned();
if (is_worker)
worker_returned(fd_worker);
/* get kernel uevent */
if (pfd[FD_NETLINK].revents & POLLIN) {
if (is_netlink) {
struct udev_device *dev;
dev = udev_monitor_receive_device(monitor);
@ -1426,32 +1547,37 @@ int main(int argc, char *argv[])
}
/* start new events */
if (!udev_list_is_empty(&event_list) && !stop_exec_queue)
events_start(udev);
if (!udev_list_is_empty(&event_list) && !udev_exit && !stop_exec_queue)
event_queue_start(udev);
/* get signal */
if (pfd[FD_SIGNAL].revents & POLLIN) {
if (is_signal) {
struct signalfd_siginfo fdsi;
ssize_t size;
size = read(pfd[FD_SIGNAL].fd, &fdsi, sizeof(struct signalfd_siginfo));
size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
if (size == sizeof(struct signalfd_siginfo))
handle_signal(udev, fdsi.ssi_signo);
}
/* we are shutting down, the events below are not handled anymore */
if (udev_exit)
continue;
/* device node and rules directory inotify watch */
if (pfd[FD_INOTIFY].revents & POLLIN)
if (is_inotify)
handle_inotify(udev);
/*
* get control message
*
* This needs to be after the inotify handling, to make sure,
* that the settle signal is send back after the possibly generated
* that the ping is send back after the possibly generated
* "change" events by the inotify device node watch.
*
* A single time we may receive a client connection which we need to
* keep open to block the client. It will be closed right before we
* exit.
*/
if (pfd[FD_CONTROL].revents & POLLIN)
handle_ctrl_msg(udev_ctrl);
if (is_ctrl)
ctrl_conn = handle_ctrl_msg(udev_ctrl);
/* rules changed, set by inotify or a HUP signal */
if (reload_config) {
@ -1470,16 +1596,21 @@ int main(int argc, char *argv[])
udev_queue_export_cleanup(udev_queue_export);
rc = 0;
exit:
udev_queue_export_unref(udev_queue_export);
if (fd_ep >= 0)
close(fd_ep);
worker_list_cleanup(udev);
event_queue_cleanup(udev, EVENT_UNDEF);
udev_rules_unref(rules);
udev_ctrl_unref(udev_ctrl);
if (pfd[FD_SIGNAL].fd >= 0)
close(pfd[FD_SIGNAL].fd);
if (fd_signal >= 0)
close(fd_signal);
if (worker_watch[READ_END] >= 0)
close(worker_watch[READ_END]);
if (worker_watch[WRITE_END] >= 0)
close(worker_watch[WRITE_END]);
udev_monitor_unref(monitor);
udev_queue_export_unref(udev_queue_export);
udev_ctrl_connection_unref(ctrl_conn);
udev_ctrl_unref(udev_ctrl);
udev_selinux_exit(udev);
udev_unref(udev);
udev_log_close();