udevd.c   udevd.c 
skipping to change at line 60 skipping to change at line 60
#include "udev-util.h" #include "udev-util.h"
#include "sd-daemon.h" #include "sd-daemon.h"
#include "cgroup-util.h" #include "cgroup-util.h"
#include "dev-setup.h" #include "dev-setup.h"
#include "fileio.h" #include "fileio.h"
static bool debug; static bool debug;
void udev_main_log(struct udev *udev, int priority, void udev_main_log(struct udev *udev, int priority,
const char *file, int line, const char *fn, const char *file, int line, const char *fn,
const char *format, va_list args) const char *format, va_list args) {
{
log_metav(priority, file, line, fn, format, args); log_metav(priority, file, line, fn, format, args);
} }
static struct udev_rules *rules; static struct udev_rules *rules;
static struct udev_ctrl *udev_ctrl; static struct udev_ctrl *udev_ctrl;
static struct udev_monitor *monitor; static struct udev_monitor *monitor;
static int worker_watch[2] = { -1, -1 }; static int worker_watch[2] = { -1, -1 };
static int fd_signal = -1; static int fd_signal = -1;
static int fd_ep = -1; static int fd_ep = -1;
static int fd_inotify = -1; static int fd_inotify = -1;
static bool stop_exec_queue; static bool stop_exec_queue;
static bool reload; static bool reload;
static int children; static int children;
static int children_max; static int children_max;
static int exec_delay; static int exec_delay;
static usec_t event_timeout_usec = 30 * USEC_PER_SEC;
static sigset_t sigmask_orig; static sigset_t sigmask_orig;
static UDEV_LIST(event_list); static UDEV_LIST(event_list);
static UDEV_LIST(worker_list); static UDEV_LIST(worker_list);
static char *udev_cgroup; static char *udev_cgroup;
static bool udev_exit; static bool udev_exit;
enum event_state { enum event_state {
EVENT_UNDEF, EVENT_UNDEF,
EVENT_QUEUED, EVENT_QUEUED,
EVENT_RUNNING, EVENT_RUNNING,
skipping to change at line 108 skipping to change at line 108
size_t devpath_len; size_t devpath_len;
const char *devpath_old; const char *devpath_old;
dev_t devnum; dev_t devnum;
int ifindex; int ifindex;
bool is_block; bool is_block;
#ifdef HAVE_FIRMWARE #ifdef HAVE_FIRMWARE
bool nodelay; bool nodelay;
#endif #endif
}; };
static inline struct event *node_to_event(struct udev_list_node *node) static inline struct event *node_to_event(struct udev_list_node *node) {
{
return container_of(node, struct event, node); return container_of(node, struct event, node);
} }
static void event_queue_cleanup(struct udev *udev, enum event_state type); static void event_queue_cleanup(struct udev *udev, enum event_state type);
enum worker_state { enum worker_state {
WORKER_UNDEF, WORKER_UNDEF,
WORKER_RUNNING, WORKER_RUNNING,
WORKER_IDLE, WORKER_IDLE,
WORKER_KILLED, WORKER_KILLED,
skipping to change at line 139 skipping to change at line 138
struct event *event; struct event *event;
usec_t event_start_usec; usec_t event_start_usec;
}; };
/* passed from worker to main process */ /* passed from worker to main process */
struct worker_message { struct worker_message {
pid_t pid; pid_t pid;
int exitcode; int exitcode;
}; };
static inline struct worker *node_to_worker(struct udev_list_node *node) static inline struct worker *node_to_worker(struct udev_list_node *node) {
{
return container_of(node, struct worker, node); return container_of(node, struct worker, node);
} }
static void event_queue_delete(struct event *event) static void event_queue_delete(struct event *event) {
{
udev_list_node_remove(&event->node); udev_list_node_remove(&event->node);
udev_device_unref(event->dev); udev_device_unref(event->dev);
free(event); free(event);
} }
static struct worker *worker_ref(struct worker *worker) static struct worker *worker_ref(struct worker *worker) {
{
worker->refcount++; worker->refcount++;
return worker; return worker;
} }
static void worker_cleanup(struct worker *worker) static void worker_cleanup(struct worker *worker) {
{
udev_list_node_remove(&worker->node); udev_list_node_remove(&worker->node);
udev_monitor_unref(worker->monitor); udev_monitor_unref(worker->monitor);
children--; children--;
free(worker); free(worker);
} }
static void worker_unref(struct worker *worker) static void worker_unref(struct worker *worker) {
{
worker->refcount--; worker->refcount--;
if (worker->refcount > 0) if (worker->refcount > 0)
return; return;
log_debug("worker [%u] cleaned up", worker->pid); log_debug("worker [%u] cleaned up", worker->pid);
worker_cleanup(worker); worker_cleanup(worker);
} }
static void worker_list_cleanup(struct udev *udev) static void worker_list_cleanup(struct udev *udev) {
{
struct udev_list_node *loop, *tmp; struct udev_list_node *loop, *tmp;
udev_list_node_foreach_safe(loop, tmp, &worker_list) { udev_list_node_foreach_safe(loop, tmp, &worker_list) {
struct worker *worker = node_to_worker(loop); struct worker *worker = node_to_worker(loop);
worker_cleanup(worker); worker_cleanup(worker);
} }
} }
static void worker_new(struct event *event) static void worker_new(struct event *event) {
{
struct udev *udev = event->udev; struct udev *udev = event->udev;
struct worker *worker; struct worker *worker;
struct udev_monitor *worker_monitor; struct udev_monitor *worker_monitor;
pid_t pid; pid_t pid;
/* listen for new events */ /* listen for new events */
worker_monitor = udev_monitor_new_from_netlink(udev, NULL); worker_monitor = udev_monitor_new_from_netlink(udev, NULL);
if (worker_monitor == NULL) if (worker_monitor == NULL)
return; return;
/* allow the main daemon netlink address to send devices to the wor ker */ /* allow the main daemon netlink address to send devices to the wor ker */
skipping to change at line 288 skipping to change at line 280
goto out; goto out;
} }
/* needed for SIGCHLD/SIGTERM in spawn() */ /* needed for SIGCHLD/SIGTERM in spawn() */
udev_event->fd_signal = fd_signal; udev_event->fd_signal = fd_signal;
if (exec_delay > 0) if (exec_delay > 0)
udev_event->exec_delay = exec_delay; udev_event->exec_delay = exec_delay;
/* /*
* Take a "read lock" on the device node; this esta blishes * Take a shared lock on the device node; this esta blishes
* a concept of device "ownership" to serialize dev ice * a concept of device "ownership" to serialize dev ice
* access. External processes holding a "write lock " will * access. External processes holding an exclusive lock will
* cause udev to skip the event handling; in the ca se udev * cause udev to skip the event handling; in the ca se udev
* acquired the lock, the external process will blo ck until * acquired the lock, the external process can bloc k until
* udev has finished its event handling. * udev has finished its event handling.
*/ */
if (!streq_ptr(udev_device_get_action(dev), "remove
/* ") &&
* <kabi_> since we make check - device seems unuse streq_ptr("block", udev_device_get_subsystem(de
d - we try v)) &&
* ioctl to deactivate - and device is foun !startswith(udev_device_get_sysname(dev), "dm-"
d to be opened ) &&
* <kay> sure, you try to take a write lock !startswith(udev_device_get_sysname(dev), "md")
* <kay> if you get it udev is out ) {
* <kay> if you can't get it, udev is busy
* <kabi_> we cannot deactivate openned device (as
it is in-use)
* <kay> maybe we should just exclude dm from that
thing entirely
* <kabi_> IMHO this sounds like a good plan for th
is moment
*/
if (streq_ptr("block", udev_device_get_subsystem(de
v)) &&
!startswith(udev_device_get_sysname(dev), "dm-"
)) {
struct udev_device *d = dev; struct udev_device *d = dev;
if (streq_ptr("partition", udev_device_get_ devtype(d))) if (streq_ptr("partition", udev_device_get_ devtype(d)))
d = udev_device_get_parent(d); d = udev_device_get_parent(d);
if (d) { if (d) {
fd_lock = open(udev_device_get_devn ode(d), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); fd_lock = open(udev_device_get_devn ode(d), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
if (fd_lock >= 0 && flock(fd_lock, LOCK_SH|LOCK_NB) < 0) { if (fd_lock >= 0 && flock(fd_lock, LOCK_SH|LOCK_NB) < 0) {
log_debug("Unable to flock( %s), skipping event handling: %m", udev_device_get_devnode(d)); log_debug("Unable to flock( %s), skipping event handling: %m", udev_device_get_devnode(d));
err = -EWOULDBLOCK; err = -EWOULDBLOCK;
fd_lock = safe_close(fd_loc k); fd_lock = safe_close(fd_loc k);
goto skip; goto skip;
} }
} }
} }
/* apply rules, create node, symlinks */ /* apply rules, create node, symlinks */
udev_event_execute_rules(udev_event, rules, &sigmas k_orig); udev_event_execute_rules(udev_event, event_timeout_ usec, rules, &sigmask_orig);
udev_event_execute_run(udev_event, &sigmask_orig); udev_event_execute_run(udev_event, event_timeout_us ec, &sigmask_orig);
/* apply/restore inotify watch */ /* apply/restore inotify watch */
if (udev_event->inotify_watch) { if (udev_event->inotify_watch) {
udev_watch_begin(udev, dev); udev_watch_begin(udev, dev);
udev_device_update_db(dev); udev_device_update_db(dev);
} }
safe_close(fd_lock); safe_close(fd_lock);
/* send processed event back to libudev listeners * / /* send processed event back to libudev listeners * /
skipping to change at line 427 skipping to change at line 410
worker->event_start_usec = now(CLOCK_MONOTONIC); worker->event_start_usec = now(CLOCK_MONOTONIC);
worker->event = event; worker->event = event;
event->state = EVENT_RUNNING; event->state = EVENT_RUNNING;
udev_list_node_append(&worker->node, &worker_list); udev_list_node_append(&worker->node, &worker_list);
children++; children++;
log_debug("seq %llu forked new worker [%u]", udev_device_ge t_seqnum(event->dev), pid); log_debug("seq %llu forked new worker [%u]", udev_device_ge t_seqnum(event->dev), pid);
break; break;
} }
} }
static void event_run(struct event *event) static void event_run(struct event *event) {
{
struct udev_list_node *loop; struct udev_list_node *loop;
udev_list_node_foreach(loop, &worker_list) { udev_list_node_foreach(loop, &worker_list) {
struct worker *worker = node_to_worker(loop); struct worker *worker = node_to_worker(loop);
ssize_t count; ssize_t count;
if (worker->state != WORKER_IDLE) if (worker->state != WORKER_IDLE)
continue; continue;
count = udev_monitor_send_device(monitor, worker->monitor, event->dev); count = udev_monitor_send_device(monitor, worker->monitor, event->dev);
skipping to change at line 463 skipping to change at line 445
if (children >= children_max) { if (children >= children_max) {
if (children_max > 1) if (children_max > 1)
log_debug("maximum number (%i) of children reached" , children); log_debug("maximum number (%i) of children reached" , children);
return; return;
} }
/* start new worker and pass initial device */ /* start new worker and pass initial device */
worker_new(event); worker_new(event);
} }
static int event_queue_insert(struct udev_device *dev) static int event_queue_insert(struct udev_device *dev) {
{
struct event *event; struct event *event;
event = new0(struct event, 1); event = new0(struct event, 1);
if (event == NULL) if (event == NULL)
return -1; return -1;
event->udev = udev_device_get_udev(dev); event->udev = udev_device_get_udev(dev);
event->dev = dev; event->dev = dev;
event->seqnum = udev_device_get_seqnum(dev); event->seqnum = udev_device_get_seqnum(dev);
event->devpath = udev_device_get_devpath(dev); event->devpath = udev_device_get_devpath(dev);
skipping to change at line 493 skipping to change at line 474
#endif #endif
log_debug("seq %llu queued, '%s' '%s'", udev_device_get_seqnum(dev) , log_debug("seq %llu queued, '%s' '%s'", udev_device_get_seqnum(dev) ,
udev_device_get_action(dev), udev_device_get_subsystem(dev)); udev_device_get_action(dev), udev_device_get_subsystem(dev));
event->state = EVENT_QUEUED; event->state = EVENT_QUEUED;
udev_list_node_append(&event->node, &event_list); udev_list_node_append(&event->node, &event_list);
return 0; return 0;
} }
static void worker_kill(struct udev *udev) static void worker_kill(struct udev *udev) {
{
struct udev_list_node *loop; struct udev_list_node *loop;
udev_list_node_foreach(loop, &worker_list) { udev_list_node_foreach(loop, &worker_list) {
struct worker *worker = node_to_worker(loop); struct worker *worker = node_to_worker(loop);
if (worker->state == WORKER_KILLED) if (worker->state == WORKER_KILLED)
continue; continue;
worker->state = WORKER_KILLED; worker->state = WORKER_KILLED;
kill(worker->pid, SIGTERM); kill(worker->pid, SIGTERM);
} }
} }
/* lookup event for identical, parent, child device */ /* lookup event for identical, parent, child device */
static bool is_devpath_busy(struct event *event) static bool is_devpath_busy(struct event *event) {
{
struct udev_list_node *loop; struct udev_list_node *loop;
size_t common; size_t common;
/* check if queue contains events we depend on */ /* check if queue contains events we depend on */
udev_list_node_foreach(loop, &event_list) { udev_list_node_foreach(loop, &event_list) {
struct event *loop_event = node_to_event(loop); struct event *loop_event = node_to_event(loop);
/* we already found a later event, earlier can not block us , no need to check again */ /* we already found a later event, earlier can not block us , no need to check again */
if (loop_event->seqnum < event->delaying_seqnum) if (loop_event->seqnum < event->delaying_seqnum)
continue; continue;
skipping to change at line 587 skipping to change at line 566
return true; return true;
} }
/* no matching device */ /* no matching device */
continue; continue;
} }
return false; return false;
} }
static void event_queue_start(struct udev *udev) static void event_queue_start(struct udev *udev) {
{
struct udev_list_node *loop; struct udev_list_node *loop;
udev_list_node_foreach(loop, &event_list) { udev_list_node_foreach(loop, &event_list) {
struct event *event = node_to_event(loop); struct event *event = node_to_event(loop);
if (event->state != EVENT_QUEUED) if (event->state != EVENT_QUEUED)
continue; continue;
/* do not start event if parent or child event is still run ning */ /* do not start event if parent or child event is still run ning */
if (is_devpath_busy(event)) if (is_devpath_busy(event))
continue; continue;
event_run(event); event_run(event);
} }
} }
static void event_queue_cleanup(struct udev *udev, enum event_state match_t static void event_queue_cleanup(struct udev *udev, enum event_state match_t
ype) ype) {
{
struct udev_list_node *loop, *tmp; struct udev_list_node *loop, *tmp;
udev_list_node_foreach_safe(loop, tmp, &event_list) { udev_list_node_foreach_safe(loop, tmp, &event_list) {
struct event *event = node_to_event(loop); struct event *event = node_to_event(loop);
if (match_type != EVENT_UNDEF && match_type != event->state ) if (match_type != EVENT_UNDEF && match_type != event->state )
continue; continue;
event_queue_delete(event); event_queue_delete(event);
} }
} }
static void worker_returned(int fd_worker) static void worker_returned(int fd_worker) {
{
for (;;) { for (;;) {
struct worker_message msg; struct worker_message msg;
ssize_t size; ssize_t size;
struct udev_list_node *loop; struct udev_list_node *loop;
size = recv(fd_worker, &msg, sizeof(struct worker_message), MSG_DONTWAIT); size = recv(fd_worker, &msg, sizeof(struct worker_message), MSG_DONTWAIT);
if (size != sizeof(struct worker_message)) if (size != sizeof(struct worker_message))
break; break;
/* lookup worker who sent the signal */ /* lookup worker who sent the signal */
skipping to change at line 652 skipping to change at line 628
} }
if (worker->state != WORKER_KILLED) if (worker->state != WORKER_KILLED)
worker->state = WORKER_IDLE; worker->state = WORKER_IDLE;
worker_unref(worker); worker_unref(worker);
break; break;
} }
} }
} }
/* receive the udevd message from userspace */ /* receive the udevd message from userspace */
static struct udev_ctrl_connection *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 *udev = udev_ctrl_get_udev(uctrl);
struct udev_ctrl_connection *ctrl_conn; struct udev_ctrl_connection *ctrl_conn;
struct udev_ctrl_msg *ctrl_msg = NULL; struct udev_ctrl_msg *ctrl_msg = NULL;
const char *str; const char *str;
int i; int i;
ctrl_conn = udev_ctrl_get_connection(uctrl); ctrl_conn = udev_ctrl_get_connection(uctrl);
if (ctrl_conn == NULL) if (ctrl_conn == NULL)
goto out; goto out;
skipping to change at line 842 skipping to change at line 817
return 0; return 0;
} }
log_debug("device %s closed, synthesising 'change'", udev_device_ge t_devnode(dev)); log_debug("device %s closed, synthesising 'change'", udev_device_ge t_devnode(dev));
strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL); strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
write_string_file(filename, "change"); write_string_file(filename, "change");
return 0; return 0;
} }
static int handle_inotify(struct udev *udev) static int handle_inotify(struct udev *udev) {
{
int nbytes, pos; int nbytes, pos;
char *buf; char *buf;
struct inotify_event *ev; struct inotify_event *ev;
int r; int r;
r = ioctl(fd_inotify, FIONREAD, &nbytes); r = ioctl(fd_inotify, FIONREAD, &nbytes);
if (r < 0 || nbytes <= 0) if (r < 0 || nbytes <= 0)
return -errno; return -errno;
buf = malloc(nbytes); buf = malloc(nbytes);
skipping to change at line 882 skipping to change at line 856
else if (ev->mask & IN_IGNORED) else if (ev->mask & IN_IGNORED)
udev_watch_end(udev, dev); udev_watch_end(udev, dev);
udev_device_unref(dev); udev_device_unref(dev);
} }
free(buf); free(buf);
return 0; return 0;
} }
static void handle_signal(struct udev *udev, int signo) static void handle_signal(struct udev *udev, int signo) {
{
switch (signo) { switch (signo) {
case SIGINT: case SIGINT:
case SIGTERM: case SIGTERM:
udev_exit = true; udev_exit = true;
break; break;
case SIGCHLD: case SIGCHLD:
for (;;) { for (;;) {
pid_t pid; pid_t pid;
int status; int status;
struct udev_list_node *loop, *tmp; struct udev_list_node *loop, *tmp;
skipping to change at line 943 skipping to change at line 916
break; break;
} }
} }
break; break;
case SIGHUP: case SIGHUP:
reload = true; reload = true;
break; break;
} }
} }
static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) {
{
int ctrl = -1, netlink = -1; int ctrl = -1, netlink = -1;
int fd, n; int fd, n;
n = sd_listen_fds(true); n = sd_listen_fds(true);
if (n <= 0) if (n <= 0)
return -1; return -1;
for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) { for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) {
if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) { if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) {
if (ctrl >= 0) if (ctrl >= 0)
skipping to change at line 985 skipping to change at line 957
*rnetlink = netlink; *rnetlink = netlink;
return 0; return 0;
} }
/* /*
* read the kernel commandline, in case we need to get into debug mode * read the kernel commandline, in case we need to get into debug mode
* udev.log-priority=<level> syslog priority * udev.log-priority=<level> syslog priority
* udev.children-max=<number of workers> events are fully serialized if set to 1 * udev.children-max=<number of workers> events are fully serialized if set to 1
* udev.exec-delay=<number of seconds> delay execution of every execut ed program * udev.exec-delay=<number of seconds> delay execution of every execut ed program
*/ */
static void kernel_cmdline_options(struct udev *udev) static void kernel_cmdline_options(struct udev *udev) {
{
_cleanup_free_ char *line = NULL; _cleanup_free_ char *line = NULL;
char *w, *state; const char *word, *state;
size_t l; size_t l;
int r; int r;
r = proc_cmdline(&line); r = proc_cmdline(&line);
if (r < 0) if (r < 0)
log_warning("Failed to read /proc/cmdline, ignoring: %s", s trerror(-r)); log_warning("Failed to read /proc/cmdline, ignoring: %s", s trerror(-r));
if (r <= 0) if (r <= 0)
return; return;
FOREACH_WORD_QUOTED(w, l, line, state) { FOREACH_WORD_QUOTED(word, l, line, state) {
char *s, *opt; char *s, *opt;
s = strndup(w, l); s = strndup(word, l);
if (!s) if (!s)
break; break;
/* accept the same options for the initrd, prefixed with "r d." */ /* accept the same options for the initrd, prefixed with "r d." */
if (in_initrd() && startswith(s, "rd.")) if (in_initrd() && startswith(s, "rd."))
opt = s + 3; opt = s + 3;
else else
opt = s; opt = s;
if (startswith(opt, "udev.log-priority=")) { if (startswith(opt, "udev.log-priority=")) {
int prio; int prio;
prio = util_log_priority(opt + 18); prio = util_log_priority(opt + 18);
log_set_max_level(prio); log_set_max_level(prio);
udev_set_log_priority(udev, prio); udev_set_log_priority(udev, prio);
} else if (startswith(opt, "udev.children-max=")) { } else if (startswith(opt, "udev.children-max=")) {
children_max = strtoul(opt + 18, NULL, 0); children_max = strtoul(opt + 18, NULL, 0);
} else if (startswith(opt, "udev.exec-delay=")) { } else if (startswith(opt, "udev.exec-delay=")) {
exec_delay = strtoul(opt + 16, NULL, 0); exec_delay = strtoul(opt + 16, NULL, 0);
} else if (startswith(opt, "udev.event-timeout=")) {
event_timeout_usec = strtoul(opt + 16, NULL, 0) * U
SEC_PER_SEC;
} }
free(s); free(s);
} }
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{
struct udev *udev; struct udev *udev;
sigset_t mask; sigset_t mask;
int daemonize = false; int daemonize = false;
int resolve_names = 1; int resolve_names = 1;
static const struct option options[] = { static const struct option options[] = {
{ "daemon", no_argument, NULL, 'd' }, { "daemon", no_argument, NULL, 'd' },
{ "debug", no_argument, NULL, 'D' }, { "debug", no_argument, NULL, 'D' },
{ "children-max", required_argument, NULL, 'c' }, { "children-max", required_argument, NULL, 'c' },
{ "exec-delay", required_argument, NULL, 'e' }, { "exec-delay", required_argument, NULL, 'e' },
{ "event-timeout", required_argument, NULL, 't' },
{ "resolve-names", required_argument, NULL, 'N' }, { "resolve-names", required_argument, NULL, 'N' },
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
{} {}
}; };
int fd_ctrl = -1; int fd_ctrl = -1;
int fd_netlink = -1; int fd_netlink = -1;
int fd_worker = -1; int fd_worker = -1;
struct epoll_event ep_ctrl, ep_inotify, ep_signal, ep_netlink, ep_w orker; struct epoll_event ep_ctrl, ep_inotify, ep_signal, ep_netlink, ep_w orker;
struct udev_ctrl_connection *ctrl_conn = NULL; struct udev_ctrl_connection *ctrl_conn = NULL;
skipping to change at line 1081 skipping to change at line 1054
switch (option) { switch (option) {
case 'd': case 'd':
daemonize = true; daemonize = true;
break; break;
case 'c': case 'c':
children_max = strtoul(optarg, NULL, 0); children_max = strtoul(optarg, NULL, 0);
break; break;
case 'e': case 'e':
exec_delay = strtoul(optarg, NULL, 0); exec_delay = strtoul(optarg, NULL, 0);
break; break;
case 't':
event_timeout_usec = strtoul(optarg, NULL, 0) * USE
C_PER_SEC;
break;
case 'D': case 'D':
debug = true; debug = true;
log_set_max_level(LOG_DEBUG); log_set_max_level(LOG_DEBUG);
udev_set_log_priority(udev, LOG_DEBUG); udev_set_log_priority(udev, LOG_DEBUG);
break; break;
case 'N': case 'N':
if (streq(optarg, "early")) { if (streq(optarg, "early")) {
resolve_names = 1; resolve_names = 1;
} else if (streq(optarg, "late")) { } else if (streq(optarg, "late")) {
resolve_names = 0; resolve_names = 0;
skipping to change at line 1105 skipping to change at line 1081
log_error("resolve-names must be early, lat e or never"); log_error("resolve-names must be early, lat e or never");
goto exit; goto exit;
} }
break; break;
case 'h': case 'h':
printf("Usage: udevd OPTIONS\n" printf("Usage: udevd OPTIONS\n"
" --daemon\n" " --daemon\n"
" --debug\n" " --debug\n"
" --children-max=<maximum number of workers >\n" " --children-max=<maximum number of workers >\n"
" --exec-delay=<seconds to wait before exec uting RUN=>\n" " --exec-delay=<seconds to wait before exec uting RUN=>\n"
" --event-timeout=<seconds to wait before t erminating an event>\n"
" --resolve-names=early|late|never\n" " --resolve-names=early|late|never\n"
" --version\n" " --version\n"
" --help\n" " --help\n"
"\n"); "\n");
goto exit; goto exit;
case 'V': case 'V':
printf("%s\n", VERSION); printf("%s\n", VERSION);
goto exit; goto exit;
default: default:
goto exit; goto exit;
skipping to change at line 1418 skipping to change at line 1395
worker_kill(udev); worker_kill(udev);
} }
/* check for hanging events */ /* check for hanging events */
udev_list_node_foreach(loop, &worker_list) { udev_list_node_foreach(loop, &worker_list) {
struct worker *worker = node_to_worker(loop ); struct worker *worker = node_to_worker(loop );
if (worker->state != WORKER_RUNNING) if (worker->state != WORKER_RUNNING)
continue; continue;
if ((now(CLOCK_MONOTONIC) - worker->event_s if ((now(CLOCK_MONOTONIC) - worker->event_s
tart_usec) > 30 * USEC_PER_SEC) { tart_usec) > event_timeout_usec) {
log_error("worker [%u] %s timeout; log_error("worker [%u] %s timeout;
kill it", worker->pid, kill it", worker->pid, worker->event->devpath);
worker->event ? worker->event->
devpath : "<idle>");
kill(worker->pid, SIGKILL); kill(worker->pid, SIGKILL);
worker->state = WORKER_KILLED; worker->state = WORKER_KILLED;
/* drop reference taken for state ' running' */ /* drop reference taken for state ' running' */
worker_unref(worker); worker_unref(worker);
if (worker->event) { log_error("seq %llu '%s' killed", u
log_error("seq %llu '%s' ki dev_device_get_seqnum(worker->event->dev), worker->event->devpath);
lled", udev_device_get_seqnum(worker->event->dev), worker->event->devpath); worker->event->exitcode = -64;
worker->event->exitcode = - event_queue_delete(worker->event);
64; worker->event = NULL;
event_queue_delete(worker->
event);
worker->event = NULL;
}
} }
} }
} }
is_worker = is_signal = is_inotify = is_netlink = is_ctrl = false; is_worker = is_signal = is_inotify = is_netlink = is_ctrl = false;
for (i = 0; i < fdcount; i++) { for (i = 0; i < fdcount; i++) {
if (ev[i].data.fd == fd_worker && ev[i].events & EP OLLIN) if (ev[i].data.fd == fd_worker && ev[i].events & EP OLLIN)
is_worker = true; is_worker = true;
else if (ev[i].data.fd == fd_netlink && ev[i].event s & EPOLLIN) else if (ev[i].data.fd == fd_netlink && ev[i].event s & EPOLLIN)
 End of changes. 38 change blocks. 
89 lines changed or deleted 59 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/