Failing shell code under busybox 1.36.1 that worked with 1.31.1
Harvey
harv at gmx.de
Fri Feb 16 12:28:56 UTC 2024
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 at busybox.net
>>>> http://lists.busybox.net/mailman/listinfo/busybox
>>> _______________________________________________
>>> busybox mailing list
>>> busybox at busybox.net
>>> http://lists.busybox.net/mailman/listinfo/busybox
>>>
> _______________________________________________
> busybox mailing list
> busybox at busybox.net
> http://lists.busybox.net/mailman/listinfo/busybox
More information about the busybox
mailing list