zsh-workers
 help / Atom feed
* Why does zsh un-ignores SIGQUIT?
@ 2019-04-24  8:13 Stephane Chazelas
  2019-04-24 16:13 ` Peter Stephenson
  0 siblings, 1 reply; 5+ messages in thread
From: Stephane Chazelas @ 2019-04-24  8:13 UTC (permalink / raw)
  To: Zsh hackers list

$ (trap '' QUIT; grep SigIgn /proc/self/status; ./Src/zsh -c 'grep SigIgn /proc/self/status')
SigIgn: 0000000000000004
SigIgn: 0000000000000000

That only seems to be happening for SIGQUIT.

(that's from the current git HEAD)

-- 
Stephane

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Why does zsh un-ignores SIGQUIT?
  2019-04-24  8:13 Why does zsh un-ignores SIGQUIT? Stephane Chazelas
@ 2019-04-24 16:13 ` Peter Stephenson
  2019-04-25 21:17   ` Stephane Chazelas
  0 siblings, 1 reply; 5+ messages in thread
From: Peter Stephenson @ 2019-04-24 16:13 UTC (permalink / raw)
  To: zsh-workers

On Wed, 2019-04-24 at 09:13 +0100, Stephane Chazelas wrote:
> $ (trap '' QUIT; grep SigIgn /proc/self/status; ./Src/zsh -c 'grep SigIgn /proc/self/status')
> SigIgn: 0000000000000004
> SigIgn: 0000000000000000
> 
> That only seems to be happening for SIGQUIT.
> 
> (that's from the current git HEAD)

SIGQUIT is ignored internally within the shell, visible below the patched
code.  The shell knows if you've explicitly ignored SIGQUIT, but not if
it's ignored by inheritance when the shell starts.  The flag is tested
in entersubsh().

pws

diff --git a/Src/init.c b/Src/init.c
index e7e62e2f7..2d5c3296d 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -1234,6 +1234,15 @@ init_signals(void)
 
     intr();
 
+#ifdef POSIX_SIGNALS
+    {
+	struct sigaction act;
+	if (!sigaction(SIGQUIT, NULL, &act) &&
+	    act.sa_handler == SIG_IGN)
+	    sigtrapped[SIGQUIT] = ZSIG_IGNORED;
+    }
+#endif
+
 #ifndef QDEBUG
     signal_ignore(SIGQUIT);
 #endif


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Why does zsh un-ignores SIGQUIT?
  2019-04-24 16:13 ` Peter Stephenson
@ 2019-04-25 21:17   ` Stephane Chazelas
  2019-04-26 13:42     ` Peter Stephenson
  0 siblings, 1 reply; 5+ messages in thread
From: Stephane Chazelas @ 2019-04-25 21:17 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

2019-04-24 17:13:51 +0100, Peter Stephenson:
> On Wed, 2019-04-24 at 09:13 +0100, Stephane Chazelas wrote:
> > $ (trap '' QUIT; grep SigIgn /proc/self/status; ./Src/zsh -c 'grep SigIgn /proc/self/status')
> > SigIgn: 0000000000000004
> > SigIgn: 0000000000000000
> > 
> > That only seems to be happening for SIGQUIT.
> > 
> > (that's from the current git HEAD)
> 
> SIGQUIT is ignored internally within the shell, visible below the patched
> code.  The shell knows if you've explicitly ignored SIGQUIT, but not if
> it's ignored by inheritance when the shell starts.  The flag is tested
> in entersubsh().
[...patch skipped...]


Thanks,

that change seems to introduce a new inconsistency though. See
below.

POSIX does require that signals that were ignored upon startup
of the shell remain ignored.

POSIX> Signals that were ignored on entry to a non-interactive
POSIX> shell cannot be trapped or reset, although no error need
POSIX> be reported when attempting to do so. An interactive
POSIX> shell may reset or catch signals ignored on entry.

zsh, thankfully ignores that requirement. That's an annoying
requirement that probably has its origin on systems that didn't
have terminal job control (tcsetpgrp()...) and is usually a
nuisance today.

In zsh

   trap handler INT

Installs the "handler" on SIGINT even if SIGINT was ignored on
startup.

What I found out recently though
(https://unix.stackexchange.com/questions/513781/regain-ability-to-use-c-to-close-backgrounded-then-effectively-foregrounded-p/515159#515159)
is that it does seem to honour the POSIX requirement when it
comes to "resetting" the signal disposition (to its default).

In zsh

   trap - INT

Does not reset the default signal disposition of SIGINT if
SIGINT was ignored upon startup.

$ (trap "" INT; zsh -c 'trap - INT; grep SigIgn /proc/self/status')
SigIgn: 0000000000000002

One can work around that by setting a trap first:

$ (trap "" INT; zsh -c 'trap : INT; trap - INT; grep SigIgn /proc/self/status')
SigIgn: 0000000000000000

Even explicitely ignoring it will do:

$ (trap "" INT; zsh -c 'trap "" INT; trap - INT; grep SigIgn /proc/self/status')
SigIgn: 0000000000000000


Which brings us to this change, which means SIGQUIT is now
treated specially in this regard:

$ (trap "" INT QUIT; ./Src/zsh -c 'trap - INT QUIT; grep SigIgn /proc/self/status')
SigIgn: 0000000000000002

(with the diff applied)

I was able to reset the default handler for SIGQUIT but not for
SIGINT.

I wonder what the rationale is for why zsh will happily install a
handler on an ignored signal but not reset to default.

I can understand where the POSIX requirement is coming from.

When you do

myscript &

on a system that doesn't have job control, you don't want
processes started by the script to be killed when you press ^C.

Or when you do:

nohup myscript

You want myscript and all the processes it spawns to be immune
to hang-ups.

But I don't understand why zsh would let me set a handler but
not reset to default. It would make more sense to me if it was the
reverse. If I want to reset the default handler without having
set one in the first place, surely I know what I'm doing and
what I ask should be honoured.

Here, unless someone can think of a good reason why zsh behaves
the way it does, I'd suggest zsh ignore the POSIX requirement
altogether and honours what the user wants: apply the traps as
requested regardless of whether the signal was ignored on
startup or not, at least in zsh emulation.

Maybe honour the POSIX requirements in sh emulation.

While I'm at it, there's another related POSIX requirement that
I often find annoying:

In non-interactive shells.

cmd &

is meant to run cmd with SIGINT and SIGQUIT ignored (some form
of crude and ancient uncalled for job control).

That's actually more annoying than the other POSIX requirement
mentioned earlier.

When you do:

(cmd1 & cmd2) | cmd3


There's no reason cmd1 should not also be killed by SIGINT when
you press ^C.

That's where being able to cancel that ignoring of SIGINT can
come handy.

zsh does honour that latter requirement though.

What's the sentiment of zsh developer about potentially ignoring
that POSIX requirement as well? What can that break?

-- 
Stephane

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Why does zsh un-ignores SIGQUIT?
  2019-04-25 21:17   ` Stephane Chazelas
@ 2019-04-26 13:42     ` Peter Stephenson
  2019-04-26 14:03       ` Peter Stephenson
  0 siblings, 1 reply; 5+ messages in thread
From: Peter Stephenson @ 2019-04-26 13:42 UTC (permalink / raw)
  To: zsh-workers

On Thu, 2019-04-25 at 22:17 +0100, Stephane Chazelas wrote:
> I wonder what the rationale is for why zsh will happily install a
> handler on an ignored signal but not reset to default.

I think it's simply this in the removetrap() code...

    trapped = sigtrapped[sig];
...
    if (!trapped) {
	unqueue_signals();
        return NULL;
    }

If the signal was ignored on entry, it stays ignored (because that's
down in the OS), but zsh doesn't mark it as handled specially.  So
when we get the request to unset it we execute this code, shrugging our
shoulders and doing nothing.  For SIGQUIT we now do mark it as
handled specially.

Instead of laboriously setting up records for all signals, maybe we
could add a call to set the default signal handler in the "if" above?
At worst that should have no effect, probably.

pws


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Why does zsh un-ignores SIGQUIT?
  2019-04-26 13:42     ` Peter Stephenson
@ 2019-04-26 14:03       ` Peter Stephenson
  0 siblings, 0 replies; 5+ messages in thread
From: Peter Stephenson @ 2019-04-26 14:03 UTC (permalink / raw)
  To: zsh-workers

On Fri, 2019-04-26 at 14:42 +0100, Peter Stephenson wrote:
> On Thu, 2019-04-25 at 22:17 +0100, Stephane Chazelas wrote:
> > 
> > I wonder what the rationale is for why zsh will happily install a
> > handler on an ignored signal but not reset to default.
> I think it's simply this in the removetrap() code...
> 
>     trapped = sigtrapped[sig];
> ...
>     if (!trapped) {
> 	unqueue_signals();
>         return NULL;
>     }
> 
> If the signal was ignored on entry, it stays ignored (because that's
> down in the OS), but zsh doesn't mark it as handled specially.  So
> when we get the request to unset it we execute this code, shrugging our
> shoulders and doing nothing.  For SIGQUIT we now do mark it as
> handled specially.
> 
> Instead of laboriously setting up records for all signals, maybe we
> could add a call to set the default signal handler in the "if" above?
> At worst that should have no effect, probably.

Reading through, I think simply omitting that block should have the right
effect --- all the specific internal effects later in the function are
protected by their own "if"s, so this has the desired effect of only
fixing up the OS state.

I'm not going to commit this immediately.

diff --git a/Src/signals.c b/Src/signals.c
index f294049c2..14218177a 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -1011,10 +1011,6 @@ removetrap(int sig)
 	(!trapped || locallevel > (sigtrapped[sig] >> ZSIG_SHIFT)))
 	dosavetrap(sig, locallevel);
 
-    if (!trapped) {
-	unqueue_signals();
-        return NULL;
-    }
     if (sigtrapped[sig] & ZSIG_TRAPPED)
 	nsigtrapped--;
     sigtrapped[sig] = 0;



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, back to index

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-24  8:13 Why does zsh un-ignores SIGQUIT? Stephane Chazelas
2019-04-24 16:13 ` Peter Stephenson
2019-04-25 21:17   ` Stephane Chazelas
2019-04-26 13:42     ` Peter Stephenson
2019-04-26 14:03       ` Peter Stephenson

zsh-workers

Archives are clonable: git clone --mirror http://inbox.vuxu.org/zsh-workers

Newsgroup available over NNTP:
	nntp://inbox.vuxu.org/vuxu.archive.zsh.workers


AGPL code for this site: git clone https://public-inbox.org/ public-inbox