Merge with BusyBox 1.26.0 development version prior to significant hush changes.

This commit is contained in:
Stephen Heumann 2018-01-01 12:59:30 -06:00
commit 31f1b35500
5 changed files with 110 additions and 41 deletions

View File

@ -5,7 +5,7 @@
#ifndef BUSYBOX_H #ifndef BUSYBOX_H
#define BUSYBOX_H 1 #define BUSYBOX_H 1
#define BB_VER "1.25.0 (GNO hush 1.2-dev)" #define BB_VER "1.26.0.git (GNO hush 1.2-dev)"
#include "libbb.h" #include "libbb.h"
/* BB_DIR_foo and BB_SUID_bar constants: */ /* BB_DIR_foo and BB_SUID_bar constants: */
@ -13,7 +13,17 @@
PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
#if ENABLE_FEATURE_PREFER_APPLETS /* Defined in appletlib.c (by including generated applet_tables.h) */
/* Keep in sync with applets/applet_tables.c! */
extern const char applet_names[] ALIGN1;
extern int (*const applet_main[])(int argc, char **argv);
extern const uint8_t applet_flags[] ALIGN1;
extern const uint8_t applet_suid[] ALIGN1;
extern const uint8_t applet_install_loc[] ALIGN1;
#if ENABLE_FEATURE_PREFER_APPLETS \
|| ENABLE_FEATURE_SH_STANDALONE \
|| ENABLE_FEATURE_SH_NOFORK
# define APPLET_IS_NOFORK(i) (applet_flags[(i)/4] & (1 << (2 * ((i)%4)))) # define APPLET_IS_NOFORK(i) (applet_flags[(i)/4] & (1 << (2 * ((i)%4))))
# define APPLET_IS_NOEXEC(i) (applet_flags[(i)/4] & (1 << ((2 * ((i)%4))+1))) # define APPLET_IS_NOEXEC(i) (applet_flags[(i)/4] & (1 << ((2 * ((i)%4))+1)))
#else #else
@ -25,6 +35,14 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
# define APPLET_SUID(i) ((applet_suid[(i)/4] >> (2 * ((i)%4)) & 3)) # define APPLET_SUID(i) ((applet_suid[(i)/4] >> (2 * ((i)%4)) & 3))
#endif #endif
#if ENABLE_FEATURE_INSTALLER
#define APPLET_INSTALL_LOC(i) ({ \
unsigned v = (i); \
if (v & 1) v = applet_install_loc[v/2] >> 4; \
else v = applet_install_loc[v/2] & 0xf; \
v; })
#endif
/* Length of these names has effect on size of libbusybox /* Length of these names has effect on size of libbusybox
* and "individual" binaries. Keep them short. * and "individual" binaries. Keep them short.

View File

@ -27,23 +27,20 @@ extern int optreset; /* exists on GNO, but isn't in the header files */
uint32_t uint32_t
getopt32(char **argv, const char *applet_opts, ...) getopt32(char **argv, const char *applet_opts, ...)
The command line options must be declared in const char The command line options are passed as the applet_opts string.
*applet_opts as a string of chars, for example:
flags = getopt32(argv, "rnug");
If one of the given options is found, a flag value is added to If one of the given options is found, a flag value is added to
the return value (an unsigned long). the return value.
The flag value is determined by the position of the char in The flag value is determined by the position of the char in
applet_opts string. For example, in the above case: applet_opts string. For example:
flags = getopt32(argv, "rnug"); flags = getopt32(argv, "rnug");
"r" will add 1 (bit 0) "r" will set 1 (bit 0)
"n" will add 2 (bit 1) "n" will set 2 (bit 1)
"u" will add 4 (bit 2) "u" will set 4 (bit 2)
"g" will add 8 (bit 3) "g" will set 8 (bit 3)
and so on. You can also look at the return value as a bit and so on. You can also look at the return value as a bit
field and each option sets one bit. field and each option sets one bit.
@ -55,7 +52,7 @@ getopt32(char **argv, const char *applet_opts, ...)
(options and their parameters will be moved into argv[] (options and their parameters will be moved into argv[]
positions prior to argv[optind]). positions prior to argv[optind]).
":" If one of the options requires an argument, then add a ":" "o:" If one of the options requires an argument, then add a ":"
after the char in applet_opts and provide a pointer to store after the char in applet_opts and provide a pointer to store
the argument. For example: the argument. For example:
@ -68,15 +65,39 @@ getopt32(char **argv, const char *applet_opts, ...)
&pointer_to_arg_for_a, &pointer_to_arg_for_b, &pointer_to_arg_for_a, &pointer_to_arg_for_b,
&pointer_to_arg_for_c, &pointer_to_arg_for_d); &pointer_to_arg_for_c, &pointer_to_arg_for_d);
The type of the pointer (char* or llist_t*) may be controlled The type of the pointer may be controlled by "o::" or "o+" in
by the "::" special separator that is set in the external string the external string opt_complementary (see below for more info).
opt_complementary (see below for more info).
"::" If option can have an *optional* argument, then add a "::" "o::" If option can have an *optional* argument, then add a "::"
after its char in applet_opts and provide a pointer to store after its char in applet_opts and provide a pointer to store
the argument. Note that optional arguments _must_ the argument. Note that optional arguments _must_
immediately follow the option: -oparam, not -o param. immediately follow the option: -oparam, not -o param.
"o:+" This means that the parameter for this option is a nonnegative integer.
It will be processed with xatoi_positive() - allowed range
is 0..INT_MAX.
int param; // "unsigned param;" will also work
getopt32(argv, "p:+", &param);
"o:*" This means that the option can occur multiple times. Each occurrence
will be saved as a llist_t element instead of char*.
For example:
The grep applet can have one or more "-e pattern" arguments.
In this case you should use getopt32() as follows:
llist_t *patterns = NULL;
(this pointer must be initializated to NULL if the list is empty
as required by llist_add_to_end(llist_t **old_head, char *new_item).)
getopt32(argv, "e:*", &patterns);
$ grep -e user -e root /etc/passwd
root:x:0:0:root:/root:/bin/bash
user:x:500:500::/home/user:/bin/bash
"+" If the first character in the applet_opts string is a plus, "+" If the first character in the applet_opts string is a plus,
then option processing will stop as soon as a non-option is then option processing will stop as soon as a non-option is
encountered in the argv array. Useful for applets like env encountered in the argv array. Useful for applets like env
@ -92,7 +113,7 @@ const char *applet_long_options
This struct allows you to define long options: This struct allows you to define long options:
static const char applet_longopts[] ALIGN1 = static const char applet_longopts[] ALIGN1 =
//"name\0" has_arg val //"name\0" has_arg val
"verbose\0" No_argument "v" "verbose\0" No_argument "v"
; ;
applet_long_options = applet_longopts; applet_long_options = applet_longopts;
@ -100,7 +121,7 @@ const char *applet_long_options
The last member of struct option (val) typically is set to The last member of struct option (val) typically is set to
matching short option from applet_opts. If there is no matching matching short option from applet_opts. If there is no matching
char in applet_opts, then: char in applet_opts, then:
- return bit have next position after short options - return bit has next position after short options
- if has_arg is not "No_argument", use ptr for arg also - if has_arg is not "No_argument", use ptr for arg also
- opt_complementary affects it too - opt_complementary affects it too
@ -149,8 +170,8 @@ const char *opt_complementary
llist_t *my_b = NULL; llist_t *my_b = NULL;
int verbose_level = 0; int verbose_level = 0;
opt_complementary = "vv:b::b-c:c-b"; opt_complementary = "vv:b-c:c-b";
f = getopt32(argv, "vb:c", &my_b, &verbose_level); f = getopt32(argv, "vb:*c", &my_b, &verbose_level);
if (f & 2) // -c after -b unsets -b flag if (f & 2) // -c after -b unsets -b flag
while (my_b) dosomething_with(llist_pop(&my_b)); while (my_b) dosomething_with(llist_pop(&my_b));
if (my_b) // but llist is stored if -b is specified if (my_b) // but llist is stored if -b is specified
@ -243,7 +264,7 @@ Special characters:
"x--x" Variation of the above, it means that -x option should occur "x--x" Variation of the above, it means that -x option should occur
at most once. at most once.
"a+" A plus after a char in opt_complementary means that the parameter "o+" A plus after a char in opt_complementary means that the parameter
for this option is a nonnegative integer. It will be processed for this option is a nonnegative integer. It will be processed
with xatoi_positive() - allowed range is 0..INT_MAX. with xatoi_positive() - allowed range is 0..INT_MAX.
@ -251,7 +272,7 @@ Special characters:
opt_complementary = "p+"; opt_complementary = "p+";
getopt32(argv, "p:", &param); getopt32(argv, "p:", &param);
"a::" A double colon after a char in opt_complementary means that the "o::" A double colon after a char in opt_complementary means that the
option can occur multiple times. Each occurrence will be saved as option can occur multiple times. Each occurrence will be saved as
a llist_t element instead of char*. a llist_t element instead of char*.
@ -265,12 +286,17 @@ Special characters:
as required by llist_add_to_end(llist_t **old_head, char *new_item).) as required by llist_add_to_end(llist_t **old_head, char *new_item).)
opt_complementary = "e::"; opt_complementary = "e::";
getopt32(argv, "e:", &patterns); getopt32(argv, "e:", &patterns);
$ grep -e user -e root /etc/passwd $ grep -e user -e root /etc/passwd
root:x:0:0:root:/root:/bin/bash root:x:0:0:root:/root:/bin/bash
user:x:500:500::/home/user:/bin/bash user:x:500:500::/home/user:/bin/bash
"o+" and "o::" can be handled by "o:+" and "o:*" specifiers
in option string (and it is preferred), but this does not work
for "long options only" cases, such as tar --exclude=PATTERN,
wget --header=HDR cases.
"a?b" A "?" between an option and a group of options means that "a?b" A "?" between an option and a group of options means that
at least one of them is required to occur if the first option at least one of them is required to occur if the first option
occurs in preceding command line arguments. occurs in preceding command line arguments.
@ -356,6 +382,7 @@ getopt32(char **argv, const char *applet_opts, ...)
char **pargv; char **pargv;
int min_arg = 0; int min_arg = 0;
int max_arg = -1; int max_arg = -1;
char *applet_opts_copy = NULL;
#define SHOW_USAGE_IF_ERROR 1 #define SHOW_USAGE_IF_ERROR 1
#define ALL_ARGV_IS_OPTS 2 #define ALL_ARGV_IS_OPTS 2
@ -370,21 +397,26 @@ getopt32(char **argv, const char *applet_opts, ...)
va_start(p, applet_opts); va_start(p, applet_opts);
complementary = calloc(33, sizeof(*complementary));
if (complementary == NULL)
goto error2;
on_off = complementary;
applet_opts_copy = malloc(strlen(applet_opts) + 1);
if (applet_opts_copy == NULL)
goto error2;
applet_opts = strcpy(applet_opts_copy, applet_opts);
/* skip bbox extension */ /* skip bbox extension */
first_char = applet_opts[0]; first_char = applet_opts[0];
if (first_char == '!') if (first_char == '!')
applet_opts++; applet_opts++;
c = 0;
complementary = calloc(33, sizeof(*complementary));
if (complementary == NULL)
goto error;
on_off = complementary;
/* skip GNU extension */ /* skip GNU extension */
s = (const unsigned char *)applet_opts; s = (const unsigned char *)applet_opts;
if (*s == '+' || *s == '-') if (*s == '+' || *s == '-')
s++; s++;
c = 0;
while (*s) { while (*s) {
if (c >= 32) if (c >= 32)
break; break;
@ -392,6 +424,13 @@ getopt32(char **argv, const char *applet_opts, ...)
on_off->switch_on = (1 << c); on_off->switch_on = (1 << c);
if (*++s == ':') { if (*++s == ':') {
on_off->optarg = va_arg(p, void **); on_off->optarg = va_arg(p, void **);
if (s[1] == '+' || s[1] == '*') {
/* 'o:+' or 'o:*' */
on_off->param_type = (s[1] == '+') ?
PARAM_INT : PARAM_LIST;
overlapping_strcpy((char*)s + 1, (char*)s + 2);
}
/* skip possible 'o::' (or 'o:+:' !) */
while (*++s == ':') while (*++s == ':')
continue; continue;
} }
@ -444,6 +483,7 @@ getopt32(char **argv, const char *applet_opts, ...)
applet_long_options = NULL; applet_long_options = NULL;
} }
#endif /* ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG */ #endif /* ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG */
for (s = (const unsigned char *)opt_complementary; s && *s; s++) { for (s = (const unsigned char *)opt_complementary; s && *s; s++) {
t_complementary *pair; t_complementary *pair;
unsigned *pair_switch; unsigned *pair_switch;
@ -622,11 +662,14 @@ getopt32(char **argv, const char *applet_opts, ...)
option_mask32 = flags; option_mask32 = flags;
free(complementary); free(complementary);
free(applet_opts_copy);
return flags; return flags;
error: error:
if (first_char != '!') if (first_char != '!')
bb_show_usage(); bb_show_usage();
error2:
free(complementary); free(complementary);
free(applet_opts_copy);
return (int32_t)-1; return (int32_t)-1;
} }

View File

@ -83,7 +83,9 @@
# define CHAR_T wchar_t # define CHAR_T wchar_t
static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); } static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); }
# if ENABLE_FEATURE_EDITING_VI # if ENABLE_FEATURE_EDITING_VI
static bool BB_isalnum(CHAR_T c) { return ((unsigned)c < 256 && isalnum(c)); } static bool BB_isalnum_or_underscore(CHAR_T c) {
return ((unsigned)c < 256 && isalnum(c)) || c == '_';
}
# endif # endif
static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); } static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
# undef isspace # undef isspace
@ -98,7 +100,11 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
# define BB_NUL '\0' # define BB_NUL '\0'
# define CHAR_T char # define CHAR_T char
# define BB_isspace(c) isspace(c) # define BB_isspace(c) isspace(c)
# define BB_isalnum(c) isalnum(c) # if ENABLE_FEATURE_EDITING_VI
static bool BB_isalnum_or_underscore(CHAR_T c) {
return ((unsigned)c < 256 && isalnum(c)) || c == '_';
}
# endif
# define BB_ispunct(c) ispunct(c) # define BB_ispunct(c) ispunct(c)
#endif #endif
#if ENABLE_UNICODE_PRESERVE_BROKEN #if ENABLE_UNICODE_PRESERVE_BROKEN
@ -1762,9 +1768,9 @@ vi_word_motion(int eat)
{ {
CHAR_T *command = command_ps; CHAR_T *command = command_ps;
if (BB_isalnum(command[cursor]) || command[cursor] == '_') { if (BB_isalnum_or_underscore(command[cursor])) {
while (cursor < command_len while (cursor < command_len
&& (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_') && (BB_isalnum_or_underscore(command[cursor+1]))
) { ) {
input_forward(); input_forward();
} }
@ -1806,9 +1812,9 @@ vi_end_motion(void)
input_forward(); input_forward();
if (cursor >= command_len-1) if (cursor >= command_len-1)
return; return;
if (BB_isalnum(command[cursor]) || command[cursor] == '_') { if (BB_isalnum_or_underscore(command[cursor])) {
while (cursor < command_len-1 while (cursor < command_len-1
&& (BB_isalnum(command[cursor+1]) || command[cursor+1] == '_') && (BB_isalnum_or_underscore(command[cursor+1]))
) { ) {
input_forward(); input_forward();
} }
@ -1841,9 +1847,9 @@ vi_back_motion(void)
input_backward(1); input_backward(1);
if (cursor <= 0) if (cursor <= 0)
return; return;
if (BB_isalnum(command[cursor]) || command[cursor] == '_') { if (BB_isalnum_or_underscore(command[cursor])) {
while (cursor > 0 while (cursor > 0
&& (BB_isalnum(command[cursor-1]) || command[cursor-1] == '_') && (BB_isalnum_or_underscore(command[cursor-1]))
) { ) {
input_backward(1); input_backward(1);
} }

View File

@ -88,7 +88,7 @@ config FEATURE_SH_EXTRA_QUIET
config FEATURE_SH_STANDALONE config FEATURE_SH_STANDALONE
bool "Standalone shell" bool "Standalone shell"
default n default n
depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS depends on (HUSH || ASH)
help help
This option causes busybox shells to use busybox applets This option causes busybox shells to use busybox applets
in preference to executables in the PATH whenever possible. For in preference to executables in the PATH whenever possible. For
@ -121,7 +121,7 @@ config FEATURE_SH_STANDALONE
config FEATURE_SH_NOFORK config FEATURE_SH_NOFORK
bool "Run 'nofork' applets directly" bool "Run 'nofork' applets directly"
default n default n
depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS depends on (HUSH || ASH)
help help
This option causes busybox shells to not execute typical This option causes busybox shells to not execute typical
fork/exec/wait sequence, but call <applet>_main directly, fork/exec/wait sequence, but call <applet>_main directly,

View File

@ -9982,9 +9982,11 @@ static int FAST_FUNC builtin_break(char **argv)
unsigned depth; unsigned depth;
if (G.depth_of_loop == 0) { if (G.depth_of_loop == 0) {
bb_error_msg("%s: only meaningful in a loop", argv[0]); bb_error_msg("%s: only meaningful in a loop", argv[0]);
/* if we came from builtin_continue(), need to undo "= 1" */
G.flag_break_continue = 0;
return EXIT_SUCCESS; /* bash compat */ return EXIT_SUCCESS; /* bash compat */
} }
G.flag_break_continue++; /* BC_BREAK = 1 */ G.flag_break_continue++; /* BC_BREAK = 1, or BC_CONTINUE = 2 */
G.depth_break_continue = depth = parse_numeric_argv1(argv, 1, 1); G.depth_break_continue = depth = parse_numeric_argv1(argv, 1, 1);
if (depth == UINT_MAX) if (depth == UINT_MAX)