Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 193 lines (136 sloc) 3.235 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
#!/usr/bin/perl -w

=head1 NAME

timeout - Run a command and kill it after the given period.

=cut


=head1 SYNOPSIS

General Options:

--timeout Specify the maximum execution time.
--help Show the help information for this script.
--verbose Show useful debugging information.

=cut


=head1 ABOUT

This command will allow you to run a subcommand and terminate
that after the given time.

You may specify the timeout period in either seconds, minutes and
seconds, or hours, minutes and seconds. For example:

=for example begin

# kill after 32 seconds
timeout -t 32 top

# kill after two minutes, five seconds
timeout -t 2:5 top

# kill after six hour, five minutes, and two seconds.
timeout -t 6:5:2 top

=for example end

The timeout period is mandatory and has no default.

=cut

=head1 AUTHOR

Steve
--
http://www.steve.org.uk/

=cut


=head1 LICENSE

Copyright (c) 2013 by Steve Kemp. All rights reserved.

This script is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

The LICENSE file contains the full text of the license.

=cut

use strict;
use warnings;

use Getopt::Long;
use Pod::Usage;



#
# Get the options, either defaults or from the command line.
#
my %config = parsedOptions();

#
# Ensure we have a timeotut
#
if ( !$config{ 'timeout' } )
{
    print "Please specify a timeout.\n";
    exit(2);
}

#
# If we're being verbose..
#
if ( $config{ 'verbose' } )
{
    print "Running command: " . join( " ", @ARGV ) . "\n";
    print "Max executiong time " . $config{ 'timeout' } . " seconds\n";

}

#
# Call the command we were given, with our timeout.
#
timed_system( $config{ 'timeout' }, @ARGV );

#
# All done.
#
exit(0);


sub timed_system
{
    my $time = shift;
    my $pid;

    local $SIG{ ALRM } = sub {
        kill 15, $pid or die "kill: $!";
        die "Timeout!";
    }; # Just SIGTERM.
    eval {
        $pid = fork;
        die "Fork failed: $!" unless defined $pid;
        unless ($pid)
        {
            exec @_;
            die "Exec failed: $!";
        }
        alarm $time;
        waitpid $pid => 0;
    };
    die $@ if $@ && $@ !~ /^Timeout!/;
}



=begin doc

Parse the command line options (minimal!)

=end doc

=cut

sub parsedOptions
{
    my %vars;

    exit
      if (
           !GetOptions( "help" => \$vars{ 'help' },
                        "timeout=s" => \$vars{ 'timeout' },
                        "verbose" => \$vars{ 'verbose' } ) );

    pod2usage(1) if ( $vars{ 'help' } );

    if ( !$vars{ 'timeout' } )
    {
        print "Please specify a timeout\n";
        exit(2);
    }


    #
    # HH:MM:SS
    #
    if ( $vars{ 'timeout' } =~ /^([0-9]+):([0-9]+):([0-9]+)$/ )
    {
        my $sec = $3 + ( 60 * $2 ) + ( 60 * 60 * $1 );
        $vars{ 'timeout' } = $sec;
    }
    elsif ( $vars{ 'timeout' } =~ /^([0-9]+):([0-9]+)$/ )
    {

        #
        # MM:SS
        #
        my $sec = $2 + ( 60 * $1 );
        $vars{ 'timeout' } = $sec;
    }
    elsif ( $vars{ 'timeout' } =~ /^([0-9]+)$/ )
    {

        #
        # SS
        #
    }
    else
    {
        print "Invalid timeout specification\n";
        exit(2);
    }

    return (%vars);

}
Something went wrong with that request. Please try again.