[
  {
    "path": ".dockerignore",
    "content": "./dist\n"
  },
  {
    "path": ".gitignore",
    "content": "dist\nsign.key\n.env\n.mypy_cache\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: required\nservices:\n  - docker\n\nlanguage: generic\n\nenv:\n  matrix:\n    - ARCH_SUFFIX= CC=gcc ARCH_NATIVE=1 MINIMAL=\n    - ARCH_SUFFIX=amd64 CC=gcc ARCH_NATIVE=1 MINIMAL=\n    - ARCH_SUFFIX=amd64 CC=gcc ARCH_NATIVE=1 MINIMAL=1\n    - ARCH_SUFFIX=x86_64 CC=gcc ARCH_NATIVE=1 MINIMAL=\n    - ARCH_SUFFIX=x86_64 CC=gcc ARCH_NATIVE=1 MINIMAL=1\n    - ARCH_SUFFIX=arm64 CC=aarch64-linux-gnu-gcc ARCH_NATIVE= MINIMAL=\n    - ARCH_SUFFIX=armel CC=arm-linux-gnueabi-gcc ARCH_NATIVE= MINIMAL=\n    - ARCH_SUFFIX=armhf CC=arm-linux-gnueabihf-gcc ARCH_NATIVE= MINIMAL=\n    - ARCH_SUFFIX=i386 CFLAGS=\"-m32\" ARCH_NATIVE= MINIMAL=\n    - ARCH_SUFFIX=muslc-amd64 CC=musl-gcc ARCH_NATIVE=1 MINIMAL=\n    - ARCH_SUFFIX=ppc64el CC=powerpc64le-linux-gnu-gcc ARCH_NATIVE= MINIMAL=\n    - ARCH_SUFFIX=ppc64le CC=powerpc64le-linux-gnu-gcc ARCH_NATIVE= MINIMAL=\n    - ARCH_SUFFIX=s390x CC=s390x-linux-gnu-gcc ARCH_NATIVE= MINIMAL=\n    - ARCH_SUFFIX=mips64el CC=mips64el-linux-gnuabi64-gcc-5 ARCH_NATIVE= MINIMAL=\n  global:\n    - secure: \"RKF9Z9gLxp6k/xITqn7ma1E9HfpYcDXuJFf4862WeH9EMnK9lDq+TWnGsQfkIlqh8h9goe7U+BvRiTibj9MiD5u7eluLo3dlwsLxPpYtyswYeLeC1wKKdT5LPGAXbRKomvBalRYMI+dDnGIM4w96mHgGGvx2zZXGkiAQhm6fJ3k=\"\n    - DIST_DIR=\"${PWD}/dist\"\n\nbefore_install:\n  - 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\"\n\nscript:\n  - ./ddist.sh\n  - ls -lah \"$DIST_DIR\"\n  - git diff --exit-code\n\ndeploy:\n  provider: releases\n  api_key:\n    secure: VaYWmhdyhPYNvUy0tlGBYdjsdHIGHh/jwYzC96DBLS9BYIErtBkm21sdCLPKuNI1mGOwqoUjY+WywV2zJaBG10iBQCuFLpA9bblnN4fi257m79z7zqMbCvM145Up9x2jMQ0v03avd6pxCfQsr8WC9fnhWVYaD68Ir/hTpjZ60u8=\n  file: \"${DIST_DIR}/*\"\n  file_glob: true\n  skip_cleanup: true\n  on:\n    repo: krallin/tini\n    tags: true\n    condition: '-z \"$MINIMAL\"'\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required (VERSION 2.8.12...3.10)\nproject (tini C)\n\n# Config\nset (tini_VERSION_MAJOR 0)\nset (tini_VERSION_MINOR 19)\nset (tini_VERSION_PATCH 0)\n\n# Build options\noption(MINIMAL \"Disable argument parsing and verbose output\" OFF)\n\nif(MINIMAL)\n\tadd_definitions(-DTINI_MINIMAL=1)\nendif()\n\n# Extract git version and dirty-ness\nexecute_process (\n  COMMAND git --git-dir \"${PROJECT_SOURCE_DIR}/.git\" --work-tree \"${PROJECT_SOURCE_DIR}\" log -n 1 --date=local --pretty=format:%h\n  WORKING_DIRECTORY \"${PROJECT_SOURCE_DIR}\"\n  RESULT_VARIABLE git_version_check_ret\n  OUTPUT_VARIABLE tini_VERSION_GIT\n)\n\nexecute_process(\n  COMMAND git --git-dir \"${PROJECT_SOURCE_DIR}/.git\" --work-tree \"${PROJECT_SOURCE_DIR}\" status --porcelain --untracked-files=no\n  WORKING_DIRECTORY \"${PROJECT_SOURCE_DIR}\"\n  OUTPUT_VARIABLE git_dirty_check_out\n)\n\nif(\"${git_version_check_ret}\" EQUAL 0)\n  set(tini_VERSION_GIT \" - git.${tini_VERSION_GIT}\")\n  if(NOT \"${git_dirty_check_out}\" STREQUAL \"\")\n    set(tini_VERSION_GIT \"${tini_VERSION_GIT}-dirty\")\n  endif()\nelse()\n  set(tini_VERSION_GIT \"\")\nendif()\n\n# Flags\ninclude(CheckCSourceCompiles)\n\ncheck_c_source_compiles(\"\n#ifndef _FORTIFY_SOURCE\n#error \\\"Not defined: _FORTIFY_SOURCE\\\"\n#endif\nint main(void)                                                                                                              {\n  return 0;\n}\n\" HAS_BUILTIN_FORTIFY)\n\n# Flags\nif(NOT HAS_BUILTIN_FORTIFY)\n\tadd_definitions(-D_FORTIFY_SOURCE=2)\nendif()\n\nset (CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -std=gnu99 -Werror -Wextra -Wall -pedantic-errors -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat\")\nset (CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-s\")\n\n# Build\n\nconfigure_file (\n\t\"${PROJECT_SOURCE_DIR}/src/tiniConfig.h.in\"\n\t\"${PROJECT_BINARY_DIR}/tiniConfig.h\"\n\t@ONLY\n)\n\nconfigure_file (\n\t\"${PROJECT_SOURCE_DIR}/tpl/README.md.in\"\n\t\"${PROJECT_SOURCE_DIR}/README.md\"\n\t@ONLY\n)\n\nconfigure_file (\n\t\"${PROJECT_SOURCE_DIR}/tpl/VERSION.in\"\n\t\"${PROJECT_BINARY_DIR}/VERSION\"\n\t@ONLY\n)\n\n\ninclude_directories (\"${PROJECT_BINARY_DIR}\")\n\nadd_executable (tini src/tini.c)\n\nadd_executable (tini-static src/tini.c)\nset_target_properties (tini-static PROPERTIES LINK_FLAGS \"-Wl,--no-export-dynamic -static\")\n\n# Installation\ninstall (TARGETS tini DESTINATION bin)\ninstall (TARGETS tini-static DESTINATION bin)\n\n# Packaging\ninclude (InstallRequiredSystemLibraries)\nset (CPACK_PACKAGE_DESCRIPTION_SUMMARY \"A tiny but valid init process for containers\")\nset (CPACK_PACKAGE_VENDOR \"Thomas Orozco\")\nset (CPACK_PACKAGE_CONTACT \"thomas@orozco.fr\")\nset (CPACK_PACKAGE_DESCRIPTION_FILE \"${CMAKE_CURRENT_SOURCE_DIR}/README.md\")\nset (CPACK_RESOURCE_FILE_LICENSE \"${CMAKE_CURRENT_SOURCE_DIR}/LICENSE\")\nset (CPACK_PACKAGE_VERSION_MAJOR \"${tini_VERSION_MAJOR}\")\nset (CPACK_PACKAGE_VERSION_MINOR \"${tini_VERSION_MINOR}\")\nset (CPACK_PACKAGE_VERSION_PATCH \"${tini_VERSION_PATCH}\")\nset (CPACK_PACKAGE_EXECUTABLES \"${CMAKE_PROJECT_NAME}\")\nset (CPACK_PACKAGE_NAME \"${CMAKE_PROJECT_NAME}\")\nset (CPACK_PACKAGE_FILE_NAME \"${CMAKE_PROJECT_NAME}_${tini_VERSION_MAJOR}.${tini_VERSION_MINOR}.${tini_VERSION_PATCH}\")\nset (CPACK_PACKAGE_VERSION \"${tini_VERSION_MAJOR}.${tini_VERSION_MINOR}.${tini_VERSION_PATCH}\")\n\nset (CPACK_DEBIAN_PACKAGE_ARCHITECTURE \"amd64\")  # TODO\nset (CPACK_DEBIAN_PACKAGE_DEPENDS \"libc6 (>= 2.3.4)\")\n\nset (CPACK_RPM_PACKAGE_ARCHITECTURE \"x86_64\")\n\nset (CPACK_GENERATOR \"DEB\" \"RPM\")\n\ninclude (CPack)\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM ubuntu:xenial\n\nARG ARCH_SUFFIX\n\nCOPY ci/install_deps.sh /install_deps.sh\nRUN /install_deps.sh\n\n# Pre-install those here for faster local builds.\nRUN CFLAGS=\"-DPR_SET_CHILD_SUBREAPER=36 -DPR_GET_CHILD_SUBREAPER=37\" python3 -m pip install psutil python-prctl bitmap\n\nARG ARCH_NATIVE\nARG CC\n\n# Persist ARGs into the image\n\nENV ARCH_SUFFIX=\"$ARCH_SUFFIX\" \\\n    ARCH_NATIVE=\"$ARCH_NATIVE\" \\\n    CC=\"$CC\"\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Thomas Orozco <thomas@orozco.fr>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<!--\n\n#####################################\n# THIS FILE IS AUTOGENERATED!       #\n# Edit ./tpl/README.md.in instead   #\n#####################################\n\n-->\n\n\nTini - A tiny but valid `init` for containers\n=============================================\n\n[![Build Status](https://travis-ci.org/krallin/tini.svg?branch=master)](https://travis-ci.org/krallin/tini)\n\nTini is the simplest `init` you could think of.\n\nAll Tini does is spawn a single child (Tini is meant to be run in a container),\nand wait for it to exit all the while reaping zombies and performing\nsignal forwarding.\n\n\nWhy Tini?\n---------\n\nUsing Tini has several benefits:\n\n- It protects you from software that accidentally creates zombie processes,\n  which can (over time!) starve your entire system for PIDs (and make it\n  unusable).\n- It ensures that the *default signal handlers* work for the software you run\n  in your Docker image. For example, with Tini, `SIGTERM` properly terminates\n  your process even if you didn't explicitly install a signal handler for it.\n- It does so completely transparently! Docker images that work without Tini\n  will work with Tini without any changes.\n\nIf you'd like more detail on why this is useful, review this issue discussion:\n[What is advantage of Tini?][0].\n\n\nUsing Tini\n----------\n\n*NOTE: If you are using Docker 1.13 or greater, Tini is included in Docker\nitself. This includes all versions of Docker CE. To enable Tini, just [pass the\n`--init` flag to `docker run`][5].*\n\n*NOTE: There are [pre-built Docker images available for Tini][10]. If\nyou're currently using an Ubuntu or CentOS image as your base, you can use\none of those as a drop-in replacement.*\n\n*NOTE: There are Tini packages for Alpine Linux and NixOS. See below for\ninstallation instructions.*\n\nAdd Tini to your container, and make it executable. Then, just invoke Tini\nand pass your program and its arguments as arguments to Tini.\n\nIn Docker, you will want to use an entrypoint so you don't have to remember\nto manually invoke Tini:\n\n    # Add Tini\n    ENV TINI_VERSION=v0.19.0\n    ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\n    RUN chmod +x /tini\n    ENTRYPOINT [\"/tini\", \"--\"]\n\n    # Run your program under Tini\n    CMD [\"/your/program\", \"-and\", \"-its\", \"arguments\"]\n    # or docker run your-image /your/program ...\n\nNote that you *can* skip the `--` under certain conditions, but you might\nas well always include it to be safe. If you see an error message that\nlooks like `tini: invalid option -- 'c'`, then you *need* to add the `--`.\n\nArguments for Tini itself should be passed like `-v` in the following example:\n`/tini -v -- /your/program`.\n\n*NOTE: The binary linked above is a 64-bit dynamically-linked binary.*\n\n\n### Signed binaries ###\n\nThe `tini` and `tini-static` binaries are signed using the key `595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7`.\n\nYou can verify their signatures using `gpg` (which you may install using\nyour package manager):\n\n    ENV TINI_VERSION v0.19.0\n    ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\n    ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini.asc /tini.asc\n    RUN gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7 \\\n     && gpg --batch --verify /tini.asc /tini\n    RUN chmod +x /tini\n\n\n### Verifying binaries via checksum ###\n\nThe `tini` and `tini-static` binaries have generated checksums (`SHA1` and `SHA256`).\n\nYou can verify their checksums using `sha1sum` and `sha256sum` (which you may install using\nyour package manager):\n\n    ENV TINI_VERSION v0.19.0\n    RUN wget --no-check-certificate --no-cookies --quiet https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-amd64 \\\n        && wget --no-check-certificate --no-cookies --quiet https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-amd64.sha256sum \\\n        && echo \"$(cat tini-amd64.sha256sum)\" | sha256sum -c\n\n\n### Alpine Linux Package ###\n\nOn Alpine Linux, you can use the following command to install Tini:\n\n    RUN apk add --no-cache tini\n    # Tini is now available at /sbin/tini\n    ENTRYPOINT [\"/sbin/tini\", \"--\"]\n\n\n### NixOS ###\n\nUsing Nix, you can use the following command to install Tini:\n\n    nix-env --install tini\n\n\n### Debian ###\n\nOn Debian (Buster or newer), you can use the following command to install Tini:\n\n    apt-get install tini\n\nNote that this installs `/usr/bin/tini` (and `/usr/bin/tini-static`), not `/tini`.\n\n\n### Arch Linux ###\n\nOn Arch Linux, there is a package available on the [AUR](https://wiki.archlinux.org/index.php/Arch_User_Repository).\nInstall using the [official instructions](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages)\nor use an [AUR helper](https://wiki.archlinux.org/index.php/AUR_helpers):\n\n    pacaur -S tini\n\n\n### Other Platforms ###\n\nARM and 32-bit binaries are available! You can find the complete list of\navailable binaries under [the releases tab][11].\n\n\nOptions\n-------\n\n### Verbosity ###\n\nThe `-v` argument can be used for extra verbose output (you can pass it up to\n3 times, e.g. `-vvv`).\n\n\n### Subreaping ###\n\nBy default, Tini needs to run as PID 1 so that it can reap zombies (by\nrunning as PID 1, zombies get re-parented to Tini).\n\nIf for some reason, you cannot run Tini as PID 1, you should register Tini as\na process subreaper instead (only in Linux >= 3.4), by either:\n\n  + Passing the `-s` argument to Tini (`tini -s -- ...`)\n  + Setting the environment variable `TINI_SUBREAPER`\n    (e.g. `export TINI_SUBREAPER=`).\n\nThis will ensure that zombies get re-parented to Tini despite Tini not running\nas PID 1.\n\n*NOTE: Tini will issue a warning if it detects that it isn't running as PID 1\nand isn't registered as a subreaper. If you don't see a warning, you're fine.*\n\n\n### Remapping exit codes ###\n\nTini will reuse the child's exit code when exiting, but occasionally, this may\nnot be exactly what you want (e.g. if your child exits with 143 after receiving\nSIGTERM). Notably, this can be an issue with Java apps.\n\nIn this case, you can use the `-e` flag to remap an arbitrary exit code to 0.\nYou can pass the flag multiple times if needed.\n\nFor example:\n\n```\ntini -e 143 -- ...\n```\n\n\n### Process group killing ###\n\nBy default, Tini only kills its immediate child process.  This can be\ninconvenient if sending a signal to that process does not have the desired\neffect.  For example, if you do\n\n    docker run --rm krallin/ubuntu-tini sh -c 'sleep 10'\n\nand ctrl-C it, nothing happens: SIGINT is sent to the 'sh' process,\nbut that shell won't react to it while it is waiting for the 'sleep'\nto finish.\n\nYou can configure Tini to kill the child process group, so that every process\nin the group gets the signal, by either:\n\n  + Passing the `-g` argument to Tini (`tini -g -- ...`)\n  + Setting the environment variable `TINI_KILL_PROCESS_GROUP`\n    (e.g. `export TINI_KILL_PROCESS_GROUP=`).\n\nThis corresponds more closely to what happens when you do ctrl-C etc. in a\nterminal: The signal is sent to the foreground process group.\n\n    docker run --rm --entrypoint tini krallin/ubuntu-tini -g -- sh -c 'sleep 10'\n\n### Parent Death Signal ###\n\nTini can set its parent death signal, which is the signal Tini should receive\nwhen *its* parent exits. To set the parent death signal, use the `-p` flag with\nthe name of the signal Tini should receive when its parent exits:\n\n```\ntini -p SIGTERM -- ...\n```\n\n*NOTE: See [this PR discussion][12] to learn more about the parent death signal\nand use cases.*\n\n\nMore\n----\n\n### Existing Entrypoint ###\n\nTini can also be used with an existing entrypoint in your container!\n\nAssuming your entrypoint was `/docker-entrypoint.sh`, then you would use:\n\n    ENTRYPOINT [\"/tini\", \"--\", \"/docker-entrypoint.sh\"]\n\n\n### Statically-Linked Version ###\n\nTini has very few dependencies (it only depends on libc), but if your\ncontainer fails to start, you might want to consider using the statically-built\nversion instead:\n\n    ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static /tini\n\n\n### Size Considerations ###\n\nTini is a very small file (in the 10KB range), so it doesn't add much weight\nto your container.\n\nThe statically-linked version is bigger, but still < 1M.\n\n\nBuilding Tini\n-------------\n\nIf you'd rather not download the binary, you can build Tini by running\n`cmake . && make`.\n\nBefore building, you probably also want to run:\n\n    export CFLAGS=\"-DPR_SET_CHILD_SUBREAPER=36 -DPR_GET_CHILD_SUBREAPER=37\"\n\nThis ensure that even if you're building on a system that has old Linux Kernel\nheaders (< 3.4), Tini will be built with child subreaper support. This is\nusually what you want if you're going to use Tini with Docker (if your host\nKernel supports Docker, it should also support child subreapers).\n\n\nUnderstanding Tini\n------------------\n\nAfter spawning your process, Tini will wait for signals and forward those\nto the child process, and periodically reap zombie processes that may be\ncreated within your container.\n\nWhen the \"first\" child process exits (`/your/program` in the examples above),\nTini exits as well, with the exit code of the child process (so you can\ncheck your container's exit code to know whether the child exited\nsuccessfully).\n\n\nDebugging\n---------\n\nIf something isn't working just like you expect, consider increasing the\nverbosity level (up to 3):\n\n    tini -v    -- bash -c 'exit 1'\n    tini -vv   -- true\n    tini -vvv  -- pwd\n\n\nAuthors\n=======\n\nMaintainer:\n\n  + [Thomas Orozco][20]\n\nContributors:\n\n  + [Tianon Gravi][30]\n  + [David Wragg][31]\n  + [Michael Crosby][32]\n  + [Wyatt Preul][33]\n  + [Patrick Steinhardt][34]\n\nSpecial thanks to:\n\n  + [Danilo Bürger][40] for packaging Tini for Alpine\n  + [Asko Soukka][41] for packaging Tini for Nix\n  + [nfnty][42] for packaging Tini for Arch Linux\n\n\n  [0]: https://github.com/krallin/tini/issues/8\n  [5]: https://docs.docker.com/engine/reference/commandline/run/\n  [10]: https://github.com/krallin/tini-images\n  [11]: https://github.com/krallin/tini/releases\n  [12]: https://github.com/krallin/tini/pull/114\n  [20]: https://github.com/krallin/\n  [30]: https://github.com/tianon\n  [31]: https://github.com/dpw\n  [32]: https://github.com/crosbymichael\n  [33]: https://github.com/geek\n  [34]: https://github.com/pks-t\n  [40]: https://github.com/danilobuerger\n  [41]: https://github.com/datakurre\n  [42]: https://github.com/nfnty/pkgbuilds/tree/master/tini/tini\n"
  },
  {
    "path": "ci/install_deps.sh",
    "content": "#!/bin/bash\nset -o errexit\nset -o nounset\nset -o xtrace\n\nDEPS=(\n  build-essential git gdb valgrind cmake rpm file\n  libcap-dev python3-dev python3-pip python3-setuptools\n  hardening-includes gnupg\n)\n\ncase \"${ARCH_SUFFIX-}\" in\n  amd64|x86_64|'') ;;\n  arm64) DEPS+=(gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu libc6-dev-arm64-cross) ;;\n  armel) DEPS+=(gcc-arm-linux-gnueabi binutils-arm-linux-gnueabi libc6-dev-armel-cross) ;;\n  armhf) DEPS+=(gcc-arm-linux-gnueabihf binutils-arm-linux-gnueabihf libc6-dev-armhf-cross) ;;\n  i386) DEPS+=(libc6-dev-i386  gcc-multilib) ;;\n  muslc-amd64) DEPS+=(musl-tools) ;;\n  ppc64el|ppc64le) DEPS+=(gcc-powerpc64le-linux-gnu binutils-powerpc64le-linux-gnu libc6-dev-ppc64el-cross) ;;\n  s390x) DEPS+=(gcc-s390x-linux-gnu binutils-s390x-linux-gnu libc6-dev-s390x-cross) ;;\n  mips64el) DEPS+=(gcc-5-mips64el-linux-gnuabi64 binutils-mips64el-linux-gnuabi64 libc6-dev-mips64el-cross) ;;\n  *) echo \"Unknown ARCH_SUFFIX=${ARCH_SUFFIX-}\"; exit 1 ;;\nesac\n\napt-get update\napt-get install --no-install-recommends --yes \"${DEPS[@]}\"\nrm -rf /var/lib/apt/lists/*\n\npython3 -m pip install --upgrade pip\npython3 -m pip install virtualenv\n"
  },
  {
    "path": "ci/run_build.sh",
    "content": "#!/bin/bash\n# Should be run from the root dir, or SOURCE_DIR should be set.\nset -o errexit\nset -o nounset\nset -o pipefail\n\n# Default compiler\n: ${CC:=\"gcc\"}\n\n\n# Paths\n: ${SOURCE_DIR:=\".\"}\n: ${DIST_DIR:=\"${SOURCE_DIR}/dist\"}\n: ${BUILD_DIR:=\"/tmp/build\"}\n\n# GPG Configuration\n: ${GPG_PASSPHRASE:=\"\"}\n\n\n# Make those paths absolute, and export them for the Python tests to consume.\nexport SOURCE_DIR=\"$(readlink -f \"${SOURCE_DIR}\")\"\nexport DIST_DIR=\"$(readlink -f \"${DIST_DIR}\")\"\nexport BUILD_DIR=\"$(readlink -f \"${BUILD_DIR}\")\"\n\n# Configuration\n: ${FORCE_SUBREAPER:=\"1\"}\nexport FORCE_SUBREAPER\n\n\n# Our build platform doesn't have those newer Linux flags, but we want Tini to have subreaper support\n# We also use those in our tests\nCFLAGS=\"${CFLAGS-} -DPR_SET_CHILD_SUBREAPER=36 -DPR_GET_CHILD_SUBREAPER=37\"\nif [[ \"${FORCE_SUBREAPER}\" -eq 1 ]]; then\n  # If FORCE_SUBREAPER is requested, then we set those CFLAGS for the Tini build\n  export CFLAGS\nfi\n\necho \"CC=${CC}\"\necho \"CFLAGS=${CFLAGS}\"\necho \"MINIMAL=${MINIMAL-}\"\necho \"ARCH_SUFFIX=${ARCH_SUFFIX-}\"\necho \"ARCH_NATIVE=${ARCH_NATIVE-}\"\n\n# Ensure Python output is not buffered (to make tests output clearer)\nexport PYTHONUNBUFFERED=1\n\n# Set path to prioritize our utils\nexport REAL_PATH=\"${PATH}\"\nexport PATH=\"${SOURCE_DIR}/ci/util:${PATH}\"\n\n# Build\nCMAKE_ARGS=(-B\"${BUILD_DIR}\" -H\"${SOURCE_DIR}\")\nif [[ -n \"${MINIMAL:-}\" ]]; then\n  CMAKE_ARGS+=(-DMINIMAL=ON)\nfi\ncmake \"${CMAKE_ARGS[@]}\"\n\npushd \"${BUILD_DIR}\"\nmake clean\nmake\nif [[ -n \"${ARCH_NATIVE-}\" ]]; then\n  make package\nfi\npopd\n\npkg_version=\"$(cat \"${BUILD_DIR}/VERSION\")\"\n\nif [[ -n \"${ARCH_NATIVE-}\" ]]; then\n  echo \"Built native package (ARCH_NATIVE=${ARCH_NATIVE-})\"\n  echo \"Running smoke and internal tests\"\n\n  BIN_TEST_DIR=\"${BUILD_DIR}/bin-test\"\n  mkdir -p \"$BIN_TEST_DIR\"\n  export PATH=\"${BIN_TEST_DIR}:${PATH}\"\n\n  # Smoke tests (actual tests need Docker to run; they don't run within the CI environment)\n  for tini in \"${BUILD_DIR}/tini\" \"${BUILD_DIR}/tini-static\"; do\n    echo \"Smoke test for ${tini}\"\n    \"$tini\" --version\n\n    echo \"Testing ${tini} --version\"\n    \"$tini\" --version | grep -q \"tini version\"\n\n    echo \"Testing ${tini} without arguments exits with 1\"\n    ! \"$tini\" 2>/dev/null\n\n    echo \"Testing ${tini} shows help message\"\n    {\n      ! \"$tini\" 2>&1\n    } | grep -q \"supervision of a valid init process\"\n\n    if [[ -n \"${MINIMAL:-}\" ]]; then\n      echo \"Testing $tini with: true\"\n      \"${tini}\" true\n\n      echo \"Testing $tini with: false\"\n      if \"${tini}\" false; then\n        exit 1\n      fi\n\n      echo \"Testing ${tini} does not reference options that don't exist\"\n      ! {\n        ! \"$tini\" 2>&1\n      } | grep -q \"more verbose\"\n\n      # We try running binaries named after flags (both valid and invalid\n      # flags) and test that they run.\n      for flag in h s w x; do\n        bin=\"-${flag}\"\n        echo \"Testing $tini can run binary: ${bin}\"\n        cp \"$(which true)\" \"${BIN_TEST_DIR}/${bin}\"\n        \"$tini\" \"$bin\"\n      done\n\n      echo \"Testing $tini can run binary --version if args are given\"\n      cp \"$(which true)\" \"${BIN_TEST_DIR}/--version\"\n      if \"$tini\" \"--version\" --foo | grep -q \"tini version\"; then\n        exit 1\n      fi\n    else\n      echo \"Testing ${tini} -h\"\n      \"${tini}\" -h\n\n      echo \"Testing $tini for license\"\n      \"$tini\" -l | diff - \"${SOURCE_DIR}/LICENSE\"\n\n      echo \"Testing $tini with: true\"\n      \"${tini}\" -vvv true\n\n      echo \"Testing $tini with: false\"\n      if \"${tini}\" -vvv false; then\n        exit 1\n      fi\n\n      echo \"Testing ${tini} references options that exist\"\n      {\n        ! \"$tini\" 2>&1\n      } | grep -q \"more verbose\"\n\n      echo \"Testing $tini with: -- true (should succeed)\"\n      \"${tini}\" -vvv -- true\n\n      echo \"Testing $tini with: -- -- true (should fail)\"\n      if \"${tini}\" -vvv -- -- true; then\n        exit 1\n      fi\n    fi\n\n    echo \"Testing ${tini} supports TINI_VERBOSITY\"\n    TINI_VERBOSITY=3 \"$tini\" true 2>&1 | grep -q 'Received SIGCHLD'\n\n    echo \"Testing ${tini} exits with 127 if the command does not exist\"\n    \"$tini\" foobar123 && rc=\"$?\" || rc=\"$?\"\n    if [[ \"$rc\" != 127 ]]; then\n      echo \"Exit code was: ${rc}\"\n      exit 1\n    fi\n\n    echo \"Testing ${tini} exits with 126 if the command is not executable\"\n    \"$tini\" /etc && rc=\"$?\" || rc=\"$?\"\n    if [[ \"$rc\" != 126 ]]; then\n      echo \"Exit code was: ${rc}\"\n      exit 1\n    fi\n\n    # Test stdin / stdout are handed over to child\n    echo \"Testing ${tini} does not break pipes\"\n    echo \"exit 0\" | \"${tini}\" sh\n    if [[ ! \"$?\" -eq \"0\" ]]; then\n      echo \"Pipe test failed\"\n      exit 1\n    fi\n\n    echo \"Checking hardening on $tini\"\n    hardening_skip=(--nopie --nostackprotector --nobindnow)\n    if [[ \"$CC\" == \"musl-gcc\" ]]; then\n      # FORTIFY_SOURCE is a glibc thing\n      hardening_skip=(\"${hardening_skip[@]}\" --nofortify)\n    fi\n    hardening-check  \"${hardening_skip[@]}\" \"${tini}\"\n  done\n\n  # Quick package audit\n  if which rpm >/dev/null; then\n    echo \"Contents for RPM:\"\n    rpm -qlp \"${BUILD_DIR}/tini_${pkg_version}.rpm\"\n    echo \"--\"\n  fi\n\n  if which dpkg >/dev/null; then\n    echo \"Contents for DEB:\"\n    dpkg --contents \"${BUILD_DIR}/tini_${pkg_version}.deb\"\n    echo \"--\"\n  fi\n\n  # Compile test code\n  \"${CC}\" -o \"${BUILD_DIR}/sigconf-test\" \"${SOURCE_DIR}/test/sigconf/sigconf-test.c\"\n\n  # Create virtual environment to run tests.\n  # Accept system site packages for faster local builds.\n  VENV=\"${BUILD_DIR}/venv\"\n  virtualenv --system-site-packages \"${VENV}\"\n\n  # Don't use activate because it does not play nice with nounset\n  export PATH=\"${VENV}/bin:${PATH}\"\n  export CFLAGS  # We need them to build our test suite, regardless of FORCE_SUBREAPER\n\n  # Install test dependencies\n  CC=gcc python3 -m pip install psutil python-prctl bitmap\n\n  # Run tests\n  python3 \"${SOURCE_DIR}/test/run_inner_tests.py\"\nelse\n  echo \"Not a native build, skipping smoke and internal tests\"\nfi\n\n# Now, copy over files to DIST_DIR, with appropriate names depending on the\n# architecture.\n# Handle the DEB / RPM\nmkdir -p \"${DIST_DIR}\"\n\nDIST_TINIS=()\n\nSUFFIX=\"\"\nif [[ -n \"$ARCH_SUFFIX\" ]]; then\n  SUFFIX=\"-${ARCH_SUFFIX}\"\nelif [[ -z \"$ARCH_NATIVE\" ]]; then\n  echo \"Refusing to publish a non-native build without suffix!\"\n  exit 1\nfi\n\nfor build_tini in tini tini-static; do\n  dist_tini=\"${build_tini}${SUFFIX}\"\n  cp \"${BUILD_DIR}/${build_tini}\" \"${DIST_DIR}/${dist_tini}\"\n  DIST_TINIS+=(\"$dist_tini\")\ndone\n\nif [[ -n \"${ARCH_NATIVE-}\" ]]; then\n  for pkg_format in deb rpm; do\n    build_tini=\"tini_${pkg_version}.${pkg_format}\"\n    dist_tini=\"tini_${pkg_version}${SUFFIX}.${pkg_format}\"\n    cp \"${BUILD_DIR}/${build_tini}\" \"${DIST_DIR}/${dist_tini}\"\n    DIST_TINIS+=(\"$dist_tini\")\n  done\nfi\n\necho \"Tinis: ${DIST_TINIS[*]}\"\n\npushd \"$DIST_DIR\"\n\nfor tini in \"${DIST_TINIS[@]}\"; do\n  echo \"${tini}:\"\n\n  for sum in sha1sum sha256sum; do\n    \"$sum\" \"$tini\" | tee \"${tini}.${sum}\"\n  done\n\n  file \"$tini\"\n  echo \"--\"\ndone\n\n# If a signing key and passphrase are made available, then use it to sign the\n# binaries\nif [[ -n \"$GPG_PASSPHRASE\" ]] && [[ -f \"${SOURCE_DIR}/sign.key\" ]]; then\n  echo \"Signing tinis\"\n  GPG_SIGN_HOMEDIR=\"${BUILD_DIR}/gpg-sign\"\n  GPG_VERIFY_HOMEDIR=\"${BUILD_DIR}/gpg-verify\"\n  PGP_KEY_FINGERPRINT=\"595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7\"\n  PGP_KEYSERVER=\"ha.pool.sks-keyservers.net\"\n\n  mkdir \"${GPG_SIGN_HOMEDIR}\" \"${GPG_VERIFY_HOMEDIR}\"\n  chmod 700 \"${GPG_SIGN_HOMEDIR}\" \"${GPG_VERIFY_HOMEDIR}\"\n\n  gpg --homedir \"${GPG_SIGN_HOMEDIR}\" --import \"${SOURCE_DIR}/sign.key\"\n  gpg --homedir \"${GPG_VERIFY_HOMEDIR}\" --keyserver \"$PGP_KEYSERVER\" --recv-keys \"$PGP_KEY_FINGERPRINT\"\n\n  for tini in \"${DIST_TINIS[@]}\"; do\n    echo \"${GPG_PASSPHRASE}\" | gpg --homedir \"${GPG_SIGN_HOMEDIR}\" --passphrase-fd 0 --armor --detach-sign \"${tini}\"\n    gpg --homedir \"${GPG_VERIFY_HOMEDIR}\" --verify \"${tini}.asc\"\n  done\nfi\n\npopd\n"
  },
  {
    "path": "ci/util/rpmbuild",
    "content": "#!/bin/bash\n# Wrapper for rpm build that first removes files that should be in there\n# We need this for compatibility with CMake <= 2.8.10 (which is the only version we have in Travis)\n# See: http://www.cmake.org/pipermail/cmake-commits/2013-April/014818.html\nset -o nounset\nset -o errexit\nset -o pipefail\n\n# Remove PATH hack so we can find the real rpmbuild\nexport PATH=\"${REAL_PATH}\"\n\necho \"Using local rpmbuild\"\n\nspecFile=\"${!#}\"  # Last argument\n\nfor removeLine in '\"/usr\"' '\"/usr/bin\"'; do\n  sed -i \"s|${removeLine}||g\" \"${specFile}\"\ndone\n\n# Passthrough to rpmbuild\nexec rpmbuild \"${@}\"\n"
  },
  {
    "path": "ddist.sh",
    "content": "#!/bin/bash\nset -o errexit\nset -o nounset\n\nREL_HERE=$(dirname \"${BASH_SOURCE}\")\nHERE=$(cd \"${REL_HERE}\"; pwd)\n\nIMG=\"tini-build\"\n\nif [[ -n \"${ARCH_SUFFIX-}\" ]]; then\n  IMG=\"${IMG}_${ARCH_SUFFIX}\"\nfi\n\nif [[ -n \"${ARCH_NATIVE-}\" ]]; then\n  IMG=\"${IMG}_native\"\nfi\n\nif [[ -n \"${CC-}\" ]]; then\n  IMG=\"${IMG}_${CC}\"\nfi\n\n# Cleanup the build dir\nrm -f \"${HERE}/dist\"/*\n\n# Create the build image\necho \"build: ${IMG}\"\n\ndocker build \\\n  --build-arg \"ARCH_SUFFIX=${ARCH_SUFFIX-}\" \\\n  --build-arg \"ARCH_NATIVE=${ARCH_NATIVE-}\" \\\n  --build-arg \"CC=${CC-gcc}\" \\\n  -t \"${IMG}\" \\\n  .\n\n# Build new Tini\nSRC=\"/tini\"\n\ndocker run -it --rm \\\n  --volume=\"${HERE}:${SRC}\" \\\n  -e BUILD_DIR=/tmp/tini-build \\\n  -e SOURCE_DIR=\"${SRC}\" \\\n  -e FORCE_SUBREAPER=\"${FORCE_SUBREAPER-1}\" \\\n  -e GPG_PASSPHRASE=\"${GPG_PASSPHRASE-}\" \\\n  -e CFLAGS=\"${CFLAGS-}\" \\\n  -e MINIMAL=\"${MINIMAL-}\" \\\n  -u \"$(id -u):$(id -g)\" \\\n  \"${IMG}\" \"${SRC}/ci/run_build.sh\"\n"
  },
  {
    "path": "dtest.sh",
    "content": "#!/bin/bash\nset -o errexit\nset -o nounset\n\nIMG=\"tini\"\n\nif [[ \"$#\" != 1 ]]; then\n  echo \"Usage: $0 ARCH_SUFFIX\"\n  exit 1\nfi\nsuffix=\"$1\"\n\nIMG=\"tini-build-${suffix}\"\npython test/run_outer_tests.py \"${IMG}\"\n"
  },
  {
    "path": "run_tests.sh",
    "content": "#!/bin/bash\nset -o errexit\nset -o nounset\n\nREL_HERE=$(dirname \"${BASH_SOURCE}\")\nHERE=$(cd \"${REL_HERE}\"; pwd)\n\nfor i in $(seq 0 1); do\n  export FORCE_SUBREAPER=\"${i}\"\n  echo \"Testing with FORCE_SUBREAPER=${FORCE_SUBREAPER}\"\n  \"${HERE}/ddist.sh\"\n  \"${HERE}/dtest.sh\"\ndone\n"
  },
  {
    "path": "src/tini.c",
    "content": "/* See LICENSE file for copyright and license details. */\n#define _GNU_SOURCE\n\n#include <sys/types.h>\n#include <sys/wait.h>\n#include <sys/prctl.h>\n\n#include <assert.h>\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <time.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <stdbool.h>\n#include <libgen.h>\n\n#include \"tiniConfig.h\"\n#include \"tiniLicense.h\"\n\n#if TINI_MINIMAL\n#define PRINT_FATAL(...)                         fprintf(stderr, __VA_ARGS__); fprintf(stderr, \"\\n\");\n#define PRINT_WARNING(...)  if (verbosity > 0) { fprintf(stderr, __VA_ARGS__); fprintf(stderr, \"\\n\"); }\n#define PRINT_INFO(...)     if (verbosity > 1) { fprintf(stdout, __VA_ARGS__); fprintf(stdout, \"\\n\"); }\n#define PRINT_DEBUG(...)    if (verbosity > 2) { fprintf(stdout, __VA_ARGS__); fprintf(stdout, \"\\n\"); }\n#define PRINT_TRACE(...)    if (verbosity > 3) { fprintf(stdout, __VA_ARGS__); fprintf(stdout, \"\\n\"); }\n#define DEFAULT_VERBOSITY 0\n#else\n#define PRINT_FATAL(...)                         fprintf(stderr, \"[FATAL tini (%i)] \", getpid()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, \"\\n\");\n#define PRINT_WARNING(...)  if (verbosity > 0) { fprintf(stderr, \"[WARN  tini (%i)] \", getpid()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, \"\\n\"); }\n#define PRINT_INFO(...)     if (verbosity > 1) { fprintf(stdout, \"[INFO  tini (%i)] \", getpid()); fprintf(stdout, __VA_ARGS__); fprintf(stdout, \"\\n\"); }\n#define PRINT_DEBUG(...)    if (verbosity > 2) { fprintf(stdout, \"[DEBUG tini (%i)] \", getpid()); fprintf(stdout, __VA_ARGS__); fprintf(stdout, \"\\n\"); }\n#define PRINT_TRACE(...)    if (verbosity > 3) { fprintf(stdout, \"[TRACE tini (%i)] \", getpid()); fprintf(stdout, __VA_ARGS__); fprintf(stdout, \"\\n\"); }\n#define DEFAULT_VERBOSITY 1\n#endif\n\n#define ARRAY_LEN(x)  (sizeof(x) / sizeof((x)[0]))\n\n#define INT32_BITFIELD_SET(F, i)     ( F[(i / 32)] |=  (1 << (i % 32)) )\n#define INT32_BITFIELD_CLEAR(F, i)   ( F[(i / 32)] &= ~(1 << (i % 32)) )\n#define INT32_BITFIELD_TEST(F, i)    ( F[(i / 32)] &   (1 << (i % 32)) )\n#define INT32_BITFIELD_CHECK_BOUNDS(F, i) do {  assert(i >= 0); assert(ARRAY_LEN(F) > (uint) (i / 32)); } while(0)\n\n#define STATUS_MAX 255\n#define STATUS_MIN 0\n\ntypedef struct {\n   sigset_t* const sigmask_ptr;\n   struct sigaction* const sigttin_action_ptr;\n   struct sigaction* const sigttou_action_ptr;\n} signal_configuration_t;\n\nstatic const struct {\n   char *const name;\n   int number;\n} signal_names[] = {\n   { \"SIGHUP\", SIGHUP },\n   { \"SIGINT\", SIGINT },\n   { \"SIGQUIT\", SIGQUIT },\n   { \"SIGILL\", SIGILL },\n   { \"SIGTRAP\", SIGTRAP },\n   { \"SIGABRT\", SIGABRT },\n   { \"SIGBUS\", SIGBUS },\n   { \"SIGFPE\", SIGFPE },\n   { \"SIGKILL\", SIGKILL },\n   { \"SIGUSR1\", SIGUSR1 },\n   { \"SIGSEGV\", SIGSEGV },\n   { \"SIGUSR2\", SIGUSR2 },\n   { \"SIGPIPE\", SIGPIPE },\n   { \"SIGALRM\", SIGALRM },\n   { \"SIGTERM\", SIGTERM },\n   { \"SIGCHLD\", SIGCHLD },\n   { \"SIGCONT\", SIGCONT },\n   { \"SIGSTOP\", SIGSTOP },\n   { \"SIGTSTP\", SIGTSTP },\n   { \"SIGTTIN\", SIGTTIN },\n   { \"SIGTTOU\", SIGTTOU },\n   { \"SIGURG\", SIGURG },\n   { \"SIGXCPU\", SIGXCPU },\n   { \"SIGXFSZ\", SIGXFSZ },\n   { \"SIGVTALRM\", SIGVTALRM },\n   { \"SIGPROF\", SIGPROF },\n   { \"SIGWINCH\", SIGWINCH },\n   { \"SIGSYS\", SIGSYS },\n};\n\nstatic unsigned int verbosity = DEFAULT_VERBOSITY;\n\nstatic int32_t expect_status[(STATUS_MAX - STATUS_MIN + 1) / 32];\n\n#ifdef PR_SET_CHILD_SUBREAPER\n#define HAS_SUBREAPER 1\n#define OPT_STRING \"p:hvwgle:s\"\n#define SUBREAPER_ENV_VAR \"TINI_SUBREAPER\"\n#else\n#define HAS_SUBREAPER 0\n#define OPT_STRING \"p:hvwgle:\"\n#endif\n\n#define VERBOSITY_ENV_VAR \"TINI_VERBOSITY\"\n#define KILL_PROCESS_GROUP_GROUP_ENV_VAR \"TINI_KILL_PROCESS_GROUP\"\n\n#define TINI_VERSION_STRING \"tini version \" TINI_VERSION TINI_GIT\n\n\n#if HAS_SUBREAPER\nstatic unsigned int subreaper = 0;\n#endif\nstatic unsigned int parent_death_signal = 0;\nstatic unsigned int kill_process_group = 0;\n\nstatic unsigned int warn_on_reap = 0;\n\nstatic struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };\n\nstatic const char reaper_warning[] = \"Tini is not running as PID 1 \"\n#if HAS_SUBREAPER\n       \"and isn't registered as a child subreaper\"\n#endif\n\".\\n\\\nZombie processes will not be re-parented to Tini, so zombie reaping won't work.\\n\\\nTo fix the problem, \"\n#if HAS_SUBREAPER\n#ifndef TINI_MINIMAL\n\"use the -s option or \"\n#endif\n\"set the environment variable \" SUBREAPER_ENV_VAR \" to register Tini as a child subreaper, or \"\n#endif\n\"run Tini as PID 1.\";\n\nint restore_signals(const signal_configuration_t* const sigconf_ptr) {\n\tif (sigprocmask(SIG_SETMASK, sigconf_ptr->sigmask_ptr, NULL)) {\n\t\tPRINT_FATAL(\"Restoring child signal mask failed: '%s'\", strerror(errno));\n\t\treturn 1;\n\t}\n\n\tif (sigaction(SIGTTIN, sigconf_ptr->sigttin_action_ptr, NULL)) {\n\t\tPRINT_FATAL(\"Restoring SIGTTIN handler failed: '%s'\", strerror((errno)));\n\t\treturn 1;\n\t}\n\n\tif (sigaction(SIGTTOU, sigconf_ptr->sigttou_action_ptr, NULL)) {\n\t\tPRINT_FATAL(\"Restoring SIGTTOU handler failed: '%s'\", strerror((errno)));\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nint isolate_child(void) {\n\t// Put the child into a new process group.\n\tif (setpgid(0, 0) < 0) {\n\t\tPRINT_FATAL(\"setpgid failed: %s\", strerror(errno));\n\t\treturn 1;\n\t}\n\n\t// If there is a tty, allocate it to this new process group. We\n\t// can do this in the child process because we're blocking\n\t// SIGTTIN / SIGTTOU.\n\n\t// Doing it in the child process avoids a race condition scenario\n\t// if Tini is calling Tini (in which case the grandparent may make the\n\t// parent the foreground process group, and the actual child ends up...\n\t// in the background!)\n\tif (tcsetpgrp(STDIN_FILENO, getpgrp())) {\n\t\tif (errno == ENOTTY) {\n\t\t\tPRINT_DEBUG(\"tcsetpgrp failed: no tty (ok to proceed)\");\n\t\t} else if (errno == ENXIO) {\n\t\t\t// can occur on lx-branded zones\n\t\t\tPRINT_DEBUG(\"tcsetpgrp failed: no such device (ok to proceed)\");\n\t\t} else {\n\t\t\tPRINT_FATAL(\"tcsetpgrp failed: %s\", strerror(errno));\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\n\nint spawn(const signal_configuration_t* const sigconf_ptr, char* const argv[], int* const child_pid_ptr) {\n\tpid_t pid;\n\n\t// TODO: check if tini was a foreground process to begin with (it's not OK to \"steal\" the foreground!\")\n\n\tpid = fork();\n\tif (pid < 0) {\n\t\tPRINT_FATAL(\"fork failed: %s\", strerror(errno));\n\t\treturn 1;\n\t} else if (pid == 0) {\n\n\t\t// Put the child in a process group and make it the foreground process if there is a tty.\n\t\tif (isolate_child()) {\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Restore all signal handlers to the way they were before we touched them.\n\t\tif (restore_signals(sigconf_ptr)) {\n\t\t\treturn 1;\n\t\t}\n\n\t\texecvp(argv[0], argv);\n\n\t\t// execvp will only return on an error so make sure that we check the errno\n\t\t// and exit with the correct return status for the error that we encountered\n\t\t// See: http://www.tldp.org/LDP/abs/html/exitcodes.html#EXITCODESREF\n\t\tint status = 1;\n\t\tswitch (errno) {\n\t\t\tcase ENOENT:\n\t\t\t\tstatus = 127;\n\t\t\t\tbreak;\n\t\t\tcase EACCES:\n\t\t\t\tstatus = 126;\n\t\t\t\tbreak;\n\t\t}\n\t\tPRINT_FATAL(\"exec %s failed: %s\", argv[0], strerror(errno));\n\t\treturn status;\n\t} else {\n\t\t// Parent\n\t\tPRINT_INFO(\"Spawned child process '%s' with pid '%i'\", argv[0], pid);\n\t\t*child_pid_ptr = pid;\n\t\treturn 0;\n\t}\n}\n\nvoid print_usage(char* const name, FILE* const file) {\n\tchar *dirc, *bname;\n\n\tdirc = strdup(name);\n\tbname = basename(dirc);\n\n\tfprintf(file, \"%s (%s)\\n\", bname, TINI_VERSION_STRING);\n\n#if TINI_MINIMAL\n\tfprintf(file, \"Usage: %s PROGRAM [ARGS] | --version\\n\\n\", bname);\n#else\n\tfprintf(file, \"Usage: %s [OPTIONS] PROGRAM -- [ARGS] | --version\\n\\n\", bname);\n#endif\n\tfprintf(file, \"Execute a program under the supervision of a valid init process (%s)\\n\\n\", bname);\n\n\tfprintf(file, \"Command line options:\\n\\n\");\n\n\tfprintf(file, \"  --version: Show version and exit.\\n\");\n\n#if TINI_MINIMAL\n#else\n\tfprintf(file, \"  -h: Show this help message and exit.\\n\");\n#if HAS_SUBREAPER\n\tfprintf(file, \"  -s: Register as a process subreaper (requires Linux >= 3.4).\\n\");\n#endif\n\tfprintf(file, \"  -p SIGNAL: Trigger SIGNAL when parent dies, e.g. \\\"-p SIGKILL\\\".\\n\");\n\tfprintf(file, \"  -v: Generate more verbose output. Repeat up to 3 times.\\n\");\n\tfprintf(file, \"  -w: Print a warning when processes are getting reaped.\\n\");\n\tfprintf(file, \"  -g: Send signals to the child's process group.\\n\");\n\tfprintf(file, \"  -e EXIT_CODE: Remap EXIT_CODE (from 0 to 255) to 0 (can be repeated).\\n\");\n\tfprintf(file, \"  -l: Show license and exit.\\n\");\n#endif\n\n\tfprintf(file, \"\\n\");\n\n\tfprintf(file, \"Environment variables:\\n\\n\");\n#if HAS_SUBREAPER\n\tfprintf(file, \"  %s: Register as a process subreaper (requires Linux >= 3.4).\\n\", SUBREAPER_ENV_VAR);\n#endif\n\tfprintf(file, \"  %s: Set the verbosity level (default: %d).\\n\", VERBOSITY_ENV_VAR, DEFAULT_VERBOSITY);\n\tfprintf(file, \"  %s: Send signals to the child's process group.\\n\", KILL_PROCESS_GROUP_GROUP_ENV_VAR);\n\n\tfprintf(file, \"\\n\");\n\tfree(dirc);\n}\n\nvoid print_license(FILE* const file) {\n    if(LICENSE_len > fwrite(LICENSE, sizeof(char), LICENSE_len, file)) {\n        // Don't handle this error for now, since parse_args won't care\n        // about the return value. We do need to check it to compile with\n        // older glibc, though.\n        // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25509\n        // See: http://sourceware.org/bugzilla/show_bug.cgi?id=11959\n    }\n}\n\nint set_pdeathsig(char* const arg) {\n\tsize_t i;\n\n\tfor (i = 0; i < ARRAY_LEN(signal_names); i++) {\n\t\tif (strcmp(signal_names[i].name, arg) == 0) {\n\t\t\t/* Signals start at value \"1\" */\n\t\t\tparent_death_signal = signal_names[i].number;\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\treturn 1;\n}\n\nint add_expect_status(char* arg) {\n\tlong status = 0;\n\tchar* endptr = NULL;\n\tstatus = strtol(arg, &endptr, 10);\n\n\tif ((endptr == NULL) || (*endptr != 0)) {\n\t\treturn 1;\n\t}\n\n\tif ((status < STATUS_MIN) || (status > STATUS_MAX)) {\n\t\treturn 1;\n\t}\n\n\tINT32_BITFIELD_CHECK_BOUNDS(expect_status, status);\n\tINT32_BITFIELD_SET(expect_status, status);\n\treturn 0;\n}\n\nint parse_args(const int argc, char* const argv[], char* (**child_args_ptr_ptr)[], int* const parse_fail_exitcode_ptr) {\n\tchar* name = argv[0];\n\n\t// We handle --version if it's the *only* argument provided.\n\tif (argc == 2 && strcmp(\"--version\", argv[1]) == 0) {\n\t\t*parse_fail_exitcode_ptr = 0;\n\t\tfprintf(stdout, \"%s\\n\", TINI_VERSION_STRING);\n\t\treturn 1;\n\t}\n\n#ifndef TINI_MINIMAL\n\tint c;\n\twhile ((c = getopt(argc, argv, OPT_STRING)) != -1) {\n\t\tswitch (c) {\n\t\t\tcase 'h':\n\t\t\t\tprint_usage(name, stdout);\n\t\t\t\t*parse_fail_exitcode_ptr = 0;\n\t\t\t\treturn 1;\n#if HAS_SUBREAPER\n\t\t\tcase 's':\n\t\t\t\tsubreaper++;\n\t\t\t\tbreak;\n#endif\n\t\t\tcase 'p':\n\t\t\t\tif (set_pdeathsig(optarg)) {\n\t\t\t\t\tPRINT_FATAL(\"Not a valid option for -p: %s\", optarg);\n\t\t\t\t\t*parse_fail_exitcode_ptr = 1;\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'v':\n\t\t\t\tverbosity++;\n\t\t\t\tbreak;\n\n\t\t\tcase 'w':\n\t\t\t\twarn_on_reap++;\n\t\t\t\tbreak;\n\n\t\t\tcase 'g':\n\t\t\t\tkill_process_group++;\n\t\t\t\tbreak;\n\n\t\t\tcase 'e':\n\t\t\t\tif (add_expect_status(optarg)) {\n\t\t\t\t\tPRINT_FATAL(\"Not a valid option for -e: %s\", optarg);\n\t\t\t\t\t*parse_fail_exitcode_ptr = 1;\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'l':\n\t\t\t\tprint_license(stdout);\n\t\t\t\t*parse_fail_exitcode_ptr = 0;\n\t\t\t\treturn 1;\n\n\t\t\tcase '?':\n\t\t\t\tprint_usage(name, stderr);\n\t\t\t\treturn 1;\n\t\t\tdefault:\n\t\t\t\t/* Should never happen */\n\t\t\t\treturn 1;\n\t\t}\n\t}\n#endif\n\n\t*child_args_ptr_ptr = calloc(argc-optind+1, sizeof(char*));\n\tif (*child_args_ptr_ptr == NULL) {\n\t\tPRINT_FATAL(\"Failed to allocate memory for child args: '%s'\", strerror(errno));\n\t\treturn 1;\n\t}\n\n\tint i;\n\tfor (i = 0; i < argc - optind; i++) {\n\t\t(**child_args_ptr_ptr)[i] = argv[optind+i];\n\t}\n\t(**child_args_ptr_ptr)[i] = NULL;\n\n\tif (i == 0) {\n\t\t/* User forgot to provide args! */\n\t\tprint_usage(name, stderr);\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nint parse_env(void) {\n#if HAS_SUBREAPER\n\tif (getenv(SUBREAPER_ENV_VAR) != NULL) {\n\t\tsubreaper++;\n\t}\n#endif\n\n\tif (getenv(KILL_PROCESS_GROUP_GROUP_ENV_VAR) != NULL) {\n\t\tkill_process_group++;\n\t}\n\n\tchar* env_verbosity = getenv(VERBOSITY_ENV_VAR);\n\tif (env_verbosity != NULL) {\n\t\tverbosity = atoi(env_verbosity);\n\t}\n\n\treturn 0;\n}\n\n\n#if HAS_SUBREAPER\nint register_subreaper (void) {\n\tif (subreaper > 0) {\n\t\tif (prctl(PR_SET_CHILD_SUBREAPER, 1)) {\n\t\t\tif (errno == EINVAL) {\n\t\t\t\tPRINT_FATAL(\"PR_SET_CHILD_SUBREAPER is unavailable on this platform. Are you using Linux >= 3.4?\")\n\t\t\t} else {\n\t\t\t\tPRINT_FATAL(\"Failed to register as child subreaper: %s\", strerror(errno))\n\t\t\t}\n\t\t\treturn 1;\n\t\t} else {\n\t\t\tPRINT_TRACE(\"Registered as child subreaper\");\n\t\t}\n\t}\n\treturn 0;\n}\n#endif\n\n\nvoid reaper_check (void) {\n\t/* Check that we can properly reap zombies */\n#if HAS_SUBREAPER\n\tint bit = 0;\n#endif\n\n\tif (getpid() == 1) {\n\t\treturn;\n\t}\n\n#if HAS_SUBREAPER\n\tif (prctl(PR_GET_CHILD_SUBREAPER, &bit)) {\n\t\tPRINT_DEBUG(\"Failed to read child subreaper attribute: %s\", strerror(errno));\n\t} else if (bit == 1) {\n\t\treturn;\n\t}\n#endif\n\n\tPRINT_WARNING(reaper_warning);\n}\n\n\nint configure_signals(sigset_t* const parent_sigset_ptr, const signal_configuration_t* const sigconf_ptr) {\n\t/* Block all signals that are meant to be collected by the main loop */\n\tif (sigfillset(parent_sigset_ptr)) {\n\t\tPRINT_FATAL(\"sigfillset failed: '%s'\", strerror(errno));\n\t\treturn 1;\n\t}\n\n\t// These ones shouldn't be collected by the main loop\n\tuint i;\n\tint signals_for_tini[] = {SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGABRT, SIGTRAP, SIGSYS, SIGTTIN, SIGTTOU};\n\tfor (i = 0; i < ARRAY_LEN(signals_for_tini); i++) {\n\t\tif (sigdelset(parent_sigset_ptr, signals_for_tini[i])) {\n\t\t\tPRINT_FATAL(\"sigdelset failed: '%i'\", signals_for_tini[i]);\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tif (sigprocmask(SIG_SETMASK, parent_sigset_ptr, sigconf_ptr->sigmask_ptr)) {\n\t\tPRINT_FATAL(\"sigprocmask failed: '%s'\", strerror(errno));\n\t\treturn 1;\n\t}\n\n\t// Handle SIGTTIN and SIGTTOU separately. Since Tini makes the child process group\n\t// the foreground process group, there's a chance Tini can end up not controlling the tty.\n\t// If TOSTOP is set on the tty, this could block Tini on writing debug messages. We don't\n\t// want that. Ignore those signals.\n\tstruct sigaction ign_action;\n\tmemset(&ign_action, 0, sizeof ign_action);\n\n\tign_action.sa_handler = SIG_IGN;\n\tsigemptyset(&ign_action.sa_mask);\n\n\tif (sigaction(SIGTTIN, &ign_action, sigconf_ptr->sigttin_action_ptr)) {\n\t\tPRINT_FATAL(\"Failed to ignore SIGTTIN\");\n\t\treturn 1;\n\t}\n\n\tif (sigaction(SIGTTOU, &ign_action, sigconf_ptr->sigttou_action_ptr)) {\n\t\tPRINT_FATAL(\"Failed to ignore SIGTTOU\");\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nint wait_and_forward_signal(sigset_t const* const parent_sigset_ptr, pid_t const child_pid) {\n\tsiginfo_t sig;\n\n\tif (sigtimedwait(parent_sigset_ptr, &sig, &ts) == -1) {\n\t\tswitch (errno) {\n\t\t\tcase EAGAIN:\n\t\t\t\tbreak;\n\t\t\tcase EINTR:\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tPRINT_FATAL(\"Unexpected error in sigtimedwait: '%s'\", strerror(errno));\n\t\t\t\treturn 1;\n\t\t}\n\t} else {\n\t\t/* There is a signal to handle here */\n\t\tswitch (sig.si_signo) {\n\t\t\tcase SIGCHLD:\n\t\t\t\t/* Special-cased, as we don't forward SIGCHLD. Instead, we'll\n\t\t\t\t * fallthrough to reaping processes.\n\t\t\t\t */\n\t\t\t\tPRINT_DEBUG(\"Received SIGCHLD\");\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tPRINT_DEBUG(\"Passing signal: '%s'\", strsignal(sig.si_signo));\n\t\t\t\t/* Forward anything else */\n\t\t\t\tif (kill(kill_process_group ? -child_pid : child_pid, sig.si_signo)) {\n\t\t\t\t\tif (errno == ESRCH) {\n\t\t\t\t\t\tPRINT_WARNING(\"Child was dead when forwarding signal\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tPRINT_FATAL(\"Unexpected error when forwarding signal: '%s'\", strerror(errno));\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nint reap_zombies(const pid_t child_pid, int* const child_exitcode_ptr) {\n\tpid_t current_pid;\n\tint current_status;\n\n\twhile (1) {\n\t\tcurrent_pid = waitpid(-1, &current_status, WNOHANG);\n\n\t\tswitch (current_pid) {\n\n\t\t\tcase -1:\n\t\t\t\tif (errno == ECHILD) {\n\t\t\t\t\tPRINT_TRACE(\"No child to wait\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tPRINT_FATAL(\"Error while waiting for pids: '%s'\", strerror(errno));\n\t\t\t\treturn 1;\n\n\t\t\tcase 0:\n\t\t\t\tPRINT_TRACE(\"No child to reap\");\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t/* A child was reaped. Check whether it's the main one. If it is, then\n\t\t\t\t * set the exit_code, which will cause us to exit once we've reaped everyone else.\n\t\t\t\t */\n\t\t\t\tPRINT_DEBUG(\"Reaped child with pid: '%i'\", current_pid);\n\t\t\t\tif (current_pid == child_pid) {\n\t\t\t\t\tif (WIFEXITED(current_status)) {\n\t\t\t\t\t\t/* Our process exited normally. */\n\t\t\t\t\t\tPRINT_INFO(\"Main child exited normally (with status '%i')\", WEXITSTATUS(current_status));\n\t\t\t\t\t\t*child_exitcode_ptr = WEXITSTATUS(current_status);\n\t\t\t\t\t} else if (WIFSIGNALED(current_status)) {\n\t\t\t\t\t\t/* Our process was terminated. Emulate what sh / bash\n\t\t\t\t\t\t * would do, which is to return 128 + signal number.\n\t\t\t\t\t\t */\n\t\t\t\t\t\tPRINT_INFO(\"Main child exited with signal (with signal '%s')\", strsignal(WTERMSIG(current_status)));\n\t\t\t\t\t\t*child_exitcode_ptr = 128 + WTERMSIG(current_status);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tPRINT_FATAL(\"Main child exited for unknown reason\");\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Be safe, ensure the status code is indeed between 0 and 255.\n\t\t\t\t\t*child_exitcode_ptr = *child_exitcode_ptr % (STATUS_MAX - STATUS_MIN + 1);\n\n\t\t\t\t\t// If this exitcode was remapped, then set it to 0.\n\t\t\t\t\tINT32_BITFIELD_CHECK_BOUNDS(expect_status, *child_exitcode_ptr);\n\t\t\t\t\tif (INT32_BITFIELD_TEST(expect_status, *child_exitcode_ptr)) {\n\t\t\t\t\t\t*child_exitcode_ptr = 0;\n\t\t\t\t\t}\n\t\t\t\t} else if (warn_on_reap > 0) {\n\t\t\t\t\tPRINT_WARNING(\"Reaped zombie process with pid=%i\", current_pid);\n\t\t\t\t}\n\n\t\t\t\t// Check if other childs have been reaped.\n\t\t\t\tcontinue;\n\t\t}\n\n\t\t/* If we make it here, that's because we did not continue in the switch case. */\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\n\nint main(int argc, char *argv[]) {\n\tpid_t child_pid;\n\n\t// Those are passed to functions to get an exitcode back.\n\tint child_exitcode = -1;  // This isn't a valid exitcode, and lets us tell whether the child has exited.\n\tint parse_exitcode = 1;   // By default, we exit with 1 if parsing fails.\n\n\t/* Parse command line arguments */\n\tchar* (*child_args_ptr)[];\n\tint parse_args_ret = parse_args(argc, argv, &child_args_ptr, &parse_exitcode);\n\tif (parse_args_ret) {\n\t\treturn parse_exitcode;\n\t}\n\n\t/* Parse environment */\n\tif (parse_env()) {\n\t\treturn 1;\n\t}\n\n\t/* Configure signals */\n\tsigset_t parent_sigset, child_sigset;\n\tstruct sigaction sigttin_action, sigttou_action;\n\tmemset(&sigttin_action, 0, sizeof sigttin_action);\n\tmemset(&sigttou_action, 0, sizeof sigttou_action);\n\n\tsignal_configuration_t child_sigconf = {\n\t\t.sigmask_ptr = &child_sigset,\n\t\t.sigttin_action_ptr = &sigttin_action,\n\t\t.sigttou_action_ptr = &sigttou_action,\n\t};\n\n\tif (configure_signals(&parent_sigset, &child_sigconf)) {\n\t\treturn 1;\n\t}\n\n\t/* Trigger signal on this process when the parent process exits. */\n\tif (parent_death_signal && prctl(PR_SET_PDEATHSIG, parent_death_signal)) {\n\t\tPRINT_FATAL(\"Failed to set up parent death signal\");\n\t\treturn 1;\n\t }\n\n#if HAS_SUBREAPER\n\t/* If available and requested, register as a subreaper */\n\tif (register_subreaper()) {\n\t\treturn 1;\n\t};\n#endif\n\n\t/* Are we going to reap zombies properly? If not, warn. */\n\treaper_check();\n\n\t/* Go on */\n\tint spawn_ret = spawn(&child_sigconf, *child_args_ptr, &child_pid);\n\tif (spawn_ret) {\n\t\treturn spawn_ret;\n\t}\n\tfree(child_args_ptr);\n\n\twhile (1) {\n\t\t/* Wait for one signal, and forward it */\n\t\tif (wait_and_forward_signal(&parent_sigset, child_pid)) {\n\t\t\treturn 1;\n\t\t}\n\n\t\t/* Now, reap zombies */\n\t\tif (reap_zombies(child_pid, &child_exitcode)) {\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (child_exitcode != -1) {\n\t\t\tPRINT_TRACE(\"Exiting: child has exited\");\n\t\t\treturn child_exitcode;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/tiniConfig.h.in",
    "content": "#define TINI_VERSION \"@tini_VERSION_MAJOR@.@tini_VERSION_MINOR@.@tini_VERSION_PATCH@\"\n#define TINI_GIT     \"@tini_VERSION_GIT@\"\n"
  },
  {
    "path": "src/tiniLicense.h",
    "content": "unsigned char LICENSE[] = {\n  0x54, 0x68, 0x65, 0x20, 0x4d, 0x49, 0x54, 0x20, 0x4c, 0x69, 0x63, 0x65,\n  0x6e, 0x73, 0x65, 0x20, 0x28, 0x4d, 0x49, 0x54, 0x29, 0x0a, 0x0a, 0x43,\n  0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29,\n  0x20, 0x32, 0x30, 0x31, 0x35, 0x20, 0x54, 0x68, 0x6f, 0x6d, 0x61, 0x73,\n  0x20, 0x4f, 0x72, 0x6f, 0x7a, 0x63, 0x6f, 0x20, 0x3c, 0x74, 0x68, 0x6f,\n  0x6d, 0x61, 0x73, 0x40, 0x6f, 0x72, 0x6f, 0x7a, 0x63, 0x6f, 0x2e, 0x66,\n  0x72, 0x3e, 0x0a, 0x0a, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69,\n  0x6f, 0x6e, 0x20, 0x69, 0x73, 0x20, 0x68, 0x65, 0x72, 0x65, 0x62, 0x79,\n  0x20, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x66, 0x72,\n  0x65, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65,\n  0x2c, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x70, 0x65, 0x72,\n  0x73, 0x6f, 0x6e, 0x20, 0x6f, 0x62, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e,\n  0x67, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x0a, 0x6f, 0x66, 0x20,\n  0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72,\n  0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x73, 0x73, 0x6f, 0x63, 0x69,\n  0x61, 0x74, 0x65, 0x64, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e,\n  0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x73,\n  0x20, 0x28, 0x74, 0x68, 0x65, 0x20, 0x22, 0x53, 0x6f, 0x66, 0x74, 0x77,\n  0x61, 0x72, 0x65, 0x22, 0x29, 0x2c, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x65,\n  0x61, 0x6c, 0x0a, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x6f,\n  0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f,\n  0x75, 0x74, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69,\n  0x6f, 0x6e, 0x2c, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x69, 0x6e,\n  0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x6c, 0x69,\n  0x6d, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65,\n  0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x0a, 0x74, 0x6f, 0x20, 0x75,\n  0x73, 0x65, 0x2c, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x2c, 0x20, 0x6d, 0x6f,\n  0x64, 0x69, 0x66, 0x79, 0x2c, 0x20, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x2c,\n  0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x2c, 0x20, 0x64, 0x69,\n  0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x2c, 0x20, 0x73, 0x75,\n  0x62, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c, 0x20, 0x61, 0x6e,\n  0x64, 0x2f, 0x6f, 0x72, 0x20, 0x73, 0x65, 0x6c, 0x6c, 0x0a, 0x63, 0x6f,\n  0x70, 0x69, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20,\n  0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2c, 0x20, 0x61, 0x6e,\n  0x64, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x20,\n  0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x77,\n  0x68, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74,\n  0x77, 0x61, 0x72, 0x65, 0x20, 0x69, 0x73, 0x0a, 0x66, 0x75, 0x72, 0x6e,\n  0x69, 0x73, 0x68, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x6f, 0x20,\n  0x73, 0x6f, 0x2c, 0x20, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20,\n  0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 0x6f,\n  0x77, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69,\n  0x6f, 0x6e, 0x73, 0x3a, 0x0a, 0x0a, 0x54, 0x68, 0x65, 0x20, 0x61, 0x62,\n  0x6f, 0x76, 0x65, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,\n  0x74, 0x20, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64,\n  0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73,\n  0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x20,\n  0x73, 0x68, 0x61, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, 0x63,\n  0x6c, 0x75, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x0a, 0x61, 0x6c, 0x6c,\n  0x20, 0x63, 0x6f, 0x70, 0x69, 0x65, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x73,\n  0x75, 0x62, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x70,\n  0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x74,\n  0x68, 0x65, 0x20, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x2e,\n  0x0a, 0x0a, 0x54, 0x48, 0x45, 0x20, 0x53, 0x4f, 0x46, 0x54, 0x57, 0x41,\n  0x52, 0x45, 0x20, 0x49, 0x53, 0x20, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44,\n  0x45, 0x44, 0x20, 0x22, 0x41, 0x53, 0x20, 0x49, 0x53, 0x22, 0x2c, 0x20,\n  0x57, 0x49, 0x54, 0x48, 0x4f, 0x55, 0x54, 0x20, 0x57, 0x41, 0x52, 0x52,\n  0x41, 0x4e, 0x54, 0x59, 0x20, 0x4f, 0x46, 0x20, 0x41, 0x4e, 0x59, 0x20,\n  0x4b, 0x49, 0x4e, 0x44, 0x2c, 0x20, 0x45, 0x58, 0x50, 0x52, 0x45, 0x53,\n  0x53, 0x20, 0x4f, 0x52, 0x0a, 0x49, 0x4d, 0x50, 0x4c, 0x49, 0x45, 0x44,\n  0x2c, 0x20, 0x49, 0x4e, 0x43, 0x4c, 0x55, 0x44, 0x49, 0x4e, 0x47, 0x20,\n  0x42, 0x55, 0x54, 0x20, 0x4e, 0x4f, 0x54, 0x20, 0x4c, 0x49, 0x4d, 0x49,\n  0x54, 0x45, 0x44, 0x20, 0x54, 0x4f, 0x20, 0x54, 0x48, 0x45, 0x20, 0x57,\n  0x41, 0x52, 0x52, 0x41, 0x4e, 0x54, 0x49, 0x45, 0x53, 0x20, 0x4f, 0x46,\n  0x20, 0x4d, 0x45, 0x52, 0x43, 0x48, 0x41, 0x4e, 0x54, 0x41, 0x42, 0x49,\n  0x4c, 0x49, 0x54, 0x59, 0x2c, 0x0a, 0x46, 0x49, 0x54, 0x4e, 0x45, 0x53,\n  0x53, 0x20, 0x46, 0x4f, 0x52, 0x20, 0x41, 0x20, 0x50, 0x41, 0x52, 0x54,\n  0x49, 0x43, 0x55, 0x4c, 0x41, 0x52, 0x20, 0x50, 0x55, 0x52, 0x50, 0x4f,\n  0x53, 0x45, 0x20, 0x41, 0x4e, 0x44, 0x20, 0x4e, 0x4f, 0x4e, 0x49, 0x4e,\n  0x46, 0x52, 0x49, 0x4e, 0x47, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x2e, 0x20,\n  0x49, 0x4e, 0x20, 0x4e, 0x4f, 0x20, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x20,\n  0x53, 0x48, 0x41, 0x4c, 0x4c, 0x20, 0x54, 0x48, 0x45, 0x0a, 0x41, 0x55,\n  0x54, 0x48, 0x4f, 0x52, 0x53, 0x20, 0x4f, 0x52, 0x20, 0x43, 0x4f, 0x50,\n  0x59, 0x52, 0x49, 0x47, 0x48, 0x54, 0x20, 0x48, 0x4f, 0x4c, 0x44, 0x45,\n  0x52, 0x53, 0x20, 0x42, 0x45, 0x20, 0x4c, 0x49, 0x41, 0x42, 0x4c, 0x45,\n  0x20, 0x46, 0x4f, 0x52, 0x20, 0x41, 0x4e, 0x59, 0x20, 0x43, 0x4c, 0x41,\n  0x49, 0x4d, 0x2c, 0x20, 0x44, 0x41, 0x4d, 0x41, 0x47, 0x45, 0x53, 0x20,\n  0x4f, 0x52, 0x20, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x0a, 0x4c, 0x49, 0x41,\n  0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x2c, 0x20, 0x57, 0x48, 0x45, 0x54,\n  0x48, 0x45, 0x52, 0x20, 0x49, 0x4e, 0x20, 0x41, 0x4e, 0x20, 0x41, 0x43,\n  0x54, 0x49, 0x4f, 0x4e, 0x20, 0x4f, 0x46, 0x20, 0x43, 0x4f, 0x4e, 0x54,\n  0x52, 0x41, 0x43, 0x54, 0x2c, 0x20, 0x54, 0x4f, 0x52, 0x54, 0x20, 0x4f,\n  0x52, 0x20, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x57, 0x49, 0x53, 0x45, 0x2c,\n  0x20, 0x41, 0x52, 0x49, 0x53, 0x49, 0x4e, 0x47, 0x20, 0x46, 0x52, 0x4f,\n  0x4d, 0x2c, 0x0a, 0x4f, 0x55, 0x54, 0x20, 0x4f, 0x46, 0x20, 0x4f, 0x52,\n  0x20, 0x49, 0x4e, 0x20, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49,\n  0x4f, 0x4e, 0x20, 0x57, 0x49, 0x54, 0x48, 0x20, 0x54, 0x48, 0x45, 0x20,\n  0x53, 0x4f, 0x46, 0x54, 0x57, 0x41, 0x52, 0x45, 0x20, 0x4f, 0x52, 0x20,\n  0x54, 0x48, 0x45, 0x20, 0x55, 0x53, 0x45, 0x20, 0x4f, 0x52, 0x20, 0x4f,\n  0x54, 0x48, 0x45, 0x52, 0x20, 0x44, 0x45, 0x41, 0x4c, 0x49, 0x4e, 0x47,\n  0x53, 0x20, 0x49, 0x4e, 0x0a, 0x54, 0x48, 0x45, 0x20, 0x53, 0x4f, 0x46,\n  0x54, 0x57, 0x41, 0x52, 0x45, 0x2e, 0x0a\n};\nunsigned int LICENSE_len = 1099;\n"
  },
  {
    "path": "test/pdeathsignal/stage_1.py",
    "content": "#!/usr/bin/env python\nfrom __future__ import print_function\n\nimport os\nimport sys\nimport subprocess\n\n\ndef main():\n    pid = os.getpid()\n\n    tini = sys.argv[1]\n    ret = sys.argv[2]\n    stage_2 = os.path.join(os.path.dirname(__file__), \"stage_2.py\")\n\n    cmd = [\n        tini,\n        \"-vvv\",\n        \"-p\",\n        \"SIGUSR1\",\n        \"--\",\n        stage_2,\n        str(pid),\n        ret\n    ]\n\n    subprocess.Popen(cmd).wait()\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "test/pdeathsignal/stage_2.py",
    "content": "#!/usr/bin/env python\nfrom __future__ import print_function\n\nimport os\nimport sys\nimport signal\nimport time\n\n\ndef main():\n    ret = sys.argv[2]\n\n    def handler(*args):\n        with open(ret, \"w\") as f:\n            f.write(\"ok\")\n        sys.exit(0)\n\n    signal.signal(signal.SIGUSR1, handler)\n    pid = int(sys.argv[1])\n\n    os.kill(pid, signal.SIGKILL)\n    time.sleep(5)\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "test/pgroup/stage_1.py",
    "content": "#!/usr/bin/env python\nimport os\nimport subprocess\nimport signal\n\n\ndef reset_sig_handler():\n    signal.signal(signal.SIGUSR1, signal.SIG_DFL)\n\n\nif __name__ == \"__main__\":\n    signal.signal(signal.SIGUSR1, signal.SIG_IGN)\n    p = subprocess.Popen(\n            [\"sleep\", \"1000\"],\n            preexec_fn=reset_sig_handler\n        )\n    p.wait()\n\n"
  },
  {
    "path": "test/reaping/stage_1.py",
    "content": "#!/usr/bin/env python3\nimport os\nimport sys\nimport subprocess\nimport time\n\nimport psutil\n\n\ndef in_group_or_reaped(pid):\n    try:\n        return os.getpgid(pid) == os.getpgid(0)\n    except OSError:\n        return True\n\n\ndef main():\n    stage_2 = os.path.join(os.path.dirname(__file__), \"stage_2.py\")\n    subprocess.Popen([stage_2]).wait()\n\n    # In tests, we assume this process is the direct child of init\n    this_process = psutil.Process(os.getpid())\n    init_process = this_process.parent()\n\n    print(\"Reaping test: stage_1 is pid{0}, init is pid{1}\".format(\n        this_process.pid, init_process.pid))\n\n    # The only child PID that should persist is this one.\n    expected_pids = [this_process.pid]\n\n    print(\"Expecting pids to remain: {0}\".format(\n        \", \".join(str(pid) for pid in expected_pids)))\n\n    while 1:\n        pids = [p.pid for p in init_process.children(recursive=True)]\n        print(\"Has pids: {0}\".format(\", \".join(str(pid) for pid in pids)))\n        for pid in pids:\n            assert in_group_or_reaped(pid), \"Child had unexpected pgid\"\n        if set(pids) == set(expected_pids):\n            break\n        time.sleep(1)\n\n    # Now, check if there are any zombies. For each of the potential zombies,\n    # we check that the pgid is ours.  NOTE: We explicitly test that this test\n    # fails if subreaping is disabled, so we can be confident this doesn't turn\n    # a failure into a success.\n    for process in psutil.process_iter():\n        if process.pid == this_process.pid:\n            continue\n        if not in_group_or_reaped(process.pid):\n            continue\n        print(\"Not reaped: pid {0}: {1}\".format(process.pid, process.name()))\n        sys.exit(1)\n\n    sys.exit(0)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "test/reaping/stage_2.py",
    "content": "#!/usr/bin/env python\nfrom __future__ import print_function\nimport subprocess\nimport os\nimport random\n\n\nif __name__ == \"__main__\":\n    # Spawn lots of process\n    for i in range(0, 100):\n        cmd = [\"sleep\", str(1 + i % 2 + random.random())]\n        proc = subprocess.Popen(cmd)\n"
  },
  {
    "path": "test/run_inner_tests.py",
    "content": "#!/usr/bin/env python3\n# coding:utf-8\nimport os\nimport sys\nimport signal\nimport subprocess\nimport time\nimport psutil\nimport bitmap\nimport re\nimport itertools\nimport tempfile\n\nDEVNULL = open(os.devnull, \"wb\")\n\nSIGNUM_TO_SIGNAME = dict(\n    (v, k) for k, v in signal.__dict__.items() if re.match(\"^SIG[A-Z]+$\", k)\n)\n\n\ndef busy_wait(condition_callable, timeout):\n    checks = 100\n    increment = float(timeout) / checks\n\n    for _ in range(checks):\n        if condition_callable():\n            return\n        time.sleep(increment)\n\n    assert False, \"Condition was never met\"\n\n\ndef main():\n    src = os.environ[\"SOURCE_DIR\"]\n    build = os.environ[\"BUILD_DIR\"]\n\n    args_disabled = os.environ.get(\"MINIMAL\")\n\n    proxy = os.path.join(src, \"test\", \"subreaper-proxy.py\")\n    tini = os.path.join(build, \"tini\")\n\n    subreaper_support = bool(int(os.environ[\"FORCE_SUBREAPER\"]))\n\n    # Run the exit code test. We use POSIXLY_CORRECT here to not need --\n    # until that's the default in Tini anyways.\n    if not args_disabled:\n        print(\"Running exit code test for {0}\".format(tini))\n        for code in range(0, 256):\n            p = subprocess.Popen(\n                [tini, \"-e\", str(code), \"--\", \"sh\", \"-c\", \"exit {0}\".format(code)],\n                stdout=DEVNULL,\n                stderr=DEVNULL,\n                universal_newlines=True,\n            )\n            ret = p.wait()\n            assert ret == 0, \"Inclusive exit code test failed for %s, exit: %s\" % (\n                code,\n                ret,\n            )\n\n            other_codes = [x for x in range(0, 256) if x != code]\n            args = list(itertools.chain(*[[\"-e\", str(x)] for x in other_codes]))\n\n            p = subprocess.Popen(\n                [tini] + args + [\"sh\", \"-c\", \"exit {0}\".format(code)],\n                env=dict(os.environ, POSIXLY_CORRECT=\"1\"),\n                stdout=DEVNULL,\n                stderr=DEVNULL,\n                universal_newlines=True,\n            )\n            ret = p.wait()\n            assert ret == code, \"Exclusive exit code test failed for %s, exit: %s\" % (\n                code,\n                ret,\n            )\n\n    tests = [([proxy, tini], {})]\n\n    if subreaper_support:\n        if not args_disabled:\n            tests.append(([tini, \"-s\"], {}))\n        tests.append(([tini], {\"TINI_SUBREAPER\": \"\"}))\n\n    for target, env in tests:\n        # Run the reaping test\n        print(\"Running reaping test ({0} with env {1})\".format(\" \".join(target), env))\n        p = subprocess.Popen(\n            target + [os.path.join(src, \"test\", \"reaping\", \"stage_1.py\")],\n            env=dict(os.environ, **env),\n            stdout=subprocess.PIPE,\n            stderr=subprocess.PIPE,\n            universal_newlines=True,\n        )\n\n        out, err = p.communicate()\n\n        if subreaper_support:\n            # If subreaper support sin't available, Tini won't looku p its subreaper bit\n            # and will output the error message here.\n            assert \"zombie reaping won't work\" not in err, \"Warning message was output!\"\n        ret = p.wait()\n        assert (\n            \"Reaped zombie process with pid=\" not in err\n        ), \"Warning message was output!\"\n        assert ret == 0, \"Reaping test failed!\\nOUT: %s\\nERR: %s\" % (out, err)\n\n        if not args_disabled:\n            print(\n                \"Running reaping display test ({0} with env {1})\".format(\n                    \" \".join(target), env\n                )\n            )\n            p = subprocess.Popen(\n                target + [\"-w\", os.path.join(src, \"test\", \"reaping\", \"stage_1.py\")],\n                env=dict(os.environ, **env),\n                stdout=subprocess.PIPE,\n                stderr=subprocess.PIPE,\n                universal_newlines=True,\n            )\n\n            out, err = p.communicate()\n            ret = p.wait()\n            assert (\n                \"Reaped zombie process with pid=\" in err\n            ), \"Warning message was output!\"\n            assert ret == 0, \"Reaping display test failed!\\nOUT: %s\\nERR: %s\" % (\n                out,\n                err,\n            )\n\n        # Run the signals test\n        for signum in [signal.SIGTERM, signal.SIGUSR1, signal.SIGUSR2]:\n            print(\n                \"running signal test for: {0} ({1} with env {2})\".format(\n                    signum, \" \".join(target), env\n                )\n            )\n            p = subprocess.Popen(\n                target + [os.path.join(src, \"test\", \"signals\", \"test.py\")],\n                env=dict(os.environ, **env),\n                universal_newlines=True,\n            )\n            busy_wait(\n                lambda: len(psutil.Process(p.pid).children(recursive=True)) > 1, 10\n            )\n            p.send_signal(signum)\n            ret = p.wait()\n            assert (\n                ret == 128 + signum\n            ), \"Signals test failed (ret was {0}, expected {1})\".format(\n                ret, 128 + signum\n            )\n\n    # Run the process group test\n    # This test has Tini spawn a process that ignores SIGUSR1 and spawns a child that doesn't (and waits on the child)\n    # We send SIGUSR1 to Tini, and expect the grand-child to terminate, then the child, and then Tini.\n    if not args_disabled:\n        print(\"Running process group test (arguments)\")\n        p = subprocess.Popen(\n            [tini, \"-g\", os.path.join(src, \"test\", \"pgroup\", \"stage_1.py\")],\n            stdout=subprocess.PIPE,\n            stderr=subprocess.PIPE,\n            universal_newlines=True,\n        )\n\n        busy_wait(lambda: len(psutil.Process(p.pid).children(recursive=True)) == 2, 10)\n        p.send_signal(signal.SIGUSR1)\n        busy_wait(lambda: p.poll() is not None, 10)\n\n    print(\"Running process group test (environment variable)\")\n    p = subprocess.Popen(\n        [tini, os.path.join(src, \"test\", \"pgroup\", \"stage_1.py\")],\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        env=dict(os.environ, TINI_KILL_PROCESS_GROUP=\"1\"),\n        universal_newlines=True,\n    )\n\n    busy_wait(lambda: len(psutil.Process(p.pid).children(recursive=True)) == 2, 10)\n    p.send_signal(signal.SIGUSR1)\n    busy_wait(lambda: p.poll() is not None, 10)\n\n    # Run failing test. Force verbosity to 1 so we see the subreaper warning\n    # regardless of whether MINIMAL is set.\n    print(\"Running zombie reaping failure test (Tini should warn)\")\n    p = subprocess.Popen(\n        [tini, os.path.join(src, \"test\", \"reaping\", \"stage_1.py\")],\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        env=dict(os.environ, TINI_VERBOSITY=\"1\"),\n        universal_newlines=True,\n    )\n    out, err = p.communicate()\n    assert \"zombie reaping won't work\" in err, \"No warning message was output!\"\n    ret = p.wait()\n    assert ret == 1, \"Reaping test succeeded (it should have failed)!\"\n\n    # Test that the signals are properly in place here.\n    print(\"Running signal configuration test\")\n\n    p = subprocess.Popen(\n        [os.path.join(build, \"sigconf-test\"), tini, \"cat\", \"/proc/self/status\"],\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        universal_newlines=True,\n    )\n    out, err = p.communicate()\n\n    # Extract the signal properties, and add a zero at the end.\n    props = [line.split(\":\") for line in out.splitlines()]\n    props = [(k.strip(), v.strip()) for (k, v) in props]\n    props = [\n        (k, bitmap.BitMap.fromstring(bin(int(v, 16))[2:].zfill(32)))\n        for (k, v) in props\n        if k in [\"SigBlk\", \"SigIgn\", \"SigCgt\"]\n    ]\n    props = dict(props)\n\n    # Print actual handling configuration\n    for k, bmp in props.items():\n        print(\n            \"{0}: {1}\".format(\n                k,\n                \", \".join(\n                    [\n                        \"{0} ({1})\".format(SIGNUM_TO_SIGNAME[n + 1], n + 1)\n                        for n in bmp.nonzero()\n                    ]\n                ),\n            )\n        )\n\n    for signal_set_name, signals_to_test_for in [\n        (\"SigIgn\", [signal.SIGTTOU, signal.SIGSEGV, signal.SIGINT]),\n        (\"SigBlk\", [signal.SIGTTIN, signal.SIGILL, signal.SIGTERM]),\n    ]:\n        for signum in signals_to_test_for:\n            # Use signum - 1 because the bitmap is 0-indexed but represents signals strting at 1\n            assert (signum - 1) in props[\n                signal_set_name\n            ].nonzero(), \"{0} ({1}) is missing in {2}!\".format(\n                SIGNUM_TO_SIGNAME[signum], signum, signal_set_name\n            )\n\n    # Test parent death signal handling.\n    if not args_disabled:\n        print(\"Running parent death signal test\")\n        f = tempfile.NamedTemporaryFile()\n        try:\n            p = subprocess.Popen(\n                [os.path.join(src, \"test\", \"pdeathsignal\", \"stage_1.py\"), tini, f.name],\n                stdout=DEVNULL,\n                stderr=DEVNULL,\n                universal_newlines=True,\n            )\n            p.wait()\n\n            busy_wait(lambda: open(f.name).read() == \"ok\", 10)\n        finally:\n            f.close()\n\n    print(\"---------------------------\")\n    print(\"All done, tests as expected\")\n    print(\"---------------------------\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "test/run_outer_tests.py",
    "content": "#coding:utf-8\nimport os\nimport sys\nimport time\nimport pipes\nimport subprocess\nimport threading\nimport pexpect\nimport signal\n\n\nclass ReturnContainer():\n    def __init__(self):\n        self.value = None\n\n\nclass Command(object):\n    def __init__(self, cmd, fail_cmd, post_cmd=None, post_delay=0):\n        self.cmd = cmd\n        self.fail_cmd = fail_cmd\n        self.post_cmd = post_cmd\n        self.post_delay = post_delay\n        self.proc = None\n\n    def run(self, timeout=None, retcode=0):\n        print \"Testing '{0}'...\".format(\" \".join(pipes.quote(s) for s in self.cmd)),\n        sys.stdout.flush()\n\n        err = None\n        pipe_kwargs = {\"stdout\": subprocess.PIPE, \"stderr\": subprocess.PIPE, \"stdin\": subprocess.PIPE}\n\n        def target():\n            self.proc = subprocess.Popen(self.cmd, **pipe_kwargs)\n            self.stdout, self.stderr = self.proc.communicate()\n\n        thread = threading.Thread(target=target)\n        thread.daemon = True\n\n        thread.start()\n\n        if self.post_cmd is not None:\n            time.sleep(self.post_delay)\n            subprocess.check_call(self.post_cmd, **pipe_kwargs)\n\n        thread.join(timeout - self.post_delay if timeout is not None else timeout)\n\n        # Checks\n        if thread.is_alive():\n            subprocess.check_call(self.fail_cmd, **pipe_kwargs)\n            err = Exception(\"Test failed with timeout!\")\n\n        elif self.proc.returncode != retcode:\n            err = Exception(\"Test failed with unexpected returncode (expected {0}, got {1})\".format(retcode, self.proc.returncode))\n\n        if err is not None:\n            print \"FAIL\"\n            print \"--- STDOUT ---\"\n            print getattr(self, \"stdout\", \"no stdout\")\n            print \"--- STDERR ---\"\n            print getattr(self, \"stderr\", \"no stderr\")\n            print \"--- ... ---\"\n            raise err\n        else:\n            print \"OK\"\n\n\ndef attach_and_type_exit_0(name):\n    print \"Attaching to {0} to exit 0\".format(name)\n    p = pexpect.spawn(\"docker attach {0}\".format(name))\n    p.sendline('')\n    p.sendline('exit 0')\n    p.close()\n\n\ndef attach_and_issue_ctrl_c(name):\n    print \"Attaching to {0} to CTRL+C\".format(name)\n    p = pexpect.spawn(\"docker attach {0}\".format(name))\n    p.expect_exact('#')\n    p.sendintr()\n    p.close()\n\n\ndef test_tty_handling(img, name, base_cmd, fail_cmd, container_command, exit_function, expect_exit_code):\n    print \"Testing TTY handling (using container command '{0}' and exit function '{1}')\".format(container_command, exit_function.__name__)\n    rc = ReturnContainer()\n\n    shell_ready_event = threading.Event()\n\n    def spawn():\n        cmd = base_cmd + [\"--tty\", \"--interactive\", img, \"/tini/dist/tini\"]\n        if os.environ.get(\"MINIMAL\") is None:\n            cmd.append(\"--\")\n        cmd.append(container_command)\n        p = pexpect.spawn(\" \".join(cmd))\n        p.expect_exact(\"#\")\n        shell_ready_event.set()\n        rc.value = p.wait()\n\n    thread = threading.Thread(target=spawn)\n    thread.daemon = True\n\n    thread.start()\n\n    if not shell_ready_event.wait(2):\n        raise Exception(\"Timeout waiting for shell to spawn\")\n\n    exit_function(name)\n\n    thread.join(timeout=2)\n\n    if thread.is_alive():\n        subprocess.check_call(fail_cmd)\n        raise Exception(\"Timeout waiting for container to exit!\")\n\n    if rc.value != expect_exit_code:\n        raise Exception(\"Return code is: {0} (expected {1})\".format(rc.value, expect_exit_code))\n\n\n\ndef main():\n    img = sys.argv[1]\n    name = \"{0}-test\".format(img)\n    args_disabled = os.environ.get(\"MINIMAL\")\n\n    root = os.path.abspath(os.path.join(os.path.dirname(__file__), \"..\"))\n\n    base_cmd = [\n        \"docker\",\n        \"run\",\n        \"--rm\",\n        \"--volume={0}:/tini\".format(root),\n        \"--name={0}\".format(name),\n    ]\n\n    fail_cmd = [\"docker\", \"kill\", \"-s\", \"KILL\", name]\n\n    # Funtional tests\n    for entrypoint in [\"/tini/dist/tini\", \"/tini/dist/tini-static\"]:\n        functional_base_cmd = base_cmd + [\n            \"--entrypoint={0}\".format(entrypoint),\n            \"-e\", \"TINI_VERBOSITY=3\",\n            img,\n        ]\n\n        # Reaping test\n        Command(functional_base_cmd + [\"/tini/test/reaping/stage_1.py\"], fail_cmd).run(timeout=10)\n\n        # Signals test\n        for sig, retcode in [(\"TERM\", 143), (\"USR1\", 138), (\"USR2\", 140)]:\n            Command(\n                functional_base_cmd + [\"/tini/test/signals/test.py\"],\n                fail_cmd,\n                [\"docker\", \"kill\", \"-s\", sig, name],\n                2\n            ).run(timeout=10, retcode=retcode)\n\n        # Exit code test\n        Command(functional_base_cmd + [\"-z\"], fail_cmd).run(retcode=127 if args_disabled else 1)\n        Command(functional_base_cmd + [\"-h\"], fail_cmd).run(retcode=127 if args_disabled else 0)\n        Command(functional_base_cmd + [\"zzzz\"], fail_cmd).run(retcode=127)\n        Command(functional_base_cmd + [\"-w\"], fail_cmd).run(retcode=127 if args_disabled else 0)\n\n    # Valgrind test (we only run this on the dynamic version, because otherwise Valgrind may bring up plenty of errors that are\n    # actually from libc)\n    Command(base_cmd + [img, \"valgrind\", \"--leak-check=full\", \"--error-exitcode=1\", \"/tini/dist/tini\", \"ls\"], fail_cmd).run()\n\n    # Test tty handling\n    test_tty_handling(img, name, base_cmd, fail_cmd, \"dash\", attach_and_type_exit_0, 0)\n    test_tty_handling(img, name, base_cmd, fail_cmd, \"dash -c 'while true; do echo \\#; sleep 0.1; done'\", attach_and_issue_ctrl_c, 128 + signal.SIGINT)\n\n    # Installation tests (sh -c is used for globbing and &&)\n    for image, pkg_manager, extension in [\n            [\"ubuntu:precise\", \"dpkg\", \"deb\"],\n            [\"ubuntu:trusty\", \"dpkg\", \"deb\"],\n            [\"centos:6\", \"rpm\", \"rpm\"],\n            [\"centos:7\", \"rpm\", \"rpm\"],\n    ]:\n        Command(base_cmd + [image, \"sh\", \"-c\", \"{0} -i /tini/dist/*.{1} && /usr/bin/tini true\".format(pkg_manager, extension)], fail_cmd).run()\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "test/sigconf/sigconf-test.c",
    "content": "/*\nTest program to:\n+ Ignore a few signals\n+ Block a few signals\n+ Exec whatever the test runner asked for\n*/\n\n#include <stdlib.h>\n#include <signal.h>\n#include <unistd.h>\n\n\nint main(int argc, char *argv[]) {\n\t// Signals to ignore\n\tsignal(SIGTTOU, SIG_IGN);  // This one should still be in SigIgn (Tini touches it to ignore it, and should restore it)\n\tsignal(SIGSEGV, SIG_IGN);  // This one should still be in SigIgn (Tini shouldn't touch it)\n\tsignal(SIGINT,  SIG_IGN);  // This one should still be in SigIgn (Tini should block it to forward it, and restore it)\n\n\t// Signals to block\n\tsigset_t set;\n\tsigemptyset(&set);\n\tsigaddset(&set, SIGTTIN);  // This one should still be in SigIgn (Tini touches it to ignore it, and should restore it)\n\tsigaddset(&set, SIGILL);   // This one should still be in SigIgn (Tini shouldn't touch it)\n\tsigaddset(&set, SIGTERM);  // This one should still be in SigIgn (Tini should block it to forward it, and restore it)\n\tsigprocmask(SIG_BLOCK, &set, NULL);\n\n\t// Run whatever we were asked to run\n\texecvp(argv[1], argv+1);\n}\n"
  },
  {
    "path": "test/signals/test.py",
    "content": "#!/usr/bin/env python\nimport signal\nimport os\n\n\ndef main():\n    signal.signal(signal.SIGTERM, signal.SIG_DFL)\n    signal.signal(signal.SIGUSR1, signal.SIG_DFL)\n    signal.signal(signal.SIGUSR2, signal.SIG_DFL)\n    os.system(\"sleep 100\")\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "test/subreaper-proxy.py",
    "content": "#!/usr/bin/env python3\n#coding:utf-8\nimport os\nimport sys\n\nimport prctl\n\n\ndef main():\n    args = sys.argv[1:]\n\n    print(\"subreaper-proxy: running '%s'\" % (\" \".join(args)))\n\n    prctl.set_child_subreaper(1)\n    os.execv(args[0], args)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "tpl/README.md.in",
    "content": "<!--\n\n#####################################\n# THIS FILE IS AUTOGENERATED!       #\n# Edit ./tpl/README.md.in instead   #\n#####################################\n\n-->\n\n\nTini - A tiny but valid `init` for containers\n=============================================\n\n[![Build Status](https://travis-ci.org/krallin/tini.svg?branch=master)](https://travis-ci.org/krallin/tini)\n\nTini is the simplest `init` you could think of.\n\nAll Tini does is spawn a single child (Tini is meant to be run in a container),\nand wait for it to exit all the while reaping zombies and performing\nsignal forwarding.\n\n\nWhy Tini?\n---------\n\nUsing Tini has several benefits:\n\n- It protects you from software that accidentally creates zombie processes,\n  which can (over time!) starve your entire system for PIDs (and make it\n  unusable).\n- It ensures that the *default signal handlers* work for the software you run\n  in your Docker image. For example, with Tini, `SIGTERM` properly terminates\n  your process even if you didn't explicitly install a signal handler for it.\n- It does so completely transparently! Docker images that work without Tini\n  will work with Tini without any changes.\n\nIf you'd like more detail on why this is useful, review this issue discussion:\n[What is advantage of Tini?][0].\n\n\nUsing Tini\n----------\n\n*NOTE: If you are using Docker 1.13 or greater, Tini is included in Docker\nitself. This includes all versions of Docker CE. To enable Tini, just [pass the\n`--init` flag to `docker run`][5].*\n\n*NOTE: There are [pre-built Docker images available for Tini][10]. If\nyou're currently using an Ubuntu or CentOS image as your base, you can use\none of those as a drop-in replacement.*\n\n*NOTE: There are Tini packages for Alpine Linux and NixOS. See below for\ninstallation instructions.*\n\nAdd Tini to your container, and make it executable. Then, just invoke Tini\nand pass your program and its arguments as arguments to Tini.\n\nIn Docker, you will want to use an entrypoint so you don't have to remember\nto manually invoke Tini:\n\n    # Add Tini\n    ENV TINI_VERSION=v@tini_VERSION_MAJOR@.@tini_VERSION_MINOR@.@tini_VERSION_PATCH@\n    ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\n    RUN chmod +x /tini\n    ENTRYPOINT [\"/tini\", \"--\"]\n\n    # Run your program under Tini\n    CMD [\"/your/program\", \"-and\", \"-its\", \"arguments\"]\n    # or docker run your-image /your/program ...\n\nNote that you *can* skip the `--` under certain conditions, but you might\nas well always include it to be safe. If you see an error message that\nlooks like `tini: invalid option -- 'c'`, then you *need* to add the `--`.\n\nArguments for Tini itself should be passed like `-v` in the following example:\n`/tini -v -- /your/program`.\n\n*NOTE: The binary linked above is a 64-bit dynamically-linked binary.*\n\n\n### Signed binaries ###\n\nThe `tini` and `tini-static` binaries are signed using the key `595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7`.\n\nYou can verify their signatures using `gpg` (which you may install using\nyour package manager):\n\n    ENV TINI_VERSION v@tini_VERSION_MAJOR@.@tini_VERSION_MINOR@.@tini_VERSION_PATCH@\n    ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini\n    ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini.asc /tini.asc\n    RUN gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7 \\\n     && gpg --batch --verify /tini.asc /tini\n    RUN chmod +x /tini\n\n\n### Verifying binaries via checksum ###\n\nThe `tini` and `tini-static` binaries have generated checksums (`SHA1` and `SHA256`).\n\nYou can verify their checksums using `sha1sum` and `sha256sum` (which you may install using\nyour package manager):\n\n    ENV TINI_VERSION v@tini_VERSION_MAJOR@.@tini_VERSION_MINOR@.@tini_VERSION_PATCH@\n    RUN wget --no-check-certificate --no-cookies --quiet https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-amd64 \\\n        && wget --no-check-certificate --no-cookies --quiet https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-amd64.sha256sum \\\n        && echo \"$(cat tini-amd64.sha256sum)\" | sha256sum -c\n\n\n### Alpine Linux Package ###\n\nOn Alpine Linux, you can use the following command to install Tini:\n\n    RUN apk add --no-cache tini\n    # Tini is now available at /sbin/tini\n    ENTRYPOINT [\"/sbin/tini\", \"--\"]\n\n\n### NixOS ###\n\nUsing Nix, you can use the following command to install Tini:\n\n    nix-env --install tini\n\n\n### Debian ###\n\nOn Debian (Buster or newer), you can use the following command to install Tini:\n\n    apt-get install tini\n\nNote that this installs `/usr/bin/tini` (and `/usr/bin/tini-static`), not `/tini`.\n\n\n### Arch Linux ###\n\nOn Arch Linux, there is a package available on the [AUR](https://wiki.archlinux.org/index.php/Arch_User_Repository).\nInstall using the [official instructions](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages)\nor use an [AUR helper](https://wiki.archlinux.org/index.php/AUR_helpers):\n\n    pacaur -S tini\n\n\n### Other Platforms ###\n\nARM and 32-bit binaries are available! You can find the complete list of\navailable binaries under [the releases tab][11].\n\n\nOptions\n-------\n\n### Verbosity ###\n\nThe `-v` argument can be used for extra verbose output (you can pass it up to\n3 times, e.g. `-vvv`).\n\n\n### Subreaping ###\n\nBy default, Tini needs to run as PID 1 so that it can reap zombies (by\nrunning as PID 1, zombies get re-parented to Tini).\n\nIf for some reason, you cannot run Tini as PID 1, you should register Tini as\na process subreaper instead (only in Linux >= 3.4), by either:\n\n  + Passing the `-s` argument to Tini (`tini -s -- ...`)\n  + Setting the environment variable `TINI_SUBREAPER`\n    (e.g. `export TINI_SUBREAPER=`).\n\nThis will ensure that zombies get re-parented to Tini despite Tini not running\nas PID 1.\n\n*NOTE: Tini will issue a warning if it detects that it isn't running as PID 1\nand isn't registered as a subreaper. If you don't see a warning, you're fine.*\n\n\n### Remapping exit codes ###\n\nTini will reuse the child's exit code when exiting, but occasionally, this may\nnot be exactly what you want (e.g. if your child exits with 143 after receiving\nSIGTERM). Notably, this can be an issue with Java apps.\n\nIn this case, you can use the `-e` flag to remap an arbitrary exit code to 0.\nYou can pass the flag multiple times if needed.\n\nFor example:\n\n```\ntini -e 143 -- ...\n```\n\n\n### Process group killing ###\n\nBy default, Tini only kills its immediate child process.  This can be\ninconvenient if sending a signal to that process does not have the desired\neffect.  For example, if you do\n\n    docker run --rm krallin/ubuntu-tini sh -c 'sleep 10'\n\nand ctrl-C it, nothing happens: SIGINT is sent to the 'sh' process,\nbut that shell won't react to it while it is waiting for the 'sleep'\nto finish.\n\nYou can configure Tini to kill the child process group, so that every process\nin the group gets the signal, by either:\n\n  + Passing the `-g` argument to Tini (`tini -g -- ...`)\n  + Setting the environment variable `TINI_KILL_PROCESS_GROUP`\n    (e.g. `export TINI_KILL_PROCESS_GROUP=`).\n\nThis corresponds more closely to what happens when you do ctrl-C etc. in a\nterminal: The signal is sent to the foreground process group.\n\n    docker run --rm --entrypoint tini krallin/ubuntu-tini -g -- sh -c 'sleep 10'\n\n### Parent Death Signal ###\n\nTini can set its parent death signal, which is the signal Tini should receive\nwhen *its* parent exits. To set the parent death signal, use the `-p` flag with\nthe name of the signal Tini should receive when its parent exits:\n\n```\ntini -p SIGTERM -- ...\n```\n\n*NOTE: See [this PR discussion][12] to learn more about the parent death signal\nand use cases.*\n\n\nMore\n----\n\n### Existing Entrypoint ###\n\nTini can also be used with an existing entrypoint in your container!\n\nAssuming your entrypoint was `/docker-entrypoint.sh`, then you would use:\n\n    ENTRYPOINT [\"/tini\", \"--\", \"/docker-entrypoint.sh\"]\n\n\n### Statically-Linked Version ###\n\nTini has very few dependencies (it only depends on libc), but if your\ncontainer fails to start, you might want to consider using the statically-built\nversion instead:\n\n    ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static /tini\n\n\n### Size Considerations ###\n\nTini is a very small file (in the 10KB range), so it doesn't add much weight\nto your container.\n\nThe statically-linked version is bigger, but still < 1M.\n\n\nBuilding Tini\n-------------\n\nIf you'd rather not download the binary, you can build Tini by running\n`cmake . && make`.\n\nBefore building, you probably also want to run:\n\n    export CFLAGS=\"-DPR_SET_CHILD_SUBREAPER=36 -DPR_GET_CHILD_SUBREAPER=37\"\n\nThis ensure that even if you're building on a system that has old Linux Kernel\nheaders (< 3.4), Tini will be built with child subreaper support. This is\nusually what you want if you're going to use Tini with Docker (if your host\nKernel supports Docker, it should also support child subreapers).\n\n\nUnderstanding Tini\n------------------\n\nAfter spawning your process, Tini will wait for signals and forward those\nto the child process, and periodically reap zombie processes that may be\ncreated within your container.\n\nWhen the \"first\" child process exits (`/your/program` in the examples above),\nTini exits as well, with the exit code of the child process (so you can\ncheck your container's exit code to know whether the child exited\nsuccessfully).\n\n\nDebugging\n---------\n\nIf something isn't working just like you expect, consider increasing the\nverbosity level (up to 3):\n\n    tini -v    -- bash -c 'exit 1'\n    tini -vv   -- true\n    tini -vvv  -- pwd\n\n\nAuthors\n=======\n\nMaintainer:\n\n  + [Thomas Orozco][20]\n\nContributors:\n\n  + [Tianon Gravi][30]\n  + [David Wragg][31]\n  + [Michael Crosby][32]\n  + [Wyatt Preul][33]\n  + [Patrick Steinhardt][34]\n\nSpecial thanks to:\n\n  + [Danilo Bürger][40] for packaging Tini for Alpine\n  + [Asko Soukka][41] for packaging Tini for Nix\n  + [nfnty][42] for packaging Tini for Arch Linux\n\n\n  [0]: https://github.com/krallin/tini/issues/8\n  [5]: https://docs.docker.com/engine/reference/commandline/run/\n  [10]: https://github.com/krallin/tini-images\n  [11]: https://github.com/krallin/tini/releases\n  [12]: https://github.com/krallin/tini/pull/114\n  [20]: https://github.com/krallin/\n  [30]: https://github.com/tianon\n  [31]: https://github.com/dpw\n  [32]: https://github.com/crosbymichael\n  [33]: https://github.com/geek\n  [34]: https://github.com/pks-t\n  [40]: https://github.com/danilobuerger\n  [41]: https://github.com/datakurre\n  [42]: https://github.com/nfnty/pkgbuilds/tree/master/tini/tini\n"
  },
  {
    "path": "tpl/VERSION.in",
    "content": "@tini_VERSION_MAJOR@.@tini_VERSION_MINOR@.@tini_VERSION_PATCH@\n"
  }
]