summaryrefslogtreecommitdiffstats
path: root/src/udev/udev-spawn.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/udev/udev-spawn.c94
1 files changed, 58 insertions, 36 deletions
diff --git a/src/udev/udev-spawn.c b/src/udev/udev-spawn.c
index 67a3005..3f867a8 100644
--- a/src/udev/udev-spawn.c
+++ b/src/udev/udev-spawn.c
@@ -23,6 +23,7 @@ typedef struct Spawn {
usec_t timeout_usec;
int timeout_signal;
usec_t event_birth_usec;
+ usec_t cmd_birth_usec;
bool accept_failure;
int fd_stdout;
int fd_stderr;
@@ -105,19 +106,18 @@ static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
DEVICE_TRACE_POINT(spawn_timeout, spawn->device, spawn->cmd);
- kill_and_sigcont(spawn->pid, spawn->timeout_signal);
-
- log_device_error(spawn->device, "Spawned process '%s' ["PID_FMT"] timed out after %s, killing",
+ log_device_error(spawn->device, "Spawned process '%s' ["PID_FMT"] timed out after %s, killing.",
spawn->cmd, spawn->pid,
FORMAT_TIMESPAN(spawn->timeout_usec, USEC_PER_SEC));
+ kill_and_sigcont(spawn->pid, spawn->timeout_signal);
return 1;
}
static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
Spawn *spawn = ASSERT_PTR(userdata);
- log_device_warning(spawn->device, "Spawned process '%s' ["PID_FMT"] is taking longer than %s to complete",
+ log_device_warning(spawn->device, "Spawned process '%s' ["PID_FMT"] is taking longer than %s to complete.",
spawn->cmd, spawn->pid,
FORMAT_TIMESPAN(spawn->timeout_warn_usec, USEC_PER_SEC));
@@ -164,31 +164,20 @@ static int spawn_wait(Spawn *spawn) {
if (r < 0)
return log_device_debug_errno(spawn->device, r, "Failed to allocate sd-event object: %m");
- if (spawn->timeout_usec > 0) {
- usec_t usec, age_usec;
-
- usec = now(CLOCK_MONOTONIC);
- age_usec = usec - spawn->event_birth_usec;
- if (age_usec < spawn->timeout_usec) {
- if (spawn->timeout_warn_usec > 0 &&
- spawn->timeout_warn_usec < spawn->timeout_usec &&
- spawn->timeout_warn_usec > age_usec) {
- spawn->timeout_warn_usec -= age_usec;
-
- r = sd_event_add_time(e, NULL, CLOCK_MONOTONIC,
- usec + spawn->timeout_warn_usec, USEC_PER_SEC,
- on_spawn_timeout_warning, spawn);
- if (r < 0)
- return log_device_debug_errno(spawn->device, r, "Failed to create timeout warning event source: %m");
- }
-
- spawn->timeout_usec -= age_usec;
-
+ if (spawn->timeout_usec != USEC_INFINITY) {
+ if (spawn->timeout_warn_usec < spawn->timeout_usec) {
r = sd_event_add_time(e, NULL, CLOCK_MONOTONIC,
- usec + spawn->timeout_usec, USEC_PER_SEC, on_spawn_timeout, spawn);
+ usec_add(spawn->cmd_birth_usec, spawn->timeout_warn_usec), USEC_PER_SEC,
+ on_spawn_timeout_warning, spawn);
if (r < 0)
- return log_device_debug_errno(spawn->device, r, "Failed to create timeout event source: %m");
+ return log_device_debug_errno(spawn->device, r, "Failed to create timeout warning event source: %m");
}
+
+ r = sd_event_add_time(e, NULL, CLOCK_MONOTONIC,
+ usec_add(spawn->cmd_birth_usec, spawn->timeout_usec), USEC_PER_SEC,
+ on_spawn_timeout, spawn);
+ if (r < 0)
+ return log_device_debug_errno(spawn->device, r, "Failed to create timeout event source: %m");
}
if (spawn->fd_stdout >= 0) {
@@ -222,8 +211,6 @@ static int spawn_wait(Spawn *spawn) {
int udev_event_spawn(
UdevEvent *event,
- usec_t timeout_usec,
- int timeout_signal,
bool accept_failure,
const char *cmd,
char *result,
@@ -238,9 +225,30 @@ int udev_event_spawn(
int r;
assert(event);
+ assert(IN_SET(event->event_mode, EVENT_UDEV_WORKER, EVENT_UDEVADM_TEST, EVENT_TEST_RULE_RUNNER, EVENT_TEST_SPAWN));
assert(event->dev);
+ assert(cmd);
assert(result || result_size == 0);
+ if (event->event_mode == EVENT_UDEVADM_TEST &&
+ !STARTSWITH_SET(cmd, "ata_id", "cdrom_id", "dmi_memory_id", "fido_id", "mtd_probe", "scsi_id")) {
+ log_device_debug(event->dev, "Running in test mode, skipping execution of '%s'.", cmd);
+ result[0] = '\0';
+ if (ret_truncated)
+ *ret_truncated = false;
+ return 0;
+ }
+
+ int timeout_signal = event->worker ? event->worker->timeout_signal : SIGKILL;
+ usec_t timeout_usec = event->worker ? event->worker->timeout_usec : DEFAULT_WORKER_TIMEOUT_USEC;
+ usec_t now_usec = now(CLOCK_MONOTONIC);
+ usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec);
+ usec_t cmd_timeout_usec = usec_sub_unsigned(timeout_usec, age_usec);
+ if (cmd_timeout_usec <= 0)
+ return log_device_warning_errno(event->dev, SYNTHETIC_ERRNO(ETIME),
+ "The event already takes longer (%s) than the timeout (%s), skipping execution of '%s'.",
+ FORMAT_TIMESPAN(age_usec, 1), FORMAT_TIMESPAN(timeout_usec, 1), cmd);
+
/* pipes from child to parent */
if (result || log_get_max_level() >= LOG_INFO)
if (pipe2(outpipe, O_NONBLOCK|O_CLOEXEC) != 0)
@@ -300,10 +308,11 @@ int udev_event_spawn(
.cmd = cmd,
.pid = pid,
.accept_failure = accept_failure,
- .timeout_warn_usec = udev_warn_timeout(timeout_usec),
- .timeout_usec = timeout_usec,
+ .timeout_warn_usec = udev_warn_timeout(cmd_timeout_usec),
+ .timeout_usec = cmd_timeout_usec,
.timeout_signal = timeout_signal,
.event_birth_usec = event->birth_usec,
+ .cmd_birth_usec = now_usec,
.fd_stdout = outpipe[READ_END],
.fd_stderr = errpipe[READ_END],
.result = result,
@@ -323,29 +332,42 @@ int udev_event_spawn(
return r; /* 0 for success, and positive if the program failed */
}
-void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_signal) {
+void udev_event_execute_run(UdevEvent *event) {
const char *command;
void *val;
int r;
+ assert(event);
+
ORDERED_HASHMAP_FOREACH_KEY(val, command, event->run_list) {
UdevBuiltinCommand builtin_cmd = PTR_TO_UDEV_BUILTIN_CMD(val);
if (builtin_cmd != _UDEV_BUILTIN_INVALID) {
log_device_debug(event->dev, "Running built-in command \"%s\"", command);
- r = udev_builtin_run(event, builtin_cmd, command, false);
+ r = udev_builtin_run(event, builtin_cmd, command);
if (r < 0)
log_device_debug_errno(event->dev, r, "Failed to run built-in command \"%s\", ignoring: %m", command);
} else {
- if (event->exec_delay_usec > 0) {
+ if (event->worker && event->worker->exec_delay_usec > 0) {
+ usec_t timeout_usec = event->worker ? event->worker->timeout_usec : DEFAULT_WORKER_TIMEOUT_USEC;
+ usec_t now_usec = now(CLOCK_MONOTONIC);
+ usec_t age_usec = usec_sub_unsigned(now_usec, event->birth_usec);
+
+ if (event->worker->exec_delay_usec >= usec_sub_unsigned(timeout_usec, age_usec)) {
+ log_device_warning(event->dev,
+ "Cannot delaying execution of \"%s\" for %s, skipping.",
+ command, FORMAT_TIMESPAN(event->worker->exec_delay_usec, USEC_PER_SEC));
+ continue;
+ }
+
log_device_debug(event->dev, "Delaying execution of \"%s\" for %s.",
- command, FORMAT_TIMESPAN(event->exec_delay_usec, USEC_PER_SEC));
- (void) usleep_safe(event->exec_delay_usec);
+ command, FORMAT_TIMESPAN(event->worker->exec_delay_usec, USEC_PER_SEC));
+ (void) usleep_safe(event->worker->exec_delay_usec);
}
log_device_debug(event->dev, "Running command \"%s\"", command);
- r = udev_event_spawn(event, timeout_usec, timeout_signal, false, command, NULL, 0, NULL);
+ r = udev_event_spawn(event, /* accept_failure = */ false, command, NULL, 0, NULL);
if (r < 0)
log_device_warning_errno(event->dev, r, "Failed to execute '%s', ignoring: %m", command);
else if (r > 0) /* returned value is positive when program fails */