summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS10
-rw-r--r--doc/index.html3
-rw-r--r--doc/posix-cd.html2
-rw-r--r--doc/posix-umask.html69
-rw-r--r--doc/umask.html11
-rw-r--r--doc/upgrade.html8
-rw-r--r--package/deps.mak3
-rw-r--r--package/info2
-rw-r--r--package/modes1
-rw-r--r--package/targets.mak5
-rw-r--r--src/posix/deps-exe/posix-umask1
-rw-r--r--src/posix/posix-umask.c174
-rw-r--r--src/posix/posix-umask.txt37
13 files changed, 318 insertions, 8 deletions
diff --git a/NEWS b/NEWS
index c614ec0..7ae513e 100644
--- a/NEWS
+++ b/NEWS
@@ -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
+