bug-gawk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [bug-gawk] system() should return != 0 when the process is killed


From: Stephane Chazelas
Subject: Re: [bug-gawk] system() should return != 0 when the process is killed
Date: Sat, 5 Mar 2016 08:47:36 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

[repost as my first posting via gmane NNTP yesterday seems not
to have gone through]

2016-03-03 17:58:25 +0100, Tobia Conforto:
[...]
> It looks like gawk's system() only returns bits 8 to 15 (or s>>8) of the
> value returned by system(3), discarding any information about the
> termination of the child process by a signal.
>
> This breaks use cases like this (and probably others):
>
>     do {
>         ...
>     } while (! system("sleep 10"))
>
> where the intention is to break the loop when the user interrupts (^C) the
> child process.
>
> It would arguably be better if gawk returned a composite code, as
> traditionally done by most shells and interpreters, for example (s&127)+128
> if killed, s>>8 otherwise, as in Bash.
>
> Other awk implementations (nawk, bwk-awk, and mawk) always return values !=
> 0 when the child process executed by system() is killed by a signal.
[...]

Note that there's also a problem with close() on a getline
pipeline.

That's probably something that should be clarified in the POSIX
spec first. Or gawk could go with the mawk approach which seems
the most consistent to me.

See also:
http://unix.stackexchange.com/questions/267415/make-bash-exit-0-when-called-by-awk-and-interrupted-with-c/267424#267424
for more context, reproduced below:

What awk's system() should return [1]is poorly specified.

What seems to be common among awk implementations is that upon a normal
exit, it returns the exit code (the number passed to exit(3) modulo
256), but when the shell process is killed by a signal, there's a lot of
different behaviour.

Also note that while the C function system(3) is meant to ignore SIGINT
(and SIGQUIT) in the parent, it's not very clear (to me at least) that
the requirement also applies to awk's system(). Some awk implementations
(like mawk) will die upon that SIGINT (that's also the behaviour I'd
like to see as I don't like my CTRL-C being ignored just because awk
happens to be running the system() function), some (like gawk or
traditional implementations) won't.

Also note that some shells can intercept some of those signals and
eventually call exit() which would affect the behaviour (see the
discussion in comments about the Bourne shell for instance), which is
why I use exec in the examples below to remove the shell from the loop.

For the value returned by system() (there's even more variation if you
consider close()^1) upon a SIGINT, we see:

$ nawk 'BEGIN {print system("exec kill -s INT $$")}'
0.0078125
$ bwk-awk 'BEGIN {print system("exec kill -s INT $$")}'
0.0078125
$ mawk 'BEGIN {print system("exec kill -s INT $$")}'
130
$ gawk 'BEGIN {print system("exec kill -s INT $$")}'
0

0.0078125 being 2 / 256 (for a SEGV of 11, you'd get 0.542969
((128+11)/256) if a core was dumped, 0.0429688 (11/256) otherwise), nawk
being the nawk found on Solaris 10 or 11, or its Linux port in the
Heirloom toolchest, bwk-awk being [2]the awk maintained by Brian
Kernighan himself (the K in awk) the basis for the awk found on some
BSDs (here tested on Debian GNU/Linux). /usr/xpg4/bin/awk on Solaris 11
behaves like gawk.

So based on the value s returned by system(3) (an integer where bits 0
to 6 are the signal number, bit 7 the core-bit, and bits 8 to 15 the
exit code), awk's system() above returns either:

  * s / 256 (traditional awk implementations),
  * int(s/256) (gawk),
  * or in mawk, the same transformation as done by shells like the
    Bourne or C-shell for instance ((s&127)+128 if killed, s>>8
    otherwise), except that if a core is dumped, you get (s&127)+256
    instead of (s&127)+128 (the value is (s&255)+128).

So, here, you could do instead:

awk 'BEGIN{print system("trap exit\\ 1 INT; sleep 10")}'

But it would still cause awk to be killed with some awk implementations
like mawk. If your sh is bash or yash, you could do:

awk 'BEGIN{print system("set -m; sleep 10; exit")}'

So sleep is run in its own process group (and only it gets the SIGINT).

Another alternative could be to ignore SIGINT before calling awk.
However, most shells (and that's a POSIX requirement) cannot change a
signal handler if the signal was already ignored on start. So things
like:

(
  trap '' INT
  awk 'BEGIN{print system("trap exit\\ 1 INT; sleep 10; exit")}'
)

Won't work. zsh doesn't have that (self-inflicted) limitation though, so
if you know zsh is available, you could do:

(
  trap '' INT
  awk 'BEGIN{print system("exec zsh -c \"TRAPINT() exit 1; sleep 10\"")}'
)

Which would work whether awk is mawk, gawk or other and would avoid
having to mess with job control. At this point though, it would be worth
considering using perl/python/ruby... instead of awk where you can adapt
the signal handling to your needs.

Notes

^1 Upon close() of a pipeline, as in:

awk 'BEGIN {cmd = "kill -s INT $$"; cmd | getline; print close(cmd)}'

First, this time ^C interrupts awk in all implementations I've tried
(there's not such requirement to ignore SIGINT/SIGQUIT for
popen(3)/pclose(3) (a natural way to implement that getline) as there is
for system(3)).

But when it comes to the exit status (where s is the value returned by
pclose(3)/waitpid(2) like for system() above), we see:

  * Solaris nawk: doesn't work, you can't call close() like that in
    Solaris nawk.
  * /usr/xpg4/bin/awk on Solaris. Returns always 0, even upon a exit(1)
    done by the process. Clearly a conformance bug.
  * gawk: returns s&255 if killed (includes the core bit), s>>8
    otherwise.
  * bwk-awk: gives s (exit 1 gives 256, killed by SIGINT gives 2, killed
    by SIGSEGV with core gives 139).
  * mawk: same as for system(), looks like mawk is the only
    implementation that gave any thought into that.

References

   Visible links
   1. http://austingroupbugs.net/view.php?id=947#c2657
   2. http://www.cs.princeton.edu/%7Ebwk/btl.mirror/

-- 
Stephane



reply via email to

[Prev in Thread] Current Thread [Next in Thread]