Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package dash for openSUSE:Factory checked in at 2026-10-03 20:13:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/dash (Old) and /work/SRC/openSUSE:Factory/.dash.new.1631729 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "dash" Sat Oct 3 20:13:07 2026 rev:34 rq:1382147 version:0.5.13.5 Changes: -------- --- /work/SRC/openSUSE:Factory/dash/dash.changes 2026-06-29 17:30:49.670991487 +0200 +++ /work/SRC/openSUSE:Factory/.dash.new.1631729/dash.changes 2026-10-03 20:13:08.479616987 +0200 @@ -1,0 +2,23 @@ +Fri Oct 2 15:46:12 UTC 2026 - Dirk Müller <[email protected]> + +- add CVE-2026-102474.patch (bsc#1283151, CVE-2026-102474) + +------------------------------------------------------------------- +Tue Sep 29 14:14:41 UTC 2026 - Dirk Müller <[email protected]> + +- update to 0.5.13.5: + * builtin: Add CTLESC before all CCTLs in dollar single quote + * input: Fix overeager NUL deletion in SMALL mode + * var: Call setlocale when LC variables are set + * var: Remove unset check in varnull + * var: Restore double NUL on unset variables + * parser: Do not print prompt if input buffer is not empty + * parser: Use USTPUTC in parsebackq + * parser: Print escapes for command substitution in EOF marker + * parser: Clamp backslash-c sequences to 7 bits + * man: Use proper grave accent character + * man: Use literal > and < characters + * builtin: Fix unaligned access in conv_escape + * builtin: Fix octal escapes in dollar-single-quotes + +------------------------------------------------------------------- @@ -4 +27 @@ -- update to 0.15.3.4 (bsc#1269494, CVE-2026-31323): +- update to 0.5.13.4 (bsc#1269494, CVE-2026-31323): @@ -19 +42 @@ -- Update to 0.15.3.1 +- Update to 0.5.13.1 Old: ---- dash-0.5.13.4.tar.gz New: ---- CVE-2026-102474.patch dash-0.5.13.5.tar.gz ----------(New B)---------- New: - add CVE-2026-102474.patch (bsc#1283151, CVE-2026-102474) ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ dash.spec ++++++ --- /var/tmp/diff_new_pack.IjrxeX/_old 2026-10-03 20:13:09.282650610 +0200 +++ /var/tmp/diff_new_pack.IjrxeX/_new 2026-10-03 20:13:09.284650694 +0200 @@ -18,13 +18,14 @@ Name: dash -Version: 0.5.13.4 +Version: 0.5.13.5 Release: 0 Summary: POSIX-compliant Implementation of /bin/sh License: BSD-3-Clause AND GPL-2.0-or-later Group: System/Shells URL: http://gondor.apana.org.au/~herbert/dash/ Source0: http://gondor.apana.org.au/~herbert/dash/files/%{name}-%{version}.tar.gz +Patch1: CVE-2026-102474.patch BuildRequires: pkgconfig BuildRequires: pkgconfig(libedit) ++++++ CVE-2026-102474.patch ++++++ --- dash-0.5.13.5/src/bltin/printf.c +++ dash-0.5.13.5/src/bltin/printf.c @@ -169,7 +169,7 @@ char *cp; STARTSTACKSTR(cp); - CHECKSTRSPACE(4, cp); + CHECKSTRSPACE(8, cp); ret = conv_escape(fmt, cp, false); fmt += ret >> 4; out1mem(cp, ret & 15); @@ -290,7 +290,7 @@ unsigned ret; int ch; - CHECKSTRSPACE(4, cp); + CHECKSTRSPACE(8, cp); c = *str++; if (c != '\\') { ++++++ dash-0.5.13.4.tar.gz -> dash-0.5.13.5.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dash-0.5.13.4/configure new/dash-0.5.13.5/configure --- old/dash-0.5.13.4/configure 2026-05-09 04:59:28.000000000 +0200 +++ new/dash-0.5.13.5/configure 2026-07-18 00:24:51.000000000 +0200 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for dash 0.5.13.4. +# Generated by GNU Autoconf 2.72 for dash 0.5.13.5. # # # Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, @@ -601,8 +601,8 @@ # Identity of this package. PACKAGE_NAME='dash' PACKAGE_TARNAME='dash' -PACKAGE_VERSION='0.5.13.4' -PACKAGE_STRING='dash 0.5.13.4' +PACKAGE_VERSION='0.5.13.5' +PACKAGE_STRING='dash 0.5.13.5' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1302,7 +1302,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures dash 0.5.13.4 to adapt to many kinds of systems. +'configure' configures dash 0.5.13.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1369,7 +1369,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of dash 0.5.13.4:";; + short | recursive ) echo "Configuration of dash 0.5.13.5:";; esac cat <<\_ACEOF @@ -1474,7 +1474,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -dash configure 0.5.13.4 +dash configure 0.5.13.5 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -1991,7 +1991,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by dash $as_me 0.5.13.4, which was +It was created by dash $as_me 0.5.13.5, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -3466,7 +3466,7 @@ # Define the identity of the package. PACKAGE='dash' - VERSION='0.5.13.4' + VERSION='0.5.13.5' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -6294,7 +6294,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by dash $as_me 0.5.13.4, which was +This file was extended by dash $as_me 0.5.13.5, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6362,7 +6362,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -dash config.status 0.5.13.4 +dash config.status 0.5.13.5 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dash-0.5.13.4/configure.ac new/dash-0.5.13.5/configure.ac --- old/dash-0.5.13.4/configure.ac 2026-05-09 04:55:05.000000000 +0200 +++ new/dash-0.5.13.5/configure.ac 2026-07-18 00:23:59.000000000 +0200 @@ -1,4 +1,4 @@ -AC_INIT([dash],[0.5.13.4]) +AC_INIT([dash],[0.5.13.5]) AM_INIT_AUTOMAKE([foreign subdir-objects]) AC_CONFIG_SRCDIR([src/main.c]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dash-0.5.13.4/src/bltin/printf.c new/dash-0.5.13.5/src/bltin/printf.c --- old/dash-0.5.13.4/src/bltin/printf.c 2025-10-11 15:07:39.000000000 +0200 +++ new/dash-0.5.13.5/src/bltin/printf.c 2026-07-18 00:15:01.000000000 +0200 @@ -56,6 +56,7 @@ #include "bltin.h" #include "parser.h" +#include "syntax.h" #include "system.h" #define PF(f, func) { \ @@ -332,6 +333,7 @@ char *out = out0; char *str = str0; unsigned value; + int och; int ch; ch = *str; @@ -349,7 +351,7 @@ value = '\\'; - if (isodigit(ch)) { + if (unlikely(isodigit(ch))) { ch = 3; value = 0; do { @@ -359,12 +361,22 @@ } str--; + +check_value: + if (SQSYNTAX[(signed char)value] != CCTL) + break; + /* fall through */ + + case '\\': + if (mbchar) + USTPUTC(CTLESC, out); break; case 'x': ch = 2; hex: + och = ch; value = 0; do { int c = *++str; @@ -388,8 +400,11 @@ value += d; } while (--ch); + if (och <= 2) + goto check_value; + if (value < 0x80) - break; + goto check_value; if (value < 0x110000) { int mboff = (mbchar - 1) * 2; @@ -419,7 +434,7 @@ USTPUTC(CTLMBCHAR, out); USTPUTC(len, out); STADJUST(mboff, out); - *(uint32_t *)out = value; + memcpy(out, &value, 4); STADJUST(len, out); USTPUTC(len, out); USTPUTC(CTLMBCHAR, out); @@ -432,9 +447,6 @@ ch = 4; goto hex; - case '\\': - break; - case 'a': /* alert */ case 'b': /* backspace */ case 'f': /* form-feed */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dash-0.5.13.4/src/dash.1 new/dash-0.5.13.5/src/dash.1 --- old/dash-0.5.13.4/src/dash.1 2025-09-23 13:07:58.000000000 +0200 +++ new/dash-0.5.13.5/src/dash.1 2026-06-07 07:20:12.000000000 +0200 @@ -197,7 +197,7 @@ set from the remaining argument operands. .It Fl C Em noclobber Don't overwrite existing files with -.Dq \*[Gt] . +.Dq > . .It Fl e Em errexit If not interactive, exit immediately if any untested command fails. The exit status of a command is considered to be @@ -268,9 +268,9 @@ Following is a list of operators: .Bl -ohang -offset indent .It "Control operators:" -.Dl & && \&( \&) \&; ;; | || \*[Lt]newline\*[Gt] +.Dl & && \&( \&) \&; ;; | || <newline> .It "Redirection operators:" -.Dl \*[Lt] \*[Gt] \*[Gt]| \*[Lt]\*[Lt] \*[Gt]\*[Gt] \*[Lt]& \*[Gt]& \*[Lt]\*[Lt]- \*[Lt]\*[Gt] +.Dl < > >| << >> <& >& <<- <> .El .Ss Quoting Quoting is used to remove the special meaning of certain characters or @@ -293,12 +293,12 @@ meaning of all characters except dollarsign .Pq $ , backquote -.Pq ` , +.Pq \(ga , and backslash .Pq \e . The backslash inside double quotes is historically weird, and serves to quote only the following characters: -.Dl $ ` \*q \e \*[Lt]newline\*[Gt] . +.Dl $ \(ga \*q \e <newline> . Otherwise it remains literal. .Ss Reserved Words Reserved words are words that have special meaning to the @@ -391,25 +391,25 @@ .Sq Bq 3 ) , that refers to a file descriptor. .Bl -tag -width aaabsfiles -offset indent -.It [n] Ns \*[Gt] file +.It [n] Ns > file Redirect standard output (or n) to file. -.It [n] Ns \*[Gt]| file +.It [n] Ns >| file Same, but override the .Fl C option. -.It [n] Ns \*[Gt]\*[Gt] file +.It [n] Ns >> file Append standard output (or n) to file. -.It [n] Ns \*[Lt] file +.It [n] Ns < file Redirect standard input (or n) from file. -.It [n1] Ns \*[Lt]& Ns n2 +.It [n1] Ns <& Ns n2 Copy file descriptor n2 as stdin (or fd n1). -.It [n] Ns \*[Lt]&- +.It [n] Ns <&- Close standard input (or n). -.It [n1] Ns \*[Gt]& Ns n2 +.It [n1] Ns >& Ns n2 Copy file descriptor n2 as stdout (or fd n1). -.It [n] Ns \*[Gt]&- +.It [n] Ns >&- Close standard output (or n). -.It [n] Ns \*[Lt]\*[Gt] file +.It [n] Ns <> file Open file for reading and writing on standard input (or n). .El .Pp @@ -417,7 +417,7 @@ .Dq here-document . .Bl -item -offset indent .It -.Li [n]\*[Lt]\*[Lt] delimiter +.Li [n]<< delimiter .Dl here-doc-text ... .Li delimiter .El @@ -431,9 +431,9 @@ expansion (as described in the section on .Dq Expansions ) . If the operator is -.Dq \*[Lt]\*[Lt]- +.Dq <<- instead of -.Dq \*[Lt]\*[Lt] , +.Dq << , then leading tabs in the here-doc-text are stripped. .Ss Search and Execution There are three types of commands: shell functions, builtin commands, and @@ -567,7 +567,7 @@ takes place before redirection, it can be modified by redirection. For example: .Pp -.Dl $ command1 2\*[Gt]&1 | command2 +.Dl $ command1 2>&1 | command2 .Pp sends both the standard output and standard error of command1 to the standard input of command2. @@ -698,7 +698,7 @@ their output as though they were one program: .\".Pp .Bd -literal -offset indent -{ printf \*q hello \*q ; printf \*q world\\n" ; } \*[Gt] greeting +{ printf \*q hello \*q ; printf \*q world\\n" ; } > greeting .Ed .Pp Note that @@ -764,7 +764,7 @@ A parameter can also be denoted by a number or a special character as explained below. .Ss Positional Parameters -A positional parameter is a parameter denoted by a number (n \*[Gt] 0). +A positional parameter is a parameter denoted by a number (n > 0). The shell sets these initially to the values of its command line arguments that follow the name of the shell script. The @@ -983,7 +983,7 @@ version .Pc : .Pp -.Dl `command` +.Dl \(gacommand\(ga .Pp The shell expands the command substitution by executing command in a subshell environment and replacing the command substitution with the @@ -1627,19 +1627,19 @@ The characters and their meanings are as follows: .Bl -tag -width Ds -offset indent .It Cm \ea -Write a \*[Lt]bell\*[Gt] character. +Write a <bell> character. .It Cm \eb -Write a \*[Lt]backspace\*[Gt] character. +Write a <backspace> character. .It Cm \ef -Write a \*[Lt]form-feed\*[Gt] character. +Write a <form-feed> character. .It Cm \en -Write a \*[Lt]new-line\*[Gt] character. +Write a <new-line> character. .It Cm \er -Write a \*[Lt]carriage return\*[Gt] character. +Write a <carriage return> character. .It Cm \et -Write a \*[Lt]tab\*[Gt] character. +Write a <tab> character. .It Cm \ev -Write a \*[Lt]vertical tab\*[Gt] character. +Write a <vertical tab> character. .It Cm \e\e Write a backslash character. .It Cm \e Ns Ar num @@ -2062,13 +2062,13 @@ and .Ar \&s\&2 are not identical. -.It Ar \&s\&1 Cm \&\*[Lt] Ar \&s\&2 +.It Ar \&s\&1 Cm \&< Ar \&s\&2 True if string .Ar \&s\&1 comes before .Ar \&s\&2 based on the ASCII value of their characters. -.It Ar \&s\&1 Cm \&\*[Gt] Ar \&s\&2 +.It Ar \&s\&1 Cm \&> Ar \&s\&2 True if string .Ar \&s\&1 comes after @@ -2380,7 +2380,7 @@ .Dq #\ . .It Ev PS2 The secondary prompt string, which defaults to -.Dq \*[Gt]\ . +.Dq >\ . .It Ev PS4 Output before each line when execution trace (set -x) is enabled, defaults to diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dash-0.5.13.4/src/input.c new/dash-0.5.13.5/src/input.c --- old/dash-0.5.13.4/src/input.c 2026-05-09 04:54:18.000000000 +0200 +++ new/dash-0.5.13.5/src/input.c 2026-07-05 07:17:02.000000000 +0200 @@ -217,39 +217,47 @@ } -static int __pgetc(void) +/* + * Read a character from the script, returning PEOF on end of file. + * Nul characters in the input are silently discarded. + */ + +int __attribute__((noinline)) pgetc(void) { + struct strpush *sp = parsefile->spfree; int c; + if (unlikely(sp)) + freestrings(sp); + +again: if (parsefile->unget) { long unget = -(long)(unsigned)parsefile->unget--; - return parsefile->nextc[unget]; + return (signed char)parsefile->nextc[unget]; } - if (parsefile->nleft > 0) { +nextc: + if (likely(parsefile->nleft > 0)) { parsefile->nleft--; c = (signed char)*parsefile->nextc++; + } else if (unlikely(parsefile->strpush)) { + popstring(); + /* The freestrings call must be delayed til the next + * pgetc call for PEOA to work properly. + */ + goto again; } else c = preadbuffer(); - return c; -} - - -/* - * Read a character from the script, returning PEOF on end of file. - * Nul characters in the input are silently discarded. - */ - -int __attribute__((noinline)) pgetc(void) -{ - struct strpush *sp = parsefile->spfree; - - if (unlikely(sp)) - freestrings(sp); + /* delete nul characters */ + if (IS_DEFINED_SMALL && unlikely(!c)) { + parsefile->nextc = memmove(parsefile->nextc - 1, + parsefile->nextc, parsefile->nleft); + goto nextc; + } - return __pgetc(); + return c; } int pgetc_eoa(void) @@ -374,10 +382,6 @@ int more; char *q; - if (unlikely(parsefile->strpush)) { - popstring(); - return __pgetc(); - } if (parsefile->eof & 2) { eof: parsefile->eof = 3; @@ -408,6 +412,12 @@ } } + if (IS_DEFINED_SMALL) { + q += more; + more = 0; + goto done; + } + /* delete nul characters */ for (;;) { int c; @@ -422,9 +432,6 @@ q++; - if (IS_DEFINED_SMALL) - goto check; - switch (c) { case '\n': goto done; @@ -439,11 +446,8 @@ } check: - if (more <= 0) { - if (!IS_DEFINED_SMALL) - goto again; - break; - } + if (more <= 0) + goto again; } done: input_set_lleft(parsefile, more); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dash-0.5.13.4/src/jobs.c new/dash-0.5.13.5/src/jobs.c --- old/dash-0.5.13.4/src/jobs.c 2026-03-21 09:56:03.000000000 +0100 +++ new/dash-0.5.13.5/src/jobs.c 2026-06-13 03:49:51.000000000 +0200 @@ -1264,20 +1264,13 @@ { char *name; - STARTSTACKSTR(name); - commandtextcont(n, name); + STARTSTACKSTR(cmdnextc); + cmdtxt(n); name = stackblock(); TRACE(("commandtext: name %p, end %p\n", name, cmdnextc)); return savestr(name); } -char *commandtextcont(union node *n, char *next) -{ - cmdnextc = next; - cmdtxt(n); - return cmdnextc; -} - STATIC void cmdtxt(union node *n) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dash-0.5.13.4/src/jobs.h new/dash-0.5.13.5/src/jobs.h --- old/dash-0.5.13.4/src/jobs.h 2026-03-16 02:45:46.000000000 +0100 +++ new/dash-0.5.13.5/src/jobs.h 2026-06-13 03:49:51.000000000 +0200 @@ -107,7 +107,6 @@ struct job *vforkexec(union node *n, char **argv, const char *path, int idx); int waitforjob(struct job *); int stoppedjobs(void); -char *commandtextcont(union node *n, char *next); #if ! JOBS #define setjobctl(on) ((void)(on)) /* do nothing */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dash-0.5.13.4/src/main.c new/dash-0.5.13.5/src/main.c --- old/dash-0.5.13.4/src/main.c 2025-09-23 13:07:58.000000000 +0200 +++ new/dash-0.5.13.5/src/main.c 2026-06-18 14:01:01.000000000 +0200 @@ -32,7 +32,6 @@ * SUCH DAMAGE. */ -#include <locale.h> #include <stdio.h> #include <signal.h> #include <sys/stat.h> @@ -104,8 +103,6 @@ monitor(4, etext, profile_buf, sizeof profile_buf, 50); #endif - setlocale(LC_ALL, ""); - state = 0; if (unlikely(setjmp(main_handler.loc))) { int e; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dash-0.5.13.4/src/parser.c new/dash-0.5.13.5/src/parser.c --- old/dash-0.5.13.4/src/parser.c 2026-05-09 04:54:18.000000000 +0200 +++ new/dash-0.5.13.5/src/parser.c 2026-06-13 03:50:04.000000000 +0200 @@ -92,6 +92,7 @@ int innerdq; int varpushed; int dblquote; + int backq; /* Inside back quotes (here-doc word only). */ int varnest; /* levels of variables expansion */ int parenlevel; /* levels of parens in arithmetic */ int dqvarnest; /* levels of variables expansion within double quotes */ @@ -968,7 +969,7 @@ p += !((c ^ *p) | (c ^ '\\')); - conv_ch = (c & ~((c & 0x40) >> 1)) ^ 0x40; + conv_ch = (c & ~((c & 0x40) >> 1) & 0x7f) ^ 0x40; USTPUTC(conv_ch, out); } @@ -1004,7 +1005,7 @@ }; int chkeofmark = checkkwd & CHKEOFMARK; struct synstack *synstack = &synbase; - bool sqheredoc = syntax == SQSYNTAX; + bool printesc = syntax == SQSYNTAX; struct nodelist *bqlist = NULL; int dollarsq = 0; int c = firstc; @@ -1035,9 +1036,10 @@ CHECKSTRSPACE((MB_LEN_MAX > 16 ? MB_LEN_MAX : 16) + 7, out); fieldsplitting = synstack->syntax == BASESYNTAX && - !synstack->varnest ? 4 : 0; + !(synstack->varnest | + synstack->backq) ? 4 : 0; ml = getmbc(c, out, fieldsplitting | - (sqheredoc ? 2 : 0)); + (printesc ? 2 : 0)); if (ml == 1) { if (out == stackblock()) return TBLANK; @@ -1079,7 +1081,8 @@ } if ( - synstack->dblquote && + (synstack->dblquote | + synstack->backq) && c != '\\' && c != '`' && c != '$' && ( c != '"' || @@ -1182,13 +1185,19 @@ USTPUTC(c, out); break; case CBQUOTE: /* '`' */ + if (synstack->backq == 2) + goto end_backq; USTPUTC('`', out); PARSEBACKQOLD(); break; case CEOF: goto endword; /* exit outer loop */ default: - if (fieldsplitting) + if (c == ')' && synstack->backq == 1) { +end_backq: + synstack_pop(&synstack); + printesc = 0; + } else if (fieldsplitting) goto endword; /* exit outer loop */ USTPUTC(c, out); } @@ -1197,7 +1206,8 @@ endword: if (synstack->syntax == ARISYNTAX) synerror("Missing '))'"); - if (synstack->syntax != BASESYNTAX && eofmark == NULL) + if ((synstack->syntax != BASESYNTAX && eofmark == NULL) || + synstack->backq) synerror("Unterminated quoted string"); if (synstack->varnest != 0) { /* { */ @@ -1520,16 +1530,20 @@ char *pstr; char *str; - if (!chkeofmark) { - STADJUST(oldstyle - 1, out); - out[-1] = CTLBACKQ; - } - if (!chkeofmark || !oldstyle) { - str = stackblock(); - savelen = out - (char *)stackblock(); - grabstackblock(savelen); - STARTSTACKSTR(out); - } + if (chkeofmark) { + synstack_push(&synstack, + synstack->prev ?: alloca(sizeof(*synstack)), + BASESYNTAX); + synstack->backq = oldstyle + 1; + printesc = 1; + goto parsebackq_out; + } + STADJUST(oldstyle - 1, out); + out[-1] = CTLBACKQ; + str = stackblock(); + savelen = out - (char *)stackblock(); + grabstackblock(savelen); + STARTSTACKSTR(out); if (oldstyle) { /* We must read until the closing backquote, giving special treatment to some slashes, and then push the string and @@ -1539,6 +1553,7 @@ int pc; while (!done) { + CHECKSTRSPACE(MB_LEN_MAX + 1, pout); if (needprompt) { setprompt(2); } @@ -1551,8 +1566,7 @@ pc = pgetc(); if (pc != '\\' && pc != '`' && pc != '$' && (!synstack->dblquote || pc != '"')) - STPUTC('\\', pout); - CHECKSTRSPACE(MB_LEN_MAX, pout); + USTPUTC('\\', pout); ml = getmbc(pc, pout, 2); pout += ml; if (ml) @@ -1569,12 +1583,8 @@ default: break; } - STPUTC(pc, pout); + USTPUTC(pc, pout); } - if (chkeofmark) { - out = pout; - goto parsebackq_oldreturn; - } pout[-1] = 0; pstr = grabstackstr(pout); setinputstring(pstr); @@ -1612,6 +1622,7 @@ out = stnputs(str, savelen, stackblock()); +parsebackq_out: if (oldstyle) { /* Ignore any pushed back tokens left from the backquote * parsing. @@ -1619,10 +1630,6 @@ tokpushback = 0; goto parsebackq_oldreturn; } else { - if (chkeofmark) { - out = commandtextcont(n, out); - STPUTC(')', out); - } goto parsebackq_newreturn; } } @@ -1705,8 +1712,7 @@ /* NOTREACHED */ } -STATIC void -setprompt(int which) +static void __attribute__((noinline)) setprompt(int which) { struct stackmark smark; int show; @@ -1719,7 +1725,7 @@ #else show = !el; #endif - if (show) { + if (show && !parsefile->nleft) { pushstackmark(&smark, stackblocksize()); out2str(getprompt(NULL)); popstackmark(&smark); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dash-0.5.13.4/src/var.c new/dash-0.5.13.5/src/var.c --- old/dash-0.5.13.4/src/var.c 2025-09-23 13:07:58.000000000 +0200 +++ new/dash-0.5.13.5/src/var.c 2026-06-18 14:01:01.000000000 +0200 @@ -32,6 +32,7 @@ * SUCH DAMAGE. */ +#include <locale.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> @@ -81,6 +82,12 @@ int lineno; char linenovar[sizeof("LINENO=")+sizeof(int)*CHAR_BIT/3+1] = "LINENO="; +static void changelocale(const char *val) +{ + putenv((char *)val); + setlocale(LC_ALL, nullstr); +} + /* Some macros in var.h depend on the order, add new variables to the end. */ struct var varinit[] = { #if ATTY @@ -101,6 +108,11 @@ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM\0", 0 }, { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE\0", sethistsize }, #endif + { 0, VSTRFIXED|VTEXTFIXED|VFULL|VUNSET, "LC_ALL\0", changelocale }, + { 0, VSTRFIXED|VTEXTFIXED|VFULL|VUNSET, "LC_COLLATE\0", changelocale }, + { 0, VSTRFIXED|VTEXTFIXED|VFULL|VUNSET, "LC_CTYPE\0", changelocale }, + { 0, VSTRFIXED|VTEXTFIXED|VFULL|VUNSET, "LC_NUMERIC\0", changelocale }, + { 0, VSTRFIXED|VTEXTFIXED|VFULL|VUNSET, "LANG\0", changelocale }, }; STATIC struct var *vartab[VTABSIZE]; @@ -156,7 +168,21 @@ static char *varnull(const char *s) { - return (strchr(s, '=') ?: nullstr - 1) + 1; + /* Unset variables always end with two NUL chars. */ + return strchrnul(s, '=') + 1; +} + +static void varfunc(struct var *vp) +{ + const char *s; + + if (!vp->func) + return; + + s = vp->text; + if (!(vp->flags & VFULL)) + s = varnull(s); + (*vp->func)(s); } /* @@ -210,9 +236,9 @@ vallen = strlen(val); } INTOFF; - p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen); + p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen + 1); if (val) { - *p++ = '='; + p[-1] = '='; p = mempcpy(p, val, vallen); } *p = '\0'; @@ -298,8 +324,8 @@ vp->text = s; vp->flags = flags; - if (vp->func && (flags & VNOFUNC) == 0) - (*vp->func)(varnull(s)); + if (!(flags & VNOFUNC)) + varfunc(vp); out: return vp; @@ -535,8 +561,8 @@ ckfree(vp->text); vp->flags = lvp->flags; vp->text = lvp->text; - if (vp->func && !(vp->flags & VNOFUNC)) - (*vp->func)(varnull(vp->text)); + if (!(vp->flags & VNOFUNC)) + varfunc(vp); } ckfree(lvp); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dash-0.5.13.4/src/var.h new/dash-0.5.13.5/src/var.h --- old/dash-0.5.13.4/src/var.h 2025-09-23 13:07:58.000000000 +0200 +++ new/dash-0.5.13.5/src/var.h 2026-06-18 14:01:01.000000000 +0200 @@ -48,7 +48,7 @@ #define VSTACK 0x10 /* text is allocated on the stack */ #define VUNSET 0x20 /* the variable is not set */ #define VNOFUNC 0x40 /* don't call the callback function */ -/* #define VNOSET 0x80 do not set variable - just readonly test */ +#define VFULL 0x80 /* pass value suitable for putenv */ #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
