[Bug-wget] Timeouts too long?

Paul McFerrin pmcferrin@columbus.rr.com
Sat Oct 3 07:20:00 GMT 2009


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



More information about the Cygwin mailing list