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/ |