diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2020-11-23 23:27:31 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2020-11-23 23:27:31 +0000 |
commit | a43216278137fe399cdcea6210e580b445e16197 (patch) | |
tree | 99249d45157b13afc7b3dbad07416c065e64a153 | |
parent | 7812e30b70ee3d27c2b01d21d346c52656927858 (diff) | |
download | execline-a43216278137fe399cdcea6210e580b445e16197.tar.xz |
New forstdin; new trap; prepare for 2.7.0.0
-rw-r--r-- | INSTALL | 2 | ||||
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | doc/forstdin.html | 4 | ||||
-rw-r--r-- | doc/index.html | 4 | ||||
-rw-r--r-- | doc/trap.html | 25 | ||||
-rw-r--r-- | doc/upgrade.html | 10 | ||||
-rw-r--r-- | package/info | 2 | ||||
-rw-r--r-- | src/execline/forstdin.c | 11 | ||||
-rw-r--r-- | src/execline/trap.c | 147 |
9 files changed, 115 insertions, 97 deletions
@@ -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: @@ -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> <em>eofcode</em> : 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 <em>millisecs</em></tt> : 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) ; } } } |