628 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			628 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<HTML>
 | 
						|
<HEAD>
 | 
						|
<link rel="SHORTCUT ICON" href="http://www.cons.org/favicon.ico">
 | 
						|
<TITLE>Proper handling of SIGINT/SIGQUIT [http://www.cons.org/cracauer/sigint.html]</TITLE>
 | 
						|
<!-- Created by: GNU m4 using $Revision: 1.20 $ of crawww.m4lib on 11-Feb-2005 -->
 | 
						|
<BODY BGCOLOR="#fff8e1">
 | 
						|
<CENTER><H2>Proper handling of SIGINT/SIGQUIT</H2></CENTER>
 | 
						|
<img src=linie.png width="100%" alt=" ">
 | 
						|
<P>
 | 
						|
 | 
						|
<table border=1 cellpadding=4>
 | 
						|
<tr><th valign=top align=left>Abstract: </th>
 | 
						|
<td valign=top align=left>
 | 
						|
In UNIX terminal sessions, you usually have a key like
 | 
						|
<code>C-c</code> (Control-C) to immediately end whatever program you
 | 
						|
have running in the foreground. This should work even when the program
 | 
						|
you called has called other programs in turn. Everything should be
 | 
						|
aborted, giving you your command prompt back, no matter how deep the
 | 
						|
call stack is.
 | 
						|
 | 
						|
<p>Basically, it's trivial. But the existence of interactive
 | 
						|
applications that use SIGINT and/or SIGQUIT for other purposes than a
 | 
						|
complete immediate abort make matters complicated, and - as was to
 | 
						|
expect - left us with several ways to solve the problems. Of course,
 | 
						|
existing shells and applications follow different ways.
 | 
						|
 | 
						|
<P>This Web pages outlines different ways to solve the problem and
 | 
						|
argues that only one of them can do everything right, although it
 | 
						|
means that we have to fix some existing software.
 | 
						|
 | 
						|
 | 
						|
 | 
						|
</td></tr><tr><th valign=top align=left>Intended audience: </th>
 | 
						|
<td valign=top align=left>Programmers who implement programs that catch SIGINT/SIGQUIT.
 | 
						|
<BR>Programmers who implements shells or shell-like programs that
 | 
						|
execute batches of programs.
 | 
						|
 | 
						|
<p>Users who have problems problems getting rid of runaway shell
 | 
						|
scripts using <code>Control-C</code>. Or have interactive applications
 | 
						|
that don't behave right when sending SIGINT. Examples are emacs'es
 | 
						|
that die on Control-g or shellscript statements that sometimes are
 | 
						|
executed and sometimes not, apparently not determined by the user's
 | 
						|
intention. 
 | 
						|
 | 
						|
 | 
						|
</td></tr><tr><th valign=top align=left>Required knowledge: </th>
 | 
						|
<td valign=top align=left>You have to know what it means to catch SIGINT or SIGQUIT and how
 | 
						|
processes are waiting for other processes (childs) they spawned.
 | 
						|
 | 
						|
 | 
						|
</td></tr></table>
 | 
						|
<img src=linie.png width="100%" alt=" ">
 | 
						|
 | 
						|
 | 
						|
<H3>Basic concepts</H3>
 | 
						|
 | 
						|
What technically happens when you press Control-C is that all programs
 | 
						|
running in the foreground in your current terminal (or virtual
 | 
						|
terminal) get the signal SIGINT sent.
 | 
						|
 | 
						|
<p>You may change the key that triggers the signal using
 | 
						|
<code>stty</code> and running programs may remap the SIGINT-sending
 | 
						|
key at any time they like, without your intervention and without
 | 
						|
asking you first.
 | 
						|
 | 
						|
<p>The usual reaction of a running program to SIGINT is to exit.
 | 
						|
However, not all program do an exit on SIGINT, programs are free to
 | 
						|
use the signal for other actions or to ignore it at all.
 | 
						|
 | 
						|
<p>All programs running in the foreground receive the signal. This may
 | 
						|
be a nested "stack" of programs: You started a program that started
 | 
						|
another and the outer is waiting for the inner to exit. This nesting
 | 
						|
may be arbitrarily deep.
 | 
						|
 | 
						|
<p>The innermost program is the one that decides what to do on SIGINT.
 | 
						|
It may exit, do something else or do nothing. Still, when the user hit
 | 
						|
SIGINT, all the outer programs are awaken, get the signal and may
 | 
						|
react on it.
 | 
						|
 | 
						|
<H3>What we try to achieve</H3>
 | 
						|
 | 
						|
The problem is with shell scripts (or similar programs that call
 | 
						|
several subprograms one after another).
 | 
						|
 | 
						|
<p>Let us consider the most basic script:
 | 
						|
<PRE>
 | 
						|
#! /bin/sh
 | 
						|
program1
 | 
						|
program2
 | 
						|
</PRE>
 | 
						|
and the usual run looks like this:
 | 
						|
<PRE>
 | 
						|
$ sh myscript
 | 
						|
[output of program1]
 | 
						|
[output of program2]
 | 
						|
$
 | 
						|
</PRE>
 | 
						|
 | 
						|
<p>Let us assume that both programs do nothing special on SIGINT, they
 | 
						|
just exit.
 | 
						|
 | 
						|
<p>Now imagine the user hits C-c while a shellscript is executing its
 | 
						|
first program. The following programs receive SIGINT: program1 and
 | 
						|
also the shell executing the script. program1 exits. 
 | 
						|
 | 
						|
<p>But what should the shell do? If we say that it is only the
 | 
						|
innermost's programs business to react on SIGINT, the shell will do
 | 
						|
nothing special (not exit) and it will continue the execution of the
 | 
						|
script and run program2. But this is wrong: The user's intention in
 | 
						|
hitting C-c is to abort the whole script, to get his prompt back. If
 | 
						|
he hits C-c while the first program is running, he does not want
 | 
						|
program2 to be even started.
 | 
						|
 | 
						|
<p>here is what would happen if the shell doesn't do anything:
 | 
						|
<PRE>
 | 
						|
$ sh myscript
 | 
						|
[first half of program1's output]
 | 
						|
C-c   [users presses C-c]
 | 
						|
[second half of program1's output will not be displayed]
 | 
						|
[output of program2 will appear]
 | 
						|
</PRE>
 | 
						|
 | 
						|
 | 
						|
<p>Consider a more annoying example:
 | 
						|
<pre>
 | 
						|
#! /bin/sh
 | 
						|
# let's assume there are 300 *.dat files
 | 
						|
for file in *.dat ; do
 | 
						|
	dat2ascii $dat
 | 
						|
done
 | 
						|
</pre>
 | 
						|
 | 
						|
If your shell wouldn't end if the user hits <code>C-c</code>,
 | 
						|
<code>C-c</code> would just end <strong>one</strong> dat2ascii run and
 | 
						|
the script would continue. Thus, you had to hit <code>C-c</code> up to
 | 
						|
300 times to end this script.
 | 
						|
 | 
						|
<H3>Alternatives to do so</H3>
 | 
						|
 | 
						|
<p>There are several ways to handle abortion of shell scripts when
 | 
						|
SIGINT is received while a foreground child runs:
 | 
						|
 | 
						|
<menu>
 | 
						|
 | 
						|
<li>As just outlined, the shellscript may just continue, ignoring the
 | 
						|
fact that the user hit <code>C-c</code>. That way, your shellscript -
 | 
						|
including any loops - would continue and you had no chance of aborting
 | 
						|
it except using the kill command after finding out the outermost
 | 
						|
shell's PID. This "solution" will not be discussed further, as it is
 | 
						|
obviously not desirable.
 | 
						|
 | 
						|
<p><li>The shell itself exits immediately when it receives SIGINT. Not
 | 
						|
only the program called will exit, but the calling (the
 | 
						|
script-executing) shell. The first variant is to exit the shell (and
 | 
						|
therefore discontinuing execution of the script) immediately, while
 | 
						|
the background program may still be executing (remember that although
 | 
						|
the shell is just waiting for the called program to exit, it is woken
 | 
						|
up and may act). I will call the way of doing things the "IUE" (for
 | 
						|
"immediate unconditional exit") for the rest of this document.
 | 
						|
 | 
						|
<p><li>As a variant of the former, when the shell receives SIGINT
 | 
						|
while it is waiting for a child to exit, the shell does not exit
 | 
						|
immediately. but it remembers the fact that a SIGINT happened. After
 | 
						|
the called program exits and the shell's wait ends, the shell will
 | 
						|
exit itself and hence discontinue the script. I will call the way of
 | 
						|
doing things the "WUE" (for "wait and unconditional exit") for the
 | 
						|
rest of this document.
 | 
						|
 | 
						|
<p><li>There is also a way that the calling shell can tell whether the
 | 
						|
called program exited on SIGINT and if it ignored SIGINT (or used it
 | 
						|
for other purposes). As in the <sl>WUE</sl> way, the shell waits for
 | 
						|
the child to complete. It figures whether the program was ended on
 | 
						|
SIGINT and if so, it discontinue the script. If the program did any
 | 
						|
other exit, the script will be continued. I will call the way of doing
 | 
						|
things the "WCE" (for "wait and cooperative exit") for the rest of
 | 
						|
this document.
 | 
						|
 | 
						|
</menu>
 | 
						|
 | 
						|
<H3>The problem</H3>
 | 
						|
 | 
						|
On first sight, all three solutions (IUE, WUE and WCE) all seem to do
 | 
						|
what we want: If C-c is hit while the first program of the shell
 | 
						|
script runs, the script is discontinued. The user gets his prompt back
 | 
						|
immediately. So what are the difference between these way of handling
 | 
						|
SIGINT?
 | 
						|
 | 
						|
<p>There are programs that use the signal SIGINT for other purposes
 | 
						|
than exiting. They use it as a normal keystroke. The user is expected
 | 
						|
to use the key that sends SIGINT during a perfectly normal program
 | 
						|
run. As a result, the user sends SIGINT in situations where he/she
 | 
						|
does not want the program or the script to end.
 | 
						|
 | 
						|
<p>The primary example is the emacs editor: C-g does what ESC does in
 | 
						|
other applications: It cancels a partially executed or prepared
 | 
						|
operation. Technically, emacs remaps the key that sends SIGINT from
 | 
						|
C-c to C-g and catches SIGINT.
 | 
						|
 | 
						|
<p>Remember that the SIGINT is sent to all programs running in the
 | 
						|
foreground. If emacs is executing from a shell script, both emacs and
 | 
						|
the shell get SIGINT. emacs is the program that decides what to do:
 | 
						|
Exit on SIGINT or not. emacs decides not to exit. The problem arises
 | 
						|
when the shell draws its own conclusions from receiving SIGINT without
 | 
						|
consulting emacs for its opinion.
 | 
						|
 | 
						|
<p>Consider this script:
 | 
						|
<PRE>
 | 
						|
#! /bin/sh
 | 
						|
emacs /tmp/foo
 | 
						|
cp /tmp/foo /home/user/mail/sent
 | 
						|
</PRE>
 | 
						|
 | 
						|
<p>If C-g is used in emacs, both the shell and emacs will received
 | 
						|
SIGINT. Emacs will not exit, the user used C-g as a normal editing
 | 
						|
keystroke, he/she does not want the script to be aborted on C-g.
 | 
						|
 | 
						|
<p>The central problem is that the second command (cp) may
 | 
						|
unintentionally be killed when the shell draws its own conclusion
 | 
						|
about the user's intention. The innermost program is the only one to
 | 
						|
judge.
 | 
						|
 | 
						|
<H3>One more example</H3>
 | 
						|
 | 
						|
<p>Imagine a mail session using a curses mailer in a tty. You called
 | 
						|
your mailer and started to compose a message. Your mailer calls emacs.
 | 
						|
<code>C-g</code> is a normal editing key in emacs. Technically it
 | 
						|
sends SIGINT (it was <code>C-c</code>, but emacs remapped the key) to
 | 
						|
<menu>
 | 
						|
<li>emacs
 | 
						|
<li>the shell between your mailer and emacs, the one from your mailers
 | 
						|
    system("emacs /tmp/bla.44") command
 | 
						|
<li>the mailer itself
 | 
						|
<li>possibly another shell if your mailer was called by a shell script
 | 
						|
or from another application using system(3)
 | 
						|
<li>your interactive shell (which ignores it since it is interactive
 | 
						|
and hence is not relevant to this discussion)
 | 
						|
</menu>
 | 
						|
 | 
						|
<p>If everyone just exits on SIGINT, you will be left with nothing but
 | 
						|
your login shell, without asking.
 | 
						|
 | 
						|
<p>But for sure you don't want to be dropped out of your editor and
 | 
						|
out of your mailer back to the commandline, having your edited data
 | 
						|
and mailer status deleted.
 | 
						|
 | 
						|
<p>Understand the difference: While <code>C-g</code> is used an a kind
 | 
						|
of abort key in emacs, it isn't the major "abort everything" key. When
 | 
						|
you use <code>C-g</code> in emacs, you want to end some internal emacs
 | 
						|
command. You don't want your whole emacs and mailer session to end.
 | 
						|
 | 
						|
<p>So, if the shell exits immediately if the user sends SIGINT (the
 | 
						|
second of the four ways shown above), the parent of emacs would die,
 | 
						|
leaving emacs without the controlling tty. The user will lose it's
 | 
						|
editing session immediately and unrecoverable. If the "main" shell of
 | 
						|
the operating system defaults to this behavior, every editor session
 | 
						|
that is spawned from a mailer or such will break (because it is
 | 
						|
usually executed by system(3), which calls /bin/sh). This was the case
 | 
						|
in FreeBSD before I and Bruce Evans changed it in 1998.
 | 
						|
 | 
						|
<p>If the shell recognized that SIGINT was sent and exits after the
 | 
						|
current foreground process exited (the third way of the four), the
 | 
						|
editor session will not be disturbed, but things will still not work
 | 
						|
right.
 | 
						|
 | 
						|
<H3>A further look at the alternatives</H3>
 | 
						|
 | 
						|
<p>Still considering this script to examine the shell's actions in the
 | 
						|
IUE, WUE and ICE way of handling SIGINT:
 | 
						|
<PRE>
 | 
						|
#! /bin/sh
 | 
						|
emacs /tmp/foo
 | 
						|
cp /tmp/foo /home/user/mail/sent
 | 
						|
</PRE>
 | 
						|
 | 
						|
<p>The IUE ("immediate unconditional exit") way does not work at all:
 | 
						|
emacs wants to survive the SIGINT (it's a normal editing key for
 | 
						|
emacs), but its parent shell unconditionally thinks "We received
 | 
						|
SIGINT. Abort everything. Now.". The shell will exit even before emacs
 | 
						|
exits. But this will leave emacs in an unusable state, since the death
 | 
						|
of its calling shell will leave it without required resources (file
 | 
						|
descriptors). This way does not work at all for shellscripts that call
 | 
						|
programs that use SIGINT for other purposes than immediate exit. Even
 | 
						|
for programs that exit on SIGINT, but want to do some cleanup between
 | 
						|
the signal and the exit, may fail before they complete their cleanup.
 | 
						|
 | 
						|
<p>It should be noted that this way has one advantage: If a child
 | 
						|
blocks SIGINT and does not exit at all, this way will get control back
 | 
						|
to the user's terminal. Since such programs should be banned from your
 | 
						|
system anyway, I don't think that weighs against the disadvantages.
 | 
						|
 | 
						|
<p>WUE ("wait and unconditional exit") is a little more clever: If C-g
 | 
						|
was used in emacs, the shell will get SIGINT. It will not immediately
 | 
						|
exit, but remember the fact that a SIGINT happened. When emacs ends
 | 
						|
(maybe a long time after the SIGINT), it will say "Ok, a SIGINT
 | 
						|
happened sometime while the child was executing, the user wants the
 | 
						|
script to be discontinued". It will then exit. The cp will not be
 | 
						|
executed. But that's bad. The "cp" will be executed when the emacs
 | 
						|
session ended without the C-g key ever used, but it will not be
 | 
						|
executed when the user used C-g at least one time. That is clearly not
 | 
						|
desired. Since C-g is a normal editing key in emacs, the user expects
 | 
						|
the rest of the script to behave identically no matter what keys he
 | 
						|
used.
 | 
						|
 | 
						|
<p>As a result, the "WUE" way is better than the "IUE" way in that it
 | 
						|
does not break SIGINT-using programs completely. The emacs session
 | 
						|
will end undisturbed. But it still does not support scripts where
 | 
						|
other actions should be performed after a program that use SIGINT for
 | 
						|
non-exit purposes. Since the behavior is basically undeterminable for
 | 
						|
the user, this can lead to nasty surprises.
 | 
						|
 | 
						|
<p>The "WCE" way fixes this by "asking" the called program whether it
 | 
						|
exited on SIGINT or not. While emacs receives SIGINT, it does not exit
 | 
						|
on it and a calling shell waiting for its exit will not be told that
 | 
						|
it exited on SIGINT. (Although it receives SIGINT at some point in
 | 
						|
time, the system does not enforce that emacs will exit with
 | 
						|
"I-exited-on-SIGINT" status. This is under emacs' control, see below).
 | 
						|
 | 
						|
<p>this still work for the normal script without SIGINT-using
 | 
						|
programs:</p>
 | 
						|
<PRE>
 | 
						|
#! /bin/sh
 | 
						|
program1
 | 
						|
program2
 | 
						|
</PRE>
 | 
						|
 | 
						|
Unless program1 and program2 mess around with signal handling, the
 | 
						|
system will tell the calling shell whether the programs exited
 | 
						|
normally or as a result of SIGINT.
 | 
						|
 | 
						|
<p>The "WCE" way then has an easy way to things right: When one called
 | 
						|
program exited with "I-exited-on-SIGINT" status, it will discontinue
 | 
						|
the script after this program. If the program ends without this
 | 
						|
status, the next command in the script is started.
 | 
						|
 | 
						|
<p>It is important to understand that a shell in "WCE" modus does not
 | 
						|
need to listen to the SIGINT signal at all. Both in the
 | 
						|
"emacs-then-cp" script and in the "several-normal-programs" script, it
 | 
						|
will be woken up and receive SIGINT when the user hits the
 | 
						|
corresponding key. But the shell does not need to react on this event
 | 
						|
and it doesn't need to remember the event of any SIGINT, either.
 | 
						|
Telling whether the user wants to end a script is done by asking that
 | 
						|
program that has to decide, that program that interprets keystrokes
 | 
						|
from the user, the innermost program.
 | 
						|
 | 
						|
<H3>So everything is well with WCE?</H3>
 | 
						|
 | 
						|
Well, almost.
 | 
						|
 | 
						|
<p>The problem with the "WCE" modus is that there are broken programs
 | 
						|
that do not properly communicate the required information up to the
 | 
						|
calling program.
 | 
						|
 | 
						|
<p>Unless a program messes with signal handling, the system does this
 | 
						|
automatically. 
 | 
						|
 | 
						|
<p>There are programs that want to exit on SIGINT, but they don't let
 | 
						|
the system do the automatic exit, because they want to do some
 | 
						|
cleanup. To do so, they catch SIGINT, do the cleanup and then exit by
 | 
						|
themselves.
 | 
						|
 | 
						|
<p>And here is where the problem arises: Once they catch the signal,
 | 
						|
the system will no longer communicate the "I-exited-on-SIGINT" status
 | 
						|
to the calling program automatically. Even if the program exit
 | 
						|
immediately in the signal handler of SIGINT. Once it catches the
 | 
						|
signal, it has to take care of communicating the signal status
 | 
						|
itself.
 | 
						|
 | 
						|
<p>Some programs don't do this. On SIGINT, they do cleanup and exit
 | 
						|
immediatly, but the calling shell isn't told about the non-normal exit
 | 
						|
and it will call the next program in the script.
 | 
						|
 | 
						|
<p>As a result, the user hits SIGINT and while one program exits, the
 | 
						|
shellscript continues. To him/her it looks like the shell fails to
 | 
						|
obey to his abortion command.
 | 
						|
 | 
						|
<p>Both IUE or WUE shell would not have this problem, since they
 | 
						|
discontinue the script on their own. But as I said, they don't support
 | 
						|
programs using SIGINT for non-exiting purposes, no matter whether
 | 
						|
these programs properly communicate their signal status to the calling
 | 
						|
shell or not.
 | 
						|
 | 
						|
<p>Since some shell in wide use implement the WUE way (and some even
 | 
						|
IUE), there is a considerable number of broken programs out there that
 | 
						|
break WCE shells. The programmers just don't recognize it if their
 | 
						|
shell isn't WCE.
 | 
						|
 | 
						|
<H3>How to be a proper program</H3>
 | 
						|
 | 
						|
<p>(Short note in advance: What you need to achieve is that
 | 
						|
WIFSIGNALED(status) is true in the calling program and that
 | 
						|
WTERMSIG(status) returns SIGINT.)
 | 
						|
 | 
						|
<p>If you don't catch SIGINT, the system automatically does the right
 | 
						|
thing for you: Your program exits and the calling program gets the
 | 
						|
right "I-exited-on-SIGINT" status after waiting for your exit.
 | 
						|
 | 
						|
<p>But once you catch SIGINT, you have to act.
 | 
						|
 | 
						|
<p>Decide whether the SIGINT is used for exit/abort purposes and hence
 | 
						|
a shellscript calling this program should discontinue. This is
 | 
						|
hopefully obvious. If you just need to do some cleanup on SIGINT, but
 | 
						|
then exit immediately, the answer is "yes".
 | 
						|
 | 
						|
<p>If so, you have to tell the calling program about it by exiting
 | 
						|
with the "I-exited-on-SIGINT" status.
 | 
						|
 | 
						|
<p>There is no other way of doing this than to kill yourself with a
 | 
						|
SIGINT signal. Do it by resetting the SIGINT handler to SIG_DFL, then
 | 
						|
send yourself the signal.
 | 
						|
 | 
						|
<PRE>
 | 
						|
void sigint_handler(int sig)
 | 
						|
{
 | 
						|
	<do some cleanup>
 | 
						|
	signal(SIGINT, SIG_DFL);
 | 
						|
	kill(getpid(), SIGINT);
 | 
						|
}
 | 
						|
</PRE>
 | 
						|
 | 
						|
Notes:
 | 
						|
 | 
						|
<MENU>
 | 
						|
 | 
						|
<LI>You cannot "fake" the proper exit status by an exit(3) with a
 | 
						|
special numeric value. People often assume this since the manuals for
 | 
						|
shells often list some return value for exactly this. But this is just
 | 
						|
a convention for your shell script. It does not work from one UNIX API
 | 
						|
program to another. 
 | 
						|
 | 
						|
<P>All that happens is that the shell sets the "$?" variable to a
 | 
						|
special numeric value for the convenience of your script, because your
 | 
						|
script does not have access to the lower-lever UNIX status evaluation
 | 
						|
functions. This is just an agreement between your script and the
 | 
						|
executing shell, it does not have any meaning in other contexts.
 | 
						|
 | 
						|
<P><LI>Do not use kill(0, SIGINT) without consulting the manul for
 | 
						|
your OS implementation. I.e. on BSD, this would not send the signal to
 | 
						|
the current process, but to all processes in the group.
 | 
						|
 | 
						|
<P><LI>POSIX 1003.1 allows all these calls to appear in signal
 | 
						|
handlers, so it is portable.
 | 
						|
 | 
						|
</MENU>
 | 
						|
 | 
						|
<p>In a bourne shell script, you can catch signals using the
 | 
						|
<code>trap</code> command. Here, the same as for C programs apply.  If
 | 
						|
the intention of SIGINT is to end your program, you have to exit in a
 | 
						|
way that the calling programs "sees" that you have been killed.  If
 | 
						|
you don't catch SIGINT, this happend automatically, but of you catch
 | 
						|
SIGINT, i.e. to do cleanup work, you have to end the program by
 | 
						|
killing yourself, not by calling exit.
 | 
						|
 | 
						|
<p>Consider this example from FreeBSD's <code>mkdep</code>, which is a
 | 
						|
bourne shell script.
 | 
						|
 | 
						|
<pre>
 | 
						|
TMP=_mkdep$$
 | 
						|
trap 'rm -f $TMP ; trap 2 ; kill -2 $$' 1 2 3 13 15
 | 
						|
</pre>
 | 
						|
 | 
						|
Yes, you have to do it the hard way. It's even more annoying in shell
 | 
						|
scripts than in C programs since you can't "pre-delete" temporary
 | 
						|
files (which isn't really portable in C, though).
 | 
						|
 | 
						|
<P>All this applies to programs in all languages, not only C and
 | 
						|
bourne shell. Every language implementation that lets you catch SIGINT
 | 
						|
should also give you the option to reset the signal and kill yourself.
 | 
						|
 | 
						|
<P>It is always desireable to exit the right way, even if you don't
 | 
						|
expect your usual callers to depend on it, some unusual one will come
 | 
						|
along. This proper exit status will be needed for WCE and will not
 | 
						|
hurt when the calling shell uses IUE or WUE.
 | 
						|
 | 
						|
<H3>How to be a proper shell</H3>
 | 
						|
 | 
						|
All this applies only for the script-executing case. Most shells will
 | 
						|
also have interactive modes where things are different.
 | 
						|
 | 
						|
<MENU>
 | 
						|
 | 
						|
<LI>Do nothing special when SIGINT appears while you wait for a child.
 | 
						|
You don't even have to remember that one happened.
 | 
						|
 | 
						|
<P><LI>Wait for child to exit, get the exit status. Do not truncate it
 | 
						|
to type char.
 | 
						|
 | 
						|
<P><LI>Look at WIFSIGNALED(status) and WTERMSIG(status) to tell
 | 
						|
whether the child says "I exited on SIGINT: in my opinion the user
 | 
						|
wants the shellscript to be discontinued".
 | 
						|
 | 
						|
<P><LI>If the latter applies, discontinue the script.
 | 
						|
 | 
						|
<P><LI>Exit. But since a shellscript may in turn be called by a
 | 
						|
shellscript, you need to make sure that you properly communicate the
 | 
						|
discontinue intention to the calling program. As in any other program
 | 
						|
(see above), do
 | 
						|
 | 
						|
<PRE>
 | 
						|
	signal(SIGINT, SIG_DFL);
 | 
						|
	kill(getpid(), SIGINT);
 | 
						|
</PRE>
 | 
						|
 | 
						|
</MENU>
 | 
						|
 | 
						|
<H3>Other remarks</H3>
 | 
						|
 | 
						|
Although this web page talks about SIGINT only, almost the same issues
 | 
						|
apply to SIGQUIT, including proper exiting by killing yourself after
 | 
						|
catching the signal and proper reaction on the WIFSIGNALED(status)
 | 
						|
value. One notable difference for SIGQUIT is that you have to make
 | 
						|
sure that not the whole call tree dumps core.
 | 
						|
 | 
						|
<H3>What to fight</H3>
 | 
						|
 | 
						|
Make sure all programs <em>really</em> kill themselves if they react
 | 
						|
to SIGINT or SIGQUIT and intend to abort their operation as a result
 | 
						|
of this signal. Programs that don't use SIGINT/SIGQUIT as a
 | 
						|
termination trigger - but as part of normal operation - don't kill
 | 
						|
themselves, but do a normal exit instead.
 | 
						|
 | 
						|
<p>Make sure people understand why you can't fake an exit-on-signal by
 | 
						|
doing exit(...) using any numerical status.
 | 
						|
 | 
						|
<p>Make sure you use a shell that behaves right. Especially if you
 | 
						|
develop programs, since it will help seeing problems.
 | 
						|
 | 
						|
<H3>Concrete examples how to fix programs:</H3>
 | 
						|
<ul>
 | 
						|
 | 
						|
<li>The fix for FreeBSD's
 | 
						|
<A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/time/time.c.diff?r1=1.10&r2=1.11">time(1)</A>. This fix is the best example, it's quite short and clear and
 | 
						|
it fixes a case where someone tried to fake signal exit status by a
 | 
						|
numerical value. And the complete program is small.
 | 
						|
 | 
						|
<p><li>Fix for FreeBSD's
 | 
						|
<A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/truss/main.c.diff?r1=1.9&r2=1.10">truss(1)</A>.
 | 
						|
 | 
						|
<p><li>The fix for FreeBSD's
 | 
						|
<A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/mkdep/mkdep.gcc.sh.diff?r1=1.8.2.1&r2=1.8.2.2">mkdep(1)</A>, a shell script.
 | 
						|
 | 
						|
 | 
						|
<p><li>Fix for FreeBSD's make(1), <A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/make/job.c.diff?r1=1.9&r2=1.10">part 1</A>,
 | 
						|
<A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/make/compat.c.diff?r1=1.10&r2=1.11">part 2</A>.
 | 
						|
 | 
						|
</ul>
 | 
						|
 | 
						|
<H3>Testsuite for shells</H3>
 | 
						|
 | 
						|
I have a collection of shellscripts that test shells for the
 | 
						|
behavior. See my <A HREF="download/">download dir</A> to get the newest
 | 
						|
"sh-interrupt" files, either as a tarfile or as individual file for
 | 
						|
online browsing. This isn't really documented, besides from the
 | 
						|
comments the scripts echo.
 | 
						|
 | 
						|
<H3>Appendix 1 - table of implementation choices</H3>
 | 
						|
 | 
						|
<table border cellpadding=2>
 | 
						|
 | 
						|
<tr valign=top>
 | 
						|
<th>Method sign</th>
 | 
						|
<th>Does what?</th>
 | 
						|
<th>Example shells that implement it:</th>
 | 
						|
<th>What happens when a shellscript called emacs, the user used
 | 
						|
<code>C-g</code> and the script has additional commands in it?</th>
 | 
						|
<th>What happens when a shellscript called emacs, the user did not use
 | 
						|
<code>C-c</code> and the script has additional commands in it?</th>
 | 
						|
<th>What happens if a non-interactive child catches SIGINT?</th>
 | 
						|
<th>To behave properly, childs must do what?</th>
 | 
						|
</tr>
 | 
						|
 | 
						|
<tr valign=top align=left>
 | 
						|
<td>IUE</td>
 | 
						|
<td>The shell executing a script exits immediately if it receives
 | 
						|
SIGINT.</td> 
 | 
						|
<td>4.4BSD ash (ash), NetBSD, FreeBSD prior to 3.0/22.8</td>
 | 
						|
<td>The editor session is lost and subsequent commands are not
 | 
						|
executed.</td>
 | 
						|
<td>The editor continues as normal and the subsequent commands are
 | 
						|
executed. </td>
 | 
						|
<td>The scripts ends immediately, returning to the caller even before
 | 
						|
the current foreground child of the shell exits. </td>
 | 
						|
<td>It doesn't matter what the child does or how it exits, even if the
 | 
						|
child continues to operate, the shell returns. </td>
 | 
						|
</tr>
 | 
						|
 | 
						|
<tr valign=top align=left>
 | 
						|
<td>WUE</td>
 | 
						|
<td>If the shell executing a script received SIGINT while a foreground
 | 
						|
process was running, it will exit after that child's exit.</td>
 | 
						|
<td>pdksh (OpenBSD /bin/sh)</td>
 | 
						|
<td>The editor continues as normal, but subsequent commands from the
 | 
						|
script are not executed.</td>
 | 
						|
<td>The editor continues as normal and subsequent commands are
 | 
						|
executed. </td>
 | 
						|
<td>The scripts returns to its caller after the current foreground
 | 
						|
child exits, no matter how the child exited. </td>
 | 
						|
<td>It doesn't matter how the child exits (signal status or not), but
 | 
						|
if it doesn't return at all, the shell will not return. In no case
 | 
						|
will further commands from the script be executed. </td>
 | 
						|
</tr>
 | 
						|
 | 
						|
<tr valign=top align=left>
 | 
						|
<td>WCE</td>
 | 
						|
<td>The shell exits if a child signaled that it was killed on a
 | 
						|
signal (either it had the default handler for SIGINT or it killed
 | 
						|
itself).  </td>
 | 
						|
<td>bash (Linux /bin/sh), most commercial /bin/sh, FreeBSD /bin/sh
 | 
						|
from 3.0/2.2.8.</td> 
 | 
						|
<td>The editor continues as normal and subsequent commands are
 | 
						|
executed. </td>
 | 
						|
<td>The editor continues as normal and subsequent commands are
 | 
						|
executed. </td>
 | 
						|
<td>The scripts returns to its caller after the current foreground
 | 
						|
child exits, but only if the child exited with signal status. If
 | 
						|
the child did a normal exit (even if it received SIGINT, but catches
 | 
						|
it), the script will continue. </td>
 | 
						|
<td>The child must be implemented right, or the user will not be able
 | 
						|
to break shell scripts reliably.</td> 
 | 
						|
</tr>
 | 
						|
 | 
						|
</table>
 | 
						|
 | 
						|
<P><img src=linie.png width="100%" alt=" ">
 | 
						|
<BR>©2005 Martin Cracauer <cracauer @ cons.org>
 | 
						|
<A HREF="http://www.cons.org/cracauer/">http://www.cons.org/cracauer/</A>
 | 
						|
<BR>Last changed: $Date: 2005/02/11 21:44:43 $
 | 
						|
</BODY></HTML>
 |