From f6d937cc6741617087c850be30ad5dea0b5e4d89 Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 31 Dec 2015 12:58:43 +0000 Subject: [PATCH 01/21] also recognise ksh93 compiled binaries and LZIP compressed files --- exec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 362bf45..78d50f9 100644 --- a/exec.c +++ b/exec.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.168 2015/10/09 21:36:55 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.169 2015/12/31 12:58:43 tg Exp $"); #ifndef MKSH_DEFAULT_EXECSHELL #define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh" @@ -999,6 +999,7 @@ scriptexec(struct op *tp, const char **ap) (m == /* ECOFF_SH */ 0x0500 || m == 0x0005) || (m == /* bzip */ 0x425A) || (m == /* "MZ" */ 0x4D5A) || (m == /* "NE" */ 0x4E45) || (m == /* "LX" */ 0x4C58) || + (m == /* ksh93 */ 0x0B13) || (m == /* LZIP */ 0x4C5A) || (m == /* xz */ 0xFD37 && buf[2] == 'z' && buf[3] == 'X' && buf[4] == 'Z') || (m == /* 7zip */ 0x377A) || (m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D)) From f0b83e194adc2320dd2e66612fadc8d97a332730 Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 31 Dec 2015 20:25:48 +0000 Subject: [PATCH 02/21] =?UTF-8?q?future=20directions;=20izabera=E2=80=99s?= =?UTF-8?q?=20got=20a=20point=20and=20we=E2=80=99ll=20need=20two=20locales?= =?UTF-8?q?=20(C=20and=20C.UTF-8),=20but=20we=E2=80=99ll=20need=20this=20i?= =?UTF-8?q?n=20MirBSD=20a=CC=B2n=CC=B2d=CC=B2=20audit=20its=20scripts=20fi?= =?UTF-8?q?rst?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mksh.1 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mksh.1 b/mksh.1 index 5e04d8e..0f69945 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.383 2015/12/12 22:25:14 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.384 2015/12/31 20:25:48 tg Exp $ .\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, @@ -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: December 12 2015 $ +.Dd $Mdocdate: December 31 2015 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" @@ -4138,6 +4138,12 @@ or case-insensitively; for direct builtin calls depending on the aforementioned environment variables; or for stdin or scripts, if the input begins with a UTF-8 Byte Order Mark. +.Pp +In near future, locale tracking will be implemented, which means that +.Ic set Fl +U +is changed whenever one of the +.Tn POSIX +locale-related environment variables changes. .It Fl u \*(Ba Fl o Ic nounset Referencing of an unset parameter, other than .Dq $@ @@ -6552,6 +6558,7 @@ case ${KSH_VERSION:\-} in esac ;; esac .Ed +In near future, (Unicode) locale tracking will be implemented though. .Sh BUGS Suspending (using \*(haZ) pipelines like the one below will only suspend the currently running part of the pipeline; in this example, From 54e31ce5620943e40c00123f891b504c01097049 Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 31 Dec 2015 20:38:59 +0000 Subject: [PATCH 03/21] plug EEXIST --- shf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shf.c b/shf.c index 0583792..3b63c7b 100644 --- a/shf.c +++ b/shf.c @@ -25,7 +25,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.68 2015/10/09 15:38:36 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.69 2015/12/31 20:38:59 tg Exp $"); /* flags to shf_emptybuf() */ #define EB_READSW 0x01 /* about to switch to reading */ @@ -1121,6 +1121,8 @@ cstrerror(int errnum) #endif case EACCES: return ("Permission denied"); + case EEXIST: + return ("File exists"); case ENOTDIR: return ("Not a directory"); #ifdef EINVAL From c56d848a10a4c746c870fbe4507118bea5f6d800 Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 31 Dec 2015 21:00:12 +0000 Subject: [PATCH 04/21] set -U after LANG/LC_*, for future compatibility, cf. commitid 10056858F3B37548534 --- dot.mkshrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dot.mkshrc b/dot.mkshrc index 8f241b0..ab13f9d 100644 --- a/dot.mkshrc +++ b/dot.mkshrc @@ -1,5 +1,5 @@ # $Id$ -# $MirOS: src/bin/mksh/dot.mkshrc,v 1.103 2015/12/12 18:47:40 tg Exp $ +# $MirOS: src/bin/mksh/dot.mkshrc,v 1.104 2015/12/31 21:00:12 tg Exp $ #- # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014, 2015 @@ -596,8 +596,8 @@ done #\unset LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_IDENTIFICATION LC_MONETARY \ # LC_NAME LC_NUMERIC LC_TELEPHONE LC_TIME #p=en_GB.UTF-8 -#\set -U #\export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p +#\set -U \unset p From 4059e105a283fa280d150154fa1b0e5c6daa7dfd Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 31 Dec 2015 21:03:47 +0000 Subject: [PATCH 05/21] fstat(2) after open(2) for set -C case when initial stat(2) was !S_ISREG to fix race condition as suggested by jilles --- check.t | 6 +++--- exec.c | 42 ++++++++++++++++++++++++++++++++---------- sh.h | 4 ++-- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/check.t b/check.t index d5745f5..0189cf6 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.716 2015/12/12 23:31:15 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.717 2015/12/31 21:03:44 tg Exp $ # -*- mode: sh -*- #- # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, @@ -30,7 +30,7 @@ # (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date expected-stdout: - @(#)MIRBSD KSH R52 2015/12/12 + @(#)MIRBSD KSH R52 2015/12/31 description: Check version of shell. stdin: @@ -39,7 +39,7 @@ name: KSH_VERSION category: shell:legacy-no --- expected-stdout: - @(#)LEGACY KSH R52 2015/12/12 + @(#)LEGACY KSH R52 2015/12/31 description: Check version of legacy shell. stdin: diff --git a/exec.c b/exec.c index 78d50f9..9361c19 100644 --- a/exec.c +++ b/exec.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.169 2015/12/31 12:58:43 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.170 2015/12/31 21:03:47 tg Exp $"); #ifndef MKSH_DEFAULT_EXECSHELL #define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh" @@ -1363,7 +1363,7 @@ iosetup(struct ioword *iop, struct tbl *tp) int u = -1; char *cp = iop->ioname; int iotype = iop->ioflag & IOTYPE; - bool do_open = true, do_close = false; + bool do_open = true, do_close = false, do_fstat = false; int flags = 0; struct ioword iotmp; struct stat statb; @@ -1392,14 +1392,27 @@ iosetup(struct ioword *iop, struct tbl *tp) break; case IOWRITE: - flags = O_WRONLY | O_CREAT | O_TRUNC; - /* - * The stat() is here to allow redirections to - * things like /dev/null without error. - */ - if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB) && - (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode))) - flags |= O_EXCL; + if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB)) { + /* >file under set -C */ + if (stat(cp, &statb)) { + /* nonexistent file */ + flags = O_WRONLY | O_CREAT | O_EXCL; + } else if (S_ISREG(statb.st_mode)) { + /* regular file, refuse clobbering */ + goto clobber_refused; + } else { + /* + * allow redirections to things + * like /dev/null without error + */ + flags = O_WRONLY; + /* but check again after opening */ + do_fstat = true; + } + } else { + /* >|file or set +C */ + flags = O_WRONLY | O_CREAT | O_TRUNC; + } break; case IORDWR: @@ -1444,6 +1457,15 @@ iosetup(struct ioword *iop, struct tbl *tp) return (-1); } u = binopen3(cp, flags, 0666); + if (do_fstat && u >= 0) { + /* prevent race conditions */ + if (fstat(u, &statb) || S_ISREG(statb.st_mode)) { + close(u); + clobber_refused: + u = -1; + errno = EEXIST; + } + } } if (u < 0) { /* herein() may already have printed message */ diff --git a/sh.h b/sh.h index 6cdd6c0..39530aa 100644 --- a/sh.h +++ b/sh.h @@ -175,9 +175,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.751 2015/12/12 22:25:15 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.752 2015/12/31 21:03:47 tg Exp $"); #endif -#define MKSH_VERSION "R52 2015/12/12" +#define MKSH_VERSION "R52 2015/12/31" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES From fd5360903d34c50dded6a1a30bfbb6b7cb528720 Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 31 Dec 2015 21:16:20 +0000 Subject: [PATCH 06/21] =?UTF-8?q?don=E2=80=99t=20use=20unset=20in=20portab?= =?UTF-8?q?le=20code=20either,=20thanks=20autoconf=20texinfo=20manual?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Build.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Build.sh b/Build.sh index f8267bf..46561ae 100644 --- a/Build.sh +++ b/Build.sh @@ -1,5 +1,5 @@ #!/bin/sh -srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.693 2015/12/12 22:25:10 tg Exp $' +srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.694 2015/12/31 21:16:20 tg Exp $' #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014, 2015 @@ -1237,19 +1237,20 @@ dragonegg|llvm) vv '|' "llc -version" ;; esac +etd=" on $et" case $et in klibc) add_cppflags -DMKSH_NO_LIMITS ;; unknown) # nothing special detected, don’t worry - unset et + etd= ;; *) # huh? ;; esac -$e "$bi==> which compiler seems to be used...$ao $ui$ct${et+ on $et}$ao" +$e "$bi==> which compiler seems to be used...$ao $ui$ct$etd$ao" rmf conftest.c conftest.o conftest a.out* a.exe* conftest.exe* vv.out # From 7771c3b7d2c3a3d21009dceb393c62246fc8a6f7 Mon Sep 17 00:00:00 2001 From: tg Date: Sat, 2 Jan 2016 20:11:31 +0000 Subject: [PATCH 07/21] glibc now causes warnings with set[ug]id also on kFreeBSD and Hurd --- Build.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Build.sh b/Build.sh index 46561ae..0bd52d5 100644 --- a/Build.sh +++ b/Build.sh @@ -1,8 +1,8 @@ #!/bin/sh -srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.694 2015/12/31 21:16:20 tg Exp $' +srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.695 2016/01/02 20:11:31 tg Exp $' #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011, 2012, 2013, 2014, 2015 +# 2011, 2012, 2013, 2014, 2015, 2016 # mirabilos # # Provided that these terms and disclaimer and all copyright notices @@ -745,6 +745,7 @@ GNU) *tendracc*) ;; *) add_cppflags -D_GNU_SOURCE ;; esac + add_cppflags -DSETUID_CAN_FAIL_WITH_EAGAIN # define MKSH__NO_PATH_MAX to use Hurd-only functions add_cppflags -DMKSH__NO_PATH_MAX ;; @@ -753,6 +754,7 @@ GNU/kFreeBSD) *tendracc*) ;; *) add_cppflags -D_GNU_SOURCE ;; esac + add_cppflags -DSETUID_CAN_FAIL_WITH_EAGAIN ;; Haiku) add_cppflags -DMKSH_ASSUME_UTF8; HAVE_ISSET_MKSH_ASSUME_UTF8=1 From 678fd25b3631a3ec828104c727398d86c7ca2e91 Mon Sep 17 00:00:00 2001 From: tg Date: Tue, 12 Jan 2016 16:33:17 +0000 Subject: [PATCH 08/21] be clearer on what we do to the array on read -a other than clearing it --- mksh.1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mksh.1 b/mksh.1 index 0f69945..43dc74d 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,8 +1,8 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.384 2015/12/31 20:25:48 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.385 2016/01/12 16:33:17 tg Exp $ .\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, -.\" 2010, 2011, 2012, 2013, 2014, 2015 +.\" 2010, 2011, 2012, 2013, 2014, 2015, 2016 .\" mirabilos .\" .\" 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: December 31 2015 $ +.Dd $Mdocdate: January 12 2016 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" @@ -3815,7 +3815,8 @@ Store the result without word splitting into the parameter .Ev REPLY ) as array of characters (wide characters if the .Ic utf8\-mode -option is enacted, octets otherwise). +option is enacted, octets otherwise); the codepoints are +encoded as decimal numbers by default. .It Fl d Ar x Use the first byte of .Ar x , From 2492c5692b67619eb44a7728b78b8d9be70612a1 Mon Sep 17 00:00:00 2001 From: tg Date: Wed, 13 Jan 2016 17:20:52 +0000 Subject: [PATCH 09/21] =?UTF-8?q?incorporate=20suggestions=20by=20J?= =?UTF-8?q?=EF=BF=BDrg=20Schilling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- check.t | 6 +++--- funcs.c | 21 ++++++++++----------- mksh.1 | 7 ++++--- sh.h | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/check.t b/check.t index 0189cf6..27fd81d 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.717 2015/12/31 21:03:44 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.718 2016/01/13 17:20:46 tg Exp $ # -*- mode: sh -*- #- # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, @@ -30,7 +30,7 @@ # (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date expected-stdout: - @(#)MIRBSD KSH R52 2015/12/31 + @(#)MIRBSD KSH R52 2016/01/13 description: Check version of shell. stdin: @@ -39,7 +39,7 @@ name: KSH_VERSION category: shell:legacy-no --- expected-stdout: - @(#)LEGACY KSH R52 2015/12/31 + @(#)LEGACY KSH R52 2016/01/13 description: Check version of legacy shell. stdin: diff --git a/funcs.c b/funcs.c index 2a6fd88..07bd026 100644 --- a/funcs.c +++ b/funcs.c @@ -5,7 +5,7 @@ /*- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - * 2010, 2011, 2012, 2013, 2014, 2015 + * 2010, 2011, 2012, 2013, 2014, 2015, 2016 * mirabilos * * 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.288 2015/12/12 19:27:36 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.289 2016/01/13 17:20:49 tg Exp $"); #if HAVE_KILLPG /* @@ -2355,16 +2355,14 @@ int c_exitreturn(const char **wp) { int n, how = LEXIT; - const char *arg; - if (ksh_getopt(wp, &builtin_opt, null) == '?') - goto c_exitreturn_err; - arg = wp[builtin_opt.optind]; - - if (arg) - exstat = bi_getn(arg, &n) ? (n & 0xFF) : 1; - else if (trap_exstat != -1) + if (wp[1]) { + if (wp[2]) + goto c_exitreturn_err; + exstat = bi_getn(wp[1], &n) ? (n & 0xFF) : 1; + } else if (trap_exstat != -1) exstat = trap_exstat; + if (wp[0][0] == 'r') { /* return */ struct env *ep; @@ -2385,12 +2383,13 @@ c_exitreturn(const char **wp) how = LSHELL; } - /* get rid of any i/o redirections */ + /* get rid of any I/O redirections */ quitenv(NULL); unwind(how); /* NOTREACHED */ c_exitreturn_err: + bi_errorf("too many arguments"); return (1); } diff --git a/mksh.1 b/mksh.1 index 43dc74d..72da56d 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.385 2016/01/12 16:33:17 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.386 2016/01/13 17:20:50 tg Exp $ .\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, @@ -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: January 12 2016 $ +.Dd $Mdocdate: January 13 2016 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" @@ -2965,7 +2965,8 @@ Builtins that are not special: Once the type of command has been determined, any command-line parameter assignments are performed and exported for the duration of the command. .Pp -The following describes the special and regular built-in commands: +The following describes the special and regular built-in commands and +builtin-like reserved words: .Pp .Bl -tag -width false -compact .It Ic \&. Ar file Op Ar arg ... diff --git a/sh.h b/sh.h index 39530aa..5d8c0ac 100644 --- a/sh.h +++ b/sh.h @@ -175,9 +175,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.752 2015/12/31 21:03:47 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.753 2016/01/13 17:20:52 tg Exp $"); #endif -#define MKSH_VERSION "R52 2015/12/31" +#define MKSH_VERSION "R52 2016/01/13" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES From 0a1f594503b8aa92497c8ab38b376da5eda511f0 Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 14 Jan 2016 19:52:20 +0000 Subject: [PATCH 10/21] =?UTF-8?q?parse=20=E2=80=9C$(=20((=20=E2=80=A6=20)?= =?UTF-8?q?=20=E2=80=A6=20)=20=E2=80=A6=20)=E2=80=9D=20correctly=20(LP#153?= =?UTF-8?q?2621)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lex.c | 6 ++++-- syn.c | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lex.c b/lex.c index a5a1009..b552dfc 100644 --- a/lex.c +++ b/lex.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2014, 2015 + * 2011, 2012, 2013, 2014, 2015, 2016 * mirabilos * * 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.214 2015/12/12 19:05:52 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.215 2016/01/14 19:52:20 tg Exp $"); /* * states while lexing word @@ -777,6 +777,7 @@ yylex(int cf) Source *s; ungetsc(c2); + ungetsc(c); /* * mismatched parenthesis - * assume we were really @@ -789,6 +790,7 @@ yylex(int cf) s->start = s->str = s->u.freeme = dp; s->next = source; source = s; + ungetsc('('/*)*/); return ('('/*)*/); } } else if (c == '(') diff --git a/syn.c b/syn.c index 6b41b4d..6c787b8 100644 --- a/syn.c +++ b/syn.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, - * 2011, 2012, 2013, 2014, 2015 + * 2011, 2012, 2013, 2014, 2015, 2016 * mirabilos * * 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.107 2015/12/12 21:03:53 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.108 2016/01/14 19:52:20 tg Exp $"); struct nesting_state { int start_token; /* token than began nesting (eg, FOR) */ @@ -400,6 +400,7 @@ get_command(int cf) case LWORD: break; case '(': /*)*/ + c = '('; goto Subshell; default: syntaxerr(NULL); From 5be0ec410ec4a885c2baea37209f552a73e9855d Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 14 Jan 2016 20:21:39 +0000 Subject: [PATCH 11/21] leak less memory --- var.c | 61 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/var.c b/var.c index d8e31ae..58551e8 100644 --- a/var.c +++ b/var.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2014, 2015 + * 2011, 2012, 2013, 2014, 2015, 2016 * mirabilos * * Provided that these terms and disclaimer and all copyright notices @@ -28,7 +28,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/var.c,v 1.195 2015/10/09 16:11:19 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/var.c,v 1.196 2016/01/14 20:21:39 tg Exp $"); /*- * Variables @@ -218,14 +218,16 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp) return (n); } +#define vn vname.ro /* * Search for variable, if not found create globally. */ struct tbl * global(const char *n) { - struct block *l = e->loc; struct tbl *vp; + union mksh_cchack vname; + struct block *l = e->loc; int c; bool array; uint32_t h, val; @@ -234,9 +236,9 @@ global(const char *n) * check to see if this is an array; * dereference namerefs; must come first */ - n = array_index_calc(n, &array, &val); - h = hash(n); - c = (unsigned char)n[0]; + vn = array_index_calc(n, &array, &val); + h = hash(vn); + c = (unsigned char)vn[0]; if (!ksh_isalphx(c)) { if (array) errorf("bad substitution"); @@ -246,15 +248,15 @@ global(const char *n) vp->areap = ATEMP; *vp->name = c; if (ksh_isdigit(c)) { - if (getn(n, &c) && (c <= l->argc)) + if (getn(vn, &c) && (c <= l->argc)) /* setstr can't fail here */ setstr(vp, l->argv[c], KSH_RETURN_ERROR); vp->flag |= RDONLY; - return (vp); + goto out; } vp->flag |= RDONLY; - if (n[1] != '\0') - return (vp); + if (vn[1] != '\0') + goto out; vp->flag |= ISSET|INTEGER; switch (c) { case '$': @@ -278,17 +280,23 @@ global(const char *n) default: vp->flag &= ~(ISSET|INTEGER); } - return (vp); + goto out; } - l = varsearch(e->loc, &vp, n, h); - if (vp != NULL) - return (array ? arraysearch(vp, val) : vp); - vp = ktenter(&l->vars, n, h); + l = varsearch(e->loc, &vp, vn, h); + if (vp != NULL) { + if (array) + vp = arraysearch(vp, val); + goto out; + } + vp = ktenter(&l->vars, vn, h); if (array) vp = arraysearch(vp, val); vp->flag |= DEFINED; - if (special(n)) + if (special(vn)) vp->flag |= SPECIAL; + out: + if (vn != n) + afree(vname.rw, ATEMP); return (vp); } @@ -298,8 +306,9 @@ global(const char *n) struct tbl * local(const char *n, bool copy) { - struct block *l = e->loc; struct tbl *vp; + union mksh_cchack vname; + struct block *l = e->loc; bool array; uint32_t h, val; @@ -307,20 +316,20 @@ local(const char *n, bool copy) * check to see if this is an array; * dereference namerefs; must come first */ - n = array_index_calc(n, &array, &val); - h = hash(n); - if (!ksh_isalphx(*n)) { + vn = array_index_calc(n, &array, &val); + h = hash(vn); + if (!ksh_isalphx(*vn)) { vp = &vtemp; vp->flag = DEFINED|RDONLY; vp->type = 0; vp->areap = ATEMP; - return (vp); + goto out; } - vp = ktenter(&l->vars, n, h); + vp = ktenter(&l->vars, vn, h); if (copy && !(vp->flag & DEFINED)) { struct tbl *vq; - varsearch(l->next, &vq, n, h); + varsearch(l->next, &vq, vn, h); if (vq != NULL) { vp->flag |= vq->flag & (EXPORT | INTEGER | RDONLY | LJUST | RJUST | @@ -333,10 +342,14 @@ local(const char *n, bool copy) if (array) vp = arraysearch(vp, val); vp->flag |= DEFINED; - if (special(n)) + if (special(vn)) vp->flag |= SPECIAL; + out: + if (vn != n) + afree(vname.rw, ATEMP); return (vp); } +#undef vn /* get variable string value */ char * From 000580ca8ff9aafc30d0adf0a032b6665bd36ba1 Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 14 Jan 2016 21:17:50 +0000 Subject: [PATCH 12/21] fix buffer overrun (LP#1533394) --- expr.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/expr.c b/expr.c index 9030389..64b9481 100644 --- a/expr.c +++ b/expr.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2014 + * 2011, 2012, 2013, 2014, 2016 * mirabilos * * 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.80 2015/11/29 17:05:00 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.81 2016/01/14 21:17:50 tg Exp $"); /* the order of these enums is constrained by the order of opinfo[] */ enum token { @@ -659,7 +659,8 @@ exprtoken(Expr_state *es) es->tok = VAR; } else if (c == '1' && cp[1] == '#') { cp += 2; - cp += utf_ptradj(cp); + if (*cp) + cp += utf_ptradj(cp); strndupx(tvar, es->tokp, cp - es->tokp, ATEMP); goto process_tvar; #ifndef MKSH_SMALL From 0141794c2eae3434199aee545679b2eb8ace91d0 Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 14 Jan 2016 22:30:43 +0000 Subject: [PATCH 13/21] correctly handle nested ADELIM parsing: ADELIM doubles as CSUBST (LP#1453827) --- eval.c | 13 ++++--------- tree.c | 21 +++++++++++++++++---- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/eval.c b/eval.c index 44d4c55..ba89e79 100644 --- a/eval.c +++ b/eval.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2014, 2015 + * 2011, 2012, 2013, 2014, 2015, 2016 * mirabilos * * 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.178 2015/12/12 22:24:07 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.179 2016/01/14 22:30:43 tg Exp $"); /* * string expansion @@ -437,8 +437,6 @@ expand( beg = wdcopy(sp, ATEMP); mid = beg + (wdscan(sp, ADELIM) - sp); stg = beg + (wdscan(sp, CSUBST) - sp); - if (mid >= stg) - goto unwind_substsyn; mid[-2] = EOS; if (mid[-1] == /*{*/'}') { sp += mid - beg - 1; @@ -446,9 +444,8 @@ expand( } else { end = mid + (wdscan(mid, ADELIM) - mid); - if (end >= stg || - /* more than max delimiters */ - end[-1] != /*{*/ '}') + if (end[-1] != /*{*/ '}') + /* more than max delimiters */ goto unwind_substsyn; end[-2] = EOS; sp += end - beg - 1; @@ -488,8 +485,6 @@ expand( s = wdcopy(sp, ATEMP); p = s + (wdscan(sp, ADELIM) - sp); d = s + (wdscan(sp, CSUBST) - sp); - if (p >= d) - goto unwind_substsyn; p[-2] = EOS; if (p[-1] == /*{*/'}') d = NULL; diff --git a/tree.c b/tree.c index edc3d02..7a7df5d 100644 --- a/tree.c +++ b/tree.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2015 + * 2011, 2012, 2013, 2015, 2016 * mirabilos * * Provided that these terms and disclaimer and all copyright notices @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.79 2015/12/12 19:08:58 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.80 2016/01/14 22:30:43 tg Exp $"); #define INDENT 8 @@ -318,6 +318,10 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode) case EOS: return (--wp); case ADELIM: + if (*wp == /*{*/'}') { + ++wp; + goto wdvarput_csubst; + } case CHAR: c = *wp++; shf_putc(c, shf); @@ -383,8 +387,10 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode) wp = wdvarput(shf, wp, 0, opmode); break; case CSUBST: - if (*wp++ == '}') + if (*wp++ == '}') { + wdvarput_csubst: shf_putc('}', shf); + } return (wp); case OPAT: shf_putchar(*wp++, shf); @@ -581,8 +587,10 @@ wdscan(const char *wp, int c) case EOS: return (wp); case ADELIM: - if (c == ADELIM) + if (c == ADELIM && nest == 0) return (wp + 1); + if (*wp == /*{*/'}') + goto wdscan_csubst; /* FALLTHROUGH */ case CHAR: case QCHAR: @@ -604,6 +612,7 @@ wdscan(const char *wp, int c) ; break; case CSUBST: + wdscan_csubst: wp++; if (c == CSUBST && nest == 0) return (wp); @@ -807,6 +816,10 @@ dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel) shf_puts("EOS", shf); return (--wp); case ADELIM: + if (*wp == /*{*/'}') { + shf_puts("]ADELIM(})", shf); + return (wp + 1); + } shf_puts("ADELIM=", shf); if (0) case CHAR: From 1b0e4f54cbe25b9801e97c7430ec21f50a3c7cc2 Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 14 Jan 2016 22:49:33 +0000 Subject: [PATCH 14/21] =?UTF-8?q?permit=20'read=20-A/-a=20arr[idx]'=20as?= =?UTF-8?q?=20long=20as=20only=20one=20element=20is=20read;=20fix=20corrup?= =?UTF-8?q?tion=20of=20array=20indic=C4=93s=20with=20this=20construct=20(L?= =?UTF-8?q?P#1533396)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- funcs.c | 26 ++++++++++++++++++++------ sh.h | 6 ++++-- var.c | 6 ++++-- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/funcs.c b/funcs.c index 07bd026..c20519a 100644 --- a/funcs.c +++ b/funcs.c @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.289 2016/01/13 17:20:49 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.290 2016/01/14 22:49:31 tg Exp $"); #if HAVE_KILLPG /* @@ -1851,13 +1851,15 @@ c_read(const char **wp) enum { LINES, BYTES, UPTO, READALL } readmode = LINES; char delim = '\n'; size_t bytesleft = 128, bytesread; - struct tbl *vp /* FU gcc */ = NULL, *vq; + struct tbl *vp /* FU gcc */ = NULL, *vq = NULL; char *cp, *allocd = NULL, *xp; const char *ccp; XString xs; size_t xsave = 0; mksh_ttyst tios; bool restore_tios = false; + /* to catch read -aN2 foo[i] */ + bool subarray = false; #if HAVE_SELECT bool hastimeout = false; struct timeval tv, tvlim; @@ -2102,6 +2104,7 @@ c_read(const char **wp) XinitN(xs, 128, ATEMP); if (intoarray) { vp = global(*wp); + subarray = last_lookup_was_array; if (vp->flag & RDONLY) { c_read_splitro: bi_errorf("read-only: %s", *wp); @@ -2110,10 +2113,10 @@ c_read(const char **wp) afree(cp, ATEMP); goto c_read_out; } - /* exporting an array is currently pointless */ - unset(vp, 1); /* counter for array index */ - c = 0; + c = subarray ? arrayindex(vp) : 0; + /* exporting an array is currently pointless */ + unset(vp, subarray ? 0 : 1); } if (!aschars) { /* skip initial IFS whitespace */ @@ -2215,7 +2218,18 @@ c_read(const char **wp) c_read_gotword: Xput(xs, xp, '\0'); if (intoarray) { - vq = arraysearch(vp, c++); + if (subarray) { + /* array element passed, accept first read */ + if (vq) { + bi_errorf("nested arrays not yet supported"); + goto c_read_spliterr; + } + vq = vp; + if (c) + /* [0] doesn't */ + vq->flag |= AINDEX; + } else + vq = arraysearch(vp, c++); } else { vq = global(*wp); /* must be checked before exporting */ diff --git a/sh.h b/sh.h index 5d8c0ac..1fb56ca 100644 --- a/sh.h +++ b/sh.h @@ -10,7 +10,7 @@ /*- * Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2014, 2015 + * 2011, 2012, 2013, 2014, 2015, 2016 * mirabilos * * Provided that these terms and disclaimer and all copyright notices @@ -175,7 +175,7 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.753 2016/01/13 17:20:52 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.754 2016/01/14 22:49:32 tg Exp $"); #endif #define MKSH_VERSION "R52 2016/01/13" @@ -1186,6 +1186,8 @@ struct tbl { }; EXTERN struct tbl vtemp; +/* set by global() and local() */ +EXTERN bool last_lookup_was_array; /* common flag bits */ #define ALLOC BIT(0) /* val.s has been allocated */ diff --git a/var.c b/var.c index 58551e8..d816eb1 100644 --- a/var.c +++ b/var.c @@ -28,7 +28,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/var.c,v 1.196 2016/01/14 20:21:39 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/var.c,v 1.197 2016/01/14 22:49:33 tg Exp $"); /*- * Variables @@ -295,6 +295,7 @@ global(const char *n) if (special(vn)) vp->flag |= SPECIAL; out: + last_lookup_was_array = array; if (vn != n) afree(vname.rw, ATEMP); return (vp); @@ -345,6 +346,7 @@ local(const char *n, bool copy) if (special(vn)) vp->flag |= SPECIAL; out: + last_lookup_was_array = array; if (vn != n) afree(vname.rw, ATEMP); return (vp); @@ -1486,7 +1488,7 @@ arrayname(const char *str) const char *p; char *rv; - if ((p = cstrchr(str, '[')) == 0) + if (!(p = cstrchr(str, '['))) /* Shouldn't happen, but why worry? */ strdupx(rv, str, ATEMP); else From c51e067e62e4c4f72461eb1c07dd263a457ed2a2 Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 14 Jan 2016 23:18:11 +0000 Subject: [PATCH 15/21] incorporate more feedback from schily --- histrap.c | 6 +++--- jobs.c | 11 ++++------- mksh.1 | 11 ++++++++--- sh.h | 6 ++++-- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/histrap.c b/histrap.c index eae9e9d..57f2124 100644 --- a/histrap.c +++ b/histrap.c @@ -3,7 +3,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2014, 2015 + * 2011, 2012, 2014, 2015, 2016 * mirabilos * * 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.151 2015/11/29 17:05:01 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.152 2016/01/14 23:18:08 tg Exp $"); Trap sigtraps[ksh_NSIG + 1]; static struct sigaction Sigact_ign; @@ -1213,7 +1213,7 @@ fatal_trap_check(void) do { if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL))) /* return value is used as an exit code */ - return (128 + p->signal); + return (ksh_sigmask(p->signal)); ++p; } while (--i); return (0); diff --git a/jobs.c b/jobs.c index 0e355a9..0cecdc5 100644 --- a/jobs.c +++ b/jobs.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, - * 2012, 2013, 2014, 2015 + * 2012, 2013, 2014, 2015, 2016 * mirabilos * * 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.116 2015/10/09 16:11:15 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.117 2016/01/14 23:18:09 tg Exp $"); #if HAVE_KILLPG #define mksh_killpg killpg @@ -215,14 +215,11 @@ j_init(void) static int proc_errorlevel(Proc *p) { - int termsig; - switch (p->state) { case PEXITED: return ((WEXITSTATUS(p->status)) & 255); case PSIGNALLED: - termsig = WTERMSIG(p->status); - return ((termsig < 1 || termsig > 127) ? 255 : 128 + termsig); + return (ksh_sigmask(WTERMSIG(p->status))); default: return (0); } @@ -756,7 +753,7 @@ waitfor(const char *cp, int *sigp) if (rv < 0) /* we were interrupted */ - *sigp = 128 + -rv; + *sigp = ksh_sigmask(-rv); return (rv); } diff --git a/mksh.1 b/mksh.1 index 72da56d..4e056e4 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.386 2016/01/13 17:20:50 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.387 2016/01/14 23:18:09 tg Exp $ .\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, @@ -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: January 13 2016 $ +.Dd $Mdocdate: January 14 2016 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" @@ -179,6 +179,11 @@ script use. Its command language is a superset of the .Xr sh C shell language and largely compatible to the original Korn shell. +At times, this manual page may give scripting advice; while it +sometimes does take portable shell scripting or various standards +into account all information is first and foremost presented with +.Nm +in mind and should be taken as such. .Ss I'm an Android user, so what's mksh? .Nm mksh is a @@ -1744,7 +1749,7 @@ command below for a list of options). The exit status of the last non-asynchronous command executed. If the last command was killed by a signal, .Ic $?\& -is set to 128 plus the signal number. +is set to 128 plus the signal number, but at most 255. .It Ev 0 The name of the shell, determined as follows: the first argument to diff --git a/sh.h b/sh.h index 1fb56ca..109596c 100644 --- a/sh.h +++ b/sh.h @@ -175,9 +175,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.754 2016/01/14 22:49:32 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.755 2016/01/14 23:18:11 tg Exp $"); #endif -#define MKSH_VERSION "R52 2016/01/13" +#define MKSH_VERSION "R52 2016/01/14" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES @@ -379,6 +379,8 @@ struct rusage { #define ksh_NSIG 64 #endif +#define ksh_sigmask(sig) (((sig) < 1 || (sig) > 127) ? 255 : 128 + (sig)) + /* OS-dependent additions (functions, variables, by OS) */ From 7181c9e40cd1b5a7182e1259cbf697c230dd4009 Mon Sep 17 00:00:00 2001 From: tg Date: Thu, 14 Jan 2016 23:19:12 +0000 Subject: [PATCH 16/21] =?UTF-8?q?somewhat=20surprisingly,=20we=20can=20do?= =?UTF-8?q?=20bashisms=20better=20than=20GNU=20bash=20now=20=E2=98=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- check.t | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/check.t b/check.t index 27fd81d..d9d0eea 100644 --- a/check.t +++ b/check.t @@ -1,8 +1,8 @@ -# $MirOS: src/bin/mksh/check.t,v 1.718 2016/01/13 17:20:46 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.719 2016/01/14 23:19:12 tg Exp $ # -*- mode: sh -*- #- # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011, 2012, 2013, 2014, 2015 +# 2011, 2012, 2013, 2014, 2015, 2016 # mirabilos # # Provided that these terms and disclaimer and all copyright notices @@ -30,7 +30,7 @@ # (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date expected-stdout: - @(#)MIRBSD KSH R52 2016/01/13 + @(#)MIRBSD KSH R52 2016/01/14 description: Check version of shell. stdin: @@ -39,7 +39,7 @@ name: KSH_VERSION category: shell:legacy-no --- expected-stdout: - @(#)LEGACY KSH R52 2016/01/13 + @(#)LEGACY KSH R52 2016/01/14 description: Check version of legacy shell. stdin: @@ -8515,7 +8515,7 @@ expected-stdout: name: varexpand-substr-3 description: Check that some things that work in bash fail. - This is by design. And that some things fail in both. + This is by design. Oh and vice versa, nowadays. stdin: export x=abcdefghi n=2 "$__progname" -c 'echo v${x:(n)}x' @@ -8523,12 +8523,13 @@ stdin: "$__progname" -c 'echo x${x:n}x' "$__progname" -c 'echo y${x:}x' "$__progname" -c 'echo z${x}x' + # next fails only in bash "$__progname" -c 'x=abcdef;y=123;echo ${x:${y:2:1}:2}' >/dev/null 2>&1; echo $? expected-stdout: vcdefghix wcdefghix zabcdefghix - 1 + 0 expected-stderr-pattern: /x:n.*bad substitution.*\n.*bad substitution/ --- From 44be0bdb0b249ad48f9ae85f017a66e8b487670d Mon Sep 17 00:00:00 2001 From: tg Date: Tue, 19 Jan 2016 23:09:48 +0000 Subject: [PATCH 17/21] =?UTF-8?q?deliberately=20revert=20from=20POSIX=20to?= =?UTF-8?q?=20classical=20behaviour=20for=20"=E2=80=A6`=E2=80=A6\"?= =?UTF-8?q?=E2=80=A6\"=E2=80=A6`=E2=80=A6"=20until=20http://austingroupbug?= =?UTF-8?q?s.net/view.php=3Fid=3D1015=20is=20resolved=20(either=20way),=20?= =?UTF-8?q?mksh=20R52=20regression;=20cf.=20Debian=20#810846,=20#811092?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lex.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lex.c b/lex.c index b552dfc..2b2cd0c 100644 --- a/lex.c +++ b/lex.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.215 2016/01/14 19:52:20 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.216 2016/01/19 23:09:48 tg Exp $"); /* * states while lexing word @@ -550,8 +550,10 @@ yylex(int cf) * undefined results occur.”). */ statep->ls_bool = false; +#ifdef austingroupbugs1015_is_still_not_resolved if (Flag(FPOSIX)) break; +#endif s2 = statep; base = state_info.base; while (/* CONSTCOND */ 1) { From 046d8e5b7ac1b0406a225987a3f359d1866098b4 Mon Sep 17 00:00:00 2001 From: tg Date: Tue, 19 Jan 2016 23:12:15 +0000 Subject: [PATCH 18/21] =?UTF-8?q?align=20with=20future=20POSIX=20on=20http?= =?UTF-8?q?://austingroupbugs.net/view.php=3Fid=3D351=20with=20accepted=20?= =?UTF-8?q?interpretation=20(*sigh*);=20merge=20VARASN|ARRAYVAR=E2=86=92CM?= =?UTF-8?q?DASN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- check.t | 20 ++++++++++++++++---- eval.c | 4 ++-- funcs.c | 4 ++-- lex.c | 6 +++--- sh.h | 13 +++++++------ syn.c | 40 +++++++++++++++++++++++++++------------- 6 files changed, 57 insertions(+), 30 deletions(-) diff --git a/check.t b/check.t index d9d0eea..133f4a6 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.719 2016/01/14 23:19:12 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.720 2016/01/19 23:12:10 tg Exp $ # -*- mode: sh -*- #- # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, @@ -30,7 +30,7 @@ # (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date expected-stdout: - @(#)MIRBSD KSH R52 2016/01/14 + @(#)MIRBSD KSH R52 2016/01/19 description: Check version of shell. stdin: @@ -39,7 +39,7 @@ name: KSH_VERSION category: shell:legacy-no --- expected-stdout: - @(#)LEGACY KSH R52 2016/01/14 + @(#)LEGACY KSH R52 2016/01/19 description: Check version of legacy shell. stdin: @@ -6592,12 +6592,24 @@ description: env-setup: !HOME=/sweet! stdin: echo ${A=a=}~ b=~ c=d~ ~ + export e=~ f=d~ + command command export g=~ h=d~ + echo ". $e . $f ." + echo ". $g . $h ." set -o posix - unset A + unset A e f g h echo ${A=a=}~ b=~ c=d~ ~ + export e=~ f=d~ + command command export g=~ h=d~ + echo ". $e . $f ." + echo ". $g . $h ." expected-stdout: a=/sweet b=/sweet c=d~ /sweet + . /sweet . d~ . + . /sweet . d~ . a=~ b=~ c=d~ /sweet + . /sweet . d~ . + . /sweet . d~ . --- name: tilde-expand-2 description: diff --git a/eval.c b/eval.c index ba89e79..3e670da 100644 --- a/eval.c +++ b/eval.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.179 2016/01/14 22:30:43 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.180 2016/01/19 23:12:12 tg Exp $"); /* * string expansion @@ -1324,7 +1324,7 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED) char *name; if ((io->ioflag & IOTYPE) != IOREAD) - errorf("%s: %s", "funny $() command", + errorf("%s: %s", T_funny_command, snptreef(NULL, 32, "%R", io)); shf = shf_open(name = evalstr(io->ioname, DOTILDE), O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC); diff --git a/funcs.c b/funcs.c index c20519a..01ed15f 100644 --- a/funcs.c +++ b/funcs.c @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.290 2016/01/14 22:49:31 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.291 2016/01/19 23:12:13 tg Exp $"); #if HAVE_KILLPG /* @@ -103,7 +103,7 @@ const struct builtin mkshbuiltins[] = { {"cd", c_cd}, /* dash compatibility hack */ {"chdir", c_cd}, - {"command", c_command}, + {Tcommand, c_command}, {"*=continue", c_brkcont}, {"echo", c_print}, {"*=eval", c_eval}, diff --git a/lex.c b/lex.c index 2b2cd0c..fc7177a 100644 --- a/lex.c +++ b/lex.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.216 2016/01/19 23:09:48 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.217 2016/01/19 23:12:14 tg Exp $"); /* * states while lexing word @@ -269,7 +269,7 @@ yylex(int cf) } /* FALLTHROUGH */ case SBASE: - if (c == '[' && (cf & (VARASN|ARRAYVAR))) { + if (c == '[' && (cf & CMDASN)) { /* temporary */ *wp = EOS; if (is_wdvarname(Xstring(ws, wp), false)) { @@ -1092,7 +1092,7 @@ yylex(int cf) } } else if (cf & ALIAS) { /* retain typeset et al. even when quoted */ - if (assign_command((dp = wdstrip(yylval.cp, 0)))) + if (assign_command((dp = wdstrip(yylval.cp, 0)), true)) strlcpy(ident, dp, sizeof(ident)); afree(dp, ATEMP); } diff --git a/sh.h b/sh.h index 109596c..ef54ec0 100644 --- a/sh.h +++ b/sh.h @@ -175,9 +175,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.755 2016/01/14 23:18:11 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.756 2016/01/19 23:12:14 tg Exp $"); #endif -#define MKSH_VERSION "R52 2016/01/14" +#define MKSH_VERSION "R52 2016/01/19" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES @@ -864,6 +864,8 @@ EXTERN const char Tgbuiltin[] E_INIT("=builtin"); #define Tbuiltin (Tgbuiltin + 1) /* "builtin" */ EXTERN const char T_function[] E_INIT(" function"); #define Tfunction (T_function + 1) /* "function" */ +EXTERN const char T_funny_command[] E_INIT("funny $() command"); +#define Tcommand (T_funny_command + 10) /* "command" */ EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n"); #define TC_IFSWS (TC_LEX1 + 7) /* space tab newline */ @@ -1632,13 +1634,12 @@ typedef union { #define ALIAS BIT(2) /* recognise alias */ #define KEYWORD BIT(3) /* recognise keywords */ #define LETEXPR BIT(4) /* get expression inside (( )) */ -#define VARASN BIT(5) /* check for var=word */ -#define ARRAYVAR BIT(6) /* parse x[1 & 2] as one word */ +#define CMDASN BIT(5) /* parse x[1 & 2] as one word, for typeset */ +#define HEREDOC BIT(6) /* parsing a here document body */ #define ESACONLY BIT(7) /* only accept esac keyword */ #define CMDWORD BIT(8) /* parsing simple command (alias related) */ #define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */ #define LQCHAR BIT(10) /* source string contains QCHAR */ -#define HEREDOC BIT(11) /* parsing a here document body */ #define HERES 10 /* max number of << in line */ @@ -1989,7 +1990,7 @@ char *shf_smprintf(const char *, ...) ssize_t shf_vfprintf(struct shf *, const char *, va_list) MKSH_A_FORMAT(__printf__, 2, 0); /* syn.c */ -int assign_command(const char *); +int assign_command(const char *, bool); void initkeywords(void); struct op *compile(Source *, bool); bool parse_usec(const char *, struct timeval *); diff --git a/syn.c b/syn.c index 6c787b8..ab32418 100644 --- a/syn.c +++ b/syn.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.108 2016/01/14 19:52:20 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.109 2016/01/19 23:12:15 tg Exp $"); struct nesting_state { int start_token; /* token than began nesting (eg, FOR) */ @@ -272,7 +272,6 @@ get_command(int cf) int c, iopn = 0, syniocf, lno; struct ioword *iop, **iops; XPtrV args, vars; - char *tcp; struct nesting_state old_nesting; /* NUFILE is small enough to leave this addition unchecked */ @@ -281,7 +280,7 @@ get_command(int cf) XPinit(vars, 16); syniocf = KEYWORD|sALIAS; - switch (c = token(cf|KEYWORD|sALIAS|VARASN)) { + switch (c = token(cf|KEYWORD|sALIAS|CMDASN)) { default: REJECT; afree(iops, ATEMP); @@ -296,9 +295,18 @@ get_command(int cf) syniocf &= ~(KEYWORD|sALIAS); t = newtp(TCOM); t->lineno = source->line; + goto get_command_begin; while (/* CONSTCOND */ 1) { - cf = (t->u.evalflags ? ARRAYVAR : 0) | - (XPsize(args) == 0 ? sALIAS|VARASN : CMDWORD); + bool check_assign_cmd; + + if (XPsize(args) == 0) { + get_command_begin: + check_assign_cmd = true; + cf = sALIAS | CMDASN; + } else if (t->u.evalflags) + cf = CMDWORD | CMDASN; + else + cf = CMDWORD; switch (tpeek(cf)) { case REDIR: while ((iop = synio(cf)) != NULL) { @@ -316,9 +324,12 @@ get_command(int cf) * dubious but AT&T ksh acts this way */ if (iopn == 0 && XPsize(vars) == 0 && - XPsize(args) == 0 && - assign_command(ident)) - t->u.evalflags = DOVACHECK; + check_assign_cmd) { + if (assign_command(ident, false)) + t->u.evalflags = DOVACHECK; + else if (strcmp(ident, Tcommand) != 0) + check_assign_cmd = false; + } if ((XPsize(args) == 0 || Flag(FKEYWORD)) && is_wdvarassign(yylval.cp)) XPput(vars, yylval.cp); @@ -329,6 +340,8 @@ get_command(int cf) case '(' /*)*/: if (XPsize(args) == 0 && XPsize(vars) == 1 && is_wdvarassign(yylval.cp)) { + char *tcp; + /* wdarrassign: foo=(bar) */ ACCEPT; @@ -432,7 +445,7 @@ get_command(int cf) case FOR: case SELECT: t = newtp((c == FOR) ? TFOR : TSELECT); - musthave(LWORD, ARRAYVAR); + musthave(LWORD, CMDASN); if (!is_wdvarname(yylval.cp, true)) yyerror("%s: %s\n", c == FOR ? "for" : Tselect, "bad identifier"); @@ -573,7 +586,7 @@ elsepart(void) { struct op *t; - switch (token(KEYWORD|sALIAS|VARASN)) { + switch (token(KEYWORD|sALIAS|CMDASN)) { case ELSE: if ((t = c_list(true)) == NULL) syntaxerr(NULL); @@ -944,13 +957,14 @@ compile(Source *s, bool skiputf8bom) * $ */ int -assign_command(const char *s) +assign_command(const char *s, bool docommand) { if (!*s) return (0); return ((strcmp(s, Talias) == 0) || (strcmp(s, Texport) == 0) || (strcmp(s, Treadonly) == 0) || + (docommand && (strcmp(s, Tcommand) == 0)) || (strcmp(s, Ttypeset) == 0)); } @@ -992,7 +1006,7 @@ static const char db_gthan[] = { CHAR, '>', EOS }; static Test_op dbtestp_isa(Test_env *te, Test_meta meta) { - int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN)); + int c = tpeek(CMDASN | (meta == TM_BINOP ? 0 : CONTIN)); bool uqword; char *save = NULL; Test_op ret = TO_NONOP; @@ -1038,7 +1052,7 @@ static const char * dbtestp_getopnd(Test_env *te, Test_op op MKSH_A_UNUSED, bool do_eval MKSH_A_UNUSED) { - int c = tpeek(ARRAYVAR); + int c = tpeek(CMDASN); if (c != LWORD) return (NULL); From 9167be0584f947911ec9e1943ba20ea5ff31de07 Mon Sep 17 00:00:00 2001 From: tg Date: Wed, 20 Jan 2016 20:29:48 +0000 Subject: [PATCH 19/21] handle SIGPIPE in built-in cat correctly (LP#1532621) --- funcs.c | 62 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/funcs.c b/funcs.c index 01ed15f..64b294c 100644 --- a/funcs.c +++ b/funcs.c @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.291 2016/01/19 23:12:13 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.292 2016/01/20 20:29:48 tg Exp $"); #if HAVE_KILLPG /* @@ -3669,10 +3669,11 @@ c_realpath(const char **wp) int c_cat(const char **wp) { - int fd = STDIN_FILENO, rv, eno; + int fd = STDIN_FILENO, rv; ssize_t n, w; const char *fn = ""; char *buf, *cp; + int opipe = 0; #define MKSH_CAT_BUFSIZ 4096 /* parse options: POSIX demands we support "-u" as no-op */ @@ -3694,54 +3695,64 @@ c_cat(const char **wp) return (1); } + /* catch SIGPIPE */ + opipe = block_pipe(); + do { if (*wp) { fn = *wp++; if (ksh_isdash(fn)) fd = STDIN_FILENO; else if ((fd = binopen2(fn, O_RDONLY)) < 0) { - eno = errno; - bi_errorf("%s: %s", fn, cstrerror(eno)); + bi_errorf("%s: %s", fn, cstrerror(errno)); rv = 1; continue; } } while (/* CONSTCOND */ 1) { - n = blocking_read(fd, (cp = buf), MKSH_CAT_BUFSIZ); - eno = errno; - /* give the user a chance to ^C out */ - intrcheck(); - if (n == -1) { - if (eno == EINTR) { + if ((n = blocking_read(fd, (cp = buf), + MKSH_CAT_BUFSIZ)) == -1) { + if (errno == EINTR) { + restore_pipe(opipe); + /* give the user a chance to ^C out */ + intrcheck(); /* interrupted, try again */ + opipe = block_pipe(); continue; } /* an error occured during reading */ - bi_errorf("%s: %s", fn, cstrerror(eno)); + bi_errorf("%s: %s", fn, cstrerror(errno)); rv = 1; break; } else if (n == 0) /* end of file reached */ 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) - /* interrupted, try again */ - continue; + if ((w = write(STDOUT_FILENO, cp, n)) != -1) { + n -= w; + cp += w; + continue; + } + if (errno == EINTR) { + restore_pipe(opipe); + /* give the user a chance to ^C out */ + intrcheck(); + /* interrupted, try again */ + opipe = block_pipe(); + continue; + } + if (errno == EPIPE) { + /* fake receiving signel */ + rv = ksh_sigmask(SIGPIPE); + } else { /* an error occured during writing */ bi_errorf("%s: %s", "", - cstrerror(eno)); + cstrerror(errno)); rv = 1; - if (fd != STDIN_FILENO) - close(fd); - goto out; } - n -= w; - cp += w; + if (fd != STDIN_FILENO) + close(fd); + goto out; } } if (fd != STDIN_FILENO) @@ -3749,6 +3760,7 @@ c_cat(const char **wp) } while (*wp); out: + restore_pipe(opipe); free_osfunc(buf); return (rv); } From 61f7661b9273408186832e8c1107644a51ccef80 Mon Sep 17 00:00:00 2001 From: tg Date: Wed, 20 Jan 2016 21:34:13 +0000 Subject: [PATCH 20/21] fix errno in print/echo builtin; optimise (with partial rewrite) --- check.t | 6 +-- funcs.c | 164 ++++++++++++++++++++++++++++++-------------------------- lex.c | 35 ++++-------- sh.h | 4 +- 4 files changed, 104 insertions(+), 105 deletions(-) diff --git a/check.t b/check.t index 133f4a6..98d260d 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.720 2016/01/19 23:12:10 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.721 2016/01/20 21:34:09 tg Exp $ # -*- mode: sh -*- #- # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, @@ -30,7 +30,7 @@ # (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date expected-stdout: - @(#)MIRBSD KSH R52 2016/01/19 + @(#)MIRBSD KSH R52 2016/01/20 description: Check version of shell. stdin: @@ -39,7 +39,7 @@ name: KSH_VERSION category: shell:legacy-no --- expected-stdout: - @(#)LEGACY KSH R52 2016/01/19 + @(#)LEGACY KSH R52 2016/01/20 description: Check version of legacy shell. stdin: diff --git a/funcs.c b/funcs.c index 64b294c..ab6e3b7 100644 --- a/funcs.c +++ b/funcs.c @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.292 2016/01/20 20:29:48 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.293 2016/01/20 21:34:11 tg Exp $"); #if HAVE_KILLPG /* @@ -278,20 +278,18 @@ static void s_put(int); int c_print(const char **wp) { -#define PO_NL BIT(0) /* print newline */ -#define PO_EXPAND BIT(1) /* expand backslash sequences */ -#define PO_PMINUSMINUS BIT(2) /* print a -- argument */ -#define PO_HIST BIT(3) /* print to history instead of stdout */ -#define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */ int fd = 1, c; - int flags = PO_EXPAND | PO_NL; - const char *s, *emsg; + const char *s; XString xs; char *xp; + /* print newline; expand backslash sequences */ + bool po_nl = true, po_exp = true; + /* print to history instead of file descriptor / stdout */ + bool po_hist = false; if (wp[0][0] == 'e') { - /* echo builtin */ - wp++; + /* "echo" builtin */ + ++wp; #ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT if (Flag(FSH)) { /* @@ -299,7 +297,7 @@ c_print(const char **wp) * one that supports -e but does not enable it by * default */ - flags = PO_NL; + po_exp = false; } #endif if (Flag(FPOSIX) || @@ -309,14 +307,14 @@ c_print(const char **wp) Flag(FAS_BUILTIN)) { /* Debian Policy 10.4 compliant "echo" builtin */ if (*wp && !strcmp(*wp, "-n")) { - /* we recognise "-n" only as the first arg */ - flags = 0; - wp++; - } else - /* otherwise, we print everything as-is */ - flags = PO_NL; + /* recognise "-n" only as the first arg */ + po_nl = false; + ++wp; + } + /* print everything as-is */ + po_exp = false; } else { - int nflags = flags; + bool new_exp = po_exp, new_nl = po_nl; /** * a compromise between sysV and BSD echo commands: @@ -329,62 +327,65 @@ c_print(const char **wp) * quences are enabled by default. */ - while ((s = *wp) && *s == '-' && s[1]) { - while (*++s) - if (*s == 'n') - nflags &= ~PO_NL; - else if (*s == 'e') - nflags |= PO_EXPAND; - else if (*s == 'E') - nflags &= ~PO_EXPAND; - else - /* - * bad option: don't use - * nflags, print argument - */ - break; - - if (*s) - break; - wp++; - flags = nflags; + print_tradparse_arg: + if ((s = *wp) && *s++ == '-' && *s) { + print_tradparse_ch: + switch ((c = *s++)) { + case 'E': + new_exp = false; + goto print_tradparse_ch; + case 'e': + new_exp = true; + goto print_tradparse_ch; + case 'n': + new_nl = false; + goto print_tradparse_ch; + case '\0': + po_exp = new_exp; + po_nl = new_nl; + ++wp; + goto print_tradparse_arg; + } } } } else { - int optc; - const char *opts = "Rnprsu,"; + /* "print" builtin */ + const char *opts = "npRrsu,"; + const char *emsg; + /* print a "--" argument */ + bool po_pminusminus = false; - while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) - switch (optc) { - case 'R': - /* fake BSD echo command */ - flags |= PO_PMINUSMINUS; - flags &= ~PO_EXPAND; - opts = "ne"; - break; + while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1) + switch (c) { case 'e': - flags |= PO_EXPAND; + po_exp = true; break; case 'n': - flags &= ~PO_NL; + po_nl = false; break; case 'p': if ((fd = coproc_getfd(W_OK, &emsg)) < 0) { - bi_errorf("%s: %s", "-p", emsg); + bi_errorf("-p: %s", emsg); return (1); } break; + case 'R': + /* fake BSD echo command */ + po_pminusminus = true; + po_exp = false; + opts = "en"; + break; case 'r': - flags &= ~PO_EXPAND; + po_exp = false; break; case 's': - flags |= PO_HIST; + po_hist = true; break; case 'u': if (!*(s = builtin_opt.optarg)) fd = 0; else if ((fd = check_fd(s, W_OK, &emsg)) < 0) { - bi_errorf("%s: %s: %s", "-u", s, emsg); + bi_errorf("-u%s: %s", s, emsg); return (1); } break; @@ -393,22 +394,23 @@ c_print(const char **wp) } if (!(builtin_opt.info & GI_MINUSMINUS)) { - /* treat a lone - like -- */ + /* treat a lone "-" like "--" */ if (wp[builtin_opt.optind] && ksh_isdash(wp[builtin_opt.optind])) builtin_opt.optind++; - } else if (flags & PO_PMINUSMINUS) - builtin_opt.optind--; + } else if (po_pminusminus) + builtin_opt.optind--; wp += builtin_opt.optind; } Xinit(xs, xp, 128, ATEMP); - while (*wp != NULL) { + if (*wp != NULL) { + print_read_arg: s = *wp; while ((c = *s++) != '\0') { Xcheck(xs, xp); - if ((flags & PO_EXPAND) && c == '\\') { + if (po_exp && c == '\\') { s_ptr = s; c = unbksl(false, s_get, s_put); s = s_ptr; @@ -416,11 +418,11 @@ c_print(const char **wp) /* rejected by generic function */ switch ((c = *s++)) { case 'c': - flags &= ~PO_NL; + po_nl = false; /* AT&T brain damage */ continue; case '\0': - s--; + --s; c = '\\'; break; default: @@ -440,18 +442,22 @@ c_print(const char **wp) } Xput(xs, xp, c); } - if (*++wp != NULL) + if (*++wp != NULL) { Xput(xs, xp, ' '); + goto print_read_arg; + } } - if (flags & PO_NL) + if (po_nl) Xput(xs, xp, '\n'); - if (flags & PO_HIST) { + c = 0; + if (po_hist) { Xput(xs, xp, '\0'); histsave(&source->line, Xstring(xs, xp), HIST_STORE, false); Xfree(xs, xp); } else { - int len = Xlength(xs, xp); + size_t len = Xlength(xs, xp); + bool po_coproc = false; int opipe = 0; /* @@ -461,30 +467,36 @@ c_print(const char **wp) * not enough). */ if (coproc.write >= 0 && coproc.write == fd) { - flags |= PO_COPROC; + po_coproc = true; opipe = block_pipe(); } - for (s = Xstring(xs, xp); len > 0; ) { - if ((c = write(fd, s, len)) < 0) { - if (flags & PO_COPROC) - restore_pipe(opipe); + + s = Xstring(xs, xp); + while (len > 0) { + ssize_t nwritten; + + if ((nwritten = write(fd, s, len)) < 0) { if (errno == EINTR) { - /* allow user to ^C out */ + if (po_coproc) + restore_pipe(opipe); + /* give the user a chance to ^C out */ intrcheck(); - if (flags & PO_COPROC) + /* interrupted, try again */ + if (po_coproc) opipe = block_pipe(); continue; } - return (1); + c = 1; + break; } - s += c; - len -= c; + s += nwritten; + len -= nwritten; } - if (flags & PO_COPROC) + if (po_coproc) restore_pipe(opipe); } - return (0); + return (c); } static int diff --git a/lex.c b/lex.c index fc7177a..e5305ae 100644 --- a/lex.c +++ b/lex.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.217 2016/01/19 23:12:14 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.218 2016/01/20 21:34:12 tg Exp $"); /* * states while lexing word @@ -94,8 +94,7 @@ static void ungetsc_i(int); static int getsc_uu(void); static void getsc_line(Source *); static int getsc_bn(void); -static int s_get(void); -static void s_put(int); +static int getsc_i(void); static char *get_brace_var(XString *, char *); static bool arraysub(char **); static void gethere(void); @@ -112,7 +111,7 @@ static int ignore_backslash_newline; #define o_getsc_u() ((*source->str != '\0') ? *source->str++ : getsc_uu()) /* retrace helper */ -#define o_getsc_r(carg) { \ +#define o_getsc_r(carg) \ int cev = (carg); \ struct sretrace_info *rp = retrace_info; \ \ @@ -122,17 +121,17 @@ static int ignore_backslash_newline; rp = rp->next; \ } \ \ - return (cev); \ -} - -#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST) -static int getsc(void); + return (cev); +/* callback */ static int -getsc(void) +getsc_i(void) { o_getsc_r(o_getsc()); } + +#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST) +#define getsc getsc_i #else static int getsc_r(int); @@ -590,8 +589,8 @@ yylex(int cf) *wp++ = CQUOTE; ignore_backslash_newline--; } else if (c == '\\') { - if ((c2 = unbksl(true, s_get, s_put)) == -1) - c2 = s_get(); + if ((c2 = unbksl(true, getsc_i, ungetsc)) == -1) + c2 = getsc(); if (c2 == 0) statep->ls_bool = true; if (!statep->ls_bool) { @@ -1787,15 +1786,3 @@ pop_state_i(State_info *si, Lex_state *old_end) return (si->base + STATE_BSIZE - 1); } - -static int -s_get(void) -{ - return (getsc()); -} - -static void -s_put(int c) -{ - ungetsc(c); -} diff --git a/sh.h b/sh.h index ef54ec0..239cc23 100644 --- a/sh.h +++ b/sh.h @@ -175,9 +175,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.756 2016/01/19 23:12:14 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.757 2016/01/20 21:34:13 tg Exp $"); #endif -#define MKSH_VERSION "R52 2016/01/19" +#define MKSH_VERSION "R52 2016/01/20" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES From 91ae6ad199035b1cfa2589592cbca1570b4c1c4f Mon Sep 17 00:00:00 2001 From: tg Date: Wed, 20 Jan 2016 22:04:54 +0000 Subject: [PATCH 21/21] update --- mksh.1 | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/mksh.1 b/mksh.1 index 4e056e4..923c721 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.387 2016/01/14 23:18:09 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.388 2016/01/20 22:04:54 tg Exp $ .\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, @@ -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: January 14 2016 $ +.Dd $Mdocdate: January 20 2016 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" @@ -439,7 +439,7 @@ Whitespace and meta-characters can be quoted individually using a backslash or in groups using double .Pq Sq \&" or single -.Pq Sq \*(aq +.Pq Dq \*(aq quotes. Note that the following characters are also treated specially by the shell and must be quoted if they are to represent themselves: @@ -993,7 +993,7 @@ case both the .Ql \e and the newline are stripped. Second, a single quote -.Pq Sq \*(aq +.Pq Dq \*(aq quotes everything up to the next single quote (this may span lines). Third, a double quote .Pq Sq \&" @@ -1006,8 +1006,8 @@ up to the next unquoted double quote. .Ql $ and .Ql \` -inside double quotes have their usual meaning (i.e. parameter, command, or -arithmetic substitution) except no field splitting is carried out on the +inside double quotes have their usual meaning (i.e. parameter, arithmetic, +or command substitution) except no field splitting is carried out on the results of double-quoted substitutions. If a .Ql \e @@ -1031,7 +1031,9 @@ characters inside can be escaped and do not terminate the string then); the expanded result is treated as any other single-quoted string. If a double-quoted string is preceded by an unquoted .Ql $ , -the latter is ignored. +the +.Ql $ +is simply ignored. .Ss Backslash expansion In places where backslashes are expanded, certain C and .At @@ -1291,6 +1293,8 @@ command which is run in a subshell. For .Pf $( Ns Ar command Ns \&) and +.Pf ${\*(Ba\& Ns Ar command Ns \&;} +and .Pf ${\ \& Ar command Ns \&;} substitutions, normal quoting rules are used when .Ar command @@ -1301,6 +1305,8 @@ form, a followed by any of .Ql $ , .Ql \` , +.Ql \&" +.Pq currently, and violating Tn POSIX , or .Ql \e is stripped (a @@ -6588,8 +6594,20 @@ when multiple shells are accessing the file; the rollover process for the in-memory portion of the history is slow, should use .Xr memmove 3 . .Pp +Handling of backslash plus double-quote inside the (deprecated) +.Pf \` Ns Ar command Ns \` +form of command substitution when the substitution itself is +also inside double quotes currently deliberately violates +.Tn POSIX +even in +.Fl o Ic posix +mode until Austin group bug 1015 has been resolved either way, +as the current wording of the standard prohibits the current +and historic practice of several shells which several scripts +(admittedly wrongly) depend on. +.Pp This document attempts to describe -.Nm mksh\ R52 +.Nm mksh\ R52b and up, .\" with vendor patches from insert-your-name-here, compiled without any options impacting functionality, such as