Mail Archives: cygwin/2009/10/03/03:20:20
I've written a small & nifty program that will terminate a command line
after N seconds. It was written nearly 18 years ago and has served me
very well. I'm not saying that you always live with bad program design,
but having a solution is quite nice. The usage is:
tcmd [-s {sig#}] [-t secs] [-x] cmd args ...
Ejoy. This one is on me.
Here is the source, compile for yourselves.
----------------------------------------------------------------
#ident "@(#)tcmd.c - NCP 1.1 08/28/91 - PEM"
/*
Execute the command line and terminate if it does
not complete within a specified time limit.
Usage:
tcmd [-s signal] [-t secs] [-x] cmd args ...
Upon timeout, signal "signal" (default is SIGTERM) is
sent to all children in child process group.
Exit codes:
0 = success
254 = timed-out
253 = execvp() failed for cmd
252 = fork() failed
251 = usage() exit
128-146 = cmd terminated with signal 'sig - 127'
all_others = exit status of "cmd"
Author: Paul E. McFerrin, 55821, Aug 27, 1991
*/
#include <stdio.h>
#include <signal.h>
#include <errno.h>
extern int errno, optind;
extern char *optarg;
int tlimit; /* allowed time limit */
int ksig; /* signal to use to terminate */
int timeout(); /* alarm clock signal catcher */
int timedout; /* > 0 if execution timed out */
int childpid; /* pid of chil process */
char *cmd; /* the name of our process, argv[0] */
main( argc, argv )
int argc;
char *argv[];
{
int xflag, opt, i, status, ws, myuid;
myuid = getuid(); /* remember our real-uid */
cmd = *argv; /* save our name is global area */
tlimit = 30; /* default 30 seconds */
ksig = SIGTERM; /* default terminate signal */
xflag=0;
timedout = 0;
if( argc <= 1 ) usage(); /* no return */
while ( (opt = getopt(argc, argv, "s:t:x")) != EOF ) {
switch (opt) {
case 'x' :
xflag = 1;
break;
case 't' :
tlimit = atoi(optarg);
if( tlimit <= 0) {
fprintf(stderr, "%s: time limit must be
> 0\n",
cmd);
usage();
}
break;
case 's' :
ksig = atoi(optarg);
if( ksig < 1 || ksig > SIGUSR2 ) {
fprintf(stderr, "%s: bad signal number:
%s\n",
cmd, optarg);
usage();
}
break;
default:
usage();
}
}
if( xflag ) {
fprintf(stderr, "+ ");
for(i=optind; i<argc; i++) {
fprintf(stderr, "%s ", argv[i]);
}
fprintf(stderr, "\n");
}
childpid = fork();
switch (childpid) {
case -1 :
fprintf(stderr, "%s: can not fork()\n", cmd);
perror("");
exit(252);
break;
case 0 : /* child */
break;
default : /* parent */
signal(SIGALRM, timeout);
signal(SIGHUP, timeout);
signal(SIGINT, timeout);
signal(SIGTERM, timeout);
signal(SIGQUIT, timeout);
signal(SIGPIPE, timeout);
signal(SIGUSR1, timeout);
signal(SIGUSR2, timeout);
alarm(tlimit);
do {
ws = wait(&status);
} while ( (ws != childpid) && (ws < 0 && errno == EINTR) );
alarm(0);
if( timedout == SIGALRM ) {
if( xflag ) fprintf(stderr,
"%s: Command timed-out\n", cmd);
exit(254);
}
exit( (status & 255) ? status + 127 : status >> 8);
break;
}
/*
* At this point, the child is executing this code. Become
* a process group leader to that our parent can kill all
* of our processes not known by our parent.
*/
setuid(myuid); /* give up root access */
setpgrp();
execvp( argv[optind], &argv[optind] );
fprintf( stderr, "%s: '%s' - not executed. ", cmd, argv[optind] );
perror( "" );
exit( 253 );
}
usage()
{
fprintf( stderr, "Usage: %s [-t secs] [-s signal] [-x] command
[ arg ..
. ]\n", cmd );
exit(251);
}
/*
* signal trap handler. If signal receive is SIGALRM then
* we send "ksig". All other signals are sent as is to the
* child process group leader. This permits hangups,
* interrupts, and quits, .... to be received by the new
* process group.
*/
timeout(sig)
int sig;
{
timedout = sig == SIGALRM ? ksig : sig;
if( childpid < 3 ) return; /* fail safe protection */
kill(-childpid, timedout);
return;
}
- Paul
Micah Cowan wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> With Wget's default of 20 tries, and 900-second timeouts, the following
> bug report notes that Wget can sit on a download attempt for a total of
> 2.5 hours (actually, my math puts it at 5).
>
> https://savannah.gnu.org/bugs/index.php?27141
>
> Obviously, we can adjust these settings in wgetrc, but should that be
> necessary? Are people happy with the current timeout settings, and if
> not, what are some proposed better values?
>
> - --
> Micah J. Cowan
> Programmer, musician, typesetting enthusiast, gamer.
> Maintainer of GNU Wget and GNU Teseq
> http://micah.cowan.name/
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.9 (GNU/Linux)
> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
>
> iEYEARECAAYFAkrGRlcACgkQ7M8hyUobTrG18gCfTHKEcrdXrG/An2g5IM9ZPyTK
> uK0An1vJXqsSF98X8vO7MRsR+f2197Tf
> =SJkz
> -----END PGP SIGNATURE-----
>
>
>
>
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
- Raw text -