static int children;
static int children_max;
static int exec_delay;
-static sigset_t orig_sigmask;
+static sigset_t sigmask_orig;
static UDEV_LIST(event_list);
static UDEV_LIST(worker_list);
static bool udev_exit;
close(fd_signal);
close(fd_ep);
close(worker_watch[READ_END]);
- udev_log_close();
- udev_log_init("udevd-work");
sigfillset(&mask);
fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
for (;;) {
struct udev_event *udev_event;
- struct worker_message msg = {};
- int err;
+ struct worker_message msg;
int failed = 0;
+ int err;
info(udev, "seq %llu running\n", udev_device_get_seqnum(dev));
udev_event = udev_event_new(dev);
goto out;
}
- /* set timeout to prevent hanging processes */
- alarm(UDEV_EVENT_TIMEOUT);
+ /* needed for SIGCHLD/SIGTERM in spawn() */
+ udev_event->fd_signal = fd_signal;
if (exec_delay > 0)
udev_event->exec_delay = exec_delay;
/* apply rules, create node, symlinks */
- err = udev_event_execute_rules(udev_event, rules);
-
- /* rules may change/disable the timeout */
- if (udev_device_get_event_timeout(dev) >= 0)
- alarm(udev_device_get_event_timeout(dev));
+ err = udev_event_execute_rules(udev_event, rules, &sigmask_orig);
if (err == 0)
- failed = udev_event_execute_run(udev_event, &orig_sigmask);
-
- alarm(0);
+ failed = udev_event_execute_run(udev_event, &sigmask_orig);
/* apply/restore inotify watch */
if (err == 0 && udev_event->inotify_watch) {
udev_monitor_send_device(worker_monitor, NULL, dev);
/* send udevd the result of the event execution */
+ memset(&msg, 0, sizeof(struct worker_message));
if (err != 0)
msg.exitcode = err;
else if (failed != 0)
send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0);
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;
+ if (udev_event->sigterm) {
+ udev_event_unref(udev_event);
+ goto out;
+ }
+
+ udev_event_unref(udev_event);
+
/* wait for more device messages from main udevd, or term signal */
while (dev == NULL) {
struct epoll_event ev[4];
int i;
fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1);
- if (fdcount < 0)
- continue;
+ if (fdcount < 0) {
+ if (errno == EINTR)
+ continue;
+ err = -errno;
+ err(udev, "failed to poll: %m\n");
+ goto out;
+ }
for (i = 0; i < fdcount; i++) {
if (ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN) {
switch (fdsi.ssi_signo) {
case SIGTERM:
goto out;
- case SIGALRM:
- rc = EXIT_FAILURE;
- goto out;
}
}
}
if (worker->pid != pid)
continue;
-
info(udev, "worker [%u] exit\n", pid);
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0)
+ err(udev, "worker [%u] exit with return code %i\n", pid, WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ err(udev, "worker [%u] terminated by signal %i (%s)\n",
+ pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
+ } else if (WIFSTOPPED(status)) {
+ err(udev, "worker [%u] stopped\n", pid);
+ } else if (WIFCONTINUED(status)) {
+ err(udev, "worker [%u] continued\n", pid);
+ } else {
+ err(udev, "worker [%u] exit with status 0x%04x\n", pid, status);
+ }
+
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- err(udev, "worker [%u] unexpectedly returned with status 0x%04x\n", pid, status);
if (worker->event != NULL) {
- err(udev, "worker [%u] failed while handling '%s'\n", pid, worker->event->devpath);
+ err(udev, "worker [%u] failed while handling '%s'\n",
+ pid, worker->event->devpath);
worker->event->exitcode = -32;
event_queue_delete(worker->event, true);
- /* drop reference from running event */
+ /* drop reference taken for state 'running' */
worker_unref(worker);
}
}
f = fopen("/dev/kmsg", "w");
if (f != NULL) {
- fprintf(f, "<30>udev[%u]: converting old udev database\n", getpid());
+ fprintf(f, "<30>udevd[%u]: converting old udev database\n", getpid());
fclose(f);
}
udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024);
+ /* create queue file before signalling 'ready', to make sure we block 'settle' */
+ udev_queue_export = udev_queue_export_new(udev);
+ if (udev_queue_export == NULL) {
+ err(udev, "error creating queue file\n");
+ goto exit;
+ }
+
if (daemonize) {
pid_t pid;
int fd;
rc = 4;
goto exit;
default:
- rc = 0;
- goto exit;
+ rc = EXIT_SUCCESS;
+ goto exit_keep_queue;
}
setsid();
f = fopen("/dev/kmsg", "w");
if (f != NULL) {
- fprintf(f, "<30>udev[%u]: starting version " VERSION "\n", getpid());
+ fprintf(f, "<30>udevd[%u]: starting version " VERSION "\n", getpid());
fclose(f);
}
/* block and listen to all signals on signalfd */
sigfillset(&mask);
- sigprocmask(SIG_SETMASK, &mask, &orig_sigmask);
+ sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (fd_signal < 0) {
fprintf(stderr, "error creating signalfd\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;
}
}
- udev_queue_export_cleanup(udev_queue_export);
- rc = 0;
+ rc = EXIT_SUCCESS;
exit:
+ udev_queue_export_cleanup(udev_queue_export);
+exit_keep_queue:
if (fd_ep >= 0)
close(fd_ep);
worker_list_cleanup(udev);