diff options
Diffstat (limited to 'src/udev/udev-spawn.c')
-rw-r--r-- | src/udev/udev-spawn.c | 94 |
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 */ |