|
|
@ -90,11 +90,11 @@ static int32_t expect_status[(STATUS_MAX - STATUS_MIN + 1) / 32]; |
|
|
|
|
|
|
|
|
|
|
|
#ifdef PR_SET_CHILD_SUBREAPER |
|
|
|
#ifdef PR_SET_CHILD_SUBREAPER |
|
|
|
#define HAS_SUBREAPER 1 |
|
|
|
#define HAS_SUBREAPER 1 |
|
|
|
#define OPT_STRING "p:hvwgle:s" |
|
|
|
#define OPT_STRING "p:hvwgle:R:s" |
|
|
|
#define SUBREAPER_ENV_VAR "TINI_SUBREAPER" |
|
|
|
#define SUBREAPER_ENV_VAR "TINI_SUBREAPER" |
|
|
|
#else |
|
|
|
#else |
|
|
|
#define HAS_SUBREAPER 0 |
|
|
|
#define HAS_SUBREAPER 0 |
|
|
|
#define OPT_STRING "p:hvwgle:" |
|
|
|
#define OPT_STRING "p:hvwgle:R:" |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
#define VERBOSITY_ENV_VAR "TINI_VERBOSITY" |
|
|
|
#define VERBOSITY_ENV_VAR "TINI_VERBOSITY" |
|
|
@ -111,6 +111,8 @@ static unsigned int kill_process_group = 0; |
|
|
|
|
|
|
|
|
|
|
|
static unsigned int warn_on_reap = 0; |
|
|
|
static unsigned int warn_on_reap = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum respawn_enum { Never, Always, OnFailure } respawn_type = Never; |
|
|
|
|
|
|
|
|
|
|
|
static struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 }; |
|
|
|
static struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 }; |
|
|
|
|
|
|
|
|
|
|
|
static const char reaper_warning[] = "Tini is not running as PID 1 " |
|
|
|
static const char reaper_warning[] = "Tini is not running as PID 1 " |
|
|
@ -248,6 +250,7 @@ void print_usage(char* const name, FILE* const file) { |
|
|
|
fprintf(file, " -w: Print a warning when processes are getting reaped.\n"); |
|
|
|
fprintf(file, " -w: Print a warning when processes are getting reaped.\n"); |
|
|
|
fprintf(file, " -g: Send signals to the child's process group.\n"); |
|
|
|
fprintf(file, " -g: Send signals to the child's process group.\n"); |
|
|
|
fprintf(file, " -e EXIT_CODE: Remap EXIT_CODE (from 0 to 255) to 0 (can be repeated).\n"); |
|
|
|
fprintf(file, " -e EXIT_CODE: Remap EXIT_CODE (from 0 to 255) to 0 (can be repeated).\n"); |
|
|
|
|
|
|
|
fprintf(file, " -R {A|F}: Respawn [A]lways or On-[F]ailure.\n"); |
|
|
|
fprintf(file, " -l: Show license and exit.\n"); |
|
|
|
fprintf(file, " -l: Show license and exit.\n"); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
@ -287,6 +290,20 @@ int set_pdeathsig(char* const arg) { |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int set_respawn(char* const arg) { |
|
|
|
|
|
|
|
if (strlen(arg) != 1) { |
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
} else if (arg[0] == 'A') { |
|
|
|
|
|
|
|
respawn_type = Always; |
|
|
|
|
|
|
|
} else if (arg[0] == 'F') { |
|
|
|
|
|
|
|
respawn_type = OnFailure; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int add_expect_status(char* arg) { |
|
|
|
int add_expect_status(char* arg) { |
|
|
|
long status = 0; |
|
|
|
long status = 0; |
|
|
|
char* endptr = NULL; |
|
|
|
char* endptr = NULL; |
|
|
@ -361,6 +378,14 @@ int parse_args(const int argc, char* const argv[], char* (**child_args_ptr_ptr)[ |
|
|
|
*parse_fail_exitcode_ptr = 0; |
|
|
|
*parse_fail_exitcode_ptr = 0; |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'R': |
|
|
|
|
|
|
|
if (set_respawn(optarg)) { |
|
|
|
|
|
|
|
PRINT_FATAL("Not a valid option for -R: %s", optarg); |
|
|
|
|
|
|
|
*parse_fail_exitcode_ptr = 1; |
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case '?': |
|
|
|
case '?': |
|
|
|
print_usage(name, stderr); |
|
|
|
print_usage(name, stderr); |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
@ -573,8 +598,13 @@ int reap_zombies(const pid_t child_pid, int* const child_exitcode_ptr) { |
|
|
|
/* Our process was terminated. Emulate what sh / bash
|
|
|
|
/* Our process was terminated. Emulate what sh / bash
|
|
|
|
* would do, which is to return 128 + signal number. |
|
|
|
* would do, which is to return 128 + signal number. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
PRINT_INFO("Main child exited with signal (with signal '%s')", strsignal(WTERMSIG(current_status))); |
|
|
|
unsigned int signum = WTERMSIG(current_status); |
|
|
|
*child_exitcode_ptr = 128 + WTERMSIG(current_status); |
|
|
|
PRINT_INFO("Main child exited with signal (with signal '%s')", strsignal(signum)); |
|
|
|
|
|
|
|
if (parent_death_signal > 0 && parent_death_signal == signum && respawn_type != Never) { |
|
|
|
|
|
|
|
PRINT_DEBUG("Disabling respawns"); |
|
|
|
|
|
|
|
respawn_type = Never; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
*child_exitcode_ptr = 128 + signum; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
PRINT_FATAL("Main child exited for unknown reason"); |
|
|
|
PRINT_FATAL("Main child exited for unknown reason"); |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
@ -655,26 +685,49 @@ int main(int argc, char *argv[]) { |
|
|
|
/* Are we going to reap zombies properly? If not, warn. */ |
|
|
|
/* Are we going to reap zombies properly? If not, warn. */ |
|
|
|
reaper_check(); |
|
|
|
reaper_check(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lab_respawn: |
|
|
|
|
|
|
|
child_exitcode = -1; |
|
|
|
|
|
|
|
|
|
|
|
/* Go on */ |
|
|
|
/* Go on */ |
|
|
|
int spawn_ret = spawn(&child_sigconf, *child_args_ptr, &child_pid); |
|
|
|
int spawn_ret = spawn(&child_sigconf, *child_args_ptr, &child_pid); |
|
|
|
if (spawn_ret) { |
|
|
|
if (spawn_ret) { |
|
|
|
return spawn_ret; |
|
|
|
return spawn_ret; |
|
|
|
} |
|
|
|
} |
|
|
|
free(child_args_ptr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (1) { |
|
|
|
while (1) { |
|
|
|
/* Wait for one signal, and forward it */ |
|
|
|
/* Wait for one signal, and forward it */ |
|
|
|
if (wait_and_forward_signal(&parent_sigset, child_pid)) { |
|
|
|
if (wait_and_forward_signal(&parent_sigset, child_pid)) { |
|
|
|
|
|
|
|
free(child_args_ptr); |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Now, reap zombies */ |
|
|
|
/* Now, reap zombies */ |
|
|
|
if (reap_zombies(child_pid, &child_exitcode)) { |
|
|
|
if (reap_zombies(child_pid, &child_exitcode)) { |
|
|
|
|
|
|
|
free(child_args_ptr); |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (child_exitcode != -1) { |
|
|
|
if (child_exitcode != -1) { |
|
|
|
|
|
|
|
switch (respawn_type) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case Always: |
|
|
|
|
|
|
|
PRINT_INFO("Child pid=%i has exited (respawning)", child_pid); |
|
|
|
|
|
|
|
sleep(1); |
|
|
|
|
|
|
|
goto lab_respawn; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case OnFailure: |
|
|
|
|
|
|
|
if (child_exitcode != 0) { |
|
|
|
|
|
|
|
PRINT_INFO("Child pid=%i has exited with %i (respawning)", child_pid, child_exitcode); |
|
|
|
|
|
|
|
sleep(1); |
|
|
|
|
|
|
|
goto lab_respawn; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// fall through ...
|
|
|
|
|
|
|
|
case Never: |
|
|
|
|
|
|
|
; /* nop */ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
PRINT_TRACE("Exiting: child has exited"); |
|
|
|
PRINT_TRACE("Exiting: child has exited"); |
|
|
|
|
|
|
|
free(child_args_ptr); |
|
|
|
return child_exitcode; |
|
|
|
return child_exitcode; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|