diff options
-rw-r--r-- | Makefile.am | 11 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/com_start.c | 10 | ||||
-rw-r--r-- | src/genrc.8 | 58 | ||||
-rw-r--r-- | src/genrc.c | 41 | ||||
-rw-r--r-- | src/genrc.h | 10 | ||||
-rw-r--r-- | src/sentinel.c | 190 |
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 @@ | |||
1 | SUBDIRS = grecs src | 1 | SUBDIRS = grecs src |
2 | dist: ChangeLog | ||
3 | .PHONY: ChangeLog | ||
4 | ChangeLog: | ||
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 | ||
17 | AC_PREREQ([2.69]) | 17 | AC_PREREQ([2.69]) |
18 | AC_INIT([genrc], [1.0], [gray@gnu.org]) | 18 | AC_INIT([genrc], [1.0.90], [gray@gnu.org]) |
19 | AC_CONFIG_SRCDIR([src/genrc.c]) | 19 | AC_CONFIG_SRCDIR([src/genrc.c]) |
20 | AC_CONFIG_HEADERS([config.h]) | 20 | AC_CONFIG_HEADERS([config.h]) |
21 | AM_INIT_AUTOMAKE([1.11 foreign silent-rules]) | 21 | AM_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. |
38 | AC_CHECK_FUNCS([getdtablesize]) | 38 | AC_CHECK_FUNCS([getdtablesize]) |
39 | 39 | ||
40 | GRECS_SETUP(grecs, [all-parsers]) | 40 | GRECS_SETUP(grecs, [all-parsers git2chg]) |
41 | 41 | ||
42 | AM_CONDITIONAL([COND_PCRE], | 42 | AM_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 |
18 | genrc \- generic system initialization script helper | 18 | genrc \- 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 | |||
101 | in \fIFILE\fR. The file will be unlinked after the subsidiary command | 103 | in \fIFILE\fR. The file will be unlinked after the subsidiary command |
102 | terminates. Unless the \fB\-\-pid\-from\fR option is given, | 104 | terminates. 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 | ||
107 | In sentinel mode, it is possible to restart the program if it | ||
108 | terminates with a specific exit code or on a specific signal. This is | ||
109 | controlled by the \fB\-\-restart\-on\-exit\fR and | ||
110 | \fB\-\-restart\-on\-signal\fR options. Use this feature to ensure the | ||
111 | service provided by the program won't get terminated because of | ||
112 | hitting a bug or encountering an unforeseen external condition. For | ||
113 | example, the following two options will ensure that the program will | ||
114 | be terminated only if it exits with status 0 or it is terminated by | ||
115 | SIGTERM or SIGQUIT signal: | ||
116 | .EX | ||
117 | --restart-on-exit='!0' --restart-on-signal='!TERM,QUIT' | ||
118 | .EE | ||
119 | .PP | ||
120 | If restarts are requested, \fBgenrc\fR will control how often it has | ||
121 | to restart the program using the same algorithm as | ||
122 | .B init (8). | ||
123 | Namely, if the program is restarted more than 10 times within two | ||
124 | minutes, \fBgenrc\fR will disable subsequent restarts for the next | ||
125 | 5 minutes. If the \fB\-\-create\-pidfile\fR option was used, the | ||
126 | PID of the controlling \fBgenrc\fR process will be stored in the | ||
127 | file during that interval. If the \fBSIGHUP\fR signal is delivered | ||
128 | during the sleep interval, the sleep will be broken prematurely and | ||
129 | the program restarted again. | ||
104 | .SS status | 130 | .SS status |
105 | In \fBstatus\fR mode \fBgenrc\fR verifies if the \fICOMMAND\fR is | 131 | In \fBstatus\fR mode \fBgenrc\fR verifies if the \fICOMMAND\fR is |
106 | already running and outputs its status on the standard output. To this | 132 | already 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 |
189 | Where to look for PIDs of the running programs. | 215 | Where 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...] | ||
218 | This option takes effect when used together with | ||
219 | \fB\-\-sentinel\fR. If the program terminates with one of status | ||
220 | codes listed as the argument to this option, it will be immediately | ||
221 | restarted. The exclamation mark at the start of the list inverts the | ||
222 | set, e.g. \fB\-\-restart\-on\-exit='!0,1'\fR means restart unless the | ||
223 | program 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...] | ||
227 | This option takes effect when used together with | ||
228 | \fB\-\-sentinel\fR. If the program terminates due to receiving one of | ||
229 | the 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). | ||
232 | The \fBSIG\fR prefix can be omitted from the signal name. Names are | ||
233 | case-insensitive. Thus, \fB1\fR, \fBHUP\fR, \fBSIGHUP\fR, and | ||
234 | \fBsighup\fR all stand for the same signal. | ||
235 | .sp | ||
236 | The exclamation mark at the start of the list complements the signal | ||
237 | set, so that e.g. \fB\-\-restart\-on\-signal='!TERM,QUIT,INT'\fR will | ||
238 | restart 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 |
193 | terminal, run it and act as a sentinel. | 242 | terminal, start it and run in background until it terminates. The |
243 | program's stdout and stderr are sent to the syslog facility | ||
244 | \fBdaemon\fR, priorities \fBinfo\fR and \fBerr\fR, correspondingly. | ||
245 | |||
246 | See 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 |
196 | Signal to send on reload (default: \fBSIGHUP\fR). Setting it to 0 is | 250 | Signal 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 | ||
31 | struct option longopts[] = { | 33 | struct 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 | }; |
50 | char shortopts[] = "c:hF:g:P:p:St:u:v"; | 54 | char shortopts[] = "c:hF:g:P:p:St:u:v"; |
@@ -127,9 +131,8 @@ is_numeric_str(char const *s) | |||
127 | } | 131 | } |
128 | 132 | ||
129 | int | 133 | int |
130 | sig_name_to_str(char const *s) | 134 | str_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 | |||
145 | int | ||
146 | str_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[] = { | |||
183 | "", | 193 | "", |
184 | " -t, --timeout=SECONDS time to wait for the program to start up or", | 194 | " -t, --timeout=SECONDS time to wait for the program to start up or", |
185 | " terminate", | 195 | " terminate", |
186 | " --sentinel PROGRAM runs in foreground; disconnect from the", | ||
187 | " controlling terminal, run it and act as a sentinel", | ||
188 | " -P, --pid-from=SOURCE where to look for PIDs of the running programs", |