mirror of https://github.com/krallin/tini.git
NO_ARGS: White labelling
- Don't mention options that don't exist in Usage. - Don't include a log prefix when NO_ARGS is set. - Turn up the default verbosity to FATAL when NO_ARGS is set. - Expose verbosity via an ENV var for debugging.
This commit is contained in:
parent
a88563ec34
commit
b3a2ba638e
|
@ -71,8 +71,11 @@ if [[ -n "${ARCH_NATIVE:=}" ]]; then
|
|||
|
||||
# Smoke tests (actual tests need Docker to run; they don't run within the CI environment)
|
||||
for tini in "${BUILD_DIR}/tini" "${BUILD_DIR}/tini-static"; do
|
||||
echo "Smoke test for ${tini}"
|
||||
"$tini" --version
|
||||
|
||||
echo "Testing ${tini} --version"
|
||||
"$tini" --version | grep "tini version"
|
||||
"$tini" --version | grep -q "tini version"
|
||||
|
||||
if [[ -n "${NO_ARGS:-}" ]]; then
|
||||
echo "Testing $tini with: true"
|
||||
|
@ -83,6 +86,18 @@ if [[ -n "${ARCH_NATIVE:=}" ]]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
echo "Testing ${tini} without arguments exits with 1"
|
||||
! "$tini" 2>/dev/null
|
||||
|
||||
echo "Testing ${tini} shows help message"
|
||||
{
|
||||
! "$tini" 2>&1
|
||||
} | grep -q "supervision of a valid init process"
|
||||
|
||||
! {
|
||||
! "$tini" 2>&1
|
||||
} | grep -q "more verbose"
|
||||
|
||||
# We try running binaries named after flags (both valid and invalid
|
||||
# flags) and test that they run.
|
||||
for flag in h s x; do
|
||||
|
@ -94,15 +109,15 @@ if [[ -n "${ARCH_NATIVE:=}" ]]; then
|
|||
|
||||
echo "Testing $tini can run binary --version if args are given"
|
||||
cp "$(which true)" "${BIN_TEST_DIR}/--version"
|
||||
if "$tini" "--version" --foo | grep "tini version"; then
|
||||
if "$tini" "--version" --foo | grep -q "tini version"; then
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Smoke test for $tini"
|
||||
echo "Testing ${tini} -h"
|
||||
"${tini}" -h
|
||||
|
||||
echo "Testing $tini for license"
|
||||
"${tini}" -l | grep -i "mit license"
|
||||
"${tini}" -l | grep -q -i "mit license"
|
||||
|
||||
echo "Testing $tini with: true"
|
||||
"${tini}" -vvv true
|
||||
|
@ -111,14 +126,17 @@ if [[ -n "${ARCH_NATIVE:=}" ]]; then
|
|||
if "${tini}" -vvv false; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Test stdin / stdout are handed over to child
|
||||
echo "Testing pipe"
|
||||
echo "exit 0" | "${tini}" -vvv sh
|
||||
if [[ ! "$?" -eq "0" ]]; then
|
||||
echo "Pipe test failed"
|
||||
exit 1
|
||||
fi
|
||||
echo "Testing ${tini} supports TINI_VERBOSITY"
|
||||
TINI_VERBOSITY=3 "$tini" true 2>&1 | grep -q 'Received SIGCHLD'
|
||||
|
||||
# Test stdin / stdout are handed over to child
|
||||
echo "Testing ${tini} does not break pipes"
|
||||
echo "exit 0" | "${tini}" sh
|
||||
if [[ ! "$?" -eq "0" ]]; then
|
||||
echo "Pipe test failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Checking hardening on $tini"
|
||||
|
|
69
src/tini.c
69
src/tini.c
|
@ -17,11 +17,21 @@
|
|||
#include "tiniConfig.h"
|
||||
#include "tiniLicense.h"
|
||||
|
||||
#if TINI_NO_ARGS
|
||||
#define PRINT_FATAL(...) fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n");
|
||||
#define PRINT_WARNING(...) if (verbosity > 0) { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
|
||||
#define PRINT_INFO(...) if (verbosity > 1) { fprintf(stdout, __VA_ARGS__); fprintf(stdout, "\n"); }
|
||||
#define PRINT_DEBUG(...) if (verbosity > 2) { fprintf(stdout, __VA_ARGS__); fprintf(stdout, "\n"); }
|
||||
#define PRINT_TRACE(...) if (verbosity > 3) { fprintf(stdout, __VA_ARGS__); fprintf(stdout, "\n"); }
|
||||
#define DEFAULT_VERBOSITY 0
|
||||
#else
|
||||
#define PRINT_FATAL(...) fprintf(stderr, "[FATAL tini (%i)] ", getpid()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n");
|
||||
#define PRINT_WARNING(...) if (verbosity > 0) { fprintf(stderr, "[WARN tini (%i)] ", getpid()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
|
||||
#define PRINT_INFO(...) if (verbosity > 1) { fprintf(stdout, "[INFO tini (%i)] ", getpid()); fprintf(stdout, __VA_ARGS__); fprintf(stdout, "\n"); }
|
||||
#define PRINT_DEBUG(...) if (verbosity > 2) { fprintf(stdout, "[DEBUG tini (%i)] ", getpid()); fprintf(stdout, __VA_ARGS__); fprintf(stdout, "\n"); }
|
||||
#define PRINT_TRACE(...) if (verbosity > 3) { fprintf(stdout, "[TRACE tini (%i)] ", getpid()); fprintf(stdout, __VA_ARGS__); fprintf(stdout, "\n"); }
|
||||
#define DEFAULT_VERBOSITY 1
|
||||
#endif
|
||||
|
||||
#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
|
@ -31,6 +41,7 @@ typedef struct {
|
|||
struct sigaction* const sigttou_action_ptr;
|
||||
} signal_configuration_t;
|
||||
|
||||
static unsigned int verbosity = DEFAULT_VERBOSITY;
|
||||
|
||||
#ifdef PR_SET_CHILD_SUBREAPER
|
||||
#define HAS_SUBREAPER 1
|
||||
|
@ -41,13 +52,14 @@ typedef struct {
|
|||
#define OPT_STRING "hvgl"
|
||||
#endif
|
||||
|
||||
#define VERBOSITY_ENV_VAR "TINI_VERBOSITY"
|
||||
|
||||
#define TINI_VERSION_STRING "tini version " TINI_VERSION TINI_GIT
|
||||
|
||||
|
||||
#if HAS_SUBREAPER
|
||||
static unsigned int subreaper = 0;
|
||||
#endif
|
||||
static unsigned int verbosity = 1;
|
||||
static unsigned int kill_process_group = 0;
|
||||
|
||||
static struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
|
||||
|
@ -56,13 +68,16 @@ static const char reaper_warning[] = "Tini is not running as PID 1 "
|
|||
#if HAS_SUBREAPER
|
||||
"and isn't registered as a child subreaper"
|
||||
#endif
|
||||
".\n\
|
||||
Zombie processes will not be re-parented to Tini, so zombie reaping won't work.\n\
|
||||
To fix the problem, "
|
||||
".\n\
|
||||
Zombie processes will not be re-parented to Tini, so zombie reaping won't work.\n\
|
||||
To fix the problem, "
|
||||
#if HAS_SUBREAPER
|
||||
"use -s or set the environment variable " SUBREAPER_ENV_VAR " to register Tini as a child subreaper, or "
|
||||
#ifndef TINI_NO_ARGS
|
||||
"use the -s option "
|
||||
#endif
|
||||
"run Tini as PID 1.";
|
||||
"or set the environment variable " SUBREAPER_ENV_VAR " to register Tini as a child subreaper, or "
|
||||
#endif
|
||||
"run Tini as PID 1.";
|
||||
|
||||
int restore_signals(const signal_configuration_t* const sigconf_ptr) {
|
||||
if (sigprocmask(SIG_SETMASK, sigconf_ptr->sigmask_ptr, NULL)) {
|
||||
|
@ -86,7 +101,7 @@ int restore_signals(const signal_configuration_t* const sigconf_ptr) {
|
|||
int isolate_child() {
|
||||
// Put the child into a new process group.
|
||||
if (setpgid(0, 0) < 0) {
|
||||
PRINT_FATAL("setpgid failed: '%s'", strerror(errno));
|
||||
PRINT_FATAL("setpgid failed: %s", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -102,7 +117,7 @@ int isolate_child() {
|
|||
if (errno == ENOTTY) {
|
||||
PRINT_DEBUG("tcsetpgrp failed: no tty (ok to proceed)")
|
||||
} else {
|
||||
PRINT_FATAL("tcsetpgrp failed: '%s'", strerror(errno));
|
||||
PRINT_FATAL("tcsetpgrp failed: %s", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +133,7 @@ int spawn(const signal_configuration_t* const sigconf_ptr, char* const argv[], i
|
|||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
PRINT_FATAL("Fork failed: '%s'", strerror(errno));
|
||||
PRINT_FATAL("fork failed: %s", strerror(errno));
|
||||
return 1;
|
||||
} else if (pid == 0) {
|
||||
|
||||
|
@ -145,8 +160,20 @@ int spawn(const signal_configuration_t* const sigconf_ptr, char* const argv[], i
|
|||
|
||||
void print_usage(char* const name, FILE* const file) {
|
||||
fprintf(file, "%s (%s)\n", basename(name), TINI_VERSION_STRING);
|
||||
fprintf(file, "Usage: %s [OPTIONS] PROGRAM -- [ARGS]\n\n", basename(name));
|
||||
|
||||
#if TINI_NO_ARGS
|
||||
fprintf(file, "Usage: %s PROGRAM [ARGS] | --version\n\n", basename(name));
|
||||
#else
|
||||
fprintf(file, "Usage: %s [OPTIONS] PROGRAM -- [ARGS] | --version\n\n", basename(name));
|
||||
#endif
|
||||
fprintf(file, "Execute a program under the supervision of a valid init process (%s)\n\n", basename(name));
|
||||
|
||||
fprintf(file, "Command line options:\n\n");
|
||||
|
||||
fprintf(file, " --version: Show version and exit.\n");
|
||||
|
||||
#if TINI_NO_ARGS
|
||||
#else
|
||||
fprintf(file, " -h: Show this help message and exit.\n");
|
||||
#if HAS_SUBREAPER
|
||||
fprintf(file, " -s: Register as a process subreaper (requires Linux >= 3.4).\n");
|
||||
|
@ -154,6 +181,16 @@ void print_usage(char* const name, FILE* const file) {
|
|||
fprintf(file, " -v: Generate more verbose output. Repeat up to 3 times.\n");
|
||||
fprintf(file, " -g: Send signals to the child's process group.\n");
|
||||
fprintf(file, " -l: Show license and exit.\n");
|
||||
#endif
|
||||
|
||||
fprintf(file, "\n");
|
||||
|
||||
fprintf(file, "Environment variables:\n\n");
|
||||
#if HAS_SUBREAPER
|
||||
fprintf(file, " %s: Register as a process subreaper (requires Linux >= 3.4)\n", SUBREAPER_ENV_VAR);
|
||||
#endif
|
||||
fprintf(file, " %s: Set the verbosity level (default: %d)\n", VERBOSITY_ENV_VAR, DEFAULT_VERBOSITY);
|
||||
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
|
||||
|
@ -172,9 +209,7 @@ int parse_args(const int argc, char* const argv[], char* (**child_args_ptr_ptr)[
|
|||
return 1;
|
||||
}
|
||||
|
||||
#if TINI_NO_ARGS
|
||||
*parse_fail_exitcode_ptr = 0;
|
||||
#else
|
||||
#ifndef TINI_NO_ARGS
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, OPT_STRING)) != -1) {
|
||||
switch (c) {
|
||||
|
@ -237,6 +272,12 @@ int parse_env() {
|
|||
subreaper++;
|
||||
}
|
||||
#endif
|
||||
|
||||
char* env_verbosity = getenv(VERBOSITY_ENV_VAR);
|
||||
if (env_verbosity != NULL) {
|
||||
verbosity = atoi(env_verbosity);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -468,7 +509,7 @@ int main(int argc, char *argv[]) {
|
|||
reaper_check();
|
||||
|
||||
/* Go on */
|
||||
if (spawn(&child_sigconf, *child_args_ptr, &child_pid)) {
|
||||
if(spawn(&child_sigconf, *child_args_ptr, &child_pid)) {
|
||||
return 1;
|
||||
}
|
||||
free(child_args_ptr);
|
||||
|
|
|
@ -80,10 +80,14 @@ def main():
|
|||
p.send_signal(signal.SIGUSR1)
|
||||
busy_wait(lambda: p.poll() is not None, 10)
|
||||
|
||||
|
||||
# Run failing test
|
||||
# Run failing test. Force verbosity to 1 so we see the subreaper warning
|
||||
# regardless of whether NO_ARGS is set.
|
||||
print "Running zombie reaping failure test (Tini should warn)"
|
||||
p = subprocess.Popen([tini, os.path.join(src, "test", "reaping", "stage_1.py")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
p = subprocess.Popen(
|
||||
[tini, os.path.join(src, "test", "reaping", "stage_1.py")],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
env={'TINI_VERBOSITY': '1'}
|
||||
)
|
||||
out, err = p.communicate()
|
||||
assert "zombie reaping won't work" in err, "No warning message was output!"
|
||||
ret = p.wait()
|
||||
|
|
Loading…
Reference in New Issue