RE: Failing shell code under busybox 1.36.1 that worked with 1.31.1

2024-02-15 Thread 'David Leonard'



Well, I also tried adding support for bash's ${var@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@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
 #defineBASH_SUBSTR  ENABLE_ASH_BASH_COMPAT
 #define IF_BASH_SUBSTR  IF_ASH_BASH_COMPAT
+#defineBASH_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 VSREPLACEALL0xe /* ${var//pattern/replacement} */
 #endif
+#if BASH_PARAM_TRANSFORM
+#define VSTRANSFORM 0xf /* ${var@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@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 
Cc: busybox@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)


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


Re: Failing shell code under busybox 1.36.1 that worked with 1.31.1

2024-02-15 Thread 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 0..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 0..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 

Re: fix large PID overflow their column in top command

2024-02-15 Thread Bernhard Reutner-Fischer
On Wed, 14 Feb 2024 14:05:15 +
Matthew Chae  wrote:

> Hi Bernhard,
> 
> I'm sending new patch and the result of bloatcheck.

Many thanks for the updated patch!

function old new   delta
display_process_list14061765+359
.rodata99721   99724  +3
--
(add/remove: 0/0 grow/shrink: 2/0 up/down: 362/0) Total: 362 bytes
   textdata bss dec hex filename
1009548   165071840 1027895   faf37 busybox_old
1009910   165071840 1028257   fb0a1 busybox_unstripped

I think that's too much. For me this gives +293 bytes, still way too much.
Can you please see if it helps to retain the manual formatting of
PID PPID USER?

PS:

procps/top.c: In function ‘display_process_list’:
procps/top.c:664:1: warning: ISO C90 forbids mixed declarations and code 
[-Wdeclaration-after-statement]
  664 | typedef struct { unsigned quot, rem; } bb_div_t;
  | ^~~

so please move your new #define PID_STR block down to right before
/* what info of the processes is shown */

In
+   int lines = (lines_rem - 1);
please drop the superfluous braces.

It is most likely not smaller to use
pid_len = strlen(make_human_readable_str(pid_max,0,0))
than to introduce this private count_digits(), i fear?
Maybe we could amortize the addition of count_digits by
reusing it elsewhere, as a follow-up.

thanks

> Can you review these and give me your thoughts?
> Just let me know if you think that the code size needs to be reduced.
> 
> Br-Matthew
> 
> From: Bernhard Reutner-Fischer 
> Sent: Tuesday, February 13, 2024 7:16 PM
> To: Matthew Chae 
> Cc: rep.dot@gmail.com ; David Laight 
> ; 'Denys Vlasenko' ; 
> busybox@busybox.net ; Christopher Wong 
> 
> Subject: Re: fix large PID overflow their column in top command
> 
> On Mon, 5 Feb 2024 09:56:20 +
> Matthew Chae  wrote:
> 
> > Hi David,
> >
> > I'm sending an improved patch based on your comments.
> >
> > Not only does it not care about the PID_MAX value,
> > it searches all the contents to be output to recognize the required column 
> > width
> > and dynamically allocates the space for PID and PPID appropriately without 
> > creating a lot of empty space.
> >
> > Additionally, this patch still allows user names to be displayed up to 8 
> > characters without truncation.
> >
> > Can you look through the attachment?  
> 
> Unfortunately the patch does not apply to current master.
> How much would your patch add to the size? Can you bring it down to a
> minimum?
> See make baseline; apply the patch;make bloatcheck
> 
> thanks
> 
> > (0002-Allocate-PID-PPID-space-dynamically-in-top-command.patch)
> >
> > BR-Matthew Chae
> > 
> > From: David Laight 
> > Sent: Thursday, November 23, 2023 6:10 PM
> > To: 'Denys Vlasenko' ; Matthew Chae 
> > 
> > Cc: busybox@busybox.net ; Christopher Wong 
> > 
> > Subject: RE: fix large PID overflow their column in top command
> >
> > ...  
> > > +   fp = xfopen_for_read("/proc/sys/kernel/pid_max");
> > > +   if (!fgets(pid_buf, PID_DIGITS_MAX + 1, fp)) {
> > > ...
> > > +   if (strncmp(pid_buf, "32768", 5) == 0)
> > > +   pid_digits_num = 5;
> > > +   else
> > > +   pid_digits_num = PID_DIGITS_MAX;
> > >
> > > The logic above is not sound. Even if sysctl kernel.pid_max
> > > is 32768, there can be already running processes with pids > 9.  
> >
> > It's also probably wrong for pretty much all other values.
> >
> > I'd just base the column width on strlen(pid_buf) with a minimum
> > value of 5.
> >
> > It is unlikely that pid_max has been reduced - so column overflow
> > it that case probably doesn't really matter.
> >
> > The more interesting case is really a system with a very large pid_max
> > that has never run many processes.
> > You don't really want lots of blank space.
> >
> > I can't remember whether top reads everything before doing any output?
> > Since the output is sorted it probably almost always does.
> > In which case it knows the column width it will need.
> >
> > I did post a patch a while back that enabled 'Irix mode'.
> > (100% cpu is one cpu at 100%, not all cpus at 100%)
> > Maybe I should dig it out again.
> >
> > David
> >
> > -
> > Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 
> > 1PT, UK
> > Registration No: 1397386 (Wales)  
> 

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


Re: udhcpc: throttled down data transmission

2024-02-15 Thread Alexander Wilhelm
Am Thu, Feb 15, 2024 at 12:23:06PM + schrieb Laurent Bercot:
> > I'm using 'udhcpc' on my ARM64 platform with the following scenario: I have 
> > one
> > 'eth0' interface that has a static ip address and the 'udhcpc' client on the
> > same interface. That leads to low data transmission performace on that
> > interface.
> 
>  Most people use udhcpc when they *don't* have a static IP address on
> an interface, the point of DHCP being to assign an IP address. In that
> common use case, it is impossible to use UDP, since IPv4 is not
> configured yet! Listening on a raw socket is the only option.
> 
>  Your use case is pretty niche, already having IPv4 configured on your
> interface before you use udhcpc. It's not surprising that udhcpc isn't
> optimized for it: it's a small client after all.
> 
>  I suppose it could be patched to add an option to use UDP when the
> interface already has an address, but it would mean effort, and more code
> in busybox, which is probably not worth the trade-off.
> 
> --
>  Laurent
> 

Thank you for the clear explanation. I'm going to disable the 'udhcpc' client
when the interface 'eth0' has already an static IP address.


Best regards
Alexander Wilhelm
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: udhcpc: throttled down data transmission

2024-02-15 Thread Laurent Bercot

I'm using 'udhcpc' on my ARM64 platform with the following scenario: I have one
'eth0' interface that has a static ip address and the 'udhcpc' client on the
same interface. That leads to low data transmission performace on that
interface.


 Most people use udhcpc when they *don't* have a static IP address on
an interface, the point of DHCP being to assign an IP address. In that
common use case, it is impossible to use UDP, since IPv4 is not
configured yet! Listening on a raw socket is the only option.

 Your use case is pretty niche, already having IPv4 configured on your
interface before you use udhcpc. It's not surprising that udhcpc isn't
optimized for it: it's a small client after all.

 I suppose it could be patched to add an option to use UDP when the
interface already has an address, but it would mean effort, and more 
code

in busybox, which is probably not worth the trade-off.

--
 Laurent

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


RE: Failing shell code under busybox 1.36.1 that worked with 1.31.1

2024-02-15 Thread David Laight
From: David Leonard
> Sent: 15 February 2024 08:46
> To: Harvey 
> Cc: busybox@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)
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


RE: Failing shell code under busybox 1.36.1 that worked with 1.31.1

2024-02-15 Thread David Laight
From: Harvey
> Sent: 14 February 2024 18:18
> 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\# }
> }

Try just splitting the quoting of the final '
Just adding "" before it might be enough.
Failing that add it on the next line.

Probably easier than trying to find the bug in ash.
(been there, done that...)

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, 
UK
Registration No: 1397386 (Wales)
___
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


Re: Failing shell code under busybox 1.36.1 that worked with 1.31.1

2024-02-15 Thread 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 0..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 0..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//'/'\"'\"'}''"