aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-05-20 10:53:30 +0300
committerSergey Poznyakoff <gray@gnu.org>2018-05-20 10:53:30 +0300
commitddb46c6aa42ada061e51c635c0230e4dc8eab881 (patch)
treeb003ae6af354f553207981b4fc281e8f9e19c60e
parented8389beadb7cf1f8d95fe7addbc9ff2783f4d07 (diff)
downloadgenrc-ddb46c6aa42ada061e51c635c0230e4dc8eab881.tar.gz
genrc-ddb46c6aa42ada061e51c635c0230e4dc8eab881.tar.bz2
Sentinel mode: restart the program on certain conditions
* Makefile.am: Create the ChangeLog file from git log. * configure.ac: Request git2chg * src/com_start.c: Use sigaction instead of signal. * src/genrc.8: Document new options. * src/genrc.c: New options --restart-on-exit and --restart-on-signal. * src/genrc.h (str_to_sig, str_to_int): New prototypes. (add_restart_condition): New prototype. * src/sentinel.c (restart_on, add_restart_condition): (check_failure_rate): New functions. (wait_loop): Return if restart is requested. (sentinel): Restart the program if needed.
-rw-r--r--Makefile.am11
-rw-r--r--configure.ac4
-rw-r--r--src/com_start.c10
-rw-r--r--src/genrc.858
-rw-r--r--src/genrc.c41
-rw-r--r--src/genrc.h10
-rw-r--r--src/sentinel.c190
7 files changed, 304 insertions, 20 deletions
diff --git a/Makefile.am b/Makefile.am
index 31e9e5f..dac3cb3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1 +1,12 @@
1SUBDIRS = grecs src 1SUBDIRS = grecs src
2dist: ChangeLog
3.PHONY: ChangeLog
4ChangeLog:
5 $(AM_V_GEN)if test -d .git; then \
6 git log --pretty='format:%ct %an <%ae>%n%n%s%n%n%b%n' | \
7 awk -f $(top_srcdir)/@GRECS_SUBDIR@/build-aux/git2chg.awk \
8 > ChangeLog.tmp; \
9 cmp ChangeLog ChangeLog.tmp > /dev/null 2>&1 || \
10 mv ChangeLog.tmp ChangeLog; \
11 rm -f ChangeLog.tmp; \
12 fi
diff --git a/configure.ac b/configure.ac
index 5d36092..a568649 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,7 +15,7 @@
15# along with genrc. If not, see <http://www.gnu.org/licenses/>. 15# along with genrc. If not, see <http://www.gnu.org/licenses/>.
16 16
17AC_PREREQ([2.69]) 17AC_PREREQ([2.69])
18AC_INIT([genrc], [1.0], [gray@gnu.org]) 18AC_INIT([genrc], [1.0.90], [gray@gnu.org])
19AC_CONFIG_SRCDIR([src/genrc.c]) 19AC_CONFIG_SRCDIR([src/genrc.c])
20AC_CONFIG_HEADERS([config.h]) 20AC_CONFIG_HEADERS([config.h])
21AM_INIT_AUTOMAKE([1.11 foreign silent-rules]) 21AM_INIT_AUTOMAKE([1.11 foreign silent-rules])
@@ -37,7 +37,7 @@ AC_CHECK_HEADERS([getopt.h pcre.h])
37# Checks for library functions. 37# Checks for library functions.
38AC_CHECK_FUNCS([getdtablesize]) 38AC_CHECK_FUNCS([getdtablesize])
39 39
40GRECS_SETUP(grecs, [all-parsers]) 40GRECS_SETUP(grecs, [all-parsers git2chg])
41 41
42AM_CONDITIONAL([COND_PCRE], 42AM_CONDITIONAL([COND_PCRE],
43 [test "$ac_cv_header_pcre_h" = yes && test "$ac_cv_lib_pcre_main" = yes]) 43 [test "$ac_cv_header_pcre_h" = yes && test "$ac_cv_lib_pcre_main" = yes])
diff --git a/src/com_start.c b/src/com_start.c
index 5744e39..3a9dffc 100644
--- a/src/com_start.c
+++ b/src/com_start.c
@@ -43,9 +43,13 @@ timedwaitpid(pid_t pid, int *status)
43{ 43{
44 struct timeval now, stoptime, ttw; 44 struct timeval now, stoptime, ttw;
45 int rc = -1; 45 int rc = -1;
46 SIGHANDLER oldsig; 46 struct sigaction act, oldact;
47
48 act.sa_handler = sigchld;
49 act.sa_flags = 0;
50 sigemptyset(&act.sa_mask);
51 sigaction(SIGCHLD, &act, &oldact);
47 52
48 oldsig = signal(SIGCHLD, sigchld);
49 gettimeofday(&stoptime, NULL); 53 gettimeofday(&stoptime, NULL);
50 stoptime.tv_sec += genrc_timeout; 54 stoptime.tv_sec += genrc_timeout;
51 while (1) { 55 while (1) {
@@ -73,7 +77,7 @@ timedwaitpid(pid_t pid, int *status)
73 } 77 }
74 78
75 } 79 }
76 signal(SIGCHLD, oldsig); 80 sigaction(SIGCHLD, &oldact, NULL);
77 if (rc) { 81 if (rc) {
78 kill(pid, SIGKILL); 82 kill(pid, SIGKILL);
79 } 83 }
diff --git a/src/genrc.8 b/src/genrc.8
index 00522ee..959a00e 100644
--- a/src/genrc.8
+++ b/src/genrc.8
@@ -13,7 +13,7 @@
13.\" 13.\"
14.\" You should have received a copy of the GNU General Public License 14.\" You should have received a copy of the GNU General Public License
15.\" along with genrc. If not, see <http://www.gnu.org/licenses/>. 15.\" along with genrc. If not, see <http://www.gnu.org/licenses/>.
16.TH GENRC 8 "May 17, 2018" "GENRC" "Genrc User Manual" 16.TH GENRC 8 "May 20, 2018" "GENRC" "Genrc User Manual"
17.SH NAME 17.SH NAME
18genrc \- generic system initialization script helper 18genrc \- generic system initialization script helper
19.SH SYNOPSIS 19.SH SYNOPSIS
@@ -36,6 +36,8 @@ genrc \- generic system initialization script helper
36 [\fB\-\-pid\-from=\fISOURCE\fR]\ 36 [\fB\-\-pid\-from=\fISOURCE\fR]\
37 [\fB\-\-pidfile=\fIPIDFILE\fR]\ 37 [\fB\-\-pidfile=\fIPIDFILE\fR]\
38 [\fB\-\-program=\fIPROGRAM\fR]\ 38 [\fB\-\-program=\fIPROGRAM\fR]\
39 [\fB\-\-restart\-on\-exit=\fR[\fB!\fR]\fISTATUS\fR[\fB,\fISTATUS\fR...]]\
40 [\fB\-\-restart\-on\-signal=\fR[\fB!\fR]\fISIG\fR[\fB,\fISIG\fR...]]\
39 [\fB\-\-sentinel\fR]\ 41 [\fB\-\-sentinel\fR]\
40 [\fB\-\-signal\-reload=\fISIG\fR]\ 42 [\fB\-\-signal\-reload=\fISIG\fR]\
41 [\fB\-\-signal\-stop=\fISIG\fR]\ 43 [\fB\-\-signal\-stop=\fISIG\fR]\
@@ -101,6 +103,30 @@ If the \fB\-\-create\-pidfile=\fIFILENAME\fR option is given together with
101in \fIFILE\fR. The file will be unlinked after the subsidiary command 103in \fIFILE\fR. The file will be unlinked after the subsidiary command
102terminates. Unless the \fB\-\-pid\-from\fR option is given, 104terminates. Unless the \fB\-\-pid\-from\fR option is given,
103\fB\-\-pid\-from=FILE:\fIFILENAME\fR will be assumed. 105\fB\-\-pid\-from=FILE:\fIFILENAME\fR will be assumed.
106.PP
107In sentinel mode, it is possible to restart the program if it
108terminates with a specific exit code or on a specific signal. This is
109controlled by the \fB\-\-restart\-on\-exit\fR and
110\fB\-\-restart\-on\-signal\fR options. Use this feature to ensure the
111service provided by the program won't get terminated because of
112hitting a bug or encountering an unforeseen external condition. For
113example, the following two options will ensure that the program will
114be terminated only if it exits with status 0 or it is terminated by
115SIGTERM or SIGQUIT signal:
116.EX
117--restart-on-exit='!0' --restart-on-signal='!TERM,QUIT'
118.EE
119.PP
120If restarts are requested, \fBgenrc\fR will control how often it has
121to restart the program using the same algorithm as
122.B init (8).
123Namely, if the program is restarted more than 10 times within two
124minutes, \fBgenrc\fR will disable subsequent restarts for the next
1255 minutes. If the \fB\-\-create\-pidfile\fR option was used, the
126PID of the controlling \fBgenrc\fR process will be stored in the
127file during that interval. If the \fBSIGHUP\fR signal is delivered
128during the sleep interval, the sleep will be broken prematurely and
129the program restarted again.
104.SS status 130.SS status
105In \fBstatus\fR mode \fBgenrc\fR verifies if the \fICOMMAND\fR is 131In \fBstatus\fR mode \fBgenrc\fR verifies if the \fICOMMAND\fR is
106already running and outputs its status on the standard output. To this 132already running and outputs its status on the standard output. To this
@@ -188,9 +214,37 @@ Name of the program to run.
188\fB\-P\fR, \fB\-\-pid\-from=\fISOURCE\fR 214\fB\-P\fR, \fB\-\-pid\-from=\fISOURCE\fR
189Where to look for PIDs of the running programs. 215Where to look for PIDs of the running programs.
190.TP 216.TP
217\fB\-\-restart\-on\-exit=\fR[\fB!\fR]\fISTATUS\fR[\fB,\fISTATUS\fR...]
218This option takes effect when used together with
219\fB\-\-sentinel\fR. If the program terminates with one of status
220codes listed as the argument to this option, it will be immediately
221restarted. The exclamation mark at the start of the list inverts the
222set, e.g. \fB\-\-restart\-on\-exit='!0,1'\fR means restart unless the
223program exit code is 0 or 1. Note the use of quotation to prevent the
224\fB!\fR from being interpreted by the shell.
225.TP
226\fB\-\-restart\-on\-signal=\fR[\fB!\fR]\fISIG\fR[\fB,\fISIG\fR...]
227This option takes effect when used together with
228\fB\-\-sentinel\fR. If the program terminates due to receiving one of
229the signals from this list, it will be immediately restarted. Each
230\fISIG\fR is either a signal number, or a signal name, as listed in
231.BR signal (7).
232The \fBSIG\fR prefix can be omitted from the signal name. Names are
233case-insensitive. Thus, \fB1\fR, \fBHUP\fR, \fBSIGHUP\fR, and
234\fBsighup\fR all stand for the same signal.
235.sp
236The exclamation mark at the start of the list complements the signal
237set, so that e.g. \fB\-\-restart\-on\-signal='!TERM,QUIT,INT'\fR will
238restart the program unless it terminates on one of the listed signals.
239.TP
191\fB\-\-sentinel\fR 240\fB\-\-sentinel\fR
192\fIPROGRAM\fR runs in foreground; disconnect from the controlling 241\fIPROGRAM\fR runs in foreground; disconnect from the controlling
193terminal, run it and act as a sentinel. 242terminal, start it and run in background until it terminates. The
243program's stdout and stderr are sent to the syslog facility
244\fBdaemon\fR, priorities \fBinfo\fR and \fBerr\fR, correspondingly.
245
246See the options \fB\-\-restart\-on\-exit\fR and
247\fB\-\-restart\-on\-signal\fR for details on how to restart the program.
194.TP 248.TP
195\fB\-\-signal\-reload=\fISIG\fR 249\fB\-\-signal\-reload=\fISIG\fR
196Signal to send on reload (default: \fBSIGHUP\fR). Setting it to 0 is 250Signal to send on reload (default: \fBSIGHUP\fR). Setting it to 0 is
diff --git a/src/genrc.c b/src/genrc.c
index ae3070d..9052987 100644
--- a/src/genrc.c
+++ b/src/genrc.c
@@ -25,7 +25,9 @@ enum {
25 OPT_SIGNAL_RELOAD, 25 OPT_SIGNAL_RELOAD,
26 OPT_NO_RELOAD, 26 OPT_NO_RELOAD,
27 OPT_SIGNAL_STOP, 27 OPT_SIGNAL_STOP,
28 OPT_CREATE_PIDFILE 28 OPT_CREATE_PIDFILE,
29 OPT_RESTART_ON_EXIT,
30 OPT_RESTART_ON_SIGNAL,
29}; 31};
30 32
31struct option longopts[] = { 33struct option longopts[] = {
@@ -45,6 +47,8 @@ struct option longopts[] = {
45 { "verbose", no_argument, 0, 'v' }, 47 { "verbose", no_argument, 0, 'v' },
46 { "user", required_argument, 0, 'u' }, 48 { "user", required_argument, 0, 'u' },
47 { "group", required_argument, 0, 'g' }, 49 { "group", required_argument, 0, 'g' },
50 { "restart-on-exit", required_argument, 0, OPT_RESTART_ON_EXIT },
51 { "restart-on-signal", required_argument, 0, OPT_RESTART_ON_SIGNAL },
48 { NULL } 52 { NULL }
49}; 53};
50char shortopts[] = "c:hF:g:P:p:St:u:v"; 54char shortopts[] = "c:hF:g:P:p:St:u:v";
@@ -127,9 +131,8 @@ is_numeric_str(char const *s)
127} 131}
128 132
129int 133int
130sig_name_to_str(char const *s) 134str_to_int(char const *s)
131{ 135{
132 if (is_numeric_str(s)) {
133 char *end; 136 char *end;
134 unsigned long n; 137 unsigned long n;
135 errno = 0; 138 errno = 0;
@@ -137,6 +140,13 @@ sig_name_to_str(char const *s)
137 if (errno || *end || n > UINT_MAX) 140 if (errno || *end || n > UINT_MAX)
138 return -1; 141 return -1;
139 return n; 142 return n;
143}
144
145int
146str_to_sig(char const *s)
147{
148 if (is_numeric_str(s)) {
149 return str_to_int(s);
140 } else { 150 } else {
141 struct sigdefn *sd; 151 struct sigdefn *sd;
142 152
@@ -183,8 +193,6 @@ char const *help_msg[] = {