3 <link rel="SHORTCUT ICON" href="http://www.cons.org/favicon.ico">
4 <TITLE>Proper handling of SIGINT/SIGQUIT [http://www.cons.org/cracauer/sigint.html]</TITLE>
5 <!-- Created by: GNU m4 using $Revision: 1.20 $ of crawww.m4lib on 11-Feb-2005 -->
6 <BODY BGCOLOR="#fff8e1">
7 <CENTER><H2>Proper handling of SIGINT/SIGQUIT</H2></CENTER>
8 <img src=linie.png width="100%" alt=" ">
11 <table border=1 cellpadding=4>
12 <tr><th valign=top align=left>Abstract: </th>
13 <td valign=top align=left>
14 In UNIX terminal sessions, you usually have a key like
15 <code>C-c</code> (Control-C) to immediately end whatever program you
16 have running in the foreground. This should work even when the program
17 you called has called other programs in turn. Everything should be
18 aborted, giving you your command prompt back, no matter how deep the
21 <p>Basically, it's trivial. But the existence of interactive
22 applications that use SIGINT and/or SIGQUIT for other purposes than a
23 complete immediate abort make matters complicated, and - as was to
24 expect - left us with several ways to solve the problems. Of course,
25 existing shells and applications follow different ways.
27 <P>This Web pages outlines different ways to solve the problem and
28 argues that only one of them can do everything right, although it
29 means that we have to fix some existing software.
33 </td></tr><tr><th valign=top align=left>Intended audience: </th>
34 <td valign=top align=left>Programmers who implement programs that catch SIGINT/SIGQUIT.
35 <BR>Programmers who implements shells or shell-like programs that
36 execute batches of programs.
38 <p>Users who have problems problems getting rid of runaway shell
39 scripts using <code>Control-C</code>. Or have interactive applications
40 that don't behave right when sending SIGINT. Examples are emacs'es
41 that die on Control-g or shellscript statements that sometimes are
42 executed and sometimes not, apparently not determined by the user's
46 </td></tr><tr><th valign=top align=left>Required knowledge: </th>
47 <td valign=top align=left>You have to know what it means to catch SIGINT or SIGQUIT and how
48 processes are waiting for other processes (childs) they spawned.
52 <img src=linie.png width="100%" alt=" ">
55 <H3>Basic concepts</H3>
57 What technically happens when you press Control-C is that all programs
58 running in the foreground in your current terminal (or virtual
59 terminal) get the signal SIGINT sent.
61 <p>You may change the key that triggers the signal using
62 <code>stty</code> and running programs may remap the SIGINT-sending
63 key at any time they like, without your intervention and without
66 <p>The usual reaction of a running program to SIGINT is to exit.
67 However, not all program do an exit on SIGINT, programs are free to
68 use the signal for other actions or to ignore it at all.
70 <p>All programs running in the foreground receive the signal. This may
71 be a nested "stack" of programs: You started a program that started
72 another and the outer is waiting for the inner to exit. This nesting
73 may be arbitrarily deep.
75 <p>The innermost program is the one that decides what to do on SIGINT.
76 It may exit, do something else or do nothing. Still, when the user hit
77 SIGINT, all the outer programs are awaken, get the signal and may
80 <H3>What we try to achieve</H3>
82 The problem is with shell scripts (or similar programs that call
83 several subprograms one after another).
85 <p>Let us consider the most basic script:
91 and the usual run looks like this:
99 <p>Let us assume that both programs do nothing special on SIGINT, they
102 <p>Now imagine the user hits C-c while a shellscript is executing its
103 first program. The following programs receive SIGINT: program1 and
104 also the shell executing the script. program1 exits.
106 <p>But what should the shell do? If we say that it is only the
107 innermost's programs business to react on SIGINT, the shell will do
108 nothing special (not exit) and it will continue the execution of the
109 script and run program2. But this is wrong: The user's intention in
110 hitting C-c is to abort the whole script, to get his prompt back. If
111 he hits C-c while the first program is running, he does not want
112 program2 to be even started.
114 <p>here is what would happen if the shell doesn't do anything:
117 [first half of program1's output]
118 C-c [users presses C-c]
119 [second half of program1's output will not be displayed]
120 [output of program2 will appear]
124 <p>Consider a more annoying example:
127 # let's assume there are 300 *.dat files
128 for file in *.dat ; do
133 If your shell wouldn't end if the user hits <code>C-c</code>,
134 <code>C-c</code> would just end <strong>one</strong> dat2ascii run and
135 the script would continue. Thus, you had to hit <code>C-c</code> up to
136 300 times to end this script.
138 <H3>Alternatives to do so</H3>
140 <p>There are several ways to handle abortion of shell scripts when
141 SIGINT is received while a foreground child runs:
145 <li>As just outlined, the shellscript may just continue, ignoring the
146 fact that the user hit <code>C-c</code>. That way, your shellscript -
147 including any loops - would continue and you had no chance of aborting
148 it except using the kill command after finding out the outermost
149 shell's PID. This "solution" will not be discussed further, as it is
150 obviously not desirable.
152 <p><li>The shell itself exits immediately when it receives SIGINT. Not
153 only the program called will exit, but the calling (the
154 script-executing) shell. The first variant is to exit the shell (and
155 therefore discontinuing execution of the script) immediately, while
156 the background program may still be executing (remember that although
157 the shell is just waiting for the called program to exit, it is woken
158 up and may act). I will call the way of doing things the "IUE" (for
159 "immediate unconditional exit") for the rest of this document.
161 <p><li>As a variant of the former, when the shell receives SIGINT
162 while it is waiting for a child to exit, the shell does not exit
163 immediately. but it remembers the fact that a SIGINT happened. After
164 the called program exits and the shell's wait ends, the shell will
165 exit itself and hence discontinue the script. I will call the way of
166 doing things the "WUE" (for "wait and unconditional exit") for the
167 rest of this document.
169 <p><li>There is also a way that the calling shell can tell whether the
170 called program exited on SIGINT and if it ignored SIGINT (or used it
171 for other purposes). As in the <sl>WUE</sl> way, the shell waits for
172 the child to complete. It figures whether the program was ended on
173 SIGINT and if so, it discontinue the script. If the program did any
174 other exit, the script will be continued. I will call the way of doing
175 things the "WCE" (for "wait and cooperative exit") for the rest of
182 On first sight, all three solutions (IUE, WUE and WCE) all seem to do
183 what we want: If C-c is hit while the first program of the shell
184 script runs, the script is discontinued. The user gets his prompt back
185 immediately. So what are the difference between these way of handling
188 <p>There are programs that use the signal SIGINT for other purposes
189 than exiting. They use it as a normal keystroke. The user is expected
190 to use the key that sends SIGINT during a perfectly normal program
191 run. As a result, the user sends SIGINT in situations where he/she
192 does not want the program or the script to end.
194 <p>The primary example is the emacs editor: C-g does what ESC does in
195 other applications: It cancels a partially executed or prepared
196 operation. Technically, emacs remaps the key that sends SIGINT from
197 C-c to C-g and catches SIGINT.
199 <p>Remember that the SIGINT is sent to all programs running in the
200 foreground. If emacs is executing from a shell script, both emacs and
201 the shell get SIGINT. emacs is the program that decides what to do:
202 Exit on SIGINT or not. emacs decides not to exit. The problem arises
203 when the shell draws its own conclusions from receiving SIGINT without
204 consulting emacs for its opinion.
206 <p>Consider this script:
210 cp /tmp/foo /home/user/mail/sent
213 <p>If C-g is used in emacs, both the shell and emacs will received
214 SIGINT. Emacs will not exit, the user used C-g as a normal editing
215 keystroke, he/she does not want the script to be aborted on C-g.
217 <p>The central problem is that the second command (cp) may
218 unintentionally be killed when the shell draws its own conclusion
219 about the user's intention. The innermost program is the only one to
222 <H3>One more example</H3>
224 <p>Imagine a mail session using a curses mailer in a tty. You called
225 your mailer and started to compose a message. Your mailer calls emacs.
226 <code>C-g</code> is a normal editing key in emacs. Technically it
227 sends SIGINT (it was <code>C-c</code>, but emacs remapped the key) to
230 <li>the shell between your mailer and emacs, the one from your mailers
231 system("emacs /tmp/bla.44") command
232 <li>the mailer itself
233 <li>possibly another shell if your mailer was called by a shell script
234 or from another application using system(3)
235 <li>your interactive shell (which ignores it since it is interactive
236 and hence is not relevant to this discussion)
239 <p>If everyone just exits on SIGINT, you will be left with nothing but
240 your login shell, without asking.
242 <p>But for sure you don't want to be dropped out of your editor and
243 out of your mailer back to the commandline, having your edited data
244 and mailer status deleted.
246 <p>Understand the difference: While <code>C-g</code> is used an a kind
247 of abort key in emacs, it isn't the major "abort everything" key. When
248 you use <code>C-g</code> in emacs, you want to end some internal emacs
249 command. You don't want your whole emacs and mailer session to end.
251 <p>So, if the shell exits immediately if the user sends SIGINT (the
252 second of the four ways shown above), the parent of emacs would die,
253 leaving emacs without the controlling tty. The user will lose it's
254 editing session immediately and unrecoverable. If the "main" shell of
255 the operating system defaults to this behavior, every editor session
256 that is spawned from a mailer or such will break (because it is
257 usually executed by system(3), which calls /bin/sh). This was the case
258 in FreeBSD before I and Bruce Evans changed it in 1998.
260 <p>If the shell recognized that SIGINT was sent and exits after the
261 current foreground process exited (the third way of the four), the
262 editor session will not be disturbed, but things will still not work
265 <H3>A further look at the alternatives</H3>
267 <p>Still considering this script to examine the shell's actions in the
268 IUE, WUE and ICE way of handling SIGINT:
272 cp /tmp/foo /home/user/mail/sent
275 <p>The IUE ("immediate unconditional exit") way does not work at all:
276 emacs wants to survive the SIGINT (it's a normal editing key for
277 emacs), but its parent shell unconditionally thinks "We received
278 SIGINT. Abort everything. Now.". The shell will exit even before emacs
279 exits. But this will leave emacs in an unusable state, since the death
280 of its calling shell will leave it without required resources (file
281 descriptors). This way does not work at all for shellscripts that call
282 programs that use SIGINT for other purposes than immediate exit. Even
283 for programs that exit on SIGINT, but want to do some cleanup between
284 the signal and the exit, may fail before they complete their cleanup.
286 <p>It should be noted that this way has one advantage: If a child
287 blocks SIGINT and does not exit at all, this way will get control back
288 to the user's terminal. Since such programs should be banned from your
289 system anyway, I don't think that weighs against the disadvantages.
291 <p>WUE ("wait and unconditional exit") is a little more clever: If C-g
292 was used in emacs, the shell will get SIGINT. It will not immediately
293 exit, but remember the fact that a SIGINT happened. When emacs ends
294 (maybe a long time after the SIGINT), it will say "Ok, a SIGINT
295 happened sometime while the child was executing, the user wants the
296 script to be discontinued". It will then exit. The cp will not be
297 executed. But that's bad. The "cp" will be executed when the emacs
298 session ended without the C-g key ever used, but it will not be
299 executed when the user used C-g at least one time. That is clearly not
300 desired. Since C-g is a normal editing key in emacs, the user expects
301 the rest of the script to behave identically no matter what keys he
304 <p>As a result, the "WUE" way is better than the "IUE" way in that it
305 does not break SIGINT-using programs completely. The emacs session
306 will end undisturbed. But it still does not support scripts where
307 other actions should be performed after a program that use SIGINT for
308 non-exit purposes. Since the behavior is basically undeterminable for
309 the user, this can lead to nasty surprises.
311 <p>The "WCE" way fixes this by "asking" the called program whether it
312 exited on SIGINT or not. While emacs receives SIGINT, it does not exit
313 on it and a calling shell waiting for its exit will not be told that
314 it exited on SIGINT. (Although it receives SIGINT at some point in
315 time, the system does not enforce that emacs will exit with
316 "I-exited-on-SIGINT" status. This is under emacs' control, see below).
318 <p>this still work for the normal script without SIGINT-using
326 Unless program1 and program2 mess around with signal handling, the
327 system will tell the calling shell whether the programs exited
328 normally or as a result of SIGINT.
330 <p>The "WCE" way then has an easy way to things right: When one called
331 program exited with "I-exited-on-SIGINT" status, it will discontinue
332 the script after this program. If the program ends without this
333 status, the next command in the script is started.
335 <p>It is important to understand that a shell in "WCE" modus does not
336 need to listen to the SIGINT signal at all. Both in the
337 "emacs-then-cp" script and in the "several-normal-programs" script, it
338 will be woken up and receive SIGINT when the user hits the
339 corresponding key. But the shell does not need to react on this event
340 and it doesn't need to remember the event of any SIGINT, either.
341 Telling whether the user wants to end a script is done by asking that
342 program that has to decide, that program that interprets keystrokes
343 from the user, the innermost program.
345 <H3>So everything is well with WCE?</H3>
349 <p>The problem with the "WCE" modus is that there are broken programs
350 that do not properly communicate the required information up to the
353 <p>Unless a program messes with signal handling, the system does this
356 <p>There are programs that want to exit on SIGINT, but they don't let
357 the system do the automatic exit, because they want to do some
358 cleanup. To do so, they catch SIGINT, do the cleanup and then exit by
361 <p>And here is where the problem arises: Once they catch the signal,
362 the system will no longer communicate the "I-exited-on-SIGINT" status
363 to the calling program automatically. Even if the program exit
364 immediately in the signal handler of SIGINT. Once it catches the
365 signal, it has to take care of communicating the signal status
368 <p>Some programs don't do this. On SIGINT, they do cleanup and exit
369 immediatly, but the calling shell isn't told about the non-normal exit
370 and it will call the next program in the script.
372 <p>As a result, the user hits SIGINT and while one program exits, the
373 shellscript continues. To him/her it looks like the shell fails to
374 obey to his abortion command.
376 <p>Both IUE or WUE shell would not have this problem, since they
377 discontinue the script on their own. But as I said, they don't support
378 programs using SIGINT for non-exiting purposes, no matter whether
379 these programs properly communicate their signal status to the calling
382 <p>Since some shell in wide use implement the WUE way (and some even
383 IUE), there is a considerable number of broken programs out there that
384 break WCE shells. The programmers just don't recognize it if their
387 <H3>How to be a proper program</H3>
389 <p>(Short note in advance: What you need to achieve is that
390 WIFSIGNALED(status) is true in the calling program and that
391 WTERMSIG(status) returns SIGINT.)
393 <p>If you don't catch SIGINT, the system automatically does the right
394 thing for you: Your program exits and the calling program gets the
395 right "I-exited-on-SIGINT" status after waiting for your exit.
397 <p>But once you catch SIGINT, you have to act.
399 <p>Decide whether the SIGINT is used for exit/abort purposes and hence
400 a shellscript calling this program should discontinue. This is
401 hopefully obvious. If you just need to do some cleanup on SIGINT, but
402 then exit immediately, the answer is "yes".
404 <p>If so, you have to tell the calling program about it by exiting
405 with the "I-exited-on-SIGINT" status.
407 <p>There is no other way of doing this than to kill yourself with a
408 SIGINT signal. Do it by resetting the SIGINT handler to SIG_DFL, then
409 send yourself the signal.
412 void sigint_handler(int sig)
415 signal(SIGINT, SIG_DFL);
416 kill(getpid(), SIGINT);
424 <LI>You cannot "fake" the proper exit status by an exit(3) with a
425 special numeric value. People often assume this since the manuals for
426 shells often list some return value for exactly this. But this is just
427 a convention for your shell script. It does not work from one UNIX API
430 <P>All that happens is that the shell sets the "$?" variable to a
431 special numeric value for the convenience of your script, because your
432 script does not have access to the lower-lever UNIX status evaluation
433 functions. This is just an agreement between your script and the
434 executing shell, it does not have any meaning in other contexts.
436 <P><LI>Do not use kill(0, SIGINT) without consulting the manul for
437 your OS implementation. I.e. on BSD, this would not send the signal to
438 the current process, but to all processes in the group.
440 <P><LI>POSIX 1003.1 allows all these calls to appear in signal
441 handlers, so it is portable.
445 <p>In a bourne shell script, you can catch signals using the
446 <code>trap</code> command. Here, the same as for C programs apply. If
447 the intention of SIGINT is to end your program, you have to exit in a
448 way that the calling programs "sees" that you have been killed. If
449 you don't catch SIGINT, this happend automatically, but of you catch
450 SIGINT, i.e. to do cleanup work, you have to end the program by
451 killing yourself, not by calling exit.
453 <p>Consider this example from FreeBSD's <code>mkdep</code>, which is a
458 trap 'rm -f $TMP ; trap 2 ; kill -2 $$' 1 2 3 13 15
461 Yes, you have to do it the hard way. It's even more annoying in shell
462 scripts than in C programs since you can't "pre-delete" temporary
463 files (which isn't really portable in C, though).
465 <P>All this applies to programs in all languages, not only C and
466 bourne shell. Every language implementation that lets you catch SIGINT
467 should also give you the option to reset the signal and kill yourself.
469 <P>It is always desireable to exit the right way, even if you don't
470 expect your usual callers to depend on it, some unusual one will come
471 along. This proper exit status will be needed for WCE and will not
472 hurt when the calling shell uses IUE or WUE.
474 <H3>How to be a proper shell</H3>
476 All this applies only for the script-executing case. Most shells will
477 also have interactive modes where things are different.
481 <LI>Do nothing special when SIGINT appears while you wait for a child.
482 You don't even have to remember that one happened.
484 <P><LI>Wait for child to exit, get the exit status. Do not truncate it
487 <P><LI>Look at WIFSIGNALED(status) and WTERMSIG(status) to tell
488 whether the child says "I exited on SIGINT: in my opinion the user
489 wants the shellscript to be discontinued".
491 <P><LI>If the latter applies, discontinue the script.
493 <P><LI>Exit. But since a shellscript may in turn be called by a
494 shellscript, you need to make sure that you properly communicate the
495 discontinue intention to the calling program. As in any other program
499 signal(SIGINT, SIG_DFL);
500 kill(getpid(), SIGINT);
505 <H3>Other remarks</H3>
507 Although this web page talks about SIGINT only, almost the same issues
508 apply to SIGQUIT, including proper exiting by killing yourself after
509 catching the signal and proper reaction on the WIFSIGNALED(status)
510 value. One notable difference for SIGQUIT is that you have to make
511 sure that not the whole call tree dumps core.
513 <H3>What to fight</H3>
515 Make sure all programs <em>really</em> kill themselves if they react
516 to SIGINT or SIGQUIT and intend to abort their operation as a result
517 of this signal. Programs that don't use SIGINT/SIGQUIT as a
518 termination trigger - but as part of normal operation - don't kill
519 themselves, but do a normal exit instead.
521 <p>Make sure people understand why you can't fake an exit-on-signal by
522 doing exit(...) using any numerical status.
524 <p>Make sure you use a shell that behaves right. Especially if you
525 develop programs, since it will help seeing problems.
527 <H3>Concrete examples how to fix programs:</H3>
530 <li>The fix for FreeBSD's
531 <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
532 it fixes a case where someone tried to fake signal exit status by a
533 numerical value. And the complete program is small.
535 <p><li>Fix for FreeBSD's
536 <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>.
538 <p><li>The fix for FreeBSD's
539 <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.
542 <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>,
543 <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>.
547 <H3>Testsuite for shells</H3>
549 I have a collection of shellscripts that test shells for the
550 behavior. See my <A HREF="download/">download dir</A> to get the newest
551 "sh-interrupt" files, either as a tarfile or as individual file for
552 online browsing. This isn't really documented, besides from the
553 comments the scripts echo.
555 <H3>Appendix 1 - table of implementation choices</H3>
557 <table border cellpadding=2>
562 <th>Example shells that implement it:</th>
563 <th>What happens when a shellscript called emacs, the user used
564 <code>C-g</code> and the script has additional commands in it?</th>
565 <th>What happens when a shellscript called emacs, the user did not use
566 <code>C-c</code> and the script has additional commands in it?</th>
567 <th>What happens if a non-interactive child catches SIGINT?</th>
568 <th>To behave properly, childs must do what?</th>
571 <tr valign=top align=left>
573 <td>The shell executing a script exits immediately if it receives
575 <td>4.4BSD ash (ash), NetBSD, FreeBSD prior to 3.0/22.8</td>
576 <td>The editor session is lost and subsequent commands are not
578 <td>The editor continues as normal and the subsequent commands are
580 <td>The scripts ends immediately, returning to the caller even before
581 the current foreground child of the shell exits. </td>
582 <td>It doesn't matter what the child does or how it exits, even if the
583 child continues to operate, the shell returns. </td>
586 <tr valign=top align=left>
588 <td>If the shell executing a script received SIGINT while a foreground
589 process was running, it will exit after that child's exit.</td>
590 <td>pdksh (OpenBSD /bin/sh)</td>
591 <td>The editor continues as normal, but subsequent commands from the
592 script are not executed.</td>
593 <td>The editor continues as normal and subsequent commands are
595 <td>The scripts returns to its caller after the current foreground
596 child exits, no matter how the child exited. </td>
597 <td>It doesn't matter how the child exits (signal status or not), but
598 if it doesn't return at all, the shell will not return. In no case
599 will further commands from the script be executed. </td>
602 <tr valign=top align=left>
604 <td>The shell exits if a child signaled that it was killed on a
605 signal (either it had the default handler for SIGINT or it killed
607 <td>bash (Linux /bin/sh), most commercial /bin/sh, FreeBSD /bin/sh
609 <td>The editor continues as normal and subsequent commands are
611 <td>The editor continues as normal and subsequent commands are
613 <td>The scripts returns to its caller after the current foreground
614 child exits, but only if the child exited with signal status. If
615 the child did a normal exit (even if it received SIGINT, but catches
616 it), the script will continue. </td>
617 <td>The child must be implemented right, or the user will not be able
618 to break shell scripts reliably.</td>
623 <P><img src=linie.png width="100%" alt=" ">
624 <BR>©2005 Martin Cracauer <cracauer @ cons.org>
625 <A HREF="http://www.cons.org/cracauer/">http://www.cons.org/cracauer/</A>
626 <BR>Last changed: $Date: 2005/02/11 21:44:43 $