2 * Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/types.h>
38 #include <sys/resource.h>
43 static int exitAfterLastSignal=0;
44 static int kilterDebug=0;
48 puts("Copyright (c) 2004 Teodor Sigaev <teodor@sigaev.ru>. All rights reserved.");
50 puts("kilter [-d] [-e] -SIGNAL [+]TIMEOUT [-SIGNAL [+]TIMEOUT [...]] COMMAND");
51 puts(" -d - debug mode");
52 puts(" -e - don't wait child exit after last signal sended");
53 puts(" +TIMEOUT - means related time to previous");
63 static SigName signalname[]={
70 /* { "EMT", SIGEMT }, */
89 { "VTALRM", SIGVTALRM },
91 { "WINCH", SIGWINCH },
92 /* { "INFO", SIGINFO }, */
99 name2sign(char *name) {
100 SigName *ptr = signalname;
103 if ( strncmp(name,"sig",3)==0 )
106 while( ptr && ptr->name ) {
107 if ( strcmp(name, ptr->name)==0 )
116 static char sbuf[16];
119 sign2name(unsigned int sign) {
120 SigName *ptr = signalname;
122 while( ptr && ptr->name ) {
123 if (sign==ptr->sign) {
125 strcpy(sbuf+3,ptr->name);
133 typedef struct ChildAction {
136 struct ChildAction *next;
139 #define PCL_WAITOPTION 0
141 #define PCL_OPTIONVAL 2
145 parsecmdline(int argn, char *argv[], ChildAction **ca) {
147 int state=PCL_WAITOPTION;
148 ChildAction *captr=NULL,*caend=NULL,*caprev=NULL;
152 for(i=0;i<argn;i++) {
156 if ( state == PCL_WAITOPTION ) {
161 } else if ( state == PCL_OPTION ) {
163 captr = t0malloc(sizeof(ChildAction));
171 captr->sign=atoi(ptr);
172 if ( !sign2name(captr->sign) )
173 tlog(TL_ALARM|TL_EXIT,"Unknown signal value: %d", captr->sign);
174 } else if (isalpha(*ptr)) {
175 if ( strcmp(ptr,"h")==0 ) {
177 } else if ( strcmp(ptr,"d")==0 ) {
179 state = PCL_WAITOPTION;
181 } else if ( strcmp(ptr,"e")==0 ) {
182 exitAfterLastSignal=1;
183 state = PCL_WAITOPTION;
186 captr = t0malloc(sizeof(ChildAction));
194 captr->sign=name2sign(ptr);
196 tlog(TL_ALARM|TL_EXIT,"Unknown signal name: %s", ptr);
199 tlog(TL_ALARM|TL_EXIT,"Unknown option: %s", ptr);
200 state = PCL_OPTIONVAL;
202 } else if ( state == PCL_OPTIONVAL ) {
203 tassert(captr!=NULL);
204 if (isdigit(*ptr) || *ptr=='+' ) {
205 captr->timeout = atoi(ptr);
206 if ( captr->timeout==0 )
207 tlog(TL_ALARM|TL_EXIT,"Wrong timeout: %s", ptr);
208 if (*ptr!='+' && caprev) {
209 if ( captr->timeout<=caprev->timeout )
210 tlog(TL_ALARM|TL_EXIT,"Wrong absolute timeout: %d", captr->timeout);
211 captr->timeout -= caprev->timeout;
213 state = PCL_WAITOPTION;
215 tlog(TL_ALARM|TL_EXIT,"Wrong timeout: %s", ptr);
218 tlog(TL_CRIT|TL_EXIT,"parsecmdline: Wrong state: %d", state);
228 static int wasSIGCHILD=0;
231 handlerSIGCHILD(int s) {
237 main(int argn, char *argv[]) {
238 ChildAction *ca,*ptr;
246 skip=parsecmdline(argn-1, argv+1, &ca)+1;
247 if ( skip==1 ) usage();
253 opentlog( TL_OPEN_STDERR, TL_DEBUG, NULL);
255 opentlog( TL_OPEN_SYSLOG, TL_INFO, NULL);
257 if ( signal(SIGCHLD, handlerSIGCHILD)==SIG_ERR )
258 tlog(TL_CRIT|TL_EXIT,"signal call failed: %s", strerror(errno));
261 if ( (child=fork()) == 0 ) {
263 if (execvp(*argv, argv)==-1)
264 tlog(TL_CRIT|TL_EXIT,"Exec error: %s", strerror(errno));
267 tlog(TL_CRIT|TL_EXIT,"Can't fork: %s", strerror(errno));
270 elapsedtime=(wasSIGCHILD) ? ca->timeout : sleep(ca->timeout);
271 if ( elapsedtime > 0 || wasSIGCHILD ) {
273 if ( waitpid(child, &status, WNOHANG) == -1 )
274 tlog(TL_CRIT|TL_EXIT,"waitpid for %d process failed: %s", child, strerror(errno));
275 if ( WIFEXITED(status) ) {
276 tlog(TL_INFO, "Child %d was exited with status %d", child, WEXITSTATUS(status));
278 } else if ( WIFSIGNALED(status) ) {
279 tlog(TL_INFO, "Child %d was exited with signal %d(%s)", child, WTERMSIG(status),
280 ( sign2name(WTERMSIG(status)) ) ? sign2name(WTERMSIG(status)) : "unknown");
283 ca->timeout = elapsedtime;
285 if ( kill(child, ca->sign) != 0 )
286 tlog(TL_CRIT|TL_EXIT,"kill %d process failed: %s", child, strerror(errno));
287 tlog(TL_INFO,"%s'ed process %d", sign2name(ca->sign), child);
294 if ( exitAfterLastSignal==0 ) {
295 if ( waitpid(child, &status, 0) == -1 )
296 tlog(TL_CRIT|TL_EXIT,"waitpid for %d process failed: %s", child, strerror(errno));
297 if ( WIFEXITED(status) )
298 tlog(TL_INFO, "Child %d was exited with status %d", child, WEXITSTATUS(status));
299 else if ( WIFSIGNALED(status) )
300 tlog(TL_INFO, "Child %d was exited with signal %d(%s)", child, WTERMSIG(status),
301 ( sign2name(WTERMSIG(status)) ) ? sign2name(WTERMSIG(status)) : "unknown");
303 tlog(TL_INFO, "Child %d wasn't exited",child);
305 tlog(TL_DEBUG, "Exit, don't wait a process %d", child);