From b02792c9ac5b8ff483bec88fdb16c886edf576f7 Mon Sep 17 00:00:00 2001 From: Sadaf Ebrahimi Date: Fri, 31 Mar 2023 18:17:33 +0000 Subject: [PATCH] Upgrade mksh to mksh-R59c Test: TreeHugger Change-Id: I6d4f4497e54fd97672ee0d634b322277326a9748 --- Android.bp | 3 +- Android.patch.txt | 36 +++-- METADATA | 15 ++ src/Build.sh | 98 ++++++++----- src/FAQ2HTML.sh | 6 +- src/check.pl | 6 +- src/check.t | 47 +++--- src/edit.c | 122 ++++++++-------- src/exec.c | 8 +- src/expr.c | 7 +- src/funcs.c | 250 ++++---------------------------- src/histrap.c | 7 +- src/lksh.1 | 13 +- src/main.c | 7 +- src/misc.c | 50 ++++--- src/mksh.1 | 47 ++++-- src/mksh.faq | 36 ++++- src/os2.c | 89 ++++++++---- src/rlimits.gen | 6 +- src/rlimits.opt | 6 +- src/sh.h | 14 +- src/shf.c | 6 +- src/syn.c | 13 +- src/tree.c | 100 +++++++------ src/ulimit.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++ src/ulimits.gen | 60 ++++++++ src/ulimits.opt | 46 ++++++ src/var.c | 4 +- 28 files changed, 934 insertions(+), 528 deletions(-) create mode 100644 src/ulimit.c create mode 100644 src/ulimits.gen create mode 100644 src/ulimits.opt diff --git a/Android.bp b/Android.bp index dcb534e..a300947 100644 --- a/Android.bp +++ b/Android.bp @@ -38,6 +38,7 @@ cc_defaults { "src/shf.c", "src/syn.c", "src/tree.c", + "src/ulimit.c", "src/var.c", ], @@ -125,7 +126,7 @@ cc_defaults { "-DHAVE_SYS_ERRLIST_DECL=0", "-DHAVE_SYS_SIGLIST_DECL=1", "-DHAVE_PERSISTENT_HISTORY=0", - "-DMKSH_BUILD_R=592", + "-DMKSH_BUILD_R=593", // Additional flags "-DMKSH_DEFAULT_PROFILEDIR=\"/system/etc\"", diff --git a/Android.patch.txt b/Android.patch.txt index eefcd5c..72a9db5 100644 --- a/Android.patch.txt +++ b/Android.patch.txt @@ -1,8 +1,7 @@ -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 @@ +diff -u mksh-R59c/mksh/funcs.c src/funcs.c +--- mksh-R59c/mksh/funcs.c 2020-08-27 19:53:11.000000000 +0000 ++++ src/funcs.c 2023-03-31 18:02:12.376044783 +0000 +@@ -98,7 +98,9 @@ {Tsgbreak, c_brkcont}, {T__builtin, c_builtin}, {Tbuiltin, c_builtin}, @@ -12,7 +11,7 @@ diff -u mksh-R59b/funcs.c src/funcs.c {Tcd, c_cd}, /* dash compatibility hack */ {"chdir", c_cd}, -@@ -125,7 +127,9 @@ +@@ -119,7 +121,9 @@ {"pwd", c_pwd}, {Tread, c_read}, {Tdsgreadonly, c_typeset}, @@ -22,7 +21,7 @@ diff -u mksh-R59b/funcs.c src/funcs.c {"~rename", c_rename}, {"*=return", c_exitreturn}, {Tsghset, c_set}, -@@ -159,8 +163,10 @@ +@@ -153,8 +157,10 @@ {"~printf", c_printf}, #endif #if HAVE_SELECT @@ -33,25 +32,22 @@ diff -u mksh-R59b/funcs.c src/funcs.c #ifdef __MirBSD__ /* alias to "true" for historical reasons */ {"domainname", c_true}, -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 @@ +diff -u mksh-R59c/mksh/main.c src/main.c +--- mksh-R59c/mksh/main.c 2020-10-01 20:29:21.000000000 +0000 ++++ src/main.c 2023-03-31 18:09:32.827660886 +0000 +@@ -413,6 +413,12 @@ + /* import environment */ init_environ(); - ++ + /* override default PATH regardless of environment */ +#ifdef MKSH_DEFPATH_OVERRIDE + vp = global(TPATH); + setstr(vp, MKSH_DEFPATH_OVERRIDE, KSH_RETURN_ERROR); +#endif -+ + /* for security */ 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 +Only in src/: rlimits.gen +Only in src/: sh_flags.gen +Only in src/: ulimits.gen diff --git a/METADATA b/METADATA index d97975c..c6745e1 100644 --- a/METADATA +++ b/METADATA @@ -1,3 +1,18 @@ +name: "mksh" third_party { + url { + type: HOMEPAGE + value: "http://www.mirbsd.org/mksh" + } + url { + type: ARCHIVE + value: "http://www.mirbsd.org/MirOS/dist/mir/mksh/mksh-R59c.tgz" + } + version: "mksh-R59c" license_type: NOTICE + last_upgrade_date { + year: 2023 + month: 3 + day: 31 + } } diff --git a/src/Build.sh b/src/Build.sh index 1d30045..597d8ca 100644 --- a/src/Build.sh +++ b/src/Build.sh @@ -1,5 +1,5 @@ #!/bin/sh -srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.756 2020/05/16 22:53:03 tg Exp $' +srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.763 2020/09/04 21:01:37 tg Exp $' #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, @@ -721,6 +721,13 @@ case $TARGET_OS in add_cppflags -DMKSH_NO_SIGSETJMP add_cppflags -DMKSH_TYPEDEF_SIG_ATOMIC_T=int ;; +A/UX) + add_cppflags -D_POSIX_SOURCE + : "${CC=gcc}" + : "${LIBS=-lposix}" + # GCC defines AUX but cc nothing + add_cppflags -D__A_UX__ + ;; AIX) add_cppflags -D_ALL_SOURCE : "${HAVE_SETLOCALE_CTYPE=0}" @@ -862,10 +869,9 @@ Minix-vmd) ;; Minix3) add_cppflags -DMKSH_UNEMPLOYED - add_cppflags -DMKSH_NO_LIMITS add_cppflags -D_POSIX_SOURCE -D_POSIX_1_SOURCE=2 -D_MINIX oldish_ed=no-stderr-ed # /usr/bin/ed(!) is broken - : "${HAVE_SETLOCALE_CTYPE=0}" + : "${HAVE_SETLOCALE_CTYPE=0}${MKSH_UNLIMITED=1}" #XXX recheck ulimit ;; MirBSD) ;; @@ -898,7 +904,7 @@ NEXTSTEP) Ninix3) # similar to Minix3 add_cppflags -DMKSH_UNEMPLOYED - add_cppflags -DMKSH_NO_LIMITS + : "${MKSH_UNLIMITED=1}" #XXX recheck ulimit # but no idea what else could be needed oswarn="; it has unknown issues" ;; @@ -911,15 +917,14 @@ OS/2) HAVE_ISOFF_MKSH_ASSUME_UTF8=1 HAVE_TERMIOS_H=0 HAVE_MKNOD=0 # setmode() incompatible - oswarn="; it is being ported" check_categories="$check_categories nosymlink" : "${CC=gcc}" : "${SIZE=: size}" SRCS="$SRCS os2.c" add_cppflags -DMKSH_UNEMPLOYED add_cppflags -DMKSH_NOPROSPECTOFWORK - add_cppflags -DMKSH_NO_LIMITS add_cppflags -DMKSH_DOSPATH + : "${MKSH_UNLIMITED=1}" if test $textmode = 0; then x='dis' y='standard OS/2 tools' @@ -1363,7 +1368,7 @@ esac etd=" on $et" case $et in klibc) - add_cppflags -DMKSH_NO_LIMITS + : "${MKSH_UNLIMITED=1}" ;; unknown) # nothing special detected, don’t worry @@ -1898,23 +1903,6 @@ ac_test can_ucbint8 '!' can_int8type 1 "for UCB 8-bit integer type" <<-'EOF' int main(int ac, char *av[]) { return ((u_int8_t)(size_t)av[ac]); } EOF -ac_test rlim_t <<-'EOF' - #include - #if HAVE_BOTH_TIME_H - #include - #include - #elif HAVE_SYS_TIME_H - #include - #elif HAVE_TIME_H - #include - #endif - #if HAVE_SYS_RESOURCE_H - #include - #endif - #include - int main(void) { return (((int)(rlim_t)0) + isatty(0)); } -EOF - # only testn: added later below ac_testn sig_t <<-'EOF' #include @@ -2067,6 +2055,35 @@ ac_test lock_fcntl '!' flock 1 'whether we can lock files with fcntl' <<-'EOF' } EOF +ac_test rlimit '' 'getrlimit and setrlimit' <<-'EOF' + #define MKSH_INCLUDES_ONLY + #include "sh.h" + int main(void) { + struct rlimit l; + if (getrlimit(0, &l)) return 1; + l.rlim_max = l.rlim_cur; + l.rlim_cur = RLIM_INFINITY; + return (setrlimit(0, &l)); + } +EOF + +ac_test rlim_t rlimit 0 <<-'EOF' + #include + #if HAVE_BOTH_TIME_H + #include + #include + #elif HAVE_SYS_TIME_H + #include + #elif HAVE_TIME_H + #include + #endif + #if HAVE_SYS_RESOURCE_H + #include + #endif + #include + int main(void) { return (((int)(rlim_t)0) + isatty(0)); } +EOF + ac_test getrusage <<-'EOF' #define MKSH_INCLUDES_ONLY #include "sh.h" @@ -2457,11 +2474,24 @@ mksh_cfg= cfg_NSIG $e done. fi +if test 1 = "$MKSH_UNLIMITED"; then + add_cppflags -DMKSH_UNLIMITED +else + MKSH_UNLIMITED=0 +fi + +if test 1 = "$USE_PRINTF_BUILTIN"; then + add_cppflags -DMKSH_PRINTF_BUILTIN +else + USE_PRINTF_BUILTIN=0 +fi + addsrcs '!' HAVE_STRLCPY strlcpy.c addsrcs USE_PRINTF_BUILTIN printf.c -test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN +addsrcs '!' MKSH_UNLIMITED ulimit.c + test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose" -add_cppflags -DMKSH_BUILD_R=592 +add_cppflags -DMKSH_BUILD_R=593 $e $bi$me: Finished configuration testing, now producing output.$ao @@ -2544,7 +2574,7 @@ cat >test.sh <<-EOF args[\${#args[*]}]=\$TMPDIR fi print Testing mksh for conformance: - grep -F -e Mir''OS: -e MIRBSD "\$sflag" + grep -F -e 'KSH R' -e Mir''OS: "\$sflag" | sed '/KSH/s/^./& /' print "This shell is actually:\\n\\t\$KSH_VERSION" print 'test.sh built for mksh $dstversion' cstr='\$os = defined \$^O ? \$^O : "unknown";' @@ -2604,7 +2634,6 @@ for file in $SRCS; do op=`echo x"$file" | sed 's/^x\(.*\)\.c$/\1./'` test -f $file || file=$srcdir/$file files="$files$sp$file" - sp=' ' echo "$CC $CFLAGS $CPPFLAGS $emitbc $file || exit 1" >>Rebuild.sh if test $cm = dragonegg; then echo "mv ${op}s ${op}ll" >>Rebuild.sh @@ -2613,6 +2642,7 @@ for file in $SRCS; do else objs="$objs$sp${op}o" fi + sp=' ' done case $cm in dragonegg|llvm) @@ -2628,7 +2658,7 @@ echo tcfn=$mkshexe >>Rebuild.sh echo "$CC $CFLAGS $LDFLAGS -o \$tcfn $lobjs $LIBS $ccpr" >>Rebuild.sh echo "test -f \$tcfn || exit 1; $SIZE \$tcfn" >>Rebuild.sh if test $cm = makefile; then - extras='emacsfn.h exprtok.h rlimits.opt sh.h sh_flags.opt var_spec.h' + extras='emacsfn.h exprtok.h rlimits.opt sh.h sh_flags.opt ulimits.opt var_spec.h' test 0 = $HAVE_SYS_SIGNAME && extras="$extras signames.inc" gens= genq= for file in $optfiles; do @@ -2734,11 +2764,11 @@ if test $legacy = 0; then fi $e $e Installing the manual: -if test -e FAQ.htm; then +if test -f FAQ.htm; then $e "# $i -c -o root -g bin -m 444 FAQ.htm /usr/share/doc/mksh/" fi if test -f mksh.cat1; then - if test -e FAQ.htm; then + if test -f FAQ.htm; then $e plus either fi $e "# $i -c -o root -g bin -m 444 lksh.cat1" \ @@ -2751,7 +2781,7 @@ $e "# $i -c -o root -g bin -m 444 lksh.1 mksh.1 /usr/share/man/man1/" $e $e Run the regression test suite: ./test.sh $e Please also read the sample file dot.mkshrc and the fine manual. -test -e FAQ.htm || \ +test -f FAQ.htm || \ $e Run FAQ2HTML.sh and place FAQ.htm into a suitable location as well. exit 0 @@ -2775,6 +2805,7 @@ TARGET_OS default: $(uname -s || uname) TARGET_OSREV [QNX] default: $(uname -r) ==== feature selectors ==== +MKSH_UNLIMITED 1 to omit ulimit builtin completely USE_PRINTF_BUILTIN 1 to include (unsupported) printf(1) as builtin ===== general format ===== HAVE_STRLEN ac_test @@ -2782,7 +2813,7 @@ HAVE_STRING_H ac_header HAVE_CAN_FSTACKPROTECTORALL ac_flags ==== cpp definitions ==== -DEBUG dont use in production, wants gcc, implies: +DEBUG don’t use in production, wants gcc, implies: DEBUG_LEAKS enable freeing resources before exiting KSH_VERSIONNAME_VENDOR_EXT when patching; space+plus+word (e.g. " +SuSE") MKSHRC_PATH "~/.mkshrc" (do not change) @@ -2804,7 +2835,6 @@ MKSH_NOPROSPECTOFWORK disable jobs, co-processes, etc. (do not use) MKSH_NOPWNAM skip PAM calls, for -static on glibc or Solaris MKSH_NO_CMDLINE_EDITING disable command line editing code entirely MKSH_NO_DEPRECATED_WARNING omit warning when deprecated stuff is run -MKSH_NO_LIMITS omit ulimit code MKSH_NO_SIGSETJMP define if sigsetjmp is broken or not available MKSH_NO_SIGSUSPEND use sigprocmask+pause instead of sigsuspend MKSH_SMALL omit some code, optimise hard for size (slower) diff --git a/src/FAQ2HTML.sh b/src/FAQ2HTML.sh index 180ed98..ecff077 100644 --- a/src/FAQ2HTML.sh +++ b/src/FAQ2HTML.sh @@ -1,5 +1,5 @@ -#!/bin/mksh -rcsid='$MirOS: src/bin/mksh/FAQ2HTML.sh,v 1.1 2020/02/03 22:23:33 tg Exp $' +#!/bin/sh +rcsid='$MirOS: src/bin/mksh/FAQ2HTML.sh,v 1.2 2020/10/31 04:17:36 tg Exp $' #- # Copyright © 2020 # mirabilos @@ -37,7 +37,7 @@ fi src_id=$(sed $p -n '/^RCSID: /s///p' "$srcdir"/mksh.faq) # sanity check case $src_id in -(*"$nl"*) +*"$nl"*) echo >&2 "E: more than one RCSID in mksh.faq?" exit 1 ;; esac diff --git a/src/check.pl b/src/check.pl index c08e287..8e3efe9 100644 --- a/src/check.pl +++ b/src/check.pl @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.pl,v 1.50 2019/08/01 20:05:55 tg Exp $ +# $MirOS: src/bin/mksh/check.pl,v 1.51 2020/06/22 17:10:59 tg Exp $ # $OpenBSD: th,v 1.1 2013/12/02 20:39:44 millert Exp $ #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, @@ -55,7 +55,7 @@ # default is no arguments. # script m Value is written to a file which # is passed as an argument to the program -# (after the arguments arguments) +# (after the arguments from arguments) # stdin m Value is written to a file which is # used as standard-input for the program; # default is to use /dev/null. @@ -195,7 +195,7 @@ Usage: $prog [-Pv] [-C cat] [-e e=v] [-p prog] [-s fn] [-T dir] \ the path (kludge option) -p p Use p as the program to test -s s Read tests from file s; if s is a directory, it is recursively - scaned for test files (which end in .t). + scanned for test files (which end in .t). -T dir Use dir instead of /tmp to hold temporary files -t t Use t as default time limit for tests (default is unlimited) -U lcl Use lcl as UTF-8 locale (e.g. C.UTF-8) instead of the default diff --git a/src/check.t b/src/check.t index 8818822..311f5c1 100644 --- a/src/check.t +++ b/src/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.845 2020/05/16 22:19:15 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.853 2020/10/31 03:53:03 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/05/16 + KSH R59 2020/10/31 description: Check base version of full shell stdin: @@ -6109,7 +6109,7 @@ expected-stderr-pattern: /does\/not\/exist/ --- name: regression-28 description: - variable assignements not detected well + variable assignments not detected well stdin: a.x=1 echo hi expected-exit: e != 0 @@ -6184,7 +6184,7 @@ expected-stdout: --- name: regression-35 description: - Tempory files used for here-docs in functions get trashed after + Temporay files used for here-docs in functions get trashed after the function is parsed (before it is executed) stdin: f1() { @@ -7457,7 +7457,7 @@ expected-stdout: name: xxx-param-subst-qmark-1 description: Check suppresion of error message with null string. According to - POSIX, it shouldn't print the error as 'word' isn't ommitted. + POSIX, it shouldn't print the error as 'word' isn't omitted. ksh88/93, Solaris /bin/sh and /usr/xpg4/bin/sh all print the error. stdin: unset foo @@ -8853,9 +8853,10 @@ description: XXX if the OS can already execute them, we lose note: cygwin execve(2) doesn't return to us with ENOEXEC, we lose note: Ultrix perl5 t4 returns 65280 (exit-code 255) and no text + note: A/UX perl5 returns 6400 (exit-code 25), passes #1-3 XXX fails when LD_PRELOAD is set with -e and Perl chokes it (ASan) need-pass: no -category: !os:cygwin,!os:midipix,!os:msys,!os:ultrix,!os:uwin-nt,!smksh +category: !os:aux,!os:cygwin,!os:midipix,!os:msys,!os:ultrix,!os:uwin-nt,!smksh env-setup: !FOO=BAR! stdin: print '#!'"$__progname"'\nprint "1 a=$ENV{FOO}";' >t1 @@ -11489,13 +11490,11 @@ name: fd-cloexec-1 description: Verify that file descriptors > 2 are private for Korn shells AT&T ksh93 does this still, which means we must keep it as well - XXX fails on some old Perl installations -need-pass: no stdin: cat >cld <<-EOF #!$__perlname - open(my \$fh, ">&", 9) or die "E: open \$!"; - syswrite(\$fh, "Fowl\\n", 5) or die "E: write \$!"; + open(FH, ">&9") or die "E: open \$!"; + syswrite(FH, "Fowl\\n", 5) or die "E: write \$!"; EOF chmod +x cld exec 9>&1 @@ -11508,13 +11507,11 @@ name: fd-cloexec-2 description: Verify that file descriptors > 2 are not private for POSIX shells See Debian Bug #154540, Closes: #499139 - XXX fails on some old Perl installations -need-pass: no stdin: cat >cld <<-EOF #!$__perlname - open(my \$fh, ">&", 9) or die "E: open \$!"; - syswrite(\$fh, "Fowl\\n", 5) or die "E: write \$!"; + open(FH, ">&9") or die "E: open \$!"; + syswrite(FH, "Fowl\\n", 5) or die "E: write \$!"; EOF chmod +x cld test -n "$POSH_VERSION" || set -o posix @@ -12079,10 +12076,10 @@ expected-stdout: EOFN )|tr u x); } function reread_IOWRITE_IOCLOB_IOHERE_noIOSKIP { - x=$( ( \cat >|bar <<"EOFN" + x=$( ( \cat >|bar <<"EOFN" ) | \tr u x foo EOFN - ) | \tr u x ) + ) } inline_IOWRITE_noIOCLOB_IOHERE_IOSKIP() { cat 1>bar <<-EOFI @@ -12112,10 +12109,10 @@ expected-stdout: EOFI )|tr u x); } function reread_IOWRITE_noIOCLOB_IOHERE_IOSKIP { - x=$( ( \cat >bar <<-EOFI + x=$( ( \cat >bar <<-EOFI ) | \tr u x foo EOFI - ) | \tr u x ) + ) } inline_IORDWR_IODUP() { sh 1<>/dev/console 0<&1 2>&1 @@ -13640,6 +13637,11 @@ description: words, and command -p[vV] should find aliases, reserved words, and builtins over external commands. stdin: + # extra checks prep + mkdir mrr + :>mrr/miau + chmod +x mrr/miau + # priorities PATH=/bin:/usr/bin alias foo="bar baz" alias '[ab]=:' @@ -13653,6 +13655,14 @@ stdin: # extra checks alias '[ab]' whence '[ab]' + PATH=mrr + case $(command -v miau) { + (mrr/miau) echo fail ;; + (!(/*|[A-Z]:/*)) echo fail2 ;; + ($PWD/mrr/miau) echo ok ;; + (/*|[A-Z]:/*) echo pwd bad? ;; + (*) echo not reached ;; + } expected-stdout: if if @@ -13680,6 +13690,7 @@ expected-stdout: '[ab]' is an alias for : '[ab]'=: : + ok --- name: whence-preserve-tradition description: diff --git a/src/edit.c b/src/edit.c index 8c1c2c8..a98f5dd 100644 --- a/src/edit.c +++ b/src/edit.c @@ -29,7 +29,7 @@ #ifndef MKSH_NO_CMDLINE_EDITING -__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.351 2020/04/15 20:16:19 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.357 2020/10/31 05:02:17 tg Exp $"); /* * in later versions we might use libtermcap for this, but since external @@ -41,6 +41,10 @@ __RCSID("$MirOS: src/bin/mksh/edit.c,v 1.351 2020/04/15 20:16:19 tg Exp $"); #define MKSH_CLS_STRING KSH_ESC_STRING "[;H" KSH_ESC_STRING "[J" #endif +#if !defined(MKSH_SMALL) || !MKSH_S_NOVI +static const char ctrl_x_e[] = "fc -e \"${VISUAL:-${EDITOR:-vi}}\" --"; +#endif + /* tty driver characters we are interested in */ #define EDCHAR_DISABLED 0xFFFFU #define EDCHAR_INITIAL 0xFFFEU @@ -153,7 +157,7 @@ x_getc(void) char c; ssize_t n; - while ((n = blocking_read(STDIN_FILENO, &c, 1)) < 0 && errno == EINTR) + while ((n = blocking_read(0, &c, 1)) < 0 && errno == EINTR) if (trap) { x_mode(false); runtraps(0); @@ -970,7 +974,6 @@ static char *wbuf[2]; /* window buffers */ static int wbuf_len; /* length of window buffers (x_cols - 3) */ static int win; /* window buffer in use */ static char morec; /* more character at right of window */ -static int lastref; /* argument to last refresh() */ static int holdlen; /* length of holdbuf */ #endif static int pwidth; /* width of prompt */ @@ -989,11 +992,11 @@ static void x_zots(char *); static void x_zotc3(char **); static void x_vi_zotc(int); static void x_load_hist(char **); -static int x_search(char *, int, int); +static int x_search(const char *, int, int); #ifndef MKSH_SMALL static int x_search_dir(int); #endif -static int x_match(char *, char *); +static int x_match(const char *, const char *); static void x_redraw(int); static void x_push(size_t); static void x_bind_showone(int, int); @@ -1946,7 +1949,7 @@ x_search_hist(int c) offset = x_match(xbuf, pat); if (offset >= 0) { x_goto(xbuf + offset + (p - pat) - - (*pat == '^')); + (*pat == '^' ? 1 : 0)); continue; } } @@ -1968,18 +1971,21 @@ x_search_hist(int c) /* search backward from current line */ static int -x_search(char *pat, int sameline, int offset) +x_search(const char *pat, int sameline, int offset) { char **hp; int i; + size_t patlen = strlen(pat); + if (*pat == '^') + --patlen; for (hp = x_histp - (sameline ? 0 : 1); hp >= history; --hp) { i = x_match(*hp, pat); if (i >= 0) { if (offset < 0) x_e_putc2('\n'); x_load_hist(hp); - x_goto(xbuf + i + strlen(pat) - (*pat == '^')); + x_goto(xbuf + i + patlen); return (i); } } @@ -2024,7 +2030,7 @@ x_search_dir(int search_dir /* should've been bool */) /* return position of first match of pattern in string, else -1 */ static int -x_match(char *str, char *pat) +x_match(const char *str, const char *pat) { if (*pat == '^') { return ((strncmp(str, pat + 1, strlen(pat + 1)) == 0) ? 0 : -1); @@ -3125,10 +3131,6 @@ static int x_edit_line(int c MKSH_A_UNUSED) { if (x_arg_defaulted) { - if (xep == xbuf) { - x_e_putc2(KSH_BEL); - return (KSTD); - } if (modified) { *xep = '\0'; histsave(&source->line, xbuf, HIST_STORE, true); @@ -3137,10 +3139,9 @@ x_edit_line(int c MKSH_A_UNUSED) x_arg = source->line - (histptr - x_histp); } if (x_arg) - shf_snprintf(xbuf, xend - xbuf, Tf_sd, - "fc -e ${VISUAL:-${EDITOR:-vi}} --", x_arg); + shf_snprintf(xbuf, xend - xbuf, Tf_sd, ctrl_x_e, x_arg); else - strlcpy(xbuf, "fc -e ${VISUAL:-${EDITOR:-vi}} --", xend - xbuf); + strlcpy(xbuf, ctrl_x_e, xend - xbuf); xep = strnul(xbuf); return (x_newline('\n')); } @@ -3433,13 +3434,13 @@ static int Forwword(int); static int Backword(int); static int Endword(int); static int grabhist(int, int); -static int grabsearch(int, int, int, const char *); +static int grabsearch(const char *, int, int, bool); static void redraw_line(bool); -static void refresh(int); +static void refresh(bool); static int outofwin(void); static void rewindow(void); static int newcol(unsigned char, int); -static void display(char *, char *, int); +static void display(char *, char *, bool); static void ed_mov_opt(int, char *); static int expand_word(int); static int complete_word(int, int); @@ -3610,7 +3611,6 @@ x_vi(char *buf) winwidth = x_cols - pwidth - 3; win = 0; morec = ' '; - lastref = 1; holdlen = 0; editmode = 2; @@ -3712,7 +3712,7 @@ vi_hook(int ch) case 0: if (state == VLIT) { vs->cursor--; - refresh(0); + refresh(false); } else refresh(insert != 0); break; @@ -3738,7 +3738,7 @@ vi_hook(int ch) if (putbuf(ord(ch) == ORD('/') ? "/" : "?", 1, false) != 0) return (-1); - refresh(0); + refresh(false); } if (state == VVERSION) { save_cbuf(); @@ -3746,7 +3746,7 @@ vi_hook(int ch) vs->linelen = 0; putbuf(KSH_VERSION, strlen(KSH_VERSION), false); - refresh(0); + refresh(false); } } } @@ -3758,14 +3758,14 @@ vi_hook(int ch) vi_error(); } else vs->cbuf[vs->cursor++] = ch; - refresh(1); + refresh(true); state = VNORMAL; break; case VVERSION: restore_cbuf(); state = VNORMAL; - refresh(0); + refresh(false); break; case VARG1: @@ -3829,7 +3829,7 @@ vi_hook(int ch) if (!srchpat[0]) { vi_error(); state = VNORMAL; - refresh(0); + refresh(false); return (0); } } else { @@ -3842,17 +3842,17 @@ vi_hook(int ch) srchlen--; vs->linelen -= char_len(locpat[srchlen]); vs->cursor = vs->linelen; - refresh(0); + refresh(false); return (0); } restore_cbuf(); state = VNORMAL; - refresh(0); + refresh(false); } else if (isched(ch, edchars.kill)) { srchlen = 0; vs->linelen = 1; vs->cursor = 1; - refresh(0); + refresh(false); return (0); } else if (isched(ch, edchars.werase)) { unsigned int i, n; @@ -3871,7 +3871,7 @@ vi_hook(int ch) vs->linelen -= char_len(locpat[i]); srchlen = (int)n; vs->cursor = vs->linelen; - refresh(0); + refresh(false); return (0); } else { if (srchlen == SRCHLEN - 1) @@ -3890,7 +3890,7 @@ vi_hook(int ch) vs->cbuf[vs->linelen++] = ch; } vs->cursor = vs->linelen; - refresh(0); + refresh(false); } return (0); } @@ -3931,7 +3931,7 @@ vi_hook(int ch) switch (vi_cmd(argc1, curcmd)) { case -1: vi_error(); - refresh(0); + refresh(false); break; case 0: if (insert != 0) @@ -3939,7 +3939,7 @@ vi_hook(int ch) refresh(insert != 0); break; case 1: - refresh(0); + refresh(false); return (1); case 2: /* back from a 'v' command - don't redraw the screen */ @@ -3954,7 +3954,7 @@ vi_hook(int ch) switch (vi_cmd(lastac, lastcmd)) { case -1: vi_error(); - refresh(0); + refresh(false); break; case 0: if (insert != 0) { @@ -3967,10 +3967,10 @@ vi_hook(int ch) vi_error(); } } - refresh(0); + refresh(false); break; case 1: - refresh(0); + refresh(false); return (1); case 2: /* back from a 'v' command - can't happen */ @@ -4135,8 +4135,9 @@ static int vi_cmd(int argcnt, const char *cmd) { int ncursor; - int cur, c1, c2, c3 = 0; + int cur, c1, c2; int any; + bool b; struct edstate *t; if (argcnt == 0 && !is_zerocount(*cmd)) @@ -4407,8 +4408,6 @@ vi_cmd(int argcnt, const char *cmd) case ORD('v'): if (!argcnt) { - if (vs->linelen == 0) - return (-1); if (modified) { vs->cbuf[vs->linelen] = '\0'; histsave(&source->line, vs->cbuf, @@ -4419,12 +4418,9 @@ vi_cmd(int argcnt, const char *cmd) } if (argcnt) shf_snprintf(vs->cbuf, vs->cbufsize, Tf_sd, - "fc -e ${VISUAL:-${EDITOR:-vi}} --", - argcnt); + ctrl_x_e, argcnt); else - strlcpy(vs->cbuf, - "fc -e ${VISUAL:-${EDITOR:-vi}} --", - vs->cbufsize); + strlcpy(vs->cbuf, ctrl_x_e, vs->cbufsize); vs->linelen = strlen(vs->cbuf); return (2); @@ -4474,25 +4470,23 @@ vi_cmd(int argcnt, const char *cmd) /* FALLTHROUGH */ case ORD('/'): - c3 = 1; + c1 = 1; srchlen = 0; lastsearch = *cmd; - /* FALLTHROUGH */ + if (0) + /* FALLTHROUGH */ case ORD('n'): case ORD('N'): + c1 = 0; if (lastsearch == ORD(' ')) return (-1); - if (lastsearch == ORD('?')) - c1 = 1; - else - c1 = 0; + b = (lastsearch == ORD('?')); if (*cmd == 'N') - c1 = !c1; - if ((c2 = grabsearch(modified, hnum, - c1, srchpat)) < 0) { - if (c3) { + b = !b; + if ((c2 = grabsearch(srchpat, modified, hnum, b)) < 0) { + if (c1) { restore_cbuf(); - refresh(0); + refresh(false); } return (-1); } else { @@ -5117,20 +5111,20 @@ grabhist(int save, int n) } static int -grabsearch(int save, int start, int fwd, const char *pat) +grabsearch(const char *pat, int save, int start, bool fwd) { char *hptr; int hist; bool anchored; - if ((start == 0 && fwd == 0) || (start >= hlast - 1 && fwd == 1)) + if ((start == 0 && !fwd) || (start >= hlast - 1 && fwd)) return (-1); if (fwd) start++; else start--; anchored = *pat == '^' ? (++pat, true) : false; - if ((hist = findhist(start, fwd, pat, anchored)) < 0) { + if ((hist = findhist(start, pat, fwd, anchored)) < 0) { /* (start != 0 && fwd && match(holdbufp, pat) >= 0) */ if (start != 0 && fwd && strcmp(holdbufp, pat) >= 0) { restore_cbuf(); @@ -5163,12 +5157,8 @@ redraw_line(bool newl) } static void -refresh(int leftside) +refresh(bool leftside) { - if (leftside < 0) - leftside = lastref; - else - lastref = leftside; if (outofwin()) rewindow(); display(wbuf[1 - win], wbuf[win], leftside); @@ -5224,7 +5214,7 @@ newcol(unsigned char ch, int col) } static void -display(char *wb1, char *wb2, int leftside) +display(char *wb1, char *wb2, bool leftside) { unsigned char ch; char *twb1, *twb2, mc; @@ -5379,7 +5369,7 @@ expand_word(int cmd) hnum = hlast; insert = INSERT; lastac = 0; - refresh(0); + refresh(false); return (rval); } @@ -5494,7 +5484,7 @@ complete_word(int cmd, int count) insert = INSERT; /* prevent this from being redone... */ lastac = 0; - refresh(0); + refresh(false); return (rval); } diff --git a/src/exec.c b/src/exec.c index 9d1b69b..447d441 100644 --- a/src/exec.c +++ b/src/exec.c @@ -24,7 +24,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.223 2020/04/07 23:14:41 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.224 2020/08/27 19:52:43 tg Exp $"); #ifndef MKSH_DEFAULT_EXECSHELL #define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh" @@ -1213,7 +1213,7 @@ findcom(const char *name, int flags) } Search: - if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET))) && + if ((!tp || (tp->type == CTALIAS && !(tp->flag & ISSET))) && (flags & FC_PATH)) { if (!tp) { if (insert && !(flags & FC_DEFPATH)) { @@ -1351,10 +1351,8 @@ search_path(const char *name, const char *lpath, XcheckN(xs, xp, p - sp); memcpy(xp, sp, p - sp); xp += p - sp; -#ifdef __OS2__ - if (xp > Xstring(xs, xp) && mksh_cdirsep(xp[-1])) + if (mksh_cdirsep(xp[-1])) xp--; -#endif *xp++ = '/'; } sp = p; diff --git a/src/expr.c b/src/expr.c index 6764279..cb389c1 100644 --- a/src/expr.c +++ b/src/expr.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.107 2020/03/27 02:49:40 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.108 2020/06/20 02:27:50 tg Exp $"); #define EXPRTOK_DEFNS #include "exprtok.h" @@ -886,8 +886,8 @@ static int mb_ucsbsearch(const struct mb_ucsrange arr[], size_t elems, unsigned int val) MKSH_A_PURE; /* - * Generated from the UCD 13.0.0 by - * MirOS: contrib/code/Snippets/eawparse,v 1.14 2020/03/27 01:33:21 tg Exp $ + * Generated from the UCD 13.0.0 - see /usr/share/doc/legal/LICENCE-BSD - by + * MirOS: contrib/code/Snippets/eawparse,v 1.15 2020/06/15 20:31:13 tg Exp $ */ /*- @@ -1136,6 +1136,7 @@ static const struct mb_ucsrange mb_ucs_combining[] = { { 0xABE5, 0xABE5 }, { 0xABE8, 0xABE8 }, { 0xABED, 0xABED }, + { 0xD7B0, 0xD7FF }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE2F }, diff --git a/src/funcs.c b/src/funcs.c index d3427d0..ff6506d 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -1,7 +1,6 @@ /* $OpenBSD: c_ksh.c,v 1.37 2015/09/10 22:48:58 nicm Exp $ */ /* $OpenBSD: c_sh.c,v 1.46 2015/07/20 20:46:24 guenther Exp $ */ /* $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $ */ -/* $OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $ */ /*- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, @@ -39,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.373 2020/05/16 22:38:21 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.379 2020/08/27 19:52:44 tg Exp $"); #if HAVE_KILLPG /* @@ -52,12 +51,7 @@ __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.373 2020/05/16 22:38:21 tg Exp $"); #define mksh_kill kill #endif -/* XXX conditions correct? */ -#if !defined(RLIM_INFINITY) && !defined(MKSH_NO_LIMITS) -#define MKSH_NO_LIMITS 1 -#endif - -#ifdef MKSH_NO_LIMITS +#ifdef MKSH_UNLIMITED #define c_ulimit c_true #endif @@ -713,7 +707,23 @@ do_whence(const char **wp, int fcflags, bool vflag, bool iscommand) "exported " : "", Talias); } - shf_puts(tp->val.s, shl_stdout); + if (!mksh_abspath(tp->val.s)) { + const char *xcwd = current_wd[0] ? + current_wd : "."; + size_t xlen = strlen(xcwd); + size_t clen = strlen(tp->val.s) + 1; + char *xp = alloc(xlen + 1 + clen, ATEMP); + + memcpy(xp, xcwd, xlen); + if (mksh_cdirsep(xp[xlen - 1])) + --xlen; + xp[xlen++] = '/'; + memcpy(xp + xlen, tp->val.s, clen); + simplify_path(xp); + shf_puts(xp, shl_stdout); + afree(xp, ATEMP); + } else + shf_puts(tp->val.s, shl_stdout); } else { if (vflag) shprintf(Tnot_found_s, id); @@ -3219,214 +3229,6 @@ ptest_error(Test_env *te, int ofs, const char *msg) bi_errorf(Tf_s, msg); } -#ifndef MKSH_NO_LIMITS -#define SOFT 0x1 -#define HARD 0x2 - -/* Magic to divine the 'm' and 'v' limits */ - -#ifdef RLIMIT_AS -#if !defined(RLIMIT_VMEM) || (RLIMIT_VMEM == RLIMIT_AS) || \ - !defined(RLIMIT_RSS) || (RLIMIT_VMEM == RLIMIT_RSS) -#define ULIMIT_V_IS_AS -#elif defined(RLIMIT_VMEM) -#if !defined(RLIMIT_RSS) || (RLIMIT_RSS == RLIMIT_AS) -#define ULIMIT_V_IS_AS -#else -#define ULIMIT_V_IS_VMEM -#endif -#endif -#endif - -#ifdef RLIMIT_RSS -#ifdef ULIMIT_V_IS_VMEM -#define ULIMIT_M_IS_RSS -#elif defined(RLIMIT_VMEM) && (RLIMIT_VMEM == RLIMIT_RSS) -#define ULIMIT_M_IS_VMEM -#else -#define ULIMIT_M_IS_RSS -#endif -#if defined(ULIMIT_M_IS_RSS) && defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS) -#undef ULIMIT_M_IS_RSS -#endif -#endif - -#if !defined(RLIMIT_AS) && !defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_VMEM) -#define ULIMIT_V_IS_VMEM -#endif - -#if !defined(ULIMIT_V_IS_VMEM) && defined(RLIMIT_VMEM) && \ - (!defined(RLIMIT_RSS) || (defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS))) -#define ULIMIT_M_IS_VMEM -#endif - -#if defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_AS) && \ - (RLIMIT_VMEM == RLIMIT_AS) -#undef ULIMIT_M_IS_VMEM -#endif - -#if defined(ULIMIT_M_IS_RSS) && defined(ULIMIT_M_IS_VMEM) -# error nonsensical m ulimit -#endif - -#if defined(ULIMIT_V_IS_VMEM) && defined(ULIMIT_V_IS_AS) -# error nonsensical v ulimit -#endif - -struct limits { - /* limit resource */ - int resource; - /* multiply by to get rlim_{cur,max} values */ - unsigned int factor; - /* getopts char */ - char optchar; - /* limit name */ - char name[1]; -}; - -#define RLIMITS_DEFNS -#define FN(lname,lid,lfac,lopt) \ - static const struct { \ - int resource; \ - unsigned int factor; \ - char optchar; \ - char name[sizeof(lname)]; \ - } rlimits_ ## lid = { \ - lid, lfac, lopt, lname \ - }; -#include "rlimits.gen" - -static void print_ulimit(const struct limits *, int); -static int set_ulimit(const struct limits *, const char *, int); - -static const struct limits * const rlimits[] = { -#define RLIMITS_ITEMS -#include "rlimits.gen" -}; - -static const char rlimits_opts[] = -#define RLIMITS_OPTCS -#include "rlimits.gen" - ; - -int -c_ulimit(const char **wp) -{ - size_t i = 0; - int how = SOFT | HARD, optc, what = 'f'; - bool all = false; - - while ((optc = ksh_getopt(wp, &builtin_opt, rlimits_opts)) != -1) - switch (optc) { - case 'H': - how = HARD; - break; - case 'S': - how = SOFT; - break; - case 'a': - all = true; - break; - case '?': - bi_errorf("usage: ulimit [-%s] [value]", rlimits_opts); - return (1); - default: - what = optc; - } - - while (i < NELEM(rlimits)) { - if (rlimits[i]->optchar == what) - goto found; - ++i; - } - internal_warningf("ulimit: %c", what); - return (1); - found: - if (wp[builtin_opt.optind]) { - if (all || wp[builtin_opt.optind + 1]) { - bi_errorf(Ttoo_many_args); - return (1); - } - return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how)); - } - if (!all) - print_ulimit(rlimits[i], how); - else for (i = 0; i < NELEM(rlimits); ++i) { - shprintf("-%c: %-20s ", rlimits[i]->optchar, rlimits[i]->name); - print_ulimit(rlimits[i], how); - } - return (0); -} - -static int -set_ulimit(const struct limits *l, const char *v, int how) -{ - rlim_t val = (rlim_t)0; - struct rlimit limit; - - if (strcmp(v, "unlimited") == 0) - val = (rlim_t)RLIM_INFINITY; - else { - mksh_uari_t rval; - - if (!evaluate(v, (mksh_ari_t *)&rval, KSH_RETURN_ERROR, false)) - return (1); - /* - * Avoid problems caused by typos that evaluate misses due - * to evaluating unset parameters to 0... - * If this causes problems, will have to add parameter to - * evaluate() to control if unset params are 0 or an error. - */ - if (!rval && !ctype(v[0], C_DIGIT)) { - bi_errorf("invalid %s limit: %s", l->name, v); - return (1); - } - val = (rlim_t)((rlim_t)rval * l->factor); - } - - if (getrlimit(l->resource, &limit) < 0) { -#ifndef MKSH_SMALL - bi_errorf("limit %s could not be read, contact the mksh developers: %s", - l->name, cstrerror(errno)); -#endif - /* some can't be read */ - limit.rlim_cur = RLIM_INFINITY; - limit.rlim_max = RLIM_INFINITY; - } - if (how & SOFT) - limit.rlim_cur = val; - if (how & HARD) - limit.rlim_max = val; - if (!setrlimit(l->resource, &limit)) - return (0); - if (errno == EPERM) - bi_errorf("%s exceeds allowable %s limit", v, l->name); - else - bi_errorf("bad %s limit: %s", l->name, cstrerror(errno)); - return (1); -} - -static void -print_ulimit(const struct limits *l, int how) -{ - rlim_t val = (rlim_t)0; - struct rlimit limit; - - if (getrlimit(l->resource, &limit)) { - shf_puts("unknown\n", shl_stdout); - return; - } - if (how & SOFT) - val = limit.rlim_cur; - else if (how & HARD) - val = limit.rlim_max; - if (val == (rlim_t)RLIM_INFINITY) - shf_puts("unlimited\n", shl_stdout); - else - shprintf("%lu\n", (unsigned long)(val / l->factor)); -} -#endif - int c_rename(const char **wp) { @@ -3483,7 +3285,7 @@ c_realpath(const char **wp) int c_cat(const char **wp) { - int fd = STDIN_FILENO, rv; + int fd = 0, rv; ssize_t n, w; const char *fn = ""; char *buf, *cp; @@ -3516,7 +3318,7 @@ c_cat(const char **wp) if (*wp) { fn = *wp++; if (ksh_isdash(fn)) - fd = STDIN_FILENO; + fd = 0; else if ((fd = binopen2(fn, O_RDONLY)) < 0) { bi_errorf(Tf_sD_s, fn, cstrerror(errno)); rv = 1; @@ -3535,7 +3337,7 @@ c_cat(const char **wp) opipe = block_pipe(); continue; } - /* an error occured during reading */ + /* an error occurred during reading */ bi_errorf(Tf_sD_s, fn, cstrerror(errno)); rv = 1; break; @@ -3545,7 +3347,7 @@ c_cat(const char **wp) while (n) { if (intrsig) goto has_intrsig; - if ((w = write(STDOUT_FILENO, cp, n)) != -1) { + if ((w = write(1, cp, n)) != -1) { n -= w; cp += w; continue; @@ -3564,17 +3366,17 @@ c_cat(const char **wp) /* fake receiving signal */ rv = ksh_sigmask(SIGPIPE); } else { - /* an error occured during writing */ + /* an error occurred during writing */ bi_errorf(Tf_sD_s, "", cstrerror(errno)); rv = 1; } - if (fd != STDIN_FILENO) + if (fd != 0) close(fd); goto out; } } - if (fd != STDIN_FILENO) + if (fd != 0) close(fd); } while (*wp); diff --git a/src/histrap.c b/src/histrap.c index 84211c6..7f46201 100644 --- a/src/histrap.c +++ b/src/histrap.c @@ -27,7 +27,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.169 2019/09/16 21:10:33 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.170 2020/10/01 22:53:20 tg Exp $"); Trap sigtraps[ksh_NSIG + 1]; static struct sigaction Sigact_ign; @@ -415,7 +415,8 @@ hist_get(const char *str, bool approx, bool allow_cur) bool anchored = *str == '?' ? (++str, false) : true; /* the -1 is to avoid the current fc command */ - if ((n = findhist(histptr - history - 1, 0, str, anchored)) < 0) + if ((n = findhist(histptr - history - 1, str, false, + anchored)) < 0) bi_errorf(Tf_sD_s, str, Tnot_in_history); else hp = &history[n]; @@ -479,7 +480,7 @@ histnum(int n) * direction. */ int -findhist(int start, int fwd, const char *str, bool anchored) +findhist(int start, const char *str, bool fwd, bool anchored) { char **hp; int maxhist = histptr - history; diff --git a/src/lksh.1 b/src/lksh.1 index 0d6b226..7965156 100644 --- a/src/lksh.1 +++ b/src/lksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/lksh.1,v 1.25 2018/12/25 19:38:08 tg Exp $ +.\" $MirOS: src/bin/mksh/lksh.1,v 1.26 2020/09/04 22:37:01 tg Exp $ .\"- .\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2016, 2017, 2018 .\" mirabilos @@ -25,7 +25,8 @@ .\" thus use - for hyphens and \- for minus signs and option dashes .\" * ~ is size-reduced and placed atop in groff, so use \*(TI .\" * ^ is size-reduced and placed atop in groff, so use \*(ha -.\" * \(en does not work in nroff, so use \*(en +.\" * \(en does not work in nroff, so use \*(en for a solo en dash +.\" * and \*(EM for a correctly spaced em dash .\" * <>| are problematic, so redefine and use \*(Lt\*(Gt\*(Ba .\" Also make sure to use \& *before* a punctuation char that is to not .\" be interpreted as punctuation, and especially with two-letter words @@ -59,6 +60,12 @@ . ds ha ^ . ds en \(em .\} +.ie n \{\ +. ds EM \ \*(en\ \& +.\} +.el \{\ +. ds EM \f(TR\^\(em\^\fP +.\} .\" .\" Implement .Dd with the Mdocdate RCS keyword .\" @@ -74,7 +81,7 @@ .\" with -mandoc, it might implement .Mx itself, but we want to .\" use our own definition. And .Dd must come *first*, always. .\" -.Dd $Mdocdate: December 25 2018 $ +.Dd $Mdocdate: September 4 2020 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" diff --git a/src/main.c b/src/main.c index 1328045..e17ac75 100644 --- a/src/main.c +++ b/src/main.c @@ -35,7 +35,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/main.c,v 1.372 2020/05/16 22:51:24 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/main.c,v 1.374 2020/10/01 20:28:54 tg Exp $"); #ifndef MKSHRC_PATH #define MKSHRC_PATH "~/.mkshrc" @@ -1203,7 +1203,7 @@ remove_temps(struct temp *tp) /* * Initialise tty_fd. Used for tracking the size of the terminal, - * saving/resetting tty modes upon forground job completion, and + * saving/resetting tty modes upon foreground job completion, and * for setting up the tty process group. Return values: * 0 = got controlling tty * 1 = got terminal but no controlling tty @@ -1435,7 +1435,8 @@ error_prefix(bool fileline) /* Avoid foo: foo[2]: ... */ if (!fileline || !source || !source->file || strcmp(source->file, kshname) != 0) - shf_fprintf(shl_out, Tf_sD_, kshname + (*kshname == '-')); + shf_fprintf(shl_out, Tf_sD_, kshname + + (*kshname == '-' ? 1 : 0)); if (fileline && source && source->file != NULL) { shf_fprintf(shl_out, "%s[%lu]: ", source->file, (unsigned long)(source->errline ? diff --git a/src/misc.c b/src/misc.c index b19a253..f9f0201 100644 --- a/src/misc.c +++ b/src/misc.c @@ -33,7 +33,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.299 2020/05/16 22:19:58 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.302 2020/08/27 19:52:45 tg Exp $"); #define KSH_CHVT_FLAG #ifdef MKSH_SMALL @@ -1328,7 +1328,7 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp) if (go->flags & GF_ERROR) bi_errorfz(); } - return ('?'); + return (ORD('?')); } /** * : means argument must be present, may be part of option argument @@ -1347,7 +1347,7 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp) if (optionsp[0] == ':') { go->buf[0] = c; go->optarg = go->buf; - return (':'); + return (ORD(':')); } warningf(true, Tf_optfoo, (go->flags & GF_NONAME) ? "" : argv[0], @@ -1355,7 +1355,7 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp) c, Treq_arg); if (go->flags & GF_ERROR) bi_errorfz(); - return ('?'); + return (ORD('?')); } go->p = 0; } else if (*o == ',') { @@ -1383,7 +1383,7 @@ ksh_getopt(const char **argv, Getopt *go, const char *optionsp) go->optarg = NULL; } } - return (c); + return (ord(c)); } /* @@ -1927,7 +1927,7 @@ do_realpath(const char *upath) * - if file starts with '/', append file to result & set cdpathp to NULL * - if file starts with ./ or ../ append cwd and file to result * and set cdpathp to NULL - * - if the first element of cdpathp doesnt start with a '/' xx or '.' xx + * - if the first element of cdpathp doesn't start with a '/' xx or '.' xx * then cwd is appended to result. * - the first element of cdpathp is appended to result * - file is appended to result @@ -1983,16 +1983,18 @@ make_path(const char *cwd, const char *file, XcheckN(*xsp, xp, len); memcpy(xp, cwd, len); xp += len; - if (!mksh_cdirsep(cwd[len - 1])) - Xput(*xsp, xp, '/'); + if (mksh_cdirsep(xp[-1])) + xp--; + *xp++ = '/'; } *phys_pathp = Xlength(*xsp, xp); if (use_cdpath && plen) { XcheckN(*xsp, xp, plen); memcpy(xp, plist, plen); xp += plen; - if (!mksh_cdirsep(plist[plen - 1])) - Xput(*xsp, xp, '/'); + if (mksh_cdirsep(xp[-1])) + xp--; + *xp++ = '/'; rval = 1; } } @@ -2056,9 +2058,14 @@ simplify_path(char *p) case '\\': #endif /* exactly two leading slashes? (SUSv4 3.266) */ - if (p[1] == p[0] && !mksh_cdirsep(p[2])) + if (p[1] == p[0] && !mksh_cdirsep(p[2])) { /* keep them, e.g. for UNC pathnames */ +#ifdef MKSH_DOSPATH + *p++ = '/'; +#else ++p; +#endif + } needslash = true; break; default: @@ -2189,26 +2196,26 @@ c_cd(const char **wp) oldpwd_s = global(TOLDPWD); if (!wp[0]) { - /* No arguments - go home */ + /* no arguments; go home */ if ((dir = str_val(global("HOME"))) == null) { bi_errorf("no home directory (HOME not set)"); return (2); } } else if (!wp[1]) { - /* One argument: - or dir */ - strdupx(allocd, wp[0], ATEMP); - if (ksh_isdash((dir = allocd))) { - afree(allocd, ATEMP); - allocd = NULL; + /* one argument: - or dir */ + if (ksh_isdash(wp[0])) { dir = str_val(oldpwd_s); if (dir == null) { bi_errorf(Tno_OLDPWD); return (2); } printpath = true; + } else { + strdupx(allocd, wp[0], ATEMP); + dir = allocd; } } else if (!wp[2]) { - /* Two arguments - substitute arg1 in PWD for arg2 */ + /* two arguments; substitute arg1 in PWD for arg2 */ size_t ilen, olen, nlen, elen; char *cp; @@ -2217,10 +2224,9 @@ c_cd(const char **wp) return (2); } /* - * substitute arg1 for arg2 in current path. - * if the first substitution fails because the cd fails - * we could try to find another substitution. For now - * we don't + * Substitute arg1 for arg2 in current path. If the first + * substitution fails because the cd fails we could try to + * find another substitution. For now, we don't. */ if ((cp = strstr(current_wd, wp[0])) == NULL) { bi_errorf(Tbadsubst); diff --git a/src/mksh.1 b/src/mksh.1 index 1f1a121..6cfb70c 100644 --- a/src/mksh.1 +++ b/src/mksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.491 2020/05/16 22:12:36 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.494 2020/10/01 22:39:57 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: May 16 2020 $ +.Dd $Mdocdate: October 1 2020 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" @@ -1414,7 +1414,7 @@ or where .Ar name is a parameter name. -Substitutions of an an array in scalar context, i.e. without an +Substitutions of an array in scalar context, i.e. without an .Ar expr in the latter form mentioned above, expand the element with the key .Dq 0 . @@ -5333,10 +5333,16 @@ Set the number of cached threads to Impose a size limit of .Ar n blocks on the size of core dumps. +Silently ignored if the system does not support this limit. .It Fl d Ar n Limit the size of the data area to .Ar n kibibytes. +.br +On some systems, read-only maximum +.Xr brk 2 +size minus +.Li etext . .It Fl e Ar n Set the maximum niceness to .Ar n . @@ -5369,6 +5375,7 @@ kibibytes on the amount of physical memory used. Impose a limit of .Ar n file descriptors that can be open at once. +On some systems attempts to set are silently ignored. .It Fl O Ar n Set the number of AIO operations to .Ar n . @@ -6064,11 +6071,18 @@ words. .Op Ar n .No \*(haXe .Xc -Edit line +Internally run the command +.Ic fc \-e \&"${VISUAL:\-${EDITOR:\-vi}}" Fl \- Ar n +.br +on a temporary script file to interactively edit line .Ar n -or the current line, if not specified, interactively. -The actual command executed is -.Ic fc \-e ${VISUAL:\-${EDITOR:\-vi}} Ar n . +(if +.Ar n +is not specified, the current line); then, unless the editor invoked +exits nonzero but even if the script was not changed, execute the +resulting script as if typed on the command line; both the edited +.Pq resulting +and original lines are added onto history. .It end\-of\-history: \*(ha[\*(Gt Moves to the end of the history. .It end\-of\-line: \*(haE, ANSI-End, PC-End @@ -6426,15 +6440,18 @@ is not specified, it goes to the most recent remembered line. .It Xo .Oo Ar n Oc Ns v .Xc -Edit line +Internally run the command +.Ic fc \-e \&"${VISUAL:\-${EDITOR:\-vi}}" Fl \- Ar n +.br +on a temporary script file to interactively edit line .Ar n -using the -.Xr vi 1 -editor; if +(if .Ar n -is not specified, the current line is edited. -The actual command executed is -.Ic fc \-e ${VISUAL:\-${EDITOR:\-vi}} Ar n . +is not specified, the current line); then, unless the editor invoked +exits nonzero but even if the script was not changed, execute the +resulting script as if typed on the command line; both the edited +.Pq resulting +and original lines are added onto history. .It * and \*(haX Command or file name expansion is applied to the current big-word (with an appended @@ -7072,7 +7089,7 @@ for the in-memory portion of the history is slow, should use .Xr memmove 3 . .Pp This document attempts to describe -.Nm mksh\ R59b +.Nm mksh\ R59c 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 83e0191..6634d60 100644 --- a/src/mksh.faq +++ b/src/mksh.faq @@ -1,4 +1,4 @@ -RCSID: $MirOS: src/bin/mksh/mksh.faq,v 1.7 2020/04/25 12:09:55 tg Exp $ +RCSID: $MirOS: src/bin/mksh/mksh.faq,v 1.10 2020/10/01 22:59:12 tg Exp $ ToC: spelling Title: How do you spell mksh? How do you pronounce it? @@ -207,7 +207,7 @@ Title: Why doesn’t this use a Makefile to build? ToC: oldbsd Title: Why do other BSDs and QNX still use pdksh instead of mksh? -

Some systems are resistent to change, mostly due to bikeshedding +

Some systems are resistant to change, mostly due to bikeshedding (some people would, for example, rather see all shells banned to ports/pkgsrc®) and hysterial raisins (historical reasons ☻). Most BSDs have mksh packages available, and it works on all of them and @@ -297,6 +297,29 @@ pdksh derivative); $SH_VERSION (“PD KSH” as sh), $YASH_VERSION< (yash), $ZSH_VERSION (or if $VERSION begins with “zsh”); a list of more approaches exists. ---- +ToC: ctrl-x-e +Title: Multiline command editing + +

mksh is very independent of the terminal and external libraries and + databases, such as termcap, and therefore is conservative in which ANSI + control codes are sent to the terminal.

+

For this reason, mksh’s input line editing uses a “windowed one-line” + concept: the line the cursor is on is a “window” into the whole input, + horizontally scrolled. Some other shells (that are much larger and have + more dependencies on external tooling) use a “multi-line” editing mode, + and users occasionally wish for this. It is on the long-term TODO, but + (due to the aforementioned implications) this is not trivial.

+

One way to achieve multi-line editing is to disable input + line editing: set +o emacs +o vi
This will, however, lose + you all editing features: tab completion, cursor keys, history, etc.

+

Another way, if you don’t need it all the time, is to use a function + that spawns your editor on the input line: press ^Xe in the + default emacs mode or Esc + v in vi mode. Once you exit the + editor, whatever was written there is run; this includes the original + command line if you quit without saving, so request the editor to exit + nōn-zero (e.g. using jupp’s “abendjoe” command) to prevent execution. + This is really useful to write ad-hōc scripts as well.

+---- ToC: ctrl-l-cls Title: ^L (Ctrl-L) does not clear the screen @@ -439,6 +462,15 @@ Title: I get an error in this regex comparison … becomes…
[[ foo = *@(foo|bar)*baz* ]]

---- +ToC: trim-vector +Title: ${@?}: bad substitution + +

In mksh, you cannot assign to or trim a vector (yet). For most + cases it is possible to write the affected code in a way avoiding + this extension; for example, trimming ${@#foo} could be + applied to $1 only and ${@?} can be replaced + with a test whether $# -eq 0.

+---- ToC: extensions-to-avoid Title: Are there any extensions to avoid? diff --git a/src/os2.c b/src/os2.c index 8a80782..ed31eff 100644 --- a/src/os2.c +++ b/src/os2.c @@ -1,7 +1,7 @@ /*- * Copyright (c) 2015, 2017, 2020 * KO Myung-Hun - * Copyright (c) 2017 + * Copyright (c) 2017, 2020 * mirabilos * * Provided that these terms and disclaimer and all copyright notices @@ -32,11 +32,23 @@ #include #include -__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.10 2020/04/07 11:13:45 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.11 2020/10/01 21:13:45 tg Exp $"); -static char *remove_trailing_dots(char *); -static int access_stat_ex(int (*)(), const char *, void *); -static int test_exec_exist(const char *, char *); +struct a_s_arg { + union { + int (*i)(const char *, int); + int (*p)(const char *, void *); + } fn; + union { + int i; + void *p; + } arg; + bool isint; +}; + +static void remove_trailing_dots(char *, size_t); +static int access_stat_ex(const char *, struct a_s_arg *); +static int test_exec_exist(const char *, void *); static void response(int *, const char ***); static char *make_response_file(char * const *); static void add_temp(const char *); @@ -223,23 +235,18 @@ setextlibpath(const char *name, const char *val) } /* remove trailing dots */ -static char * -remove_trailing_dots(char *name) +static void +remove_trailing_dots(char *name, size_t namelen) { - char *p = strnul(name); + char *p = name + namelen; while (--p > name && *p == '.') /* nothing */; if (*p != '.' && *p != '/' && *p != '\\' && *p != ':') p[1] = '\0'; - - return (name); } -#define REMOVE_TRAILING_DOTS(name) \ - remove_trailing_dots(memcpy(alloca(strlen(name) + 1), name, strlen(name) + 1)) - /* alias of stat() */ extern int _std_stat(const char *, struct stat *); @@ -247,7 +254,12 @@ extern int _std_stat(const char *, struct stat *); int stat(const char *name, struct stat *buffer) { - return (_std_stat(REMOVE_TRAILING_DOTS(name), buffer)); + size_t namelen = strlen(name) + 1; + char nodots[namelen]; + + memcpy(nodots, name, namelen); + remove_trailing_dots(nodots, namelen); + return (_std_stat(nodots, buffer)); } /* alias of access() */ @@ -257,6 +269,9 @@ extern int _std_access(const char *, int); int access(const char *name, int mode) { + size_t namelen = strlen(name) + 1; + char nodots[namelen]; + /* * On OS/2 kLIBC, X_OK is set only for executable files. * This prevents scripts from being executed. @@ -264,7 +279,9 @@ access(const char *name, int mode) if (mode & X_OK) mode = (mode & ~X_OK) | R_OK; - return (_std_access(REMOVE_TRAILING_DOTS(name), mode)); + memcpy(nodots, name, namelen); + remove_trailing_dots(nodots, namelen); + return (_std_access(nodots, mode)); } #define MAX_X_SUFFIX_LEN 4 @@ -274,7 +291,7 @@ static const char *x_suffix_list[] = /* call fn() by appending executable extensions */ static int -access_stat_ex(int (*fn)(), const char *name, void *arg) +access_stat_ex(const char *name, struct a_s_arg *action) { char *x_name; const char **x_suffix; @@ -288,7 +305,8 @@ access_stat_ex(int (*fn)(), const char *name, void *arg) strlcpy(x_name, name, x_namelen); strlcat(x_name, *x_suffix, x_namelen); - rc = fn(x_name, arg); + rc = action->isint ? action->fn.i(x_name, action->arg.i) : + action->fn.p(x_name, action->arg.p); } afree(x_name, ATEMP); @@ -300,8 +318,12 @@ access_stat_ex(int (*fn)(), const char *name, void *arg) int access_ex(int (*fn)(const char *, int), const char *name, int mode) { - /*XXX this smells fishy --mirabilos */ - return (access_stat_ex(fn, name, (void *)mode)); + struct a_s_arg arg; + + arg.fn.i = fn; + arg.arg.i = mode; + arg.isint = true; + return (access_stat_ex(name, &arg)); } /* stat()/lstat() version */ @@ -309,34 +331,39 @@ int stat_ex(int (*fn)(const char *, struct stat *), const char *name, struct stat *buffer) { - return (access_stat_ex(fn, name, buffer)); + struct a_s_arg arg; + + arg.fn.p = fn; + arg.arg.p = buffer; + arg.isint = false; + return (access_stat_ex(name, &arg)); } static int -test_exec_exist(const char *name, char *real_name) +test_exec_exist(const char *name, void *arg) { struct stat sb; + char *real_name; if (stat(name, &sb) < 0 || !S_ISREG(sb.st_mode)) return (-1); - /* safe due to calculations in real_exec_name() */ - memcpy(real_name, name, strlen(name) + 1); - + /*XXX memory leak */ + strdupx(real_name, name, ATEMP); + *((char **)arg) = real_name; return (0); } const char * real_exec_name(const char *name) { - char x_name[strlen(name) + MAX_X_SUFFIX_LEN + 1]; - const char *real_name = name; + struct a_s_arg arg; + char *real_name; - if (access_stat_ex(test_exec_exist, real_name, x_name) != -1) - /*XXX memory leak */ - strdupx(real_name, x_name, ATEMP); - - return (real_name); + arg.fn.p = &test_exec_exist; + arg.arg.p = (void *)(&real_name); + arg.isint = false; + return (access_stat_ex(name, &arg) ? name : real_name); } /* make a response file to pass a very long command line */ diff --git a/src/rlimits.gen b/src/rlimits.gen index 5ccd007..cf684b4 100644 --- a/src/rlimits.gen +++ b/src/rlimits.gen @@ -1,6 +1,6 @@ /* +++ GENERATED FILE +++ DO NOT EDIT +++ */ /*- - * Copyright (c) 2013, 2015 + * Copyright (c) 2013, 2015, 2019 * mirabilos * * Provided that these terms and disclaimer and all copyright notices @@ -17,11 +17,13 @@ * of dealing in the work, even if advised of the possibility of such * damage or existence of a defect, except proven that it results out * of said person's immediate fault when using the work as intended. + *- + * Keep {r,u}limits.opt in sync with each other! */ #ifndef RLIMITS_OPTCS #if defined(RLIMITS_DEFNS) -__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.4 2019/04/24 20:56:31 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.5 2020/07/24 20:11:18 tg Exp $"); #elif defined(RLIMITS_ITEMS) #define FN(lname,lid,lfac,lopt) (const struct limits *)(&rlimits_ ## lid), #endif diff --git a/src/rlimits.opt b/src/rlimits.opt index db2a531..b806b40 100644 --- a/src/rlimits.opt +++ b/src/rlimits.opt @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2013, 2015 + * Copyright (c) 2013, 2015, 2019 * mirabilos * * Provided that these terms and disclaimer and all copyright notices @@ -16,10 +16,12 @@ * of dealing in the work, even if advised of the possibility of such * damage or existence of a defect, except proven that it results out * of said person's immediate fault when using the work as intended. + *- + * Keep {r,u}limits.opt in sync with each other! */ @RLIMITS_DEFNS -__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.4 2019/04/24 20:56:31 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.5 2020/07/24 20:11:18 tg Exp $"); @RLIMITS_ITEMS #define FN(lname,lid,lfac,lopt) (const struct limits *)(&rlimits_ ## lid), @@ diff --git a/src/sh.h b/src/sh.h index 8394c89..575f9bf 100644 --- a/src/sh.h +++ b/src/sh.h @@ -78,7 +78,9 @@ #if HAVE_PATHS_H #include #endif +#ifndef MKSH_NOPWNAM #include +#endif #include #include #include @@ -191,9 +193,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.898 2020/05/16 22:38:23 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.904 2020/10/31 03:53:06 tg Exp $"); #endif -#define MKSH_VERSION "R59 2020/05/16" +#define MKSH_VERSION "R59 2020/10/31" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES @@ -247,10 +249,6 @@ typedef u_int8_t uint8_t; /* other standard types */ -#if !HAVE_RLIM_T -typedef unsigned long rlim_t; -#endif - #if !HAVE_SIG_T #undef sig_t typedef void (*sig_t)(int); @@ -668,7 +666,7 @@ char *ucstrstr(char *, const char *); #endif #endif -#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 592) +#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 593) #error Must run Build.sh to compile this. extern void thiswillneverbedefinedIhope(void); int @@ -2522,7 +2520,7 @@ void sethistfile(const char *); char **histpos(void) MKSH_A_PURE; int histnum(int); #endif -int findhist(int, int, const char *, bool) MKSH_A_PURE; +int findhist(int, const char *, bool, bool) MKSH_A_PURE; char **hist_get_newest(bool); void inittraps(void); void alarm_init(void); diff --git a/src/shf.c b/src/shf.c index 8e95fc6..ec7fc1f 100644 --- a/src/shf.c +++ b/src/shf.c @@ -27,7 +27,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.101 2019/12/11 17:56:58 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.102 2020/06/22 17:11:03 tg Exp $"); /* flags to shf_emptybuf() */ #define EB_READSW 0x01 /* about to switch to reading */ @@ -666,7 +666,7 @@ shf_write(const char *buf, ssize_t nbytes, struct shf *shf) if (nbytes < 0) internal_errorf(Tf_szs, Tshf_write, nbytes, Tbytes); - /* Don't buffer if buffer is empty and we're writting a large amount. */ + /* don't buffer if buffer is empty and we're writing a large amount */ if ((ncopy = shf->wnleft) && (shf->wp != shf->buf || nbytes < shf->wnleft)) { if (ncopy > nbytes) @@ -782,7 +782,7 @@ shf_smprintf(const char *fmt, ...) #define FL_ZERO 0x040 /* '0' seen */ #define FL_DOT 0x080 /* '.' seen */ #define FL_UPPER 0x100 /* format character was uppercase */ -#define FL_NUMBER 0x200 /* a number was formated %[douxefg] */ +#define FL_NUMBER 0x200 /* a number was formatted %[douxefg] */ #define FL_SIZET 0x400 /* 'z' seen */ #define FM_SIZES 0x430 /* h/l/z mask */ diff --git a/src/syn.c b/src/syn.c index 3387cf5..bcb5a5a 100644 --- a/src/syn.c +++ b/src/syn.c @@ -24,7 +24,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.128 2020/03/31 00:30:05 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.129 2020/10/31 01:21:58 tg Exp $"); struct nesting_state { int start_token; /* token than began nesting (eg, FOR) */ @@ -268,13 +268,12 @@ get_command(int cf, int sALIAS) { struct op *t; int c, iopn = 0, syniocf, lno; - struct ioword *iop, **iops; + struct ioword *iop; XPtrV args, vars; struct nesting_state old_nesting; bool check_decl_utility; + static struct ioword *iops[NUFILE + 1]; - /* NUFILE is small enough to leave this addition unchecked */ - iops = alloc2((NUFILE + 1), sizeof(struct ioword *), ATEMP); XPinit(args, 16); XPinit(vars, 16); @@ -282,7 +281,6 @@ get_command(int cf, int sALIAS) switch (c = token(cf|KEYWORD|sALIAS|CMDASN)) { default: REJECT; - afree(iops, ATEMP); XPfree(args); XPfree(vars); /* empty line */ @@ -510,12 +508,11 @@ get_command(int cf, int sALIAS) } if (iopn == 0) { - afree(iops, ATEMP); t->ioact = NULL; } else { iops[iopn++] = NULL; - iops = aresize2(iops, iopn, sizeof(struct ioword *), ATEMP); - t->ioact = iops; + t->ioact = alloc2(iopn, sizeof(struct ioword *), ATEMP); + memcpy(t->ioact, iops, iopn * sizeof(struct ioword *)); } if (t->type == TCOM || t->type == TDBRACKET) { diff --git a/src/tree.c b/src/tree.c index 335e3fb..85fa0d6 100644 --- a/src/tree.c +++ b/src/tree.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.97 2018/10/20 18:46:00 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.100 2020/10/31 04:28:54 tg Exp $"); #define INDENT 8 @@ -37,6 +37,19 @@ static void iofree(struct ioword **, Area *); /* "foo& ; bar" and "foo |& ; bar" are invalid */ static bool prevent_semicolon; +/* here document diversion */ +static unsigned short ptree_nest; +static bool ptree_hashere; +static struct shf ptree_heredoc; +#define ptree_outhere(shf) do { \ + if (ptree_hashere) { \ + shf_puts(shf_sclose(&ptree_heredoc), (shf)); \ + shf_putc('\n', (shf)); \ + ptree_hashere = false; \ + /*prevent_semicolon = true;*/ \ + } \ +} while (/* CONSTCOND */ 0) + static const char Telif_pT[] = "elif %T"; /* @@ -82,8 +95,11 @@ ptree(struct op *t, int indent, struct shf *shf) w = (const char **)t->vars; while (*w) fptreef(shf, indent, Tf_S_, *w++); - } else + } +#ifndef MKSH_SMALL + else shf_puts("#no-vars# ", shf); +#endif if (t->args) { w = t->args; if (*w && **w == CHAR) { @@ -97,8 +113,11 @@ ptree(struct op *t, int indent, struct shf *shf) } while (*w) fptreef(shf, indent, Tf_S_, *w++); - } else + } +#ifndef MKSH_SMALL + else shf_puts("#no-args# ", shf); +#endif break; case TEXEC: t = t->left; @@ -221,36 +240,9 @@ ptree(struct op *t, int indent, struct shf *shf) prevent_semicolon = false; break; } - if ((ioact = t->ioact) != NULL) { - bool need_nl = false; - + if ((ioact = t->ioact) != NULL) while (*ioact != NULL) pioact(shf, *ioact++); - /* Print here documents after everything else... */ - ioact = t->ioact; - while (*ioact != NULL) { - struct ioword *iop = *ioact++; - - /* heredoc is NULL when tracing (set -x) */ - if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE && - iop->heredoc) { - shf_putc('\n', shf); - shf_puts(iop->heredoc, shf); - fptreef(shf, indent, Tf_s, - evalstr(iop->delim, 0)); - need_nl = true; - } - } - /* - * Last delimiter must be followed by a newline (this - * often leads to an extra blank line, but it's not - * worth worrying about) - */ - if (need_nl) { - shf_putc('\n', shf); - prevent_semicolon = true; - } - } } static void @@ -272,11 +264,29 @@ pioact(struct shf *shf, struct ioword *iop) shf_putc('<', shf); break; case IOHERE: + if (flag & IOHERESTR) { + shf_puts("<<<", shf); + goto ioheredelim; + } shf_puts("<<", shf); if (flag & IOSKIP) shf_putc('-', shf); - else if (flag & IOHERESTR) - shf_putc('<', shf); + if (iop->heredoc /* nil when tracing */) { + /* here document diversion */ + if (!ptree_hashere) { + shf_sopen(NULL, 0, SHF_WR | SHF_DYNAMIC, + &ptree_heredoc); + ptree_hashere = true; + } + shf_putc('\n', &ptree_heredoc); + shf_puts(iop->heredoc, &ptree_heredoc); + /* iop->delim is set before iop->heredoc */ + shf_puts(evalstr(iop->delim, 0), &ptree_heredoc); + } + ioheredelim: + /* delim is NULL during syntax error printing */ + if (iop->delim && !(iop->ioflag & IONDELIM)) + wdvarput(shf, iop->delim, 0, WDS_TPUTS); break; case IOCAT: shf_puts(">>", shf); @@ -293,11 +303,8 @@ pioact(struct shf *shf, struct ioword *iop) shf_puts(flag & IORDUP ? "<&" : ">&", shf); break; } - /* name/delim are NULL when printing syntax errors */ - if (type == IOHERE) { - if (iop->delim && !(iop->ioflag & IONDELIM)) - wdvarput(shf, iop->delim, 0, WDS_TPUTS); - } else if (iop->ioname) { + /* name is NULL for IOHERE or when printing syntax errors */ + if (iop->ioname) { if (flag & IONAMEXP) print_value_quoted(shf, iop->ioname); else @@ -342,13 +349,6 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode) c = ord(*wp++); if (opmode & WDS_TPUTS) switch (c) { - case ORD('\n'): - if (quotelevel == 0) { - c = ORD('\''); - shf_putc(c, shf); - shf_putc(ORD('\n'), shf); - } - break; default: if (quotelevel == 0) /* FALLTHROUGH */ @@ -467,6 +467,9 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va) { int c; + if (!ptree_nest++) + ptree_hashere = false; + while ((c = ord(*fmt++))) { if (c == '%') { switch ((c = ord(*fmt++))) { @@ -504,10 +507,10 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va) shf_putc(';', shf); shf_putc(' ', shf); } else { - int i; + int i = indent; + ptree_outhere(shf); shf_putc('\n', shf); - i = indent; while (i >= 8) { shf_putc('\t', shf); i -= 8; @@ -530,6 +533,9 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va) dont_trash_prevent_semicolon: ; } + + if (!--ptree_nest) + ptree_outhere(shf); } /* diff --git a/src/ulimit.c b/src/ulimit.c new file mode 100644 index 0000000..5bdfdd1 --- /dev/null +++ b/src/ulimit.c @@ -0,0 +1,360 @@ +/* $OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $ */ + +/*- + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2019, 2020 + * mirabilos + * + * Provided that these terms and disclaimer and all copyright notices + * are retained or reproduced in an accompanying document, permission + * is granted to deal in this work without restriction, including un- + * limited rights to use, publicly perform, distribute, sell, modify, + * merge, give away, or sublicence. + * + * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to + * the utmost extent permitted by applicable law, neither express nor + * implied; without malicious intent or gross negligence. In no event + * may a licensor, author or contributor be held liable for indirect, + * direct, other damage, loss, or other issues arising in any way out + * of dealing in the work, even if advised of the possibility of such + * damage or existence of a defect, except proven that it results out + * of said person's immediate fault when using the work as intended. + */ + +#include "sh.h" + +__RCSID("$MirOS: src/bin/mksh/ulimit.c,v 1.3 2020/07/24 21:08:26 tg Exp $"); + +#define SOFT 0x1 +#define HARD 0x2 + +#if HAVE_RLIMIT + +#if !HAVE_RLIM_T +typedef unsigned long rlim_t; +#endif + +/* Magic to divine the 'm' and 'v' limits */ + +#ifdef RLIMIT_AS +#if !defined(RLIMIT_VMEM) || (RLIMIT_VMEM == RLIMIT_AS) || \ + !defined(RLIMIT_RSS) || (RLIMIT_VMEM == RLIMIT_RSS) +#define ULIMIT_V_IS_AS +#elif defined(RLIMIT_VMEM) +#if !defined(RLIMIT_RSS) || (RLIMIT_RSS == RLIMIT_AS) +#define ULIMIT_V_IS_AS +#else +#define ULIMIT_V_IS_VMEM +#endif +#endif +#endif + +#ifdef RLIMIT_RSS +#ifdef ULIMIT_V_IS_VMEM +#define ULIMIT_M_IS_RSS +#elif defined(RLIMIT_VMEM) && (RLIMIT_VMEM == RLIMIT_RSS) +#define ULIMIT_M_IS_VMEM +#else +#define ULIMIT_M_IS_RSS +#endif +#if defined(ULIMIT_M_IS_RSS) && defined(RLIMIT_AS) && \ + !defined(__APPLE__) && (RLIMIT_RSS == RLIMIT_AS) +/* On Mac OSX keep -m as -v alias for pkgsrc and other software expecting it */ +#undef ULIMIT_M_IS_RSS +#endif +#endif + +#if !defined(RLIMIT_AS) && !defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_VMEM) +#define ULIMIT_V_IS_VMEM +#endif + +#if !defined(ULIMIT_V_IS_VMEM) && defined(RLIMIT_VMEM) && \ + (!defined(RLIMIT_RSS) || (defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS))) +#define ULIMIT_M_IS_VMEM +#endif + +#if defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_AS) && \ + (RLIMIT_VMEM == RLIMIT_AS) +#undef ULIMIT_M_IS_VMEM +#endif + +#if defined(ULIMIT_M_IS_RSS) && defined(ULIMIT_M_IS_VMEM) +# error nonsensical m ulimit +#endif + +#if defined(ULIMIT_V_IS_VMEM) && defined(ULIMIT_V_IS_AS) +# error nonsensical v ulimit +#endif + +#define LIMITS_GEN "rlimits.gen" + +#else /* !HAVE_RLIMIT */ + +#undef RLIMIT_CORE /* just in case */ + +#if defined(UL_GETFSIZE) +#define KSH_UL_GFIL UL_GETFSIZE +#elif defined(UL_GFILLIM) +#define KSH_UL_GFIL UL_GFILLIM +#elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST) +#define KSH_UL_GFIL 1 +#endif + +#if defined(UL_SETFSIZE) +#define KSH_UL_SFIL UL_SETFSIZE +#elif defined(UL_SFILLIM) +#define KSH_UL_SFIL UL_SFILLIM +#elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST) +#define KSH_UL_SFIL 2 +#endif + +#if defined(KSH_UL_SFIL) +#define KSH_UL_WFIL true +#else +#define KSH_UL_WFIL false +#define KSH_UL_SFIL 0 +#endif + +#if defined(UL_GETMAXBRK) +#define KSH_UL_GBRK UL_GETMAXBRK +#elif defined(UL_GMEMLIM) +#define KSH_UL_GBRK UL_GMEMLIM +#elif defined(__A_UX__) || defined(KSH_ULIMIT2_TEST) +#define KSH_UL_GBRK 3 +#endif + +#if defined(UL_GDESLIM) +#define KSH_UL_GDES UL_GDESLIM +#elif defined(__GLIBC__) || defined(KSH_ULIMIT2_TEST) +#define KSH_UL_GDES 4 +#endif + +extern char etext; +extern long ulimit(int, long); + +#define LIMITS_GEN "ulimits.gen" + +#endif /* !HAVE_RLIMIT */ + +struct limits { + /* limit resource / read command */ + int resource; +#if HAVE_RLIMIT + /* multiply by to get rlim_{cur,max} values */ + unsigned int factor; +#else + /* write command */ + int wesource; + /* writable? */ + bool writable; +#endif + /* getopts char */ + char optchar; + /* limit name */ + char name[1]; +}; + +#define RLIMITS_DEFNS +#if HAVE_RLIMIT +#define FN(lname,lid,lfac,lopt) \ + static const struct { \ + int resource; \ + unsigned int factor; \ + char optchar; \ + char name[sizeof(lname)]; \ + } rlimits_ ## lid = { \ + lid, lfac, lopt, lname \ + }; +#else +#define FN(lname,lg,ls,lw,lopt) \ + static const struct { \ + int rcmd; \ + int wcmd; \ + bool writable; \ + char optchar; \ + char name[sizeof(lname)]; \ + } rlimits_ ## lg = { \ + lg, ls, lw, lopt, lname \ + }; +#endif +#include LIMITS_GEN + +static void print_ulimit(const struct limits *, int); +static int set_ulimit(const struct limits *, const char *, int); + +static const struct limits * const rlimits[] = { +#define RLIMITS_ITEMS +#include LIMITS_GEN +}; + +static const char rlimits_opts[] = +#define RLIMITS_OPTCS +#include LIMITS_GEN +#ifndef RLIMIT_CORE + "c" +#endif + ; + +int +c_ulimit(const char **wp) +{ + size_t i = 0; + int how = SOFT | HARD, optc; + char what = 'f'; + bool all = false; + + while ((optc = ksh_getopt(wp, &builtin_opt, rlimits_opts)) != -1) + switch (optc) { + case ORD('H'): + how = HARD; + break; + case ORD('S'): + how = SOFT; + break; + case ORD('a'): + all = true; + break; + case ORD('?'): + bi_errorf("usage: ulimit [-%s] [value]", rlimits_opts); + return (1); + default: + what = optc; + } + + while (i < NELEM(rlimits)) { + if (rlimits[i]->optchar == what) + goto found; + ++i; + } +#ifndef RLIMIT_CORE + if (what == ORD('c')) + /* silently accept */ + return 0; +#endif + internal_warningf("ulimit: %c", what); + return (1); + found: + if (wp[builtin_opt.optind]) { + if (all || wp[builtin_opt.optind + 1]) { + bi_errorf(Ttoo_many_args); + return (1); + } + return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how)); + } + if (!all) + print_ulimit(rlimits[i], how); + else for (i = 0; i < NELEM(rlimits); ++i) { + shprintf("-%c: %-20s ", rlimits[i]->optchar, rlimits[i]->name); + print_ulimit(rlimits[i], how); + } + return (0); +} + +#if HAVE_RLIMIT +#define RL_T rlim_t +#define RL_U (rlim_t)RLIM_INFINITY +#else +#define RL_T long +#define RL_U LONG_MAX +#endif + +static int +set_ulimit(const struct limits *l, const char *v, int how MKSH_A_UNUSED) +{ + RL_T val = (RL_T)0; +#if HAVE_RLIMIT + struct rlimit limit; +#endif + + if (strcmp(v, "unlimited") == 0) + val = RL_U; + else { + mksh_uari_t rval; + + if (!evaluate(v, (mksh_ari_t *)&rval, KSH_RETURN_ERROR, false)) + return (1); + /* + * Avoid problems caused by typos that evaluate misses due + * to evaluating unset parameters to 0... + * If this causes problems, will have to add parameter to + * evaluate() to control if unset params are 0 or an error. + */ + if (!rval && !ctype(v[0], C_DIGIT)) { + bi_errorf("invalid %s limit: %s", l->name, v); + return (1); + } +#if HAVE_RLIMIT + val = (rlim_t)((rlim_t)rval * l->factor); +#else + val = (RL_T)rval; +#endif + } + +#if HAVE_RLIMIT + if (getrlimit(l->resource, &limit) < 0) { +#ifndef MKSH_SMALL + bi_errorf("limit %s could not be read, contact the mksh developers: %s", + l->name, cstrerror(errno)); +#endif + /* some can't be read */ + limit.rlim_cur = RLIM_INFINITY; + limit.rlim_max = RLIM_INFINITY; + } + if (how & SOFT) + limit.rlim_cur = val; + if (how & HARD) + limit.rlim_max = val; + if (!setrlimit(l->resource, &limit)) + return (0); +#else + if (l->writable == false) { + /* check.t:ulimit-2 fails if we return 1 and/or do: + bi_errorf(Tf_ro, l->name); + */ + return (0); + } + if (ulimit(l->wesource, val) != -1L) + return (0); +#endif + if (errno == EPERM) + bi_errorf("%s exceeds allowable %s limit", v, l->name); + else + bi_errorf("bad %s limit: %s", l->name, cstrerror(errno)); + return (1); +} + +static void +print_ulimit(const struct limits *l, int how MKSH_A_UNUSED) +{ + RL_T val = (RL_T)0; +#if HAVE_RLIMIT + struct rlimit limit; + + if (getrlimit(l->resource, &limit)) +#else + if ((val = ulimit(l->resource, 0)) < 0) +#endif + { + shf_puts("unknown\n", shl_stdout); + return; + } +#if HAVE_RLIMIT + if (how & SOFT) + val = limit.rlim_cur; + else if (how & HARD) + val = limit.rlim_max; +#endif + if (val == RL_U) + shf_puts("unlimited\n", shl_stdout); + else { +#if HAVE_RLIMIT + val /= l->factor; +#elif defined(KSH_UL_GBRK) + if (l->resource == KSH_UL_GBRK) + val = (RL_T)(((size_t)val - (size_t)&etext) / + (size_t)1024); +#endif + shprintf("%lu\n", (unsigned long)val); + } +} diff --git a/src/ulimits.gen b/src/ulimits.gen new file mode 100644 index 0000000..374df60 --- /dev/null +++ b/src/ulimits.gen @@ -0,0 +1,60 @@ +/* +++ GENERATED FILE +++ DO NOT EDIT +++ */ +/*- + * Copyright (c) 2013, 2015, 2020 + * mirabilos + * + * Provided that these terms and disclaimer and all copyright notices + * are retained or reproduced in an accompanying document, permission + * is granted to deal in this work without restriction, including un- + * limited rights to use, publicly perform, distribute, sell, modify, + * merge, give away, or sublicence. + * + * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to + * the utmost extent permitted by applicable law, neither express nor + * implied; without malicious intent or gross negligence. In no event + * may a licensor, author or contributor be held liable for indirect, + * direct, other damage, loss, or other issues arising in any way out + * of dealing in the work, even if advised of the possibility of such + * damage or existence of a defect, except proven that it results out + * of said person's immediate fault when using the work as intended. + *- + * Keep {r,u}limits.opt in sync with each other! + */ + +#ifndef RLIMITS_OPTCS +#if defined(RLIMITS_DEFNS) +__RCSID("$MirOS: src/bin/mksh/ulimits.opt,v 1.2 2020/07/24 20:50:11 tg Exp $"); +#elif defined(RLIMITS_ITEMS) +#define FN(lname,lg,ls,lw,lopt) (const struct limits *)(&rlimits_ ## lg), +#endif +#ifndef F0 +#define F0 FN +#endif +#ifdef KSH_UL_GFIL +FN("file(blocks)", KSH_UL_GFIL, KSH_UL_SFIL, KSH_UL_WFIL, 'f') +#endif +#ifdef KSH_UL_GBRK +FN("data(KiB)", KSH_UL_GBRK, 0, false, 'd') +#endif +#ifdef KSH_UL_GDES +FN("nofiles(descriptors)", KSH_UL_GDES, 0, false, 'n') +#endif +#undef F0 +#undef FN +#undef RLIMITS_DEFNS +#undef RLIMITS_ITEMS +#else +"a" +#ifdef KSH_UL_GBRK +"d" +#endif +#ifdef KSH_UL_GFIL +"f" +#endif +"H" +#ifdef KSH_UL_GDES +"n" +#endif +"S" +#undef RLIMITS_OPTCS +#endif diff --git a/src/ulimits.opt b/src/ulimits.opt new file mode 100644 index 0000000..aad64be --- /dev/null +++ b/src/ulimits.opt @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2013, 2015, 2020 + * mirabilos + * + * Provided that these terms and disclaimer and all copyright notices + * are retained or reproduced in an accompanying document, permission + * is granted to deal in this work without restriction, including un- + * limited rights to use, publicly perform, distribute, sell, modify, + * merge, give away, or sublicence. + * + * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to + * the utmost extent permitted by applicable law, neither express nor + * implied; without malicious intent or gross negligence. In no event + * may a licensor, author or contributor be held liable for indirect, + * direct, other damage, loss, or other issues arising in any way out + * of dealing in the work, even if advised of the possibility of such + * damage or existence of a defect, except proven that it results out + * of said person's immediate fault when using the work as intended. + *- + * Keep {r,u}limits.opt in sync with each other! + */ + +@RLIMITS_DEFNS +__RCSID("$MirOS: src/bin/mksh/ulimits.opt,v 1.2 2020/07/24 20:50:11 tg Exp $"); +@RLIMITS_ITEMS +#define FN(lname,lg,ls,lw,lopt) (const struct limits *)(&rlimits_ ## lg), +@@ + +/* generic options for the ulimit builtin */ + +f|KSH_UL_GFIL +FN("file(blocks)", KSH_UL_GFIL, KSH_UL_SFIL, KSH_UL_WFIL + +>d|KSH_UL_GBRK +FN("data(KiB)", KSH_UL_GBRK, 0, false + +>n|KSH_UL_GDES +FN("nofiles(descriptors)", KSH_UL_GDES, 0, false + +|RLIMITS_OPTCS diff --git a/src/var.c b/src/var.c index ade60c5..e3c92eb 100644 --- a/src/var.c +++ b/src/var.c @@ -29,7 +29,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/var.c,v 1.236 2020/04/13 16:29:34 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/var.c,v 1.237 2020/06/22 17:11:03 tg Exp $"); /*- * Variables @@ -1900,7 +1900,7 @@ c_typeset(const char **wp) break; } - /* see comment below regarding possible opions */ + /* see comment below regarding possible options */ opts = istset ? "L#R#UZ#afgi#lnprtux" : "p"; builtin_opt.flags |= GF_PLUSOPT;