[comp.unix.shell] Getting HUPed

kiyun@mirror.tmc.com (KiYun Roe) (03/20/91)

I've been encountering a problem with some of my shell scripts and
SIGHUP that I don't understand.  I run a lot of scripts overnight.
These are usually named xsomething.sh.  They may generate temporary
files which I want to clean up.  Here's what I want to use to start
them off:

    #! /bin/sh

    type=`expr $0 : '.*x\(.*\)\.sh'`
    exec > x$type.log 2>&1

    trap "rm -f /tmp/p$$.* ; exit" 0 1 2 13 15

This automatically redirects stdout and stderr to a log file and cleans
up some temp files on exit or certain signals.

The problem is that I log back in the next day and find out that the
script has long finished its real work, but it's forking like crazy,
trying to do the rm.  I guess each time it tries to do the rm it
receives a SIGHUP which forks another subshell to do the rm.

I don't understand this.  First, I thought that the -f flag would keep
rm quiet, so I don't understand why it has to interact with the
terminal at all.  Second, I thought the exec > .. 2>&1 would redirect
all output, but it doesn't.  If I do "xsomething.sh >& save.out &"
before I log out (I use tcsh), when I log back in save.out contains a
Hangup message for each subshell and xsomething.log (the automatic log
file) doesn't contain anything.  Finally, most of the times there are
temporary files to cleanup, so the globbing and rm should work
normally.  I can't figure out whether this is a bug in our version of
sh or whether things are "supposed" to work this way.

----
KiYun Roe	kiyun@mirror.TMC.COM
Mirror Systems	2067 Massachusetts Avenue  Cambridge, MA  02140
Telephone:	617-661-0777

tif@doorstop.austin.ibm.com (Paul Chamberlain) (03/21/91)

In article <53767@mirror.tmc.com> kiyun@mirror.tmc.com (KiYun Roe) writes:
>    trap "rm -f /tmp/p$$.* ; exit" 0 1 2 13 15
>
>... but it's forking like crazy,

Isn't this when you have to do this:

	trap "rm -f /tmp/p$$.* ; trap 0; exit" 0 1 2 13 15

If 0 is trapped when you try to exit, you trap, and so on ...

Paul Chamberlain | I do NOT speak for IBM.          IBM VNET: PAULCC AT AUSTIN
512/838-9748     | ...!cs.utexas.edu!ibmchs!auschs!doorstop.austin.ibm.com!tif

]) (03/22/91)

Here's how I handle tempfiles...

Assume I need two of them and that I'll use $$ as part of the filename
to allow for multiple copies of the script to run simultaneously.

--- start junk (a sh or ksh script) ---
:
# Make and load a couple of temp files and trap for them to
# be removed automagically on exit.
TEMP1=/usr/tmp/junk1.$$
TEMP2=/usr/tmp/junk2.$$
trap 'rm -f $TEMP1 $TEMP2' 0 1 2 3 14 15

ls > $TEMP1 2>$TEMP2

echo "number of files: \c"; wc -l < $TEMP1
[ -s $TEMP2 ] && echo "number of error messages: \c"; wc -l < $TEMP2
--- end junk (a sh or ksh script) ---

The thing about the trapped command is that you don't need to issue
an exit from within the command-series.  The sh (or ksh) will simply
execute the command on its merry way out.

Don't use $$ in filenames of tempfiles without loading the resulting
filename into a simple variable.  $$ changes value when you fork a
subshell, for instance.  This *might* be what led (combined with the
exit in the trapped command-series) to the cascade of processes.

...Kris
-- 
Kristopher Stephens, | (408-746-6047) | krs@uts.amdahl.com | KC6DFS
Amdahl Corporation   |                |                    |
     [The opinions expressed above are mine, solely, and do not    ]
     [necessarily reflect the opinions or policies of Amdahl Corp. ]

kiyun@mirror.tmc.com (KiYun Roe) (03/26/91)

Thanks to everyone who tried to help me with my problem.  I determined
that the problem was in a call to isatty(0) inside /bin/rm.  To recap,
I have a bunch of shell scripts that start off something like this:

    #! /bin/sh

    type=`expr $0 : '.*x\(.*\)\.sh'`
    exec > x$type.log 2>&1

    trap "rm -f /tmp/p$$.* ; exit" 0 1 2 13 15

If I start one of these off in the background and log back on, I find
that it has gone into an infinite SIGHUP loop.  Apparently, what is
happening is that /bin/rm calls isatty(0) which leads to a SIGHUP,
which the shell traps, which calls /bin/rm, etc.  I'm guessing at this,
but I compiled a version of rm without the isatty(0) call and the
script worked fine.  (BTW, /bin/rm calls isatty to automatically set
the -f option if the input isn't a terminal.  I don't know if that's
standard or unique to Pyramid Unix.)

Some of you suggested that executing exit inside a trap handler would
cause an infinite loop.  Well, it doesn't on my machine, and I can't
see how it would generate Hangup messages which was the most perplexing
part of my problem.  However, I would be interested in knowing if it
really does cause an infinite exit loop under a different version of
Unix.

Anyway, here's the prolog I'm using for this particular class of
scripts now:

    #! /bin/sh

    type=`expr $0 : '.*x\(.*\)\.sh'`
    exec > x$type.log 2>&1

    trap "exec rm -f /usr/tmp/p$$.* < /dev/null" 0 1 2 13 15

I hope the exec will take care of any infinite loops, and redirecting
stdin to /dev/null should keep rm out of trouble.

kiyun@mirror.tmc.com (KiYun Roe) (03/26/91)

In article <d2wB01ev46cG00@amdahl.uts.amdahl.com> krs@amdahl.uts.amdahl.com (Kris Stephens [Hail Eris!]) writes:
>The thing about the trapped command is that you don't need to issue
>an exit from within the command-series.  The sh (or ksh) will simply
>execute the command on its merry way out.

My experience is that if I don't put an exit within the trap command
series, the script doesn't exit when it receives a signal.  It just
cleans up the temp files and then continues to execute.  I use a trap
handler so that I can clean-up before aborting on a signal, not to keep
the signal from aborting the script.

So, the issue is whether an exit in the trap 0 handler will cause any
harm (loop), but I've never had any problem with that.

-- 
----
KiYun Roe	kiyun@mirror.TMC.COM
Mirror Systems	2067 Massachusetts Avenue  Cambridge, MA  02140
Telephone:	617-661-0777

]) (03/27/91)

In article <53902@mirror.tmc.com> kiyun@mirror.UUCP (KiYun Roe) writes:
>In article <d2wB01ev46cG00@amdahl.uts.amdahl.com> krs@amdahl.uts.amdahl.com (Kris Stephens [Hail Eris!]) writes:
>>The thing about the trapped command is that you don't need to issue
>>an exit from within the command-series.  The sh (or ksh) will simply
>>execute the command on its merry way out.
>
>My experience is that if I don't put an exit within the trap command
>series, the script doesn't exit when it receives a signal.  It just
>cleans up the temp files and then continues to execute.  I use a trap
>handler so that I can clean-up before aborting on a signal, not to keep
>the signal from aborting the script.
>
>So, the issue is whether an exit in the trap 0 handler will cause any
>harm (loop), but I've never had any problem with that.

Okay, it ain't clear to me from reading ksh.1.  If I....

	trap 'echo "signalled"' 0 1 2 3 14 15

in a script (not in a function of the script), it *is* clear that 0
will echo "signalled" and exit.  It's not clear to me what will happen
on signals 1 2 3 14 15, though.

Should this work to (a) echo "signalled" and (b) exit, without recursion:

	trap 'echo "signalled"; exit' 0 1 2 3 14 15

where by "without recursion" I mean successive firings on the trap?
What would the exit code be if the trap is taken by execution of an
'exit 1' in the script?  Would it be 0 because the echo was a success?
Should I, instead, do:

	trap 'echo "signalled"' 0
	trap 'echo "signalled"; exit' 1 2 3 14 15

to avoid a possible recursion and protect the exit code?

Anyone *really* know?
...Kris
-- 
Kristopher Stephens, | (408-746-6047) | krs@uts.amdahl.com | KC6DFS
Amdahl Corporation   |                |                    |
     [The opinions expressed above are mine, solely, and do not    ]
     [necessarily reflect the opinions or policies of Amdahl Corp. ]

lml@cbnews.att.com (l.mark.larsen) (03/30/91)

In article <c8C901q64a9q00@amdahl.uts.amdahl.com> krs@amdahl.uts.amdahl.com (Kris Stephens [Hail Eris!]) writes:
# In article <53902@mirror.tmc.com> kiyun@mirror.UUCP (KiYun Roe) writes:
# >In article <d2wB01ev46cG00@amdahl.uts.amdahl.com> krs@amdahl.uts.amdahl.com (Kris Stephens [Hail Eris!]) writes:
# >>The thing about the trapped command is that you don't need to issue
# >>an exit from within the command-series.  The sh (or ksh) will simply
# >>execute the command on its merry way out.

This is only true of the 0 (aka EXIT in ksh) "interrupt" - as KiYun pointed out
in his reply.

# Okay, it ain't clear to me from reading ksh.1.  If I....
# 
# 	trap 'echo "signalled"' 0 1 2 3 14 15
# 
# in a script (not in a function of the script), it *is* clear that 0
# will echo "signalled" and exit.  It's not clear to me what will happen
# on signals 1 2 3 14 15, though.
# 
# Should this work to (a) echo "signalled" and (b) exit, without recursion:
# 
# 	trap 'echo "signalled"; exit' 0 1 2 3 14 15
# 
# where by "without recursion" I mean successive firings on the trap?
# What would the exit code be if the trap is taken by execution of an
# 'exit 1' in the script?  Would it be 0 because the echo was a success?

No, it would be 0 because no argument is supplied to the exit.

# Should I, instead, do:
# 
# 	trap 'echo "signalled"' 0
# 	trap 'echo "signalled"; exit' 1 2 3 14 15
# 
# to avoid a possible recursion and protect the exit code?

This won't protect the exit code either.

# 
# Anyone *really* know?

Well, let me give it my best shot...

Think of traps as being like signal handlers in C under UNIX(TM).  If you
don't catch the signal, the default action is to terminate the program.  The
same is true of a shell script.  You can ignore signals in a program.  To
do the same in a shell script, you set the action to the null string:

trap "" 1 2 3 15	# ignore some interrupts

Finally, you can call some user-defined signal handler which can do pretty 
much anything you want.  In a shell script, the same is true.  (For the
remainder of my message, I'll be talking about ksh88e, which is what I use.
The principles are generally true with earlier versions of ksh or with the
Bourne shell.)

I have used traps quite a bit and had occasion to explore their behavior
rather thoroughly.  First of all, the book states that, if several events
("interrupts") occur at about the same time, they are handled in the following
order:

DEBUG
ERR
all true interrupts (in numerical order)
EXIT

The EXIT trap is called whenever you 'exit' explicitly or the script finishes
executing in some fashion.  Note that the shell also provides the -e flag
which is similar to, but separate from, the ERR trap.  This flag takes
precedence over the real interrupts and causes an exit to occur, which will
trigger any EXIT trap.  By the same token, DEBUG is similar to, but different
from, the -x flag.  With these ideas in mind, it is possible to do many
interesting things.

One other point about traps and true interrupts (e.g., SIGINT): two or more
in a row can cause the trap to be started multiple times (depending on how
close together the interrupts are and how long it takes to execute the trap
action), so I think it is best to reset the trap first thing to ignore future
interrupts:

trap 'trap "" 1 2 3 15; rm -f $TMPFILE; exit 1' 1 2 3 15

Finally, I usually prefer to set all my traps at once (whenever the action
is the same) but this can cause the EXIT trap to be called twice if a true
interrupt occurs.  It also would cause the script to always exit with a value
of 1.  To get around this, I take advantage of the fact that the trap action
is expanded at execution time, so I do something like this (note: you must use
single quotes (or something equivalent) to protect against the expansion of
$RET at the time the trap is set):

RET=1
trap 'trap "" 1 2 3 15; rm -f $TMPFILE; trap 0; exit $RET' 0 1 2 3 15

# the script does its thing and at the end or before an explicit call to
# exit, I put:

RET=0

So, what happens is that the call to 'rm -f $TMPFILE' is made just once,
regardless of whether the script terminates normally or not.  Also, the 
script exits with a value indicative of what caused it to terminate.  I've
noted one funny thing that I think is a bug (inherited from the Bourne shell?):
If SIGINT is sent with the traps as noted above, then $? is set to 129
rather than 1 (or even 130).  The ksh book states $? is the value of the last
command executed and that it is 128 plus the signal number when an interrupt
terminated the command.  In this case though, the last command executed by
the script is 'exit $RET', so I think the value of $? should be 1.  If the
script terminates due to some other signal (e.g., SIGHUP) the value of $? is
indeed 1.

Hope this helps...
L. Mark Larsen
lml@atlas.att.com

peter@ficc.ferranti.com (Peter da Silva) (04/03/91)

In article <c8C901q64a9q00@amdahl.uts.amdahl.com> krs@amdahl.uts.amdahl.com (Kris Stephens [Hail Eris!]) writes:
> 	trap 'echo "signalled"' 0
> 	trap 'echo "signalled"; exit' 1 2 3 14 15

No, you should do:

	trap 'echo "signalled"; exit' 0
	trap exit 1 2 3 14 15

Because (at least on some versions of the shell) the exit in the trap N
triggers the trap 0, and you will get two "signalled" messages.
-- 
Peter da Silva.  `-_-'  peter@ferranti.com
+1 713 274 5180.  'U`  "Have you hugged your wolf today?"

Ewige Blumenkraft.