#683671 dash doesn't ignore SIGINT when running a command that traps SIGINT, should implement WCE

Package:
dash
Source:
dash
Description:
POSIX-compliant shell
Submitter:
Vincent Lefevre
Date:
2026-01-03 00:19:02 UTC
Severity:
important
Tags:
#683671#5
Date:
2012-08-02 17:06:19 UTC
From:
To:
When running an interactive command, dash doesn't ignore SIGINT
and SIGQUIT.

For instance, here's what I get with Emacs 24 (not a previous
version, since previously, Emacs had its own progress group,
so that the bug wasn't visible), by typing Ctrl-G Ctrl-X Ctrl-C
in Emacs:

$ bash -c "emacs -Q -nw; echo foo"; echo bar
foo
bar
$ dash -c "emacs -Q -nw; echo foo"; echo bar

$ echo $?
130
$

The main problem is that dash is generally used as /bin/sh, thus
by the system() command (or equivalent). So, typing Ctrl-G in an
Emacs running in a terminal has the effect to make the sh shell
fail, without any possible workaround. This affects applications
that run an editor such as Subversion (svn command) and Mutt.

For instance, with svn:

$ SVN_EDITOR=emacs svn ci
svn: E200012: Commit failed (details follow):
svn: E200012: system('emacs svn-commit.tmp') returned 2
svn: E200012: Your commit message was left in a temporary file:
svn: E200012:    '/home/vinc17/wd/db/svn-commit.tmp'

zsh: interrupt  SVN_EDITOR=emacs svnwrapper ci

According to Andreas Schwab[*], this is a bug in dash. And indeed,
the system(3) man page says:

      system()  executes a command specified in command by calling
      /bin/sh -c command, and returns after the command  has  been
      completed.  During execution of the command, SIGCHLD will be
      blocked, and SIGINT and SIGQUIT will be ignored.

[*] http://debbugs.gnu.org/cgi/bugreport.cgi?bug=11886#17

#683671#10
Date:
2012-08-02 18:03:11 UTC
From:
To:
severity 683671 serious
# not Debian-specific
tags 683671 + upstream moreinfo
quit

Hi Vincent,

Vincent Lefevre wrote:

Can you explain that more precisely?  At first glance it seems like an
ordinary important bug.

[...]

Thanks for the pointer.

http://unix.org/2008edition/ tells me:

  When a command is in an asynchronous list, it shall inherit from the
  shell a signal action of ignored (SIG_IGN) for the SIGQUIT and
  SIGINT signals, and may inherit a signal mask in which SIGQUIT and
  SIGINT are blocked. Otherwise, the signal actions and signal mask
  inherited by the command shall be the same as those inherited by the
  shell from its parent unless a signal action is modified by the trap
  special built-in (see trap )

In 'sh -c "emacs -nw"', the emacs command is not in an asynchronous
list, so I would suspect that emacs is supposed to inherit the same
signal actions as the shell inherited.

How about this patch (which at least gets rid of a mysterious code
artifact)?

Curious,
Jonathan

diff --git a/src/trap.c b/src/trap.c
index 17316c9..1fa835b 100644
--- a/src/trap.c
+++ b/src/trap.c
@@ -347,7 +347,7 @@ setinteractive(int on)
 {
 	static int is_interactive;

-	if (++on == is_interactive)
+	if (on == is_interactive)
 		return;
 	is_interactive = on;
 	setsignal(SIGINT);

#683671#19
Date:
2012-08-07 12:40:19 UTC
From:
To:
Hi Jonathan,

Emacs is often called by other programs, and possibly from a /bin/sh
script, with postprocessing. Here's a simple example:

#!/bin/sh
trap 'true' INT
sh -c 'emacs -nw tmpfile; mv tmpfile newfile'
rm -f tmpfile
cat newfile
rm -f newfile

If Ctrl-G is typed in Emacs, the data are lost. Even though a
correction could be done on such a simple example, in real
applications, this is less obvious. And how do we do the difference
between (1) a real SIGINT from Ctrl-C, meaning that the user is no
longer interested in the data and clean-up can be done, and (2) a
SIGINT coming from a bug, meaning that temporary files should be
left on the disk and the user should guess where his data are and
what they mean?

This paragraph is about signals inherited by the command. Here the
question is what the shell should do with SIGINT/SIGQUIT signals it
receives while it is executing a command which is not killed by the
signal?

Not that how the command is affected by the signal is important.
See the difference between:

#!/bin/sh
trap 'true' INT
bash -c 'date > tmpfile; sleep 5; mv tmpfile newfile'
rm -f tmpfile
cat newfile
rm -f newfile

with Ctrl-C during the "sleep 5", and:

#!/bin/sh
trap 'true' INT
bash -c 'date > tmpfile; emacs -nw; mv tmpfile newfile'
rm -f tmpfile
cat newfile
rm -f newfile

with Ctrl-G in Emacs. You can also try:

#!/bin/sh
trap 'true' INT
bash -c 'date > tmpfile; gdb; mv tmpfile newfile'
rm -f tmpfile
cat newfile
rm -f newfile

with Ctrl-C in gdb.

If bash is replaced by dash, one always gets a failure, not just in
the first case.

Since there was a similar problem with zsh and GNU Emacs under
Mac OS X (and I really lost data several times, until I identified
the problem, but contrary to here, the problem was occurring with
all Emacs versions[*]), I now remember this page:

http://www.cons.org/cracauer/sigint.html

It probably gives the answer of what should be done.

[*] http://www.zsh.org/mla/workers/2009/msg00926.html

#683671#26
Date:
2012-08-07 15:26:46 UTC
From:
To:
Vincent Lefevre wrote:

Weird.  Why does system(3) claim it sets SIGINT to SIG_IGN, then?

Puzzled,
Jonathan

#683671#31
Date:
2012-08-07 16:47:15 UTC
From:
To:
Well, this is from POSIX:

http://pubs.opengroup.org/onlinepubs/9699919799/functions/system.html

It is said:

  The system() function shall behave as if a child process were
  created using fork(), and the child process invoked the sh utility
  using execl() as follows:

    execl(<shell path>, "sh", "-c", command, (char *)0);

  where <shell path> is an unspecified pathname for the sh utility. It
  is unspecified whether the handlers registered with pthread_atfork()
  are called as part of the creation of the child process.

  The system() function shall ignore the SIGINT and SIGQUIT signals,
  and shall block the SIGCHLD signal, while waiting for the command to
  terminate. If this might cause the application to miss a signal that
  would have killed it, then the application should examine the return
  value from system() and take whatever action is appropriate to the
  application if the command terminated due to receipt of a signal.

The rationale makes it clear about which process(es) shall ignore
these signals:

  Ignoring SIGINT and SIGQUIT in the parent process prevents
  coordination problems (two processes reading from the same terminal,
  for example) when the executed command ignores or catches one of the
  signals.

and from the example implementation, one can see that the previous
actions are restored in the child, just before executing /bin/sh.

This contradicts the glibc manual, which doesn't claim to do anything
concerning signals in the system() implementation (and in some other
discussion, it was said that glibc does only what is written):

#683671#36
Date:
2012-08-08 08:38:58 UTC
From:
To:
Vincent Lefevre wrote:

Ah, I should have remembered.  That's the right behavior for system(),
and it's what glibc does.  (I'm afraid I have no interest in fixing
the glibc manual, since its copyright holders have chosen to use an
unpleasant license and stick to it and there is better documentation
available elsewhere.)

Thanks,
Jonathan

#683671#41
Date:
2012-08-28 11:05:45 UTC
From:
To:
Hi,

this bug log now suggests that zsh is in the same boat and the bug
possibly lies within emacs.  Do you still think it's a release-critical
bug in dash?

Thanks, Gerrit.

#683671#44
Date:
2012-08-28 11:22:39 UTC
From:
To:
spamcop is wrong.
----- Forwarded message from MAILER-DAEMON@a.mx.smarden.org ----- Date: 28 Aug 2012 11:12:28 -0000 From: MAILER-DAEMON@a.mx.smarden.org Subject: failure notice Hi. This is the qmail-send program at a.mx.smarden.org. I'm afraid I wasn't able to deliver your message to the following addresses. This is a permanent error; I've given up. Sorry it didn't work out. <vincent@vinc17.net>: 92.243.22.117 does not like recipient. Remote host said: 554 5.7.1 Service unavailable; Client host [176.74.58.109] blocked using bl.spamcop.net; Blocked - see http://www.spamcop.net/bl.shtml?176.74.58.109 Giving up on 92.243.22.117.
--- Below this line is a copy of the message. Received: (qmail 3983 invoked by uid 1000); 28 Aug 2012 11:05:45 -0000 Message-ID: <20120828110545.3982.qmail@818822b293fcc9.315fe32.mid.smarden.org> Date: Tue, 28 Aug 2012 11:05:45 +0000 From: Gerrit Pape <pape@smarden.org> To: Vincent Lefevre <vincent@vinc17.net>, 683671@bugs.debian.org Cc: Jonathan Nieder <jrnieder@gmail.com> Subject: Re: Bug#683671: dash doesn't ignore SIGINT when running an interactive command Reply-To: Vincent Lefevre <vincent@vinc17.net>, 683671@bugs.debian.org, Jonathan Nieder <jrnieder@gmail.com> References: <20120802170618.GA18343@ypig.lip.ens-lyon.fr> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20120802170618.GA18343@ypig.lip.ens-lyon.fr> Hi, this bug log now suggests that zsh is in the same boat and the bug possibly lies within emacs. Do you still think it's a release-critical bug in dash? Thanks, Gerrit.
----- End forwarded message -----
#683671#49
Date:
2012-08-28 12:36:59 UTC
From:
To:
Well, contrary to dash, zsh is not meant to be a POSIX shell, and
cannot (must not) be used as /bin/sh (zsh has a sh emulation mode,
but it is not perfect, and its status is quite unclear). This is
one major point.

However I think that any application that uses the INTR character
for its own, internal purpose should put itself in its own process
group to avoid side effects. But if developers don't agree, the
problem must be dealt with in the shell. Note that

http://pubs.opengroup.org/onlinepubs/9699919799/functions/system.html

(see "Application Usage" and "Rationale") suggests that it's up to
the callers (the system() implementation and, by extension, the sh
implementation) to do the necessary to ignore signals when need be.
The fact that dash implements WUE instead of IUE avoids the most
important problems mentioned at the above URL, though.

Moreover gdb has the same problem as Emacs, though problems are less
likely to appear in practice than with Emacs (an editor is much more
often called by system() than gdb).

I think that the current status may badly affect the usual use of
some applications like Emacs. The fact that there are, AFAIK, no
workarounds (except by not using dash, e.g. by changing the /bin/sh
symlink) makes me think that it should still be a RC bug.

#683671#54
Date:
2012-10-30 22:38:14 UTC
From:
To:
Would you mind if this were reassigned to release-notes?  It would say
something along the lines of "Dash is not yet ready as an interactive
shell, bash is currently the only recommended posix-compliant shell.
You will experience issues such as #683671 using dash interactively."

In the meantime, this should be reported to the upstream dash
developers so they can start working on a fix.

Best wishes,
Mike

#683671#57
Date:
2012-10-30 22:38:14 UTC
From:
To:
Would you mind if this were reassigned to release-notes?  It would say
something along the lines of "Dash is not yet ready as an interactive
shell, bash is currently the only recommended posix-compliant shell.
You will experience issues such as #683671 using dash interactively."

In the meantime, this should be reported to the upstream dash
developers so they can start working on a fix.

Best wishes,
Mike

#683671#62
Date:
2012-10-30 22:46:40 UTC
From:
To:
Michael Gilbert wrote:

I think that's an overstatement.  Maybe "Dash in Debian is not intended
to be used as an interactive shell" could be accurate, though.

Please don't reassign this bug, but feel free to clone it and lower
the severity.

Thanks,
Jonathan

#683671#65
Date:
2012-10-30 22:46:40 UTC
From:
To:
Michael Gilbert wrote:

I think that's an overstatement.  Maybe "Dash in Debian is not intended
to be used as an interactive shell" could be accurate, though.

Please don't reassign this bug, but feel free to clone it and lower
the severity.

Thanks,
Jonathan

#683671#70
Date:
2012-10-30 23:59:30 UTC
From:
To:
The word "interactive" is incorrect, because when the shell is used
to run some program (e.g. via C's system() function), it is not
interactive.

Yes, this is really a bug in dash IMHO, but Emacs is partly in fault
because the Ctrl-G will also send the signal in the other processes in
the same process group an Emacs (though this may not be very common).
The current situation is extremely annoying. :(

#683671#75
Date:
2012-12-05 16:34:29 UTC
From:
To:
[also sent to 683671@b.d.o since this concerns dash; for reportbug,
one should do a test with bash as /bin/sh to see whether reportbug
is really buggy or if this is just a consequence of the dash bug.]

I couldn't try because the Debian BTS doesn't have a test system
(due avoid creating a dummy bug report), but a Ctrl-C in Mutt
also sends a SIGINT to the whole process group (as expected),
even when one doesn't quit Mutt and Mutt terminates normally.
So, even if the problem is "fixed" (avoided) in Emacs, the real
problem still exists.

#683671#80
Date:
2013-01-26 12:42:02 UTC
From:
To:
Control: severity -1 important

I don't think this should be a blocker for release.  Downgrading.

Cheers,
Julien

#683671#89
Date:
2020-02-11 02:36:32 UTC
From:
To:
# hello, control, been a while...
tag 683671 + patch fixed-upstream
thanks

Hi Andrej et al.,

After independently encountering and then debugging this problem to the point where I had a fix, I learned that Antonio Ospite had come up with an identical one (modulus whitespace) over a year ago[1].  I've attached a copy.

It really sucks that dash has had this bug for 12 years, given that:
1. It's Debian's default /bin/sh;
2. We're required by Policy to 'set -e' in our maintainer scripts[2]; and
3. Script authors generally don't write signal handlers for fun--they do it because they need to clean up or roll back some activity, and this bug utterly frustrates their efforts.

Were I active in the project, I'd be raising hell like in the old days to get this bug's severity back up to 'serious', on the premise that it frustrates the robustness of maintainer scripts that we try to ensure with 'set -e' in the first place.

The fix is a transposition of one line; please consider applying it.

I notice there are other fixes in the git repo, also usually from Antonio Ospite, for various compiler warnings.  Those may be worthy of consideration in a near-term package release as well.

Cheers!

[1] https://git.kernel.org/pub/scm/utils/dash/dash.git/commit/?id=06204f0c9f539fcb8cb532166656e80b81bd689a
[2] https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html

#683671#94
Date:
2020-02-11 02:36:32 UTC
From:
To:
# hello, control, been a while...
tag 683671 + patch fixed-upstream
thanks

Hi Andrej et al.,

After independently encountering and then debugging this problem to the point where I had a fix, I learned that Antonio Ospite had come up with an identical one (modulus whitespace) over a year ago[1].  I've attached a copy.

It really sucks that dash has had this bug for 12 years, given that:
1. It's Debian's default /bin/sh;
2. We're required by Policy to 'set -e' in our maintainer scripts[2]; and
3. Script authors generally don't write signal handlers for fun--they do it because they need to clean up or roll back some activity, and this bug utterly frustrates their efforts.

Were I active in the project, I'd be raising hell like in the old days to get this bug's severity back up to 'serious', on the premise that it frustrates the robustness of maintainer scripts that we try to ensure with 'set -e' in the first place.

The fix is a transposition of one line; please consider applying it.

I notice there are other fixes in the git repo, also usually from Antonio Ospite, for various compiler warnings.  Those may be worthy of consideration in a near-term package release as well.

Cheers!

[1] https://git.kernel.org/pub/scm/utils/dash/dash.git/commit/?id=06204f0c9f539fcb8cb532166656e80b81bd689a
[2] https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html

#683671#99
Date:
2020-02-11 02:59:31 UTC
From:
To:
[...]

I don't see the relation with bug 683671.

#683671#104
Date:
2020-02-11 02:59:31 UTC
From:
To:
[...]

I don't see the relation with bug 683671.

#683671#107
Date:
2020-02-11 02:59:31 UTC
From:
To:
[...]

I don't see the relation with bug 683671.

#683671#112
Date:
2020-02-11 03:12:21 UTC
From:
To:
tag 683671 - patch fixed-upstream
tag 779416 + patch fixed-upstream
thanks

Hi Vincent,

Er, it appears that I misunderstood the discussion in the bug history.

I had been fixing a bug where an INT signal handler improperly did not reraise INT against itself, and had Martin Cracauer's article on INT, QUIT and shell signal handlers[1] fresh in my brain.  When I addressed the bad signal handler issue I was startled that dash did not behave according to my expectations.

I prepared to file a bug against dash, and when scanning the existing bug list I found this one and, perhaps hastily, concluded that it was the same issue.

Re-reviewing the list of open bugs against dash, it looks like I should have stumbled across #779416 instead.

I apologize for my error.  Thanks for the clarification.

Cheers!

[1] https://www.cons.org/cracauer/sigint.html

[...]

I don't see the relation with bug 683671.

#683671#119
Date:
2024-10-11 21:53:10 UTC
From:
To:
Hello,
is there any progress on this [bug]?

Was it forwarded upstream?
Are the upstream developers willing to fix it?

[bug]: <https://bugs.debian.org/683671>

#683671#124
Date:
2026-01-02 23:10:40 UTC
From:
To:
Please let me know, thanks for your time and understanding.
#683671#129
Date:
2026-01-02 23:59:02 UTC
From:
To:
Hi,

I can no longer reproduce the bug. I'm wondering whether there
has been a change in Emacs or in dash...

#683671#134
Date:
2026-01-03 00:17:15 UTC
From:
To:
Control: found -1 0.5.12-12

It seems to be Emacs. Here's another testcase (type Ctrl-C just
after running the command):

$ dash -c 'echo foo; bash -c "trap \"echo Interrupt; exit 0\" INT; sleep 5"'; echo OK
foo
^CInterrupt

$ bash -c 'echo foo; bash -c "trap \"echo Interrupt; exit 0\" INT; sleep 5"'; echo OK
foo
^CInterrupt
OK
$ ksh93 -c 'echo foo; bash -c "trap \"echo Interrupt; exit 0\" INT; sleep 5"'; echo OK
foo
^CInterrupt
OK
$ mksh -c 'echo foo; bash -c "trap \"echo Interrupt; exit 0\" INT; sleep 5"'; echo OK
foo
^CInterrupt

$

So dash still doesn't implement WCE.

Ditto for mksh. FYI, the mksh Debian bug was closed because mksh
upstream bugs are not tracked in Debian, and its upstream bug is

https://bugs.launchpad.net/mksh/+bug/1064726

For dash, I don't know whether it has been reported upstream.
According to its home page, there's just a mailing-list, and the
archive website is broken: 503 Service Temporarily Unavailable