aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-09-20 18:45:59 +0200
committerdec05eba <dec05eba@protonmail.com>2020-09-20 18:45:59 +0200
commitf41a28fe3ec5042849583081ca0e1aa6c38a7187 (patch)
treefe9967e994ff0fa9357dca81174a3d0ed092a4f1
parent45c427b23e035aac49bc961115a1beff1f74d5ee (diff)
Daemonize async process to automatically reap the child when it dies
-rw-r--r--include/Program.h4
-rw-r--r--src/Program.c41
2 files changed, 32 insertions, 13 deletions
diff --git a/include/Program.h b/include/Program.h
index bc3e91e..cd45b30 100644
--- a/include/Program.h
+++ b/include/Program.h
@@ -30,7 +30,9 @@ bool wait_program_non_blocking(pid_t process_id, int *status);
/*
@args need to have at least 2 arguments. The first which is the program name
- and the last which is NULL, which indicates end of args
+ and the last which is NULL, which indicates end of args.
+ @result_process_id should be set to NULL if you are not interested in the exit status of the child process
+ and you want the child process to be cleaned up automatically when it dies.
*/
int exec_program_async(const char **args, pid_t *result_process_id);
#if 0
diff --git a/src/Program.c b/src/Program.c
index fe2ae3f..bb476c4 100644
--- a/src/Program.c
+++ b/src/Program.c
@@ -33,12 +33,12 @@ int exec_program(const char **args, ProgramOutputCallback output_callback, void
} else if(pid == 0) { /* child */
if(prctl(PR_SET_PDEATHSIG, SIGTERM) == -1) {
perror("prctl(PR_SET_PDEATHSIG, SIGTERM) failed");
- exit(127);
+ _exit(127);
}
/* Test if the parent died before the above call to prctl */
if(getppid() != parent_pid)
- exit(127);
+ _exit(127);
dup2(fd[WRITE_END], STDOUT_FILENO);
close(fd[READ_END]);
@@ -46,7 +46,7 @@ int exec_program(const char **args, ProgramOutputCallback output_callback, void
execvp(args[0], args);
perror("execvp");
- exit(127);
+ _exit(127);
} else { /* parent */
close(fd[WRITE_END]);
@@ -151,16 +151,33 @@ int exec_program_async(const char **args, pid_t *result_process_id) {
perror("Failed to fork");
return -err;
} else if(pid == 0) { /* child */
- if(prctl(PR_SET_PDEATHSIG, SIGTERM) == -1) {
- perror("prctl(PR_SET_PDEATHSIG, SIGTERM) failed");
- exit(127);
- }
-
- /* Test if the parent died before the above call to prctl */
- if(getppid() != parent_pid)
- exit(127);
+ if(result_process_id) {
+ if(prctl(PR_SET_PDEATHSIG, SIGTERM) == -1) {
+ perror("prctl(PR_SET_PDEATHSIG, SIGTERM) failed");
+ _exit(127);
+ }
- execvp(args[0], args);
+ /* Test if the parent died before the above call to prctl */
+ if(getppid() != parent_pid)
+ _exit(127);
+
+ execvp(args[0], args);
+ perror("execvp");
+ _exit(127);
+ } else {
+ setsid();
+ signal(SIGHUP, SIG_IGN);
+
+ // Daemonize child to make the parent the init process which will reap the zombie child
+ pid_t second_child = fork();
+ if(second_child == 0) { // child
+ execvp(args[0], args);
+ perror("execvp");
+ _exit(127);
+ } else if(second_child != -1) {
+ _exit(0);
+ }
+ }
} else { /* parent */
if(result_process_id)
*result_process_id = pid;