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: Fri, 4 Mar 2016 22:50:13 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

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.

   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) (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]