Failing shell code under busybox 1.36.1 that worked with 1.31.1

'David Leonard' d+busybox at adaptive-enterprises.com
Fri Feb 16 03:33:46 UTC 2024


Well, I also tried adding support for bash's ${var at Q} (which I think is the
  most readable way to solve quoting) but it seems I really don't understand
how ash's subevalvar() works after all :)


./busybox ash -xvc 'v="ab cd"; echo "(${v at Q})"'
+ v='ab cd'
ash: vstransform:str='Q'
ash: vstransform:startp='ab cd'
+ echo ''"'"'a'"'"'ab cd'"'"')'
'a'ab cd')





diff --git a/shell/ash.c b/shell/ash.c
index ae1b79f37..8d5d6146d 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -222,6 +222,8 @@
  #define IF_BASH_PATTERN_SUBST       IF_ASH_BASH_COMPAT
  #define    BASH_SUBSTR          ENABLE_ASH_BASH_COMPAT
  #define IF_BASH_SUBSTR              IF_ASH_BASH_COMPAT
+#define    BASH_PARAM_TRANSFORM ENABLE_ASH_BASH_COMPAT
+#define IF_BASH_PARAM_TRANSFORM     IF_ASH_BASH_COMPAT
  /* BASH_TEST2: [[ EXPR ]]
   * Status of [[ support:
   *   && and || work as they should
@@ -574,6 +576,7 @@ var_end(const char *var)
  	return var;
  }

+static int hasmeta(const char *);

  /* ============ Parser data */

@@ -868,6 +871,9 @@ out2str(const char *p)
  #define VSREPLACE       0xd     /* ${var/pattern/replacement} */
  #define VSREPLACEALL    0xe     /* ${var//pattern/replacement} */
  #endif
+#if BASH_PARAM_TRANSFORM
+#define VSTRANSFORM     0xf     /* ${var at operator} */
+#endif

  static const char dolatstr[] ALIGN1 = {
  	CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
@@ -7262,6 +7268,20 @@ subevalvar(char *start, char *str, int strloc,
  		repl ? NULL : (slash_pos < 0 ? NULL : &slash_pos)
  	);

+#if BASH_PARAM_TRANSFORM
+	if (subtype == VSTRANSFORM) {
+		bb_error_msg("vstransform:str='%s'", str);
+		if (strcmp(str, "Q") != 0)
+			goto out1;
+		bb_error_msg("vstransform:startp='%s'", startp);
+		char *quoted = single_quote(startp);
+		int len = strlen(quoted);
+		memmove(startp, quoted, len);
+		loc = startp + len;
+		goto out;
+	}
+#endif /* BASH_PARAM_TRANSFORM */
+
  #if BASH_PATTERN_SUBST
  	workloc = expdest - (char *)stackblock();
  	if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
@@ -7432,7 +7452,7 @@ subevalvar(char *start, char *str, int strloc,
   out:
  	amount = loc - expdest;
  	STADJUST(amount, expdest);
-#if BASH_PATTERN_SUBST
+#if BASH_PATTERN_SUBST || BASH_PARAM_TRANSFORM
   out1:
  #endif
  	/* Remove any recorded regions beyond start of variable */
@@ -7671,6 +7691,9 @@ evalvar(char *p, int flag)
  #if BASH_PATTERN_SUBST
  	case VSREPLACE:
  	case VSREPLACEALL:
+#endif
+#if BASH_PARAM_TRANSFORM
+	case VSTRANSFORM:
  #endif
  		break;
  	default:
@@ -12989,6 +13012,13 @@ parsesub: {
  					goto badsub;
  				subtype++; /* VSREPLACEALL */
  				break;
+#endif
+#if BASH_PARAM_TRANSFORM
+			case '@':
+				/* ${v at operator} */
+				subtype = VSTRANSFORM;
+				newsyn = BASESYNTAX;
+				break;
  #endif
  			}
  		} else {


On Thu, 15 Feb 2024, David Laight wrote:

> From: David Leonard
>> Sent: 15 February 2024 08:46
>> To: Harvey <harv at gmx.de>
>> Cc: busybox at busybox.net
>> Subject: Re: Failing shell code under busybox 1.36.1 that worked with 1.31.1
>>
>>
>>>         _result="$_result '${_p//'/'\"'\"'}'"
>>
>> Busybox ash has a CONFIG_ASH_BASH_COMPAT config to get this ${var//...}
>> replacement behaviour.  And, in bash, the ' in the pattern section is treated
>> as a quote start. To give the ' a literal meaning, use \'
>> eg ${_p//\'/..repl..}
> ...
>
> It is probably safer to the quotes into variables.
> Then the syntax analysis won't get messed up.
>
> So something like:
> sq="'"
> qsq='"'"'"'"'
>
> then
> 	"${_p/$sg/$qsq}"
>
> is probably ok and maybe more readable.
>
> 	David
>
> -
> Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
> Registration No: 1397386 (Wales)
>


More information about the busybox mailing list