BTW, do we have to propose this patch somewhere else or is this already the right place?

Greetings
Harvey

Am 15.02.24 um 22:48 schrieb Harvey:
David,

I can confirm that your patch solves my problem without any further need to change the shell code. Now V 1.36.1 acts in the same way as V 1.31.1 did. Thank you so mutch! Maybe this is candidate to merge ;)

Greetings
Harvey

Am 15.02.24 um 09:45 schrieb David Leonard:

        _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..}

In current busybox ash you will run into a bug where quotes aren't
handled in the pattern, and even loses the rest of the word, as you
observed. That is, given this script:

     var="don't g/o"
     echo "${var/'/'o}!"
     echo "${var/\'/\'o}!"

bash outputs:

     don't g!            (pattern="/o" repl="")
     don'ot g/o!            (pattern="'", repl="'o")

and busybox ash outputs:

     don't g/o            (pattern=?, repl=?, NOTE: lost !)
     don'ot g/o!            (pattern="'", repl="'o")

Here's a patch to make ash a little bit closer to bash.

--- a/shell/ash.c
+++ b/shell/ash.c
@@ -7058,6 +7058,7 @@ subevalvar(char *start, char *str, int strloc,
          */
         repl = NULL;
         if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
+               int quoted = 0;
                 /* Find '/' and replace with NUL */
                 repl = start;
                 /* The pattern can't be empty.
@@ -7073,6 +7074,11 @@ subevalvar(char *start, char *str, int strloc,
                                 repl = NULL;
                                 break;
                         }
+                       /* Handle quoted patterns */
+                       if ((unsigned char)*repl == CTLQUOTEMARK)
+                               quoted ^= 1;
+                       if (quoted)
+                               goto literal;
                         if (*repl == '/') {
                                 *repl = '\0';
                                 break;
@@ -7084,6 +7090,7 @@ subevalvar(char *start, char *str, int strloc,
                         /* Handle escaped slashes, e.g. "${v/\//_}" (they are CTLESC'ed by this point) */
                         if ((unsigned char)*repl == CTLESC && repl[1])
                                 repl++;
+               literal:
                         repl++;
                 }
         }

new file mode 100644
index 000000000..23aecb5ae
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_bash_repl_quoted.right
@@ -0,0 +1,3 @@
+ab.
+axb.
+x/b.
new file mode 100644
index 000000000..d2ba39578
--- /dev/null
+++ b/shell/ash_test/ash-vars/var_bash_repl_quoted.tests
@@ -0,0 +1,4 @@
+v=a/b
+echo "${v/'/'}."
+echo "${v/'/'/x}."
+echo "${v/'a'/x}."



On Wed, 14 Feb 2024, Harvey wrote:

Sorry, posted the wrong version of the pack_args() funtion:
I have payed with possible solutions for so long that I forgot the
restore the original before posting  -blush-

Here is the original version:
------------------------------------------------------------------------

# Packs arguments into a single string.
#
# Input:
#   $1 = name of variable receiving the arguments in such a way that
#        (re)evaluating them provides the original arguments
#   $2... = arguments
# Example:
#   func() {
#     local args
#     pack_args args "$@"
#     send_rpc func_impl "$args"
#   }
#   # (in another process) > #   receive_rpc() {
#     local func="$1"
#     local args="$2"
#     eval $func "$args"
#   }
pack_args()
{
    local _p _resvar=$1 _result= _value
    shift
    for _p
    do
        _result="$_result '${_p//'/'\"'\"'}'"
    done
    eval $_resvar=\${_result\# }
}
------------------------------------------------------------------------

Harvey

Am 14.02.24 um 19:06 schrieb Harvey:
Hello,

I am part of the team of a small router distribution called fli4l:
https://www.fli4l.de/doku.php?id=start.

We use buildroot to generate our images. Due to a hardware crash and the leaving of our main developer we are facing the dead of our project. But
there are still some people left and at least we want to try to keep it
alive 😉

That said - the first we have to try is the update of our buildroot
base. A lot of work is already done and but we struggle with the busybox
update, especially with the ash shell contained. When updating to
Version 1.36.1 we are facing script failures in places that did work
until busybox 1.31.1.

I have tried to debug the code and it seems that the error is contained
in a helper include for string handling.

The code is:
------------------------------------------------------------------------
# Packs arguments into a single string.
#
# Input:
#   $1 = name of variable receiving the arguments in such a way that
#        (re)evaluating them provides the original arguments
#   $2... = arguments
# Example:
#   func() {
#     local args
#     pack_args args "$@"
#     send_rpc func_impl "$args"
#   }
#   # (in another process)
#   receive_rpc() {
#     local func="$1"
#     local args="$2"
#     eval $func "$args"
#   }
pack_args()
{
     local _p _resvar=$1 _result= _value
     shift
     for _p
     do
         _result="$_result '${_p//'/'\"'\"'}''"
     done
     eval $_resvar=\${_result\# }
}
------------------------------------------------------------------------

The debug trace (using set -x) in V1.31.1 looks like this:

+ pack_args exit_trap_0 sync_unlock_all_resources
+ local _p '_resvar=exit_trap_0' '_result=' _value
+ shift
+ _result=' '"'"'sync_unlock_all_resources'"'"
+ eval 'exit_trap_0=${_result#' '}'
+ exit_trap_0=''"'"'sync_unlock_all_resources'"'"
+ exit_trap_num=1
+ return 0

------------------------------------------------------------------------
while in V1.36.1 it looks like this:

+ pack_args exit_trap_0 sync_unlock_all_resources
+ local _p '_resvar=exit_trap_0' '_result=' _value
+ shift
+ _result=' '"'"'sync_unlock_all_resources'
                                           ^^^^ missing quote
+ eval 'exit_trap_0=${_result#' '}'
+ exit_trap_0=''"'"'sync_unlock_all_resources'
                                              ^^^^ missing quote
+ exit_trap_num=1
+ return 0

The eval line then fails with 'Unterminated quoted string'

Unfortunately I can't tell where the difference lies.

I hope someone can help or at least point me in the right direction.

Greetings
Harvey
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to