5 ## (c) 2004-2007 Piotr Roszatycki <dexter@debian.org>, GPL
7 ## $Id: timeout.pl 4 2007-06-19 11:58:08Z piotr.roszatycki $
11 timeout - Run command with bounded time.
25 B<timeout> executes a command and imposes an elapsed time limit. When the
26 time limit is reached, B<timeout> sends a predefined signal to the target
39 ##############################################################################
41 ## Default values for constant variables
51 ##############################################################################
55 my @signals = qw< HUP INT QUIT TERM SEGV PIPE XCPU XFSZ ALRM >;
58 ##############################################################################
60 ## Signal to send after timeout. Default is KILL.
66 ## Command to execute as array of arguments
69 ## PID for fork function
72 ## PID for wait function
76 ##############################################################################
80 ## Prints usage message.
83 # Lazy loading for Pod::Usage
84 eval 'use Pod::Usage;';
93 ## Prints help message.
96 # Lazy loading for Pod::Usage
97 eval 'use Pod::Usage;';
100 pod2usage(-verbose=>1, -message=>"$NAME $VERSION\n");
104 ## signal_handler($sig)
106 ## Handler for signals to clean up child processes
108 sub signal_handler($) {
110 if ($sig eq 'ALRM') {
111 printf STDERR "Timeout: aborting ``%s'' with SIG%s\n", join(' ', @command), $signal;
113 printf STDERR "Got signal SIG%s: aborting command ``%s'' with signal SIG%s\n", $sig, join(' ', @command), $signal;
115 kill $signal, -$child_pid;
120 ##############################################################################
126 ## Parse command line arguments
128 if ($arg =~ /^-(.*)$/) {
130 if ($arg eq '-h' || $arg eq '--help') {
132 } elsif ($opt =~ /^[A-Z0-9]+$/) {
133 if ($opt =~ /^\d+/) {
134 # Convert numeric signal to name by using the perl interpreter's
136 usage() unless defined $Config{sig_name};
137 $signal = (split(' ', $Config{sig_name}))[$opt];
148 usage() if @ARGV < 2;
152 usage() unless $arg =~ /^\d+$/;
162 if (! defined($child_pid = fork)) {
163 die "Could not fork: $!\n";
165 } elsif ($child_pid == 0) {
168 ## Set new process group
172 exec @command or die "Can not run command `" . join(' ', @command) . "': $!\n";
177 ## Set the handle for signals
178 foreach my $sig (@signals) {
179 $SIG{$sig} = \&signal_handler;
186 while (($pid = wait) != -1 && $pid != $child_pid) {}
189 exit ($pid == $child_pid ? $? >> 8 : -1);
194 B<timeout> executes a command and imposes an elapsed time limit.
195 The command is run in a separate POSIX process group so that the
196 right thing happens with commands that spawn child processes.
204 Specify an optional signal name to send to the controlled process. By default,
205 B<timeout> sends B<KILL>, which cannot be caught or ignored.
209 The elapsed time limit after which the command is terminated.
213 The command to be executed.
223 Return code from called command.
227 Internal error. No return code could be fetched.
231 The timeout was occured.
259 =head1 SCRIPT CATEGORIES
261 UNIX/System_administration
265 Piotr Roszatycki E<lt>dexter@debian.orgE<gt>
269 Copyright 2004-2007 by Piotr Roszatycki E<lt>dexter@debian.orgE<gt>.
271 Inspired by timeout.c that is part of The Coroner's Toolkit.
273 All rights reserved. This program is free software; you can redistribute it
274 and/or modify it under the terms of the GNU General Public License, the