diff options
author | Elliott Hughes <enh@google.com> | 2020-05-20 17:17:13 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2020-05-20 17:17:13 -0700 |
commit | a5d35a625a246b18a75388646d6b9b861c6dda4b (patch) | |
tree | 0d0b36ad2f9412cf1969f0c0399d2845756c5156 | |
parent | f54e593e397c3b4f0f4c1a2bd6e6a968787ca963 (diff) | |
download | mksh-a5d35a625a246b18a75388646d6b9b861c6dda4b.tar.gz |
Upgrade to mksh R59b.
R59b is a must-have bugfix upgrade for R59 (not R58):
[tg] Handle other tmux $TERM types, pointed out by multi via IRC
[tg] Fix typo in FAQ
[tg] y='a\*b'; [[ $x = $y ]] regression (Martijn Dekker) fix
[l0kod] Defuse CLIP OS O_MAYEXEC support (cf. LWN)
[tg] Make set +o output a command to restore the currently set and
(new!) cleared options, keep a reset state per session (experimental)
[tg] Correct documentation and code regarding to argv[0] parsing: first
‘-’ for login shells, then ‘r’ case-insensitively for restricted shell,
then “sh”*, again case-insensitively, for BINSH_* modes; add tests
[tg] On OS/2, allow case-insensitive name for direct builtin call
[tg] Always skip startup files if direct builtin call
[tg] Avoid some sometimes-redundant startup codepaths
Test: treehugger
Change-Id: I7b0a1d37b4d3fdf1f78569458769e89dca755fcb
-rw-r--r-- | Android.bp | 2 | ||||
-rw-r--r-- | Android.patch.txt | 21 | ||||
-rw-r--r-- | src/Build.sh | 4 | ||||
-rw-r--r-- | src/check.t | 212 | ||||
-rw-r--r-- | src/edit.c | 18 | ||||
-rw-r--r-- | src/eval.c | 3 | ||||
-rw-r--r-- | src/funcs.c | 4 | ||||
-rw-r--r-- | src/main.c | 73 | ||||
-rw-r--r-- | src/misc.c | 89 | ||||
-rw-r--r-- | src/mksh.1 | 69 | ||||
-rw-r--r-- | src/mksh.faq | 4 | ||||
-rw-r--r-- | src/sh.h | 27 | ||||
-rw-r--r-- | src/sh_flags.gen | 3 | ||||
-rw-r--r-- | src/sh_flags.opt | 6 |
14 files changed, 360 insertions, 175 deletions
@@ -107,7 +107,7 @@ cc_defaults { "-DHAVE_SYS_ERRLIST_DECL=0", "-DHAVE_SYS_SIGLIST_DECL=1", "-DHAVE_PERSISTENT_HISTORY=0", - "-DMKSH_BUILD_R=591", + "-DMKSH_BUILD_R=592", // Additional flags "-DMKSH_DEFAULT_PROFILEDIR=\"/system/etc\"", diff --git a/Android.patch.txt b/Android.patch.txt index d2cd1fa..eefcd5c 100644 --- a/Android.patch.txt +++ b/Android.patch.txt @@ -1,6 +1,7 @@ -diff -u mksh-R59/funcs.c src/funcs.c ---- mksh-R59/funcs.c 2020-04-13 12:51:34.000000000 -0700 -+++ src/funcs.c 2020-05-15 16:10:35.035013192 -0700 +Only in src: FAQ.htm +diff -u mksh-R59b/funcs.c src/funcs.c +--- mksh-R59b/funcs.c 2020-05-16 15:38:48.000000000 -0700 ++++ src/funcs.c 2020-05-20 17:14:19.588510856 -0700 @@ -104,7 +104,9 @@ {Tsgbreak, c_brkcont}, {T__builtin, c_builtin}, @@ -32,11 +33,10 @@ diff -u mksh-R59/funcs.c src/funcs.c #ifdef __MirBSD__ /* alias to "true" for historical reasons */ {"domainname", c_true}, -Only in src: funcs.c.orig -diff -u mksh-R59/main.c src/main.c ---- mksh-R59/main.c 2020-04-13 10:04:41.000000000 -0700 -+++ src/main.c 2020-05-15 16:10:35.035013192 -0700 -@@ -402,6 +402,12 @@ +diff -u mksh-R59b/main.c src/main.c +--- mksh-R59b/main.c 2020-05-16 15:51:51.000000000 -0700 ++++ src/main.c 2020-05-20 17:14:19.588510856 -0700 +@@ -414,6 +414,12 @@ /* import environment */ init_environ(); @@ -50,3 +50,8 @@ diff -u mksh-R59/main.c src/main.c typeset(TinitIFS, 0, 0, 0, 0); Only in src: main.c.orig +Only in src: Rebuild.sh +Only in src: rlimits.gen +Only in src: sh_flags.gen +Only in src: signames.inc +Only in src: test.sh diff --git a/src/Build.sh b/src/Build.sh index 1a95e66..1d30045 100644 --- a/src/Build.sh +++ b/src/Build.sh @@ -1,5 +1,5 @@ #!/bin/sh -srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.755 2020/04/07 23:15:11 tg Exp $' +srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.756 2020/05/16 22:53:03 tg Exp $' #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, @@ -2461,7 +2461,7 @@ addsrcs '!' HAVE_STRLCPY strlcpy.c addsrcs USE_PRINTF_BUILTIN printf.c test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose" -add_cppflags -DMKSH_BUILD_R=591 +add_cppflags -DMKSH_BUILD_R=592 $e $bi$me: Finished configuration testing, now producing output.$ao diff --git a/src/check.t b/src/check.t index a750c50..8818822 100644 --- a/src/check.t +++ b/src/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.838 2020/04/13 19:51:08 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.845 2020/05/16 22:19:15 tg Exp $ # -*- mode: sh -*- #- # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, @@ -31,7 +31,7 @@ # (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date expected-stdout: - KSH R59 2020/04/14 + KSH R59 2020/05/16 description: Check base version of full shell stdin: @@ -8082,45 +8082,50 @@ name: test-str-pattern description: Check that [[ x = $y ]] can take extglobs, like ksh93 stdin: + [[ -n $BASH_VERSION ]] && shopt -s extglob + function one { + n=$1 x=$2 y=$3 z=${4:-$3} + [[ $x = $y ]]; a=$? + [[ $x = "$y" ]]; b=$? + eval '[[ $x = '"$z"' ]]; c=$?' + eval '[[ $x = "'"$z"'" ]]; d=$?' + echo $n $a $b $c $d . + } x='a\' - [[ $x = a\ ]]; echo 1 $? . - [[ $x = a\\ ]]; echo 2 $? . - y='a\' - [[ $x = $y ]]; echo 3 $? . - [[ $x = "$y" ]]; echo 4 $? . - x='a\b' - y='a\b' - [[ $x = $y ]]; echo 5 $? . - [[ $x = "$y" ]]; echo 6 $? . - y='a\\b' - [[ $x = $y ]]; echo 7 $? . - [[ $x = "$y" ]]; echo 8 $? . - x='foo' - y='f+(o)' - [[ $x = $y ]]; echo 9 $? . - [[ $x = "$y" ]]; echo 10 $? . - x=$y - [[ $x = $y ]]; echo 11 $? . - [[ $x = "$y" ]]; echo 12 $? . + [[ $x = a\ ]]; echo 01 $? . + [[ $x = a\\ ]]; echo 02 $? . + one 03 'a\' 'a\' 'a\\' + one 04 'a\b' 'a\b' + one 05 'a\b' 'a\\b' + one 06 'foo' 'f+(o)' + one 07 'f+(o)' 'f+(o)' + one 08 'f+(o' 'f+(o' 'f+\(o' + one 09 foo 'f+(o' 'f+\(o' + one 10 abcde 'a\*e' + one 11 'a*e' 'a\*e' + one 12 'a\*e' 'a\*e' + echo extras: x='f+(o' - y=$x - [[ $x = $y ]]; echo 13 $? . - [[ $x = "$y" ]]; echo 14 $? . -expected-stdout: - 1 1 . - 2 0 . - 3 0 . - 4 0 . - 5 1 . - 6 0 . - 7 0 . - 8 1 . - 9 0 . - 10 1 . - 11 1 . - 12 0 . - 13 0 . - 14 0 . + z='f+(o' + eval '[[ $x = "'"$z"'" ]]; echo 14 $? "(08:4)" .' + x=foo + eval '[[ $x = "'"$z"'" ]]; echo 15 $? "(09:4)" .' +expected-stdout: + 01 1 . + 02 0 . + 03 0 0 0 0 . + 04 1 0 1 0 . + 05 0 1 0 0 . + 06 0 1 0 1 . + 07 1 0 1 0 . + 08 0 0 0 1 . + 09 1 1 1 1 . + 10 1 1 1 1 . + 11 0 1 0 1 . + 12 1 0 1 0 . + extras: + 14 0 (08:4) . + 15 1 (09:4) . --- name: test-precedence-1 description: @@ -8448,8 +8453,10 @@ description: stdin: set -o braceexpand set +o sh - [[ $(set +o) == *@(-o sh)@(| *) ]] && echo sh || echo nosh - [[ $(set +o) == *@(-o braceexpand)@(| *) ]] && echo brex || echo nobrex + [[ -o sh ]] && echo sh + [[ -o !sh ]] && echo nosh + [[ -o braceexpand ]] && echo brex + [[ -o !braceexpand ]] && echo nobrex echo {a,b,c} set +o braceexpand echo {a,b,c} @@ -8457,12 +8464,17 @@ stdin: echo {a,b,c} set -o sh echo {a,b,c} - [[ $(set +o) == *@(-o sh)@(| *) ]] && echo sh || echo nosh - [[ $(set +o) == *@(-o braceexpand)@(| *) ]] && echo brex || echo nobrex + [[ -o sh ]] && echo sh + [[ -o !sh ]] && echo nosh + [[ -o braceexpand ]] && echo brex + [[ -o !braceexpand ]] && echo nobrex set -o braceexpand echo {a,b,c} - [[ $(set +o) == *@(-o sh)@(| *) ]] && echo sh || echo nosh - [[ $(set +o) == *@(-o braceexpand)@(| *) ]] && echo brex || echo nobrex + [[ -o sh ]] && echo sh + [[ -o !sh ]] && echo nosh + [[ -o braceexpand ]] && echo brex + [[ -o !braceexpand ]] && echo nobrex + [[ $(exec -a -set "$__progname" -o) = *login+(' ')on* ]]; echo $? expected-stdout: nosh brex @@ -8475,44 +8487,110 @@ expected-stdout: a b c sh brex + 0 --- name: sh-mode-2a description: Check that posix or sh mode is *not* automatically turned on category: !binsh stdin: - ln -s "$__progname" ksh || cp "$__progname" ksh - ln -s "$__progname" sh || cp "$__progname" sh - ln -s "$__progname" ./-ksh || cp "$__progname" ./-ksh - ln -s "$__progname" ./-sh || cp "$__progname" ./-sh - for shell in {,-}{,k}sh; do - print -- $shell $(./$shell +l -c \ - '[[ $(set +o) == *"-o "@(sh|posix)@(| *) ]] && echo sh || echo nosh') + for shell in {,-}{,r}{,k,mk}sh {,-}{,R}{,K,MK}SH.EXE; do + ln -s "$__progname" ./$shell || cp "$__progname" ./$shell + print -- $shell $(./$shell +l -c ' + [[ -o sh || -o posix ]] && echo sh + [[ -o !sh && -o !posix ]] && echo nosh + [[ -o restricted ]] && echo lim || echo ok + ') done expected-stdout: - sh nosh - ksh nosh - -sh nosh - -ksh nosh + sh nosh ok + ksh nosh ok + mksh nosh ok + rsh nosh lim + rksh nosh lim + rmksh nosh lim + -sh nosh ok + -ksh nosh ok + -mksh nosh ok + -rsh nosh lim + -rksh nosh lim + -rmksh nosh lim + SH.EXE nosh ok + KSH.EXE nosh ok + MKSH.EXE nosh ok + RSH.EXE nosh lim + RKSH.EXE nosh lim + RMKSH.EXE nosh lim + -SH.EXE nosh ok + -KSH.EXE nosh ok + -MKSH.EXE nosh ok + -RSH.EXE nosh lim + -RKSH.EXE nosh lim + -RMKSH.EXE nosh lim --- name: sh-mode-2b description: Check that posix or sh mode *is* automatically turned on category: binsh stdin: - ln -s "$__progname" ksh || cp "$__progname" ksh - ln -s "$__progname" sh || cp "$__progname" sh - ln -s "$__progname" ./-ksh || cp "$__progname" ./-ksh - ln -s "$__progname" ./-sh || cp "$__progname" ./-sh - for shell in {,-}{,k}sh; do - print -- $shell $(./$shell +l -c \ - '[[ $(set +o) == *"-o "@(sh|posix)@(| *) ]] && echo sh || echo nosh') + for shell in {,-}{,r}{,k,mk}sh {,-}{,R}{,K,MK}SH.EXE; do + ln -s "$__progname" ./$shell || cp "$__progname" ./$shell + print -- $shell $(./$shell +l -c ' + [[ -o sh || -o posix ]] && echo sh + [[ -o !sh && -o !posix ]] && echo nosh + [[ -o restricted ]] && echo lim || echo ok + ') done expected-stdout: - sh sh - ksh nosh - -sh sh - -ksh nosh + sh sh ok + ksh nosh ok + mksh nosh ok + rsh sh lim + rksh nosh lim + rmksh nosh lim + -sh sh ok + -ksh nosh ok + -mksh nosh ok + -rsh sh lim + -rksh nosh lim + -rmksh nosh lim + SH.EXE sh ok + KSH.EXE nosh ok + MKSH.EXE nosh ok + RSH.EXE sh lim + RKSH.EXE nosh lim + RMKSH.EXE nosh lim + -SH.EXE sh ok + -KSH.EXE nosh ok + -MKSH.EXE nosh ok + -RSH.EXE sh lim + -RKSH.EXE nosh lim + -RMKSH.EXE nosh lim +--- +name: sh-options +description: + Check that "set +o" DTRT per POSIX +stdin: + t() { + [[ -o vi ]]; a=$? + [[ -o pipefail ]]; b=$? + echo $((++i)) $a $b . + } + set -e + set -o vi + set +o pipefail + set +e + t + x=$(set +o) + set +o vi + set -o pipefail + t + eval "$x" + t +expected-stdout: + 1 0 1 . + 2 1 0 . + 3 0 1 . --- name: pipeline-1 description: @@ -29,7 +29,7 @@ #ifndef MKSH_NO_CMDLINE_EDITING -__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.350 2020/04/13 20:46:37 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.351 2020/04/15 20:16:19 tg Exp $"); /* * in later versions we might use libtermcap for this, but since external @@ -5603,9 +5603,19 @@ x_initterm(const char *termtype) { /* default must be 0 (bss) */ x_term_mode = 0; - /* this is what tmux uses, don't ask me about it */ - if (!strcmp(termtype, "screen") || !strncmp(termtype, "screen-", 7)) - x_term_mode = 1; + /* catch any of the TERM types tmux uses, don’t ask m̲e̲ about it… */ + switch (*termtype) { + case 's': + if (!strncmp(termtype, "screen", 6) && + (termtype[6] == '\0' || termtype[6] == '-')) + x_term_mode = 1; + break; + case 't': + if (!strncmp(termtype, "tmux", 4) && + (termtype[4] == '\0' || termtype[4] == '-')) + x_term_mode = 1; + break; + } } #ifndef MKSH_SMALL @@ -24,7 +24,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.230 2020/04/07 23:14:41 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.231 2020/05/05 21:34:27 tg Exp $"); /* * string expansion @@ -882,6 +882,7 @@ expand( c = ORD('\\'); else ++x.str; + quote |= 2; break; /* ctype(c, C_PATMO) */ case ORD('!'): diff --git a/src/funcs.c b/src/funcs.c index a5cfc69..d3427d0 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -39,7 +39,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.372 2020/04/13 19:51:07 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.373 2020/05/16 22:38:21 tg Exp $"); #if HAVE_KILLPG /* @@ -330,7 +330,7 @@ c_print(const char **wp) #ifndef MKSH_MIDNIGHTBSD01ASH_COMPAT Flag(FSH) || #endif - Flag(FAS_BUILTIN)) { + as_builtin) { /* BSD "echo" cmd, Debian Policy 10.4 compliant */ ++wp; bsd_echo: @@ -35,7 +35,7 @@ #include <locale.h> #endif -__RCSID("$MirOS: src/bin/mksh/main.c,v 1.364 2020/04/13 17:04:14 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/main.c,v 1.372 2020/05/16 22:51:24 tg Exp $"); #ifndef MKSHRC_PATH #define MKSHRC_PATH "~/.mkshrc" @@ -242,6 +242,9 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) #ifdef __OS2__ os2_init(&argc, &argv); +#define builtin_name_cmp stricmp +#else +#define builtin_name_cmp strcmp #endif /* do things like getpgrp() et al. */ @@ -276,10 +279,11 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) ccp += argi; begin_parsing_kshname: argi = 0; - if (*ccp == '-') - ++ccp; } } + Flag(FLOGIN) = (ord(*ccp) == ORD('-')) || (ord(*kshname) == ORD('-')); + if (ord(*ccp) == ORD('-')) + ++ccp; if (!*ccp) ccp = empty_argv[0]; @@ -304,24 +308,32 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) ktinit(APERM, &builtins, /* currently up to 52 builtins: 75% of 128 = 2^7 */ 7); - for (i = 0; mkshbuiltins[i].name != NULL; i++) - if (!strcmp(ccp, builtin(mkshbuiltins[i].name, - mkshbuiltins[i].func))) - Flag(FAS_BUILTIN) = 1; + for (i = 0; mkshbuiltins[i].name != NULL; ++i) { + const char *builtin_name; + + builtin_name = builtin(mkshbuiltins[i].name, + mkshbuiltins[i].func); + if (!builtin_name_cmp(ccp, builtin_name)) { + /* canonicalise argv[0] */ + ccp = builtin_name; + as_builtin = true; + } + } - if (!Flag(FAS_BUILTIN)) { + if (!as_builtin) { /* check for -T option early */ argi = parse_args(argv, OF_FIRSTTIME, NULL); if (argi < 0) return (1); - /* called as rsh, rmksh, -rsh, -rmksh, etc.? */ - if (ord(*ccp) == ORD('r')) { + /* called as rsh, rmksh, -rsh, RKSH.EXE, etc.? */ + if (ksh_eq(*ccp, 'R', 'r')) { ++ccp; ++restricted_shell; } #if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED) - /* are we called as -sh or /bin/sh or so? */ - if (!strcmp(ccp, "sh" MKSH_EXE_EXT)) { + /* are we called as -rsh or /bin/sh or SH.EXE or so? */ + if (ksh_eq(ccp[0], 'S', 's') && + ksh_eq(ccp[1], 'H', 'h')) { /* either also turns off braceexpand */ #ifdef MKSH_BINSHPOSIX /* enable better POSIX conformance */ @@ -474,7 +486,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) /* this to note if utf-8 mode is set on command line (see below) */ UTFMODE = 2; - if (!Flag(FAS_BUILTIN)) { + if (!as_builtin) { argi = parse_args(argv, OF_CMDLINE, NULL); if (argi < 0) return (1); @@ -484,7 +496,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) utf_flag = UTFMODE; UTFMODE = 0; - if (Flag(FAS_BUILTIN)) { + if (as_builtin) { /* auto-detect from environment variables, always */ utf_flag = 3; } else if (Flag(FCOMMAND)) { @@ -549,8 +561,8 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) } /* this bizarreness is mandated by POSIX */ - if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) && - Flag(FTALKING)) + if (Flag(FTALKING) && fstat(0, &s_stdin) >= 0 && + S_ISCHR(s_stdin.st_mode)) reset_nonblock(0); /* initialise job control */ @@ -582,7 +594,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) #endif l = e->loc; - if (Flag(FAS_BUILTIN)) { + if (as_builtin) { l->argc = argc; l->argv = argv; l->argv[0] = ccp; @@ -650,6 +662,21 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) errexit = Flag(FERREXIT); Flag(FERREXIT) = 0; + /* save flags for "set +o" handling */ + memcpy(baseline_flags, shell_flags, sizeof(shell_flags)); + /* disable these because they have special handling */ + baseline_flags[(int)FPOSIX] = 0; + baseline_flags[(int)FSH] = 0; + /* ensure these always show up setting, for FPOSIX/FSH */ + baseline_flags[(int)FBRACEEXPAND] = 0; + baseline_flags[(int)FUNNYCODE] = 0; +#if !defined(MKSH_SMALL) || defined(DEBUG) + /* mark as initialised */ + baseline_flags[(int)FNFLAGS] = 1; +#endif + if (as_builtin) + goto skip_startup_files; + /* * Do this before profile/$ENV so that if it causes problems in them, * user will know why things broke. @@ -668,6 +695,8 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) else /* turn off -p if not set explicitly */ change_flag(FPRIVILEGED, OF_INTERNAL, false); + /* track shell-imposed changes */ + baseline_flags[(int)FPRIVILEGED] = Flag(FPRIVILEGED); } else { if (Flag(FLOGIN)) include(substitute("$HOME/.profile", 0), 0, NULL, true); @@ -681,14 +710,20 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) c_builtin(restr_com); /* After typeset command... */ Flag(FRESTRICTED) = 1; + /* track shell-imposed changes */ + baseline_flags[(int)FRESTRICTED] = 1; } Flag(FERREXIT) = errexit; if (Flag(FTALKING) && s) hist_init(s); - else + else { /* set after ENV */ + skip_startup_files: Flag(FTRACKALL) = 1; + /* track shell-imposed change (might lower surprise) */ + baseline_flags[(int)FTRACKALL] = 1; + } alarm_init(); @@ -707,7 +742,7 @@ main(int argc, const char *argv[]) struct block *l; if ((rv = main_init(argc, argv, &s, &l)) == 0) { - if (Flag(FAS_BUILTIN)) { + if (as_builtin) { rv = c_builtin(l->argv); } else { shell(s, 0); @@ -3,7 +3,8 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019 + * 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, + * 2020 * mirabilos <m@mirbsd.org> * Copyright (c) 2015 * Daniel Richard G. <skunk@iSKUNK.ORG> @@ -32,7 +33,7 @@ #include <grp.h> #endif -__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.297 2020/04/07 11:56:46 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.299 2020/05/16 22:19:58 tg Exp $"); #define KSH_CHVT_FLAG #ifdef MKSH_SMALL @@ -141,7 +142,8 @@ struct options_info { }; static void options_fmt_entry(char *, size_t, unsigned int, const void *); -static void printoptions(bool); +static int printoptions(bool); +static int printoption(size_t); /* format a single select menu item */ static void @@ -154,10 +156,32 @@ options_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg) Flag(oi->opts[i]) ? "on" : "off"); } -static void +static int +printoption(size_t i) +{ + if (Flag(i) == baseline_flags[i]) + return (0); + if (!OFN(i)[0]) { +#if !defined(MKSH_SMALL) || defined(DEBUG) + bi_errorf(Tf_sd, "change in unnamed option", (int)i); +#endif + return (1); + } + if (Flag(i) != 0 && Flag(i) != 1) { +#if !defined(MKSH_SMALL) || defined(DEBUG) + bi_errorf(Tf_s_sD_s, Tdo, OFN(i), "not 0 or 1"); +#endif + return (1); + } + shprintf(Tf__s_s, Flag(i) ? Tdo : Tpo, OFN(i)); + return (0); +} + +static int printoptions(bool verbose) { size_t i = 0; + int rv = 0; if (verbose) { size_t n = 0, len, octs = 0; @@ -187,13 +211,17 @@ printoptions(bool verbose) } else { /* short version like AT&T ksh93 */ shf_puts(Tset, shl_stdout); - while (i < NELEM(options)) { - if (Flag(i) && OFN(i)[0]) - shprintf(" -o %s", OFN(i)); + shf_puts(To_o_reset, shl_stdout); + printoption(FSH); + printoption(FPOSIX); + while (i < FNFLAGS) { + if (i != FSH && i != FPOSIX) + rv |= printoption(i); ++i; } shf_putc('\n', shl_stdout); } + return (rv); } char * @@ -362,7 +390,8 @@ parse_args(const char **argv, #undef SHFLAGS_NOT_CMD ; bool set; - const char *opts; + const char *opts = what == OF_CMDLINE || what == OF_FIRSTTIME ? + cmd_opts : set_opts; const char *array = NULL; Getopt go; size_t i; @@ -370,22 +399,6 @@ parse_args(const char **argv, bool sortargs = false; bool fcompatseen = false; - if (what == OF_CMDLINE) { - const char *p = argv[0], *q; - /* - * Set FLOGIN before parsing options so user can clear - * flag using +l. - */ - if (*p != '-') - for (q = p; *q; ) - if (mksh_cdirsep(*q++)) - p = q; - Flag(FLOGIN) = (*p == '-'); - opts = cmd_opts; - } else if (what == OF_FIRSTTIME) { - opts = cmd_opts; - } else - opts = set_opts; ksh_getopt_reset(&go, GF_ERROR|GF_PLUSOPT); while ((optc = ksh_getopt(argv, &go, opts)) != -1) { set = tobool(!(go.info & GI_PLUS)); @@ -408,7 +421,15 @@ parse_args(const char **argv, * an option (ie, can't get here if what is * OF_CMDLINE). */ - printoptions(set); +#if !defined(MKSH_SMALL) || defined(DEBUG) + if (!set && !baseline_flags[(int)FNFLAGS]) { + bi_errorf(Tf_s_s, "too early", + Tset_po); + return (-1); + } +#endif + if (printoptions(set)) + return (-1); break; } i = option(go.optarg); @@ -433,7 +454,23 @@ parse_args(const char **argv, ; else if ((i != (size_t)-1) && (OFF(i) & what)) change_flag((enum sh_flag)i, what, set); - else { + else if (!strcmp(go.optarg, To_reset)) { +#if !defined(MKSH_SMALL) || defined(DEBUG) + if (!baseline_flags[(int)FNFLAGS]) { + bi_errorf(Tf_ss, "too early", + To_o_reset); + return (-1); + } +#endif + /* + * ordering, with respect to side effects, + * was ensured above by printoptions + */ + for (i = 0; i < FNFLAGS; ++i) + if (Flag(i) != baseline_flags[i]) + change_flag((enum sh_flag)i, + what, baseline_flags[i]); + } else { bi_errorf(Tf_sD_s, go.optarg, Tunknown_option); return (-1); @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.489 2020/04/14 22:45:21 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.491 2020/05/16 22:12:36 tg Exp $ .\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, @@ -84,7 +84,7 @@ .\" with -mandoc, it might implement .Mx itself, but we want to .\" use our own definition. And .Dd must come *first*, always. .\" -.Dd $Mdocdate: April 14 2020 $ +.Dd $Mdocdate: May 16 2020 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" @@ -270,7 +270,7 @@ option is on by default (see the command below). .It Fl l Login shell. -If the basename the shell is called with (i.e. argv[0]) +If the name or basename the shell is called with (i.e. argv[0]) starts with .Ql \- or if this option is used, @@ -297,7 +297,9 @@ option is cleared automatically after processing the startup files. Restricted shell. A shell is .Dq restricted -if the basename the shell is called with (i.e. argv[0]) starts with +if the basename the shell is called with, after +.Ql \- +processing, starts with .Ql r or if this option is used. The following restrictions come into effect after the shell processes any @@ -382,7 +384,7 @@ is determined as follows: if the .Fl c option is used and there is a non-option argument, it is used as the name; if commands are being read from a file, the file is used as the name; -otherwise, the basename the shell was called with (i.e. argv[0]) is used. +otherwise, the name the shell was called with (i.e. argv[0]) is used. .Pp The exit status of the shell is 127 if the command file specified on the command line could not be opened, or non-zero if a fatal syntax error @@ -1801,12 +1803,11 @@ if it was invoked with the .Fl c option and arguments were given; otherwise the .Ar file -argument, if it was supplied; -or else the basename the shell was invoked with (i.e.\& -.Li argv[0] ) . +argument, if it was supplied; or else the name the shell was invoked with +.Pq i.e.\& Li argv[0] . .Ev $0 -is also set to the name of the current script or -the name of the current function, if it was defined with the +is also set to the name of the current script, +or to the name of the current function if it was defined with the .Ic function keyword (i.e. a Korn shell style function). .It Ev 1 No .. Ev 9 @@ -2024,7 +2025,7 @@ and .Xc See the end of the Emacs editing mode documentation for an example. .It Ev KSH_VERSION -The name and version of the shell (read-only). +The name (self-identification) and version of the shell (read-only). See also the version commands in .Sx Emacs editing mode and @@ -4562,34 +4563,42 @@ Behave closer to the standards (see .Sx POSIX mode for details). -Automatically enabled if the basename of the shell invocation begins with +Automatically enabled if the shell invocation basename, after +.Sq \- +and +.Sq r +processing, begins with .Dq sh -and this autodetection feature is compiled in (not in MirBSD; commonly used for -.Nm lksh -only). +and +.Pq often used for the Nm lksh No binary +this autodetection feature is compiled in. As a side effect, setting this flag turns off the .Ic braceexpand and .Ic utf8\-mode flags, which can be turned back on manually, and -.Pq unless both are enabled at the same time +.Pq unless both are set in the same command .Ic sh mode. .It Fl o Ic sh -Enable +Enable kludge .Pa /bin/sh -.Pq kludge -mode (see -.Sx SH mode ) . -Automatically enabled if the basename of the shell invocation begins with +compatibility mode (see +.Sx SH mode +below for details). +Automatically enabled if the basename of the shell invocation, after +.Sq \- +and +.Sq r +processing, begins with .Dq sh and this autodetection feature is compiled in .Pq rather uncommon . -As a side effect, setting this flag turns off +As a side effect, setting this flag turns off the .Ic braceexpand -mode, which can be turned back on manually, and +flag, which can be turned back on manually, and .Ic posix -mode (unless both are enabled at the same time). +mode (unless both are set in the same command). .It Fl o Ic vi Enable .Xr vi 1 Ns -like @@ -4623,12 +4632,10 @@ options (with single letter names) can be found in the parameter .Ic set Fl o with no option name will list all the options and whether each is on or off; .Ic set +o -will print the long names of all options that are currently on. -In a future version, -.Ic set +o -will behave -.Tn POSIX -compliant and print commands to restore the current options instead. +prints a command to restore the current option set, using the internal +.Ic set Fl o Ic .reset +construct, which is an implementation detail; these commands are transient +.Pq only valid within the current shell session . .Pp Remaining arguments, if any, are positional parameters and are assigned, in order, to the positional parameters (i.e. $1, $2, etc.). @@ -7065,7 +7072,7 @@ for the in-memory portion of the history is slow, should use .Xr memmove 3 . .Pp This document attempts to describe -.Nm mksh\ R59 +.Nm mksh\ R59b and up, .\" with vendor patches from insert-your-name-here, compiled without any options impacting functionality, such as diff --git a/src/mksh.faq b/src/mksh.faq index 1fc3b7d..83e0191 100644 --- a/src/mksh.faq +++ b/src/mksh.faq @@ -1,4 +1,4 @@ -RCSID: $MirOS: src/bin/mksh/mksh.faq,v 1.6 2020/04/13 20:46:39 tg Exp $ +RCSID: $MirOS: src/bin/mksh/mksh.faq,v 1.7 2020/04/25 12:09:55 tg Exp $ ToC: spelling Title: How do you spell <tt>mksh</tt>? How do you pronounce it? @@ -357,7 +357,7 @@ Title: What about programmable tab completion? The shell itself provides static deterministic tab completion. However, you can use hooks like reprogramming the Tab key to a command line editor macro, and using the <tt>evaluate-region</tt> -editor command (modulo a bugfix) together with <tt>quote-region<tt> and shell functions to +editor command (modulo a bugfix) together with <tt>quote-region</tt> and shell functions to implement a programmable completion engine. Multiple people have been considering doing so in our IRC channel; we’ll hyperlink to these engines when they are available. @@ -191,9 +191,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.892 2020/04/14 22:45:22 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.898 2020/05/16 22:38:23 tg Exp $"); #endif -#define MKSH_VERSION "R59 2020/04/14" +#define MKSH_VERSION "R59 2020/05/16" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES @@ -513,9 +513,8 @@ extern int __cdecl setegid(gid_t); #define O_BINARY 0 #endif -#ifndef O_MAYEXEC +#undef O_MAYEXEC /* https://lwn.net/Articles/820658/ */ #define O_MAYEXEC 0 -#endif #ifdef MKSH__NO_SYMLINK #undef S_ISLNK @@ -669,7 +668,7 @@ char *ucstrstr(char *, const char *); #endif #endif -#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 591) +#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 592) #error Must run Build.sh to compile this. extern void thiswillneverbedefinedIhope(void); int @@ -917,6 +916,12 @@ EXTERN struct tbl *vp_pipest; /* global PIPESTATUS array */ EXTERN short trap_exstat; /* exit status before running a trap */ EXTERN uint8_t trap_nested; /* running nested traps */ EXTERN uint8_t shell_flags[FNFLAGS]; +EXTERN uint8_t baseline_flags[FNFLAGS +#if !defined(MKSH_SMALL) || defined(DEBUG) + + 1 +#endif + ]; +EXTERN bool as_builtin; /* direct builtin call */ EXTERN const char *kshname; /* $0 */ EXTERN struct { uid_t kshuid_v; /* real UID of shell at startup */ @@ -1038,7 +1043,10 @@ EXTERN const char Tnot_found_s[] E_INIT("%s not found"); #define Tnot_started (Tjob_not_started + 4) #define TOLDPWD (Tno_OLDPWD + 3) #define Topen (Tcant_open + 6) +EXTERN const char To_o_reset[] E_INIT(" -o .reset"); +#define To_reset (To_o_reset + 4) #define TPATH (TFPATH + 1) +#define Tpo (Tset_po + 4) #define Tpv (TpVv + 1) EXTERN const char TpVv[] E_INIT("Vpv"); #define TPWD (Tno_OLDPWD + 6) @@ -1053,6 +1061,7 @@ EXTERN const char TREPLY[] E_INIT("REPLY"); EXTERN const char Treq_arg[] E_INIT("requires an argument"); EXTERN const char Tselect[] E_INIT("select"); #define Tset (Tf_parm + 18) +EXTERN const char Tset_po[] E_INIT("set +o"); EXTERN const char Tsghset[] E_INIT("*=#set"); #define Tsh (Tmksh + 2) #define TSHELL (TEXECSHELL + 4) @@ -1083,6 +1092,7 @@ EXTERN const char Tuser_sp2[] E_INIT(" user "); #define Twrite (Tshf_write + 4) EXTERN const char Tf__S[] E_INIT(" %S"); #define Tf__d (Tunexpected_type + 22) +#define Tf_ss (Tf__ss + 1) EXTERN const char Tf__ss[] E_INIT(" %s%s"); #define Tf__sN (Tf_s_s_sN + 5) #define Tf_T (Tf_s_T + 3) @@ -1091,6 +1101,7 @@ EXTERN const char Tf_s_[] E_INIT("%s "); EXTERN const char Tf_s_T[] E_INIT("%s %T"); EXTERN const char Tf_s_s_sN[] E_INIT("%s %s %s\n"); #define Tf_s_s (Tf_sD_s_s + 4) +#define Tf__s_s (Tf_sD_s_s + 3) #define Tf_s_sD_s (Tf_cant_ss_s + 6) EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s"); EXTERN const char Tf_sD_[] E_INIT("%s: "); @@ -1198,7 +1209,10 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty"); #define Tnot_started "not started" #define TOLDPWD "OLDPWD" #define Topen "open" +#define To_o_reset " -o .reset" +#define To_reset ".reset" #define TPATH "PATH" +#define Tpo "+o" #define Tpv "pv" #define TpVv "Vpv" #define TPWD "PWD" @@ -1213,6 +1227,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty"); #define Treq_arg "requires an argument" #define Tselect "select" #define Tset "set" +#define Tset_po "set +o" #define Tsghset "*=#set" #define Tsh "sh" #define TSHELL "SHELL" @@ -1243,6 +1258,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty"); #define Twrite "write" #define Tf__S " %S" #define Tf__d " %d" +#define Tf_ss "%s%s" #define Tf__ss " %s%s" #define Tf__sN " %s\n" #define Tf_T "%T" @@ -1251,6 +1267,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty"); #define Tf_s_T "%s %T" #define Tf_s_s_sN "%s %s %s\n" #define Tf_s_s "%s %s" +#define Tf__s_s " %s %s" #define Tf_s_sD_s "%s %s: %s" #define Tf_optfoo "%s%s-%c: %s" #define Tf_sD_ "%s: " diff --git a/src/sh_flags.gen b/src/sh_flags.gen index a0a0f6a..538baf1 100644 --- a/src/sh_flags.gen +++ b/src/sh_flags.gen @@ -21,7 +21,7 @@ #ifndef SHFLAGS_OPTCS #if defined(SHFLAGS_DEFNS) -__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.8 2019/12/30 03:58:58 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.9 2020/05/16 22:38:25 tg Exp $"); #elif defined(SHFLAGS_ENUMS) #define FN(sname,cname,flags,ochar) cname, #define F0(sname,cname,flags,ochar) cname = 0, @@ -95,7 +95,6 @@ FN("xtrace", FXTRACE, OF_ANY, 'x') #ifndef SHFLAGS_NOT_CMD FN("", FCOMMAND, OF_CMDLINE, 'c') #endif -FN("", FAS_BUILTIN, OF_INTERNAL, 0) FN("", FTALKING_I, OF_INTERNAL, 0) #undef F0 #undef FN diff --git a/src/sh_flags.opt b/src/sh_flags.opt index d81d9d9..d84d1f1 100644 --- a/src/sh_flags.opt +++ b/src/sh_flags.opt @@ -19,7 +19,7 @@ */ @SHFLAGS_DEFNS -__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.8 2019/12/30 03:58:58 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.9 2020/05/16 22:38:25 tg Exp $"); @SHFLAGS_ENUMS #define FN(sname,cname,flags,ochar) cname, #define F0(sname,cname,flags,ochar) cname = 0, @@ -187,10 +187,6 @@ FN("", FCOMMAND, OF_CMDLINE * anonymous flags: used internally by shell only (not visible to user) */ -/* ./. direct builtin call (divined from argv[0] multi-call binary) */ ->| -FN("", FAS_BUILTIN, OF_INTERNAL - /* ./. (internal) initial shell was interactive */ >| FN("", FTALKING_I, OF_INTERNAL |