diff options
-rw-r--r-- | INSTALL | 2 | ||||
-rw-r--r-- | doc/exitcodes.html | 97 | ||||
-rw-r--r-- | doc/forbacktickx.html | 18 | ||||
-rw-r--r-- | doc/foreground.html | 9 | ||||
-rw-r--r-- | doc/forx.html | 16 | ||||
-rw-r--r-- | doc/if.html | 4 | ||||
-rw-r--r-- | doc/ifelse.html | 3 | ||||
-rw-r--r-- | doc/ifte.html | 3 | ||||
-rw-r--r-- | doc/ifthenelse.html | 3 | ||||
-rw-r--r-- | doc/index.html | 4 | ||||
-rw-r--r-- | doc/loopwhilex.html | 25 | ||||
-rw-r--r-- | doc/upgrade.html | 12 | ||||
-rw-r--r-- | package/info | 2 | ||||
-rw-r--r-- | src/execline/forbacktickx.c | 128 | ||||
-rw-r--r-- | src/execline/forx.c | 21 | ||||
-rw-r--r-- | src/execline/if.c | 8 | ||||
-rw-r--r-- | src/execline/ifelse.c | 6 | ||||
-rw-r--r-- | src/execline/ifte.c | 6 | ||||
-rw-r--r-- | src/execline/ifthenelse.c | 4 | ||||
-rw-r--r-- | src/execline/loopwhilex.c | 25 |
20 files changed, 273 insertions, 123 deletions
@@ -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 ? +</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 ? +</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> : 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> <em>breakcodes</em> : <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> <em>okcodes</em> : <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> <em>breakcodes</em> : 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> <em>breakcodes</em> : <em>breakcodes</em> must + <li> <tt>-o</tt> <em>okcodes</em> : <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> <em>breakcodes</em> : 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> <em>exitcodes</em> : <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> : 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> <em>okcodes</em> : <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> <em>breakcodes</em> : 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> : 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) ; } |