From 9b65e1da122bec8a5d5097986622c0e00e12886e Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 14 2017 19:57:42 +0000 Subject: import dumb-init-1.2.0-1.20170802gitd283f8a.el6 --- diff --git a/.dumb-init.metadata b/.dumb-init.metadata new file mode 100644 index 0000000..ce9a686 --- /dev/null +++ b/.dumb-init.metadata @@ -0,0 +1 @@ +16c44156c856c6fb368e60ebc233ab47025305b2 SOURCES/dumb-init-d283f8a.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8538ca5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/dumb-init-d283f8a.tar.gz diff --git a/README.md b/README.md deleted file mode 100644 index 98f42b4..0000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/initscripts.patch b/SOURCES/initscripts.patch new file mode 100644 index 0000000..182d37f --- /dev/null +++ b/SOURCES/initscripts.patch @@ -0,0 +1,322 @@ +From 6d1619802269db2f62c6b51b03a049c3d3a23a2c Mon Sep 17 00:00:00 2001 +From: Frantisek Kluknavsky +Date: Mon, 21 Aug 2017 16:44:19 +0200 +Subject: [PATCH] rhel6 features + +--- + dumb-init.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 171 insertions(+), 28 deletions(-) + +diff --git a/dumb-init.c b/dumb-init.c +index 65e69ef..3893b8c 100644 +--- a/dumb-init.c ++++ b/dumb-init.c +@@ -19,6 +19,8 @@ + #include + #include + #include ++#include ++#include + #include "VERSION.h" + + #define PRINTERR(...) do { \ +@@ -34,14 +36,18 @@ + // Signals we care about are numbered from 1 to 31, inclusive. + // (32 and above are real-time signals.) + // TODO: this is likely not portable outside of Linux, or on strange architectures +-#define MAXSIG 31 ++// EDIT: we actually care about some real-time signals as well ++// SIGRTMAX is not a constant, use 64 ++#define MAXSIG 64 + + // Indices are one-indexed (signal 1 is at index 1). Index zero is unused. + int signal_rewrite[MAXSIG + 1] = {[0 ... MAXSIG] = -1}; ++char *signal_action[MAXSIG + 1] = {[0 ... MAXSIG] = ""}; + + pid_t child_pid = -1; + char debug = 0; + char use_setsid = 1; ++static char survive_bereaving = 0; + + int translate_signal(int signum) { + if (signum <= 0 || signum > MAXSIG) { +@@ -57,17 +63,75 @@ int translate_signal(int signum) { + } + } + ++void do_action(int signum) { ++ DEBUG("Action for signal %d: running %s\n", signum, signal_action[signum]); ++ int child_pid = fork(); ++ if (child_pid < 0) { ++ PRINTERR("Unable to fork. Exiting.\n"); ++ exit(1); ++ } else if (child_pid == 0) { ++ /* child */ ++ sigset_t all_signals; ++ sigfillset(&all_signals); ++ sigprocmask(SIG_UNBLOCK, &all_signals, NULL); ++ execlp("/bin/bash", "/bin/bash", "-c", signal_action[signum], (char *)NULL); ++ ++ // if this point is reached, exec failed, so we should exit nonzero ++ PRINTERR("Could not exec %s: %s\n", signal_action[signum], strerror(errno)); ++ exit(1); ++ } ++} ++ + void forward_signal(int signum) { +- signum = translate_signal(signum); +- if (signum != -1) { +- kill(use_setsid ? -child_pid : child_pid, signum); +- DEBUG("Forwarded signal %d to children.\n", signum); ++ int new_signum = translate_signal(signum); ++ if (new_signum == -2) { ++ do_action(signum); ++ } else if (new_signum != -1) { ++ kill(use_setsid ? -child_pid : child_pid, new_signum); ++ DEBUG("Forwarded signal %d to children.\n", new_signum); + } else { +- DEBUG("Not forwarding signal %d to children (ignored).\n", signum); ++ DEBUG("Not forwarding signal %d to children (ignored).\n", new_signum); + } + } + + /* ++ * Read /proc and see if there are processes except init(PIDs) ++ */ ++signed int process_count() { ++ DIR *dp; ++ struct dirent *ep; ++ char nonnumber; ++ signed int count = 0; ++ ++ dp = opendir ("/proc"); ++ if (dp != NULL) ++ { ++ while ((ep = readdir (dp)) != NULL) { ++ nonnumber = 0; ++ for (int i = 0; ep->d_name[i] != 0; ++i) { ++ if (!isdigit(ep->d_name[i])) { ++ nonnumber = 1; ++ break; ++ } ++ } ++ if (!nonnumber) { ++ DEBUG("/proc/%s is a process\n", ep->d_name); ++ ++count; ++ if (count > 1) { ++ closedir(dp); ++ return 2; //2 is enough, do not count further ++ } ++ } ++ } ++ closedir(dp); ++ } else { ++ PRINTERR("Could not open /proc.\n"); ++ return -1; ++ } ++ return count; ++} ++ ++/* + * The dumb-init signal handler. + * + * The main job of this signal handler is to forward signals along to our child +@@ -88,6 +152,7 @@ void forward_signal(int signum) { + * + */ + void handle_signal(int signum) { ++ static char bereaved = 0; + DEBUG("Received signal %d.\n", signum); + if (signum == SIGCHLD) { + int status, exit_status; +@@ -103,11 +168,26 @@ void handle_signal(int signum) { + } + + if (killed_pid == child_pid) { +- forward_signal(SIGTERM); // send SIGTERM to any remaining children +- DEBUG("Child exited with status %d. Goodbye.\n", exit_status); +- exit(exit_status); ++ bereaved = 1; ++ if (!survive_bereaving) { ++ forward_signal(SIGTERM); // send SIGTERM to any remaining children ++ DEBUG("Child exited with status %d. Goodbye.\n", exit_status); ++ exit(exit_status); ++ } else { ++ DEBUG("Child exited with status %d. Stay alive for your grandchildren.\n", exit_status); ++ } + } + } ++ ++ if ((bereaved == 1) && survive_bereaving) { ++ signed int pc = process_count(); ++ DEBUG("Process count: %d\n", pc); ++ if (pc <= 1) { ++ DEBUG("No process left, exitting.\n"); ++ exit(0); ++ } ++ } ++ + } else { + forward_signal(signum); + if (signum == SIGTSTP || signum == SIGTTOU || signum == SIGTTIN) { +@@ -126,15 +206,21 @@ void print_help(char *argv[]) { + "It is designed to run as PID1 in minimal container environments.\n" + "\n" + "Optional arguments:\n" +- " -c, --single-child Run in single-child mode.\n" +- " In this mode, signals are only proxied to the\n" +- " direct child and not any of its descendants.\n" +- " -r, --rewrite s:r Rewrite received signal s to new signal r before proxying.\n" +- " To ignore (not proxy) a signal, rewrite it to 0.\n" +- " This option can be specified multiple times.\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" ++ " -c, --single-child Run in single-child mode.\n" ++ " In this mode, signals are only proxied to the\n" ++ " direct child and not any of its descendants.\n" ++ " -b, --survive-bereaving Do not quit when the direct child dies.\n" ++ " -r, --rewrite s:r Rewrite received signal s to new signal r before proxying.\n" ++ " To ignore (not proxy) a signal, rewrite it to 0.\n" ++ " To rewrite all signals, rewrite (otherwise nonexistent) signal 0.\n" ++ " (Useful to ignore all signals, use '--rewrite 0:0').\n" ++ " This option can be specified multiple times.\n" ++ " -a, --action s:exe Run exe after receiving sinal s.\n" ++ " For example, -a '2:echo hi there'.\n" ++ " This option can be specified multiple times.\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" + "Full help is available online at https://github.com/Yelp/dumb-init\n", + VERSION, +@@ -146,11 +232,24 @@ void print_rewrite_signum_help() { + fprintf( + stderr, + "Usage: -r option takes :, where " ++ "is between 0 and %d.\n" ++ "This option can be specified multiple times.\n" ++ "Use --help for full usage.\n", ++ MAXSIG ++ ); ++ exit(1); ++} ++ ++void print_action_help() { ++ fprintf( ++ stderr, ++ "Usage: -a option takes :, where " + "is between 1 and %d.\n" + "This option can be specified multiple times.\n" + "Use --help for full usage.\n", + MAXSIG + ); ++ + exit(1); + } + +@@ -158,15 +257,36 @@ void parse_rewrite_signum(char *arg) { + int signum, replacement; + if ( + sscanf(arg, "%d:%d", &signum, &replacement) == 2 && +- (signum >= 1 && signum <= MAXSIG) && ++ (signum >= 0 && signum <= MAXSIG) && + (replacement >= 0 && replacement <= MAXSIG) + ) { +- signal_rewrite[signum] = replacement; ++ if (signum == 0) { ++ for (int i = 0; i <= MAXSIG; ++i) { ++ signal_rewrite[i] = replacement; ++ } ++ } else { ++ signal_rewrite[signum] = replacement; ++ } + } else { + print_rewrite_signum_help(); + } + } + ++void parse_action(char *arg) { ++ int signum; ++ int status; ++ int position; ++ if ( ++ (status = sscanf(arg, "%d:%n", &signum, &position)) == 1 && ++ (signum >= 0 && signum <= MAXSIG) ++ ) { ++ DEBUG("signal action: %d, position %d\n", signum, position); ++ signal_action[signum] = &(arg[position]); ++ signal_rewrite[signum] = -2; ++ } else { ++ print_action_help(); ++ } ++} + void set_rewrite_to_sigstop_if_not_defined(int signum) { + if (signal_rewrite[signum] == -1) + signal_rewrite[signum] = SIGSTOP; +@@ -175,14 +295,16 @@ void set_rewrite_to_sigstop_if_not_defined(int signum) { + char **parse_command(int argc, char *argv[]) { + int opt; + struct option long_options[] = { +- {"help", no_argument, NULL, 'h'}, +- {"single-child", no_argument, NULL, 'c'}, +- {"rewrite", required_argument, NULL, 'r'}, +- {"verbose", no_argument, NULL, 'v'}, +- {"version", no_argument, NULL, 'V'}, ++ {"help", no_argument, NULL, 'h'}, ++ {"single-child", no_argument, NULL, 'c'}, ++ {"rewrite", required_argument, NULL, 'r'}, ++ {"verbose", no_argument, NULL, 'v'}, ++ {"version", no_argument, NULL, 'V'}, ++ {"survive-bereaving",no_argument, NULL, 'b'}, ++ {"action", required_argument, NULL, 'a'}, + {NULL, 0, NULL, 0}, + }; +- while ((opt = getopt_long(argc, argv, "+hvVcr:", long_options, NULL)) != -1) { ++ while ((opt = getopt_long(argc, argv, "+hvVcbr:a:", long_options, NULL)) != -1) { + switch (opt) { + case 'h': + print_help(argv); +@@ -199,7 +321,14 @@ char **parse_command(int argc, char *argv[]) { + case 'r': + parse_rewrite_signum(optarg); + break; ++ case 'a': ++ parse_action(optarg); ++ break; ++ case 'b': ++ survive_bereaving = 1; ++ break; + default: ++ PRINTERR("Error while parsing arguments.\n"); + exit(1); + } + } +@@ -295,8 +424,22 @@ int main(int argc, char *argv[]) { + /* parent */ + DEBUG("Child spawned with PID %d.\n", child_pid); + for (;;) { +- int signum; +- sigwait(&all_signals, &signum); ++ struct timespec timeout = {1, 0}; ++ int signum = sigtimedwait(&all_signals, NULL, &timeout); ++ if (signum == -1) { ++ switch (errno) { ++ case EINVAL: ++ PRINTERR("Invalid timeout, report this as a bug!\n"); ++ exit(1); ++ case EINTR: ++ PRINTERR("Wait interrupted by a signal. This should never happen. Report this as a bug!\n"); ++ exit(1); ++ case EAGAIN: ++ //pretend timeout to be SIGCHLD, check if we want to continue running ++ signum = SIGCHLD; ++ DEBUG("Heartbeat...\n"); ++ } ++ } + handle_signal(signum); + } + } +-- +2.13.3 + diff --git a/SPECS/dumb-init.spec b/SPECS/dumb-init.spec new file mode 100644 index 0000000..3432799 --- /dev/null +++ b/SPECS/dumb-init.spec @@ -0,0 +1,96 @@ +%global provider github +%global provider_tld com +%global project Yelp +%global repo dumb-init +%global provider_prefix %{provider}.%{provider_tld}/%{project}/%{repo} +%global commit d283f8a58bea8374c03becf8f06339670f2f07ee +%global shortcommit %(c=%{commit}; echo ${c:0:7}) + +%global YYYYMMDD 20170802 + +Name: %{repo} +Version: 1.2.0 +Release: 1.%{YYYYMMDD}git%{shortcommit}%{?dist} +Summary: Entry-point for containers that proxies signals +License: MIT +URL: https://%{provider_prefix} +Source0: %{url}/archive/%{commit}/%{name}-%{shortcommit}.tar.gz +Patch0: initscripts.patch + +BuildRequires: gcc, help2man + +#To build in rhel6, we just run gcc and help2man. +#Containers do not work in rhel6, python is old, packages are missing, tests will not work +#the following is only for future reference: +#BuildRequires: python, python2-pytest, python2-mock +# /bin/xxd of vim-common of is needed for non-released versions +# BuildRequires: vim-common + +%description +dumb-init is a simple process supervisor and init system designed to run as +PID 1 inside minimal container environments (such as Docker). + +* It can handle orphaned zombie processes. +* It can pass signals properly for simple containers. + +%prep +%setup -q -n %{name}-%{commit} +%patch0 -p1 -b .initscripts + +%build +gcc -std=gnu99 %{optflags} -o %{name} dumb-init.c + +#a wrapper to redirect stderr for old help2man +cat <%{name}.wrapper +#!/bin/bash +./dumb-init "\$@" 2>&1 +EOF + +chmod a+x %{name}.wrapper +help2man --include debian/help2man --no-info --name '%{summary}' ./%{name}.wrapper> %{name}.1 +rm %{name}.wrapper + +#sadly, in rhel6, no containers, no tests +#%%check +#PATH=.:$PATH py.test tests/ + +%install +install -Dpm0755 %{name} %{buildroot}%{_bindir}/%{name} +install -Dpm0644 %{name}.1 %{buildroot}%{_mandir}/man1/%{name}.1 + +%files +%{_bindir}/%{name} +%{_mandir}/man1/%{name}.1* +%doc README.md LICENSE + +%changelog +* Mon Aug 21 2017 Frantisek Kluknavsky - 1.2.0-2.20170802gitd283f8a +- rebased and heavily adapted for rhel6 + +* Fri Feb 10 2017 Fedora Release Engineering - 1.1.3-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Wed Aug 31 2016 Muayyad Alsadi - 1.1.3-10 +- revert to python2 + +* Wed Aug 31 2016 Muayyad Alsadi - 1.1.3-9 +- support epel + +* Fri Aug 26 2016 Muayyad Alsadi - 1.1.3-8 +- run tests + +* Wed Aug 17 2016 Muayyad Alsadi - 1.1.3-7 +- let manpage automatically marked as document + +* Wed Aug 17 2016 Muayyad Alsadi - 1.1.3-6 +- remove gzip after help2man +- add missing BuildRequire + +* Wed Aug 17 2016 Muayyad Alsadi - 1.1.3-4 +- install 644 for manpage + +* Wed Aug 17 2016 Muayyad Alsadi - 1.1.3-3 +- remove vim-common and use install + +* Mon Aug 15 2016 Muayyad Alsadi - 1.1.3-2 +- initial packaging