Skip to content

Commit

Permalink
Merge pull request #60 from krallin/white-label
Browse files Browse the repository at this point in the history
"White label" when MINIMAL is set
  • Loading branch information
krallin authored Nov 4, 2016
2 parents a88563e + e8de782 commit 4a92b9e
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 75 deletions.
10 changes: 5 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ language: generic

env:
matrix:
- CC=gcc ARCH_SUFFIX=amd64 ARCH_NATIVE=1 NO_ARGS=
- CC=arm-linux-gnueabihf-gcc ARCH_SUFFIX=armhf ARCH_NATIVE= NO_ARGS=
- CC=aarch64-linux-gnu-gcc ARCH_SUFFIX=arm64 ARCH_NATIVE= NO_ARGS=
- CC=gcc ARCH_SUFFIX=amd64 ARCH_NATIVE=1 NO_ARGS=1
- CC=gcc ARCH_SUFFIX=amd64 ARCH_NATIVE=1 MINIMAL=
- CC=arm-linux-gnueabihf-gcc ARCH_SUFFIX=armhf ARCH_NATIVE= MINIMAL=
- CC=aarch64-linux-gnu-gcc ARCH_SUFFIX=arm64 ARCH_NATIVE= MINIMAL=
- CC=gcc ARCH_SUFFIX=amd64 ARCH_NATIVE=1 MINIMAL=1
global:
- SIGN_BINARIES=1
- secure: "RKF9Z9gLxp6k/xITqn7ma1E9HfpYcDXuJFf4862WeH9EMnK9lDq+TWnGsQfkIlqh8h9goe7U+BvRiTibj9MiD5u7eluLo3dlwsLxPpYtyswYeLeC1wKKdT5LPGAXbRKomvBalRYMI+dDnGIM4w96mHgGGvx2zZXGkiAQhm6fJ3k="
Expand All @@ -31,4 +31,4 @@ deploy:
on:
repo: krallin/tini
tags: true
condition: '-z "$NO_ARGS"'
condition: '-z "$MINIMAL"'
8 changes: 4 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ project (tini C)

# Config
set (tini_VERSION_MAJOR 0)
set (tini_VERSION_MINOR 12)
set (tini_VERSION_MINOR 13)
set (tini_VERSION_PATCH 0)

# Build options
option(NO_ARGS "Disable argument parsing" OFF)
option(MINIMAL "Disable argument parsing and verbose output" OFF)

if(NO_ARGS)
add_definitions(-DTINI_NO_ARGS=1)
if(MINIMAL)
add_definitions(-DTINI_MINIMAL=1)
endif()

# Extract git version and dirty-ness
Expand Down
22 changes: 12 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ In Docker, you will want to use an entrypoint so you don't have to remember
to manually invoke Tini:

# Add Tini
ENV TINI_VERSION v0.12.0
ENV TINI_VERSION v0.13.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]
Expand All @@ -63,7 +63,7 @@ The `tini` and `tini-static` binaries are signed using the key `595E85A6B1B4779E
You can verify their signatures using `gpg` (which you may install using
your package manager):

ENV TINI_VERSION v0.12.0
ENV TINI_VERSION v0.13.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini.asc /tini.asc
RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7 \
Expand Down Expand Up @@ -214,18 +214,20 @@ Maintainer:

Contributors:

+ [Tianon Gravi][21]
+ [David Wragg][22]
+ [Tianon Gravi][30]
+ [David Wragg][31]
+ [Michael Crosby][32]

Special thanks to:

+ [Danilo Bürger][23] for packaging Tini for Alpine
+ [Asko Soukka][24] for packaging Tini for Nix
+ [Danilo Bürger][40] for packaging Tini for Alpine
+ [Asko Soukka][41] for packaging Tini for Nix


[10]: https://github.com/krallin/tini-images
[20]: https://github.com/krallin/
[21]: https://github.com/tianon
[22]: https://github.com/dpw
[23]: https://github.com/danilobuerger
[24]: https://github.com/datakurre
[30]: https://github.com/tianon
[31]: https://github.com/dpw
[32]: https://github.com/crosbymichael
[40]: https://github.com/danilobuerger
[41]: https://github.com/datakurre
66 changes: 52 additions & 14 deletions ci/run_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export PATH="${SOURCE_DIR}/ci/util:${PATH}"

# Build
CMAKE_ARGS=(-B"${BUILD_DIR}" -H"${SOURCE_DIR}")
if [[ -n "${NO_ARGS:-}" ]]; then
CMAKE_ARGS+=(-DNO_ARGS=ON)
if [[ -n "${MINIMAL:-}" ]]; then
CMAKE_ARGS+=(-DMINIMAL=ON)
fi
cmake "${CMAKE_ARGS[@]}"

Expand All @@ -71,10 +71,21 @@ 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"

echo "Testing ${tini} without arguments exits with 1"
! "$tini" 2>/dev/null

if [[ -n "${NO_ARGS:-}" ]]; then
echo "Testing ${tini} shows help message"
{
! "$tini" 2>&1
} | grep -q "supervision of a valid init process"

if [[ -n "${MINIMAL:-}" ]]; then
echo "Testing $tini with: true"
"${tini}" true

Expand All @@ -83,6 +94,11 @@ if [[ -n "${ARCH_NATIVE:=}" ]]; then
exit 1
fi

echo "Testing ${tini} does not reference options that don't exist"
! {
! "$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
Expand All @@ -94,15 +110,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
Expand All @@ -112,13 +128,35 @@ if [[ -n "${ARCH_NATIVE:=}" ]]; then
exit 1
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} references options that exist"
{
! "$tini" 2>&1
} | grep -q "more verbose"
fi

echo "Testing ${tini} supports TINI_VERBOSITY"
TINI_VERBOSITY=3 "$tini" true 2>&1 | grep -q 'Received SIGCHLD'

echo "Testing ${tini} exits with 127 if the command does not exist"
"$tini" foobar123 && rc="$?" || rc="$?"
if [[ "$rc" != 127 ]]; then
echo "Exit code was: ${rc}"
exit 1
fi

echo "Testing ${tini} exits with 126 if the command is not executable"
"$tini" /etc && rc="$?" || rc="$?"
if [[ "$rc" != 126 ]]; then
echo "Exit code was: ${rc}"
exit 1
fi

# 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"
Expand Down
2 changes: 1 addition & 1 deletion ddist.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ docker run -it --rm \
-e CC="${CC:=gcc}" \
-e ARCH_NATIVE="${ARCH_NATIVE-1}" \
-e ARCH_SUFFIX="${ARCH_SUFFIX-}" \
-e NO_ARGS="${NO_ARGS-}" \
-e MINIMAL="${MINIMAL-}" \
"${IMG}" "${SRC}/ci/run_build.sh"
89 changes: 72 additions & 17 deletions src/tini.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,21 @@
#include "tiniConfig.h"
#include "tiniLicense.h"

#if TINI_MINIMAL
#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]))

Expand All @@ -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
Expand All @@ -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 };
Expand All @@ -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_MINIMAL
"use the -s option "
#endif
"or set the environment variable " SUBREAPER_ENV_VAR " to register Tini as a child subreaper, or "
#endif
"run Tini as PID 1.";
"run Tini as PID 1.";

int restore_signals(const signal_configuration_t* const sigconf_ptr) {
if (sigprocmask(SIG_SETMASK, sigconf_ptr->sigmask_ptr, NULL)) {
Expand All @@ -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;
}

Expand All @@ -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;
}
}
Expand All @@ -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) {

Expand All @@ -133,8 +148,21 @@ int spawn(const signal_configuration_t* const sigconf_ptr, char* const argv[], i
}

execvp(argv[0], argv);
PRINT_FATAL("Executing child process '%s' failed: '%s'", argv[0], strerror(errno));
return 1;

// execvp will only return on an error so make sure that we check the errno
// and exit with the correct return status for the error that we encountered
// See: http://www.tldp.org/LDP/abs/html/exitcodes.html#EXITCODESREF
int status = 1;
switch errno {
case ENOENT:
status = 127;
break;
case EACCES:
status = 126;
break;
}
PRINT_FATAL("exec %s failed: %s", argv[0], strerror(errno));
return status;
} else {
// Parent
PRINT_INFO("Spawned child process '%s' with pid '%i'", argv[0], pid);
Expand All @@ -145,15 +173,37 @@ 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_MINIMAL
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_MINIMAL
#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");
#endif
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");
}

Expand All @@ -172,9 +222,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_MINIMAL
int c;
while ((c = getopt(argc, argv, OPT_STRING)) != -1) {
switch (c) {
Expand Down Expand Up @@ -237,6 +285,12 @@ int parse_env() {
subreaper++;
}
#endif

char* env_verbosity = getenv(VERBOSITY_ENV_VAR);
if (env_verbosity != NULL) {
verbosity = atoi(env_verbosity);
}

return 0;
}

Expand Down Expand Up @@ -468,8 +522,9 @@ int main(int argc, char *argv[]) {
reaper_check();

/* Go on */
if (spawn(&child_sigconf, *child_args_ptr, &child_pid)) {
return 1;
int spawn_ret = spawn(&child_sigconf, *child_args_ptr, &child_pid);
if (spawn_ret) {
return spawn_ret;
}
free(child_args_ptr);

Expand Down
Loading

0 comments on commit 4a92b9e

Please sign in to comment.