summaryrefslogtreecommitdiff
path: root/src/udev/udev-event.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/udev/udev-event.c')
-rw-r--r--src/udev/udev-event.c266
1 files changed, 130 insertions, 136 deletions
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index bc115f112d..4dcf8f2e1c 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -23,7 +23,6 @@
#include <errno.h>
#include <ctype.h>
#include <string.h>
-#include <time.h>
#include <net/if.h>
#include <sys/prctl.h>
#include <poll.h>
@@ -31,8 +30,19 @@
#include <sys/wait.h>
#include <sys/signalfd.h>
-#include "udev.h"
#include "rtnl-util.h"
+#include "event-util.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "signal-util.h"
+#include "udev.h"
+
+typedef struct Spawn {
+ const char *cmd;
+ pid_t pid;
+ usec_t timeout_warn;
+ usec_t timeout;
+} Spawn;
struct udev_event *udev_event_new(struct udev_device *dev) {
struct udev *udev = udev_device_get_udev(dev);
@@ -45,8 +55,7 @@ struct udev_event *udev_event_new(struct udev_device *dev) {
event->udev = udev;
udev_list_init(udev, &event->run_list, false);
udev_list_init(udev, &event->seclabel_list, false);
- event->fd_signal = -1;
- event->birth_usec = now(CLOCK_MONOTONIC);
+ event->birth_usec = clock_boottime_or_monotonic();
return event;
}
@@ -110,6 +119,8 @@ size_t udev_event_apply_format(struct udev_event *event, const char *src, char *
char *s;
size_t l;
+ assert(dev);
+
from = src;
s = dest;
l = size;
@@ -374,7 +385,7 @@ out:
}
static int spawn_exec(struct udev_event *event,
- const char *cmd, char *const argv[], char **envp, const sigset_t *sigmask,
+ const char *cmd, char *const argv[], char **envp,
int fd_stdout, int fd_stderr) {
_cleanup_close_ int fd = -1;
@@ -402,9 +413,8 @@ static int spawn_exec(struct udev_event *event,
/* terminate child in case parent goes away */
prctl(PR_SET_PDEATHSIG, SIGTERM);
- /* restore original udev sigmask before exec */
- if (sigmask)
- sigprocmask(SIG_SETMASK, sigmask, NULL);
+ /* restore sigmask before exec */
+ (void) reset_signal_mask();
execve(argv[0], argv, envp);
@@ -467,7 +477,7 @@ static void spawn_read(struct udev_event *event,
if (timeout_usec > 0) {
usec_t age_usec;
- age_usec = now(CLOCK_MONOTONIC) - event->birth_usec;
+ age_usec = clock_boottime_or_monotonic() - event->birth_usec;
if (age_usec >= timeout_usec) {
log_error("timeout '%s'", cmd);
return;
@@ -540,102 +550,116 @@ static void spawn_read(struct udev_event *event,
result[respos] = '\0';
}
+static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+ Spawn *spawn = userdata;
+ char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
+
+ assert(spawn);
+
+ kill_and_sigcont(spawn->pid, SIGKILL);
+
+ log_error("spawned process '%s' ["PID_FMT"] timed out after %s, killing", spawn->cmd, spawn->pid,
+ format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout));
+
+ return 1;
+}
+
+static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
+ Spawn *spawn = userdata;
+ char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
+
+ assert(spawn);
+
+ log_warning("spawned process '%s' ["PID_FMT"] is taking longer than %s to complete", spawn->cmd, spawn->pid,
+ format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout));
+
+ return 1;
+}
+
+static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
+ Spawn *spawn = userdata;
+
+ assert(spawn);
+
+ switch (si->si_code) {
+ case CLD_EXITED:
+ if (si->si_status != 0)
+ log_warning("process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
+ else {
+ log_debug("process '%s' succeeded.", spawn->cmd);
+ sd_event_exit(sd_event_source_get_event(s), 0);
+
+ return 1;
+ }
+
+ break;
+ case CLD_KILLED:
+ case CLD_DUMPED:
+ log_warning("process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status));
+
+ break;
+ default:
+ log_error("process '%s' failed due to unknown reason.", spawn->cmd);
+ }
+
+ sd_event_exit(sd_event_source_get_event(s), -EIO);
+
+ return 1;
+}
+
static int spawn_wait(struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
const char *cmd, pid_t pid) {
- struct pollfd pfd[1];
- int err = 0;
-
- pfd[0].events = POLLIN;
- pfd[0].fd = event->fd_signal;
+ Spawn spawn = {
+ .cmd = cmd,
+ .pid = pid,
+ };
+ _cleanup_event_unref_ sd_event *e = NULL;
+ int r, ret;
- while (pid > 0) {
- int timeout;
- int timeout_warn = 0;
- int fdcount;
+ r = sd_event_new(&e);
+ if (r < 0)
+ return r;
- if (timeout_usec > 0) {
- usec_t age_usec;
+ if (timeout_usec > 0) {
+ usec_t usec, age_usec;
- age_usec = now(CLOCK_MONOTONIC) - event->birth_usec;
- if (age_usec >= timeout_usec)
- timeout = 1000;
- else {
- if (timeout_warn_usec > 0)
- timeout_warn = ((timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC;
+ usec = now(clock_boottime_or_monotonic());
+ age_usec = usec - event->birth_usec;
+ if (age_usec < timeout_usec) {
+ if (timeout_warn_usec > 0 && timeout_warn_usec < timeout_usec && age_usec < timeout_warn_usec) {
+ spawn.timeout_warn = timeout_warn_usec - age_usec;
- timeout = ((timeout_usec - timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC;
+ r = sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
+ usec + spawn.timeout_warn, USEC_PER_SEC,
+ on_spawn_timeout_warning, &spawn);
+ if (r < 0)
+ return r;
}
- } else {
- timeout = -1;
- }
- fdcount = poll(pfd, 1, timeout_warn);
- if (fdcount < 0) {
- if (errno == EINTR)
- continue;
- err = -errno;
- log_error_errno(errno, "failed to poll: %m");
- goto out;
- }
- if (fdcount == 0) {
- log_warning("slow: '%s' ["PID_FMT"]", cmd, pid);
+ spawn.timeout = timeout_usec - age_usec;
- fdcount = poll(pfd, 1, timeout);
- if (fdcount < 0) {
- if (errno == EINTR)
- continue;
- err = -errno;
- log_error_errno(errno, "failed to poll: %m");
- goto out;
- }
- if (fdcount == 0) {
- log_error("timeout: killing '%s' ["PID_FMT"]", cmd, pid);
- kill(pid, SIGKILL);
- }
+ r = sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
+ usec + spawn.timeout, USEC_PER_SEC, on_spawn_timeout, &spawn);
+ if (r < 0)
+ return r;
}
+ }
- if (pfd[0].revents & POLLIN) {
- struct signalfd_siginfo fdsi;
- int status;
- ssize_t size;
+ r = sd_event_add_child(e, NULL, pid, WEXITED, on_spawn_sigchld, &spawn);
+ if (r < 0)
+ return r;
- size = read(event->fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
- if (size != sizeof(struct signalfd_siginfo))
- continue;
+ r = sd_event_loop(e);
+ if (r < 0)
+ return r;
- switch (fdsi.ssi_signo) {
- case SIGTERM:
- event->sigterm = true;
- break;
- case SIGCHLD:
- if (waitpid(pid, &status, WNOHANG) < 0)
- break;
- if (WIFEXITED(status)) {
- log_debug("'%s' ["PID_FMT"] exit with return code %i", cmd, pid, WEXITSTATUS(status));
- if (WEXITSTATUS(status) != 0)
- err = -1;
- } else if (WIFSIGNALED(status)) {
- log_error("'%s' ["PID_FMT"] terminated by signal %i (%s)", cmd, pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
- err = -1;
- } else if (WIFSTOPPED(status)) {
- log_error("'%s' ["PID_FMT"] stopped", cmd, pid);
- err = -1;
- } else if (WIFCONTINUED(status)) {
- log_error("'%s' ["PID_FMT"] continued", cmd, pid);
- err = -1;
- } else {
- log_error("'%s' ["PID_FMT"] exit with status 0x%04x", cmd, pid, status);
- err = -1;
- }
- pid = 0;
- break;
- }
- }
- }
-out:
- return err;
+ r = sd_event_get_exit_code(e, &ret);
+ if (r < 0)
+ return r;
+
+ return ret;
}
int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]) {
@@ -674,7 +698,7 @@ out:
int udev_event_spawn(struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
- const char *cmd, char **envp, const sigset_t *sigmask,
+ const char *cmd, char **envp,
char *result, size_t ressize) {
int outpipe[2] = {-1, -1};
int errpipe[2] = {-1, -1};
@@ -724,7 +748,7 @@ int udev_event_spawn(struct udev_event *event,
log_debug("starting '%s'", cmd);
- spawn_exec(event, cmd, argv, envp, sigmask,
+ spawn_exec(event, cmd, argv, envp,
outpipe[WRITE_END], errpipe[WRITE_END]);
_exit(2 );
@@ -786,59 +810,41 @@ static int rename_netif(struct udev_event *event) {
void udev_event_execute_rules(struct udev_event *event,
usec_t timeout_usec, usec_t timeout_warn_usec,
struct udev_list *properties_list,
- struct udev_rules *rules,
- const sigset_t *sigmask) {
+ struct udev_rules *rules) {
struct udev_device *dev = event->dev;
if (udev_device_get_subsystem(dev) == NULL)
return;
if (streq(udev_device_get_action(dev), "remove")) {
- udev_device_read_db(dev, NULL);
- udev_device_delete_db(dev);
+ udev_device_read_db(dev);
udev_device_tag_index(dev, NULL, false);
+ udev_device_delete_db(dev);
if (major(udev_device_get_devnum(dev)) != 0)
udev_watch_end(event->udev, dev);
udev_rules_apply_to_event(rules, event,
timeout_usec, timeout_warn_usec,
- properties_list,
- sigmask);
+ properties_list);
if (major(udev_device_get_devnum(dev)) != 0)
udev_node_remove(dev);
} else {
- event->dev_db = udev_device_shallow_clone(dev);
+ event->dev_db = udev_device_clone_with_db(dev);
if (event->dev_db != NULL) {
- udev_device_read_db(event->dev_db, NULL);
- udev_device_set_info_loaded(event->dev_db);
-
/* disable watch during event processing */
if (major(udev_device_get_devnum(dev)) != 0)
udev_watch_end(event->udev, event->dev_db);
}
if (major(udev_device_get_devnum(dev)) == 0 &&
- streq(udev_device_get_action(dev), "move")) {
- struct udev_list_entry *entry;
-
- for ((entry = udev_device_get_properties_list_entry(event->dev_db)); entry; entry = udev_list_entry_get_next(entry)) {
- const char *key, *value;
- struct udev_list_entry *property;
-
- key = udev_list_entry_get_name(entry);
- value = udev_list_entry_get_value(entry);
-
- property = udev_device_add_property(dev, key, value);
- udev_list_entry_set_num(property, true);
- }
- }
+ streq(udev_device_get_action(dev), "move"))
+ udev_device_copy_properties(dev, event->dev_db);
udev_rules_apply_to_event(rules, event,
timeout_usec, timeout_warn_usec,
- properties_list,
- sigmask);
+ properties_list);
/* rename a new network interface, if needed */
if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") &&
@@ -850,20 +856,12 @@ void udev_event_execute_rules(struct udev_event *event,
log_warning_errno(r, "could not rename interface '%d' from '%s' to '%s': %m", udev_device_get_ifindex(dev),
udev_device_get_sysname(dev), event->name);
else {
- const char *interface_old;
-
- /* remember old name */
- interface_old = udev_device_get_sysname(dev);
-
r = udev_device_rename(dev, event->name);
if (r < 0)
log_warning_errno(r, "renamed interface '%d' from '%s' to '%s', but could not update udev_device: %m",
udev_device_get_ifindex(dev), udev_device_get_sysname(dev), event->name);
- else {
- udev_device_add_property(dev, "INTERFACE_OLD", interface_old);
- udev_device_add_property(dev, "INTERFACE", event->name);
+ else
log_debug("changed devpath to '%s'", udev_device_get_devpath(dev));
- }
}
}
@@ -898,22 +896,18 @@ void udev_event_execute_rules(struct udev_event *event,
}
/* preserve old, or get new initialization timestamp */
- if (event->dev_db != NULL && udev_device_get_usec_initialized(event->dev_db) > 0)
- udev_device_set_usec_initialized(event->dev, udev_device_get_usec_initialized(event->dev_db));
- else if (udev_device_get_usec_initialized(event->dev) == 0)
- udev_device_set_usec_initialized(event->dev, now(CLOCK_MONOTONIC));
+ udev_device_ensure_usec_initialized(event->dev, event->dev_db);
/* (re)write database file */
- udev_device_update_db(dev);
udev_device_tag_index(dev, event->dev_db, true);
+ udev_device_update_db(dev);
udev_device_set_is_initialized(dev);
- udev_device_unref(event->dev_db);
- event->dev_db = NULL;
+ event->dev_db = udev_device_unref(event->dev_db);
}
}
-void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, const sigset_t *sigmask) {
+void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec) {
struct udev_list_entry *list_entry;
udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) {
@@ -936,7 +930,7 @@ void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_
udev_event_apply_format(event, cmd, program, sizeof(program));
envp = udev_device_get_properties_envp(event->dev);
- udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, NULL, 0);
+ udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, NULL, 0);
}
}
}