From afe60a6714db9133e362eae1cf2ce80a16049250 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Wed, 15 May 2019 14:02:27 +0200 Subject: [PATCH] spawn: Allow executing list of handlers This functionality is needed for non-trivial child initialization. Change-Id: Iac1d5221fc44dc2d65c2acc260e8b9e2b1a01a17 --- src/crash-manager/crash-manager.c | 18 +++++++-------- src/dump_systemstate/dump_systemstate.c | 4 ++-- src/dump_systemstate/extras.c | 4 ++-- src/log_dump/log_dump.c | 8 +++---- src/shared/spawn.c | 40 +++++++++++++++++++-------------- src/shared/spawn.h | 33 ++++++++++++++++----------- 6 files changed, 60 insertions(+), 47 deletions(-) diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index 9e7bd49..5eb8d6b 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -456,13 +456,14 @@ static void launch_crash_popup(struct crash_info *cinfo) "--cmdpath", cinfo->cmd_path, NULL }; - spawn(av, NULL, spawn_nullstdfds, NULL, NULL, NULL); + spawn_param_s param = { .fn = spawn_nullstdfds }; + spawn(av, NULL, ¶m, NULL, NULL); } static bool dump_system_state(const struct crash_info *cinfo, pid_t *pid) { char *av[] = {"/usr/bin/dump_systemstate", "-d", "-k", "-j", "-p", "-e", "-f", cinfo->log_path, NULL}; - return spawn(av, NULL, NULL, NULL, pid, NULL); + return spawn(av, NULL, NULL, pid, NULL); } static void save_so_info(const struct crash_info *cinfo) @@ -540,7 +541,7 @@ static void launch_dbus_notify(struct crash_info *cinfo) "--prstatus_fd", prstatus_fd_str, NULL }; - spawn(av, NULL, NULL, NULL, NULL, NULL); + spawn(av, NULL, NULL, NULL, NULL); out: free(prstatus_fd_str); } @@ -585,7 +586,7 @@ static bool execute_minicoredump(struct crash_info *cinfo, int *exit_code) NULL }; - is_ok = spawn_wait(args, NULL, NULL, NULL, MINICOREDUMPER_TIMEOUT_MS, exit_code); + is_ok = spawn_wait(args, NULL, NULL, MINICOREDUMPER_TIMEOUT_MS, exit_code); /* Minicoredumper must be executed to dump at least PRSTATUS for other tools, coredump, however, might have been disabled. */ @@ -635,8 +636,8 @@ static bool execute_crash_stack(const struct crash_info *cinfo, int *exit_code) return false; } - spawn_param_u param = { .int_val = fd }; - is_ok = spawn_wait(args, NULL, spawn_setstdout, ¶m, CRASH_STACK_TIMEOUT_MS, exit_code); + spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = fd }; + is_ok = spawn_wait(args, NULL, ¶m, CRASH_STACK_TIMEOUT_MS, exit_code); close(fd); out: @@ -913,9 +914,8 @@ static void compress(struct crash_info *cinfo) } char *args[] = {"/bin/zip", "-qyr", zip_path, cinfo->name, NULL}; - - spawn_param_u param = { .char_ptr = cinfo->temp_dir }; - (void)spawn_wait(args, NULL, spawn_chdir, ¶m, ZIP_TIMEOUT_MS, NULL); + spawn_param_s param0 = { .fn = spawn_chdir, .u.char_ptr = cinfo->temp_dir }; + (void)spawn_wait(args, NULL, ¶m0, ZIP_TIMEOUT_MS, NULL); if ((lock_fd = lock_dumpdir()) < 0) return; diff --git a/src/dump_systemstate/dump_systemstate.c b/src/dump_systemstate/dump_systemstate.c index b853080..30a8f35 100644 --- a/src/dump_systemstate/dump_systemstate.c +++ b/src/dump_systemstate/dump_systemstate.c @@ -170,8 +170,8 @@ int main(int argc, char *argv[]) #define spawn_wait_checked(av, env) \ do { \ int err; \ - spawn_param_u param = { .int_val = out_fd }; \ - if (!spawn_wait(av, env, spawn_setstdout, ¶m, DEFAULT_COMMAND_TIMEOUT_MS, &err) || err != 0) { \ + spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = out_fd }; \ + if (!spawn_wait(av, env, ¶m, DEFAULT_COMMAND_TIMEOUT_MS, &err) || err != 0) { \ exit_code |= EXIT_CMDERR; \ fprintf_fd(out_fd, "\nCommand failed with error code: %d", err); \ } \ diff --git a/src/dump_systemstate/extras.c b/src/dump_systemstate/extras.c index 6033485..90625a5 100644 --- a/src/dump_systemstate/extras.c +++ b/src/dump_systemstate/extras.c @@ -97,8 +97,8 @@ int handle_extra_program(int out_fd, struct extra_dump_item *item) char *argv[] = {"/bin/sh", "-c", command_line, NULL}; int err; - spawn_param_u param = { .int_val = out_fd }; - bool failed = !spawn_wait(argv, NULL, spawn_setstdout, ¶m, DEFAULT_COMMAND_TIMEOUT_MS, &err) || err != 0; + spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = out_fd }; + bool failed = !spawn_wait(argv, NULL, ¶m, DEFAULT_COMMAND_TIMEOUT_MS, &err) || err != 0; free(command_line); return failed ? EXIT_CMDERR : 0; diff --git a/src/log_dump/log_dump.c b/src/log_dump/log_dump.c index aa63f2b..f50bf14 100644 --- a/src/log_dump/log_dump.c +++ b/src/log_dump/log_dump.c @@ -185,7 +185,7 @@ static bool dump_scripts(char *const workdir, char *const scriptsdir) _D("Calling scriptlet: %s", command); char *const av[] = {command, workdir, NULL}; - (void)spawn_wait(av, NULL, NULL, NULL, 0, NULL); + (void)spawn_wait(av, NULL, NULL, 0, NULL); } for (i = 0; i < script_num; i++) @@ -205,7 +205,7 @@ static bool dump_systemstate(const char *const destdir, const char *const timest } char *av[] = {"/usr/bin/dump_systemstate", "-k", "-d", "-j", "-e", "-f", dump_path, NULL}; - bool is_ok = spawn_wait(av, NULL, NULL, NULL, 0, exit_code); + bool is_ok = spawn_wait(av, NULL, NULL, 0, exit_code); free(dump_path); @@ -223,8 +223,8 @@ static bool compress(char *const destdir, char *const tempdir, char *const versi _D("compress tempdir is %s", tempdir); char *av[] = {"/bin/zip", "-qyr", archive_path, ".", NULL}; - spawn_param_u param = { .char_ptr = tempdir }; - bool is_ok = spawn_wait(av, NULL, spawn_chdir, ¶m, 0, exit_code); + spawn_param_s param0 = { .fn = spawn_chdir, .u.char_ptr = tempdir }; + bool is_ok = spawn_wait(av, NULL, ¶m0, 0, exit_code); _I("Storing report at %s", archive_path); diff --git a/src/shared/spawn.c b/src/shared/spawn.c index 7139f73..baca45d 100644 --- a/src/shared/spawn.c +++ b/src/shared/spawn.c @@ -36,19 +36,19 @@ /* spawn prepare function(s) - to be called in child process */ -int spawn_setstdout(spawn_param_u *param) +int spawn_setstdout(spawn_param_s *param) { assert(param); - return dup2(param->int_val, STDOUT_FILENO) < 0 ? -1 : 0; + return dup2(param->u.int_val, STDOUT_FILENO) < 0 ? -1 : 0; } -int spawn_setstdouterr(spawn_param_u *param) +int spawn_setstderr(spawn_param_s *param) { assert(param); - return dup2(param->int_val, STDOUT_FILENO) < 0 || dup2(param->int_val, STDERR_FILENO) < 0 ? -1 : 0; + return dup2(param->u.int_val, STDERR_FILENO) < 0 ? -1 : 0; } -int spawn_nullstdfds(spawn_param_u *param) +int spawn_nullstdfds(spawn_param_s *param) { int fd = open("/dev/null", O_RDWR); int ret = dup2(fd, STDIN_FILENO) < 0 || dup2(fd, STDOUT_FILENO) < 0 || dup2(fd, STDERR_FILENO) < 0 ? -1 : 0; @@ -57,16 +57,16 @@ int spawn_nullstdfds(spawn_param_u *param) return ret; } -int spawn_chdir(spawn_param_u *param) +int spawn_chdir(spawn_param_s *param) { assert(param); - return chdir(param->char_ptr); + return chdir(param->u.char_ptr); } -int spawn_umask(spawn_param_u *param) +int spawn_umask(spawn_param_s *param) { assert(param); - (void)umask(param->mode_t_val); + (void)umask(param->u.mode_t_val); return 0; } @@ -106,19 +106,25 @@ bool wait_for_pid(pid_t pid, int *exit_code) return true; } -static int spawn_child(char *const av[], char *const ev[], spawn_prepare_fn prep, spawn_param_u *param) +static int spawn_child(char *const av[], char *const ev[], spawn_param_s *param) { static const int spawn_error = 127; - int r = prep ? prep(param) : 0; - if (r < 0) - return spawn_error; + while (param) { + assert(param->fn); + + int r = param->fn(param); + if (r < 0) + return spawn_error; + + param = param->next; + }; execve(av[0], av, ev); return spawn_error; } -bool spawn(char *const av[], char *const ev[], spawn_prepare_fn prep, spawn_param_u *param, pid_t *childpid, int *childfd) +bool spawn(char *const av[], char *const ev[], spawn_param_s *param, pid_t *childpid, int *childfd) { int pipefd[2]; if (pipe(pipefd) < 0) { @@ -134,7 +140,7 @@ bool spawn(char *const av[], char *const ev[], spawn_prepare_fn prep, spawn_para return false; } else if (pid == 0) { close(pipefd[0]); - _exit(spawn_child(av, ev, prep, param)); + _exit(spawn_child(av, ev, param)); } close(pipefd[1]); @@ -180,12 +186,12 @@ static bool wait_and_kill(pid_t childpid, int childfd, int timeout_ms) return true; } -bool spawn_wait(char *const av[], char *const ev[], spawn_prepare_fn prep, spawn_param_u *param, int timeout_ms, int *exit_code) +bool spawn_wait(char *const av[], char *const ev[], spawn_param_s *param, int timeout_ms, int *exit_code) { pid_t childpid; int childfd; - if (!spawn(av, ev, prep, param, &childpid, &childfd)) { + if (!spawn(av, ev, param, &childpid, &childfd)) { _E("spawn() returned an error - aborting waiting"); return false; } diff --git a/src/shared/spawn.h b/src/shared/spawn.h index 7177ae8..431b173 100644 --- a/src/shared/spawn.h +++ b/src/shared/spawn.h @@ -26,23 +26,30 @@ extern "C" { #define DEFAULT_COMMAND_TIMEOUT_MS (60*1000) /* 60sec */ -typedef union { - int int_val; - mode_t mode_t_val; - char *char_ptr; -} spawn_param_u; +struct spawn_param; -typedef int (*spawn_prepare_fn)(spawn_param_u *param); +typedef int (*spawn_prepare_fn)(struct spawn_param *param); -int spawn_setstdout(spawn_param_u *param); -int spawn_setstdouterr(spawn_param_u *param); -int spawn_nullstdfds(spawn_param_u *param); -int spawn_chdir(spawn_param_u *param); -int spawn_umask(spawn_param_u *param); +typedef struct spawn_param { + spawn_prepare_fn fn; + + struct spawn_param *next; + union { + int int_val; + mode_t mode_t_val; + char *char_ptr; + } u; +} spawn_param_s; + +int spawn_setstdout(spawn_param_s *param); +int spawn_setstderr(spawn_param_s *param); +int spawn_nullstdfds(spawn_param_s *param); +int spawn_chdir(spawn_param_s *param); +int spawn_umask(spawn_param_s *param); bool wait_for_pid(pid_t pid, int *exit_code); -bool spawn(char *const av[], char *const ev[], spawn_prepare_fn prep, spawn_param_u *param, pid_t *childpid, int *childfd); -bool spawn_wait(char *const av[], char *const ev[], spawn_prepare_fn prep, spawn_param_u *param, int timeout_ms, int *exit_code); +bool spawn(char *const av[], char *const ev[], spawn_param_s *param, pid_t *childpid, int *childfd); +bool spawn_wait(char *const av[], char *const ev[], spawn_param_s *param, int timeout_ms, int *exit_code); #ifdef __cplusplus } -- 2.7.4