summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2015-02-19 04:13:20 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2015-02-19 04:13:20 +0000
commite1fe79a9e705e3cab8f632cdbe8e1774cdef2761 (patch)
treefcf1e195e4025ca14b7caea13c0da41fca15ea97
parentc73a41da14650d93801a59b85757a73741be986f (diff)
downloadexecline-2.1.0.0.tar.xz
- exit code overhaul: forx, forbacktickx, loopwhilex, if, ifelse, ifte,v2.1.0.0
ifthenelse - new -o option to forx, forbacktickx, loopwhilex - documentation updated - version: rc for 2.1.0.0
-rw-r--r--INSTALL2
-rw-r--r--doc/exitcodes.html97
-rw-r--r--doc/forbacktickx.html18
-rw-r--r--doc/foreground.html9
-rw-r--r--doc/forx.html16
-rw-r--r--doc/if.html4
-rw-r--r--doc/ifelse.html3
-rw-r--r--doc/ifte.html3
-rw-r--r--doc/ifthenelse.html3
-rw-r--r--doc/index.html4
-rw-r--r--doc/loopwhilex.html25
-rw-r--r--doc/upgrade.html12
-rw-r--r--package/info2
-rw-r--r--src/execline/forbacktickx.c128
-rw-r--r--src/execline/forx.c21
-rw-r--r--src/execline/if.c8
-rw-r--r--src/execline/ifelse.c6
-rw-r--r--src/execline/ifte.c6
-rw-r--r--src/execline/ifthenelse.c4
-rw-r--r--src/execline/loopwhilex.c25
20 files changed, 273 insertions, 123 deletions
diff --git a/INSTALL b/INSTALL
index 4f04ae1..9a8f893 100644
--- a/INSTALL
+++ b/INSTALL
@@ -6,7 +6,7 @@ Build Instructions
- A POSIX-compliant C development environment
- GNU make version 4.0 or later
- - skalibs version 2.3.0.0 or later: http://skarnet.org/software/skalibs/
+ - skalibs version 2.3.1.0 or later: http://skarnet.org/software/skalibs/
This software will run on any operating system that implements
POSIX.1-2008, available at:
diff --git a/doc/exitcodes.html b/doc/exitcodes.html
new file mode 100644
index 0000000..4b8afda
--- /dev/null
+++ b/doc/exitcodes.html
@@ -0,0 +1,97 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>execline: exit codes</title>
+ <meta name="Description" content="execline: exit codes" />
+ <meta name="Keywords" content="execline exit codes" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">execline</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> How to propagate exit codes up a process dynasty </h1>
+
+<p>
+ Say we have a parent process <em>P</em>, child of a grandparent process
+<em>G</em>, spawning a child process <em>C</em> and waiting for it.
+Either <em>C</em> dies normally with an exit code from 0 to 255, or it is
+killed by a signal.
+ How can we make sure that <em>P</em> reports to <em>G</em> what happened
+to <em>C</em>, with as much precision as possible&nbsp;?
+</p>
+
+<p>
+ The problem is, there's more information in a wstat (the
+structure filled in by
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html">waitpid()</a>)
+than a process can report by
+simply exiting. <em>P</em> could exit with the same exit code as <em>C</em>,
+but then what should it do if C has been killed by a signal&nbsp;?
+</p>
+
+<p>
+ An idea is to have <em>P</em> kill itself with the same signal that killed
+<em>C</em>.
+But that's actually not right, because <em>P</em> itself could be killed by a
+signal from another source, and G needs that information. "<em>P</em> has been
+killed by a signal" and "<em>C</em> has been killed by a signal" are two
+different informations, so they should not be reported in the same way.
+</p>
+
+<p>
+ So, any way you look at it, there is always more information than we
+can report.
+</p>
+
+<p>
+Shells have their own
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_08_02">convention</a>
+for reporting crashes, but since any exit code greater than 127 is reported
+as is, the information given by the shell is unreliable: "child exited 129"
+and "child was killed by SIGHUP" are indistinguishable. When shells get
+nested, all bets are off - the information conveyed by exit codes becomes
+devoid of meaning pretty fast. We need something better.
+</p>
+
+<h2> execline's solution </h2>
+
+<p>
+execline commands such as <a href="forx.html">forx</a>, that can report
+a child's exit code, proceed that way when they're in the position of
+<em>P</em>:
+</p>
+
+<ul>
+ <li> If <em>C</em> was killed by a signal: <em>P</em> exits 128 plus the
+signal number. </li>
+ <li> If <em>C</em> exited 128 or more: <em>P</em> exits 128. </li>
+ <li> Else, <em>P</em> exits with the same code as <em>C</em>. </li>
+</ul>
+
+<p>
+ Rationale:
+</p>
+
+<ul>
+ <li> 128+ exit codes are extremely rare and should report really
+problematic conditions; commands usually exit 127 or less. If <em>C</em>
+exits 128+, it's more important to convey the information
+"something really bad happened, but the <em>C</em> process itself was not
+killed by a signal" than the exact nature of the event. </li>
+ <li> Commands following that convention can be nested. If <em>P</em> exits
+129+, <em>G</em> knows that <em>C</em> was
+killed by a signal. If <em>G</em> also needs to report that to its parent,
+it will exit 128: <em>G</em>'s parent will not know the signal number, but
+it will know that <em>P</em> reported 128 or more, so either <em>C</em> or
+a scion of <em>C</em> had problems. </li>
+ <li> Exact information is reported in the common case. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/forbacktickx.html b/doc/forbacktickx.html
index d40799a..0780f3d 100644
--- a/doc/forbacktickx.html
+++ b/doc/forbacktickx.html
@@ -29,7 +29,7 @@ run another program.
</p>
<pre>
- forbacktickx [ -p | -x breakcode ] [ -n ] [ -C | -c ] [ -0 | -d <em>delim</em> ] <em>variable</em> { <em>gen...</em> } <em>loop...</em>
+ forbacktickx [ -p | -o <em>okcodes</em> | -x <em>breakcodes</em> ] [ -n ] [ -C | -c ] [ -0 | -d <em>delim</em> ] <em>variable</em> { <em>gen...</em> } <em>loop...</em>
</pre>
<ul>
@@ -56,11 +56,17 @@ exiting, though. </li>
<li> <tt>-0</tt>&nbsp;: accept null characters from <em>gen</em>'s output,
using them as delimiters. If this option and a <tt>-d</tt> option are
used simultaneously, the rightmost one wins. </li>
- <li> <tt>-x</tt>&nbsp;<em>breakcodes</em>&nbsp;: <em>breakcodes</em> must
-be a comma-separated list of exit codes. If at some point <em>loop...</em>
-exits with a code listed in <em>breakcodes</em>, forbacktickx will not keep
-looping, but will exit immediately with the same exit code. This doesn't apply
-if the <tt>-p</tt> option has been given. </li>
+ <li> <tt>-o</tt>&nbsp;<em>okcodes</em>&nbsp;: <em>okcodes</em> must
+be a comma-separated list of exit codes. If the <tt>-p</tt> flag
+hasn't been given and <em>loop</em> exits with one of the codes in
+<em>okcodes</em>,
+forbacktickx will run the following instances of the loop, but if the exit code is
+not listed in <em>okcodes</em>, forbacktickx will exit immediately with an
+<a href="exitcodes.html">approximation</a> of the same exit code. </li>
+ <li> <tt>-x</tt>&nbsp;<em>breakcodes</em>&nbsp;: like the previous
+option, but with inverted meaning - the listed exit codes are codes
+that will make forbacktickx break the loop and exit, and the unlisted exit
+codes will make it keep looping. </li>
<li> Other options are used to <a href="el_transform.html">control
the substitution mechanism</a> for every <em>x</em>. Of course, you can't
split <em>x</em>. </li>
diff --git a/doc/foreground.html b/doc/foreground.html
index a2a465f..c0928e9 100644
--- a/doc/foreground.html
+++ b/doc/foreground.html
@@ -37,7 +37,8 @@
executes it, then waits for it to complete. </li>
<li> <tt>foreground</tt> sets the <tt>?</tt> environment
variable to the exit code of <em>prog1</em>. If <em>prog1...</em>
-did not exit normally, the <tt>?</tt> value is 111. </li>
+was killed by a signal, the <tt>?</tt> value is 256 plus the signal
+number. </li>
<li> <tt>foreground</tt> then execs into <em>prog2...</em>. </li>
</ul>
@@ -51,6 +52,12 @@ wrap external commands that exit instead of natively supporting the
<li> <tt>foreground <em>prog1...</em> "" <em>prog2...</em></tt> is
equivalent to <tt>sh -c '<em>prog1...</em> ; exec <em>prog2...</em>'</tt>.
</li>
+ <li> 256 and above are not valid exit codes for commands, so when the
+<tt>?</tt> environment variable contains 256 or more, it means that the
+previous command was killed by a signal. There is no ambiguity here, and
+<tt>?</tt> reports exactly what happened to the previous command;
+<tt>foreground</tt> does not exit, so there is no need for
+<a href="exitcodes.html">exit code approximation</a>. </li>
</ul>
</body>
diff --git a/doc/forx.html b/doc/forx.html
index 0349a85..0ed4799 100644
--- a/doc/forx.html
+++ b/doc/forx.html
@@ -28,7 +28,7 @@
</p>
<pre>
- forx [ -p | -x <em>breakcodes</em> ] <em>variable</em> { <em>args...</em> } <em>loop...</em>
+ forx [ -p | -o <em>okcodes</em> | -x <em>breakcodes</em> ] <em>variable</em> { <em>args...</em> } <em>loop...</em>
</pre>
<ul>
@@ -48,11 +48,17 @@ That block contains a list of <em>args</em>. </li>
<em>loop...</em> to exit before spawning the next one. <tt>forx</tt>
will still wait for all instances of <em>loop</em> to terminate before
exiting, though. </li>
- <li> <tt>-x</tt>&nbsp;<em>breakcodes</em>&nbsp;: <em>breakcodes</em> must
+ <li> <tt>-o</tt>&nbsp;<em>okcodes</em>&nbsp;: <em>okcodes</em> must
be a comma-separated list of exit codes. If the <tt>-p</tt> flag
-hasn't been given and <em>loop</em> exits with one of the codes in <em>breakcodes</em>,
-forx will not run the following instances of the loop, but exit immediately with the
-same exit code. </li>
+hasn't been given and <em>loop</em> exits with one of the codes in
+<em>okcodes</em>,
+forx will run the following instances of the loop, but if the exit code is
+not listed in <em>okcodes</em>, forx will exit immediately with an
+<a href="exitcodes.html">approximation</a> of the same exit code. </li>
+ <li> <tt>-x</tt>&nbsp;<em>breakcodes</em>&nbsp;: like the previous
+option, but with inverted meaning - the listed exit codes are codes
+that will make forx break the loop and exit, and the unlisted exit
+codes will make it keep looping. </li>
</ul>
<h2> Notes </h2>
diff --git a/doc/if.html b/doc/if.html
index 2157a07..5723ef7 100644
--- a/doc/if.html
+++ b/doc/if.html
@@ -35,8 +35,8 @@
<li> <tt>if</tt> reads <em>prog1...</em> in a
<a href="el_semicolon.html">block</a>. It forks and executes it,
then waits for it to complete. </li>
- <li> If <em>prog1</em> crashes, <tt>if</tt> exits 1 with a special
-error message. </li>
+ <li> If <em>prog1</em> crashes, <tt>if</tt> prints an error message
+then exits 128 plus the number of the signal that killed <em>prog1</em>. </li>
<li> If <em>prog1</em> exits a non-zero status,
<tt>if</tt> exits 1.</li>
<li> Else <tt>if</tt> execs into <em>prog2</em>. </li>
diff --git a/doc/ifelse.html b/doc/ifelse.html
index 2298cf8..06d2e9c 100644
--- a/doc/ifelse.html
+++ b/doc/ifelse.html
@@ -34,7 +34,8 @@
<li> <tt>ifelse</tt> reads <em>prog1...</em> in a
<a href="el_semicolon.html">block</a>. It forks and executes it,
then waits for it to complete. </li>
- <li> If <em>prog1</em> crashes, <tt>ifelse</tt> exits 1 with an error message. </li>
+ <li> If <em>prog1</em> crashes, <tt>ifelse</tt> prints an error message
+and exits 128 plus the number of the signal that killed <em>prog1</em>. </li>
<li> If <em>prog1</em> exits with a return code equal to 0,
<tt>ifelse</tt> execs into <em>prog2</em>. </li>
<li> Else <tt>ifelse</tt> execs into <em>prog3</em>. </li>
diff --git a/doc/ifte.html b/doc/ifte.html
index 40b0ec9..9cbfdcc 100644
--- a/doc/ifte.html
+++ b/doc/ifte.html
@@ -37,7 +37,8 @@ consecutive <a href="el_semicolon.html">blocks</a>. </li>
<li> <tt>ifte</tt> runs <em>progif...</em> as a child process
and waits for it to complete. </li>
<li> If <em>progif...</em> crashes (i.e. is killed by a signal), <tt>ifte</tt>
-exits 1 with an error message. </li>
+prints an error message, then exits 128 plus the number of the signal that
+killed <em>progif</em>. </li>
<li> If <em>progif...</em> exits zero, <tt>ifte</tt> execs into
<em>progthen...</em>, else it execs into <em>progelse...</em>. </li>
</ul>
diff --git a/doc/ifthenelse.html b/doc/ifthenelse.html
index 3180412..97aec39 100644
--- a/doc/ifthenelse.html
+++ b/doc/ifthenelse.html
@@ -38,7 +38,8 @@ consecutive <a href="el_semicolon.html">blocks</a>. </li>
<li> <tt>ifthenelse</tt> runs <em>progif...</em> as a child process
and waits for it to complete. </li>
<li> If <em>progif...</em> crashes (i.e. is killed by a signal), <tt>ifthenelse</tt>
-exits 1 with an error message. </li>
+prints an error message, then exits 128 plus the number of the signal
+that killed <em>progif</em>. </li>
<li> If <em>progif...</em> exits zero, <tt>ifthenelse</tt> runs
<em>progthen...</em> as a child process, else it runs <em>progelse...</em>. </li>
<li> <tt>ifthenelse</tt> waits for its child to complete and puts the exit
diff --git a/doc/index.html b/doc/index.html
index 5fdfb46..5b19477 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -51,7 +51,7 @@ shell's syntax, and has no security issues.
<li> GNU make, version 4.0 or later. Please be aware that execline will
not build with an earlier version. </li>
<li> <a href="http://skarnet.org/software/skalibs/">skalibs</a> version
-2.3.0.0 or later. It's a build-time requirement. It's also a run-time
+2.3.1.0 or later. It's a build-time requirement. It's also a run-time
requirement if you link against the shared version of the skalibs
library. </li>
</ul>
@@ -66,7 +66,7 @@ library. </li>
<h3> Download </h3>
<ul>
- <li> The current released version of execline is <a href="execline-2.0.2.1.tar.gz">2.0.2.1</a>. </li>
+ <li> The current released version of execline is <a href="execline-2.1.0.0.tar.gz">2.1.0.0</a>. </li>
<li> Alternatively, you can checkout a copy of the execline git repository:
<pre> git clone git://git.skarnet.org/execline </pre> </li>
</ul>
diff --git a/doc/loopwhilex.html b/doc/loopwhilex.html
index 91e9fb1..8c8d760 100644
--- a/doc/loopwhilex.html
+++ b/doc/loopwhilex.html
@@ -24,31 +24,38 @@
<h2> Interface </h2>
<pre>
- loopwhilex [ -n ] [ -x <em>exitcodes</em> ] <em>prog...</em>
+ loopwhilex [ -n ] [ -o <em>okcodes</em> | -x <em>breakcodes</em> ] <em>prog...</em>
</pre>
<ul>
<li> <tt>loopwhilex</tt> runs <em>prog...</em> as a child process and
waits for it to complete. </li>
<li> As long as <em>prog</em> exits zero, <tt>loopwhile</tt> runs it again. </li>
- <li> <tt>loopwhilex</tt> then exits 0. If <em>prog</em> was killed by a signal,
-<tt>loopwhilex</tt> exits that signal's number instead. </li>
+ <li> <tt>loopwhilex</tt> then exits with an
+<a href="exitcodes.html">approximation</a> of the last <em>prog</em>
+invocation's exit code. </li>
</ul>
<h2> Options </h2>
<ul>
- <li> <tt>-x</tt>&nbsp;<em>exitcodes</em>&nbsp;: <em>exitcodes</em> must be a comma-separated
-list of valid exit codes. If this option is given, <tt>loopwhilex</tt> will run
-<em>prog...</em> as long as its exit code is <em>not</em> listed in <em>breakcodes</em>. </li>
- <li> <tt>-n</tt>&nbsp;: negate the test: run <em>prog...</em> as long as it exits non-zero
-(or exits a code that <em>is</em> listed in <em>breakcodes</em>). </li>
+ <li> <tt>-o</tt>&nbsp;<em>okcodes</em>&nbsp;: <em>okcodes</em> must
+be a comma-separated list of exit codes. <tt>loopwhilex</tt> will keep
+looping as long as <em>prog</em> exits with one of the codes in
+<em>okcodes</em>. </li>
+ <li> <tt>-x</tt>&nbsp;<em>breakcodes</em>&nbsp;: like the previous
+option, but with inverted meaning - the listed exit codes are codes
+that will break the loop and exit, and the unlisted exit codes will keep
+the loop running. </li>
+ <li> <tt>-n</tt>&nbsp;: negate the test. This option is now redundant,
+and may disappear soon. </li>
</ul>
<h2> Notes </h2>
<ul>
- <li> <tt>loopwhilex <em>prog</em>...</tt> is equivalent to <tt>loopwhilex -n -x 0 <em>prog...</em></tt>. </li>
+ <li> <tt>loopwhilex <em>prog</em>...</tt> is equivalent to <tt>loopwhilex -n -x 0 <em>prog...</em></tt>
+and <tt>loopwhilex -o 0 <em>prog</em>...</tt> </li>
<li> Be careful: execline <strong>maintains no state</strong>, in particular it
uses <strong>no real variables</strong>, and environment will
be of no use here since every instance of <em>prog...</em> runs as a separate
diff --git a/doc/upgrade.html b/doc/upgrade.html
index 115ed5e..b66a215 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -17,6 +17,18 @@
<h1> What has changed in execline </h1>
+<h2> in 2.1.0.0 </h2>
+
+<ul>
+ <li> skalibs dependency bumped to 2.3.1.0 </li>
+ <li> <a href="foreground.html">foreground</a> now sets the ? environment
+variable to 256 plus the signal number when its block was killed by a signal
+(in previous releases it used 126). </li>
+ <li> New rules for exit codes of forx, loopwhilex, forbacktickx </li>
+ <li> New <tt>-e</tt> option to <a href="loopwhilex.html">loopwhilex</a>,
+deprecating the <tt>-x</tt> option. </li>
+</ul>
+
<h2> in 2.0.2.1 </h2>
<ul>
diff --git a/package/info b/package/info
index a5b29c1..54dedf4 100644
--- a/package/info
+++ b/package/info
@@ -1,4 +1,4 @@
package=execline
-version=2.0.2.1
+version=2.1.0.0
category=admin
package_macro_name=EXECLINE
diff --git a/src/execline/forbacktickx.c b/src/execline/forbacktickx.c
index f7b1460..51f308e 100644
--- a/src/execline/forbacktickx.c
+++ b/src/execline/forbacktickx.c
@@ -17,10 +17,10 @@
#include <execline/config.h>
#include <execline/execline.h>
-#define USAGE "forbacktickx [ -p | -x breakcode,breakcode,... ] [ -n ] [ -C | -c ] [ -0 | -d delim ] var { backtickcmd... } command..."
+#define USAGE "forbacktickx [ -p | -o okcode,okcode,... | -x breakcode,breakcode,... ] [ -n ] [ -C | -c ] [ -0 | -d delim ] var { backtickcmd... } command..."
#define dieusage() strerr_dieusage(100, USAGE)
-static int isbreak (unsigned short *tab, unsigned int n, int code)
+static int isok (unsigned short *tab, unsigned int n, int code)
{
register unsigned int i = 0 ;
for (; i < n ; i++) if ((unsigned short)code == tab[i]) break ;
@@ -33,16 +33,17 @@ int main (int argc, char const **argv, char const *const *envp)
char const *delim = " \n\r\t" ;
unsigned int delimlen = 4 ;
char const *x ;
- int argc1 ;
- unsigned short breakcodes[256] ;
+ pid_t pidw ;
+ int fd, argc1 ;
+ unsigned short okcodes[256] ;
unsigned int nbc = 0 ;
- int crunch = 0, chomp = 0 ;
+ int crunch = 0, chomp = 0, not = 1 ;
PROG = "forbacktickx" ;
{
subgetopt_t l = SUBGETOPT_ZERO ;
for (;;)
{
- register int opt = subgetopt_r(argc, argv, "epnCc0d:x:", &l) ;
+ register int opt = subgetopt_r(argc, argv, "epnCc0d:o:x:", &l) ;
if (opt == -1) break ;
switch (opt)
{
@@ -58,8 +59,13 @@ int main (int argc, char const **argv, char const *const *envp)
case 'c' : crunch = 0 ; break ;
case '0' : delim = "" ; delimlen = 1 ; break ;
case 'd' : delim = l.arg ; delimlen = str_len(delim) ; break ;
+ case 'o' :
+ not = 0 ;
+ if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ;
+ break ;
case 'x' :
- if (!ushort_scanlist(breakcodes, 256, l.arg, &nbc)) dieusage() ;
+ not = 1 ;
+ if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ;
break ;
default : dieusage() ;
}
@@ -73,73 +79,69 @@ int main (int argc, char const **argv, char const *const *envp)
if (!argc1) strerr_dief1x(100, "empty block") ;
if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ;
argv[argc1] = 0 ;
+ pidw = el_spawn1(argv[0], argv, envp, &fd, 1) ;
+ if (!pidw) strerr_diefu2sys(111, "spawn ", argv[0]) ;
{
- int fd ;
- pid_t pidw = el_spawn1(argv[0], argv, envp, &fd, 1) ;
- if (!pidw) strerr_diefu2sys(111, "spawn ", argv[0]) ;
+ char buf[BUFFER_INSIZE] ;
+ buffer b = BUFFER_INIT(&buffer_read, fd, buf, BUFFER_INSIZE) ;
+ stralloc modif = STRALLOC_ZERO ;
+ unsigned int envlen = env_len(envp) ;
+ unsigned int modifstart = str_len(x)+1 ;
+ char const *newenv[envlen + 2] ;
+ if (!stralloc_ready(&modif, modifstart+1))
+ strerr_diefu1sys(111, "stralloc_ready") ;
+ byte_copy(modif.s, modifstart-1, x) ;
+ modif.s[modifstart-1] = '=' ;
+ for (;;)
{
- char buf[BUFFER_INSIZE] ;
- buffer b = BUFFER_INIT(&buffer_read, fd, buf, BUFFER_INSIZE) ;
- stralloc modif = STRALLOC_ZERO ;
- unsigned int envlen = env_len(envp) ;
- unsigned int modifstart = str_len(x)+1 ;
- char const *newenv[envlen + 2] ;
- if (!stralloc_ready(&modif, modifstart+1))
- strerr_diefu1sys(111, "stralloc_ready") ;
- byte_copy(modif.s, modifstart-1, x) ;
- modif.s[modifstart-1] = '=' ;
- for (;;)
+ pid_t pid ;
+ modif.len = modifstart ;
+ if (delimlen)
{
- pid_t pid ;
- modif.len = modifstart ;
- if (delimlen)
- {
- register int r = skagetlnsep(&b, &modif, delim, delimlen) ;
- if (!r) break ;
- else if (r < 0)
- {
- if (errno != EPIPE) strerr_diefu1sys(111, "skagetlnsep") ;
- if (chomp) break ;
- }
- else modif.len-- ;
- if ((modif.len == modifstart) && crunch) continue ;
- }
- else
- {
- unsigned int unread = 0 ;
- if (netstring_get(&b, &modif, &unread) <= 0)
- {
- if (netstring_okeof(&b, unread)) break ;
- else strerr_diefu1sys(111, "netstring_get") ;
- }
- }
- if (!stralloc_0(&modif)) strerr_diefu1sys(111, "stralloc_0") ;
- if (!env_merge(newenv, envlen+2, envp, envlen, modif.s, modif.len))
- strerr_diefu1sys(111, "merge environment") ;
- pid = el_spawn0(argv[argc1 + 1], argv + argc1 + 1, newenv) ;
- if (!pid) strerr_diefu2sys(111, "spawn ", argv[argc1+1]) ;
- if (pids.s)
+ register int r = skagetlnsep(&b, &modif, delim, delimlen) ;
+ if (!r) break ;
+ else if (r < 0)
{
- if (!genalloc_append(pid_t, &pids, &pid))
- strerr_diefu1sys(111, "genalloc_append") ;
+ if (errno != EPIPE) strerr_diefu1sys(111, "skagetlnsep") ;
+ if (chomp) break ;
}
- else
+ else modif.len-- ;
+ if ((modif.len == modifstart) && crunch) continue ;
+ }
+ else
+ {
+ unsigned int unread = 0 ;
+ if (netstring_get(&b, &modif, &unread) <= 0)
{
- int wstat ;
- if (wait_pid(pid, &wstat) < 0)
- strerr_diefu2sys(111, "wait for ", argv[argc1 + 1]) ;
- if (isbreak(breakcodes, nbc, wait_status(wstat)))
- return wait_status(wstat) ;
+ if (netstring_okeof(&b, unread)) break ;
+ else strerr_diefu1sys(111, "netstring_get") ;
}
}
- stralloc_free(&modif) ;
+ if (!stralloc_0(&modif)) strerr_diefu1sys(111, "stralloc_0") ;
+ if (!env_merge(newenv, envlen+2, envp, envlen, modif.s, modif.len))
+ strerr_diefu1sys(111, "merge environment") ;
+ pid = el_spawn0(argv[argc1 + 1], argv + argc1 + 1, newenv) ;
+ if (!pid) strerr_diefu2sys(111, "spawn ", argv[argc1+1]) ;
+ if (pids.s)
+ {
+ if (!genalloc_append(pid_t, &pids, &pid))
+ strerr_diefu1sys(111, "genalloc_append") ;
+ }
+ else
+ {
+ int wstat ;
+ if (wait_pid(pid, &wstat) < 0)
+ strerr_diefu2sys(111, "wait for ", argv[argc1 + 1]) ;
+ if (not == isok(okcodes, nbc, wait_estatus(wstat)))
+ return wait_estatus(wstat) ;
+ }
}
- fd_close(fd) ;
- if (!genalloc_append(pid_t, &pids, &pidw))
- strerr_diefu1sys(111, "genalloc_append") ;
+ stralloc_free(&modif) ;
}
+ fd_close(fd) ;
+ if (!genalloc_append(pid_t, &pids, &pidw))
+ strerr_diefu1sys(111, "genalloc_append") ;
if (!waitn(genalloc_s(pid_t, &pids), genalloc_len(pid_t, &pids)))
strerr_diefu1sys(111, "waitn") ;
- /* genalloc_free(pid_t, &pids) ; */
return 0 ;
}
diff --git a/src/execline/forx.c b/src/execline/forx.c
index 25d6d44..ef08ab2 100644
--- a/src/execline/forx.c
+++ b/src/execline/forx.c
@@ -11,10 +11,10 @@
#include <execline/config.h>
#include <execline/execline.h>
-#define USAGE "forx [ -p | -x breakcode,breakcode,... ] var { values... } command..."
+#define USAGE "forx [ -p | -o okcode,okcode,... | -x breakcode,breakcode,... ] var { values... } command..."
#define dieusage() strerr_dieusage(100, USAGE)
-static int isbreak (unsigned short *tab, unsigned int n, int code)
+static int isok (unsigned short *tab, unsigned int n, int code)
{
register unsigned int i = 0 ;
for (; i < n ; i++) if ((unsigned short)code == tab[i]) break ;
@@ -25,22 +25,27 @@ int main (int argc, char const **argv, char const *const *envp)
{
char const *x ;
int argc1 ;
- unsigned short breakcodes[256] ;
+ unsigned short okcodes[256] ;
unsigned int nbc = 0 ;
- int flagpar = 0 ;
+ int flagpar = 0, not = 1 ;
PROG = "forx" ;
{
subgetopt_t l = SUBGETOPT_ZERO ;
for (;;)
{
- register int opt = subgetopt_r(argc, argv, "epx:", &l) ;
+ register int opt = subgetopt_r(argc, argv, "epo:x:", &l) ;
if (opt == -1) break ;
switch (opt)
{
case 'e' : break ; /* compat */
case 'p' : flagpar = 1 ; break ;
+ case 'o' :
+ not = 0 ;
+ if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ;
+ break ;
case 'x' :
- if (!ushort_scanlist(breakcodes, 256, l.arg, &nbc)) dieusage() ;
+ not = 1 ;
+ if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ;
break ;
default : dieusage() ;
}
@@ -80,8 +85,8 @@ int main (int argc, char const **argv, char const *const *envp)
int wstat ;
if (wait_pid(pid, &wstat) == -1)
strerr_diefu2sys(111, "wait for ", argv[argc1+1]) ;
- if (isbreak(breakcodes, nbc, wait_status(wstat)))
- return wait_status(wstat) ;
+ if (not == isok(okcodes, nbc, wait_estatus(wstat)))
+ return wait_estatus(wstat) ;
}
}
if (flagpar)
diff --git a/src/execline/if.c b/src/execline/if.c
index 9d0b4b4..410e118 100644
--- a/src/execline/if.c
+++ b/src/execline/if.c
@@ -15,9 +15,8 @@ int main (int argc, char const **argv, char const *const *envp)
{
int argc1, wstat ;
pid_t pid ;
- unsigned int not = 0 ;
+ int not = 0, flagnormalcrash = 0 ;
unsigned short e = 1 ;
- int flagnormalcrash = 0 ;
PROG = "if" ;
{
subgetopt_t l = SUBGETOPT_ZERO ;
@@ -36,6 +35,7 @@ int main (int argc, char const **argv, char const *const *envp)
}
argc -= l.ind ; argv += l.ind ;
}
+ if (e > 255) strerr_dief1x(100, "invalid exit code") ;
argc1 = el_semicolon(argv) ;
if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ;
argv[argc1] = 0 ;
@@ -46,9 +46,9 @@ int main (int argc, char const **argv, char const *const *envp)
{
char fmt[UINT_FMT] ;
fmt[uint_fmt(fmt, WTERMSIG(wstat))] = 0 ;
- strerr_dief2x(1, "child crashed with signal ", fmt) ;
+ strerr_dief2x(128 + WTERMSIG(wstat), "child crashed with signal ", fmt) ;
}
- if (not == !wait_status(wstat)) return (int)e ;
+ if (not == !wait_estatus(wstat)) return e ;
pathexec0_run(argv+argc1+1, envp) ;
strerr_dieexec(111, argv[argc1+1]) ;
}
diff --git a/src/execline/ifelse.c b/src/execline/ifelse.c
index 6d8801e..edf7cdf 100644
--- a/src/execline/ifelse.c
+++ b/src/execline/ifelse.c
@@ -45,10 +45,10 @@ int main (int argc, char const **argv, char const *const *envp)
if (!flagnormalcrash && WIFSIGNALED(wstat))
{
char fmt[UINT_FMT] ;
- fmt[uint_fmt(fmt, WSTOPSIG(wstat))] = 0 ;
- strerr_dief2x(1, "child crashed with signal ", fmt) ;
+ fmt[uint_fmt(fmt, WTERMSIG(wstat))] = 0 ;
+ strerr_dief2x(128 + WTERMSIG(wstat), "child crashed with signal ", fmt) ;
}
- if (not != !wait_status(wstat)) argv[argc2] = 0 ; else argv += argc2+1 ;
+ if (not != !wait_estatus(wstat)) argv[argc2] = 0 ; else argv += argc2+1 ;
pathexec0_run(argv, envp) ;
strerr_dieexec(111, *argv) ;
}
diff --git a/src/execline/ifte.c b/src/execline/ifte.c
index 3fe021e..eae19c6 100644
--- a/src/execline/ifte.c
+++ b/src/execline/ifte.c
@@ -46,14 +46,14 @@ int main (int argc, char const **argv, char const *const *envp)
{
char fmt[UINT_FMT] ;
fmt[uint_fmt(fmt, WTERMSIG(wstat))] = 0 ;
- strerr_dief2x(1, "child crashed with signal ", fmt) ;
+ strerr_dief2x(128 + WTERMSIG(wstat), "child crashed with signal ", fmt) ;
}
- if (not != !wait_status(wstat)) argv[argc1] = 0 ;
- else
+ if (not == !wait_estatus(wstat))
{
argv += argc1 + 1 ;
argv[argc2] = 0 ;
}
+ else argv[argc1] = 0 ;
pathexec0_run(argv, envp) ;
strerr_dieexec(111, *argv) ;
}
diff --git a/src/execline/ifthenelse.c b/src/execline/ifthenelse.c
index 9960222..2d71fec 100644
--- a/src/execline/ifthenelse.c
+++ b/src/execline/ifthenelse.c
@@ -52,9 +52,9 @@ int main (int argc, char const **argv, char const *const *envp)
{
char fmt[UINT_FMT] ;
fmt[uint_fmt(fmt, WTERMSIG(wstat))] = 0 ;
- strerr_dief2x(1, "child crashed with signal ", fmt) ;
+ strerr_dief2x(128 + WTERMSIG(wstat), "child crashed with signal ", fmt) ;
}
- if (wait_status(wstat))
+ if (wait_estatus(wstat))
{
argv += argc2 + 1 ;
argc2 = argc3 ;
diff --git a/src/execline/loopwhilex.c b/src/execline/loopwhilex.c
index 5cb6a4e..d2955ad 100644
--- a/src/execline/loopwhilex.c
+++ b/src/execline/loopwhilex.c
@@ -8,10 +8,10 @@
#include <skalibs/djbunix.h>
#include <execline/execline.h>
-#define USAGE "loopwhilex [ -n ] [ -x exitcode,exitcode,... ] prog..."
+#define USAGE "loopwhilex [ -n ] [ -o okcode,okcode,... | -x exitcode,exitcode,... ] prog..."
#define dieusage() strerr_dieusage(100, USAGE)
-static int isbreak (unsigned short *tab, unsigned int n, int code)
+static int isok (unsigned short *tab, unsigned int n, int code)
{
register unsigned int i = 0 ;
for (; i < n ; i++) if ((unsigned short)code == tab[i]) break ;
@@ -21,21 +21,26 @@ static int isbreak (unsigned short *tab, unsigned int n, int code)
int main (int argc, char const *const *argv, char const *const *envp)
{
int wstat ;
- int not = 0, cont = 1 ;
- unsigned short breakcodes[256] ;
+ int not = 0, cont = 1, rev = 0 ;
+ unsigned short okcodes[256] ;
unsigned int nbc = 0 ;
PROG = "loopwhilex" ;
{
subgetopt_t l = SUBGETOPT_ZERO ;
for (;;)
{
- register int opt = subgetopt_r(argc, argv, "nx:", &l) ;
+ register int opt = subgetopt_r(argc, argv, "no:x:", &l) ;
if (opt == -1) break ;
switch (opt)
{
case 'n' : not = 1 ; break ;
+ case 'o' :
+ rev = 0 ;
+ if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ;
+ break ;
case 'x' :
- if (!ushort_scanlist(breakcodes, 256, l.arg, &nbc)) dieusage() ;
+ rev = 1 ;
+ if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ;
break ;
default : dieusage() ;
}
@@ -46,17 +51,17 @@ int main (int argc, char const *const *argv, char const *const *envp)
if (!nbc)
{
- breakcodes[0] = 0 ;
+ okcodes[0] = 0 ;
nbc = 1 ;
- not = !not ;
}
+ else if (rev) not = !not ;
while (cont)
{
pid_t pid = el_spawn0(argv[0], argv, envp) ;
if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ;
if (wait_pid(pid, &wstat) < 0) strerr_diefu1sys(111, "wait_pid") ;
- cont = not == isbreak(breakcodes, nbc, wait_status(wstat)) ;
+ cont = not != isok(okcodes, nbc, wait_estatus(wstat)) ;
}
- return WIFSIGNALED(wstat) ? WTERMSIG(wstat) : 0 ;
+ return wait_estatus(wstat) ;
}