diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2019-12-24 14:27:51 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2019-12-24 14:27:51 +0000 |
commit | d9b6a5820f195ef681d7cd15d70a184265b37a94 (patch) | |
tree | 49f952f89c5e6aa0992a0e45fdba636ab0d2bbca | |
parent | 2a96bc93c24f34a972740da3e7df031a2d36e7cb (diff) | |
download | execline-d9b6a5820f195ef681d7cd15d70a184265b37a94.tar.xz |
Add posix-umask; prepare for 2.6.0.0
-rw-r--r-- | NEWS | 10 | ||||
-rw-r--r-- | doc/index.html | 3 | ||||
-rw-r--r-- | doc/posix-cd.html | 2 | ||||
-rw-r--r-- | doc/posix-umask.html | 69 | ||||
-rw-r--r-- | doc/umask.html | 11 | ||||
-rw-r--r-- | doc/upgrade.html | 8 | ||||
-rw-r--r-- | package/deps.mak | 3 | ||||
-rw-r--r-- | package/info | 2 | ||||
-rw-r--r-- | package/modes | 1 | ||||
-rw-r--r-- | package/targets.mak | 5 | ||||
-rw-r--r-- | src/posix/deps-exe/posix-umask | 1 | ||||
-rw-r--r-- | src/posix/posix-umask.c | 174 | ||||
-rw-r--r-- | src/posix/posix-umask.txt | 37 |
13 files changed, 318 insertions, 8 deletions
@@ -1,5 +1,15 @@ Changelog for execline. +In 2.6.0.0 +---------- + + - The dollarat program now has its conflicting -0 and -d options +handled in the conventional way, with rightmost priority. + - New binary: posix-umask. With --enable-pedantic-posix, +umask is a symbolic link to posix-umask. And, hopefully, this +completes the "make execline POSIX-compliant" chapter. + + In 2.5.3.0 ---------- diff --git a/doc/index.html b/doc/index.html index 0a3643c..d93f704 100644 --- a/doc/index.html +++ b/doc/index.html @@ -66,7 +66,7 @@ library. </li> <h3> Download </h3> <ul> - <li> The current released version of execline is <a href="execline-2.5.3.0.tar.gz">2.5.3.0</a>. </li> + <li> The current released version of execline is <a href="execline-2.6.0.0.tar.gz">2.6.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>: @@ -128,6 +128,7 @@ to your installation: the shebang lines for your system might be something like <li><a href="cd.html">The <tt>cd</tt> program</a></li> <li><a href="posix-cd.html">The <tt>posix-cd</tt> program</a></li> <li><a href="umask.html">The <tt>umask</tt> program</a></li> +<li><a href="posix-umask.html">The <tt>posix-umask</tt> program</a></li> <li><a href="emptyenv.html">The <tt>emptyenv</tt> program</a></li> <li><a href="envfile.html">The <tt>envfile</tt> program</a></li> <li><a href="export.html">The <tt>export</tt> program</a></li> diff --git a/doc/posix-cd.html b/doc/posix-cd.html index 3a24602..5074658 100644 --- a/doc/posix-cd.html +++ b/doc/posix-cd.html @@ -26,7 +26,7 @@ given directory, then executes a program. <h2> Interface </h2> <pre> - posix-cd <em>dir</em> <em>prog...</em> + posix-cd [ -L | -P ] <em>dir</em> <em>prog...</em> </pre> <p> diff --git a/doc/posix-umask.html b/doc/posix-umask.html new file mode 100644 index 0000000..4ee310d --- /dev/null +++ b/doc/posix-umask.html @@ -0,0 +1,69 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <meta http-equiv="Content-Language" content="en" /> + <title>execline: the posix-umask command</title> + <meta name="Description" content="execline: the posix-umask command" /> + <meta name="Keywords" content="execline command umask mask posix posix-umask" /> + <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> --> +</head> +<body> + +<p> +<a href="index.html">execline</a><br /> +<a href="//skarnet.org/software/">Software</a><br /> +<a href="//skarnet.org/">skarnet.org</a> +</p> + +<h1> The <tt>posix-umask</tt> program </h1> + +<p> +<tt>posix-umask</tt> changes its file mode creation mask, then executes a program. +</p> + +<h2> Interface </h2> + +<pre> + posix-umask [ -S ] [ <em>mask</em> ] [ <em>prog...</em> ] +</pre> + +<p> +When called with no argument, <tt>posix-umask</tt> prints the value of the +file mode creation mask of the invoking process, then exits 0. +</p> + +<p> + When called with a <em>mask</em> argument, <tt>posix-umask</tt> changes +its file mode creation mask; then, if <em>prog...</em> is not empty, it execs +into it. +</p> + +<p> + <tt>posix-umask</tt> interprets <em>mask</em> as specified by the +<a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/umask.html">POSIX +specification for a <tt>umask</tt> external utility</a>. +</p> + +<h2> Notes </h2> + +<ul> + <li> <tt>posix-umask</tt> is only available when execline has been configured +with the <tt>--enable-pedantic-posix</tt> option, and in this case, the +<a href="umask.html">cd</a> binary is a symbolic link to it. </li> + <li> <tt>posix-umask</tt> fully conforms to the +<a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/umask.html">POSIX +specification</a>. When <em>prog...</em> is not empty, the behaviour of a +<tt>umask</tt> utility is not specified by POSIX, so <tt>posix-umask</tt> extends +the spec to be actually useful and usable in an execline program with the same +interface as the regular execline <a href="umask.html">umask</a> command. </li> + <li> Nobody ever executes or needs the external version (i.e. not a shell +builtin) of the POSIX <tt>umask</tt> command. Compared to the regular execline +<a href="umask.html">umask</a>, <tt>posix-umask</tt> is uselessly bloated and slow. +The only reason it exists is that some distributions refuse to package +execline correctly unless it is strictly POSIX-compliant; the +<tt>--enable-pedantic-posix</tt> configure option is there to appease them. </li> +</ul> + +</body> +</html> diff --git a/doc/umask.html b/doc/umask.html index 1acd04b..22ae137 100644 --- a/doc/umask.html +++ b/doc/umask.html @@ -36,10 +36,13 @@ then execs into <em>prog...</em>. <h2> Notes </h2> -<p> -<tt>umask</tt> is a standard shell builtin. Be careful if you want to -use the <tt>umask</tt> command outside of an <tt>execline</tt> script. -</p> +<ul> +<li> <tt>umask</tt> is a standard shell builtin. Be careful if you want to +use the <tt>umask</tt> command outside of an <tt>execline</tt> script. </li> + <li> When execline has been configured with the <tt>--enable-pedantic-posix</tt> +option, the <tt>umask</tt> binary is actually a symbolic link to the +<a href="posix-umask.html">posix-umask</a> binary. </li> +</ul> </body> </html> diff --git a/doc/upgrade.html b/doc/upgrade.html index 045803e..bbb10aa 100644 --- a/doc/upgrade.html +++ b/doc/upgrade.html @@ -18,6 +18,14 @@ <h1> What has changed in execline </h1> +<h2> in 2.6.0.0 </h2> + +<ul> + <li> <a href="dollarat.html">dollarat</a> now has its <tt>-0</tt> and <tt>-d</tt> +priority unified. (Rightmost priority.) </li> + <li> New binary: <a href="posix-umask.html">posix-umask</a>. </li> +</ul> + <h2> in 2.5.3.0 </h2> <ul> diff --git a/package/deps.mak b/package/deps.mak index 6140333..f944bc7 100644 --- a/package/deps.mak +++ b/package/deps.mak @@ -72,6 +72,7 @@ src/libexecline/exlsn_importas.o src/libexecline/exlsn_importas.lo: src/libexecl src/libexecline/exlsn_main.o src/libexecline/exlsn_main.lo: src/libexecline/exlsn_main.c src/include/execline/execline.h src/include-local/exlsn.h src/libexecline/exlsn_multidefine.o src/libexecline/exlsn_multidefine.lo: src/libexecline/exlsn_multidefine.c src/include/execline/execline.h src/include-local/exlsn.h src/posix/posix-cd.o src/posix/posix-cd.lo: src/posix/posix-cd.c +src/posix/posix-umask.o src/posix/posix-umask.lo: src/posix/posix-umask.c background: EXTRA_LIBS := -lskarnet ${SPAWN_LIB} background: src/execline/background.o ${LIBEXECLINE} @@ -174,3 +175,5 @@ libexecline.so.xyzzy: EXTRA_LIBS := -lskarnet libexecline.so.xyzzy: src/libexecline/el_execsequence.lo src/libexecline/el_getstrict.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_spawn1.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_importas.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo posix-cd: EXTRA_LIBS := -lskarnet posix-cd: src/posix/posix-cd.o +posix-umask: EXTRA_LIBS := -lskarnet +posix-umask: src/posix/posix-umask.o diff --git a/package/info b/package/info index 4a5dd27..3361ae9 100644 --- a/package/info +++ b/package/info @@ -1,4 +1,4 @@ package=execline -version=2.5.3.0 +version=2.6.0.0 category=admin package_macro_name=EXECLINE diff --git a/package/modes b/package/modes index dbe4972..204b67c 100644 --- a/package/modes +++ b/package/modes @@ -45,3 +45,4 @@ unexport 0755 wait 0755 withstdinas 0755 posix-cd 0755 +posix-umask 0755 diff --git a/package/targets.mak b/package/targets.mak index 824fc26..b502988 100644 --- a/package/targets.mak +++ b/package/targets.mak @@ -52,9 +52,12 @@ LIB_DEFS := EXECLINE=execline ifeq ($(PEDANTIC_POSIX),1) -BIN_TARGETS += posix-cd +BIN_TARGETS += posix-cd posix-umask $(DESTDIR)$(bindir)/cd: $(DESTDIR)$(bindir)/posix-cd exec ./tools/install.sh -l posix-cd $(DESTDIR)$(bindir)/cd +$(DESTDIR)$(bindir)/umask: $(DESTDIR)$(bindir)/posix-umask + exec ./tools/install.sh -l posix-umask $(DESTDIR)$(bindir)/umask + endif diff --git a/src/posix/deps-exe/posix-umask b/src/posix/deps-exe/posix-umask new file mode 100644 index 0000000..e7187fe --- /dev/null +++ b/src/posix/deps-exe/posix-umask @@ -0,0 +1 @@ +-lskarnet diff --git a/src/posix/posix-umask.c b/src/posix/posix-umask.c new file mode 100644 index 0000000..b4b9b4b --- /dev/null +++ b/src/posix/posix-umask.c @@ -0,0 +1,174 @@ +/* ISC license. */ + +#include <stdint.h> +#include <sys/stat.h> +#include <locale.h> + +#include <skalibs/gccattributes.h> +#include <skalibs/bytestr.h> +#include <skalibs/types.h> +#include <skalibs/sgetopt.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr2.h> +#include <skalibs/djbunix.h> + +#define USAGE "posix-umask [ -S ] [ mask ] [ prog... ]" +#define dieusage() strerr_dieusage(100, USAGE) +#define dieout() strerr_diefu1sys(111, "write to stdout") + + + /* well, unlike posix-cd, at least this one was fun to write */ + +static inline int output (int sym) +{ + mode_t mode = umask(0) ; + size_t m = 0 ; + char fmt[18] ; + if (sym) + { + unsigned int i = 3 ; + while (i--) + { + unsigned int mask = ~(mode >> (3*i)) ; + fmt[m++] = "ogu"[i] ; fmt[m++] = '=' ; + if (mask & 4) fmt[m++] = 'r' ; + if (mask & 2) fmt[m++] = 'w' ; + if (mask & 1) fmt[m++] = 'x' ; + if (i) fmt[m++] = ',' ; + } + } + else m += uint0_ofmt(fmt, mode, 4) ; + fmt[m++] = '\n' ; + if (buffer_putflush(buffer_1, fmt, m) < 0) dieout() ; + return 0 ; +} + +static void diesyntax (char const *) gccattr_noreturn ; +static void diesyntax (char const *s) +{ + strerr_dief3x(101, "internal parsing error: bad ", s, ". Please submit a bug-report.") ; +} + +static inline uint8_t cclass (char c) +{ + /* char tables may be more efficient, but this is way more readable */ + switch (c) + { + case 0 : return 0 ; + case ',' : return 1 ; + case '+' : + case '-' : + case '=' : return 2 ; + case 'u' : + case 'g' : + case 'o' : return 3 ; + case 'a' : return 4 ; + case 'r' : + case 'w' : + case 'x' : + case 'X' : + case 's' : + case 't' : return 5 ; + default : return 6 ; + } +} + +static inline uint8_t who_value (char c) +{ + switch (c) + { + case 'u' : return 4 ; + case 'g' : return 2 ; + case 'o' : return 1 ; + case 'a' : + case '+' : /* shortcut for when who is empty */ + case '-' : + case '=' : return 7 ; + default : diesyntax("who") ; + } +} + +static inline uint8_t perm_value (char c) +{ + switch (c) + { + case 'r' : return 4 ; + case 'w' : return 2 ; + case 'x' : + case 'X' : return 1 ; + case 's' : + case 't' : return 0 ; + default : diesyntax("perm") ; + } +} + +static inline unsigned int parsemode (char const *s) +{ + static uint16_t const table[5][7] = + { + { 0x005, 0x000, 0x064, 0x021, 0x021, 0x006, 0x006 }, + { 0x005, 0x006, 0x042, 0x021, 0x021, 0x006, 0x006 }, + { 0x005, 0x200, 0x042, 0x083, 0x006, 0x104, 0x006 }, + { 0x805, 0xe00, 0xc42, 0x006, 0x006, 0x006, 0x006 }, + { 0x805, 0xe00, 0xc42, 0x006, 0x006, 0x104, 0x006 } + } ; + unsigned int oldmode = ~umask(0) ; + uint8_t modes[3] = { oldmode & 7, (oldmode >> 3) & 7, (oldmode >> 6) & 7 } ; + uint8_t who = 0 ; + uint8_t perm = 0 ; + uint8_t state = 0 ; + char op = 0 ; + while (state < 5) + { + char c = *s++ ; + uint16_t what = table[state][cclass(c)] ; + state = what & 7 ; + if (what & 0x020) who |= who_value(c) ; + if (what & 0x080) perm = modes[byte_chr("ogu", 3, c)] ; + if (what & 0x100) perm |= perm_value(c) ; + if (what & 0x800) + { + unsigned int i = 3 ; + while (i--) if (who & (1 << i)) + switch (op) + { + case '-' : modes[i] &= ~perm ; break ; + case '+' : modes[i] |= perm ; break ; + case '=' : modes[i] = perm ; break ; + default : diesyntax("op") ; + } + } + if (what & 0x040) op = c ; + if (what & 0x200) who = 0 ; + if (what & 0x400) perm = 0 ; + } + if (state > 5) strerr_dief1x(1, "invalid mode string") ; + return ((unsigned int)modes[2] << 6) | ((unsigned int)modes[1] << 3) | modes[0] ; +} + +int main (int argc, char const **argv, char const *const *envp) +{ + int sym = 0 ; + unsigned int mode ; + PROG = "posix-umask" ; + setlocale(LC_ALL, "") ; /* totally supported, I swear */ + + { + subgetopt_t l = SUBGETOPT_ZERO ; + for (;;) + { + int opt = subgetopt_r(argc, argv, "S", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'S' : sym = 1 ; break ; + default : dieusage() ; + } + } + argc -= l.ind ; argv += l.ind ; + } + if (!argc) return output(sym) ; + if (!uint0_oscan(argv[0], &mode)) mode = ~parsemode(argv[0]) ; + umask(mode & 00777) ; + xpathexec0_run(argv+1, envp) ; +} diff --git a/src/posix/posix-umask.txt b/src/posix/posix-umask.txt new file mode 100644 index 0000000..5bf49a2 --- /dev/null +++ b/src/posix/posix-umask.txt @@ -0,0 +1,37 @@ + + parsemode() function for posix-umask + + goal: parse the "u+r,g-wx,o=u" symbolic mode string and convert it +to a numeric value suitable for umask(). + In the purest skarnet.org tradition, we implement the parser via a DFA. + +class | 0 1 2 3 4 5 6 +st\ev | \0 , +-= ugo a rwxXst other +------------------------------------------------------------------------ +START | wo w w +0 | END START OP WHO WHO X X + +WHO | o w w +1 | END X OP WHO WHO X X + +OP | r o c p +2 | END START OP PERMCPY X PERM X + +PERMCPY | ! !rR !Ro +3 | END START OP X X X X + +PERM | ! !rR !Ro p +4 | END START OP X X PERM X +------------------------------------------------------------------------ + +END=5, X=6. -> states: 3 bits +7 actions -> 10 bits total, need uint16_t + + w: 0x020: who |= c + o: 0x040: store op + c: 0x080: copy perm from c + p: 0x100: perm |= c + r: 0x200: reset who + R: 0x400: reset perm + !: 0x800: apply (who, op, perm) change + |