Merge pull request #56 from krallin/release-0.11.0

Release 0.11.0
sync-readme v0.11.0
Thomas Orozco 8 years ago committed by GitHub
commit 9e617e76d7
  1. 53
      .travis.yml
  2. 14
      CMakeLists.txt
  3. 7
      Dockerfile
  4. 5
      README.md
  5. 14
      ci/install_deps.sh
  6. 193
      ci/run_build.sh
  7. 8
      ddist.sh
  8. 4
      src/tini.c
  9. 33
      test/reaping/stage_1.py
  10. 28
      test/run_inner_tests.py
  11. 5
      tpl/README.md.in
  12. 1
      tpl/VERSION.in
  13. 55
      tpl/travis.yml.tpl

@ -1,55 +1,34 @@
#####################################
# THIS FILE IS AUTOGENERATED! #
# Edit ./tpl/travis.yml.ypl instead #
#####################################
sudo: required
dist: trusty
language: c
compiler:
- gcc
- clang
addons:
apt:
packages:
- build-essential
- cmake
- rpm
- git
- gdb
- valgrind
- python-dev
- libcap-dev
- python-pip
- python-virtualenv
- hardening-includes
- gnupg
- vim-common
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
global:
- SIGN_BINARIES=1
- secure: "RKF9Z9gLxp6k/xITqn7ma1E9HfpYcDXuJFf4862WeH9EMnK9lDq+TWnGsQfkIlqh8h9goe7U+BvRiTibj9MiD5u7eluLo3dlwsLxPpYtyswYeLeC1wKKdT5LPGAXbRKomvBalRYMI+dDnGIM4w96mHgGGvx2zZXGkiAQhm6fJ3k="
- DIST_DIR="${HOME}/up"
before_install:
- openssl aes-256-cbc -K $encrypted_2893fd5649e7_key -iv $encrypted_2893fd5649e7_iv -in sign.key.enc -out sign.key -d || echo "Encrypted signing key unavailable"
script: ./ci/run_build.sh
sudo: false
script:
- sudo ./ci/install_deps.sh
- ./ci/run_build.sh
- ls -lah "$DIST_DIR"
deploy:
provider: releases
api_key:
secure: Yk90ANpSPv1iJy8QDXCPwfaSmEr/WIJ3bzhQ6X8JvZjfrwTosbh0HrUzQyeac3nyvNwj7YJRssolOFc21IBKPpCFTZqYxSkuLPU6ysG4HGHgN6YJhOMm4mG4KKJ6741q3DJendhZpalBhCEi+NcZK/PCSD97Vl4OqRjBUged0fs=
file:
- "./dist/tini"
- "./dist/tini.asc"
- "./dist/tini-static"
- "./dist/tini-static.asc"
- "./dist/tini_0.10.0.deb"
- "./dist/tini_0.10.0.rpm"
file: "${DIST_DIR}/*"
file_glob: true
on:
repo: krallin/tini
tags: true
condition: "$CC = gcc"
condition: '-z "$NO_ARGS"'

@ -3,9 +3,16 @@ project (tini C)
# Config
set (tini_VERSION_MAJOR 0)
set (tini_VERSION_MINOR 10)
set (tini_VERSION_MINOR 11)
set (tini_VERSION_PATCH 0)
# Build options
option(NO_ARGS "Disable argument parsing" OFF)
if(NO_ARGS)
add_definitions(-DTINI_NO_ARGS=1)
endif()
# Extract git version and dirty-ness
execute_process (
COMMAND git --git-dir "${PROJECT_SOURCE_DIR}/.git" --work-tree "${PROJECT_SOURCE_DIR}" log -n 1 --date=local --pretty=format:%h
@ -74,11 +81,12 @@ configure_file (
)
configure_file (
"${PROJECT_SOURCE_DIR}/tpl/travis.yml.tpl"
"${PROJECT_SOURCE_DIR}/.travis.yml"
"${PROJECT_SOURCE_DIR}/tpl/VERSION.in"
"${PROJECT_BINARY_DIR}/VERSION"
@ONLY
)
include_directories ("${PROJECT_BINARY_DIR}")
add_executable (tini src/tini.c)

@ -1,8 +1,7 @@
FROM ubuntu:precise
FROM ubuntu:trusty
RUN apt-get update \
&& apt-get install --no-install-recommends --yes build-essential git gdb valgrind cmake rpm python-dev libcap-dev python-pip python-virtualenv hardening-includes gnupg vim-common \
&& rm -rf /var/lib/apt/lists/*
COPY ci/install_deps.sh /install_deps.sh
RUN /install_deps.sh
# Pre-install those here for faster local builds.
RUN CFLAGS="-DPR_SET_CHILD_SUBREAPER=36 -DPR_GET_CHILD_SUBREAPER=37" pip install psutil python-prctl bitmap

@ -84,6 +84,11 @@ Using Nix, you can use the following command to install Tini:
nix-env --install tini
### ARM ###
ARM images are available! Find the list of available platforms under the
releases tab.
Options
-------

@ -0,0 +1,14 @@
#!/bin/bash
set -o errexit
set -o nounset
apt-get update
apt-get install --no-install-recommends --yes \
build-essential git gdb valgrind cmake rpm \
python-dev libcap-dev python-pip python-virtualenv \
hardening-includes gnupg vim-common \
gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu libc6-dev-arm64-cross \
gcc-arm-linux-gnueabihf binutils-arm-linux-gnueabi libc6-dev-armhf-cross
rm -rf /var/lib/apt/lists/*

@ -7,6 +7,8 @@ set -o pipefail
# Default compiler
: ${CC:="gcc"}
echo "CC=${CC}"
# Paths
: ${SOURCE_DIR:="."}
: ${DIST_DIR:="${SOURCE_DIR}/dist"}
@ -42,90 +44,181 @@ export REAL_PATH="${PATH}"
export PATH="${SOURCE_DIR}/ci/util:${PATH}"
# Build
cmake -B"${BUILD_DIR}" -H"${SOURCE_DIR}"
CMAKE_ARGS=(-B"${BUILD_DIR}" -H"${SOURCE_DIR}")
if [[ -n "${NO_ARGS:-}" ]]; then
CMAKE_ARGS+=(-DNO_ARGS=ON)
fi
cmake "${CMAKE_ARGS[@]}"
pushd "${BUILD_DIR}"
make clean
make
make package
if [[ -n "${ARCH_NATIVE:=}" ]]; then
make package
fi
popd
# 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}" -h
echo "Testing $tini for license"
"${tini}" -l | grep -i "mit license"
echo "Testing $tini with: true"
"${tini}" -vvv true
pkg_version="$(cat "${BUILD_DIR}/VERSION")"
if [[ -n "${ARCH_NATIVE:=}" ]]; then
echo "Built native package (ARCH_NATIVE=${ARCH_NATIVE})"
echo "Running smoke and internal tests"
BIN_TEST_DIR="${BUILD_DIR}/bin-test"
mkdir -p "$BIN_TEST_DIR"
export PATH="${BIN_TEST_DIR}:${PATH}"
# 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
if [[ -n "${NO_ARGS:-}" ]]; then
echo "Testing $tini with: true"
"${tini}" true
echo "Testing $tini with: false"
if "${tini}" false; then
exit 1
fi
# We try running binaries named after flags (both valid and invalid
# flags) and test that they run.
for flag in h s x; do
bin="-${flag}"
echo "Testing $tini can run binary: ${bin}"
cp "$(which true)" "${BIN_TEST_DIR}/${bin}"
"$tini" "$bin"
done
else
echo "Smoke test for $tini"
"${tini}" -h
echo "Testing $tini for license"
"${tini}" -l | grep -i "mit license"
echo "Testing $tini with: true"
"${tini}" -vvv true
echo "Testing $tini with: false"
if "${tini}" -vvv false; 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
fi
echo "Checking hardening on $tini"
hardening-check --nopie --nostackprotector --nobindnow "${tini}"
done
echo "Testing $tini with: false"
if "${tini}" -vvv false; then
exit 1
# Quick package audit
if which rpm >/dev/null; then
echo "Contents for RPM:"
rpm -qlp "${BUILD_DIR}/tini_${pkg_version}.rpm"
echo "--"
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
if which dpkg >/dev/null; then
echo "Contents for DEB:"
dpkg --contents "${BUILD_DIR}/tini_${pkg_version}.deb"
echo "--"
fi
echo "Checking hardening on $tini"
hardening-check --nopie --nostackprotector --nobindnow "${tini}"
done
# Compile test code
"${CC}" -o "${BUILD_DIR}/sigconf-test" "${SOURCE_DIR}/test/sigconf/sigconf-test.c"
# Move files to the dist dir for testing
mkdir -p "${DIST_DIR}"
cp "${BUILD_DIR}"/tini{,-static,*.rpm,*deb} "${DIST_DIR}"
# Create virtual environment to run tests.
# Accept system site packages for faster local builds.
VENV="${BUILD_DIR}/venv"
virtualenv --system-site-packages "${VENV}"
# Quick package audit
if which rpm; then
echo "Contents for RPM:"
rpm -qlp "${DIST_DIR}/tini"*.rpm
fi
# Don't use activate because it does not play nice with nounset
export PATH="${VENV}/bin:${PATH}"
export CFLAGS # We need them to build our test suite, regardless of FORCE_SUBREAPER
# Install test dependencies
pip install psutil python-prctl bitmap
if which dpkg; then
echo "Contents for DEB:"
dpkg --contents "${DIST_DIR}/tini"*deb
# Run tests
python "${SOURCE_DIR}/test/run_inner_tests.py"
else
if [[ ! -n "${ARCH_SUFFIX:=}" ]]; then
echo "Built cross package, but $ARCH_SUFFIX is empty!"
exit 1
fi
echo "Built cross package (ARCH_SUFFIX=${ARCH_SUFFIX})"
echo "Skipping smoke and internal tests"
fi
# Compile test code
"${CC}" -o "${BUILD_DIR}/sigconf-test" "${SOURCE_DIR}/test/sigconf/sigconf-test.c"
# Now, copy over files to DIST_DIR, with appropriate names depending on the
# architecture.
# Handle the DEB / RPM
mkdir -p "${DIST_DIR}"
TINIS=()
for tini in tini tini-static; do
if [[ -n "${ARCH_SUFFIX:=}" ]]; then
to="${DIST_DIR}/${tini}-${ARCH_SUFFIX}"
TINIS+=("$to")
cp "${BUILD_DIR}/${tini}" "$to"
fi
# Create virtual environment to run tests.
# Accept system site packages for faster local builds.
VENV="${BUILD_DIR}/venv"
virtualenv --system-site-packages "${VENV}"
if [[ -n "${ARCH_NATIVE:=}" ]]; then
to="${DIST_DIR}/${tini}"
TINIS+=("$to")
cp "${BUILD_DIR}/${tini}" "$to"
fi
done
# Don't use activate because it does not play nice with nounset
export PATH="${VENV}/bin:${PATH}"
export CFLAGS # We need them to build our test suite, regardless of FORCE_SUBREAPER
if [[ -n "${ARCH_NATIVE:=}" ]]; then
for pkg_format in deb rpm; do
src="${BUILD_DIR}/tini_${pkg_version}.${pkg_format}"
if [[ -n "${ARCH_SUFFIX:=}" ]]; then
to="${DIST_DIR}/tini_${pkg_version}-${ARCH_SUFFIX}.${pkg_format}"
TINIS+=("$to")
cp "$src" "$to"
fi
if [[ -n "${ARCH_NATIVE:=}" ]]; then
to="${DIST_DIR}/tini_${pkg_version}.${pkg_format}"
TINIS+=("$to")
cp "$src" "$to"
fi
done
fi
# Install test dependencies
pip install psutil python-prctl bitmap
echo "Tinis: ${TINIS[*]}"
# Run tests
python "${SOURCE_DIR}/test/run_inner_tests.py"
for tini in "${TINIS[@]}"; do
echo "${tini}:"
sha1sum "$tini"
file "$tini"
echo "--"
done
# If a signing key and passphrase are made available, then use it to sign the
# binaries
if [[ -n "$GPG_PASSPHRASE" ]] && [[ -f "${SOURCE_DIR}/sign.key" ]]; then
echo "Signing binaries"
echo "Signing tinis"
GPG_SIGN_HOMEDIR="${BUILD_DIR}/gpg-sign"
GPG_VERIFY_HOMEDIR="${BUILD_DIR}/gpg-verify"
PGP_KEY_FINGERPRINT="595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7"
PGP_KEYSERVER="ha.pool.sks-keyservers.net"
mkdir "${GPG_SIGN_HOMEDIR}" "${GPG_VERIFY_HOMEDIR}"
chmod 700 "${GPG_SIGN_HOMEDIR}" "${GPG_VERIFY_HOMEDIR}"
gpg --homedir "${GPG_SIGN_HOMEDIR}" --import "${SOURCE_DIR}/sign.key"
gpg --homedir "${GPG_VERIFY_HOMEDIR}" --keyserver "$PGP_KEYSERVER" --recv-keys "$PGP_KEY_FINGERPRINT"
for tini in "${DIST_DIR}/tini" "${DIST_DIR}/tini-static"; do
for tini in "${TINIS[@]}"; do
echo "${GPG_PASSPHRASE}" | gpg --homedir "${GPG_SIGN_HOMEDIR}" --passphrase-fd 0 --armor --detach-sign "${tini}"
gpg --homedir "${GPG_VERIFY_HOMEDIR}" --verify "${tini}.asc"
done

@ -2,8 +2,6 @@
set -o errexit
set -o nounset
: ${FORCE_SUBREAPER:="1"}
REL_HERE=$(dirname "${BASH_SOURCE}")
HERE=$(cd "${REL_HERE}"; pwd)
@ -21,6 +19,10 @@ docker run -it --rm \
--volume="${HERE}:${SRC}" \
-e BUILD_DIR=/tmp/tini-build \
-e SOURCE_DIR="${SRC}" \
-e FORCE_SUBREAPER="${FORCE_SUBREAPER}" \
-e FORCE_SUBREAPER="${FORCE_SUBREAPER:="1"}" \
-e GPG_PASSPHRASE="${GPG_PASSPHRASE:=}" \
-e CC="${CC:=gcc}" \
-e ARCH_NATIVE="${ARCH_NATIVE-1}" \
-e ARCH_SUFFIX="${ARCH_SUFFIX-}" \
-e NO_ARGS="${NO_ARGS-}" \
"${IMG}" "${SRC}/ci/run_build.sh"

@ -164,6 +164,9 @@ void print_license(FILE* const file) {
int parse_args(const int argc, char* const argv[], char* (**child_args_ptr_ptr)[], int* const parse_fail_exitcode_ptr) {
char* name = argv[0];
#if TINI_NO_ARGS
*parse_fail_exitcode_ptr = 0;
#else
int c;
while ((c = getopt(argc, argv, OPT_STRING)) != -1) {
switch (c) {
@ -197,6 +200,7 @@ int parse_args(const int argc, char* const argv[], char* (**child_args_ptr_ptr)[
return 1;
}
}
#endif
*child_args_ptr_ptr = calloc(argc-optind+1, sizeof(char*));
if (*child_args_ptr_ptr == NULL) {

@ -8,33 +8,50 @@ import time
import psutil
def in_group_or_reaped(pid):
try:
return os.getpgid(pid) == os.getpgid(0)
except OSError:
return True
def main():
p = subprocess.Popen([os.path.join(os.path.dirname(__file__), "stage_2.py")])
p.wait()
stage_2 = os.path.join(os.path.dirname(__file__), "stage_2.py")
subprocess.Popen([stage_2]).wait()
# In tests, we assume this process is the direct child of init
this_process = psutil.Process(os.getpid())
init_process = this_process.parent()
print("Reaping test: stage_1 is pid{0}, init is pid{1}".format(this_process.pid, init_process.pid))
print("Reaping test: stage_1 is pid{0}, init is pid{1}".format(
this_process.pid, init_process.pid))
# The only child PID that should persist is this one.
expected_pids = [this_process.pid]
print("Expecting pids to remain: {0}".format(", ".join(str(pid) for pid in expected_pids)))
print("Expecting pids to remain: {0}".format(
", ".join(str(pid) for pid in expected_pids)))
while 1:
pids = [p.pid for p in init_process.children(recursive=True)]
print("Has pids: {0}".format(", ".join(str(pid) for pid in pids)))
for pid in pids:
assert in_group_or_reaped(pid), "Child had unexpected pgid"
if set(pids) == set(expected_pids):
break
time.sleep(1)
# Now, check if there are any zombies
# Now, check if there are any zombies. For each of the potential zombies,
# we check that the pgid is ours. NOTE: We explicitly test that this test
# fails if subreaping is disabled, so we can be confident this doesn't turn
# a failure into a success.
for process in psutil.process_iter():
if process.name() == "sleep":
print("At least one 'sleep' process was still alive or not reaped! (pid{0})".format(process.pid))
sys.exit(1)
if process.pid == this_process.pid:
continue
if not in_group_or_reaped(process.pid):
continue
print("Not reaped: pid {0}: {1}".format(process.pid, process.name()))
sys.exit(1)
sys.exit(0)

@ -29,18 +29,19 @@ def main():
src = os.environ["SOURCE_DIR"]
build = os.environ["BUILD_DIR"]
args_disabled = os.environ.get("NO_ARGS")
proxy = os.path.join(src, "test", "subreaper-proxy.py")
tini = os.path.join(build, "tini")
subreaper_support = bool(int(os.environ["FORCE_SUBREAPER"]))
tests = [([proxy, tini, "--"], {}),]
tests = [([proxy, tini], {}),]
if subreaper_support:
tests.extend([
([tini, "-s", "--"], {}),
([tini, "--"], {"TINI_SUBREAPER": ""}),
])
if not args_disabled:
tests.append(([tini, "-s"], {}))
tests.append(([tini], {"TINI_SUBREAPER": ""}))
for target, env in tests:
# Run the reaping test
@ -56,7 +57,7 @@ def main():
# and will output the error message here.
assert "zombie reaping won't work" not in err, "Warning message was output!"
ret = p.wait()
assert ret == 0, "Reaping test failed!"
assert ret == 0, "Reaping test failed!\nOUT: %s\nERR: %s" % (out, err)
# Run the signals test
@ -71,17 +72,18 @@ def main():
# Run the process group test
# This test has Tini spawn a process that ignores SIGUSR1 and spawns a child that doesn't (and waits on the child)
# We send SIGUSR1 to Tini, and expect the grand-child to terminate, then the child, and then Tini.
print "Running process group test"
p = subprocess.Popen([tini, '-g', '--', os.path.join(src, "test", "pgroup", "stage_1.py")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if not args_disabled:
print "Running process group test"
p = subprocess.Popen([tini, '-g', os.path.join(src, "test", "pgroup", "stage_1.py")], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
busy_wait(lambda: len(psutil.Process(p.pid).children(recursive=True)) == 2, 10)
p.send_signal(signal.SIGUSR1)
busy_wait(lambda: p.poll() is not None, 10)
busy_wait(lambda: len(psutil.Process(p.pid).children(recursive=True)) == 2, 10)
p.send_signal(signal.SIGUSR1)
busy_wait(lambda: p.poll() is not None, 10)
# Run failing test
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)
out, err = p.communicate()
assert "zombie reaping won't work" in err, "No warning message was output!"
ret = p.wait()
@ -91,7 +93,7 @@ def main():
# Test that the signals are properly in place here.
print "running signal configuration test"
p = subprocess.Popen([os.path.join(build, "sigconf-test"), tini, '-g', '--', "cat", "/proc/self/status"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p = subprocess.Popen([os.path.join(build, "sigconf-test"), tini, "cat", "/proc/self/status"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
# Extract the signal properties, and add a zero at the end.

@ -84,6 +84,11 @@ Using Nix, you can use the following command to install Tini:
nix-env --install tini
### ARM ###
ARM images are available! Find the list of available platforms under the
releases tab.
Options
-------

@ -0,0 +1 @@
@tini_VERSION_MAJOR@.@tini_VERSION_MINOR@.@tini_VERSION_PATCH@

@ -1,55 +0,0 @@
#####################################
# THIS FILE IS AUTOGENERATED! #
# Edit ./tpl/travis.yml.ypl instead #
#####################################
language: c
compiler:
- gcc
- clang
addons:
apt:
packages:
- build-essential
- cmake
- rpm
- git
- gdb
- valgrind
- python-dev
- libcap-dev
- python-pip
- python-virtualenv
- hardening-includes
- gnupg
- vim-common
env:
global:
- SIGN_BINARIES=1
- secure: "RKF9Z9gLxp6k/xITqn7ma1E9HfpYcDXuJFf4862WeH9EMnK9lDq+TWnGsQfkIlqh8h9goe7U+BvRiTibj9MiD5u7eluLo3dlwsLxPpYtyswYeLeC1wKKdT5LPGAXbRKomvBalRYMI+dDnGIM4w96mHgGGvx2zZXGkiAQhm6fJ3k="
before_install:
- openssl aes-256-cbc -K $encrypted_2893fd5649e7_key -iv $encrypted_2893fd5649e7_iv -in sign.key.enc -out sign.key -d || echo "Encrypted signing key unavailable"
script: ./ci/run_build.sh
sudo: false
deploy:
provider: releases
api_key:
secure: Yk90ANpSPv1iJy8QDXCPwfaSmEr/WIJ3bzhQ6X8JvZjfrwTosbh0HrUzQyeac3nyvNwj7YJRssolOFc21IBKPpCFTZqYxSkuLPU6ysG4HGHgN6YJhOMm4mG4KKJ6741q3DJendhZpalBhCEi+NcZK/PCSD97Vl4OqRjBUged0fs=
file:
- "./dist/tini"
- "./dist/tini.asc"
- "./dist/tini-static"
- "./dist/tini-static.asc"
- "./dist/tini_@tini_VERSION_MAJOR@.@tini_VERSION_MINOR@.@tini_VERSION_PATCH@.deb"
- "./dist/tini_@tini_VERSION_MAJOR@.@tini_VERSION_MINOR@.@tini_VERSION_PATCH@.rpm"
on:
repo: krallin/tini
tags: true
condition: "$CC = gcc"
Loading…
Cancel
Save