summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--INSTALL2
-rw-r--r--NEWS7
-rw-r--r--doc/forstdin.html4
-rw-r--r--doc/index.html4
-rw-r--r--doc/trap.html25
-rw-r--r--doc/upgrade.html10
-rw-r--r--package/info2
-rw-r--r--src/execline/forstdin.c11
-rw-r--r--src/execline/trap.c147
9 files changed, 115 insertions, 97 deletions
diff --git a/INSTALL b/INSTALL
index fb97b16..b17858f 100644
--- a/INSTALL
+++ b/INSTALL
@@ -6,7 +6,7 @@ Build Instructions
- A POSIX-compliant C development environment
- GNU make version 3.81 or later
- - skalibs version 2.9.3.0 or later: https://skarnet.org/software/skalibs/
+ - skalibs version 2.9.4.0 or later: https://skarnet.org/software/skalibs/
This software will run on any operating system that implements
POSIX.1-2008, available at:
diff --git a/NEWS b/NEWS
index 81a2212..54b3ebe 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,12 @@
Changelog for execline.
+In 2.7.0.0
+----------
+
+ - New -e option to forstdin.
+ - New "default" directive to trap, replacing the irrelevant "timeout".
+
+
In 2.6.1.1
----------
diff --git a/doc/forstdin.html b/doc/forstdin.html
index 5228aee..f57ee9c 100644
--- a/doc/forstdin.html
+++ b/doc/forstdin.html
@@ -30,7 +30,7 @@ run another program.
</p>
<pre>
- forstdin [ -p | -o <em>okcodes</em> | -x <em>breakcodes</em> ] [ -n ] [ -C | -c ] [ -0 | -d <em>delim</em> ] <em>variable</em> <em>loop...</em>
+ forstdin [ -p | -o <em>okcodes</em> | -x <em>breakcodes</em> ] [ -e eofcode ] [ -n ] [ -C | -c ] [ -0 | -d <em>delim</em> ] <em>variable</em> <em>loop...</em>
</pre>
<ul>
@@ -63,6 +63,8 @@ not listed in <em>okcodes</em>, forstdin will exit immediately with an
option, but with inverted meaning - the listed exit codes are codes
that will make forstdin break the loop and exit, and the unlisted exit
codes will make it keep looping. </li>
+ <li> <tt>-e</tt>&nbsp;<em>eofcode</em>&nbsp;: if forstdin reads EOF,
+exit <em>eofcode</em>. Default is 0. </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/index.html b/doc/index.html
index cb411a6..c04c9d7 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -51,7 +51,7 @@ shell's syntax, and has no security issues.
<li> A POSIX-compliant system with a standard C development environment </li>
<li> GNU make, version 3.81 or later. </li>
<li> <a href="//skarnet.org/software/skalibs/">skalibs</a> version
-2.9.3.0 or later. It's a build-time requirement. It's also a run-time
+2.9.4.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.6.1.1.tar.gz">2.6.1.1</a>. </li>
+ <li> The current released version of execline is <a href="execline-2.7.0.0.tar.gz">2.7.0.0</a>. </li>
<li> Alternatively, you can checkout a copy of the
<a href="//git.skarnet.org/cgi-bin/cgit.cgi/execline/">execline
git repository</a>:
diff --git a/doc/trap.html b/doc/trap.html
index 03d5bc4..fafd5c7 100644
--- a/doc/trap.html
+++ b/doc/trap.html
@@ -28,12 +28,12 @@ to the signals it catches.
</p>
<pre>
- trap [ -x ] [ -t <em>millisecs</em> ]
+ trap [ -x ]
{
- [ timeout { <em>progtimeout...</em> } ]
[ SIGTERM { <em>progsigterm...</em> } ]
[ quit { <em>progsigquit...</em> } ]
[ 1 { <em>progsighup</em>... } ]
+ [ default { <em>progdefault</em>... } ]
...
}
<em>prog...</em>
@@ -50,12 +50,12 @@ name (case-insensitive, with or without the <tt>SIG</tt> prefix),
run when the specified event occurs. </li>
<li> <tt>trap</tt> sets traps for the various directives it reads.
A trap for <tt>SIGTERM</tt> will be triggered when the <tt>trap</tt>
-program receives a SIGTERM.
-A trap for <tt>timeout</tt> will be triggered when <em>millisecs</em>
-milliseconds elapse without a signal being caught. </li>
+program receives a SIGTERM. A <tt>default</tt>
+trap will be used for any signal that is not caught by another trap. </li>
<li> It spawns a child executing <em>prog...</em>. </li>
<li> It sets the <tt>!</tt> environment
-variable to the pid of the <em>prog...</em> process. </li>
+variable to the pid of the <em>prog...</em> process, and the <tt>SIGNAL</tt>
+environment variable to the trapped signal. </li>
<li> Whenever it catches a signal, it spawns the program described in the
corresponding directive. It will not spawn a program for the same signal
twice: if the first subprocess is still active when another instance of the
@@ -75,12 +75,8 @@ SIGTERM, unless caught by a <tt>SIGTERM</tt> directive, will kill the
<tt>trap</tt> process (and leave <em>prog</em> running). With the
<tt>-x</tt> option, without a <tt>SIGTERM</tt> directive, a SIGTERM
will be still be caught by <tt>trap</tt>, that will send it to
-<em>prog</em>. </li>
- <li> <tt>-t&nbsp;<em>millisecs</em></tt>&nbsp;: if a <tt>timeout</tt>
-directive exists, the corresponding <em>progtimeout...</em> will be run
-every time <em>millisecs</em> milliseconds elapse without <tt>trap</tt>
-receiving a signal. By default, <em>millisecs</em> is 0, which means
-infinite (i.e. a <tt>timeout</tt> directive will never trigger). </li>
+<em>prog</em>. Note that if a <tt>default</tt> directive is present,
+this option does nothing. </li>
</ul>
<h2> Notes </h2>
@@ -88,7 +84,10 @@ infinite (i.e. a <tt>timeout</tt> directive will never trigger). </li>
<ul>
<li> Programs defined in command line directives can start with
<tt><a href="importas.html">importas</a> ! !</tt> to retrieve the pid of
-<em>prog</em> in <tt>${!}</tt> </li>
+<em>prog</em> in <tt>$!</tt>. If they need the signal number, which
+can be the case in <tt>default</tt> directives, they can for instance use
+<tt><a href="multisubstitute.html">multisubstitute</a> { importas ! ! importas SIGNAL SIGNAL }</tt>
+to get both <tt>$!</tt> and <tt>$SIGNAL</tt> substitutions. </li>
<li> <tt>trap</tt> is a standard shell builtin, with similar
functionality. It is more idiomatic, and probably more efficient,
to use that builtin in shell scripts, and to only use the
diff --git a/doc/upgrade.html b/doc/upgrade.html
index fd6e41b..aa23ab2 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -18,6 +18,16 @@
<h1> What has changed in execline </h1>
+<h2> in 2.7.0.0 </h2>
+
+<ul>
+ <li> <a href="//skarnet.org/software/skalibs/">skalibs</a>
+dependency bumped to 2.9.4.0. </li>
+ <li> New <tt>-e</tt> option to <a href="forstdin.html">forstdin</a>. </li>
+ <li> New <tt>default</tt> directive to <a href="trap.html">trap</a>,
+replacing the <tt>timeout</tt> one, which was ill-suited to that program. </li>
+</ul>
+
<h2> in 2.6.1.1 </h2>
<ul>
diff --git a/package/info b/package/info
index 9242801..35bc785 100644
--- a/package/info
+++ b/package/info
@@ -1,4 +1,4 @@
package=execline
-version=2.6.1.1
+version=2.7.0.0
category=admin
package_macro_name=EXECLINE
diff --git a/src/execline/forstdin.c b/src/execline/forstdin.c
index 95ec4d5..7979811 100644
--- a/src/execline/forstdin.c
+++ b/src/execline/forstdin.c
@@ -3,6 +3,7 @@
#include <sys/types.h>
#include <string.h>
#include <errno.h>
+
#include <skalibs/types.h>
#include <skalibs/sgetopt.h>
#include <skalibs/buffer.h>
@@ -17,7 +18,7 @@
#include <execline/config.h>
#include <execline/execline.h>
-#define USAGE "forstdin [ -p | -o okcode,okcode,... | -x breakcode,breakcode,... ] [ -n ] [ -C | -c ] [ -0 | -d delim ] var command..."
+#define USAGE "forstdin [ -p | -o okcode,okcode,... | -x breakcode,breakcode,... ] [ -e eofcode ] [ -n ] [ -C | -c ] [ -0 | -d delim ] var command..."
#define dieusage() strerr_dieusage(100, USAGE)
static genalloc pids = GENALLOC_ZERO ; /* pid_t */
@@ -51,12 +52,13 @@ int main (int argc, char const **argv, char const *const *envp)
size_t nbc = 0 ;
unsigned short okcodes[256] ;
int crunch = 0, chomp = 0, not = 1 ;
+ unsigned short eofcode = 0 ;
PROG = "forstdin" ;
{
subgetopt_t l = SUBGETOPT_ZERO ;
for (;;)
{
- int opt = subgetopt_r(argc, argv, "pnCc0d:o:x:", &l) ;
+ int opt = subgetopt_r(argc, argv, "pnCc0d:o:x:e:", &l) ;
if (opt == -1) break ;
switch (opt)
{
@@ -79,6 +81,9 @@ int main (int argc, char const **argv, char const *const *envp)
not = 1 ;
if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ;
break ;
+ case 'e' :
+ if (!ushort_scan(l.arg, &eofcode)) dieusage() ;
+ break ;
default : dieusage() ;
}
}
@@ -154,5 +159,5 @@ int main (int argc, char const **argv, char const *const *envp)
if (!pids.len) break ;
sig_pause() ;
}
- return 0 ;
+ return eofcode ;
}
diff --git a/src/execline/trap.c b/src/execline/trap.c
index 9e5b4d2..0eec7db 100644
--- a/src/execline/trap.c
+++ b/src/execline/trap.c
@@ -4,31 +4,42 @@
#include <string.h>
#include <errno.h>
#include <signal.h>
+
#include <skalibs/sgetopt.h>
#include <skalibs/types.h>
#include <skalibs/nsig.h>
#include <skalibs/sig.h>
#include <skalibs/strerr2.h>
-#include <skalibs/tai.h>
#include <skalibs/iopause.h>
#include <skalibs/selfpipe.h>
#include <skalibs/env.h>
#include <skalibs/djbunix.h>
+
#include <execline/execline.h>
-#define USAGE "trap [ -x ] [ -t timeout ] { signal { cmdline } ... } prog..."
+#define USAGE "trap [ -x ] { signal { cmdline } ... } prog..."
#define dieusage() strerr_dieusage(100, USAGE) ;
static pid_t pids[SKALIBS_NSIG + 1] ;
static char const *const *argvs[SKALIBS_NSIG] ; /* initted with 0s */
-static void action (unsigned int i, char const *const *envp)
+static inline void action (unsigned int i, char const *const *envp, size_t envlen)
{
if (argvs[i])
{
if (!pids[i])
{
- pids[i] = child_spawn0(argvs[i][0], argvs[i], envp) ;
+ char const *newenvp[envlen + 3] ;
+ char modif[9 + PID_FMT + UINT_FMT] = "!=" ;
+ size_t m = 2 ;
+ m += pid_fmt(modif + m, pids[SKALIBS_NSIG]) ;
+ modif[m++] = 0 ;
+ memcpy(modif + m, "SIGNAL=", 7) ; m += 7 ;
+ m += uint_fmt(modif + m, i) ;
+ modif[m++] = 0 ;
+ if (!env_merge(newenvp, envlen + 3, envp, envlen, modif, m))
+ strerr_diefu1sys(111, "adjust environment for child") ;
+ pids[i] = child_spawn0(argvs[i][0], argvs[i], newenvp) ;
if (!pids[i]) strerr_diefu2sys(111, "spawn ", argvs[i][0]) ;
}
}
@@ -37,13 +48,15 @@ static void action (unsigned int i, char const *const *envp)
int main (int argc, char const **argv, char const *const *envp)
{
- tain_t tto ;
+ size_t envlen = env_len(envp) ;
+ iopause_fd x = { .events = IOPAUSE_READ } ;
+ sigset_t set ;
int xfersigs = 0 ;
- int argc1, spfd ;
+ unsigned int argc1 ;
unsigned int i = 0 ;
PROG = "trap" ;
+
{
- unsigned int t = 0 ;
subgetopt_t l = SUBGETOPT_ZERO ;
for (;;)
{
@@ -52,110 +65,92 @@ int main (int argc, char const **argv, char const *const *envp)
switch (opt)
{
case 'x' : xfersigs = 1 ; break ;
- case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
default : dieusage() ;
}
}
argc -= l.ind ; argv += l.ind ;
- if (t) tain_from_millisecs(&tto, t) ;
- else tto = tain_infinite_relative ;
}
-
if (!argc) dieusage() ;
+
argc1 = el_semicolon(argv) ;
if (!argc1) strerr_dief1x(100, "empty block") ;
if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ;
if (argc1 + 1 == argc) dieusage() ;
argv[argc1] = 0 ;
- tain_now_set_stopwatch_g() ;
- spfd = selfpipe_init() ;
- if (spfd < 0) strerr_diefu1sys(111, "selfpipe_init") ;
-
- while (i < (unsigned int)argc1)
+ while (i < argc1)
{
- int argc2 ;
+ unsigned int argc2 ;
int sig = 0 ;
- if (!sig0_scan(argv[i], &sig) && strcasecmp(argv[i], "timeout"))
+ if (!sig0_scan(argv[i], &sig) && strcasecmp(argv[i], "default"))
strerr_dief3x(100, "unrecognized", " directive: ", argv[i]) ;
argc2 = el_semicolon(argv + ++i) ;
- if (!argc2)
- strerr_dief3x(100, "empty", " internal block for directive ", argv[i-1]) ;
if (i + argc2 >= argc1)
strerr_dief3x(100, "unterminated", " internal block for directive ", argv[i-1]) ;
if (argvs[sig])
strerr_dief3x(100, "duplicate", " directive: ", argv[i-1]) ;
- if (sig && selfpipe_trap(sig) < 0)
- strerr_diefu2sys(111, "trap ", argv[i-1]) ;
+ switch (sig)
+ {
+ case SIGCHLD : strerr_dief2x(100, "SIGCHLD", " cannot be trapped") ;
+ case SIGKILL : strerr_dief2x(100, "SIGKILL", " cannot be trapped") ;
+ case SIGSTOP : strerr_dief2x(100, "SIGSTOP", " cannot be trapped") ;
+ default :
+ argvs[sig] = argv + i ;
+ break ;
+ }
argv[i + argc2] = 0 ;
- argvs[sig] = argv + i ;
i += argc2 + 1 ;
}
- if (!argvs[SIGCHLD] && selfpipe_trap(SIGCHLD) < 0)
- strerr_diefu2sys(111, "trap ", "SIGCHLD") ;
+
+ if (argvs[0])
+ for (i = 1 ; i < SKALIBS_NSIG ; i++)
+ if (!argvs[i])
+ argvs[i] = argvs[0] ;
if (xfersigs)
{
- sigset_t full ;
- sigfillset(&full) ;
- sigdelset(&full, SIGCHLD) ;
- sigdelset(&full, SIGKILL) ;
- sigdelset(&full, SIGSTOP) ;
+ sigfillset(&set) ;
+ sigdelset(&set, SIGCHLD) ;
+ sigdelset(&set, SIGKILL) ;
+ sigdelset(&set, SIGSTOP) ;
+ }
+ else
+ {
+ sigemptyset(&set) ;
for (i = 1 ; i < SKALIBS_NSIG ; i++)
- if (!argvs[i] && sigismember(&full, i) > 0 && selfpipe_trap(i) < 0)
- {
- char fmt[UINT_FMT] ;
- fmt[uint_fmt(fmt, i)] = 0 ;
- strerr_diefu4sys(111, "auto-", "trap ", "signal ", fmt) ;
- }
+ if (argvs[i])
+ sigaddset(&set, i) ;
}
+ x.fd = selfpipe_init() ;
+ if (x.fd < 0) strerr_diefu1sys(111, "selfpipe_init") ;
+ if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ;
+
pids[SKALIBS_NSIG] = child_spawn0(argv[argc1 + 1], argv + argc1 + 1, envp) ;
if (!pids[SKALIBS_NSIG]) strerr_diefu2sys(111, "spawn ", argv[argc1 + 1]) ;
+ loop:
+ if (iopause_g(&x, 1, 0) < 0) strerr_diefu1sys(111, "iopause") ;
+ for (;;)
{
- iopause_fd x = { .fd = spfd, .events = IOPAUSE_READ } ;
- size_t envlen = env_len(envp) ;
- char modif[2 + PID_FMT] = "!=" ;
- size_t l = 2 + pid_fmt(modif + 2, pids[SKALIBS_NSIG]) ;
- char const *newenvp[envlen + 2] ;
- modif[l++] = 0 ;
- if (!env_merge(newenvp, envlen + 2, envp, envlen, modif, l))
- strerr_diefu1sys(111, "adjust environment") ;
- for (;;)
+ int r = selfpipe_read() ;
+ switch (r)
{
- tain_t deadline ;
- int r ;
- tain_add_g(&deadline, &tto) ;
- r = iopause_g(&x, 1, &deadline) ;
- if (r < 0) strerr_diefu1sys(111, "iopause") ;
- if (!r) action(0, newenvp) ;
- else
- {
- int cont = 1 ;
- while (cont)
+ case -1 : strerr_diefu1sys(111, "selfpipe_read") ;
+ case 0 : goto loop ;
+ case SIGCHLD :
+ for (;;)
{
- r = selfpipe_read() ;
- switch (r)
- {
- case -1 : strerr_diefu1sys(111, "selfpipe_read") ;
- case 0 : cont = 0 ; break ;
- case SIGCHLD :
- for (;;)
- {
- int wstat ;
- ssize_t id = wait_pids_nohang(pids, SKALIBS_NSIG + 1, &wstat) ;
- if (id < 0 && errno != ECHILD)
- strerr_diefu1sys(111, "wait") ;
- if (id <= 0) break ;
- pids[id - 1] = 0 ;
- if (id == SKALIBS_NSIG + 1) return wait_estatus(wstat) ;
- }
- if (!argvs[SIGCHLD]) break ;
- default :
- action(r, newenvp) ;
- }
+ int wstat ;
+ ssize_t id = wait_pids_nohang(pids, SKALIBS_NSIG + 1, &wstat) ;
+ if (id < 0 && errno != ECHILD)
+ strerr_diefu1sys(111, "wait") ;
+ if (id <= 0) break ;
+ pids[id - 1] = 0 ;
+ if (id == SKALIBS_NSIG + 1) return wait_estatus(wstat) ;
}
- }
+ break ;
+ default :
+ action(r, envp, envlen) ;
}
}
}