diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2016-06-18 18:11:53 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2016-06-18 18:11:53 +0000 |
commit | bdd970fe719f78ba0b13446190ede748e3f8fb4d (patch) | |
tree | ea4a80588e0b825db5a54e48428a7f2169b59fa6 | |
parent | 6b91dc463642bbd63a6142f198d3710c42e74c2f (diff) | |
download | execline-bdd970fe719f78ba0b13446190ede748e3f8fb4d.tar.xz |
Revert backtick to a non-wrapper; add -I to backtick and withstdinas
-rw-r--r-- | doc/backtick.html | 27 | ||||
-rw-r--r-- | doc/withstdinas.html | 27 | ||||
-rw-r--r-- | package/deps.mak | 4 | ||||
-rw-r--r-- | src/execline/backtick.c | 132 | ||||
-rw-r--r-- | src/execline/deps-exe/backtick | 1 | ||||
-rw-r--r-- | src/execline/withstdinas.c | 54 |
6 files changed, 129 insertions, 116 deletions
diff --git a/doc/backtick.html b/doc/backtick.html index 6aa2f01..694a29d 100644 --- a/doc/backtick.html +++ b/doc/backtick.html @@ -46,20 +46,27 @@ output as a value. </li> <h2> Options </h2> <ul> - <li> <tt>-i</tt> : insist. If <em>prog1</em> crashes or exits non-zero, -<tt>backtick</tt> exits with an -<a href="exitcodes.html">approximation</a> of the same exit code. </li> - <li> <tt>-D <em>default</em></tt> : default value. If -<em>prog1</em> crashes or exits non-zero, <em>default</em> is used as -<em>variable</em>'s value. If neither the <tt>-i</tt> nor the <tt>-D</tt> -option have been given, <tt>backtick</tt> execs into -<em>prog2...</em> no matter what <em>prog1</em> does, with the null word as -<em>variable</em>'s value if <em>prog1</em> didn't write anything before -dying. </li> <li> <tt>-n</tt> : chomp an ending newline off <em>prog1...</em>'s output. </li> </ul> +<p> + The other options tell backtick what to do if <em>prog1...</em>'s output +is not suitable as the contents of an environment variable, i.e. it +contains a null character: +</p> + +<ul> + <li> <tt>-i</tt> : backtick exits 1. </li> + <li> <tt>-I</tt> : <em>variable</em> is <strong>removed</strong> from +the environment, and execution proceeds. </li> + <li> <tt>-D <em>default</em></tt> : the value of <em>variable</em> +is set to <em>default</em>, and execution proceeds. </li> + <li> neither of those options: the value of <em>variable</em> is set to whatever +the start of <em>prog1...</em>'s output is, up to the first null character; +then execution proceeds. </li> +</ul> + <h2> Notes </h2> <ul> diff --git a/doc/withstdinas.html b/doc/withstdinas.html index 29ad1b6..db49681 100644 --- a/doc/withstdinas.html +++ b/doc/withstdinas.html @@ -31,7 +31,7 @@ environment variable. </p> <pre> - withstdinas [ -i | -D <em>default</em> ] [ -n ] <em>variable</em> <em>prog...</em> + withstdinas [ -i | -I | -D <em>default</em> ] [ -n ] <em>variable</em> <em>prog...</em> </pre> <ul> @@ -44,18 +44,25 @@ environment variable. <h2> Options </h2> <ul> - <li> <tt>-i</tt> : insist. If the data on stdin is invalid as -an environment variable, for instance if it contains a null -character, <tt>withstdinas</tt> exits 1. </li> - <li> <tt>-D <em>default</em></tt> : default value. -If the data on stdin is invalid, <em>default</em> is used as -<em>variable</em>'s value. If neither the <tt>-i</tt> nor the <tt>-D</tt> -option have been given, <tt>withstdinas</tt> execs into -<em>prog...</em> with <em>variable</em> containing whatever value could be read on stdin, -cut before the first null character. </li> <li> <tt>-n</tt> : chomp an ending newline off stdin. </li> </ul> +<p> + The other options tell withstdinas what to do if its input is +not suitable as the contents of an environment variable, i.e. it +contains a null character: +</p> + +<ul> + <li> <tt>-i</tt> : withstdinas exits 1. </li> + <li> <tt>-I</tt> : <em>variable</em> is <strong>removed</strong> from +the environment, and execution proceeds. </li> + <li> <tt>-D <em>default</em></tt> : the value of <em>variable</em> +is set to <em>default</em>, and execution proceeds. </li> + <li> neither of those options: the value of <em>variable</em> is set to whatever the +start of the input is, up to the first null character; and execution proceeds. </li> +</ul> + <h2> Notes </h2> <ul> diff --git a/package/deps.mak b/package/deps.mak index d38609f..88138b3 100644 --- a/package/deps.mak +++ b/package/deps.mak @@ -3,7 +3,7 @@ # src/execline/background.o src/execline/background.lo: src/execline/background.c src/include/execline/execline.h -src/execline/backtick.o src/execline/backtick.lo: src/execline/backtick.c src/include/execline/config.h src/include/execline/execline.h +src/execline/backtick.o src/execline/backtick.lo: src/execline/backtick.c src/include/execline/execline.h src/execline/cd.o src/execline/cd.lo: src/execline/cd.c src/execline/define.o src/execline/define.lo: src/execline/define.c src/include-local/exlsn.h src/execline/dollarat.o src/execline/dollarat.lo: src/execline/dollarat.c @@ -75,7 +75,7 @@ src/libexecline/exlsn_multidefine.o src/libexecline/exlsn_multidefine.lo: src/li background: EXTRA_LIBS := background: src/execline/background.o ${LIBEXECLINE} -lskarnet backtick: EXTRA_LIBS := -backtick: src/execline/backtick.o -lskarnet +backtick: src/execline/backtick.o ${LIBEXECLINE} -lskarnet cd: EXTRA_LIBS := cd: src/execline/cd.o -lskarnet define: EXTRA_LIBS := diff --git a/src/execline/backtick.c b/src/execline/backtick.c index 2deb9f3..2661983 100644 --- a/src/execline/backtick.c +++ b/src/execline/backtick.c @@ -1,84 +1,102 @@ /* ISC license. */ +#include <sys/types.h> +#include <sys/wait.h> #include <unistd.h> -#include <errno.h> -#include <skalibs/uint.h> +#include <skalibs/bytestr.h> #include <skalibs/sgetopt.h> #include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> #include <skalibs/djbunix.h> -#include <execline/config.h> #include <execline/execline.h> -#define USAGE "backtick [ -i | -D default ] [ -n ] var { prog... } command..." +#define USAGE "backtick [ -i | -I | -D default ] [ -n ] var { prog... } remainder..." #define dieusage() strerr_dieusage(100, USAGE) -int main (int argc, char const *const *argv, char const *const *envp) +int main (int argc, char const **argv, char const *const *envp) { - char const *def = 0 ; + subgetopt_t localopt = SUBGETOPT_ZERO ; + pid_t pid ; + int argc1, fdwstat ; + stralloc modif = STRALLOC_ZERO ; + unsigned int modifstart ; int insist = 0, chomp = 0 ; + char const *def = 0 ; PROG = "backtick" ; + for (;;) { - subgetopt_t l = SUBGETOPT_ZERO ; - for (;;) + register int opt = subgetopt_r(argc, argv, "iInD:", &localopt) ; + if (opt < 0) break ; + switch (opt) { - register int opt = subgetopt_r(argc, argv, "eniD:", &l) ; - if (opt == -1) break ; - switch (opt) - { - case 'e' : break ; /* compat */ - case 'n' : chomp = 1 ; break ; - case 'i' : insist = 1 ; break ; - case 'D' : def = l.arg ; break ; - default : dieusage() ; - } + case 'i' : insist = 2 ; break ; + case 'I' : insist = 1 ; break ; + case 'n' : chomp = 1 ; break ; + case 'D' : def = localopt.arg ; break ; + default : dieusage() ; } - argc -= l.ind ; argv += l.ind ; } + argc -= localopt.ind ; argv += localopt.ind ; + if (argc < 2) dieusage() ; - if (!argv[0][0]) dieusage() ; - if (!argv[1][0]) strerr_dief1x(100, "empty block") ; + if (!*argv[0]) strerr_dief1x(100, "empty variable not accepted") ; + if (!stralloc_cats(&modif, argv[0]) || !stralloc_catb(&modif, "=", 1)) + strerr_diefu1sys(111, "stralloc_catb") ; + modifstart = modif.len ; + argc-- ; argv++ ; + argc1 = el_semicolon(argv) ; + if (!argc1) strerr_dief1x(100, "empty block") ; + if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ; + + argv[argc1] = 0 ; + pid = child_spawn1_pipe(argv[0], argv, envp, &fdwstat, 1) ; + if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ; + if (!slurp(&modif, fdwstat)) strerr_diefu1sys(111, "slurp") ; + close(fdwstat) ; + if (wait_pid(pid, &fdwstat) < 0) strerr_diefu1sys(111, "wait_pid") ; + + if (wait_status(fdwstat)) { - unsigned int m = 0, i = 1 ; - int fd = dup(0) ; - char const *newargv[argc + 15] ; - char fmt[UINT_FMT] ; - if (fd < 0) + if (insist >= 2) + if (WIFSIGNALED(fdwstat)) strerr_dief1x(111, "child process crashed") ; + else strerr_dief1x(WEXITSTATUS(fdwstat), "child process exited non-zero") ; + else if (insist) { - if (errno != EBADF) strerr_diefu1sys(111, "dup stdin") ; + modif.len = modifstart - 1 ; + chomp = 0 ; } - else fmt[uint_fmt(fmt, (unsigned int)fd)] = 0 ; - newargv[m++] = EXECLINE_BINPREFIX "pipeline" ; - newargv[m++] = "--" ; - while (argv[i] && argv[i][0] != EXECLINE_BLOCK_END_CHAR && (!EXECLINE_BLOCK_END_CHAR || (argv[i][0] && argv[i][1]))) - newargv[m++] = argv[i++] ; - if (!argv[i]) strerr_dief1x(100, "unterminated block") ; - newargv[m++] = "" ; i++ ; - if (!argv[i]) strerr_dief1x(100, "empty remainder") ; - newargv[m++] = EXECLINE_BINPREFIX "withstdinas" ; - if (insist) newargv[m++] = "-i" ; - if (chomp) newargv[m++] = "-n" ; - if (def) + else if (def) { - newargv[m++] = "-D" ; - newargv[m++] = def ; + modif.len = modifstart ; + if (!stralloc_cats(&modif, def)) strerr_diefu1sys(111, "stralloc_catb") ; } - newargv[m++] = "-!" ; - newargv[m++] = "--" ; - newargv[m++] = argv[0] ; - if (fd < 0) - { - newargv[m++] = EXECLINE_BINPREFIX "fdclose" ; - newargv[m++] = "0" ; - } - else + } + if (argc == argc1 - 1) return 0 ; + if (!stralloc_0(&modif)) strerr_diefu1sys(111, "stralloc_catb") ; + { + unsigned int reallen = str_len(modif.s) ; + if (reallen < modif.len - 1) { - newargv[m++] = EXECLINE_BINPREFIX "fdmove" ; - newargv[m++] = "0" ; - newargv[m++] = fmt ; + if (insist >= 2) + strerr_dief1x(1, "child process output contained a null character") ; + else if (insist) + { + modif.len = modifstart ; + modif.s[modif.len - 1] = 0 ; + chomp = 0 ; + } + else if (def) + { + modif.len = modifstart ; + if (!stralloc_catb(&modif, def, str_len(def)+1)) + strerr_diefu1sys(111, "stralloc_catb") ; + strerr_warnw2x("child process output contained a null character", " - using default instead") ; + } + else modif.len = reallen + 1 ; } - while (argv[i]) newargv[m++] = argv[i++] ; - newargv[m++] = 0 ; - pathexec_run(newargv[0], newargv, envp) ; - strerr_dieexec(111, newargv[0]) ; + if (chomp && (modif.s[modif.len - 2] == '\n')) + modif.s[--modif.len - 1] = 0 ; } + pathexec_r(argv + argc1 + 1, envp, env_len(envp), modif.s, modif.len) ; + strerr_dieexec(111, argv[argc1 + 1]) ; } diff --git a/src/execline/deps-exe/backtick b/src/execline/deps-exe/backtick index e7187fe..97021b5 100644 --- a/src/execline/deps-exe/backtick +++ b/src/execline/deps-exe/backtick @@ -1 +1,2 @@ +${LIBEXECLINE} -lskarnet diff --git a/src/execline/withstdinas.c b/src/execline/withstdinas.c index c1e3c36..af7140f 100644 --- a/src/execline/withstdinas.c +++ b/src/execline/withstdinas.c @@ -10,7 +10,7 @@ #include <skalibs/stralloc.h> #include <skalibs/djbunix.h> -#define USAGE "withstdinas [ -i | -D default ] [ -n ] var remainder..." +#define USAGE "withstdinas [ -i | -I | -D default ] [ -n ] var remainder..." #define dieusage() strerr_dieusage(100, USAGE) int main (int argc, char const **argv, char const *const *envp) @@ -18,19 +18,19 @@ int main (int argc, char const **argv, char const *const *envp) subgetopt_t localopt = SUBGETOPT_ZERO ; stralloc modif = STRALLOC_ZERO ; unsigned int modifstart ; - int insist = 0, chomp = 0, reapit = 0 ; + int insist = 0, chomp = 0 ; char const *def = 0 ; PROG = "withstdinas" ; for (;;) { - register int opt = subgetopt_r(argc, argv, "einD:!", &localopt) ; + register int opt = subgetopt_r(argc, argv, "iInD:", &localopt) ; if (opt < 0) break ; switch (opt) { - case 'i' : insist = 1 ; break ; + case 'i' : insist = 2 ; break ; + case 'I' : insist = 1 ; break ; case 'n' : chomp = 1 ; break ; case 'D' : def = localopt.arg ; break ; - case '!' : reapit = 1 ; break ; default : dieusage() ; } } @@ -38,42 +38,23 @@ int main (int argc, char const **argv, char const *const *envp) if (!argc) dieusage() ; if (!*argv[0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ; - if (!stralloc_catb(&modif, "!", 2) - || !stralloc_cats(&modif, argv[0]) - || !stralloc_catb(&modif, "=", 1)) + if (!stralloc_cats(&modif, argv[0]) || !stralloc_catb(&modif, "=", 1)) strerr_diefu1sys(111, "stralloc_catb") ; modifstart = modif.len ; if (!slurp(&modif, 0)) strerr_diefu1sys(111, "slurp") ; - if (reapit) - { - char const *x = env_get2(envp, "!") ; - if (x) - { - uint64 pid ; - int wstat ; - if (!uint640_scan(x, &pid)) strerr_dieinvalid(100, "!") ; - if (waitpid(pid, &wstat, 0) < 0) - strerr_diefu1sys(111, "waitpid") ; - if (wait_estatus(wstat)) - { - if (insist) - if (WIFSIGNALED(wstat)) strerr_dief1x(wait_estatus(wstat), "child process crashed") ; - else strerr_dief1x(wait_estatus(wstat), "child process exited non-zero") ; - else if (def) - { - modif.len = modifstart ; - if (!stralloc_cats(&modif, def)) strerr_diefu1sys(111, "stralloc_catb") ; - } - } - } - } if (!stralloc_0(&modif)) strerr_diefu1sys(111, "stralloc_catb") ; { - unsigned int reallen = str_len(modif.s + 2) ; - if (reallen < modif.len - 3) + unsigned int reallen = str_len(modif.s) ; + if (reallen < modif.len - 1) { - if (insist) + if (insist >= 2) strerr_dief1x(1, "stdin contained a null character") ; + else if (insist) + { + modif.len = modifstart ; + modif.s[modif.len - 1] = 0 ; + chomp = 0 ; + } else if (def) { modif.len = modifstart ; @@ -81,13 +62,12 @@ int main (int argc, char const **argv, char const *const *envp) strerr_diefu1sys(111, "stralloc_catb") ; strerr_warnw2x("stdin contained a null character", " - using default instead") ; } - else - modif.len = reallen + 3 ; + else modif.len = reallen + 1 ; } if (chomp && (modif.s[modif.len - 2] == '\n')) modif.s[--modif.len - 1] = 0 ; } if (!argv[1]) return 0 ; - pathexec_r(argv + 1, envp, env_len(envp), modif.s + !reapit * 2, modif.len - !reapit * 2) ; + pathexec_r(argv + 1, envp, env_len(envp), modif.s, modif.len) ; strerr_dieexec(111, argv[1]) ; } |