Simplify execute_directory()

Remove the optional sepearate opening of the directory,
it would be just too complicated with the change to
multiple directories.

Move the middle of execute_directory() to a seperate
function to make it easier to grok.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2015-01-08 17:30:07 -05:00
parent 87b934960a
commit 4968105790
6 changed files with 105 additions and 111 deletions

View file

@ -2776,7 +2776,6 @@ static void trim_generator_dir(Manager *m, char **generator) {
}
void manager_run_generators(Manager *m) {
_cleanup_closedir_ DIR *d = NULL;
const char *generator_path;
const char *argv[5];
int r;
@ -2787,13 +2786,13 @@ void manager_run_generators(Manager *m) {
return;
generator_path = m->running_as == SYSTEMD_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH;
d = opendir(generator_path);
if (!d) {
if (errno == ENOENT)
return;
log_error_errno(errno, "Failed to enumerate generator directory %s: %m",
generator_path);
/* Optimize by skipping the whole process by not creating output directories
* if no generators are found. */
if (access(generator_path, F_OK) != 0) {
if (errno != ENOENT)
log_error_errno(errno, "Failed to open generator directory %s: %m",
generator_path);
return;
}
@ -2816,7 +2815,7 @@ void manager_run_generators(Manager *m) {
argv[4] = NULL;
RUN_WITH_UMASK(0022)
execute_directory(generator_path, d, DEFAULT_TIMEOUT_USEC, (char**) argv);
execute_directory(generator_path, DEFAULT_TIMEOUT_USEC, (char**) argv);
finish:
trim_generator_dir(m, &m->generator_unit_path);

View file

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

View file

@ -4037,13 +4037,102 @@ 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, usec_t timeout, char *argv[]) {
static int do_execute(const char *directory, usec_t timeout, char *argv[]) {
_cleanup_hashmap_free_free_ Hashmap *pids = NULL;
_cleanup_closedir_ DIR *d;
struct dirent *de;
/* 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();
reset_signal_mask();
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
d = opendir(directory);
if (!d) {
if (errno == ENOENT)
return 0;
return log_error_errno(errno, "Failed to open directory %s: %m", directory);
}
pids = hashmap_new(NULL);
if (!pids)
return log_oom();
FOREACH_DIRENT(de, d, break) {
_cleanup_free_ char *path = NULL;
pid_t pid;
int r;
if (!dirent_is_file(de))
continue;
path = strjoin(directory, "/", de->d_name, NULL);
if (!path)
return log_oom();
pid = fork();
if (pid < 0) {
log_error_errno(errno, "Failed to fork: %m");
continue;
} else if (pid == 0) {
char *_argv[2];
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
if (!argv) {
_argv[0] = path;
_argv[1] = NULL;
argv = _argv;
} else
argv[0] = path;
execv(path, argv);
return log_error_errno(errno, "Failed to execute %s: %m", path);
}
log_debug("Spawned %s as " PID_FMT ".", path, pid);
r = hashmap_put(pids, UINT_TO_PTR(pid), path);
if (r < 0)
return log_oom();
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_INFINITY)
alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
while (!hashmap_isempty(pids)) {
_cleanup_free_ char *path = NULL;
pid_t pid;
pid = PTR_TO_UINT(hashmap_first_key(pids));
assert(pid > 0);
path = hashmap_remove(pids, UINT_TO_PTR(pid));
assert(path);
wait_for_terminate_and_warn(path, pid, true);
}
return 0;
}
void execute_directory(const char *directory, usec_t timeout, char *argv[]) {
pid_t executor_pid;
int r;
assert(directory);
/* Executes all binaries in a directory in parallel and waits
/* Executes all binaries in the directory in parallel and waits
* for them to finish. Optionally a timeout is applied. */
executor_pid = fork();
@ -4052,102 +4141,8 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv
return;
} else if (executor_pid == 0) {
_cleanup_hashmap_free_free_ Hashmap *pids = NULL;
_cleanup_closedir_ DIR *_d = NULL;
struct dirent *de;
/* 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();
reset_signal_mask();
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
if (!d) {
d = _d = opendir(directory);
if (!d) {
if (errno == ENOENT)
_exit(EXIT_SUCCESS);
log_error_errno(errno, "Failed to enumerate directory %s: %m", directory);
_exit(EXIT_FAILURE);
}
}
pids = hashmap_new(NULL);
if (!pids) {
log_oom();
_exit(EXIT_FAILURE);
}
FOREACH_DIRENT(de, d, break) {
_cleanup_free_ char *path = NULL;
pid_t pid;
if (!dirent_is_file(de))
continue;
path = strjoin(directory, "/", de->d_name, NULL);
if (!path) {
log_oom();
_exit(EXIT_FAILURE);
}
pid = fork();
if (pid < 0) {
log_error_errno(errno, "Failed to fork: %m");
continue;
} else if (pid == 0) {
char *_argv[2];
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
if (!argv) {
_argv[0] = path;
_argv[1] = NULL;
argv = _argv;
} else
argv[0] = path;
execv(path, argv);
log_error_errno(errno, "Failed to execute %s: %m", path);
_exit(EXIT_FAILURE);
}
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_INFINITY)
alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
while (!hashmap_isempty(pids)) {
_cleanup_free_ char *path = NULL;
pid_t pid;
pid = PTR_TO_UINT(hashmap_first_key(pids));
assert(pid > 0);
path = hashmap_remove(pids, UINT_TO_PTR(pid));
assert(path);
wait_for_terminate_and_warn(path, pid, true);
}
_exit(EXIT_SUCCESS);
r = do_execute(directory, timeout, argv);
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
wait_for_terminate_and_warn(directory, executor_pid, true);

View file

@ -534,7 +534,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, usec_t timeout, char *argv[]);
void execute_directory(const char *directory, usec_t timeout, char *argv[]);
int kill_and_sigcont(pid_t pid, int sig);

View file

@ -107,7 +107,7 @@ static int execute(char **modes, char **states) {
if (r < 0)
return r;
execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
execute_directory(SYSTEM_SLEEP_PATH, DEFAULT_TIMEOUT_USEC, arguments);
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
@ -126,7 +126,7 @@ static int execute(char **modes, char **states) {
NULL);
arguments[1] = (char*) "post";
execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
execute_directory(SYSTEM_SLEEP_PATH, DEFAULT_TIMEOUT_USEC, arguments);
return r;
}

View file

@ -1219,7 +1219,7 @@ static void test_execute_directory(void) {
assert_se(chmod(name2, 0755) == 0);
assert_se(touch(name3) >= 0);
execute_directory(tempdir, NULL, DEFAULT_TIMEOUT_USEC, NULL);
execute_directory(tempdir, DEFAULT_TIMEOUT_USEC, NULL);
assert_se(access("/tmp/test-execute_directory/it_works", F_OK) >= 0);
assert_se(access("/tmp/test-execute_directory/it_works2", F_OK) >= 0);