Add standard command-line flags
This commit is contained in:
parent
bac1bf99b0
commit
6b7f0ce3fa
8 changed files with 99 additions and 34 deletions
|
@ -19,7 +19,8 @@ of that after merging!
|
|||
|
||||
The process to release a new version is:
|
||||
|
||||
1. Update the version in `setup.py`
|
||||
1. Update the version in `VERSION`
|
||||
2. Run `make VERSION.h`
|
||||
2. Update the Debian changelog with `dch -v {new version}`.
|
||||
3. Update the `wget` url in the README to point to the new version.
|
||||
4. Commit the changes and tag the commit like `v1.0.0`.
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
include dumb-init.c
|
||||
include VERSION
|
||||
include VERSION.h
|
||||
|
|
7
Makefile
7
Makefile
|
@ -48,9 +48,14 @@ DOCKER_TOX_TEST := sh -uexc ' \
|
|||
&& tox \
|
||||
'
|
||||
.PHONY: build
|
||||
build:
|
||||
build: VERSION.h
|
||||
$(CC) $(CFLAGS) -o dumb-init dumb-init.c
|
||||
|
||||
VERSION.h: VERSION
|
||||
echo '// THIS FILE IS AUTOMATICALLY GENERATED' > VERSION.h
|
||||
echo '// Run `make VERSION.h` to update it after modifying VERSION.' >> VERSION.h
|
||||
xxd -i VERSION >> VERSION.h
|
||||
|
||||
.PHONY: clean
|
||||
clean: clean-tox
|
||||
rm -rf dumb-init dist/ *.deb
|
||||
|
|
1
VERSION
Normal file
1
VERSION
Normal file
|
@ -0,0 +1 @@
|
|||
0.4.0
|
6
VERSION.h
Normal file
6
VERSION.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
// THIS FILE IS AUTOMATICALLY GENERATED
|
||||
// Run `make VERSION.h` to update it after modifying VERSION.
|
||||
unsigned char VERSION[] = {
|
||||
0x30, 0x2e, 0x34, 0x2e, 0x30, 0x0a
|
||||
};
|
||||
unsigned int VERSION_len = 6;
|
84
dumb-init.c
84
dumb-init.c
|
@ -5,11 +5,12 @@
|
|||
* Usage:
|
||||
* ./dumb-init python -c 'while True: pass'
|
||||
*
|
||||
* To get debug output on stderr, run with DUMB_INIT_DEBUG=1
|
||||
* To get debug output on stderr, run with '-v'.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -17,6 +18,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include "VERSION.h"
|
||||
|
||||
#define PRINTERR(...) do { \
|
||||
fprintf(stderr, "[dumb-init] " __VA_ARGS__); \
|
||||
|
@ -99,50 +101,72 @@ void handle_signal(int signum) {
|
|||
|
||||
void print_help(char *argv[]) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s COMMAND [[ARG] ...]\n"
|
||||
"dumb-init v%s"
|
||||
"Usage: %s [option] command [[arg] ...]\n"
|
||||
"\n"
|
||||
"dumb-init is a simple process designed to run as PID 1 inside Docker\n"
|
||||
"containers and proxy signals to child processes.\n"
|
||||
"dumb-init is a simple process supervisor that forwards signals to children.\n"
|
||||
"It is designed to run as PID1 in minimal container environments.\n"
|
||||
"\n"
|
||||
"Docker runs your processes as PID1. The kernel doesn't apply default signal\n"
|
||||
"handling to PID1 processes, so if your process doesn't register a custom\n"
|
||||
"signal handler, signals like TERM will just bounce off your process.\n"
|
||||
"Optional arguments:\n"
|
||||
" -c, --single-child Run in single-child mode.\n"
|
||||
" In this mode, signals are only proxies to the\n"
|
||||
" direct child and not any of its ancestors.\n"
|
||||
" -v, --verbose Print debugging information to stderr.\n"
|
||||
" -h, --help Print this help message and exit.\n"
|
||||
" -V, --version Print the current version and exit.\n"
|
||||
"\n"
|
||||
"This can result in cases where sending signals to a `docker run` process\n"
|
||||
"results in the run process exiting, but the container continuing in the\n"
|
||||
"background.\n"
|
||||
"\n"
|
||||
"A workaround is to wrap your script in this proxy, which runs as PID1. Your\n"
|
||||
"process then runs as some other PID, and the kernel won't treat the signals\n"
|
||||
"that are proxied to them specially.\n"
|
||||
"\n"
|
||||
"The proxy dies when your process dies, so it must not double-fork or do other\n"
|
||||
"weird things (this is basically a requirement for doing things sanely in\n"
|
||||
"Docker anyway).\n"
|
||||
"\n"
|
||||
"By default, dumb-init starts a process group (and session, see: man 2 setsid)\n"
|
||||
"and signals all processes in it. This is usually useful behavior, but if for\n"
|
||||
"some reason you wish to disable it, run with DUMB_INIT_SETSID=0.\n",
|
||||
"Full help is available online at https://github.com/Yelp/dumb-init\n",
|
||||
VERSION,
|
||||
argv[0]
|
||||
);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int signum;
|
||||
char *debug_env, *setsid_env;
|
||||
int signum, opt;
|
||||
|
||||
if (argc < 2) {
|
||||
print_help(argv);
|
||||
return 1;
|
||||
struct option long_options[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"single-child", no_argument, NULL, 'c'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{"version", no_argument, NULL, 'V'},
|
||||
};
|
||||
while ((opt = getopt_long(argc, argv, "+hvVc", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
print_help(argv);
|
||||
return 0;
|
||||
case 'v':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'V':
|
||||
fprintf(stderr, "dumb-init v%s", VERSION);
|
||||
return 0;
|
||||
case 'c':
|
||||
use_setsid = 0;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
debug_env = getenv("DUMB_INIT_DEBUG");
|
||||
if (optind >= argc) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Usage: %s [option] program [args]\n"
|
||||
"Try %s --help for full usage.\n",
|
||||
argv[0], argv[0]
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
char **cmd = &argv[optind];
|
||||
|
||||
char *debug_env = getenv("DUMB_INIT_DEBUG");
|
||||
if (debug_env && strcmp(debug_env, "1") == 0) {
|
||||
debug = 1;
|
||||
DEBUG("Running in debug mode.\n");
|
||||
}
|
||||
|
||||
setsid_env = getenv("DUMB_INIT_SETSID");
|
||||
char *setsid_env = getenv("DUMB_INIT_SETSID");
|
||||
if (setsid_env && strcmp(setsid_env, "0") == 0) {
|
||||
use_setsid = 0;
|
||||
DEBUG("Not running in setsid mode.\n");
|
||||
|
@ -181,7 +205,7 @@ int main(int argc, char *argv[]) {
|
|||
DEBUG("setsid complete.\n");
|
||||
}
|
||||
|
||||
execvp(argv[1], &argv[1]);
|
||||
execvp(cmd[0], &cmd[0]);
|
||||
|
||||
// if this point is reached, exec failed, so we should exit nonzero
|
||||
PRINTERR("%s: %s\n", argv[1], strerror(errno));
|
||||
|
|
3
setup.py
3
setup.py
|
@ -87,10 +87,9 @@ class build_cexe(Command):
|
|||
setup(
|
||||
name='dumb-init',
|
||||
description='Simple wrapper script which proxies signals to a child',
|
||||
version='0.4.0',
|
||||
version=open('VERSION').read().strip(),
|
||||
author='Yelp',
|
||||
platforms='linux',
|
||||
|
||||
c_executables=[
|
||||
Extension(
|
||||
'dumb-init',
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
from subprocess import PIPE
|
||||
from subprocess import Popen
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def test_exit_status(both_debug_modes, both_setsid_modes):
|
||||
"""dumb-init should say something useful when called with no arguments, and
|
||||
|
@ -9,4 +11,29 @@ def test_exit_status(both_debug_modes, both_setsid_modes):
|
|||
proc = Popen(('dumb-init'), stderr=PIPE)
|
||||
_, stderr = proc.communicate()
|
||||
assert proc.returncode != 0
|
||||
assert stderr == (
|
||||
b'Usage: dumb-init [option] program [args]\n'
|
||||
b'Try dumb-init --help for full usage.\n'
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('flag', ['-h', '--help'])
|
||||
def test_help_message(flag, both_debug_modes, both_setsid_modes):
|
||||
"""dumb-init should say something useful when called with the help flag,
|
||||
and exit zero.
|
||||
"""
|
||||
proc = Popen(('dumb-init', flag), stderr=PIPE)
|
||||
_, stderr = proc.communicate()
|
||||
assert proc.returncode == 0
|
||||
assert len(stderr) >= 50
|
||||
|
||||
|
||||
@pytest.mark.parametrize('flag', ['-V', '--version'])
|
||||
def test_version_message(flag, both_debug_modes, both_setsid_modes):
|
||||
"""dumb-init should print its version when asked to."""
|
||||
version = open('VERSION', 'rb').read()
|
||||
|
||||
proc = Popen(('dumb-init', flag), stderr=PIPE)
|
||||
_, stderr = proc.communicate()
|
||||
assert proc.returncode == 0
|
||||
assert stderr == b'dumb-init v' + version
|
||||
|
|
Loading…
Reference in a new issue