1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-11 09:18:07 +03:00

util: add timeout to generator execution

This commit is contained in:
Lennart Poettering 2014-03-06 02:19:06 +01:00
parent 6a3f892a23
commit aa62a8936f
5 changed files with 108 additions and 92 deletions

View File

@ -2657,7 +2657,7 @@ void manager_run_generators(Manager *m) {
argv[4] = NULL;
RUN_WITH_UMASK(0022)
execute_directory(generator_path, d, (char**) argv);
execute_directory(generator_path, d, DEFAULT_TIMEOUT_USEC, (char**) argv);
finish:
trim_generator_dir(m, &m->generator_unit_path);

View File

@ -368,7 +368,7 @@ int main(int argc, char *argv[]) {
arguments[0] = NULL;
arguments[1] = arg_verb;
arguments[2] = NULL;
execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);
execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
if (!in_container && !in_initrd() &&
access("/run/initramfs/shutdown", X_OK) == 0) {

View File

@ -3684,56 +3684,74 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
return endswith(de->d_name, suffix);
}
void execute_directory(const char *directory, DIR *d, char *argv[]) {
DIR *_d = NULL;
struct dirent *de;
Hashmap *pids = NULL;
void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv[]) {
pid_t executor_pid;
int r;
assert(directory);
/* Executes all binaries in a directory in parallel and
* waits for them to finish. */
/* Executes all binaries in a directory in parallel and waits
* for them to finish. Optionally a timeout is applied. */
executor_pid = fork();
if (executor_pid < 0) {
log_error("Failed to fork: %m");
return;
} else if (executor_pid == 0) {
_cleanup_hashmap_free_free_ Hashmap *pids = NULL;
_cleanup_closedir_ DIR *_d = NULL;
struct dirent *de;
sigset_t ss;
/* We fork this all off from a child process so that
* we can somewhat cleanly make use of SIGALRM to set
* a time limit */
reset_all_signal_handlers();
assert_se(sigemptyset(&ss) == 0);
assert_se(sigprocmask(SIG_SETMASK, &ss, NULL) == 0);
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
if (!d) {
if (!(_d = opendir(directory))) {
d = _d = opendir(directory);
if (!d) {
if (errno == ENOENT)
return;
_exit(EXIT_SUCCESS);
log_error("Failed to enumerate directory %s: %m", directory);
return;
_exit(EXIT_FAILURE);
}
}
d = _d;
pids = hashmap_new(NULL, NULL);
if (!pids) {
log_oom();
_exit(EXIT_FAILURE);
}
if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) {
log_error("Failed to allocate set.");
goto finish;
}
while ((de = readdir(d))) {
char *path;
FOREACH_DIRENT(de, d, break) {
_cleanup_free_ char *path = NULL;
pid_t pid;
int k;
if (!dirent_is_file(de))
continue;
if (asprintf(&path, "%s/%s", directory, de->d_name) < 0) {
log_oom();
continue;
_exit(EXIT_FAILURE);
}
if ((pid = fork()) < 0) {
pid = fork();
if (pid < 0) {
log_error("Failed to fork: %m");
free(path);
continue;
}
if (pid == 0) {
} else if (pid == 0) {
char *_argv[2];
/* Child */
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
if (!argv) {
_argv[0] = path;
@ -3743,52 +3761,46 @@ void execute_directory(const char *directory, DIR *d, char *argv[]) {
argv[0] = path;
execv(path, argv);
log_error("Failed to execute %s: %m", path);
_exit(EXIT_FAILURE);
}
log_debug("Spawned %s as %lu", path, (unsigned long) pid);
if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) {
log_error("Failed to add PID to set: %s", strerror(-k));
free(path);
log_debug("Spawned %s as " PID_FMT ".", path, pid);
r = hashmap_put(pids, UINT_TO_PTR(pid), path);
if (r < 0) {
log_oom();
_exit(EXIT_FAILURE);
}
path = NULL;
}
/* Abort execution of this process after the
* timout. We simply rely on SIGALRM as default action
* terminating the process, and turn on alarm(). */
if (timeout != (usec_t) -1)
alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
while (!hashmap_isempty(pids)) {
pid_t pid = PTR_TO_UINT(hashmap_first_key(pids));
siginfo_t si = {};
char *path;
_cleanup_free_ char *path = NULL;
pid_t pid;
if (waitid(P_PID, pid, &si, WEXITED) < 0) {
pid = PTR_TO_UINT(hashmap_first_key(pids));
assert(pid > 0);
if (errno == EINTR)
continue;
path = hashmap_remove(pids, UINT_TO_PTR(pid));
assert(path);
log_error("waitid() failed: %m");
goto finish;
wait_for_terminate_and_warn(path, pid);
}
if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) {
if (!is_clean_exit(si.si_code, si.si_status, NULL)) {
if (si.si_code == CLD_EXITED)
log_error("%s exited with exit status %i.", path, si.si_status);
else
log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status));
} else
log_debug("%s exited successfully.", path);
free(path);
}
_exit(EXIT_SUCCESS);
}
finish:
if (_d)
closedir(_d);
if (pids)
hashmap_free_free(pids);
wait_for_terminate_and_warn(directory, executor_pid);
}
int kill_and_sigcont(pid_t pid, int sig) {

View File

@ -481,7 +481,7 @@ bool tty_is_console(const char *tty) _pure_;
int vtnr_from_tty(const char *tty);
const char *default_term_for_tty(const char *tty);
void execute_directory(const char *directory, DIR *_d, char *argv[]);
void execute_directory(const char *directory, DIR *_d, usec_t timeout, char *argv[]);
int kill_and_sigcont(pid_t pid, int sig);

View File

@ -25,14 +25,15 @@
#include <string.h>
#include <getopt.h>
#include "systemd/sd-id128.h"
#include "systemd/sd-messages.h"
#include "sd-id128.h"
#include "sd-messages.h"
#include "log.h"
#include "util.h"
#include "strv.h"
#include "fileio.h"
#include "build.h"
#include "sleep-config.h"
#include "def.h"
static char* arg_verb = NULL;
@ -41,9 +42,12 @@ static int write_mode(char **modes) {
char **mode;
STRV_FOREACH(mode, modes) {
int k = write_string_file("/sys/power/disk", *mode);
int k;
k = write_string_file("/sys/power/disk", *mode);
if (k == 0)
return 0;
log_debug("Failed to write '%s' to /sys/power/disk: %s",
*mode, strerror(-k));
if (r == 0)
@ -106,7 +110,7 @@ static int execute(char **modes, char **states) {
arguments[1] = (char*) "pre";
arguments[2] = arg_verb;
arguments[3] = NULL;
execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments);
execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
log_struct(LOG_INFO,
MESSAGE_ID(SD_MESSAGE_SLEEP_START),
@ -125,7 +129,7 @@ static int execute(char **modes, char **states) {
NULL);
arguments[1] = (char*) "post";
execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments);
execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
return r;
}