From: Elliott Hughes Date: Thu, 7 Aug 2014 19:59:26 +0000 (-0700) Subject: Upgrade to mksh 50. X-Git-Tag: android-x86-7.1-r1~19^2~2 X-Git-Url: http://git.osdn.net/view?p=android-x86%2Fexternal-mksh.git;a=commitdiff_plain;h=427d76ccc44aea287b51b233f0254a6107b2b3d1 Upgrade to mksh 50. Bug: 16569301 Bug: 17814343 (cherry picked from commit 737fdce098f804459a925438e48dd711c31bbc9e) Change-Id: I7e8a142bec5f553f9e1a2568245582fe8fa14314 --- diff --git a/Android.mk b/Android.mk index 9989f67..8f910a1 100644 --- a/Android.mk +++ b/Android.mk @@ -20,7 +20,8 @@ include $(BUILD_PREBUILT) include $(CLEAR_VARS) -LOCAL_MODULE:= sh +LOCAL_MODULE := sh +LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk # mksh source files LOCAL_SRC_FILES:= src/lalloc.c src/edit.c src/eval.c src/exec.c \ @@ -41,7 +42,9 @@ LOCAL_CFLAGS:= -DMKSHRC_PATH=\"/system/etc/mkshrc\" \ -DMKSH_DONT_EMIT_IDSTRING -DMKSH_NOPWNAM -DMKSH_BUILDSH \ -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN \ -DHAVE_ATTRIBUTE_BOUNDED=0 -DHAVE_ATTRIBUTE_FORMAT=1 \ - -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_UNUSED=1 \ + -DHAVE_ATTRIBUTE_NORETURN=1 \ + -DHAVE_ATTRIBUTE_PURE=1 \ + -DHAVE_ATTRIBUTE_UNUSED=1 \ -DHAVE_ATTRIBUTE_USED=1 -DHAVE_SYS_TIME_H=1 -DHAVE_TIME_H=1 \ -DHAVE_BOTH_TIME_H=1 -DHAVE_SYS_BSDTYPES_H=0 \ -DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 \ @@ -54,14 +57,16 @@ LOCAL_CFLAGS:= -DMKSHRC_PATH=\"/system/etc/mkshrc\" \ -DHAVE_CAN_INT8TYPE=1 -DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=1 \ -DHAVE_SIG_T=1 -DHAVE_SYS_ERRLIST=0 -DHAVE_SYS_SIGNAME=1 \ -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1 -DHAVE_LOCK_FCNTL=1 \ - -DHAVE_GETRUSAGE=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_KILLPG=1 \ + -DHAVE_GETRUSAGE=1 \ + -DHAVE_GETSID=1 \ + -DHAVE_GETTIMEOFDAY=1 -DHAVE_KILLPG=1 \ -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1 -DHAVE_NICE=1 \ -DHAVE_REVOKE=0 -DHAVE_SETLOCALE_CTYPE=0 \ -DHAVE_LANGINFO_CODESET=0 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=1 \ -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 \ -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \ -DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 \ - -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=481 + -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=501 # check_categories= shell:legacy-no int:32 android convfds no-histfile diff --git a/Makefrag.inc b/Makefrag.inc new file mode 100644 index 0000000..403281f --- /dev/null +++ b/Makefrag.inc @@ -0,0 +1,40 @@ +# Makefile fragment for building mksh R50 2014/06/29 + +PROG= mksh +MAN= mksh.1 +SRCS= lalloc.c eval.c exec.c expr.c funcs.c histrap.c jobs.c lex.c main.c misc.c shf.c syn.c tree.c var.c edit.c +SRCS_FP= ../src/lalloc.c ../src/eval.c ../src/exec.c ../src/expr.c ../src/funcs.c ../src/histrap.c ../src/jobs.c ../src/lex.c ../src/main.c ../src/misc.c ../src/shf.c ../src/syn.c ../src/tree.c ../src/var.c ../src/edit.c +OBJS_BP= lalloc.o eval.o exec.o expr.o funcs.o histrap.o jobs.o lex.o main.o misc.o shf.o syn.o tree.o var.o edit.o +INDSRCS= emacsfn.h rlimits.opt sh.h sh_flags.opt var_spec.h +NONSRCS_INST= dot.mkshrc $(MAN) +NONSRCS_NOINST= Build.sh Makefile Rebuild.sh check.pl check.t test.sh +CC= /huge-ssd/lmp-dev/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/arm-linux-androideabi-gcc +CFLAGS= -fno-exceptions -Wno-multichar -msoft-float -fpic -fPIE -ffunction-sections -fdata-sections -funwind-tables -fstack-protector -Wa,--noexecstack -Werror=format-security -fno-short-enums -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -Wno-unused-but-set-variable -fno-builtin-sin -fno-strict-volatile-bitfields -Wno-psabi -mthumb-interwork -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -g -Wstrict-aliasing=2 -fgcse-after-reload -frerun-cse-after-loop -frename-registers -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -Wno-deprecated-declarations -fno-asynchronous-unwind-tables -fwrapv +CPPFLAGS= -I. -I'../src' -I/huge-ssd/lmp-dev/libnativehelper/include/nativehelper -isystem /huge-ssd/lmp-dev/system/core/include -isystem /huge-ssd/lmp-dev/hardware/libhardware/include -isystem /huge-ssd/lmp-dev/hardware/libhardware_legacy/include -isystem /huge-ssd/lmp-dev/hardware/ril/include -isystem /huge-ssd/lmp-dev/libnativehelper/include -isystem /huge-ssd/lmp-dev/frameworks/native/include -isystem /huge-ssd/lmp-dev/frameworks/native/opengl/include -isystem /huge-ssd/lmp-dev/frameworks/av/include -isystem /huge-ssd/lmp-dev/frameworks/base/include -isystem /huge-ssd/lmp-dev/external/skia/include -isystem /huge-ssd/lmp-dev/out/target/product/hammerhead/obj/include -isystem /huge-ssd/lmp-dev/bionic/libc/arch-arm/include -isystem /huge-ssd/lmp-dev/bionic/libc/include -isystem /huge-ssd/lmp-dev/bionic/libstdc++/include -isystem /huge-ssd/lmp-dev/bionic/libc/kernel/uapi -isystem /huge-ssd/lmp-dev/bionic/libc/kernel/uapi/asm-arm -isystem /huge-ssd/lmp-dev/bionic/libm/include -isystem /huge-ssd/lmp-dev/bionic/libm/include/arm -isystem /huge-ssd/lmp-dev/bionic/libthread_db/include -D_FORTIFY_SOURCE=2 -include /huge-ssd/lmp-dev/build/core/combo/include/arch/linux-arm/AndroidConfig.h -I/huge-ssd/lmp-dev/build/core/combo/include/arch/linux-arm/ -DANDROID -DNDEBUG -UDEBUG -DDEBUG_LEAKS -DMKSH_ASSUME_UTF8 -DMKSH_CONSERVATIVE_FDS -DMKSH_DONT_EMIT_IDSTRING -DMKSH_NOPWNAM -DMKSH_BUILDSH -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN -DHAVE_ATTRIBUTE_BOUNDED=0 -DHAVE_ATTRIBUTE_FORMAT=1 -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_PURE=1 -DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 -DHAVE_SYS_TIME_H=1 -DHAVE_TIME_H=1 -DHAVE_BOTH_TIME_H=1 -DHAVE_SYS_BSDTYPES_H=0 -DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SYS_SELECT_H=1 -DHAVE_SYS_SYSMACROS_H=1 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 -DHAVE_LIBGEN_H=1 -DHAVE_LIBUTIL_H=0 -DHAVE_PATHS_H=1 -DHAVE_STDINT_H=1 -DHAVE_STRINGS_H=1 -DHAVE_TERMIOS_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 -DHAVE_CAN_INTTYPES=1 -DHAVE_CAN_UCBINTS=1 -DHAVE_CAN_INT8TYPE=1 -DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=1 -DHAVE_SIG_T=1 -DHAVE_SYS_ERRLIST=0 -DHAVE_SYS_SIGNAME=1 -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1 -DHAVE_LOCK_FCNTL=1 -DHAVE_GETRUSAGE=1 -DHAVE_GETSID=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_KILLPG=1 -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1 -DHAVE_NICE=1 -DHAVE_REVOKE=0 -DHAVE_SETLOCALE_CTYPE=0 -DHAVE_LANGINFO_CODESET=0 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=1 -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 -DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=501 +LDFLAGS= -nostdlib -Bdynamic -fPIE -pie -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--icf=safe -Wl,--fix-cortex-a8 -Wl,--no-undefined /huge-ssd/lmp-dev/out/target/product/hammerhead/obj/lib/crtbegin_dynamic.o +LIBS= -L/huge-ssd/lmp-dev/out/target/product/hammerhead/obj/lib -Wl,-rpath-link=/huge-ssd/lmp-dev/out/target/product/hammerhead/obj/lib -Wl,--no-whole-archive /huge-ssd/lmp-dev/out/target/product/hammerhead/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a -lc /huge-ssd/lmp-dev/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/../lib/gcc/arm-linux-androideabi/4.8/armv7-a/libgcc.a /huge-ssd/lmp-dev/out/target/product/hammerhead/obj/lib/crtend_android.o + +.depend $(OBJS_BP): rlimits.gen sh_flags.gen +rlimits.gen: ../src/Build.sh ../src/rlimits.opt + srcfile=../src/rlimits.opt; BUILDSH_RUN_GENOPT=1; . ../src/Build.sh +sh_flags.gen: ../src/Build.sh ../src/sh_flags.opt + srcfile=../src/sh_flags.opt; BUILDSH_RUN_GENOPT=1; . ../src/Build.sh + +# not BSD make only: +#VPATH= ../src +#all: $(PROG) +#$(PROG): $(OBJS_BP) +# $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS_BP) $(LIBS) +#$(OBJS_BP): $(SRCS_FP) $(NONSRCS) +#.c.o: +# $(CC) $(CFLAGS) $(CPPFLAGS) -c $< + +# for all make variants: +#REGRESS_FLAGS= -f +#regress: +# ./test.sh $(REGRESS_FLAGS) +check_categories= shell:legacy-no int:32 android convfds no-histfile + +# for BSD make only: +#.PATH: ../src +#.include diff --git a/mkmf.sh b/mkmf.sh index f819e0d..193dae2 100644 --- a/mkmf.sh +++ b/mkmf.sh @@ -49,10 +49,10 @@ LIBS= # possible to the values used later. (You also must example the # results gathered from Makefrag.inc to see they are the same # across all Android platforms, or add appropriate ifdefs.) -# Since we no longer use the NDK, the AOSP has to have been -# built before using this script (targetting generic/emulator). +# Since we no longer use the NDK, AOSP has to have been +# built before using this script. -CC=$aospdir/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin/arm-linux-androideabi-gcc +CC=$aospdir/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/arm-linux-androideabi-gcc addvar CPPFLAGS \ -I$aospdir/libnativehelper/include/nativehelper \ -isystem $aospdir/system/core/include \ @@ -65,7 +65,7 @@ addvar CPPFLAGS \ -isystem $aospdir/frameworks/av/include \ -isystem $aospdir/frameworks/base/include \ -isystem $aospdir/external/skia/include \ - -isystem $aospdir/out/target/product/generic/obj/include \ + -isystem $ANDROID_PRODUCT_OUT/obj/include \ -isystem $aospdir/bionic/libc/arch-arm/include \ -isystem $aospdir/bionic/libc/include \ -isystem $aospdir/bionic/libstdc++/include \ @@ -134,15 +134,15 @@ addvar LDFLAGS \ -Wl,--icf=safe \ -Wl,--fix-cortex-a8 \ -Wl,--no-undefined \ - $aospdir/out/target/product/generic/obj/lib/crtbegin_dynamic.o + $ANDROID_PRODUCT_OUT/obj/lib/crtbegin_dynamic.o addvar LIBS \ - -L$aospdir/out/target/product/generic/obj/lib \ - -Wl,-rpath-link=$aospdir/out/target/product/generic/obj/lib \ + -L$ANDROID_PRODUCT_OUT/obj/lib \ + -Wl,-rpath-link=$ANDROID_PRODUCT_OUT/obj/lib \ -Wl,--no-whole-archive \ - $aospdir/out/target/product/generic/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a \ + $ANDROID_PRODUCT_OUT/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a \ -lc \ - $aospdir/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin/../lib/gcc/arm-linux-androideabi/4.7/armv7-a/libgcc.a \ - $aospdir/out/target/product/generic/obj/lib/crtend_android.o + $aospdir/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/../lib/gcc/arm-linux-androideabi/4.8/armv7-a/libgcc.a \ + $ANDROID_PRODUCT_OUT/obj/lib/crtend_android.o ### Flags used by test builds diff --git a/src/Build.sh b/src/Build.sh index 45af9dd..8ef6cb6 100644 --- a/src/Build.sh +++ b/src/Build.sh @@ -1,8 +1,8 @@ #!/bin/sh -srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.645 2013/08/10 13:44:25 tg Exp $' +srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.662 2014/06/29 10:56:08 tg Exp $' #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011, 2012, 2013 +# 2011, 2012, 2013, 2014 # Thorsten Glaser # # Provided that these terms and disclaimer and all copyright notices @@ -28,9 +28,6 @@ srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.645 2013/08/10 13:44:25 tg Exp $' LC_ALL=C export LC_ALL -echo "For the build logs, demonstrate that /dev/null and /dev/tty exist:" -ls -l /dev/null /dev/tty - case $ZSH_VERSION:$VERSION in :zsh*) ZSH_VERSION=2 ;; esac @@ -46,6 +43,162 @@ if test -d /usr/xpg4/bin/. >/dev/null 2>&1; then export PATH fi +nl=' +' +safeIFS=' ' +safeIFS=" $safeIFS$nl" +IFS=$safeIFS +allu=QWERTYUIOPASDFGHJKLZXCVBNM +alll=qwertyuiopasdfghjklzxcvbnm +alln=0123456789 +alls=______________________________________________________________ + +genopt_die() { + if test -n "$1"; then + echo >&2 "E: $*" + echo >&2 "E: in '$srcfile': '$line'" + else + echo >&2 "E: invalid input in '$srcfile': '$line'" + fi + rm -f "$bn.gen" + exit 1 +} + +genopt_soptc() { + optc=`echo "$line" | sed 's/^[<>]\(.\).*$/\1/'` + test x"$optc" = x'|' && return + optclo=`echo "$optc" | tr $allu $alll` + if test x"$optc" = x"$optclo"; then + islo=1 + else + islo=0 + fi + sym=`echo "$line" | sed 's/^[<>]/|/'` + o_str=$o_str$nl"<$optclo$islo$sym" +} + +genopt_scond() { + case x$cond in + x) + cond= + ;; + x*' '*) + cond=`echo "$cond" | sed 's/^ //'` + cond="#if $cond" + ;; + x'!'*) + cond=`echo "$cond" | sed 's/^!//'` + cond="#ifndef $cond" + ;; + x*) + cond="#ifdef $cond" + ;; + esac +} + +do_genopt() { + srcfile=$1 + test -f "$srcfile" || genopt_die Source file \$srcfile not set. + bn=`basename "$srcfile" | sed 's/.opt$//'` + o_gen= + o_str= + o_sym= + ddefs= + state=0 + exec <"$srcfile" + IFS= + while IFS= read line; do + IFS=$safeIFS + case $state:$line in + 2:'|'*) + # end of input + o_sym=`echo "$line" | sed 's/^.//'` + o_gen=$o_gen$nl"#undef F0" + o_gen=$o_gen$nl"#undef FN" + o_gen=$o_gen$ddefs + state=3 + ;; + 1:@@) + # begin of data block + o_gen=$o_gen$nl"#endif" + o_gen=$o_gen$nl"#ifndef F0" + o_gen=$o_gen$nl"#define F0 FN" + o_gen=$o_gen$nl"#endif" + state=2 + ;; + *:@@*) + genopt_die ;; + 0:@*|1:@*) + # begin of a definition block + sym=`echo "$line" | sed 's/^@//'` + if test $state = 0; then + o_gen=$o_gen$nl"#if defined($sym)" + else + o_gen=$o_gen$nl"#elif defined($sym)" + fi + ddefs="$ddefs$nl#undef $sym" + state=1 + ;; + 0:*|3:*) + genopt_die ;; + 1:*) + # definition line + o_gen=$o_gen$nl$line + ;; + 2:'<'*'|'*) + genopt_soptc + ;; + 2:'>'*'|'*) + genopt_soptc + cond=`echo "$line" | sed 's/^[^|]*|//'` + genopt_scond + case $optc in + '|') optc=0 ;; + *) optc=\'$optc\' ;; + esac + IFS= read line || genopt_die Unexpected EOF + IFS=$safeIFS + test -n "$cond" && o_gen=$o_gen$nl"$cond" + o_gen=$o_gen$nl"$line, $optc)" + test -n "$cond" && o_gen=$o_gen$nl"#endif" + ;; + esac + done + case $state:$o_sym in + 3:) genopt_die Expected optc sym at EOF ;; + 3:*) ;; + *) genopt_die Missing EOF marker ;; + esac + echo "$o_str" | sort | while IFS='|' read x opts cond; do + IFS=$safeIFS + test -n "$x" || continue + genopt_scond + test -n "$cond" && echo "$cond" + echo "\"$opts\"" + test -n "$cond" && echo "#endif" + done | { + echo "#ifndef $o_sym$o_gen" + echo "#else" + cat + echo "#undef $o_sym" + echo "#endif" + } >"$bn.gen" + IFS=$safeIFS + return 0 +} + +if test x"$BUILDSH_RUN_GENOPT" = x"1"; then + set x -G "$srcfile" + shift +fi +if test x"$1" = x"-G"; then + do_genopt "$2" + exit $? +fi + +echo "For the build logs, demonstrate that /dev/null and /dev/tty exist:" +ls -l /dev/null /dev/tty + v() { $e "$*" eval "$@" @@ -66,18 +219,12 @@ vq() { rmf() { for _f in "$@"; do case $_f in - Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|*.ico|*.1) ;; + Build.sh|check.pl|check.t|dot.mkshrc|*.1|*.c|*.h|*.ico|*.opt) ;; *) rm -f "$_f" ;; esac done } -allu=QWERTYUIOPASDFGHJKLZXCVBNM -alll=qwertyuiopasdfghjklzxcvbnm -alln=0123456789 -alls=______________________________________________________________ -nl=' -' tcfn=no bi= ui= @@ -193,8 +340,9 @@ ac_testn() { ac_ifcpp() { expr=$1; shift ac_testn "$@" <<-EOF + #include extern int thiswillneverbedefinedIhope(void); - int main(void) { return ( + int main(void) { return (isatty(0) + #$expr 0 #else @@ -251,7 +399,8 @@ ac_flags() { else ac_testn can_$vn '' "$ft" <<-'EOF' /* evil apo'stroph in comment test */ - int main(void) { return (0); } + #include + int main(void) { return (isatty(0)); } EOF fi eval fv=\$HAVE_CAN_`upper $vn` @@ -291,19 +440,14 @@ ac_header() { esac done echo "#include <$hf>" >>x - echo 'int main(void) { return (0); }' >>x + echo '#include ' >>x + echo 'int main(void) { return (isatty(0)); }' >>x ac_testn "$hv" "" "<$hf>" /dev/null` check_categories= -test -n "$srcdir" || srcdir=. # in case dirname does not exist -dstversion=`sed -n '/define MKSH_VERSION/s/^.*"\([^"]*\)".*$/\1/p' $srcdir/sh.h` +curdir=`pwd` srcdir=`dirname "$0" 2>/dev/null` +case x$srcdir in +x) + srcdir=. + ;; +*\ *|*" "*|*"$nl"*) + echo >&2 Source directory should not contain space or tab or newline. + echo >&2 Errors may occur. + ;; +*"'"*) + echo Source directory must not contain single quotes. + exit 1 + ;; +esac +dstversion=`sed -n '/define MKSH_VERSION/s/^.*"\([^"]*\)".*$/\1/p' "$srcdir/sh.h"` add_cppflags -DMKSH_BUILDSH e=echo @@ -336,6 +485,7 @@ eq=0 pm=0 cm=normal optflags=-std-compile-opts +check_categories= last= tfn= legacy=0 @@ -362,6 +512,10 @@ do :-c) last=c ;; + :-G) + echo "$me: Do not call me with '-G'!" >&2 + exit 1 + ;; :-g) # checker, debug, valgrind build add_cppflags -DDEBUG @@ -423,7 +577,7 @@ if test -d $tfn || test -d $tfn.exe; then echo "$me: Error: ./$tfn is a directory!" >&2 exit 1 fi -rmf a.exe* a.out* conftest.c *core core.* lft ${tfn}* no *.bc *.ll *.o \ +rmf a.exe* a.out* conftest.c *core core.* lft ${tfn}* no *.bc *.ll *.o *.gen \ Rebuild.sh signames.inc test.sh x vv.out SRCS="lalloc.c eval.c exec.c expr.c funcs.c histrap.c jobs.c" @@ -462,7 +616,7 @@ oswarn= ccpc=-Wc, ccpl=-Wl, tsts= -ccpr='|| for _f in ${tcfn}*; do case $_f in Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|*.ico|*.1) ;; *) rm -f "$_f" ;; esac; done' +ccpr='|| for _f in ${tcfn}*; do case $_f in Build.sh|check.pl|check.t|dot.mkshrc|*.1|*.c|*.h|*.ico|*.opt) ;; *) rm -f "$_f" ;; esac; done' # Evil hack if test x"$TARGET_OS" = x"Android"; then @@ -786,7 +940,12 @@ AIX) ;; Darwin) vv '|' "hwprefs machine_type os_type os_class >&2" + vv '|' "sw_vers >&2" + vv '|' "system_profiler SPSoftwareDataType SPHardwareDataType >&2" + vv '|' "/bin/sh --version >&2" + vv '|' "xcodebuild -version >&2" vv '|' "uname -a >&2" + vv '|' "sysctl kern.version hw.machine hw.model hw.memsize hw.availcpu hw.cpufrequency hw.byteorder hw.cpu64bit_capable >&2" ;; IRIX*) vv '|' "uname -a >&2" @@ -905,7 +1064,10 @@ vv ']' "$CPP $CFLAGS $CPPFLAGS $NOWARN conftest.c | \ sed 's/^/[ /' x eval `cat x` rmf x vv.out -echo 'int main(void) { return (0); }' >conftest.c +cat >conftest.c <<'EOF' +#include +int main(void) { return (isatty(0)); } +EOF case $ct in ack) # work around "the famous ACK const bug" @@ -1091,13 +1253,15 @@ if ac_ifcpp 'if 0' compiler_fails '' \ dec) CFLAGS="$CFLAGS ${ccpl}-non_shared" ac_testn can_delexe compiler_fails 0 'for the -non_shared linker option' <<-EOF - int main(void) { return (0); } + #include + int main(void) { return (isatty(0)); } EOF ;; dmc) CFLAGS="$CFLAGS ${ccpl}/DELEXECUTABLE" ac_testn can_delexe compiler_fails 0 'for the /DELEXECUTABLE linker option' <<-EOF - int main(void) { return (0); } + #include + int main(void) { return (isatty(0)); } EOF ;; *) @@ -1193,7 +1357,8 @@ kencc|tcc|tendra) ;; sunpro) cat >x <<-'EOF' - int main(void) { return (0); } + #include + int main(void) { return (isatty(0)); } #define __IDSTRING_CONCAT(l,p) __LINTED__ ## l ## _ ## p #define __IDSTRING_EXPAND(l,p) __IDSTRING_CONCAT(l,p) #define pad void __IDSTRING_EXPAND(__LINE__,x)(void) { } @@ -1235,7 +1400,9 @@ gcc) # mksh is not written in CFrustFrust! ac_flags 1 no_eh_frame -fno-asynchronous-unwind-tables ac_flags 1 fnostrictaliasing -fno-strict-aliasing - ac_flags 1 fstackprotectorall -fstack-protector-all + ac_flags 1 fstackprotectorstrong -fstack-protector-strong + test 1 = $HAVE_CAN_FSTACKPROTECTORSTRONG || \ + ac_flags 1 fstackprotectorall -fstack-protector-all test $cm = dragonegg && case " $CC $CFLAGS $LDFLAGS " in *\ -fplugin=*dragonegg*) ;; *) ac_flags 1 fplugin_dragonegg -fplugin=dragonegg ;; @@ -1356,8 +1523,8 @@ ac_test attribute_bounded '' 'for __attribute__((__bounded__))' <<-'EOF' #include #undef __attribute__ int xcopy(const void *, void *, size_t) - __attribute__((__bounded__ (__buffer__, 1, 3))) - __attribute__((__bounded__ (__buffer__, 2, 3))); + __attribute__((__bounded__(__buffer__, 1, 3))) + __attribute__((__bounded__(__buffer__, 2, 3))); int main(int ac, char *av[]) { return (xcopy(av[0], av[--ac], 1)); } int xcopy(const void *s, void *d, size_t n) { /* @@ -1379,7 +1546,7 @@ ac_test attribute_format '' 'for __attribute__((__format__))' <<-'EOF' #undef __attribute__ #undef fprintf extern int fprintf(FILE *, const char *format, ...) - __attribute__((__format__ (__printf__, 2, 3))); + __attribute__((__format__(__printf__, 2, 3))); int main(int ac, char **av) { return (fprintf(stderr, "%s%d", *av, ac)); } #endif EOF @@ -1396,14 +1563,29 @@ ac_test attribute_noreturn '' 'for __attribute__((__noreturn__))' <<-'EOF' void fnord(void) { exit(0); } #endif EOF +ac_test attribute_pure '' 'for __attribute__((__pure__))' <<-'EOF' + #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2)) + extern int thiswillneverbedefinedIhope(void); + /* force a failure: TenDRA and gcc 1.42 have false positive here */ + int main(void) { return (thiswillneverbedefinedIhope()); } + #else + #include + #undef __attribute__ + int foo(const char *) __attribute__((__pure__)); + int main(int ac, char **av) { return (foo(av[ac - 1]) + isatty(0)); } + int foo(const char *s) { return ((int)s[0]); } + #endif +EOF ac_test attribute_unused '' 'for __attribute__((__unused__))' <<-'EOF' #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2)) extern int thiswillneverbedefinedIhope(void); /* force a failure: TenDRA and gcc 1.42 have false positive here */ int main(void) { return (thiswillneverbedefinedIhope()); } #else + #include + #undef __attribute__ int main(int ac __attribute__((__unused__)), char **av - __attribute__((__unused__))) { return (0); } + __attribute__((__unused__))) { return (isatty(0)); } #endif EOF ac_test attribute_used '' 'for __attribute__((__used__))' <<-'EOF' @@ -1412,8 +1594,10 @@ ac_test attribute_used '' 'for __attribute__((__used__))' <<-'EOF' /* force a failure: TenDRA and gcc 1.42 have false positive here */ int main(void) { return (thiswillneverbedefinedIhope()); } #else + #include + #undef __attribute__ static const char fnord[] __attribute__((__used__)) = "42"; - int main(void) { return (0); } + int main(void) { return (isatty(0)); } #endif EOF @@ -1465,7 +1649,8 @@ ac_test both_time_h '' 'whether and can both be included' #include #include #include - int main(void) { struct tm tm; return ((int)sizeof(tm)); } + #include + int main(void) { struct tm tm; return ((int)sizeof(tm) + isatty(0)); } EOF ac_header sys/bsdtypes.h ac_header sys/file.h sys/types.h @@ -1491,11 +1676,12 @@ ac_header values.h # Environment: definitions # echo '#include +#include /* check that off_t can represent 2^63-1 correctly, thx FSF */ -#define LARGE_OFF_T (((off_t)1 << 62) - 1 + ((off_t)1 << 62)) +#define LARGE_OFF_T ((((off_t)1 << 31) << 31) - 1 + (((off_t)1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; -int main(void) { return (0); }' >lft.c +int main(void) { return (isatty(0)); }' >lft.c ac_testn can_lfs '' "for large file support" #endif #include - int main(void) { return ((int)(rlim_t)0); } + int main(void) { return (((int)(rlim_t)0) + isatty(0)); } EOF # only testn: added later below @@ -1598,8 +1784,8 @@ else #define EXTERN #define MKSH_INCLUDES_ONLY #include "sh.h" - __RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.645 2013/08/10 13:44:25 tg Exp $"); - int main(void) { printf("Hello, World!\n"); return (0); } + __RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.662 2014/06/29 10:56:08 tg Exp $"); + int main(void) { printf("Hello, World!\n"); return (isatty(0)); } EOF case $cm in llvm) @@ -1638,12 +1824,14 @@ test x"NetBSD" = x"$TARGET_OS" && $e Ignore the compatibility warning. ac_testn sys_errlist '' "the sys_errlist[] array and sys_nerr" <<-'EOF' extern const int sys_nerr; extern const char * const sys_errlist[]; - int main(void) { return (*sys_errlist[sys_nerr - 1]); } + extern int isatty(int); + int main(void) { return (*sys_errlist[sys_nerr - 1] + isatty(0)); } EOF ac_testn _sys_errlist '!' sys_errlist 0 "the _sys_errlist[] array and _sys_nerr" <<-'EOF' extern const int _sys_nerr; extern const char * const _sys_errlist[]; - int main(void) { return (*_sys_errlist[_sys_nerr - 1]); } + extern int isatty(int); + int main(void) { return (*_sys_errlist[_sys_nerr - 1] + isatty(0)); } EOF if test 1 = "$HAVE__SYS_ERRLIST"; then add_cppflags -Dsys_nerr=_sys_nerr @@ -1656,11 +1844,13 @@ for what in name list; do uwhat=`upper $what` ac_testn sys_sig$what '' "the sys_sig${what}[] array" <<-EOF extern const char * const sys_sig${what}[]; - int main(void) { return (sys_sig${what}[0][0]); } + extern int isatty(int); + int main(void) { return (sys_sig${what}[0][0] + isatty(0)); } EOF ac_testn _sys_sig$what '!' sys_sig$what 0 "the _sys_sig${what}[] array" <<-EOF extern const char * const _sys_sig${what}[]; - int main(void) { return (_sys_sig${what}[0][0]); } + extern int isatty(int); + int main(void) { return (_sys_sig${what}[0][0] + isatty(0)); } EOF eval uwhat_v=\$HAVE__SYS_SIG$uwhat if test 1 = "$uwhat_v"; then @@ -1703,6 +1893,11 @@ ac_test getrusage <<-'EOF' } EOF +ac_test getsid <<-'EOF' + #include + int main(void) { return ((int)getsid(0)); } +EOF + ac_test gettimeofday <<-'EOF' #define MKSH_INCLUDES_ONLY #include "sh.h" @@ -1722,7 +1917,7 @@ ac_test memmove <<-'EOF' #include #endif int main(int ac, char *av[]) { - return (*(int *)(void *)memmove(av[0], av[1], ac)); + return (*(int *)(void *)memmove(av[0], av[1], (size_t)ac)); } EOF @@ -1894,12 +2089,12 @@ EOF ac_test sys_errlist_decl sys_errlist 0 "for declaration of sys_errlist[] and sys_nerr" <<-'EOF' #define MKSH_INCLUDES_ONLY #include "sh.h" - int main(void) { return (*sys_errlist[sys_nerr - 1]); } + int main(void) { return (*sys_errlist[sys_nerr - 1] + isatty(0)); } EOF ac_test sys_siglist_decl sys_siglist 0 'for declaration of sys_siglist[]' <<-'EOF' #define MKSH_INCLUDES_ONLY #include "sh.h" - int main(void) { return (sys_siglist[0][0]); } + int main(void) { return (sys_siglist[0][0] + isatty(0)); } EOF # @@ -1970,7 +2165,7 @@ cta(ptr_fits_in_long, sizeof(ptrdiff_t) <= sizeof(long)); char padding[64 - NUM]; }; char ctasserts_dblcheck[sizeof(struct ctasserts) == 64 ? 1 : -1]; - int main(void) { return (sizeof(ctasserts_dblcheck)); } + int main(void) { return (sizeof(ctasserts_dblcheck) + isatty(0)); } EOF CFLAGS=$save_CFLAGS eval test 1 = \$HAVE_COMPILE_TIME_ASSERTS_$$ || exit 1 @@ -2054,6 +2249,9 @@ if test 0 = $HAVE_SYS_SIGNAME; then #define NSIG (SIGMAX+1) #elif defined(_SIGMAX) #define NSIG (_SIGMAX+1) +#else +/* XXX better error out, see sh.h */ +#define NSIG 64 #endif #endif int @@ -2072,9 +2270,9 @@ mksh_cfg= NSIG test $printf = echo || test "`printf %d 42`" = 42 || printf=echo test $printf = echo || NSIG=`printf %d "$NSIG" 2>/dev/null` $printf "NSIG=$NSIG ... " - sigs="INT SEGV ABRT KILL ALRM BUS CHLD CLD CONT DIL EMT FPE HUP ILL" - sigs="$sigs INFO IO IOT LOST PIPE PROF PWR QUIT RESV SAK STOP SYS TERM" - sigs="$sigs TRAP TSTP TTIN TTOU URG USR1 USR2 VTALRM WINCH XCPU XFSZ" + sigs="ABRT FPE ILL INT SEGV TERM ALRM BUS CHLD CONT HUP KILL PIPE QUIT" + sigs="$sigs STOP TSTP TTIN TTOU USR1 USR2 POLL PROF SYS TRAP URG VTALRM" + sigs="$sigs XCPU XFSZ INFO WINCH EMT IO DIL LOST PWR SAK CLD IOT RESV" test 1 = $HAVE_CPP_DD && test $NSIG -gt 1 && sigs="$sigs "`vq \ "$CPP $CFLAGS $CPPFLAGS $NOWARN -dD conftest.c" | \ grep '[ ]SIG[A-Z0-9][A-Z0-9]*[ ]' | \ @@ -2108,12 +2306,11 @@ mksh_cfg= NSIG $e done. fi -addsrcs -s '!' HAVE_STRLCPY strlcpy.c +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" -test -n "$LDSTATIC" && add_cppflags -DMKSH_OPTSTATIC -add_cppflags -DMKSH_BUILD_R=481 +add_cppflags -DMKSH_BUILD_R=501 $e $bi$me: Finished configuration testing, now producing output.$ao @@ -2175,6 +2372,10 @@ cat >test.sh <<-EOF fi (( vflag )) && args[\${#args[*]}]=-v (( xflag )) && args[\${#args[*]}]=-x # force usage by synerr + if [[ -n \$TMPDIR && -d \$TMPDIR/. ]]; then + args[\${#args[*]}]=-T + args[\${#args[*]}]=\$TMPDIR + fi print Testing mksh for conformance: fgrep -e MirOS: -e MIRBSD "\$sflag" print "This shell is actually:\\n\\t\$KSH_VERSION" @@ -2224,6 +2425,10 @@ llvm) ;; esac echo ": # work around NeXTstep bug" >Rebuild.sh +for file in "$srcdir"/*.opt; do + echo "echo + Running genopt on '$file'..." + echo "(srcfile='$file'; BUILDSH_RUN_GENOPT=1; . '$srcdir/Build.sh')" +done >>Rebuild.sh echo set -x >>Rebuild.sh for file in $SRCS; do op=`echo x"$file" | sed 's/^x\(.*\)\.c$/\1./'` @@ -2253,8 +2458,15 @@ 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 sh.h sh_flags.h var_spec.h' + extras='emacsfn.h rlimits.opt sh.h sh_flags.opt var_spec.h' test 0 = $HAVE_SYS_SIGNAME && extras="$extras signames.inc" + gens= genq= + for file in "$srcdir"/*.opt; do + genf=`basename "$file" | sed 's/.opt$/.gen/'` + gens="$gens $genf" + genq="$genq$nl$genf: $srcdir/Build.sh $file + srcfile=$file; BUILDSH_RUN_GENOPT=1; . $srcdir/Build.sh" + done cat >Makefrag.inc < # # Provided that these terms and disclaimer and all copyright notices @@ -172,7 +172,6 @@ BEGIN { use Getopt::Std; use Config; -use File::Temp qw/ :mktemp /; $os = defined $^O ? $^O : 'unknown'; @@ -251,7 +250,7 @@ die "$prog: no test set specified (use -s)\n" if !defined $opt_s; $test_prog = $opt_p; $verbose = defined $opt_v && $opt_v; $test_set = $opt_s; -$temp_dir = $opt_T || "/tmp"; +$temp_base = $opt_T || "/tmp"; if (defined $opt_t) { die "$prog: bad -t argument (should be number > 0): $opt_t\n" if $opt_t !~ /^\d+$/ || $opt_t <= 0; @@ -300,6 +299,18 @@ chop($pwd = `pwd 2>/dev/null`); die "$prog: couldn't get current working directory\n" if $pwd eq ''; die "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd); +die "$prog: couldn't cd to $temp_base - $!\n" if !chdir($temp_base); +die "$prog: couldn't get temporary directory base\n" unless -d '.'; +$temps = sprintf("chk%d-%d.", $$, time()); +$tempi = 0; +until (mkdir(($tempdir = sprintf("%s%03d", $temps, $tempi)), 0700)) { + die "$prog: couldn't get temporary directory\n" if $tempi++ >= 999; +} +die "$prog: couldn't cd to $tempdir - $!\n" if !chdir($tempdir); +chop($temp_dir = `pwd 2>/dev/null`); +die "$prog: couldn't get temporary directory\n" if $temp_dir eq ''; +die "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd); + if (!$program_kludge) { $test_prog = "$pwd/$test_prog" if substr($test_prog, 0, 1) ne '/'; die "$prog: $test_prog is not executable - bye\n" @@ -314,15 +325,12 @@ $SIG{'ALRM'} = 'catch_sigalrm'; $| = 1; # Create temp files -($fh, $temps) = mkstemp("${temp_dir}/rts.XXXXXXXX"); -close($fh); -($fh, $tempi) = mkstemp("${temp_dir}/rti.XXXXXXXX"); -close($fh); -($fh, $tempo) = mkstemp("${temp_dir}/rto.XXXXXXXX"); -close($fh); -($fh, $tempe) = mkstemp("${temp_dir}/rte.XXXXXXXX"); -close($fh); -$tempdir = mkdtemp("${temp_dir}/rtd.XXXXXXXX"); +$temps = "${temp_dir}/rts"; +$tempi = "${temp_dir}/rti"; +$tempo = "${temp_dir}/rto"; +$tempe = "${temp_dir}/rte"; +$tempdir = "${temp_dir}/rtd"; +mkdir($tempdir, 0700) or die "$prog: couldn't mkdir $tempdir - $!\n"; if (-d $test_set) { $file_prefix_skip = length($test_set) + 1; @@ -365,6 +373,7 @@ cleanup_exit unlink($tempi, $tempo, $tempe, $temps); &scrub_dir($tempdir) if defined $tempdir; rmdir($tempdir) if defined $tempdir; + rmdir($temp_dir) if defined $temp_dir; if ($sig) { $SIG{$sig} = 'DEFAULT'; @@ -903,7 +912,7 @@ eval_exit } else { $expr = $expect; $expr =~ s/\b([wse])\b/\$$1/g; - $expr =~ s/\b(SIG[A-Z0-9]+)\b/&$1/g; + $expr =~ s/\b(SIG[A-Z][A-Z0-9]*)\b/&$1/g; } $w = eval $expr; if ($@ ne '') { @@ -923,12 +932,13 @@ read_test %test = (); %cnt = (); while (<$in>) { + chop; next if /^\s*$/; next if /^ *#/; last if /^\s*---\s*$/; $start_lineno = $. if !defined $start_lineno; if (!/^([-\w]+):\s*(|\S|\S.*\S)\s*$/) { - print STDERR "$prog:$file:$.: unrecognised line\n"; + print STDERR "$prog:$file:$.: unrecognised line \"$_\"\n"; return undef; } ($field, $val) = ($1, $2); @@ -1154,7 +1164,7 @@ read_test print STDERR "$prog:$test{':long-name'}: expected-exit value $val not in 0..255\n"; return undef; } - } elsif ($val !~ /^([\s<>+-=*%\/&|!()]|\b[wse]\b|\bSIG[A-Z0-9]+\b)+$/) { + } elsif ($val !~ /^([\s<>+-=*%\/&|!()]|\b[wse]\b|\bSIG[A-Z][A-Z0-9]*\b)+$/) { print STDERR "$prog:$test{':long-name'}: bad expected-exit expression: $val\n"; return undef; } diff --git a/src/check.t b/src/check.t index 8df826f..6db4f3a 100644 --- a/src/check.t +++ b/src/check.t @@ -1,12 +1,8 @@ -# $MirOS: src/bin/mksh/check.t,v 1.629 2013/08/14 20:26:15 tg Exp $ -# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $ -# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $ -# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ -# $OpenBSD: regress.t,v 1.15 2013/07/01 17:25:27 jca Exp $ -# $OpenBSD: obsd-regress.t,v 1.5 2013/07/01 17:25:27 jca Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.654 2014/06/29 11:28:26 tg Exp $ +# OpenBSD src/regress/bin/ksh updated: 2013/12/02 20:39:44 #- # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011, 2012, 2013 +# 2011, 2012, 2013, 2014 # Thorsten Glaser # # Provided that these terms and disclaimer and all copyright notices @@ -31,7 +27,7 @@ # http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD expected-stdout: - @(#)MIRBSD KSH R48 2013/08/14 + @(#)MIRBSD KSH R50 2014/06/29 description: Check version of shell. stdin: @@ -40,7 +36,7 @@ name: KSH_VERSION category: shell:legacy-no --- expected-stdout: - @(#)LEGACY KSH R48 2013/08/14 + @(#)LEGACY KSH R50 2014/06/29 description: Check version of legacy shell. stdin: @@ -74,6 +70,18 @@ stdin: expected-stdout: --- +name: selftest-exec +description: + Ensure that the test run directory (default /tmp but can be changed + with check.pl flag -T or test.sh $TMPDIR) is not mounted noexec, as + we execute scripts from the scratch directory during several tests. +stdin: + print '#!'"$__progname"'\necho tf' >lq + chmod +x lq + ./lq +expected-stdout: + tf +--- name: selftest-env description: Just output the environment variables set (always fails) @@ -1640,6 +1648,14 @@ expected-stdout: 1=02. 2=02. --- +name: expand-number-1 +description: + Check that positional arguments do not overflow +stdin: + echo "1 ${12345678901234567890} ." +expected-stdout: + 1 . +--- name: eglob-bad-1 description: Check that globbing isn't done when glob has syntax error @@ -2071,12 +2087,18 @@ stdin: echo [!-ab]* echo [!ab]* echo []ab]* + :>'./!bc' + :>'./^bc' + echo [^ab]* + echo [!ab]* expected-stdout: -bc abc bbc -bc abc bbc cbc -bc cbc abc bbc + ^bc abc bbc + !bc -bc ^bc cbc --- name: glob-range-2 description: @@ -2126,6 +2148,18 @@ stdin: expected-stdout: -bc abc bbc cbc ebc --- +name: glob-trim-1 +description: + Check against a regression from fixing IFS-subst-2 +stdin: + x='#foo' + print -r "before='$x'" + x=${x%%#*} + print -r "after ='$x'" +expected-stdout: + before='#foo' + after ='' +--- name: heredoc-1 description: Check ordering/content of redundent here documents. @@ -3689,6 +3723,28 @@ expected-stdout: 12: [A] [B] [] [D] <13> <> --- +name: IFS-subst-2 +description: + Check leading whitespace after trim does not make a field +stdin: + showargs() { for i; do echo -n " <$i>"; done; echo; } + x="X 1 2" + showargs 1 shift ${x#X} +expected-stdout: + <1> <1> <2> +--- +name: IFS-arith-1 +description: + http://austingroupbugs.net/view.php?id=832 +stdin: + ${ZSH_VERSION+false} || emulate sh + ${BASH_VERSION+set -o posix} + showargs() { for x in "$@"; do echo -n "<$x> "; done; echo .; } + IFS=0 + showargs $((1230456)) +expected-stdout: + <123> <456> . +--- name: integer-base-err-1 description: Can't have 0 base (causes shell to exit) @@ -4806,11 +4862,12 @@ description: them exit 0. The POSIX behaviour is needed by BSD make. stdin: set -e - echo `false; echo hi` + echo `false; echo hi` $(<${arr[5]}>" expected-stdout: - 5|a|$v|c d||$v|b| + 5|[1]=$v|[2]=c d|[4]=$v|[0]=a|[5]=b|| + <[5]=meh><> --- name: arrays-5 description: Check if bash-style arrays with specified indices work as expected + (taken out temporarily to fix arrays-4; see also arrays-9a comment) +category: disabled stdin: v="c d" foo=([1]=\$v [2]="$v" [4]='$v' [0]=a [5]=b) @@ -7013,10 +7088,17 @@ stdin: x=([128]=foo bar baz) echo k= ${!x[*]} . echo v= ${x[*]} . + # Check that we do not break this by globbing + :>b=blah + bleh=5 + typeset -a arr + arr+=([bleh]=blah) + echo "<${arr[0]}><${arr[5]}>" expected-stdout: 5|a|$v|c d||$v|b| k= 128 129 130 . v= foo bar baz . + <> --- name: arrays-6 description: @@ -7078,15 +7160,15 @@ stdin: echo !arz[0]: ${!arz[0]} echo !arz[1]: ${!arz[1]} expected-stdout: - !arz: 0 - !arz[0]: - !arz[1]: !arz: arz - !arz[0]: 0 - !arz[1]: - !arz: 0 - !arz[0]: - !arz[1]: + !arz[0]: arz[0] + !arz[1]: arz[1] + !arz: arz + !arz[0]: arz[0] + !arz[1]: arz[1] + !arz: arz + !arz[0]: arz[0] + !arz[1]: arz[1] --- name: arrays-8 description: @@ -7177,11 +7259,11 @@ description: stdin: unset foo; foo=(bar); foo+=(baz); echo 1 ${!foo[*]} : ${foo[*]} . unset foo; foo=(foo bar); foo+=(baz); echo 2 ${!foo[*]} : ${foo[*]} . - unset foo; foo=([2]=foo [0]=bar); foo+=(baz [5]=quux); echo 3 ${!foo[*]} : ${foo[*]} . +# unset foo; foo=([2]=foo [0]=bar); foo+=(baz [5]=quux); echo 3 ${!foo[*]} : ${foo[*]} . expected-stdout: 1 0 1 : bar baz . 2 0 1 2 : foo bar baz . - 3 0 2 3 5 : bar foo baz quux . +# 3 0 2 3 5 : bar foo baz quux . --- name: arrays-9b description: @@ -7660,14 +7742,9 @@ stdin: typeset -i8 foo=10 bar=baz unset baz - bla=foo print ${foo@#} ${bar@#} ${baz@#} . - print ${foo@#123} ${bar@#456} ${baz@#789} . - print ${foo@#bla} ${bar@#bar} ${baz@#OPTIND} . expected-stdout: - D50219A0 20E5DB5B 00000000 . - 554A1C76 004A212E CB209562 . - 6B21CF91 20E5DB5B 124EA49D . + 9B15FBFB CFBDD32B 00000000 . --- name: varexpand-special-quote description: @@ -8772,7 +8849,7 @@ expected-stdout: --- name: oksh-eval description: - $OpenBSD: eval.sh,v 1.1 2010/03/24 08:29:44 fgsch Exp $ + Check expansions. stdin: a= for n in ${a#*=}; do echo 1hu ${n} .; done @@ -8932,8 +9009,7 @@ stdin: --- name: oksh-varfunction-mod1 description: - $OpenBSD: varfunction.sh,v 1.1 2003/12/15 05:28:40 otto Exp $ - Calling + (Inspired by PR 2450 on OpenBSD.) Calling FOO=bar f where f is a ksh style function, should not set FOO in the current env. If f is a Bourne style function, FOO should be set. Furthermore, @@ -8941,7 +9017,6 @@ description: from oksh, setting FOO in the function itself must change the value in setting FOO in the function itself should not change the value in global environment. - Inspired by PR 2450. stdin: print '#!'"$__progname"'\nunset RANDOM\nexport | while IFS= read -r' \ 'RANDOM; do eval '\''print -r -- "$RANDOM=$'\''"$RANDOM"'\'\"\'\; \ @@ -10502,7 +10577,7 @@ expected-stdout: ir2: ir2 s1: ir2=ind s2: typeset -n ir2 - !ind[1]: 1 + !ind[1]: blub[1] !ir2: ir2 ind[1]: e2 ir2: e3 diff --git a/src/dot.mkshrc b/src/dot.mkshrc index cbd13ed..99cc9a1 100644 --- a/src/dot.mkshrc +++ b/src/dot.mkshrc @@ -1,8 +1,8 @@ # $Id$ -# $MirOS: src/bin/mksh/dot.mkshrc,v 1.84 2013/08/10 13:43:50 tg Exp $ +# $MirOS: src/bin/mksh/dot.mkshrc,v 1.88 2014/01/11 18:09:39 tg Exp $ #- # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, -# 2011, 2012, 2013 +# 2011, 2012, 2013, 2014 # Thorsten Glaser # # Provided that these terms and disclaimer and all copyright notices @@ -105,14 +105,14 @@ function chpwd { } chpwd . function cd { - builtin cd "$@" + builtin cd "$@" || return $? chpwd "$@" } function cd_csh { local d t=${1/#~/$DIRSTACKBASE} if ! d=$(builtin cd "$t" 2>&1); then - print -u2 "${1}: ${d##*$t - }." + print -u2 "${1}: ${d##*cd: $t: }." return 1 fi cd "$t" @@ -333,9 +333,12 @@ function Lb64encode { (( u )) || set -U } -# mksh NUL counting, never zero -typeset -Z11 -Uui16 Lnzathash_v -function Lnzathash_add { +# Better Avalanche for the Jenkins Hash +typeset -Z11 -Uui16 Lbafh_v +function Lbafh_init { + Lbafh_v=0 +} +function Lbafh_add { [[ -o utf8-mode ]]; local u=$? set +U local s @@ -348,37 +351,20 @@ function Lnzathash_add { local -i i=0 n=${#s[*]} while (( i < n )); do - ((# Lnzathash_v = (Lnzathash_v + s[i++] + 1) * 1025 )) - ((# Lnzathash_v ^= Lnzathash_v >> 6 )) + ((# Lbafh_v = (Lbafh_v + s[i++] + 1) * 1025 )) + ((# Lbafh_v ^= Lbafh_v >> 6 )) done (( u )) || set -U } -function Lnzaathash_end { - ((# Lnzathash_v *= 1025 )) - ((# Lnzathash_v ^= Lnzathash_v >> 6 )) - ((# Lnzathash_v += Lnzathash_v << 3 )) - ((# Lnzathash_v = (Lnzathash_v ^ - (Lnzathash_v >> 11)) * 32769 )) - print ${Lnzathash_v#16#} -} -function Lnzaathash { - Lnzathash_v=0 - Lnzathash_add "$@" - Lnzaathash_end -} -function Lnzathash { - Lnzathash_v=0 - Lnzathash_add "$@" - Lnzathash_end -} -function Lnzathash_end { - if (( Lnzathash_v )); then - Lnzaathash_end - else - Lnzathash_v=1 - print ${Lnzathash_v#16#} - fi +function Lbafh_finish { + local -Ui t + + ((# t = (((Lbafh_v >> 7) & 0x01010101) * 0x1B) ^ \ + ((Lbafh_v << 1) & 0xFEFEFEFE) )) + ((# Lbafh_v = t ^ (t >>> 8) ^ (Lbafh_v >>> 8) ^ \ + (Lbafh_v >>> 16) ^ (Lbafh_v >>> 24) )) + : } # strip comments (and leading/trailing whitespace if IFS is set) from diff --git a/src/edit.c b/src/edit.c index 675e7ed..2459db7 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1,11 +1,11 @@ -/* $OpenBSD: edit.c,v 1.38 2013/06/03 15:41:59 tedu Exp $ */ +/* $OpenBSD: edit.c,v 1.39 2013/12/17 16:37:05 deraadt Exp $ */ /* $OpenBSD: edit.h,v 1.9 2011/05/30 17:14:35 martynas Exp $ */ -/* $OpenBSD: emacs.c,v 1.44 2011/09/05 04:50:33 marco Exp $ */ -/* $OpenBSD: vi.c,v 1.26 2009/06/29 22:50:19 martynas Exp $ */ +/* $OpenBSD: emacs.c,v 1.48 2013/12/17 16:37:05 deraadt Exp $ */ +/* $OpenBSD: vi.c,v 1.28 2013/12/18 16:45:46 deraadt Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013 + * 2011, 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -28,7 +28,7 @@ #ifndef MKSH_NO_CMDLINE_EDITING -__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.270 2013/08/14 20:26:17 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.275 2014/01/05 21:57:24 tg Exp $"); /* * in later versions we might use libtermcap for this, but since external @@ -82,7 +82,7 @@ static int x_basename(const char *, const char *); static void x_free_words(int, char **); static int x_escape(const char *, size_t, int (*)(const char *, size_t)); static int x_emacs(char *); -static void x_init_prompt(void); +static void x_init_prompt(bool); #if !MKSH_S_NOVI static int x_vi(char *); #endif @@ -148,6 +148,7 @@ x_getc(void) if (x_cols != xx_cols && editmode == 1) { /* redraw line in Emacs mode */ xx_cols = x_cols; + x_init_prompt(false); x_e_rebuildline(MKSH_CLRTOEOL_STRING); } } @@ -960,12 +961,11 @@ static void x_delete(size_t, bool); static size_t x_bword(void); static size_t x_fword(bool); static void x_goto(char *); -static char *x_bs0(char *, char *); +static char *x_bs0(char *, char *) MKSH_A_PURE; static void x_bs3(char **); static int x_size_str(char *); static int x_size2(char *, char **); static void x_zots(char *); -static void x_zotc2(int); static void x_zotc3(char **); static void x_load_hist(char **); static int x_search(char *, int, int); @@ -990,7 +990,7 @@ static int x_fold_case(int); #endif static char *x_lastcp(void); static void do_complete(int, Comp_type); -static size_t x_nb2nc(size_t); +static size_t x_nb2nc(size_t) MKSH_A_PURE; static int unget_char = -1; @@ -1167,16 +1167,17 @@ x_e_getmbc(char *sbuf) } static void -x_init_prompt(void) +x_init_prompt(bool doprint) { - prompt_trunc = pprompt(prompt, 0); + prompt_trunc = pprompt(prompt, doprint ? 0 : -1); pwidth = prompt_trunc % x_cols; prompt_trunc -= pwidth; if ((mksh_uari_t)pwidth > ((mksh_uari_t)x_cols - 3 - MIN_EDIT_SPACE)) { /* force newline after prompt */ prompt_trunc = -1; pwidth = 0; - x_e_putc2('\n'); + if (doprint) + x_e_putc2('\n'); } } @@ -1196,7 +1197,7 @@ x_emacs(char *buf) x_histp = histptr + 1; x_last_command = XFUNC_error; - x_init_prompt(); + x_init_prompt(true); x_displen = (xx_cols = x_cols) - 2 - (x_col = pwidth); x_adj_done = 0; x_adj_ok = true; @@ -1606,7 +1607,7 @@ x_size_str(char *cp) static int x_size2(char *cp, char **dcp) { - int c = *(unsigned char *)cp; + uint8_t c = *(unsigned char *)cp; if (UTFMODE && (c > 0x7F)) return (utf_widthadj(cp, (const char **)dcp)); @@ -1615,7 +1616,7 @@ x_size2(char *cp, char **dcp) if (c == '\t') /* Kludge, tabs are always four spaces. */ return (4); - if (c < ' ' || c == 0x7f) + if (ISCTRL(c) && /* but not C1 */ c < 0x80) /* control unsigned char */ return (2); return (1); @@ -1632,19 +1633,6 @@ x_zots(char *str) } static void -x_zotc2(int c) -{ - if (c == '\t') { - /* Kludge, tabs are always four spaces. */ - x_e_puts(" "); - } else if (c < ' ' || c == 0x7f) { - x_e_putc2('^'); - x_e_putc2(UNCTRL(c)); - } else - x_e_putc2(c); -} - -static void x_zotc3(char **cp) { unsigned char c = **(unsigned char **)cp; @@ -1653,7 +1641,7 @@ x_zotc3(char **cp) /* Kludge, tabs are always four spaces. */ x_e_puts(" "); (*cp)++; - } else if (c < ' ' || c == 0x7f) { + } else if (ISCTRL(c) && /* but not C1 */ c < 0x80) { x_e_putc2('^'); x_e_putc2(UNCTRL(c)); (*cp)++; @@ -1765,7 +1753,10 @@ x_newline(int c MKSH_A_UNUSED) static int x_end_of_text(int c MKSH_A_UNUSED) { - x_zotc2(edchars.eof); + char tmp = edchars.eof; + char *cp = &tmp; + + x_zotc3(&cp); x_putc('\r'); x_putc('\n'); x_flush(); @@ -2377,6 +2368,7 @@ x_mapin(const char *cp, Area *ap) /* XXX -- should handle \^ escape? */ if (*cp == '^') { cp++; + /*XXX or ^^ escape? this is ugly. */ if (*cp >= '?') /* includes '?'; ASCII */ *op++ = CTRL(*cp); @@ -2398,7 +2390,7 @@ x_mapout2(int c, char **buf) { char *p = *buf; - if (c < ' ' || c == 0x7f) { + if (ISCTRL(c)) { *p++ = '^'; *p++ = UNCTRL(c); } else @@ -3341,8 +3333,6 @@ x_mode(bool onoff) #if !MKSH_S_NOVI /* +++ vi editing mode +++ */ -#define Ctrl(c) (c&0x1f) - struct edstate { char *cbuf; ssize_t winleft; @@ -3363,7 +3353,7 @@ static void save_cbuf(void); static void restore_cbuf(void); static int putbuf(const char *, ssize_t, bool); static void del_range(int, int); -static int findch(int, int, bool, bool); +static int findch(int, int, bool, bool) MKSH_A_PURE; static int forwword(int); static int backword(int); static int endword(int); @@ -3376,13 +3366,14 @@ static void redraw_line(bool); static void refresh(int); static int outofwin(void); static void rewindow(void); -static int newcol(int, int); +static int newcol(unsigned char, int); static void display(char *, char *, int); static void ed_mov_opt(int, char *); static int expand_word(int); static int complete_word(int, int); static int print_expansions(struct edstate *, int); -#define char_len(c) ((c) < ' ' || (c) == 0x7F ? 2 : 1) +#define char_len(c) ((ISCTRL((unsigned char)c) && \ + /* but not C1 */ (unsigned char)c < 0x80) ? 2 : 1) static void x_vi_zotc(int); static void vi_error(void); static void vi_macro_reset(void); @@ -3535,7 +3526,7 @@ x_vi(char *buf) es = &ebuf; undo = &undobuf; - x_init_prompt(); + x_init_prompt(true); x_col = pwidth; if (wbuf_len != x_cols - 3 && ((wbuf_len = x_cols - 3))) { @@ -3556,7 +3547,7 @@ x_vi(char *buf) x_flush(); while (/* CONSTCOND */ 1) { if (macro.p) { - c = *macro.p++; + c = (unsigned char)*macro.p++; /* end of current macro? */ if (!c) { /* more macros left to finish? */ @@ -3618,7 +3609,7 @@ vi_hook(int ch) case VNORMAL: if (insert != 0) { - if (ch == Ctrl('v')) { + if (ch == CTRL('v')) { state = VLIT; ch = '^'; } @@ -3730,7 +3721,7 @@ vi_hook(int ch) break; case VXCH: - if (ch == Ctrl('[')) + if (ch == CTRL('[')) state = VNORMAL; else { curcmd[cmdlen++] = ch; @@ -3739,7 +3730,7 @@ vi_hook(int ch) break; case VSEARCH: - if (ch == '\r' || ch == '\n' /*|| ch == Ctrl('[')*/ ) { + if (ch == '\r' || ch == '\n' /*|| ch == CTRL('[')*/ ) { restore_cbuf(); /* Repeat last search? */ if (srchlen == 0) { @@ -3754,10 +3745,10 @@ vi_hook(int ch) memcpy(srchpat, locpat, srchlen + 1); } state = VCMD; - } else if (ch == edchars.erase || ch == Ctrl('h')) { + } else if (ch == edchars.erase || ch == CTRL('h')) { if (srchlen != 0) { srchlen--; - es->linelen -= char_len((unsigned char)locpat[srchlen]); + es->linelen -= char_len(locpat[srchlen]); es->cursor = es->linelen; refresh(0); return (0); @@ -3772,10 +3763,10 @@ vi_hook(int ch) refresh(0); return (0); } else if (ch == edchars.werase) { - int i, n = srchlen; + unsigned int i, n; struct edstate new_es, *save_es; - new_es.cursor = n; + new_es.cursor = srchlen; new_es.cbuf = locpat; save_es = es; @@ -3783,9 +3774,10 @@ vi_hook(int ch) n = backword(1); es = save_es; - for (i = srchlen; --i >= n; ) - es->linelen -= char_len((unsigned char)locpat[i]); - srchlen = n; + i = (unsigned)srchlen; + while (--i >= n) + es->linelen -= char_len(locpat[i]); + srchlen = (int)n; es->cursor = es->linelen; refresh(0); return (0); @@ -3794,12 +3786,12 @@ vi_hook(int ch) vi_error(); else { locpat[srchlen++] = ch; - if (ch < ' ' || ch == 0x7f) { + if (ISCTRL(ch) && /* but not C1 */ ch < 0x80) { if ((size_t)es->linelen + 2 > (size_t)es->cbufsize) vi_error(); es->cbuf[es->linelen++] = '^'; - es->cbuf[es->linelen++] = ch ^ '@'; + es->cbuf[es->linelen++] = UNCTRL(ch); } else { if (es->linelen >= es->cbufsize) vi_error(); @@ -3910,7 +3902,7 @@ nextstate(int ch) return (VXCH); else if (ch == '.') return (VREDO); - else if (ch == Ctrl('v')) + else if (ch == CTRL('v')) return (VVERSION); else if (is_cmd(ch)) return (VCMD); @@ -3923,7 +3915,7 @@ vi_insert(int ch) { int tcursor; - if (ch == edchars.erase || ch == Ctrl('h')) { + if (ch == edchars.erase || ch == CTRL('h')) { if (insert == REPLACE) { if (es->cursor == undo->cursor) { vi_error(); @@ -3980,7 +3972,7 @@ vi_insert(int ch) * buffer (if user inserts & deletes char, ibuf gets trashed and * we don't want to use it) */ - if (first_insert && ch != Ctrl('[')) + if (first_insert && ch != CTRL('[')) saved_inslen = 0; switch (ch) { case '\0': @@ -3990,7 +3982,7 @@ vi_insert(int ch) case '\n': return (1); - case Ctrl('['): + case CTRL('['): expanded = NONE; if (first_insert) { first_insert = false; @@ -4008,19 +4000,19 @@ vi_insert(int ch) return (redo_insert(lastac - 1)); /* { Begin nonstandard vi commands */ - case Ctrl('x'): + case CTRL('x'): expand_word(0); break; - case Ctrl('f'): + case CTRL('f'): complete_word(0, 0); break; - case Ctrl('e'): + case CTRL('e'): print_expansions(es, 0); break; - case Ctrl('i'): + case CTRL('i'): if (Flag(FVITABCOMPLETE)) { complete_word(0, 0); break; @@ -4075,8 +4067,8 @@ vi_cmd(int argcnt, const char *cmd) } switch (*cmd) { - case Ctrl('l'): - case Ctrl('r'): + case CTRL('l'): + case CTRL('r'): redraw_line(true); break; @@ -4263,7 +4255,7 @@ vi_cmd(int argcnt, const char *cmd) case 'j': case '+': - case Ctrl('n'): + case CTRL('n'): if (grabhist(modified, hnum + argcnt) < 0) return (-1); else { @@ -4274,7 +4266,7 @@ vi_cmd(int argcnt, const char *cmd) case 'k': case '-': - case Ctrl('p'): + case CTRL('p'): if (grabhist(modified, hnum - argcnt) < 0) return (-1); else { @@ -4506,26 +4498,26 @@ vi_cmd(int argcnt, const char *cmd) /* AT&T ksh */ case '=': /* Nonstandard vi/ksh */ - case Ctrl('e'): + case CTRL('e'): print_expansions(es, 1); break; /* Nonstandard vi/ksh */ - case Ctrl('i'): + case CTRL('i'): if (!Flag(FVITABCOMPLETE)) return (-1); complete_word(1, argcnt); break; /* some annoying AT&T kshs */ - case Ctrl('['): + case CTRL('['): if (!Flag(FVIESCCOMPLETE)) return (-1); /* AT&T ksh */ case '\\': /* Nonstandard vi/ksh */ - case Ctrl('f'): + case CTRL('f'): complete_word(1, argcnt); break; @@ -4533,7 +4525,7 @@ vi_cmd(int argcnt, const char *cmd) /* AT&T ksh */ case '*': /* Nonstandard vi/ksh */ - case Ctrl('x'): + case CTRL('x'): expand_word(1); break; @@ -4612,7 +4604,7 @@ domove(int argcnt, const char *cmd, int sub) break; case 'h': - case Ctrl('h'): + case CTRL('h'): if (!sub && es->cursor == 0) return (-1); ncursor = es->cursor - argcnt; @@ -5028,7 +5020,7 @@ grabsearch(int save, int start, int fwd, const char *pat) { char *hptr; int hist; - int anchored; + bool anchored; if ((start == 0 && fwd == 0) || (start >= hlast - 1 && fwd == 1)) return (-1); @@ -5036,7 +5028,7 @@ grabsearch(int save, int start, int fwd, const char *pat) start++; else start--; - anchored = *pat == '^' ? (++pat, 1) : 0; + anchored = *pat == '^' ? (++pat, true) : false; if ((hist = findhist(start, fwd, pat, anchored)) < 0) { /* (start != 0 && fwd && match(holdbufp, pat) >= 0) */ if (start != 0 && fwd && strcmp(holdbufp, pat) >= 0) { @@ -5125,7 +5117,7 @@ rewindow(void) } static int -newcol(int ch, int col) +newcol(unsigned char ch, int col) { if (ch == '\t') return ((col | 7) + 1); @@ -5153,10 +5145,10 @@ display(char *wb1, char *wb2, int leftside) *twb1++ = ' '; } while (++col < winwidth && (col & 7) != 0); else if (col < winwidth) { - if (ch < ' ' || ch == 0x7f) { + if (ISCTRL(ch) && /* but not C1 */ ch < 0x80) { *twb1++ = '^'; if (++col < winwidth) { - *twb1++ = ch ^ '@'; + *twb1++ = UNCTRL(ch); col++; } } else { @@ -5433,9 +5425,9 @@ print_expansions(struct edstate *est, int cmd MKSH_A_UNUSED) static void x_vi_zotc(int c) { - if (c < ' ' || c == 0x7f) { + if (ISCTRL(c)) { x_putc('^'); - c ^= '@'; + c = UNCTRL(c); } x_putc(c); } diff --git a/src/eval.c b/src/eval.c index b6ff1dc..62a2fad 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1,8 +1,8 @@ -/* $OpenBSD: eval.c,v 1.39 2013/07/01 17:25:27 jca Exp $ */ +/* $OpenBSD: eval.c,v 1.40 2013/09/14 20:09:30 millert Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013 + * 2011, 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.142 2013/07/24 18:03:57 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.150 2014/06/09 11:16:07 tg Exp $"); /* * string expansion @@ -74,7 +74,7 @@ static const char *maybe_expand_tilde(const char *, XString *, char **, int); static char *homedir(char *); #endif static void alt_expand(XPtrV *, char *, char *, char *, int); -static int utflen(const char *); +static int utflen(const char *) MKSH_A_PURE; static void utfincptr(const char *, mksh_ari_t *); /* UTFMODE functions */ @@ -324,9 +324,9 @@ expand( } continue; case EXPRSUB: - word = IFS_WORD; tilde_ok = 0; if (f & DONTRUNCOMMAND) { + word = IFS_WORD; *dp++ = '$'; *dp++ = '('; *dp++ = '('; while (*sp != '\0') { Xcheck(ds, dp); @@ -343,11 +343,10 @@ expand( v_evaluate(&v, substitute(sp, 0), KSH_UNWIND_ERROR, true); sp = strnul(sp) + 1; - cp = str_val(&v); - while (*cp) { - Xcheck(ds, dp); - *dp++ = *cp++; - } + x.str = str_val(&v); + type = XSUB; + if (f & DOBLANK) + doblank++; } continue; case OSUBST: { @@ -412,27 +411,10 @@ expand( if (stype) sp += slen; switch (stype & 0x17F) { - case 0x100 | '#': { - char *beg, *end; - mksh_ari_t seed; - register uint32_t h; - - beg = wdcopy(sp, ATEMP); - end = beg + (wdscan(sp, CSUBST) - sp); - end[-2] = EOS; - end = wdstrip(beg, 0); - afree(beg, ATEMP); - evaluate(substitute(end, 0), - &seed, KSH_UNWIND_ERROR, true); - /* hash with seed, for now */ - h = seed; - NZATUpdateString(h, - str_val(st->var)); - NZAATFinish(h); + case 0x100 | '#': x.str = shf_smprintf("%08X", - (unsigned int)h); + (unsigned int)hash(str_val(st->var))); break; - } case 0x100 | 'Q': { struct shf shf; @@ -700,7 +682,7 @@ expand( *dp = '\0'; quote = st->quotep; f = st->f; - if (f&DOBLANK) + if (f & DOBLANK) doblank--; switch (st->stype & 0x17F) { case '#': @@ -719,11 +701,12 @@ expand( */ x.str = trimsub(str_val(st->var), dp, st->stype); - if (x.str[0] != '\0' || st->quotep) + if (x.str[0] != '\0') { + word = IFS_WS; type = XSUB; - else - type = XNULLSUB; - if (f&DOBLANK) + } else + type = quote ? XSUB : XNULLSUB; + if (f & DOBLANK) doblank++; st = st->prev; continue; @@ -755,7 +738,7 @@ expand( dp, len), KSH_UNWIND_ERROR); x.str = str_val(st->var); type = XSUB; - if (f&DOBLANK) + if (f & DOBLANK) doblank++; st = st->prev; continue; @@ -773,7 +756,7 @@ expand( case 0x100 | 'Q': dp = Xrestpos(ds, dp, st->base); type = XSUB; - if (f&DOBLANK) + if (f & DOBLANK) doblank++; st = st->prev; continue; @@ -810,12 +793,14 @@ expand( * other stuff inside the quotes). */ type = XBASE; - if (f&DOBLANK) { + if (f & DOBLANK) { doblank--; /* - * not really correct: x=; "$x$@" should - * generate a null argument and - * set A; "${@:+}" shouldn't. + * XXX not really correct: + * x=; "$x$@" + * should generate a null argument and + * set A; "${@:+}" + * shouldn't. */ if (dp == Xstring(ds, dp)) word = IFS_WS; @@ -826,7 +811,7 @@ expand( case XSUBMID: if ((c = *x.str++) == 0) { type = XBASE; - if (f&DOBLANK) + if (f & DOBLANK) doblank--; continue; } @@ -847,7 +832,7 @@ expand( word = IFS_WORD; if ((x.str = *x.u.strv++) == NULL) { type = XBASE; - if (f&DOBLANK) + if (f & DOBLANK) doblank--; continue; } @@ -896,7 +881,7 @@ expand( if (x.split) subst_exstat = waitlast(); type = XBASE; - if (f&DOBLANK) + if (f & DOBLANK) doblank--; continue; } @@ -1269,17 +1254,12 @@ varsub(Expand *xp, const char *sp, const char *word, if (*sp == '!' && sp[1]) { ++sp; xp->var = global(sp); - if (vstrchr(sp, '[')) { - if (xp->var->flag & ISSET) - xp->str = shf_smprintf("%lu", - arrayindex(xp->var)); - else - xp->str = null; - } else if (xp->var->flag & ISSET) - xp->str = xp->var->name; + if (vstrchr(sp, '[')) + xp->str = shf_smprintf("%s[%lu]", + xp->var->name, + arrayindex(xp->var)); else - /* ksh93 compat */ - xp->str = "0"; + xp->str = xp->var->name; } else { xp->var = global(sp); xp->str = str_val(xp->var); diff --git a/src/exec.c b/src/exec.c index 50ec9ca..70ef83d 100644 --- a/src/exec.c +++ b/src/exec.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013 + * 2011, 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.125 2013/07/21 20:44:44 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.132 2014/06/24 18:38:31 tg Exp $"); #ifndef MKSH_DEFAULT_EXECSHELL #define MKSH_DEFAULT_EXECSHELL "/bin/sh" @@ -462,7 +462,7 @@ execute(struct op * volatile t, if (vp_pipest->flag & INT_L) { unset(vp_pipest, 1); vp_pipest->flag = DEFINED | ISSET | INTEGER | RDONLY | - ARRAY | INT_U; + ARRAY | INT_U | INT_L; vp_pipest->val.i = rv; } @@ -604,19 +604,15 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, /* go on, use the builtin */ break; #endif -#if !defined(MKSH_SMALL) } else if (tp->val.f == c_trap) { t->u.evalflags &= ~DOTCOMEXEC; break; -#endif } else break; tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC)); } -#if !defined(MKSH_SMALL) if (t->u.evalflags & DOTCOMEXEC) flags |= XEXEC; -#endif l_expand = e->loc; if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN)))) type_flags = 0; @@ -656,7 +652,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, /* but assign in there as usual */ typeset(cp, type_flags, 0, 0, 0); if (bourne_function_call && !(type_flags & EXPORT)) - typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0); + typeset(cp, LOCAL | LOCAL_COPY | EXPORT, 0, 0, 0); } if (Flag(FXTRACE)) { @@ -816,7 +812,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, /* set $_ to programme's full path */ /* setstr() can't fail here */ - setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0), + setstr(typeset("_", LOCAL | EXPORT, 0, INTEGER, 0), tp->val.s, KSH_RETURN_ERROR); if (flags&XEXEC) { @@ -869,7 +865,7 @@ scriptexec(struct op *tp, const char **ap) *tp->args-- = tp->str; #ifndef MKSH_SMALL - if ((fd = open(tp->str, O_RDONLY)) >= 0) { + if ((fd = open(tp->str, O_RDONLY | O_BINARY)) >= 0) { /* read first MAXINTERP octets from file */ if (read(fd, buf, sizeof(buf)) <= 0) /* read error -> no good */ @@ -884,14 +880,14 @@ scriptexec(struct op *tp, const char **ap) fd = (char *)cp - buf; /* either 0 or (if BOM) 3 */ /* scan for newline (or CR) or NUL _before_ end of buffer */ - while ((char *)cp < (buf + sizeof(buf))) + while ((size_t)((char *)cp - buf) < sizeof(buf)) if (*cp == '\0' || *cp == '\n' || *cp == '\r') { *cp = '\0'; break; } else ++cp; /* if the shebang line is longer than MAXINTERP, bail out */ - if ((char *)cp >= (buf + sizeof(buf))) + if ((size_t)((char *)cp - buf) >= sizeof(buf)) goto noshebang; /* restore begin of shebang position (buf+0 or buf+3) */ @@ -923,6 +919,10 @@ scriptexec(struct op *tp, const char **ap) *tp->args-- = (char *)cp; } noshebang: + if (buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' && + buf[3] == 'F') + errorf("%s: not executable: %d-bit ELF file", tp->str, + 32 * ((uint8_t)buf[4])); fd = buf[0] << 8 | buf[1]; if ((fd == /* OMAGIC */ 0407) || (fd == /* NMAGIC */ 0410) || @@ -931,7 +931,6 @@ scriptexec(struct op *tp, const char **ap) (fd == /* ECOFF_I386 */ 0x4C01) || (fd == /* ECOFF_M68K */ 0x0150 || fd == 0x5001) || (fd == /* ECOFF_SH */ 0x0500 || fd == 0x0005) || - (fd == 0x7F45 && buf[2] == 'L' && buf[3] == 'F') || (fd == /* "MZ" */ 0x4D5A) || (fd == /* gzip */ 0x1F8B)) errorf("%s: not executable: magic %04X", tp->str, fd); @@ -1374,7 +1373,7 @@ iosetup(struct ioword *iop, struct tbl *tp) warningf(true, "%s: %s", cp, "restricted"); return (-1); } - u = open(cp, flags, 0666); + u = open(cp, flags | O_BINARY, 0666); } if (u < 0) { /* herein() may already have printed message */ @@ -1507,7 +1506,7 @@ herein(struct ioword *iop, char **resbuf) * so temp doesn't get removed too soon). */ h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps); - if (!(shf = h->shf) || (fd = open(h->tffn, O_RDONLY, 0)) < 0) { + if (!(shf = h->shf) || (fd = open(h->tffn, O_RDONLY | O_BINARY, 0)) < 0) { i = errno; warningf(true, "can't %s temporary file %s: %s", !shf ? "create" : "open", h->tffn, cstrerror(i)); @@ -1669,7 +1668,7 @@ static Test_op dbteste_isa(Test_env *te, Test_meta meta) { Test_op ret = TO_NONOP; - int uqword; + bool uqword; const char *p; if (!*te->pos.wp) diff --git a/src/expr.c b/src/expr.c index e91c0da..057666e 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1,8 +1,8 @@ -/* $OpenBSD: expr.c,v 1.22 2013/03/28 08:39:28 nicm Exp $ */ +/* $OpenBSD: expr.c,v 1.23 2013/12/17 16:37:06 deraadt Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013 + * 2011, 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.72 2013/07/21 18:38:56 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.76 2014/06/24 19:53:19 tg Exp $"); /* the order of these enums is constrained by the order of opinfo[] */ enum token { @@ -916,8 +916,7 @@ ksh_access(const char *fn, int mode) return (rv); } -#ifndef MKSH_mirbsd_wcwidth -/* From: X11/xc/programs/xterm/wcwidth.c,v 1.6 2013/05/31 23:27:09 tg Exp $ */ +/* From: X11/xc/programs/xterm/wcwidth.c,v 1.8 2014/06/24 19:53:53 tg Exp $ */ struct mb_ucsrange { unsigned short beg; @@ -925,11 +924,11 @@ struct mb_ucsrange { }; static int mb_ucsbsearch(const struct mb_ucsrange arr[], size_t elems, - unsigned int val); + unsigned int val) MKSH_A_PURE; /* - * Generated by MirOS: contrib/code/Snippets/eawparse,v 1.1 2013/05/31 23:27:16 tg Exp $ - * from Unicode 6.2.0 + * Generated by MirOS: contrib/code/Snippets/eawparse,v 1.2 2013/11/30 13:45:17 tg Exp $ + * from the Unicode Character Database, Version 7.0.0 */ static const struct mb_ucsrange mb_ucs_combining[] = { @@ -940,8 +939,9 @@ static const struct mb_ucsrange mb_ucs_combining[] = { { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, - { 0x0600, 0x0604 }, + { 0x0600, 0x0605 }, { 0x0610, 0x061A }, + { 0x061C, 0x061C }, { 0x064B, 0x065F }, { 0x0670, 0x0670 }, { 0x06D6, 0x06DD }, @@ -958,8 +958,7 @@ static const struct mb_ucsrange mb_ucs_combining[] = { { 0x0825, 0x0827 }, { 0x0829, 0x082D }, { 0x0859, 0x085B }, - { 0x08E4, 0x08FE }, - { 0x0900, 0x0902 }, + { 0x08E4, 0x0902 }, { 0x093A, 0x093A }, { 0x093C, 0x093C }, { 0x0941, 0x0948 }, @@ -995,16 +994,19 @@ static const struct mb_ucsrange mb_ucs_combining[] = { { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, + { 0x0C00, 0x0C00 }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0C62, 0x0C63 }, + { 0x0C81, 0x0C81 }, { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, { 0x0CE2, 0x0CE3 }, + { 0x0D01, 0x0D01 }, { 0x0D41, 0x0D44 }, { 0x0D4D, 0x0D4D }, { 0x0D62, 0x0D63 }, @@ -1050,13 +1052,14 @@ static const struct mb_ucsrange mb_ucs_combining[] = { { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, - { 0x180B, 0x180D }, + { 0x180B, 0x180E }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, { 0x1A17, 0x1A18 }, + { 0x1A1B, 0x1A1B }, { 0x1A56, 0x1A56 }, { 0x1A58, 0x1A5E }, { 0x1A60, 0x1A60 }, @@ -1064,6 +1067,7 @@ static const struct mb_ucsrange mb_ucs_combining[] = { { 0x1A65, 0x1A6C }, { 0x1A73, 0x1A7C }, { 0x1A7F, 0x1A7F }, + { 0x1AB0, 0x1ABE }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, { 0x1B36, 0x1B3A }, @@ -1073,7 +1077,7 @@ static const struct mb_ucsrange mb_ucs_combining[] = { { 0x1B80, 0x1B81 }, { 0x1BA2, 0x1BA5 }, { 0x1BA8, 0x1BA9 }, - { 0x1BAB, 0x1BAB }, + { 0x1BAB, 0x1BAD }, { 0x1BE6, 0x1BE6 }, { 0x1BE8, 0x1BE9 }, { 0x1BED, 0x1BED }, @@ -1085,12 +1089,13 @@ static const struct mb_ucsrange mb_ucs_combining[] = { { 0x1CE2, 0x1CE8 }, { 0x1CED, 0x1CED }, { 0x1CF4, 0x1CF4 }, - { 0x1DC0, 0x1DE6 }, + { 0x1CF8, 0x1CF9 }, + { 0x1DC0, 0x1DF5 }, { 0x1DFC, 0x1DFF }, { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2064 }, - { 0x206A, 0x206F }, + { 0x2066, 0x206F }, { 0x20D0, 0x20F0 }, { 0x2CEF, 0x2CF1 }, { 0x2D7F, 0x2D7F }, @@ -1113,11 +1118,13 @@ static const struct mb_ucsrange mb_ucs_combining[] = { { 0xA9B3, 0xA9B3 }, { 0xA9B6, 0xA9B9 }, { 0xA9BC, 0xA9BC }, + { 0xA9E5, 0xA9E5 }, { 0xAA29, 0xAA2E }, { 0xAA31, 0xAA32 }, { 0xAA35, 0xAA36 }, { 0xAA43, 0xAA43 }, { 0xAA4C, 0xAA4C }, + { 0xAA7C, 0xAA7C }, { 0xAAB0, 0xAAB0 }, { 0xAAB2, 0xAAB4 }, { 0xAAB7, 0xAAB8 }, @@ -1130,7 +1137,7 @@ static const struct mb_ucsrange mb_ucs_combining[] = { { 0xABED, 0xABED }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, - { 0xFE20, 0xFE26 }, + { 0xFE20, 0xFE2D }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB } }; @@ -1188,4 +1195,3 @@ utf_wcwidth(unsigned int wc) return (2); return (1); } -#endif diff --git a/src/funcs.c b/src/funcs.c index 53ab789..77d9494 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -1,11 +1,11 @@ -/* $OpenBSD: c_ksh.c,v 1.33 2009/02/07 14:03:24 kili Exp $ */ -/* $OpenBSD: c_sh.c,v 1.43 2013/04/19 17:39:45 deraadt Exp $ */ +/* $OpenBSD: c_ksh.c,v 1.34 2013/12/17 16:37:05 deraadt Exp $ */ +/* $OpenBSD: c_sh.c,v 1.44 2013/09/04 15:49:18 millert Exp $ */ /* $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $ */ -/* $OpenBSD: c_ulimit.c,v 1.17 2008/03/21 12:51:19 millert 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, - * 2010, 2011, 2012, 2013 + * 2010, 2011, 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.244 2013/06/03 22:28:32 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.256 2014/06/09 13:25:52 tg Exp $"); #if HAVE_KILLPG /* @@ -60,6 +60,10 @@ __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.244 2013/06/03 22:28:32 tg Exp $"); #define c_ulimit c_true #endif +#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID +static int c_suspend(const char **); +#endif + /* getn() that prints error */ static int bi_getn(const char *as, int *ai) @@ -123,6 +127,9 @@ const struct builtin mkshbuiltins[] = { {"*=return", c_exitreturn}, {Tsgset, c_set}, {"*=shift", c_shift}, +#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID + {"suspend", c_suspend}, +#endif {"test", c_test}, {"*=times", c_times}, {"*=trap", c_trap}, @@ -641,6 +648,7 @@ c_typeset(const char **wp) const char *opts; const char *fieldstr = NULL, *basestr = NULL; bool localv = false, func = false, pflag = false, istset = true; + enum namerefflag new_refflag = SRF_NOP; switch (**wp) { @@ -721,7 +729,7 @@ c_typeset(const char **wp) flag = LCASEV; break; case 'n': - set_refflag = (builtin_opt.info & GI_PLUS) ? + new_refflag = (builtin_opt.info & GI_PLUS) ? SRF_DISABLE : SRF_ENABLE; break; /* export, readonly: POSIX -p flag */ @@ -745,8 +753,6 @@ c_typeset(const char **wp) flag = EXPORT; break; case '?': - errout: - set_refflag = SRF_NOP; return (1); } if (builtin_opt.info & GI_PLUS) { @@ -761,10 +767,10 @@ c_typeset(const char **wp) } if (fieldstr && !bi_getn(fieldstr, &field)) - goto errout; + return (1); if (basestr && (!bi_getn(basestr, &base) || base < 1 || base > 36)) { bi_errorf("%s: %s", "bad integer base", basestr); - goto errout; + return (1); } if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] && @@ -776,9 +782,9 @@ c_typeset(const char **wp) } if (func && (((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT)) || - set_refflag != SRF_NOP)) { + new_refflag != SRF_NOP)) { bi_errorf("only -t, -u and -x options may be used with -f"); - goto errout; + return (1); } if (wp[builtin_opt.optind]) { /* @@ -802,10 +808,18 @@ c_typeset(const char **wp) * are also set in this command */ if ((fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV | - INTEGER | INT_U | INT_L)) || set_refflag != SRF_NOP) + INTEGER | INT_U | INT_L)) || new_refflag != SRF_NOP) fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV | INTEGER | INT_U | INT_L); } + if (new_refflag != SRF_NOP) { + fclr &= ~(ARRAY | ASSOC); + fset &= ~(ARRAY | ASSOC); + fclr |= EXPORT; + fset |= ASSOC; + if (new_refflag == SRF_DISABLE) + fclr |= ASSOC; + } /* set variables and attributes */ if (wp[builtin_opt.optind] && @@ -836,14 +850,12 @@ c_typeset(const char **wp) } } else if (!typeset(wp[i], fset, fclr, field, base)) { bi_errorf("%s: %s", wp[i], "is not an identifier"); - goto errout; + return (1); } } - set_refflag = SRF_NOP; return (rv); } - set_refflag = SRF_NOP; /* list variables and attributes */ /* no difference at this point.. */ @@ -1345,8 +1357,10 @@ c_kill(const char **wp) for (; wp[i]; i++) { if (!bi_getn(wp[i], &n)) return (1); +#if (NSIG < 128) if (n > 128 && n < 128 + NSIG) n -= 128; +#endif if (n > 0 && n < NSIG) shprintf("%s\n", sigtraps[n].name); else @@ -3333,16 +3347,6 @@ ptest_error(Test_env *te, int ofs, const char *msg) #define SOFT 0x1 #define HARD 0x2 -struct limits { - const char *name; - int resource; /* resource to get/set */ - unsigned int factor; /* multiply by to get rlim_{cur,max} values */ - char option; -}; - -static void print_ulimit(const struct limits *, int); -static int set_ulimit(const struct limits *, const char *, int); - /* Magic to divine the 'm' and 'v' limits */ #ifdef RLIMIT_AS @@ -3385,165 +3389,38 @@ static int set_ulimit(const struct limits *, const char *, int); #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 RLIMITS_DEFNS +#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) { - static const struct limits limits[] = { - /* do not use options -H, -S or -a or change the order */ -#ifdef RLIMIT_CPU - { "time(cpu-seconds)", RLIMIT_CPU, 1, 't' }, -#endif -#ifdef RLIMIT_FSIZE - { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, -#endif -#ifdef RLIMIT_CORE - { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, -#endif -#ifdef RLIMIT_DATA - { "data(KiB)", RLIMIT_DATA, 1024, 'd' }, -#endif -#ifdef RLIMIT_STACK - { "stack(KiB)", RLIMIT_STACK, 1024, 's' }, -#endif -#ifdef RLIMIT_MEMLOCK - { "lockedmem(KiB)", RLIMIT_MEMLOCK, 1024, 'l' }, -#endif -#ifdef RLIMIT_NOFILE - { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, -#endif -#ifdef RLIMIT_NPROC - { "processes", RLIMIT_NPROC, 1, 'p' }, -#endif -#ifdef RLIMIT_SWAP - { "swap(KiB)", RLIMIT_SWAP, 1024, 'w' }, -#endif -#ifdef RLIMIT_LOCKS - { "flocks", RLIMIT_LOCKS, -1, 'L' }, -#endif -#ifdef RLIMIT_TIME - { "humantime(seconds)", RLIMIT_TIME, 1, 'T' }, -#endif -#ifdef RLIMIT_NOVMON - { "vnodemonitors", RLIMIT_NOVMON, 1, 'V' }, -#endif -#ifdef RLIMIT_SIGPENDING - { "sigpending", RLIMIT_SIGPENDING, 1, 'i' }, -#endif -#ifdef RLIMIT_MSGQUEUE - { "msgqueue(bytes)", RLIMIT_MSGQUEUE, 1, 'q' }, -#endif -#ifdef RLIMIT_AIO_MEM - { "AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024, 'M' }, -#endif -#ifdef RLIMIT_AIO_OPS - { "AIOoperations", RLIMIT_AIO_OPS, 1, 'O' }, -#endif -#ifdef RLIMIT_TCACHE - { "cachedthreads", RLIMIT_TCACHE, 1, 'C' }, -#endif -#ifdef RLIMIT_SBSIZE - { "sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024, 'B' }, -#endif -#ifdef RLIMIT_PTHREAD - { "threadsperprocess", RLIMIT_PTHREAD, 1, 'P' }, -#endif -#ifdef RLIMIT_NICE - { "maxnice", RLIMIT_NICE, 1, 'e' }, -#endif -#ifdef RLIMIT_RTPRIO - { "maxrtprio", RLIMIT_RTPRIO, 1, 'r' }, -#endif -#if defined(ULIMIT_M_IS_RSS) - { "resident-set(KiB)", RLIMIT_RSS, 1024, 'm' }, -#elif defined(ULIMIT_M_IS_VMEM) - { "memory(KiB)", RLIMIT_VMEM, 1024, 'm' }, -#endif -#if defined(ULIMIT_V_IS_VMEM) - { "virtual-memory(KiB)", RLIMIT_VMEM, 1024, 'v' }, -#elif defined(ULIMIT_V_IS_AS) - { "address-space(KiB)", RLIMIT_AS, 1024, 'v' }, -#endif - { NULL, 0, 0, 0 } - }; - static const char opts[] = "a" -#ifdef RLIMIT_SBSIZE - "B" -#endif -#ifdef RLIMIT_TCACHE - "C" -#endif -#ifdef RLIMIT_CORE - "c" -#endif -#ifdef RLIMIT_DATA - "d" -#endif -#ifdef RLIMIT_NICE - "e" -#endif -#ifdef RLIMIT_FSIZE - "f" -#endif - "H" -#ifdef RLIMIT_SIGPENDING - "i" -#endif -#ifdef RLIMIT_LOCKS - "L" -#endif -#ifdef RLIMIT_MEMLOCK - "l" -#endif -#ifdef RLIMIT_AIO_MEM - "M" -#endif -#if defined(ULIMIT_M_IS_RSS) || defined(ULIMIT_M_IS_VMEM) - "m" -#endif -#ifdef RLIMIT_NOFILE - "n" -#endif -#ifdef RLIMIT_AIO_OPS - "O" -#endif -#ifdef RLIMIT_PTHREAD - "P" -#endif -#ifdef RLIMIT_NPROC - "p" -#endif -#ifdef RLIMIT_MSGQUEUE - "q" -#endif -#ifdef RLIMIT_RTPRIO - "r" -#endif - "S" -#ifdef RLIMIT_STACK - "s" -#endif -#ifdef RLIMIT_TIME - "T" -#endif -#ifdef RLIMIT_CPU - "t" -#endif -#ifdef RLIMIT_NOVMON - "V" -#endif -#if defined(ULIMIT_V_IS_VMEM) || defined(ULIMIT_V_IS_AS) - "v" -#endif -#ifdef RLIMIT_SWAP - "w" -#endif - ; + size_t i = 0; int how = SOFT | HARD, optc, what = 'f'; bool all = false; - const struct limits *l; - while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) + while ((optc = ksh_getopt(wp, &builtin_opt, rlimits_opts)) != -1) switch (optc) { case 'H': how = HARD; @@ -3555,31 +3432,32 @@ c_ulimit(const char **wp) all = true; break; case '?': - bi_errorf("usage: ulimit [-%s] [value]", opts); + bi_errorf("usage: ulimit [-%s] [value]", rlimits_opts); return (1); default: what = optc; } - for (l = limits; l->name && l->option != what; l++) - ; - if (!l->name) { - internal_warningf("ulimit: %c", what); - return (1); + 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("too many arguments"); return (1); } - return (set_ulimit(l, wp[builtin_opt.optind], how)); + return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how)); } if (!all) - print_ulimit(l, how); - else for (l = limits; l->name; l++) { - shprintf("%-20s ", l->name); - print_ulimit(l, how); + print_ulimit(rlimits[i], how); + else for (i = 0; i < NELEM(rlimits); ++i) { + shprintf("%-20s ", rlimits[i]->name); + print_ulimit(rlimits[i], how); } return (0); } @@ -3611,7 +3489,11 @@ set_ulimit(const struct limits *l, const char *v, int how) } if (getrlimit(l->resource, &limit) < 0) { - /* some can't be read, e.g. Linux RLIMIT_LOCKS */ +#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; } @@ -3735,7 +3617,7 @@ c_cat(const char **wp) fn = *wp++; if (fn[0] == '-' && fn[1] == '\0') fd = STDIN_FILENO; - else if ((fd = open(fn, O_RDONLY)) < 0) { + else if ((fd = open(fn, O_RDONLY | O_BINARY)) < 0) { eno = errno; bi_errorf("%s: %s", fn, cstrerror(eno)); rv = 1; @@ -3761,14 +3643,12 @@ c_cat(const char **wp) break; while (n) { w = write(STDOUT_FILENO, cp, n); - eno = errno; - /* give the user a chance to ^C out */ - intrcheck(); if (w == -1) { - if (eno == EINTR) + if (errno == EINTR) /* interrupted, try again */ continue; /* an error occured during writing */ + eno = errno; bi_errorf("%s: %s", "", cstrerror(eno)); rv = 1; @@ -3844,3 +3724,24 @@ c_sleep(const char **wp) return (rv); } #endif + +#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID +static int +c_suspend(const char **wp) +{ + if (wp[1] != NULL) { + bi_errorf("too many arguments"); + return (1); + } + if (Flag(FLOGIN)) { + /* Can't suspend an orphaned process group. */ + if (getpgid(kshppid) == getpgid(0) || + getsid(kshppid) != getsid(0)) { + bi_errorf("can't suspend a login shell"); + return (1); + } + } + j_suspend(); + return (0); +} +#endif diff --git a/src/histrap.c b/src/histrap.c index 3b28f23..d15cc8d 100644 --- a/src/histrap.c +++ b/src/histrap.c @@ -3,7 +3,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012 + * 2011, 2012, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -27,7 +27,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.131 2012/12/28 02:28:35 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.134 2014/06/09 13:25:53 tg Exp $"); Trap sigtraps[NSIG + 1]; static struct sigaction Sigact_ign; @@ -442,7 +442,7 @@ hist_get(const char *str, bool approx, bool allow_cur) hp = NULL; } } else { - int anchored = *str == '?' ? (++str, 0) : 1; + 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) @@ -509,7 +509,7 @@ histnum(int n) * direction. */ int -findhist(int start, int fwd, const char *str, int anchored) +findhist(int start, int fwd, const char *str, bool anchored) { char **hp; int maxhist = histptr - history; @@ -720,7 +720,8 @@ hist_init(Source *s) retry: /* we have a file and are interactive */ - if ((fd = open(hname, O_RDWR | O_CREAT | O_APPEND, 0600)) < 0) + if ((fd = open(hname, O_RDWR | O_CREAT | O_APPEND | O_BINARY, + 0600)) < 0) return; histfd = savefd(fd); @@ -756,7 +757,7 @@ hist_init(Source *s) /* create temporary file */ nhname = shf_smprintf("%s.%d", hname, (int)procpid); if ((fd = open(nhname, O_RDWR | O_CREAT | O_TRUNC | - O_EXCL, 0600)) < 0) { + O_EXCL | O_BINARY, 0600)) < 0) { /* just don't truncate then, meh. */ goto hist_trunc_dont; } @@ -976,6 +977,7 @@ inittraps(void) trap_exstat = -1; /* Populate sigtraps based on sys_signame and sys_siglist. */ + /*XXX this is idiotic, use a multi-key/value hashtable! */ for (i = 0; i <= NSIG; i++) { sigtraps[i].signal = i; if (i == ksh_SIGERR) { diff --git a/src/jobs.c b/src/jobs.c index 3277c78..0216a34 100644 --- a/src/jobs.c +++ b/src/jobs.c @@ -1,8 +1,8 @@ -/* $OpenBSD: jobs.c,v 1.39 2009/12/13 04:36:48 deraadt Exp $ */ +/* $OpenBSD: jobs.c,v 1.40 2013/09/04 15:49:18 millert Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, - * 2012, 2013 + * 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.100 2013/07/26 20:33:23 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.104 2014/06/10 22:17:09 tg Exp $"); #if HAVE_KILLPG #define mksh_killpg killpg @@ -225,6 +225,54 @@ proc_errorlevel(Proc *p) } } +#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID +/* suspend the shell */ +void +j_suspend(void) +{ + struct sigaction sa, osa; + + /* Restore tty and pgrp. */ + if (ttypgrp_ok) { + if (tty_hasstate) + mksh_tcset(tty_fd, &tty_state); + if (restore_ttypgrp >= 0) { + if (tcsetpgrp(tty_fd, restore_ttypgrp) < 0) { + warningf(false, "%s: %s %s: %s", "j_suspend", + "tcsetpgrp", "failed", cstrerror(errno)); + } else if (setpgid(0, restore_ttypgrp) < 0) { + warningf(false, "%s: %s %s: %s", "j_suspend", + "setpgid", "failed", cstrerror(errno)); + } + } + } + + /* Suspend the shell. */ + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_DFL; + sigaction(SIGTSTP, &sa, &osa); + kill(0, SIGTSTP); + + /* Back from suspend, reset signals, pgrp and tty. */ + sigaction(SIGTSTP, &osa, NULL); + if (ttypgrp_ok) { + if (restore_ttypgrp >= 0) { + if (setpgid(0, kshpid) < 0) { + warningf(false, "%s: %s %s: %s", "j_suspend", + "setpgid", "failed", cstrerror(errno)); + ttypgrp_ok = false; + } else if (tcsetpgrp(tty_fd, kshpid) < 0) { + warningf(false, "%s: %s %s: %s", "j_suspend", + "tcsetpgrp", "failed", cstrerror(errno)); + ttypgrp_ok = false; + } + } + tty_init_state(); + } +} +#endif + /* job cleanup before shell exit */ void j_exit(void) @@ -1222,6 +1270,15 @@ j_waitj(Job *j, rv = vp->val.i; p = p->next; } + } else if (Flag(FPIPEFAIL) && (j->proc_list != NULL)) { + Proc *p = j->proc_list; + int i; + + while (p != NULL) { + if ((i = proc_errorlevel(p))) + rv = i; + p = p->next; + } } if (!(flags & JW_ASYNCNOTIFY) @@ -1281,7 +1338,11 @@ j_sigchld(int sig MKSH_A_UNUSED) getrusage(RUSAGE_CHILDREN, &ru0); do { #ifndef MKSH_NOPROSPECTOFWORK - pid = waitpid(-1, &status, (WNOHANG|WUNTRACED)); + pid = waitpid(-1, &status, (WNOHANG | +#ifdef WCONTINUED + WCONTINUED | +#endif + WUNTRACED)); #else pid = wait(&status); #endif @@ -1320,6 +1381,13 @@ j_sigchld(int sig MKSH_A_UNUSED) if (WIFSTOPPED(status)) p->state = PSTOPPED; else +#ifdef WIFCONTINUED + if (WIFCONTINUED(status)) { + p->state = j->state = PRUNNING; + /* skip check_job(), no-op in this case */ + continue; + } else +#endif #endif if (WIFSIGNALED(status)) p->state = PSIGNALLED; diff --git a/src/lex.c b/src/lex.c index e58d8b8..9d39998 100644 --- a/src/lex.c +++ b/src/lex.c @@ -1,8 +1,8 @@ -/* $OpenBSD: lex.c,v 1.47 2013/03/03 19:11:34 guenther Exp $ */ +/* $OpenBSD: lex.c,v 1.49 2013/12/17 16:37:06 deraadt Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013 + * 2011, 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.188 2013/08/10 13:44:31 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.193 2014/06/29 11:28:28 tg Exp $"); /* * states while lexing word @@ -159,9 +159,10 @@ getsc_r(int c) state = statep->type; \ } while (/* CONSTCOND */ 0) -#define PUSH_SRETRACE() do { \ +#define PUSH_SRETRACE(s) do { \ struct sretrace_info *ri; \ \ + PUSH_STATE(s); \ statep->ls_start = Xsavepos(ws, wp); \ ri = alloc(sizeof(struct sretrace_info), ATEMP); \ Xinit(ri->xs, ri->xp, 64, ATEMP); \ @@ -176,6 +177,7 @@ getsc_r(int c) dp = (void *)retrace_info; \ retrace_info = retrace_info->next; \ afree(dp, ATEMP); \ + POP_STATE(); \ } while (/* CONSTCOND */ 0) /** @@ -404,9 +406,8 @@ yylex(int cf) c = getsc(); if (c == '(') /*)*/ { *wp++ = EXPRSUB; - PUSH_STATE(SASPAREN); + PUSH_SRETRACE(SASPAREN); statep->nparen = 2; - PUSH_SRETRACE(); *retrace_info->xp++ = '('; } else { ungetsc(c); @@ -650,7 +651,6 @@ yylex(int cf) if (statep->nparen == 1) { /* end of EXPRSUB */ POP_SRETRACE(); - POP_STATE(); if ((c2 = getsc()) == /*(*/ ')') { cz = strlen(sp) - 2; @@ -833,8 +833,7 @@ yylex(int cf) } else if (c2 == '"') { /* FALLTHROUGH */ case '"': - state = statep->type = SHEREDQUOTE; - PUSH_SRETRACE(); + PUSH_SRETRACE(SHEREDQUOTE); break; } ungetsc(c2); @@ -1440,6 +1439,7 @@ getsc_line(Source *s) alarm(0); } cp = Xstring(s->xs, xp); + rndpush(cp); s->start = s->str = cp; strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp)); /* Note: if input is all nulls, this is not eof */ @@ -1521,9 +1521,10 @@ set_prompt(int to, Source *s) int pprompt(const char *cp, int ntruncate) { - int columns = 0, lines = 0; - bool indelimit = false; char delimiter = 0; + bool doprint = (ntruncate != -1); + bool indelimit = false; + int columns = 0, lines = 0; /* * Undocumented AT&T ksh feature: @@ -1552,18 +1553,19 @@ pprompt(const char *cp, int ntruncate) else if (UTFMODE && ((unsigned char)*cp > 0x7F)) { const char *cp2; columns += utf_widthadj(cp, &cp2); - if (indelimit || - (ntruncate < (x_cols * lines + columns))) + if (doprint && (indelimit || + (ntruncate < (x_cols * lines + columns)))) shf_write(cp, cp2 - cp, shl_out); cp = cp2 - /* loop increment */ 1; continue; } else columns++; - if ((*cp != delimiter) && + if (doprint && (*cp != delimiter) && (indelimit || (ntruncate < (x_cols * lines + columns)))) shf_putc(*cp, shl_out); } - shf_flush(shl_out); + if (doprint) + shf_flush(shl_out); return (x_cols * lines + columns); } diff --git a/src/main.c b/src/main.c index 291ab40..cc49349 100644 --- a/src/main.c +++ b/src/main.c @@ -1,11 +1,11 @@ -/* $OpenBSD: main.c,v 1.52 2013/06/15 17:25:19 millert Exp $ */ +/* $OpenBSD: main.c,v 1.54 2013/11/28 10:33:37 sobrado Exp $ */ /* $OpenBSD: tty.c,v 1.9 2006/03/14 22:08:01 deraadt Exp $ */ -/* $OpenBSD: io.c,v 1.22 2006/03/17 16:30:13 millert Exp $ */ +/* $OpenBSD: io.c,v 1.23 2013/12/17 16:37:06 deraadt Exp $ */ /* $OpenBSD: table.c,v 1.15 2012/02/19 07:52:30 otto Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013 + * 2011, 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -34,7 +34,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/main.c,v 1.269 2013/07/25 18:07:46 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/main.c,v 1.280 2014/06/09 12:28:17 tg Exp $"); extern char **environ; @@ -48,7 +48,6 @@ extern char **environ; static uint8_t isuc(const char *); static int main_init(int, const char *[], Source **, struct block **); -uint32_t chvt_rndsetup(const void *, size_t); void chvt_reinit(void); static void reclaim(void); static void remove_temps(struct temp *); @@ -76,7 +75,6 @@ static const char *initcoms[] = { /* not in Android for political reasons */ /* not in ARGE mksh due to no job control */ "stop=kill -STOP", - "suspend=kill -STOP $$", #endif "autoload=typeset -fu", "functions=typeset -f", @@ -144,21 +142,6 @@ rndsetup(void) return ((mksh_uari_t)h); } -uint32_t -chvt_rndsetup(const void *bp, size_t sz) -{ - register uint32_t h; - - NZATInit(h); - /* variation through pid, ppid, and the works */ - NZATUpdateMem(h, &rndsetupstate, sizeof(rndsetupstate)); - /* some variation, some possibly entropy, depending on OE */ - NZATUpdateMem(h, bp, sz); - NZAATFinish(h); - - return (h); -} - void chvt_reinit(void) { @@ -247,6 +230,23 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) if (!*ccp) ccp = empty_argv[0]; + /* + * Turn on nohup by default. (AT&T ksh does not have a nohup + * option - it always sends the hup). + */ + Flag(FNOHUP) = 1; + + /* + * Turn on brace expansion by default. AT&T kshs that have + * alternation always have it on. + */ + Flag(FBRACEEXPAND) = 1; + + /* + * Turn on "set -x" inheritance by default. + */ + Flag(FXTRACEREC) = 1; + /* define built-in commands and see if we were called as one */ ktinit(APERM, &builtins, /* currently up to 51 builtins: 75% of 128 = 2^7 */ @@ -329,25 +329,6 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) /* setstr can't fail here */ setstr(vp, def_path, KSH_RETURN_ERROR); - /* - * Turn on nohup by default for now - will change to off - * by default once people are aware of its existence - * (AT&T ksh does not have a nohup option - it always sends - * the hup). - */ - Flag(FNOHUP) = 1; - - /* - * Turn on brace expansion by default. AT&T kshs that have - * alternation always have it on. - */ - Flag(FBRACEEXPAND) = 1; - - /* - * Turn on "set -x" inheritance by default. - */ - Flag(FXTRACEREC) = 1; - #ifndef MKSH_NO_CMDLINE_EDITING /* * Set edit mode to emacs by default, may be overridden @@ -361,9 +342,14 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) #endif /* import environment */ - if (environ != NULL) - for (wp = (const char **)environ; *wp != NULL; wp++) + if (environ != NULL) { + wp = (const char **)environ; + while (*wp != NULL) { + rndpush(*wp); typeset(*wp, IMPORT | EXPORT, 0, 0, 0); + ++wp; + } + } /* for security */ typeset(initifs, 0, 0, 0, 0); @@ -421,7 +407,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) setint_n((vp_pipest = global("PIPESTATUS")), 0, 10); /* Set this before parsing arguments */ - Flag(FPRIVILEGED) = kshuid != ksheuid || kshgid != kshegid; + Flag(FPRIVILEGED) = (kshuid != ksheuid || kshgid != kshegid) ? 2 : 0; /* this to note if monitor is set on command line (see below) */ #ifndef MKSH_UNEMPLOYED @@ -436,44 +422,6 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) return (1); } -#if defined(DEBUG) && !defined(MKSH_LEGACY_MODE) - /* test wraparound of arithmetic types */ - { - volatile long xl; - volatile unsigned long xul; - volatile int xi; - volatile unsigned int xui; - volatile mksh_ari_t xa; - volatile mksh_uari_t xua, xua2; - volatile uint8_t xc; - - xa = 2147483647; - xua = 2147483647; - ++xa; - ++xua; - xua2 = xa; - xl = xa; - xul = xua; - xa = 0; - xua = 0; - --xa; - --xua; - xi = xa; - xui = xua; - xa = -1; - xua = xa; - ++xa; - ++xua; - xc = 0; - --xc; - if ((xua2 != 2147483648UL) || - (xl != (-2147483647L-1)) || (xul != 2147483648UL) || - (xi != -1) || (xui != 4294967295U) || - (xa != 0) || (xua != 0) || (xc != 255)) - errorf("integer wraparound test failed"); - } -#endif - /* process this later only, default to off (hysterical raisins) */ utf_flag = UTFMODE; UTFMODE = 0; @@ -485,7 +433,6 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) s = pushs(SSTRINGCMDLINE, ATEMP); if (!(s->start = s->str = argv[argi++])) errorf("%s %s", "-c", "requires an argument"); -#if !defined(MKSH_SMALL) while (*s->str) { if (*s->str != ' ' && ctype(*s->str, C_QUOTE)) break; @@ -494,7 +441,6 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) if (!*s->str) s->flags |= SF_MAYEXEC; s->str = s->start; -#endif #ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT /* compatibility to MidnightBSD 0.1 /bin/sh (kludge) */ if (Flag(FSH) && argv[argi] && !strcmp(argv[argi], "--")) @@ -543,12 +489,14 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) #ifndef MKSH_ASSUME_UTF8 /* auto-detect from locale or environment */ utf_flag = 4; -#elif MKSH_ASSUME_UTF8 +#else /* this may not be an #elif */ +#if MKSH_ASSUME_UTF8 utf_flag = 1; #else /* always disable UTF-8 (for interactive) */ utf_flag = 0; #endif +#endif } #ifndef MKSH_NO_CMDLINE_EDITING x_init(); @@ -637,22 +585,22 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp) if (!current_wd[0] && Flag(FTALKING)) warningf(false, "can't determine current directory"); - if (Flag(FLOGIN)) { + if (Flag(FLOGIN)) include(MKSH_SYSTEM_PROFILE, 0, NULL, true); - if (!Flag(FPRIVILEGED)) - include(substitute("$HOME/.profile", 0), 0, - NULL, true); - } - if (Flag(FPRIVILEGED)) + if (!Flag(FPRIVILEGED)) { + if (Flag(FLOGIN)) + include(substitute("$HOME/.profile", 0), 0, NULL, true); + if (Flag(FTALKING)) { + cp = substitute(substitute("${ENV:-" MKSHRC_PATH "}", + 0), DOTILDE); + if (cp[0] != '\0') + include(cp, 0, NULL, true); + } + } else { include(MKSH_SUID_PROFILE, 0, NULL, true); - else if (Flag(FTALKING)) { - char *env_file; - - /* include $ENV */ - env_file = substitute(substitute("${ENV:-" MKSHRC_PATH "}", 0), - DOTILDE); - if (*env_file != '\0') - include(env_file, 0, NULL, true); + /* turn off -p if not set explicitly */ + if (Flag(FPRIVILEGED) != 1) + change_flag(FPRIVILEGED, OF_INTERNAL, false); } if (restricted) { @@ -873,11 +821,8 @@ shell(Source * volatile s, volatile bool toplevel) unwind(LEXIT); break; } - } -#if !defined(MKSH_SMALL) - else if ((s->flags & SF_MAYEXEC) && t->type == TCOM) + } else if ((s->flags & SF_MAYEXEC) && t->type == TCOM) t->u.evalflags |= DOTCOMEXEC; -#endif if (!Flag(FNOEXEC) || (s->flags & SF_TTY)) exstat = execute(t, 0, NULL) & 0xFF; @@ -1659,7 +1604,8 @@ maketemp(Area *ap, Temp_type type, struct temp **tlist) } while (len < 5); /* cyclically attempt to open a temporary file */ - while ((i = open(tp->tffn, O_CREAT | O_EXCL | O_RDWR, 0600)) < 0) { + while ((i = open(tp->tffn, O_CREAT | O_EXCL | O_RDWR | O_BINARY, + 0600)) < 0) { if (errno != EEXIST) goto maketemp_out; /* count down from z to a then from 9 to 0 */ @@ -1921,9 +1867,10 @@ x_mkraw(int fd, mksh_ttyst *ocb, bool forread) cb = *ocb; if (forread) { + cb.c_iflag &= ~(ISTRIP); cb.c_lflag &= ~(ICANON) | ECHO; } else { - cb.c_iflag &= ~(INLCR | ICRNL); + cb.c_iflag &= ~(INLCR | ICRNL | ISTRIP); cb.c_lflag &= ~(ISIG | ICANON | ECHO); } #if defined(VLNEXT) && defined(_POSIX_VDISABLE) diff --git a/src/mirhash.h b/src/mirhash.h new file mode 100644 index 0000000..481aac0 --- /dev/null +++ b/src/mirhash.h @@ -0,0 +1,218 @@ +/*- + * Copyright © 2011, 2014 + * Thorsten Glaser + * + * 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. + *- + * This file provides BAFH (Better Avalanche for the Jenkins Hash) as + * inline macro bodies that operate on “register uint32_t” variables, + * with variants that use their local intermediate registers. + * + * Usage note for BAFH with entropy distribution: input up to 4 bytes + * is best combined into a 32-bit unsigned integer, which is then run + * through BAFHFinish_reg for mixing and then used as context instead + * of 0. Longer input should be handled the same: take the first four + * bytes as IV after mixing then add subsequent bytes the same way. + * This needs counting input bytes and is endian-dependent, thus not, + * for speed reasons, specified for the regular stable hash, but very + * much recommended if the actual output value may differ across runs + * (so is using a random value instead of 0 for the IV). + */ + +#ifndef SYSKERN_MIRHASH_H +#define SYSKERN_MIRHASH_H 1 +#define SYSKERN_MIRHASH_BAFH + +#include + +__RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.2 2014/06/29 11:48:05 tg Exp $"); + +/*- + * BAFH itself is defined by the following primitives: + * + * • BAFHInit(ctx) initialises the hash context, which consists of a + * sole 32-bit unsigned integer (ideally in a register), to 0. + * It is possible to use any initial value out of [0; 2³²[ – which + * is, in fact, recommended if using BAFH for entropy distribution + * – but for a regular stable hash, the IV 0 is needed. + * + * • BAFHUpdateOctet(ctx,val) compresses the unsigned 8-bit quantity + * into the hash context. The algorithm used is Jenkins’ one-at-a- + * time, except that an additional constant 1 is added so that, if + * the context is (still) zero, adding a NUL byte is not ignored. + * + * • BAFHror(eax,cl) evaluates to the unsigned 32-bit integer “eax”, + * rotated right by “cl” ∈ [0;31]; no casting, be careful! + * + * • BAFHFinish(ctx) avalanches the context around so every sub-byte + * depends on all input octets; afterwards, the context variable’s + * value is the hash output. BAFH does not use any padding, nor is + * the input length added; this is due to the common use case (for + * quick entropy distribution and use with a hashtable). + * Warning: BAFHFinish uses the MixColumn algorithm of AES – which + * is reversible (to avoid introducing funnels and reducing entro‐ + * py), so blinding may need to be employed for some uses, e.g. in + * mksh, after a fork. + * + * The BAFHUpdateOctet and BAFHFinish are available in two flavours: + * suffixed with _reg (assumes the context is in a register) or _mem + * (which doesn’t). + * + * The following high-level macros (with _reg and _mem variants) are + * available: + * + * • BAFHUpdateMem(ctx,buf,len) adds a memory block to a context. + * • BAFHUpdateStr(ctx,buf) is equivalent to using len=strlen(buf). + * • BAFHHostMem(ctx,buf,len) calculates the hash of the memory buf‐ + * fer using the first 4 octets (mixed) for IV, as outlined above; + * the result is endian-dependent; “ctx” assumed to be a register. + * • BAFHHostStr(ctx,buf) does the same for C strings. + * + * All macros may use ctx multiple times in their expansion, but all + * other arguments are always evaluated at most once. + * + * To stay portable, never use the BAFHHost*() macros (these are for + * host-local entropy shuffling), and encode numbers using ULEB128. + */ + +#define BAFHInit(h) do { \ + (h) = 0; \ +} while (/* CONSTCOND */ 0) + +#define BAFHUpdateOctet_reg(h,b) do { \ + (h) += (uint8_t)(b); \ + ++(h); \ + (h) += (h) << 10; \ + (h) ^= (h) >> 6; \ +} while (/* CONSTCOND */ 0) + +#define BAFHUpdateOctet_mem(m,b) do { \ + register uint32_t BAFH_h = (m); \ + \ + BAFHUpdateOctet_reg(BAFH_h, (b)); \ + (m) = BAFH_h; \ +} while (/* CONSTCOND */ 0) + +#define BAFHror(eax,cl) (((eax) >> (cl)) | ((eax) << (32 - (cl)))) + +#define BAFHFinish_reg(h) do { \ + register uint32_t BAFHFinish_v; \ + \ + BAFHFinish_v = ((h) >> 7) & 0x01010101U; \ + BAFHFinish_v += BAFHFinish_v << 1; \ + BAFHFinish_v += BAFHFinish_v << 3; \ + BAFHFinish_v ^= ((h) << 1) & 0xFEFEFEFEU; \ + \ + BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8); \ + BAFHFinish_v ^= ((h) = BAFHror((h), 8)); \ + BAFHFinish_v ^= ((h) = BAFHror((h), 8)); \ + (h) = BAFHror((h), 8) ^ BAFHFinish_v; \ +} while (/* CONSTCOND */ 0) + +#define BAFHFinish_mem(m) do { \ + register uint32_t BAFHFinish_v, BAFH_h = (m); \ + \ + BAFHFinish_v = (BAFH_h >> 7) & 0x01010101U; \ + BAFHFinish_v += BAFHFinish_v << 1; \ + BAFHFinish_v += BAFHFinish_v << 3; \ + BAFHFinish_v ^= (BAFH_h << 1) & 0xFEFEFEFEU; \ + \ + BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8); \ + BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8)); \ + BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8)); \ + (m) = BAFHror(BAFH_h, 8) ^ BAFHFinish_v; \ +} while (/* CONSTCOND */ 0) + +#define BAFHUpdateMem_reg(h,p,z) do { \ + register const uint8_t *BAFHUpdate_p; \ + register size_t BAFHUpdate_z = (z); \ + \ + BAFHUpdate_p = (const void *)(p); \ + while (BAFHUpdate_z--) \ + BAFHUpdateOctet_reg((h), *BAFHUpdate_p++); \ +} while (/* CONSTCOND */ 0) + +/* meh should have named them _r/m but that’s not valid C */ +#define BAFHUpdateMem_mem(m,p,z) do { \ + register uint32_t BAFH_h = (m); \ + \ + BAFHUpdateMem_reg(BAFH_h, (p), (z)); \ + (m) = BAFH_h; \ +} while (/* CONSTCOND */ 0) + +#define BAFHUpdateStr_reg(h,s) do { \ + register const uint8_t *BAFHUpdate_s; \ + register uint8_t BAFHUpdate_c; \ + \ + BAFHUpdate_s = (const void *)(s); \ + while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0) \ + BAFHUpdateOctet_reg((h), BAFHUpdate_c); \ +} while (/* CONSTCOND */ 0) + +#define BAFHUpdateStr_mem(m,s) do { \ + register uint32_t BAFH_h = (m); \ + \ + BAFHUpdateStr_reg(BAFH_h, (s)); \ + (m) = BAFH_h; \ +} while (/* CONSTCOND */ 0) + +#define BAFHHostMem(h,p,z) do { \ + register const uint8_t *BAFHUpdate_p; \ + register size_t BAFHUpdate_z = (z); \ + size_t BAFHHost_z; \ + union { \ + uint8_t as_u8[4]; \ + uint32_t as_u32; \ + } BAFHHost_v; \ + \ + BAFHUpdate_p = (const void *)(p); \ + BAFHHost_v.as_u32 = 0; \ + BAFHHost_z = BAFHUpdate_z < 4 ? BAFHUpdate_z : 4; \ + memcpy(BAFHHost_v.as_u8, BAFHUpdate_p, BAFHHost_z); \ + BAFHUpdate_p += BAFHHost_z; \ + BAFHUpdate_z -= BAFHHost_z; \ + (h) = BAFHHost_v.as_u32; \ + BAFHFinish_reg(h); \ + while (BAFHUpdate_z--) \ + BAFHUpdateOctet_reg((h), *BAFHUpdate_p++); \ + BAFHFinish_reg(h); \ +} while (/* CONSTCOND */ 0) + +#define BAFHHostStr(h,s) do { \ + register const uint8_t *BAFHUpdate_s; \ + register uint8_t BAFHUpdate_c; \ + union { \ + uint8_t as_u8[4]; \ + uint32_t as_u32; \ + } BAFHHost_v; \ + \ + BAFHUpdate_s = (const void *)(s); \ + if ((BAFHHost_v.as_u8[0] = *BAFHUpdate_s) != 0) \ + ++BAFHUpdate_s; \ + if ((BAFHHost_v.as_u8[1] = *BAFHUpdate_s) != 0) \ + ++BAFHUpdate_s; \ + if ((BAFHHost_v.as_u8[2] = *BAFHUpdate_s) != 0) \ + ++BAFHUpdate_s; \ + if ((BAFHHost_v.as_u8[3] = *BAFHUpdate_s) != 0) \ + ++BAFHUpdate_s; \ + (h) = BAFHHost_v.as_u32; \ + BAFHFinish_reg(h); \ + while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0) \ + BAFHUpdateOctet_reg((h), BAFHUpdate_c); \ + BAFHFinish_reg(h); \ +} while (/* CONSTCOND */ 0) + +#endif diff --git a/src/misc.c b/src/misc.c index adf4bc4..82d47d6 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1,9 +1,9 @@ -/* $OpenBSD: misc.c,v 1.37 2009/04/19 20:34:05 sthen Exp $ */ +/* $OpenBSD: misc.c,v 1.38 2013/11/28 10:33:37 sobrado Exp $ */ /* $OpenBSD: path.c,v 1.12 2005/03/30 17:16:37 deraadt Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013 + * 2011, 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -30,7 +30,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.214 2013/08/11 14:57:09 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.219 2014/01/05 21:57:27 tg Exp $"); #define KSH_CHVT_FLAG #ifdef MKSH_SMALL @@ -49,10 +49,11 @@ __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.214 2013/08/11 14:57:09 tg Exp $"); unsigned char chtypes[UCHAR_MAX + 1]; static const unsigned char *pat_scan(const unsigned char *, - const unsigned char *, bool); + const unsigned char *, bool) MKSH_A_PURE; static int do_gmatch(const unsigned char *, const unsigned char *, - const unsigned char *, const unsigned char *); -static const unsigned char *cclass(const unsigned char *, unsigned char); + const unsigned char *, const unsigned char *) MKSH_A_PURE; +static const unsigned char *cclass(const unsigned char *, unsigned char) + MKSH_A_PURE; #ifdef KSH_CHVT_CODE static void chvt(const Getopt *); #endif @@ -125,7 +126,7 @@ Xcheck_grow(XString *xsp, const char *xp, size_t more) #define SHFLAGS_DEFNS -#include "sh_flags.h" +#include "sh_flags.gen" #define OFC(i) (options[i][-2]) #define OFF(i) (((const unsigned char *)options[i])[-1]) @@ -133,7 +134,7 @@ Xcheck_grow(XString *xsp, const char *xp, size_t more) const char * const options[] = { #define SHFLAGS_ITEMS -#include "sh_flags.h" +#include "sh_flags.gen" }; /* @@ -271,6 +272,7 @@ change_flag(enum sh_flag f, int what, bool newset) /*XXX this can probably be optimised */ kshegid = kshgid = getgid(); + ksheuid = kshuid = getuid(); #if HAVE_SETRESUGID DO_SETUID(setresgid, (kshegid, kshegid, kshegid)); #if HAVE_SETGROUPS @@ -278,9 +280,8 @@ change_flag(enum sh_flag f, int what, bool newset) setgroups(1, &kshegid); #endif DO_SETUID(setresuid, (ksheuid, ksheuid, ksheuid)); -#else +#else /* !HAVE_SETRESUGID */ /* seteuid, setegid, setgid don't EAGAIN on Linux */ - ksheuid = kshuid = getuid(); #ifndef MKSH__NO_SETEUGID seteuid(ksheuid); #endif @@ -289,7 +290,7 @@ change_flag(enum sh_flag f, int what, bool newset) setegid(kshegid); #endif setgid(kshegid); -#endif +#endif /* !HAVE_SETRESUGID */ } else if ((f == FPOSIX || f == FSH) && newval) { /* Turning on -o posix or -o sh? */ Flag(FBRACEEXPAND) = 0; @@ -341,10 +342,20 @@ parse_args(const char **argv, int what, bool *setargsp) { - static char cmd_opts[NELEM(options) + 5]; /* o:T:\0 */ - static char set_opts[NELEM(options) + 6]; /* A:o;s\0 */ + static const char cmd_opts[] = +#define SHFLAGS_NOT_SET +#define SHFLAGS_OPTCS +#include "sh_flags.gen" +#undef SHFLAGS_NOT_SET + ; + static const char set_opts[] = +#define SHFLAGS_NOT_CMD +#define SHFLAGS_OPTCS +#include "sh_flags.gen" +#undef SHFLAGS_NOT_CMD + ; bool set; - char *opts; + const char *opts; const char *array = NULL; Getopt go; size_t i; @@ -352,36 +363,6 @@ parse_args(const char **argv, bool sortargs = false; bool fcompatseen = false; - /* First call? Build option strings... */ - if (cmd_opts[0] == '\0') { - char ch, *p = cmd_opts, *q = set_opts; - - /* see cmd_opts[] declaration */ - *p++ = 'o'; - *p++ = ':'; -#ifdef KSH_CHVT_FLAG - *p++ = 'T'; - *p++ = ':'; -#endif - /* see set_opts[] declaration */ - *q++ = 'A'; - *q++ = ':'; - *q++ = 'o'; - *q++ = ';'; - *q++ = 's'; - - for (i = 0; i < NELEM(options); i++) { - if ((ch = OFC(i))) { - if (OFF(i) & OF_CMDLINE) - *p++ = ch; - if (OFF(i) & OF_SET) - *q++ = ch; - } - } - *p = '\0'; - *q = '\0'; - } - if (what == OF_CMDLINE) { const char *p = argv[0], *q; /* @@ -1972,7 +1953,6 @@ c_cd(const char **wp) #ifdef KSH_CHVT_CODE -extern uint32_t chvt_rndsetup(const void *, size_t); extern void chvt_reinit(void); static void @@ -2016,9 +1996,9 @@ chvt(const Getopt *go) #endif } } - if ((fd = open(dv, O_RDWR)) < 0) { + if ((fd = open(dv, O_RDWR | O_BINARY)) < 0) { sleep(1); - if ((fd = open(dv, O_RDWR)) < 0) { + if ((fd = open(dv, O_RDWR | O_BINARY)) < 0) { errorf("%s: %s %s", "chvt", "can't open", dv); } } diff --git a/src/mksh.1 b/src/mksh.1 index 621aa97..19291ce 100644 --- a/src/mksh.1 +++ b/src/mksh.1 @@ -1,8 +1,8 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.320 2013/08/10 14:11:39 tg Exp $ -.\" $OpenBSD: ksh.1,v 1.147 2013/06/13 19:43:09 millert Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.336 2014/06/24 20:47:44 tg Exp $ +.\" $OpenBSD: ksh.1,v 1.152 2014/02/12 16:28:13 schwarze Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, -.\" 2010, 2011, 2012, 2013 +.\" 2010, 2011, 2012, 2013, 2014 .\" Thorsten Glaser .\" .\" Provided that these terms and disclaimer and all copyright notices @@ -74,7 +74,7 @@ .\" with -mandoc, it might implement .Mx itself, but we want to .\" use our own definition. And .Dd must come *first*, always. .\" -.Dd $Mdocdate: August 10 2013 $ +.Dd $Mdocdate: June 24 2014 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" @@ -247,8 +247,7 @@ below. Privileged shell. A shell is .Dq privileged -if this option is used -or if the real user ID or group ID does not match the +if the real user ID or group ID does not match the effective user ID or group ID (see .Xr getuid 2 and @@ -257,6 +256,9 @@ Clearing the privileged option causes the shell to set its effective user ID (group ID) to its real user ID (group ID). For further implications, see .Sx Startup files . +If the shell is privileged and this flag is not explicitly set, the +.Dq privileged +option is cleared automatically after processing the startup files. .It Fl r Restricted shell. A shell is @@ -366,6 +368,9 @@ parameter after subjecting it to parameter, command, arithmetic and tilde substitution; if unset or empty, the user mkshrc profile is processed; otherwise, if a file whose name is the substitution result exists, it is processed; non-existence is silently ignored. +A privileged shell then drops privileges if neither was the +.Fl p +option given on the command line nor set during execution of the startup files. .Ss Command syntax The shell begins parsing its input by removing any backslash-newline combinations, then breaking it into @@ -955,7 +960,7 @@ The second operand of the .Sq != and .Sq = -expressions are patterns (e.g. the comparison +expressions are a subset of patterns (e.g. the comparison .Ic \&[[ foobar = f*r ]] succeeds). This even works indirectly: @@ -967,6 +972,7 @@ $ [[ $bar = \&"$baz" ]]; echo $? .Pp Perhaps surprisingly, the first comparison succeeds, whereas the second doesn't. +This does not apply to all extglob metacharacters, currently. .El .El .Ss Quoting @@ -1123,7 +1129,6 @@ nameref=\*(aqtypeset \-n\*(aq nohup=\*(aqnohup \*(aq r=\*(aqfc \-e \-\*(aq stop=\*(aqkill \-STOP\*(aq -suspend=\*(aqkill \-STOP $$\*(aq type=\*(aqwhence \-v\*(aq .Ed .Pp @@ -1685,17 +1690,10 @@ Currently, must start with a space, opening parenthesis or digit to be recognised. Cannot be applied to a vector. .Pp -.It Xo -.Pf ${ Ar name -.Pf @# Ns Oo Ar seed Oc Ns } -.Xc -The internal hash of the expansion of -.Ar name , -with an optional (defaulting to zero) -.Op Ar seed . -At the moment, this is NZAAT (a 32-bit hash based on -Bob Jenkins' one-at-a-time hash), but this is not set. -This is the hash the shell uses internally for its associative arrays. +.It Pf ${ Ns Ar name Ns @#} +The hash (using the BAFH algorithm) of the expansion of +.Ar name . +This is also used internally for the shell's hashtables. .Pp .It Pf ${ Ns Ar name Ns @Q} A quoted expression safe for re-entry, whose value is the value of the @@ -2037,7 +2035,7 @@ in reverse video in the prompt string: .Bd -literal -offset indent x=$(print \e\e001) -PS1="$x$(print \e\er)$x$(tput smso)$x\e$PWD$x$(tput rmso)$x\*(Gt " +PS1="$x$(print \e\er)$x$(tput so)$x\e$PWD$x$(tput se)$x\*(Gt " .Ed .Pp Due to a strong suggestion from David G. Korn, @@ -2592,7 +2590,7 @@ in all forms of arithmetic expressions, except as numeric arguments to the built-in command. Prefixing numbers with a sole digit zero .Pq Sq 0 -leads to the shell interpreting it as base-8 integer in +leads to the shell interpreting it as base-8 (octal) integer in .Ic posix mode .Em only ; @@ -2953,8 +2951,9 @@ Builtins that are not special: .Ic false , fc , fg , getopts , .Ic jobs , kill , let , mknod , .Ic print , pwd , read , realpath , -.Ic rename , sleep , test , true , -.Ic ulimit , umask , unalias , whence +.Ic rename , sleep , suspend , test , +.Ic true , ulimit , umask , unalias , +.Ic whence .Pp Once the type of command has been determined, any command-line parameter assignments are performed and exported for the duration of the command. @@ -3411,6 +3410,7 @@ and .Ar last select commands from the history. Commands can be selected by history number +(negative numbers go backwards from the current, most recent, line) or a string specifying the most recent command starting with that string. The .Fl l @@ -3623,7 +3623,7 @@ Since expressions may need to be quoted, is syntactic sugar for .No let \&" Ns Ar expr Ns \&" . .Pp -.It let] +.It Ic let] Internally used alias for .Ic let . .Pp @@ -4036,6 +4036,12 @@ Only used if job control is enabled .It Fl C \*(Ba Fl o Ic noclobber Prevent \*(Gt redirection from overwriting existing files. Instead, \*(Gt\*(Ba must be used to force an overwrite. +Note that this is not safe to use for creation of temporary files or +lockfiles due to a TOCTOU in a check allowing one to redirect output to +.Pa /dev/null +or other device files even in +.Ic noclobber +mode. .It Fl e \*(Ba Fl o Ic errexit Exit (after executing the .Dv ERR @@ -4242,6 +4248,9 @@ mode. Enable .Xr vi 1 Ns -like command-line editing (interactive shells only). +See +.Sx Vi editing mode +for documentation and limitations. .It Fl o Ic vi\-esccomplete In vi command-line editing, do command and file name completion when escape (\*(ha[) is entered in command mode. @@ -4315,6 +4324,16 @@ and .Nm mksh , this is implemented as a shell alias instead of a builtin. .Pp +.It Ic suspend +Stops the shell as if it had received the suspend character from +the terminal. +It is not possible to suspend a login shell unless the parent process +is a member of the same terminal session but is a member of a different +process group. +As a general rule, if the shell was started by another shell or via +.Xr su 1 , +it can be suspended. +.Pp .It Ic test Ar expression .It Ic \&[ Ar expression Ic \&] .Ic test @@ -4878,7 +4897,7 @@ unless they are also given on the same command line. .Pp .It Xo .Ic ulimit -.Op Fl aBCcdefHiLlMmnOPpqrSsTtVvw +.Op Fl aBCcdefHilMmnOPpqrSsTtVvw .Op Ar value .Xc Display or set process limits. @@ -4929,8 +4948,6 @@ Set the hard limit only (the default is to set both hard and soft limits). .It Fl i Ar n Set the number of pending signals to .Ar n . -.It Fl L Ar n -Control flocks; documentation is missing. .It Fl l Ar n Impose a limit of .Ar n @@ -5673,6 +5690,7 @@ replaces the inserted text string with the next previously killed text string. .Ss Vi editing mode .Em Note: The vi command-line editing mode is orphaned, yet still functional. +It is 8-bit clean but specifically does not support UTF-8 or MBCS. .Pp The vi command-line editor in .Nm @@ -6307,15 +6325,15 @@ contains the system and suid profile. .%A Stephen G. Kochan .%A Patrick H. Wood .%B "\\*(tNUNIX\\*(sP Shell Programming" -.%V "Revised Edition" -.%D 1990 -.%I "Hayden" -.%P "xi\ +\ 490 pages" -.%O "ISBN 978\-0\-672\-48448\-3 (0\-672\-48448\-X)" +.%V "3rd Edition" +.%D 2003 +.%I "Sams" +.%P "xiii\ +\ 437 pages" +.%O "ISBN 978\-0\-672\-32490\-1 (0\-672\-32490\-3)" .Re .Rs .%A "IEEE Inc." -.%B "\\*(tNIEEE\\*(sP Standard for Information Technology \*(en Portable Operating System Interface (POSIX)" +.%T "\\*(tNIEEE\\*(sP Standard for Information Technology \*(en Portable Operating System Interface (POSIX)" .%V "Part 2: Shell and Utilities" .%D 1993 .%I "IEEE Press" @@ -6348,24 +6366,35 @@ contains the system and suid profile. .%O "ISBN 978\-0\-201\-56324\-5 (0\-201\-56324\-X)" .Re .Sh AUTHORS +.An -nosplit .Nm "The MirBSD Korn Shell" is developed by .An Thorsten Glaser Aq tg@mirbsd.org and currently maintained as part of The MirOS Project. -This shell is based upon the Public Domain Korn SHell. -The developer of mksh recognises the efforts of the pdksh authors, -who had dedicated their work into Public Domain, our users, and -all contributors, such as the Debian and OpenBSD projects. -.\" -.\" Charles Forsyth, author of the (Public Domain) Bourne Shell clone, -.\" which mksh is derived from, agreed to the following: -.\" -.\" In countries where the Public Domain status of the work may not be -.\" valid, its primary author hereby grants a copyright licence to the -.\" general public to deal in the work without restriction and permis- -.\" sion to sublicence derivates under the terms of any (OSI approved) -.\" Open Source licence. -.\" +This shell is based on the public domain 7th edition Bourne shell clone by +.An Charles Forsyth , +who kindly agreed to, in countries where the Public Domain status of the work +may not be valid, grant a copyright licence to the general public to deal in +the work without restriction and permission to sublicence derivates under the +terms of any (OSI approved) Open Source licence, +and parts of the BRL shell by +.An Doug A. Gwyn , +.An Doug Kingston , +.An Ron Natalie , +.An Arnold Robbins , +.An Lou Salkind , +and others. +The first release of +.Nm pdksh +was created by +.An Eric Gisin , +and it was subsequently maintained by +.An John R. MacMillan Aq Mt change!john@sq.sq.com , +.An Simon J. Gerraty Aq Mt sjg@zen.void.oz.au , +and +.An Michael Rendell Aq Mt michael@cs.mun.ca . +The effort of several projects, such as Debian and OpenBSD, and other +contributors including our users, to improve the shell is appreciated. See the documentation, CVS, and web site for details. .Pp The BSD daemon is Copyright \(co Marshall Kirk McKusick. @@ -6425,7 +6454,7 @@ $ /bin/sleep 666 && echo fubar .Ed .Pp This document attempts to describe -.Nm mksh\ R48 +.Nm mksh\ R50 and up, compiled without any options impacting functionality, such as .Dv MKSH_SMALL , diff --git a/src/rlimits.gen b/src/rlimits.gen new file mode 100644 index 0000000..ef71dab --- /dev/null +++ b/src/rlimits.gen @@ -0,0 +1,174 @@ +#ifndef RLIMITS_OPTCS +#if defined(RLIMITS_DEFNS) +__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.1 2013/11/17 22:21:18 tg Exp $"); +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 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 }; +#elif defined(RLIMITS_ITEMS) +#define FN(lname,lid,lfac,lopt) (const struct limits *)(&rlimits_ ## lid), +#endif +#ifndef F0 +#define F0 FN +#endif +#ifdef RLIMIT_CPU +FN("time(cpu-seconds)", RLIMIT_CPU, 1, 't') +#endif +#ifdef RLIMIT_FSIZE +FN("file(blocks)", RLIMIT_FSIZE, 512, 'f') +#endif +#ifdef RLIMIT_CORE +FN("coredump(blocks)", RLIMIT_CORE, 512, 'c') +#endif +#ifdef RLIMIT_DATA +FN("data(KiB)", RLIMIT_DATA, 1024, 'd') +#endif +#ifdef RLIMIT_STACK +FN("stack(KiB)", RLIMIT_STACK, 1024, 's') +#endif +#ifdef RLIMIT_MEMLOCK +FN("lockedmem(KiB)", RLIMIT_MEMLOCK, 1024, 'l') +#endif +#ifdef RLIMIT_NOFILE +FN("nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n') +#endif +#ifdef RLIMIT_NPROC +FN("processes", RLIMIT_NPROC, 1, 'p') +#endif +#ifdef RLIMIT_SWAP +FN("swap(KiB)", RLIMIT_SWAP, 1024, 'w') +#endif +#ifdef RLIMIT_TIME +FN("humantime(seconds)", RLIMIT_TIME, 1, 'T') +#endif +#ifdef RLIMIT_NOVMON +FN("vnodemonitors", RLIMIT_NOVMON, 1, 'V') +#endif +#ifdef RLIMIT_SIGPENDING +FN("sigpending", RLIMIT_SIGPENDING, 1, 'i') +#endif +#ifdef RLIMIT_MSGQUEUE +FN("msgqueue(bytes)", RLIMIT_MSGQUEUE, 1, 'q') +#endif +#ifdef RLIMIT_AIO_MEM +FN("AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024, 'M') +#endif +#ifdef RLIMIT_AIO_OPS +FN("AIOoperations", RLIMIT_AIO_OPS, 1, 'O') +#endif +#ifdef RLIMIT_TCACHE +FN("cachedthreads", RLIMIT_TCACHE, 1, 'C') +#endif +#ifdef RLIMIT_SBSIZE +FN("sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024, 'B') +#endif +#ifdef RLIMIT_PTHREAD +FN("threadsperprocess", RLIMIT_PTHREAD, 1, 'P') +#endif +#ifdef RLIMIT_NICE +FN("maxnice", RLIMIT_NICE, 1, 'e') +#endif +#ifdef RLIMIT_RTPRIO +FN("maxrtprio", RLIMIT_RTPRIO, 1, 'r') +#endif +#ifdef ULIMIT_M_IS_RSS +FN("resident-set(KiB)", RLIMIT_RSS, 1024, 'm') +#endif +#ifdef ULIMIT_M_IS_VMEM +FN("memory(KiB)", RLIMIT_VMEM, 1024, 'm') +#endif +#ifdef ULIMIT_V_IS_VMEM +FN("virtual-memory(KiB)", RLIMIT_VMEM, 1024, 'v') +#endif +#ifdef ULIMIT_V_IS_AS +FN("address-space(KiB)", RLIMIT_AS, 1024, 'v') +#endif +#undef F0 +#undef FN +#undef RLIMITS_DEFNS +#undef RLIMITS_ITEMS +#else +"a" +#ifdef RLIMIT_SBSIZE +"B" +#endif +#ifdef RLIMIT_TCACHE +"C" +#endif +#ifdef RLIMIT_CORE +"c" +#endif +#ifdef RLIMIT_DATA +"d" +#endif +#ifdef RLIMIT_NICE +"e" +#endif +#ifdef RLIMIT_FSIZE +"f" +#endif +"H" +#ifdef RLIMIT_SIGPENDING +"i" +#endif +#ifdef RLIMIT_MEMLOCK +"l" +#endif +#ifdef RLIMIT_AIO_MEM +"M" +#endif +#ifdef ULIMIT_M_IS_RSS +"m" +#endif +#ifdef ULIMIT_M_IS_VMEM +"m" +#endif +#ifdef RLIMIT_NOFILE +"n" +#endif +#ifdef RLIMIT_AIO_OPS +"O" +#endif +#ifdef RLIMIT_PTHREAD +"P" +#endif +#ifdef RLIMIT_NPROC +"p" +#endif +#ifdef RLIMIT_MSGQUEUE +"q" +#endif +#ifdef RLIMIT_RTPRIO +"r" +#endif +"S" +#ifdef RLIMIT_STACK +"s" +#endif +#ifdef RLIMIT_TIME +"T" +#endif +#ifdef RLIMIT_CPU +"t" +#endif +#ifdef RLIMIT_NOVMON +"V" +#endif +#ifdef ULIMIT_V_IS_AS +"v" +#endif +#ifdef ULIMIT_V_IS_VMEM +"v" +#endif +#ifdef RLIMIT_SWAP +"w" +#endif +#undef RLIMITS_OPTCS +#endif diff --git a/src/rlimits.opt b/src/rlimits.opt new file mode 100644 index 0000000..6c3908b --- /dev/null +++ b/src/rlimits.opt @@ -0,0 +1,96 @@ +@RLIMITS_DEFNS +__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.1 2013/11/17 22:21:18 tg Exp $"); +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 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 }; +@RLIMITS_ITEMS +#define FN(lname,lid,lfac,lopt) (const struct limits *)(&rlimits_ ## lid), +@@ + +/* generic options for the ulimit builtin */ + +t|RLIMIT_CPU +FN("time(cpu-seconds)", RLIMIT_CPU, 1 + +>f|RLIMIT_FSIZE +FN("file(blocks)", RLIMIT_FSIZE, 512 + +>c|RLIMIT_CORE +FN("coredump(blocks)", RLIMIT_CORE, 512 + +>d|RLIMIT_DATA +FN("data(KiB)", RLIMIT_DATA, 1024 + +>s|RLIMIT_STACK +FN("stack(KiB)", RLIMIT_STACK, 1024 + +>l|RLIMIT_MEMLOCK +FN("lockedmem(KiB)", RLIMIT_MEMLOCK, 1024 + +>n|RLIMIT_NOFILE +FN("nofiles(descriptors)", RLIMIT_NOFILE, 1 + +>p|RLIMIT_NPROC +FN("processes", RLIMIT_NPROC, 1 + +>w|RLIMIT_SWAP +FN("swap(KiB)", RLIMIT_SWAP, 1024 + +>T|RLIMIT_TIME +FN("humantime(seconds)", RLIMIT_TIME, 1 + +>V|RLIMIT_NOVMON +FN("vnodemonitors", RLIMIT_NOVMON, 1 + +>i|RLIMIT_SIGPENDING +FN("sigpending", RLIMIT_SIGPENDING, 1 + +>q|RLIMIT_MSGQUEUE +FN("msgqueue(bytes)", RLIMIT_MSGQUEUE, 1 + +>M|RLIMIT_AIO_MEM +FN("AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024 + +>O|RLIMIT_AIO_OPS +FN("AIOoperations", RLIMIT_AIO_OPS, 1 + +>C|RLIMIT_TCACHE +FN("cachedthreads", RLIMIT_TCACHE, 1 + +>B|RLIMIT_SBSIZE +FN("sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024 + +>P|RLIMIT_PTHREAD +FN("threadsperprocess", RLIMIT_PTHREAD, 1 + +>e|RLIMIT_NICE +FN("maxnice", RLIMIT_NICE, 1 + +>r|RLIMIT_RTPRIO +FN("maxrtprio", RLIMIT_RTPRIO, 1 + +>m|ULIMIT_M_IS_RSS +FN("resident-set(KiB)", RLIMIT_RSS, 1024 +>m|ULIMIT_M_IS_VMEM +FN("memory(KiB)", RLIMIT_VMEM, 1024 + +>v|ULIMIT_V_IS_VMEM +FN("virtual-memory(KiB)", RLIMIT_VMEM, 1024 +>v|ULIMIT_V_IS_AS +FN("address-space(KiB)", RLIMIT_AS, 1024 + +|RLIMITS_OPTCS diff --git a/src/sh.h b/src/sh.h index 5a95190..be716ab 100644 --- a/src/sh.h +++ b/src/sh.h @@ -1,16 +1,16 @@ -/* $OpenBSD: sh.h,v 1.31 2012/09/10 01:25:30 tedu Exp $ */ +/* $OpenBSD: sh.h,v 1.33 2013/12/18 13:53:12 millert Exp $ */ /* $OpenBSD: shf.h,v 1.6 2005/12/11 18:53:51 deraadt Exp $ */ /* $OpenBSD: table.h,v 1.8 2012/02/19 07:52:30 otto Exp $ */ /* $OpenBSD: tree.h,v 1.10 2005/03/28 21:28:22 deraadt Exp $ */ /* $OpenBSD: expand.h,v 1.6 2005/03/30 17:16:37 deraadt Exp $ */ /* $OpenBSD: lex.h,v 1.13 2013/03/03 19:11:34 guenther Exp $ */ -/* $OpenBSD: proto.h,v 1.34 2012/06/27 07:17:19 otto Exp $ */ +/* $OpenBSD: proto.h,v 1.35 2013/09/04 15:49:19 millert Exp $ */ /* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */ /* $OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $ */ /*- * Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013 + * 2011, 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -108,12 +108,12 @@ #undef __attribute__ #if HAVE_ATTRIBUTE_BOUNDED -#define MKSH_A_BOUNDED(x,y,z) __attribute__((__bounded__ (x, y, z))) +#define MKSH_A_BOUNDED(x,y,z) __attribute__((__bounded__(x, y, z))) #else #define MKSH_A_BOUNDED(x,y,z) /* nothing */ #endif #if HAVE_ATTRIBUTE_FORMAT -#define MKSH_A_FORMAT(x,y,z) __attribute__((__format__ (x, y, z))) +#define MKSH_A_FORMAT(x,y,z) __attribute__((__format__(x, y, z))) #else #define MKSH_A_FORMAT(x,y,z) /* nothing */ #endif @@ -122,6 +122,11 @@ #else #define MKSH_A_NORETURN /* nothing */ #endif +#if HAVE_ATTRIBUTE_PURE +#define MKSH_A_PURE __attribute__((__pure__)) +#else +#define MKSH_A_PURE /* nothing */ +#endif #if HAVE_ATTRIBUTE_UNUSED #define MKSH_A_UNUSED __attribute__((__unused__)) #else @@ -164,9 +169,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.667 2013/08/14 20:26:19 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.691 2014/06/29 11:28:28 tg Exp $"); #endif -#define MKSH_VERSION "R48 2013/08/14" +#define MKSH_VERSION "R50 2014/06/29" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES @@ -298,7 +303,7 @@ struct rusage { #define ksh_isupper(c) (((c) >= 'A') && ((c) <= 'Z')) #define ksh_tolower(c) (((c) >= 'A') && ((c) <= 'Z') ? (c) - 'A' + 'a' : (c)) #define ksh_toupper(c) (((c) >= 'a') && ((c) <= 'z') ? (c) - 'a' + 'A' : (c)) -#define ksh_isdash(s) (((s) != NULL) && ((s)[0] == '-') && ((s)[1] == '\0')) +#define ksh_isdash(s) (((s)[0] == '-') && ((s)[1] == '\0')) #define ksh_isspace(c) ((((c) >= 0x09) && ((c) <= 0x0D)) || ((c) == 0x20)) #define ksh_min(x,y) ((x) < (y) ? (x) : (y)) #define ksh_max(x,y) ((x) > (y) ? (x) : (y)) @@ -337,7 +342,17 @@ struct rusage { #define NSIG (SIGMAX+1) #elif defined(_SIGMAX) #define NSIG (_SIGMAX+1) +#else +# error Please have your platform define NSIG. +#define NSIG 64 +#endif #endif + +/* get rid of this (and awk/printf(1) in Build.sh) later */ +#if (NSIG < 1) +# error Your NSIG value is not positive. +#unset NSIG +#define NSIG 64 #endif @@ -396,6 +411,10 @@ extern int __cdecl setegid(gid_t); #endif #endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + #ifdef MKSH__NO_SYMLINK #undef S_ISLNK #define S_ISLNK(m) (/* CONSTCOND */ 0) @@ -414,12 +433,8 @@ extern int __cdecl setegid(gid_t); #define mksh_tcset(fd,st) ioctl((fd), TCSETAW, (st)) #endif -/* remove redundancies */ - -#if defined(MirBSD) && (MirBSD >= 0x0AB3) && !defined(MKSH_OPTSTATIC) -#define MKSH_mirbsd_wcwidth -#define utf_wcwidth(i) wcwidth((__WCHAR_TYPE__)i) -extern int wcwidth(__WCHAR_TYPE__); +#ifndef ISTRIP +#define ISTRIP 0 #endif @@ -518,7 +533,7 @@ char *ucstrstr(char *, const char *); #define mkssert(e) do { } while (/* CONSTCOND */ 0) #endif -#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 481) +#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 501) #error Must run Build.sh to compile this. extern void thiswillneverbedefinedIhope(void); int @@ -660,7 +675,7 @@ EXTERN Area aperm; /* permanent object space */ */ enum sh_flag { #define SHFLAGS_ENUMS -#include "sh_flags.h" +#include "sh_flags.gen" FNFLAGS /* (place holder: how many flags are there) */ }; @@ -1163,11 +1178,11 @@ EXTERN struct tbl vtemp; #define arrayindex(vp) ((unsigned long)((vp)->flag & AINDEX ? \ (vp)->ua.index : 0)) -EXTERN enum { +enum namerefflag { SRF_NOP, SRF_ENABLE, SRF_DISABLE -} set_refflag E_INIT(SRF_NOP); +}; /* command types */ #define CNONE 0 /* undefined */ @@ -1380,22 +1395,7 @@ struct ioword { #define DOTEMP BIT(8) /* dito: in word part of ${..[%#=?]..} */ #define DOVACHECK BIT(9) /* var assign check (for typeset, set, etc) */ #define DOMARKDIRS BIT(10) /* force markdirs behaviour */ -#if !defined(MKSH_SMALL) #define DOTCOMEXEC BIT(11) /* not an eval flag, used by sh -c hack */ -#endif - -/* - * The arguments of [[ .. ]] expressions are kept in t->args[] and flags - * indicating how the arguments have been munged are kept in t->vars[]. - * The contents of t->vars[] are stuffed strings (so they can be treated - * like all other t->vars[]) in which the second character is the one that - * is examined. The DB_* defines are the values for these second characters. - */ -#define DB_NORM 1 /* normal argument */ -#define DB_OR 2 /* || -> -o conversion */ -#define DB_AND 3 /* && -> -a conversion */ -#define DB_BE 4 /* an inserted -BE */ -#define DB_PAT 5 /* a pattern argument */ #define X_EXTRA 20 /* this many extra bytes in X string */ @@ -1426,7 +1426,7 @@ typedef char *XStringP; #define XcheckN(xs, xp, n) do { \ ssize_t more = ((xp) + (n)) - (xs).end; \ if (more > 0) \ - (xp) = Xcheck_grow(&(xs), (xp), more); \ + (xp) = Xcheck_grow(&(xs), (xp), (size_t)more); \ } while (/* CONSTCOND */ 0) /* check for overflow, expand string */ @@ -1526,9 +1526,7 @@ struct source { #define SF_ALIASEND BIT(2) /* faking space at end of alias */ #define SF_TTY BIT(3) /* type == SSTDIN & it is a tty */ #define SF_HASALIAS BIT(4) /* u.tblp valid (SALIAS, SEOF) */ -#if !defined(MKSH_SMALL) #define SF_MAYEXEC BIT(5) /* special sh -c optimisation hack */ -#endif typedef union { int i; @@ -1587,6 +1585,7 @@ typedef union { #undef CTRL #define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */ #define UNCTRL(x) ((x) ^ 0x40) /* ASCII */ +#define ISCTRL(x) (((signed char)((uint8_t)(x) + 1)) < 33) #define IDENT 64 @@ -1614,48 +1613,6 @@ EXTERN struct timeval j_usrtime, j_systime; } while (/* CONSTCOND */ 0) -/* NZAAT hash based on Bob Jenkins' one-at-a-time hash */ - -/* From: src/kern/include/nzat.h,v 1.2 2011/07/18 00:35:40 tg Exp $ */ - -#define NZATInit(h) do { \ - (h) = 0; \ -} while (/* CONSTCOND */ 0) - -#define NZATUpdateByte(h,b) do { \ - (h) += (uint8_t)(b); \ - ++(h); \ - (h) += (h) << 10; \ - (h) ^= (h) >> 6; \ -} while (/* CONSTCOND */ 0) - -#define NZATUpdateMem(h,p,z) do { \ - register const uint8_t *NZATUpdateMem_p; \ - register size_t NZATUpdateMem_z = (z); \ - \ - NZATUpdateMem_p = (const void *)(p); \ - while (NZATUpdateMem_z--) \ - NZATUpdateByte((h), *NZATUpdateMem_p++); \ -} while (/* CONSTCOND */ 0) - -#define NZATUpdateString(h,s) do { \ - register const char *NZATUpdateString_s; \ - register uint8_t NZATUpdateString_c; \ - \ - NZATUpdateString_s = (const void *)(s); \ - while ((NZATUpdateString_c = *NZATUpdateString_s++)) \ - NZATUpdateByte((h), NZATUpdateString_c); \ -} while (/* CONSTCOND */ 0) - -#define NZAATFinish(h) do { \ - (h) += (h) << 10; \ - (h) ^= (h) >> 6; \ - (h) += (h) << 3; \ - (h) ^= (h) >> 11; \ - (h) += (h) << 15; \ -} while (/* CONSTCOND */ 0) - - /* lalloc.c */ void ainit(Area *); void afreeall(Area *); @@ -1706,12 +1663,10 @@ int v_evaluate(struct tbl *, const char *, volatile int, bool); size_t utf_mbtowc(unsigned int *, const char *); size_t utf_wctomb(char *, unsigned int); int utf_widthadj(const char *, const char **); -size_t utf_mbswidth(const char *); -const char *utf_skipcols(const char *, int); -size_t utf_ptradj(const char *); -#ifndef MKSH_mirbsd_wcwidth -int utf_wcwidth(unsigned int); -#endif +size_t utf_mbswidth(const char *) MKSH_A_PURE; +const char *utf_skipcols(const char *, int) MKSH_A_PURE; +size_t utf_ptradj(const char *) MKSH_A_PURE; +int utf_wcwidth(unsigned int) MKSH_A_PURE; int ksh_access(const char *, int); struct tbl *tempvar(void); /* funcs.c */ @@ -1779,10 +1734,10 @@ void sethistsize(mksh_ari_t); void sethistfile(const char *); #endif #if !defined(MKSH_NO_CMDLINE_EDITING) && !MKSH_S_NOVI -char **histpos(void); +char **histpos(void) MKSH_A_PURE; int histnum(int); #endif -int findhist(int, int, const char *, int); +int findhist(int, int, const char *, bool) MKSH_A_PURE; char **hist_get_newest(bool); void inittraps(void); void alarm_init(void); @@ -1818,6 +1773,9 @@ int j_kill(const char *, int); #ifndef MKSH_UNEMPLOYED int j_resume(const char *, int); #endif +#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID +void j_suspend(void); +#endif int j_jobs(const char *, int, int); void j_notify(void); pid_t j_async(void); @@ -1895,15 +1853,15 @@ void DF(const char *, ...) /* misc.c */ void setctypes(const char *, int); void initctypes(void); -size_t option(const char *); +size_t option(const char *) MKSH_A_PURE; char *getoptions(void); void change_flag(enum sh_flag, int, bool); void change_xtrace(unsigned char, bool); int parse_args(const char **, int, bool *); int getn(const char *, int *); int gmatchx(const char *, const char *, bool); -int has_globbing(const char *, const char *); -int xstrcmp(const void *, const void *); +int has_globbing(const char *, const char *) MKSH_A_PURE; +int xstrcmp(const void *, const void *) MKSH_A_PURE; void ksh_getopt_reset(Getopt *, int); int ksh_getopt(const char **, Getopt *, const char *); void print_value_quoted(struct shf *, const char *); @@ -1995,19 +1953,21 @@ void setint(struct tbl *, mksh_ari_t); void setint_n(struct tbl *, mksh_ari_t, int); struct tbl *typeset(const char *, uint32_t, uint32_t, int, int); void unset(struct tbl *, int); -const char *skip_varname(const char *, int); -const char *skip_wdvarname(const char *, bool); -int is_wdvarname(const char *, bool); -int is_wdvarassign(const char *); +const char *skip_varname(const char *, bool) MKSH_A_PURE; +const char *skip_wdvarname(const char *, bool) MKSH_A_PURE; +int is_wdvarname(const char *, bool) MKSH_A_PURE; +int is_wdvarassign(const char *) MKSH_A_PURE; struct tbl *arraysearch(struct tbl *, uint32_t); char **makenv(void); void change_winsz(void); -size_t array_ref_len(const char *); +size_t array_ref_len(const char *) MKSH_A_PURE; char *arrayname(const char *); mksh_uari_t set_array(const char *, bool, const char **); -uint32_t hash(const void *); +uint32_t hash(const void *) MKSH_A_PURE; +uint32_t chvt_rndsetup(const void *, size_t) MKSH_A_PURE; mksh_ari_t rndget(void); void rndset(unsigned long); +void rndpush(const void *); enum Test_op { /* non-operator */ @@ -2058,10 +2018,11 @@ typedef struct test_env { extern const char * const dbtest_tokens[]; -Test_op test_isop(Test_meta, const char *); +Test_op test_isop(Test_meta, const char *) MKSH_A_PURE; int test_eval(Test_env *, Test_op, const char *, const char *, bool); int test_parse(Test_env *); +/* tty_fd is not opened O_BINARY, it's thus never read/written */ EXTERN int tty_fd E_INIT(-1); /* dup'd tty file descriptor */ EXTERN bool tty_devtty; /* true if tty_fd is from /dev/tty */ EXTERN mksh_ttyst tty_state; /* saved tty state */ diff --git a/src/sh_flags.gen b/src/sh_flags.gen new file mode 100644 index 0000000..cff2e87 --- /dev/null +++ b/src/sh_flags.gen @@ -0,0 +1,136 @@ +#ifndef SHFLAGS_OPTCS +#if defined(SHFLAGS_DEFNS) +__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.2 2014/06/09 12:28:19 tg Exp $"); +#define FN(sname,cname,flags,ochar) static const struct { /* character flag (if any) */ char c; /* OF_* */ unsigned char optflags; /* long name of option */ char name[sizeof(sname)]; } shoptione_ ## cname = { ochar, flags, sname }; +#elif defined(SHFLAGS_ENUMS) +#define FN(sname,cname,flags,ochar) cname, +#define F0(sname,cname,flags,ochar) cname = 0, +#elif defined(SHFLAGS_ITEMS) +#define FN(sname,cname,flags,ochar) ((const char *)(&shoptione_ ## cname)) + 2, +#endif +#ifndef F0 +#define F0 FN +#endif +F0("allexport", FEXPORT, OF_ANY, 'a') +#if HAVE_NICE +FN("bgnice", FBGNICE, OF_ANY, 0) +#endif +FN("braceexpand", FBRACEEXPAND, OF_ANY, 0) +#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("emacs", FEMACS, OF_ANY, 0) +#endif +FN("errexit", FERREXIT, OF_ANY, 'e') +#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("gmacs", FGMACS, OF_ANY, 0) +#endif +FN("ignoreeof", FIGNOREEOF, OF_ANY, 0) +FN("inherit-xtrace", FXTRACEREC, OF_ANY, 0) +#ifndef SHFLAGS_NOT_CMD +FN("interactive", FTALKING, OF_CMDLINE, 'i') +#endif +FN("keyword", FKEYWORD, OF_ANY, 'k') +#ifndef SHFLAGS_NOT_CMD +FN("login", FLOGIN, OF_CMDLINE, 'l') +#endif +FN("markdirs", FMARKDIRS, OF_ANY, 'X') +#ifndef MKSH_UNEMPLOYED +FN("monitor", FMONITOR, OF_ANY, 'm') +#endif +FN("noclobber", FNOCLOBBER, OF_ANY, 'C') +FN("noexec", FNOEXEC, OF_ANY, 'n') +FN("noglob", FNOGLOB, OF_ANY, 'f') +FN("nohup", FNOHUP, OF_ANY, 0) +FN("nolog", FNOLOG, OF_ANY, 0) +#ifndef MKSH_UNEMPLOYED +FN("notify", FNOTIFY, OF_ANY, 'b') +#endif +FN("nounset", FNOUNSET, OF_ANY, 'u') +FN("physical", FPHYSICAL, OF_ANY, 0) +FN("pipefail", FPIPEFAIL, OF_ANY, 0) +FN("posix", FPOSIX, OF_ANY, 0) +FN("privileged", FPRIVILEGED, OF_ANY, 'p') +#ifndef SHFLAGS_NOT_CMD +FN("restricted", FRESTRICTED, OF_CMDLINE, 'r') +#endif +FN("sh", FSH, OF_ANY, 0) +#ifndef SHFLAGS_NOT_CMD +FN("stdin", FSTDIN, OF_CMDLINE, 's') +#endif +FN("trackall", FTRACKALL, OF_ANY, 'h') +FN("utf8-mode", FUNICODE, OF_ANY, 'U') +FN("verbose", FVERBOSE, OF_ANY, 'v') +#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("vi", FVI, OF_ANY, 0) +#endif +#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("vi-esccomplete", FVIESCCOMPLETE, OF_ANY, 0) +#endif +#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("vi-tabcomplete", FVITABCOMPLETE, OF_ANY, 0) +#endif +#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("viraw", FVIRAW, OF_ANY, 0) +#endif +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 +#undef SHFLAGS_DEFNS +#undef SHFLAGS_ENUMS +#undef SHFLAGS_ITEMS +#else +#ifndef SHFLAGS_NOT_SET +"A:" +#endif +"a" +#ifndef MKSH_UNEMPLOYED +"b" +#endif +"C" +#ifndef SHFLAGS_NOT_CMD +"c" +#endif +"e" +"f" +"h" +#ifndef SHFLAGS_NOT_CMD +"i" +#endif +"k" +#ifndef SHFLAGS_NOT_CMD +"l" +#endif +#ifndef MKSH_UNEMPLOYED +"m" +#endif +"n" +#ifndef SHFLAGS_NOT_CMD +"o:" +#endif +#ifndef SHFLAGS_NOT_SET +"o;" +#endif +"p" +#ifndef SHFLAGS_NOT_CMD +"r" +#endif +#ifndef SHFLAGS_NOT_CMD +"s" +#endif +#ifndef SHFLAGS_NOT_SET +"s" +#endif +#ifndef SHFLAGS_NOT_CMD +"T:" +#endif +"U" +"u" +"v" +"X" +"x" +#undef SHFLAGS_OPTCS +#endif diff --git a/src/sh_flags.h b/src/sh_flags.h deleted file mode 100644 index 3e4cf56..0000000 --- a/src/sh_flags.h +++ /dev/null @@ -1,166 +0,0 @@ -#if defined(SHFLAGS_DEFNS) -__RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.16 2013/08/11 14:57:11 tg Exp $"); -#define FN(sname,cname,ochar,flags) \ - static const struct { \ - /* character flag (if any) */ \ - char c; \ - /* OF_* */ \ - unsigned char optflags; \ - /* long name of option */ \ - char name[sizeof(sname)]; \ - } shoptione_ ## cname = { \ - ochar, flags, sname \ - }; -#elif defined(SHFLAGS_ENUMS) -#define FN(sname,cname,ochar,flags) cname, -#define F0(sname,cname,ochar,flags) cname = 0, -#elif defined(SHFLAGS_ITEMS) -#define FN(sname,cname,ochar,flags) \ - ((const char *)(&shoptione_ ## cname)) + 2, -#endif - -#ifndef F0 -#define F0 FN -#endif - -/* - * special cases (see parse_args()): -A, -o, -s - * - * options are sorted by their longnames - */ - -/* -a all new parameters are created with the export attribute */ -F0("allexport", FEXPORT, 'a', OF_ANY) - -#if HAVE_NICE -/* ./. bgnice */ -FN("bgnice", FBGNICE, 0, OF_ANY) -#endif - -/* ./. enable {} globbing (non-standard) */ -FN("braceexpand", FBRACEEXPAND, 0, OF_ANY) - -#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) -/* ./. Emacs command line editing mode */ -FN("emacs", FEMACS, 0, OF_ANY) -#endif - -/* -e quit on error */ -FN("errexit", FERREXIT, 'e', OF_ANY) - -#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) -/* ./. Emacs command line editing mode, gmacs variant */ -FN("gmacs", FGMACS, 0, OF_ANY) -#endif - -/* ./. reading EOF does not exit */ -FN("ignoreeof", FIGNOREEOF, 0, OF_ANY) - -/* ./. inherit -x flag */ -FN("inherit-xtrace", FXTRACEREC, 0, OF_ANY) - -/* -i interactive shell */ -FN("interactive", FTALKING, 'i', OF_CMDLINE) - -/* -k name=value are recognised anywhere */ -FN("keyword", FKEYWORD, 'k', OF_ANY) - -/* -l login shell */ -FN("login", FLOGIN, 'l', OF_CMDLINE) - -/* -X mark dirs with / in file name completion */ -FN("markdirs", FMARKDIRS, 'X', OF_ANY) - -#ifndef MKSH_UNEMPLOYED -/* -m job control monitoring */ -FN("monitor", FMONITOR, 'm', OF_ANY) -#endif - -/* -C don't overwrite existing files */ -FN("noclobber", FNOCLOBBER, 'C', OF_ANY) - -/* -n don't execute any commands */ -FN("noexec", FNOEXEC, 'n', OF_ANY) - -/* -f don't do file globbing */ -FN("noglob", FNOGLOB, 'f', OF_ANY) - -/* ./. don't kill running jobs when login shell exits */ -FN("nohup", FNOHUP, 0, OF_ANY) - -/* ./. don't save functions in history (no effect) */ -FN("nolog", FNOLOG, 0, OF_ANY) - -#ifndef MKSH_UNEMPLOYED -/* -b asynchronous job completion notification */ -FN("notify", FNOTIFY, 'b', OF_ANY) -#endif - -/* -u using an unset variable is an error */ -FN("nounset", FNOUNSET, 'u', OF_ANY) - -/* ./. don't do logical cds/pwds (non-standard) */ -FN("physical", FPHYSICAL, 0, OF_ANY) - -/* ./. errorlevel of a pipeline is the rightmost nonzero value */ -FN("pipefail", FPIPEFAIL, 0, OF_ANY) - -/* ./. adhere more closely to POSIX even when undesirable */ -FN("posix", FPOSIX, 0, OF_ANY) - -/* -p use suid_profile; privileged shell */ -FN("privileged", FPRIVILEGED, 'p', OF_ANY) - -/* -r restricted shell */ -FN("restricted", FRESTRICTED, 'r', OF_CMDLINE) - -/* ./. kludge mode for better compat with traditional sh (OS-specific) */ -FN("sh", FSH, 0, OF_ANY) - -/* -s (invocation) parse stdin (pseudo non-standard) */ -FN("stdin", FSTDIN, 's', OF_CMDLINE) - -/* -h create tracked aliases for all commands */ -FN("trackall", FTRACKALL, 'h', OF_ANY) - -/* -U enable UTF-8 processing (non-standard) */ -FN("utf8-mode", FUNICODE, 'U', OF_ANY) - -/* -v echo input */ -FN("verbose", FVERBOSE, 'v', OF_ANY) - -#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) -/* ./. Vi command line editing mode */ -FN("vi", FVI, 0, OF_ANY) - -/* ./. enable ESC as file name completion character (non-standard) */ -FN("vi-esccomplete", FVIESCCOMPLETE, 0, OF_ANY) - -/* ./. enable Tab as file name completion character (non-standard) */ -FN("vi-tabcomplete", FVITABCOMPLETE, 0, OF_ANY) - -/* ./. always read in raw mode (no effect) */ -FN("viraw", FVIRAW, 0, OF_ANY) -#endif - -/* -x execution trace (display commands as they are run) */ -FN("xtrace", FXTRACE, 'x', OF_ANY) - -/* -c (invocation) execute specified command */ -FN("", FCOMMAND, 'c', 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, 0, OF_INTERNAL) - -/* ./. (internal) initial shell was interactive */ -FN("", FTALKING_I, 0, OF_INTERNAL) - -#undef FN -#undef F0 -#undef SHFLAGS_DEFNS -#undef SHFLAGS_ENUMS -#undef SHFLAGS_ITEMS diff --git a/src/sh_flags.opt b/src/sh_flags.opt new file mode 100644 index 0000000..99e4a22 --- /dev/null +++ b/src/sh_flags.opt @@ -0,0 +1,179 @@ +@SHFLAGS_DEFNS +__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.2 2014/06/09 12:28:19 tg Exp $"); +#define FN(sname,cname,flags,ochar) static const struct { /* character flag (if any) */ char c; /* OF_* */ unsigned char optflags; /* long name of option */ char name[sizeof(sname)]; } shoptione_ ## cname = { ochar, flags, sname }; +@SHFLAGS_ENUMS +#define FN(sname,cname,flags,ochar) cname, +#define F0(sname,cname,flags,ochar) cname = 0, +@SHFLAGS_ITEMS +#define FN(sname,cname,flags,ochar) ((const char *)(&shoptione_ ## cname)) + 2, +@@ + +/* special cases */ + +a| +F0("allexport", FEXPORT, OF_ANY + +/* ./. bgnice */ +>| HAVE_NICE +FN("bgnice", FBGNICE, OF_ANY + +/* ./. enable {} globbing (non-standard) */ +>| +FN("braceexpand", FBRACEEXPAND, OF_ANY + +/* ./. Emacs command line editing mode */ +>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("emacs", FEMACS, OF_ANY + +/* -e quit on error */ +>e| +FN("errexit", FERREXIT, OF_ANY + +/* ./. Emacs command line editing mode, gmacs variant */ +>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("gmacs", FGMACS, OF_ANY + +/* ./. reading EOF does not exit */ +>| +FN("ignoreeof", FIGNOREEOF, OF_ANY + +/* ./. inherit -x flag */ +>| +FN("inherit-xtrace", FXTRACEREC, OF_ANY + +/* -i interactive shell */ +>i|!SHFLAGS_NOT_CMD +FN("interactive", FTALKING, OF_CMDLINE + +/* -k name=value are recognised anywhere */ +>k| +FN("keyword", FKEYWORD, OF_ANY + +/* -l login shell */ +>l|!SHFLAGS_NOT_CMD +FN("login", FLOGIN, OF_CMDLINE + +/* -X mark dirs with / in file name completion */ +>X| +FN("markdirs", FMARKDIRS, OF_ANY + +/* -m job control monitoring */ +>m|!MKSH_UNEMPLOYED +FN("monitor", FMONITOR, OF_ANY + +/* -C don't overwrite existing files */ +>C| +FN("noclobber", FNOCLOBBER, OF_ANY + +/* -n don't execute any commands */ +>n| +FN("noexec", FNOEXEC, OF_ANY + +/* -f don't do file globbing */ +>f| +FN("noglob", FNOGLOB, OF_ANY + +/* ./. don't kill running jobs when login shell exits */ +>| +FN("nohup", FNOHUP, OF_ANY + +/* ./. don't save functions in history (no effect) */ +>| +FN("nolog", FNOLOG, OF_ANY + +/* -b asynchronous job completion notification */ +>b|!MKSH_UNEMPLOYED +FN("notify", FNOTIFY, OF_ANY + +/* -u using an unset variable is an error */ +>u| +FN("nounset", FNOUNSET, OF_ANY + +/* ./. don't do logical cds/pwds (non-standard) */ +>| +FN("physical", FPHYSICAL, OF_ANY + +/* ./. errorlevel of a pipeline is the rightmost nonzero value */ +>| +FN("pipefail", FPIPEFAIL, OF_ANY + +/* ./. adhere more closely to POSIX even when undesirable */ +>| +FN("posix", FPOSIX, OF_ANY + +/* -p privileged shell (suid) */ +>p| +FN("privileged", FPRIVILEGED, OF_ANY + +/* -r restricted shell */ +>r|!SHFLAGS_NOT_CMD +FN("restricted", FRESTRICTED, OF_CMDLINE + +/* ./. kludge mode for better compat with traditional sh (OS-specific) */ +>| +FN("sh", FSH, OF_ANY + +/* -s (invocation) parse stdin (pseudo non-standard) */ +>s|!SHFLAGS_NOT_CMD +FN("stdin", FSTDIN, OF_CMDLINE + +/* -h create tracked aliases for all commands */ +>h| +FN("trackall", FTRACKALL, OF_ANY + +/* -U enable UTF-8 processing (non-standard) */ +>U| +FN("utf8-mode", FUNICODE, OF_ANY + +/* -v echo input */ +>v| +FN("verbose", FVERBOSE, OF_ANY + +/* ./. Vi command line editing mode */ +>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("vi", FVI, OF_ANY + +/* ./. enable ESC as file name completion character (non-standard) */ +>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("vi-esccomplete", FVIESCCOMPLETE, OF_ANY + +/* ./. enable Tab as file name completion character (non-standard) */ +>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("vi-tabcomplete", FVITABCOMPLETE, OF_ANY + +/* ./. always read in raw mode (no effect) */ +>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) +FN("viraw", FVIRAW, OF_ANY + +/* -x execution trace (display commands as they are run) */ +>x| +FN("xtrace", FXTRACE, OF_ANY + +/* -c (invocation) execute specified command */ +>c|!SHFLAGS_NOT_CMD +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 + +|SHFLAGS_OPTCS diff --git a/src/shf.c b/src/shf.c index e8ec14a..33e89bd 100644 --- a/src/shf.c +++ b/src/shf.c @@ -25,7 +25,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.61 2013/07/21 18:36:03 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.62 2013/10/09 11:59:30 tg Exp $"); /* flags to shf_emptybuf() */ #define EB_READSW 0x01 /* about to switch to reading */ @@ -62,7 +62,7 @@ shf_open(const char *name, int oflags, int mode, int sflags) shf->flags = SHF_ALLOCS; /* Rest filled in by reopen. */ - fd = open(name, oflags, mode); + fd = open(name, oflags | O_BINARY, mode); if (fd < 0) { eno = errno; afree(shf, shf->areap); diff --git a/src/signames.inc b/src/signames.inc new file mode 100644 index 0000000..07811fd --- /dev/null +++ b/src/signames.inc @@ -0,0 +1,31 @@ + { "ABRT", 6 }, + { "FPE", 8 }, + { "ILL", 4 }, + { "INT", 2 }, + { "SEGV", 11 }, + { "TERM", 15 }, + { "ALRM", 14 }, + { "BUS", 7 }, + { "CHLD", 17 }, + { "CONT", 18 }, + { "HUP", 1 }, + { "KILL", 9 }, + { "PIPE", 13 }, + { "QUIT", 3 }, + { "STOP", 19 }, + { "TSTP", 20 }, + { "TTIN", 21 }, + { "TTOU", 22 }, + { "USR1", 10 }, + { "USR2", 12 }, + { "POLL", 29 }, + { "PROF", 27 }, + { "SYS", 31 }, + { "TRAP", 5 }, + { "URG", 23 }, + { "VTALRM", 26 }, + { "XCPU", 24 }, + { "XFSZ", 25 }, + { "WINCH", 28 }, + { "PWR", 30 }, + { "STKFLT", 16 }, diff --git a/src/strlcpy.c b/src/strlcpy.c index 53f9130..c0ebfd5 100644 --- a/src/strlcpy.c +++ b/src/strlcpy.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2006, 2008, 2009 + * Copyright (c) 2006, 2008, 2009, 2013 * Thorsten Glaser * Copyright (c) 1998 Todd C. Miller * @@ -18,13 +18,14 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/strlcpy.c,v 1.7 2009/06/10 18:12:50 tg Rel $"); +__RCSID("$MirOS: src/bin/mksh/strlcpy.c,v 1.8 2013/11/05 22:10:15 tg Exp $"); /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ +#undef strlcpy size_t strlcpy(char *dst, const char *src, size_t siz) { diff --git a/src/syn.c b/src/syn.c index 5c07d51..6a544df 100644 --- a/src/syn.c +++ b/src/syn.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, - * 2011, 2012, 2013 + * 2011, 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.92 2013/06/03 22:28:17 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.94 2014/01/05 21:57:29 tg Exp $"); struct nesting_state { int start_token; /* token than began nesting (eg, FOR) */ @@ -59,7 +59,7 @@ static void syntaxerr(const char *) MKSH_A_NORETURN; static void nesting_push(struct nesting_state *, int); static void nesting_pop(struct nesting_state *); static int assign_command(const char *); -static int inalias(struct source *); +static int inalias(struct source *) MKSH_A_PURE; static Test_op dbtestp_isa(Test_env *, Test_meta); static const char *dbtestp_getopnd(Test_env *, Test_op, bool); static int dbtestp_eval(Test_env *, Test_op, const char *, @@ -976,7 +976,7 @@ static Test_op dbtestp_isa(Test_env *te, Test_meta meta) { int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN)); - int uqword; + bool uqword; char *save = NULL; Test_op ret = TO_NONOP; diff --git a/src/tree.c b/src/tree.c index dcbd7a1..8026f8b 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.71 2013/07/26 20:33:24 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.72 2013/09/24 20:19:45 tg Exp $"); #define INDENT 8 @@ -778,15 +778,16 @@ vistree(char *dst, size_t sz, struct op *t) if (--sz == 0 || (c = (unsigned char)(*cp++)) == 0) /* NUL or not enough free space */ goto vist_out; - if ((c & 0x60) == 0 || (c & 0x7F) == 0x7F) { + if (ISCTRL(c & 0x7F)) { /* C0 or C1 control character or DEL */ if (--sz == 0) /* not enough free space for two chars */ goto vist_out; *dst++ = (c & 0x80) ? '$' : '^'; - c = (c & 0x7F) ^ 0x40; + c = UNCTRL(c & 0x7F); } else if (UTFMODE && c > 0x7F) { /* better not try to display broken multibyte chars */ + /* also go easy on the Unicode: no U+FFFD here */ c = '?'; } *dst++ = c; @@ -801,10 +802,10 @@ vistree(char *dst, size_t sz, struct op *t) void dumpchar(struct shf *shf, int c) { - if (((c & 0x60) == 0) || ((c & 0x7F) == 0x7F)) { + if (ISCTRL(c & 0x7F)) { /* C0 or C1 control character or DEL */ shf_putc((c & 0x80) ? '$' : '^', shf); - c = (c & 0x7F) ^ 0x40; + c = UNCTRL(c & 0x7F); } shf_putc(c, shf); } diff --git a/src/var.c b/src/var.c index ba8fd82..ef114e1 100644 --- a/src/var.c +++ b/src/var.c @@ -1,8 +1,8 @@ -/* $OpenBSD: var.c,v 1.35 2013/04/05 01:31:30 tedu Exp $ */ +/* $OpenBSD: var.c,v 1.38 2013/12/20 17:53:09 zhuk Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013 + * 2011, 2012, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -22,12 +22,13 @@ */ #include "sh.h" +#include "mirhash.h" #if defined(__OpenBSD__) #include #endif -__RCSID("$MirOS: src/bin/mksh/var.c,v 1.173 2013/05/31 22:47:14 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/var.c,v 1.180 2014/06/26 20:36:02 tg Exp $"); /*- * Variables @@ -40,7 +41,9 @@ __RCSID("$MirOS: src/bin/mksh/var.c,v 1.173 2013/05/31 22:47:14 tg Exp $"); */ static struct table specials; -static uint32_t lcg_state = 5381; +static uint32_t lcg_state = 5381, qh_state = 4711; +/* may only be set by typeset() just before call to array_index_calc() */ +static enum namerefflag innermost_refflag = SRF_NOP; static char *formatstr(struct tbl *, const char *); static void exportprep(struct tbl *, const char *); @@ -164,7 +167,8 @@ varsearch(struct block *l, struct tbl **vpp, const char *vn, uint32_t h) /* * Used to calculate an array index for global()/local(). Sets *arrayp * to true if this is an array, sets *valp to the array index, returns - * the basename of the array. + * the basename of the array. May only be called from global()/local() + * and must be their first callee. */ static const char * array_index_calc(const char *n, bool *arrayp, uint32_t *valp) @@ -176,7 +180,7 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp) *arrayp = false; redo_from_ref: p = skip_varname(n, false); - if (set_refflag == SRF_NOP && (p != n) && ksh_isalphx(n[0])) { + if (innermost_refflag == SRF_NOP && (p != n) && ksh_isalphx(n[0])) { struct tbl *vp; char *vn; @@ -184,8 +188,8 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp) /* check if this is a reference */ varsearch(e->loc, &vp, vn, hash(vn)); afree(vn, ATEMP); - if (vp && (vp->flag & (DEFINED|ASSOC|ARRAY)) == - (DEFINED|ASSOC)) { + if (vp && (vp->flag & (DEFINED | ASSOC | ARRAY)) == + (DEFINED | ASSOC)) { char *cp; /* gotcha! */ @@ -195,6 +199,7 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp) goto redo_from_ref; } } + innermost_refflag = SRF_NOP; if (p != n && *p == '[' && (len = array_ref_len(p))) { char *sub, *tmp; @@ -225,10 +230,13 @@ global(const char *n) bool array; uint32_t h, val; - /* Check to see if this is an array */ + /* + * check to see if this is an array; + * dereference namerefs; must come first + */ n = array_index_calc(n, &array, &val); h = hash(n); - c = n[0]; + c = (unsigned char)n[0]; if (!ksh_isalphx(c)) { if (array) errorf("bad substitution"); @@ -238,9 +246,7 @@ global(const char *n) vp->areap = ATEMP; *vp->name = c; if (ksh_isdigit(c)) { - for (c = 0; ksh_isdigit(*n); n++) - c = c*10 + *n-'0'; - if (c <= l->argc) + if (getn(n, &c) && (c <= l->argc)) /* setstr can't fail here */ setstr(vp, l->argv[c], KSH_RETURN_ERROR); vp->flag |= RDONLY; @@ -297,7 +303,10 @@ local(const char *n, bool copy) bool array; uint32_t h, val; - /* check to see if this is an array */ + /* + * check to see if this is an array; + * dereference namerefs; must come first + */ n = array_index_calc(n, &array, &val); mkssert(n != NULL); h = hash(n); @@ -500,7 +509,7 @@ getint(struct tbl *vp, mksh_ari_u *nump, bool arith) base = 8; have_base = true; } - while ((c = *s++)) { + while ((c = (unsigned char)*s++)) { if (c == '-') { neg = true; continue; @@ -702,6 +711,16 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) const char *val; size_t len; bool vappend = false; + enum namerefflag new_refflag = SRF_NOP; + + if ((set & (ARRAY | ASSOC)) == ASSOC) { + new_refflag = SRF_ENABLE; + set &= ~(ARRAY | ASSOC); + } + if ((clr & (ARRAY | ASSOC)) == ASSOC) { + new_refflag = SRF_DISABLE; + clr &= ~(ARRAY | ASSOC); + } /* check for valid variable name, search for value */ val = skip_varname(var, false); @@ -710,7 +729,7 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) return (NULL); } if (*val == '[') { - if (set_refflag != SRF_NOP) + if (new_refflag != SRF_NOP) errorf("%s: %s", var, "reference variable can't be an array"); len = array_ref_len(val); @@ -756,18 +775,32 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) tvar[len - 3] = '\0'; } - if (set_refflag == SRF_ENABLE) { - const char *qval; + if (new_refflag == SRF_ENABLE) { + const char *qval, *ccp; /* bail out on 'nameref foo+=bar' */ if (vappend) - errorfz(); + errorf("appending not allowed for nameref"); /* find value if variable already exists */ if ((qval = val) == NULL) { varsearch(e->loc, &vp, tvar, hash(tvar)); if (vp != NULL) qval = str_val(vp); } + /* check target value for being a valid variable name */ + ccp = skip_varname(qval, false); + if (ccp == qval) + errorf("%s: %s", var, "empty nameref target"); + len = (*ccp == '[') ? array_ref_len(ccp) : 0; + if (ccp[len]) { + /* + * works for cases "no array", "valid array with + * junk after it" and "invalid array"; in the + * latter case, len is also 0 and points to '[' + */ + errorf("%s: %s", qval, + "nameref target not a valid parameter name"); + } /* prevent nameref loops */ while (qval) { if (!strcmp(qval, tvar)) @@ -775,7 +808,7 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) "expression recurses on parameter"); varsearch(e->loc, &vp, qval, hash(qval)); qval = NULL; - if (vp && ((vp->flag & (ARRAY|ASSOC)) == ASSOC)) + if (vp && ((vp->flag & (ARRAY | ASSOC)) == ASSOC)) qval = str_val(vp); } } @@ -785,11 +818,12 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0)) errorf("%s: %s", tvar, "restricted"); - vp = (set&LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) : + innermost_refflag = new_refflag; + vp = (set & LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) : global(tvar); - if (set_refflag == SRF_DISABLE && (vp->flag & (ARRAY|ASSOC)) == ASSOC) + if (new_refflag == SRF_DISABLE && (vp->flag & (ARRAY|ASSOC)) == ASSOC) vp->flag &= ~ASSOC; - else if (set_refflag == SRF_ENABLE) { + else if (new_refflag == SRF_ENABLE) { if (vp->flag & ARRAY) { struct tbl *a, *tmp; @@ -809,14 +843,14 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) set &= ~(LOCAL|LOCAL_COPY); - vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp; + vpbase = (vp->flag & ARRAY) ? global(arrayname(tvar)) : vp; /* * only allow export flag to be set; AT&T ksh allows any * attribute to be changed which means it can be truncated or * modified (-L/-R/-Z/-i) */ - if ((vpbase->flag&RDONLY) && + if ((vpbase->flag & RDONLY) && (val || clr || (set & ~EXPORT))) /* XXX check calls - is error here ok by POSIX? */ errorfx(2, "read-only: %s", tvar); @@ -960,7 +994,7 @@ unset(struct tbl *vp, int flags) * the terminating NUL if whole string is legal). */ const char * -skip_varname(const char *s, int aok) +skip_varname(const char *s, bool aok) { size_t alen; @@ -1338,7 +1372,7 @@ arraysearch(struct tbl *vp, uint32_t val) struct tbl *prev, *curr, *news; size_t len; - vp->flag = (vp->flag | (ARRAY|DEFINED)) & ~ASSOC; + vp->flag = (vp->flag | (ARRAY | DEFINED)) & ~ASSOC; /* the table entry is always [0] */ if (val == 0) return (vp); @@ -1378,6 +1412,8 @@ arraysearch(struct tbl *vp, uint32_t val) * Return the length of an array reference (eg, [1+2]) - cp is assumed * to point to the open bracket. Returns 0 if there is no matching * closing bracket. + * + * XXX this should parse the actual arithmetic syntax */ size_t array_ref_len(const char *cp) @@ -1458,6 +1494,7 @@ set_array(const char *var, bool reset, const char **vals) afree(cp, ATEMP); } while ((ccp = vals[i])) { +#if 0 /* temporarily taken out due to regression */ if (*ccp == '[') { int level = 0; @@ -1478,6 +1515,7 @@ set_array(const char *var, bool reset, const char **vals) } else ccp = vals[i]; } +#endif vq = arraysearch(vp, j); /* would be nice to deal with errors here... (see above) */ @@ -1492,6 +1530,11 @@ set_array(const char *var, bool reset, const char **vals) void change_winsz(void) { + struct timeval tv; + + mksh_TIME(tv); + BAFHUpdateMem_mem(qh_state, &tv, sizeof(tv)); + #ifdef TIOCGWINSZ /* check if window size has changed */ if (tty_init_fd() < 2) { @@ -1522,9 +1565,28 @@ hash(const void *s) { register uint32_t h; - NZATInit(h); - NZATUpdateString(h, s); - NZAATFinish(h); + BAFHInit(h); + BAFHUpdateStr_reg(h, s); + BAFHFinish_reg(h); + return (h); +} + +uint32_t +chvt_rndsetup(const void *bp, size_t sz) +{ + register uint32_t h; + + /* use LCG as seed but try to get them to deviate immediately */ + h = lcg_state; + (void)rndget(); + BAFHFinish_reg(h); + /* variation through pid, ppid, and the works */ + BAFHUpdateMem_reg(h, &rndsetupstate, sizeof(rndsetupstate)); + /* some variation, some possibly entropy, depending on OE */ + BAFHUpdateMem_reg(h, bp, sz); + /* mix them all up */ + BAFHFinish_reg(h); + return (h); } @@ -1542,28 +1604,67 @@ void rndset(unsigned long v) { register uint32_t h; +#if defined(arc4random_pushb_fast) || defined(MKSH_A4PB) + register uint32_t t; +#endif + struct { + struct timeval tv; + void *sp; + uint32_t qh; + pid_t pp; + short r; + } z; + +#ifdef DEBUG + /* clear the allocated space, for valgrind */ + memset(&z, 0, sizeof(z)); +#endif - NZATInit(h); - NZATUpdateMem(h, &lcg_state, sizeof(lcg_state)); - NZATUpdateMem(h, &v, sizeof(v)); + h = lcg_state; + BAFHFinish_reg(h); + BAFHUpdateMem_reg(h, &v, sizeof(v)); + + mksh_TIME(z.tv); + z.sp = &lcg_state; + z.pp = procpid; + z.r = (short)rndget(); #if defined(arc4random_pushb_fast) || defined(MKSH_A4PB) + t = qh_state; + BAFHFinish_reg(t); + z.qh = (t & 0xFFFF8000) | rndget(); + lcg_state = (t << 15) | rndget(); /* * either we have very chap entropy get and push available, * with malloc() pulling in this code already anyway, or the * user requested us to use the old functions */ - lcg_state = h; - NZAATFinish(lcg_state); + t = h; + BAFHUpdateMem_reg(t, &lcg_state, sizeof(lcg_state)); + BAFHFinish_reg(t); + lcg_state = t; #if defined(arc4random_pushb_fast) arc4random_pushb_fast(&lcg_state, sizeof(lcg_state)); lcg_state = arc4random(); #else lcg_state = arc4random_pushb(&lcg_state, sizeof(lcg_state)); #endif - NZATUpdateMem(h, &lcg_state, sizeof(lcg_state)); + BAFHUpdateMem_reg(h, &lcg_state, sizeof(lcg_state)); +#else + z.qh = qh_state; #endif - NZAATFinish(h); + BAFHUpdateMem_reg(h, &z, sizeof(z)); + BAFHFinish_reg(h); lcg_state = h; } + +void +rndpush(const void *s) +{ + register uint32_t h = qh_state; + + BAFHUpdateStr_reg(h, s); + BAFHUpdateOctet_reg(h, 0); + qh_state = h; +}