diff --git a/Dockerfile b/Dockerfile index dc5e7dc..d823d78 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,6 @@ -FROM ubuntu:xenial +FROM ubuntu:focal + +ENV DEBIAN_FRONTEND=noninteractive ARG ARCH_SUFFIX diff --git a/README.md b/README.md index 9caf8aa..18ca57e 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,24 @@ tini -p SIGTERM -- ... and use cases.* +### System reboot on exit ### + +Instead of merely exiting when the child process exists, Tini can invoke +`reboot(2)` to bring the system down when it would exit. When running as the +true PID 1 of a kernel, this prevents a kernel panic that occurs when init +exits. Use the `-R` option to enable this behavior. + +This option allows Tini to function as the init process in a VM, for example, +in [firecracker](https://github.com/firecracker-microvm/firecracker). + +Additionally, Tini can invoke `sync(2)` before reboot. The `-S` option enables +this extra behavior. If `-S` is specified without `-R` it is ignored. + +``` +tini -R -S -- ... +``` + + More ---- diff --git a/ci/install_deps.sh b/ci/install_deps.sh index ef326d4..670db63 100755 --- a/ci/install_deps.sh +++ b/ci/install_deps.sh @@ -6,7 +6,7 @@ set -o xtrace DEPS=( build-essential git gdb valgrind cmake rpm file libcap-dev python3-dev python3-pip python3-setuptools - hardening-includes gnupg + devscripts gnupg ) case "${ARCH_SUFFIX-}" in diff --git a/src/tini.c b/src/tini.c index 2c873f9..edc8ac5 100644 --- a/src/tini.c +++ b/src/tini.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -90,11 +91,11 @@ static int32_t expect_status[(STATUS_MAX - STATUS_MIN + 1) / 32]; #ifdef PR_SET_CHILD_SUBREAPER #define HAS_SUBREAPER 1 -#define OPT_STRING "p:hvwgle:s" +#define OPT_STRING "p:hvwgle:sRS" #define SUBREAPER_ENV_VAR "TINI_SUBREAPER" #else #define HAS_SUBREAPER 0 -#define OPT_STRING "p:hvwgle:" +#define OPT_STRING "p:hvwgle:RS" #endif #define VERBOSITY_ENV_VAR "TINI_VERBOSITY" @@ -111,6 +112,9 @@ static unsigned int kill_process_group = 0; static unsigned int warn_on_reap = 0; +static unsigned int reboot_on_exit = 0; +static unsigned int sync_before_reboot = 0; + static struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 }; static const char reaper_warning[] = "Tini is not running as PID 1 " @@ -249,6 +253,8 @@ void print_usage(char* const name, FILE* const file) { 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, " -l: Show license and exit.\n"); + fprintf(file, " -R: Call reboot(2) instead of exiting.\n"); + fprintf(file, " -S: Call sync(2) before reboot. If -R is not specified, this option is ignored.\n"); #endif fprintf(file, "\n"); @@ -361,6 +367,14 @@ int parse_args(const int argc, char* const argv[], char* (**child_args_ptr_ptr)[ *parse_fail_exitcode_ptr = 0; return 1; + case 'R': + reboot_on_exit++; + break; + + case 'S': + sync_before_reboot++; + break; + case '?': print_usage(name, stderr); return 1; @@ -604,7 +618,7 @@ int reap_zombies(const pid_t child_pid, int* const child_exitcode_ptr) { } -int main(int argc, char *argv[]) { +int tini(int argc, char *argv[]) { pid_t child_pid; // Those are passed to functions to get an exitcode back. @@ -679,3 +693,20 @@ int main(int argc, char *argv[]) { } } } + + +int main(int argc, char *argv[]) { + int exit_status = tini(argc, argv); + if (reboot_on_exit) { + if (sync_before_reboot) { + sync(); + } + if (exit_status) { + PRINT_WARNING("%s exit status: %d", + argv[0], exit_status); + } + return reboot(RB_AUTOBOOT); + } else { + return exit_status; + } +} diff --git a/tpl/README.md.in b/tpl/README.md.in index 9f58fcb..b1d3bca 100644 --- a/tpl/README.md.in +++ b/tpl/README.md.in @@ -222,6 +222,24 @@ tini -p SIGTERM -- ... and use cases.* +### System reboot on exit ### + +Instead of merely exiting when the child process exists, Tini can invoke +`reboot(2)` to bring the system down when it would exit. When running as the +true PID 1 of a kernel, this prevents a kernel panic that occurs when init +exits. Use the `-R` option to enable this behavior. + +This option allows Tini to function as the init process in a VM, for example, +in [firecracker](https://github.com/firecracker-microvm/firecracker). + +Additionally, Tini can invoke `sync(2)` before reboot. The `-S` option enables +this extra behavior. If `-S` is specified without `-R` it is ignored. + +``` +tini -R -S -- ... +``` + + More ----