Unix Programming - alarm() functionality from the shell

This is Interesting: Free IT Magazines  
Home > Archive > Unix Programming > September 2005 > alarm() functionality from the shell





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author alarm() functionality from the shell
Martin Carpenter

2005-09-16, 7:48 am


Problem: I have a command that runs from the shell, from which I need to
obtain stdout and stderr, and retain the return code ($?). Sometimes, this
command will hang indefinitely, and therefore I'd like to be able to kill it
after a specified time period. (Further detail at the foot of this post).

Given that I need to keep the return code, I don't believe that I can put
the command into the background or use coprocesses (ksh/bash), unless I do
some hackery by writing $? to a temporary file or similar. Ideally, what I'd
like would be a command-line "timeout" utility:

out=`to 180 foo 2>&1`
rc=$?

for a timeout of three minutes. Is there such a thing?

I found some old posts from David Korn, applicable to ksh93, which is almost
what I need, but I only have 88i (Solaris 8):


https://mailman.research.att.com/pi...3q2/000641.html

I also found Michael Wang's "submit":

http://www.unixlabplus.com/unix-prog/submit/submit

which seems a little excessive for my needs (I don't like all of the writing
to temporary files - I'd really like something that I can drop in).

I've written a 200 line C program, a slightly anaemic version of Wang's
"submit", to do what I want, in which I fork(), execvp(), alarm(), waitpid()
and kill() as necessary. This seems fine... but is there a better way?

All suggestions to port JCL/JES will be roundly ignored ;-)





FWIW, what I'm really doing here: running Solaris' smpatch(1M) via ssh.
E.g.,

patches=`ssh -i$idfile root@$machine smpatch analyze 2>&1`

Sometimes, this will hang... indefinitely... I've sought a timeout feature
in ssh, but only found the KeepAlive options.



alexs

2005-09-16, 7:48 am


Martin Carpenter wrote:
> Problem: I have a command that runs from the shell, from which I need to
> obtain stdout and stderr, and retain the return code ($?). Sometimes, this
> command will hang indefinitely, and therefore I'd like to be able to kill it
> after a specified time period. (Further detail at the foot of this post).
>
> Given that I need to keep the return code, I don't believe that I can put
> the command into the background or use coprocesses (ksh/bash), unless I do
> some hackery by writing $? to a temporary file or similar. Ideally, what I'd
> like would be a command-line "timeout" utility:
>
> out=`to 180 foo 2>&1`
> rc=$?
>
> for a timeout of three minutes. Is there such a thing?
>
> I found some old posts from David Korn, applicable to ksh93, which is almost
> what I need, but I only have 88i (Solaris 8):
>
>
> https://mailman.research.att.com/pi...3q2/000641.html
>
> I also found Michael Wang's "submit":
>
> http://www.unixlabplus.com/unix-prog/submit/submit
>
> which seems a little excessive for my needs (I don't like all of the writing
> to temporary files - I'd really like something that I can drop in).
>
> I've written a 200 line C program, a slightly anaemic version of Wang's
> "submit", to do what I want, in which I fork(), execvp(), alarm(), waitpid()
> and kill() as necessary. This seems fine... but is there a better way?
>
> All suggestions to port JCL/JES will be roundly ignored ;-)
>
>
>
>
>
> FWIW, what I'm really doing here: running Solaris' smpatch(1M) via ssh.
> E.g.,
>
> patches=`ssh -i$idfile root@$machine smpatch analyze 2>&1`
>
> Sometimes, this will hang... indefinitely... I've sought a timeout feature
> in ssh, but only found the KeepAlive options.


Hi
Sorry if I've misunderstood your question, but if you want to
automatically kill the process after 3 minutes you could try something
like:

prog > out 2> err & ( sleep 180; kill $! )

Im guessing $? will no longer work in that scenario though, so you need
to assign it somehow (but im not sure how to do that!)

Martin Carpenter

2005-09-16, 6:01 pm


"alexs" <spam@alexs.org> wrote:

> Sorry if I've misunderstood your question,


No, I think you got it.


> you could try something like:
>
> prog > out 2> err & ( sleep 180; kill $! )
>
> Im guessing $? will no longer work in that scenario
> though, so you need to assign it somewho (but im not
> sure how to do that!)


Yes, that's exactly my problem :-/ As I said in my intro, I don't think it's
possible to capture $? if you start the process in the background [without
resorting to zany hackery].



alexs

2005-09-16, 6:01 pm

> Yes, that's exactly my problem :-/ As I said in my intro,
>I don't think it's possible to capture $? if you start the process
>in the background [without resorting to zany hackery].


I think zany hackery is order of the day:

http://groups.google.com/group/comp...eb442a548c7a0b3

Altho that looks a little excessive. Maybe something like:

( prog > out 2> err; echo $? > rc ) & ( sleep 2; kill $! )

If rc exists, the prog terminated normally and contains the code. else
it was killed.

Chuck Dillon

2005-09-16, 6:01 pm

Martin Carpenter wrote:

>
> I found some old posts from David Korn, applicable to ksh93, which is almost
> what I need, but I only have 88i (Solaris 8):


Use dtksh on Solaris 8 to get ksh93 compatibility...

-- ced


--
Chuck Dillon
Senior Software Engineer
NimbleGen Systems Inc.
Heiner Steven

2005-09-16, 6:01 pm

Martin Carpenter wrote:
> Problem: I have a command that runs from the shell, from which I need to
> obtain stdout and stderr, and retain the return code ($?). Sometimes, this
> command will hang indefinitely, and therefore I'd like to be able to kill it
> after a specified time period. (Further detail at the foot of this post).


http://www.shelldorado.com/scripts/cmds/timeout

Heiner
--
___ _
/ __| |_ _____ _____ _ _ Heiner STEVEN <heiner.steven@nexgo.de>
\__ \ _/ -_) V / -_) ' \ Shell Script Programmers: visit
|___/\__\___|\_/\___|_||_| http://www.shelldorado.com/
William Ahern

2005-09-16, 6:01 pm

Martin Carpenter <mcarpenter@free.fr> wrote:
> Problem: I have a command that runs from the shell, from which I need to
> obtain stdout and stderr, and retain the return code ($?). Sometimes, this
> command will hang indefinitely, and therefore I'd like to be able to kill it
> after a specified time period. (Further detail at the foot of this post).


> Given that I need to keep the return code, I don't believe that I can put
> the command into the background or use coprocesses (ksh/bash), unless I do
> some hackery by writing $? to a temporary file or similar. Ideally, what I'd
> like would be a command-line "timeout" utility:
>
> out=`to 180 foo 2>&1`
> rc=$?
>
> for a timeout of three minutes. Is there such a thing?
>
> I found some old posts from David Korn, applicable to ksh93, which is almost
> what I need, but I only have 88i (Solaris 8):


Personally I don't think using temporary files is hackery. You're simply
doing IPC, something the Unix filesystem was intended to be used for. I use
the following functions in several regression test scripts, and I'm not
afraid to create temporary named pipes or files to store return codes. I'm
using bash, though. I don't know how portable the waitpid implementation is.

In the past I've also written long pipelines where I saved several error
codes and stderr output to intermediate temporary files and never felt
dirty.


#
# Usage: tempnam [<pretty name>]
#
# TMPFILE=$(tempnam "example")
#
function tempnam {
if [ -z "$TMPDIR" ]; then
TMPDIR=/tmp
fi

echo ${TMPDIR}/${1}$(hexdump -n8 -e '"%02x"' /dev/urandom)

return $?
} # tempnam


#
# Usage: waitpid <pid> <timeout>
#
# Return value is the exit value of the process with pid <pid>. A return
# value of 127 means that there was no process <pid>, and a value of 128
# signals that the operation timed out.
#
function waitpid {
waitpid_PID=$1
waitpid_TIMEOUT=$2
waitpid_TIMEDOUT=0

trap 'echo "$PROGNAME: caught SIGALRM waiting for pid $waitpid_PID" >&2; waitpid_TIMEDOUT=1' 14

while [ true ]; do sleep $waitpid_TIMEOUT && kill -14 $$; done &

waitpid_ALARM=$!

wait $waitpid_PID 2>/dev/null

waitpid_STATUS=$?

kill -15 $waitpid_ALARM

wait $waitpid_ALARM 2>/dev/null

if [ $waitpid_TIMEDOUT -eq 1 ]; then
waitpid_STATUS=128
fi

return $waitpid_STATUS
} # waitpid

HK

2005-09-19, 7:50 am

Martin Carpenter wrote:
> Problem: I have a command that runs from the shell, from which I need to
> obtain stdout and stderr, and retain the return code ($?). Sometimes, this
> command will hang indefinitely, and therefore I'd like to be able to kill it
> after a specified time period. (Further detail at the foot of this post).


Just last Friday I had the same problem and for some reason did
not find this thread and the proposed solution by William Ahern.
I came up with my own solution. I dare to say it is better
commented :-). Tried it with bash, don't know if it works
with just an old sh. Take your pick:

Harald.

#!/bin/sh
########################################
################################
# Runs a command and kills it, if necessary, after a given timeout. If
# the command finishes earlier, this script also finishes earlier.
#
# Parameter:
# $1 - timeout in seconds
# $2 ... - command to run and its parameters and redirections
#
# Exit code:
# 0 - all went well
# 0<c<127 - job exited with this exit code
# >=127 - job was preempted
#
# NOTE: Don't put this into a shell function. It may not work in
# circumstances where the shell using it runs several jobs in the
# background.
#
# (C) Harald Kirsch (Harald at pifpafpuf dontmissthedot de)
########################################
################################
#set -x

# enable job control
set -m

# Fetch the timeout from $1 and execute all other arguments in the
# background.
timeout="$1"; shift
eval "$@" &

# Arrange for a SIGUSR1 to kill the above job. We do not use a pid
($!),
# because it might be wrong. The %1, however, can not be mistaken.
trap 'kill -9 %1 1>/dev/null 2>&1' SIGUSR1

# Arrange for SIGUSR1 to be send to us after the timeout in order to
# trigger the above trap. The $$ uniquely identifies this very
# script, because we make sure not to exit before this timeout job
exits.
(sleep $timeout; kill -SIGUSR1 $$ 1>/dev/null 2>&1) &

# Wait for the subprocess that does the work to exit. It either exits
# because it is finished or because it was killed prematurely. By
# a %1 instead of a pid it even works if the process has already
exited.
wait %1
result=$?

# If the subprocess finished in time, the timeout background process
# may still be running, targeting the pid of this very script. Before
# we exit, we send it home.
kill -9 %2 1>/dev/null 2>&1

# make the exit code available
exit $result

Martin Carpenter

2005-09-20, 7:49 am


"Chuck Dillon" <spam@nimblegen.com> wrote:

> Use dtksh on Solaris 8 to get ksh93 compatibility...


Thanks. And I don't even need dt for this



Martin Carpenter

2005-09-20, 7:49 am


"Heiner Steven" <heiner.steven@nexgo.de> wrote:

> http://www.shelldorado.com/scripts/cmds/timeout


Thank you for that - it's pretty much exactly what I was asking for. I have
a couple of tiny niggles:


1. Despite this line:

exec >/dev/null 0<&1 2>&1

under Linux 2.6.13, bash 2.05b.0(1), I still get:

Terminated

back at the prompt if the command lasts longer than the timeout. (Not a big
deal).


2. I chose a different sequence of signals for my C version:

You have: TERM; HUP; KILL

I chose: TERM; ABRT; KILL

I'd be slightly wary of HUP causing the process to do something odd, such as
respawn itself, after which the KILL might go a little awry.





Martin Carpenter

2005-09-20, 7:49 am


"William Ahern" <william@wilbur.25thandClement.com> wrote:

> Personally I don't think using temporary files is hackery.

....
> echo ${TMPDIR}/${1}$(hexdump -n8 -e '"%02x"' /dev/urandom)


:-)

Thanks for the reply (as well as the smile!).


> I don't know how portable the waitpid implementation is.


Reasonably so, I think. wait is available in sh, ksh and csh as well as
bash, although the csh flavour doesn't seem to take an argument.


Thanks to all who replied - I think we've succesfully beaten this small
question to death.



Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com