aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2020-07-09 13:10:58 +0100
committerRon Yorston <rmy@pobox.com>2020-07-09 13:10:58 +0100
commit9c0b2f7020d7c30b21a930ef54be632e092e533b (patch)
treeb2187c40bd2fd9f49f73599fb08e52cb7a596de0
parenta8c6e20e332a9e11a9d28cd6770eadb9c9d73cb7 (diff)
parentd21a63f9fca8eb16f79de9b72d4a3484dfaec1fc (diff)
downloadbusybox-w32-9c0b2f7020d7c30b21a930ef54be632e092e533b.tar.gz
busybox-w32-9c0b2f7020d7c30b21a930ef54be632e092e533b.tar.bz2
busybox-w32-9c0b2f7020d7c30b21a930ef54be632e092e533b.zip
Merge branch 'busybox' into merge
-rw-r--r--Makefile2
-rw-r--r--Makefile.flags2
-rw-r--r--archival/bbunzip.c2
-rw-r--r--archival/cpio.c1
-rw-r--r--archival/dpkg.c23
-rw-r--r--coreutils/expand.c8
-rw-r--r--editors/awk.c4
-rw-r--r--editors/patch.c3
-rwxr-xr-xexamples/udhcp/simple.script2
-rw-r--r--include/libbb.h3
-rw-r--r--include/platform.h4
-rw-r--r--libbb/appletlib.c38
-rw-r--r--libbb/compare_string_array.c7
-rw-r--r--libbb/duration.c1
-rw-r--r--libbb/last_char_is.c17
-rw-r--r--libbb/lineedit.c2
-rw-r--r--libbb/procps.c12
-rw-r--r--libbb/xfuncs_printf.c19
-rw-r--r--loginutils/deluser.c10
-rwxr-xr-xmake_single_applets.sh2
-rw-r--r--miscutils/bc.c2
-rw-r--r--miscutils/devfsd.c1
-rw-r--r--networking/brctl.c6
-rw-r--r--networking/httpd.c5
-rw-r--r--networking/nc_bloaty.c24
-rw-r--r--networking/udhcp/common.c98
-rw-r--r--networking/udhcp/common.h12
-rw-r--r--networking/udhcp/d6_dhcpc.c6
-rw-r--r--networking/udhcp/dhcpc.c301
-rw-r--r--networking/udhcp/dhcpd.c8
-rw-r--r--networking/udhcp/domain_codec.c27
-rw-r--r--networking/wget.c21
-rw-r--r--procps/nmeter.c68
-rw-r--r--procps/sysctl.c9
-rw-r--r--procps/top.c2
-rwxr-xr-xscripts/randomtest25
-rw-r--r--shell/Config.src20
-rw-r--r--shell/ash.c41
-rw-r--r--shell/hush.c75
-rwxr-xr-xtestsuite/awk.tests8
-rwxr-xr-xtestsuite/cpio.tests6
-rwxr-xr-xtestsuite/mdev.tests4
-rwxr-xr-xtestsuite/patch.tests4
-rwxr-xr-xtestsuite/unexpand.tests33
-rw-r--r--util-linux/acpid.c4
-rw-r--r--util-linux/nologin.c2
46 files changed, 584 insertions, 390 deletions
diff --git a/Makefile b/Makefile
index 32f6dfae9..892d5411d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
1VERSION = 1 1VERSION = 1
2PATCHLEVEL = 32 2PATCHLEVEL = 33
3SUBLEVEL = 0 3SUBLEVEL = 0
4EXTRAVERSION = .git 4EXTRAVERSION = .git
5NAME = Unnamed 5NAME = Unnamed
diff --git a/Makefile.flags b/Makefile.flags
index 26031f561..2c3fd0d25 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -78,7 +78,9 @@ CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,)
78CFLAGS += $(call cc-option,-fno-builtin-printf,) 78CFLAGS += $(call cc-option,-fno-builtin-printf,)
79 79
80# clang-9 does not like "str" + N and "if (CONFIG_ITEM && cond)" constructs 80# clang-9 does not like "str" + N and "if (CONFIG_ITEM && cond)" constructs
81ifeq ($(CC),clang)
81CFLAGS += $(call cc-option,-Wno-string-plus-int -Wno-constant-logical-operand) 82CFLAGS += $(call cc-option,-Wno-string-plus-int -Wno-constant-logical-operand)
83endif
82 84
83# FIXME: These warnings are at least partially to be concerned about and should 85# FIXME: These warnings are at least partially to be concerned about and should
84# be fixed.. 86# be fixed..
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index da6f031e3..320fe4fd1 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -388,7 +388,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
388 * Normally, "zcat" is just "gunzip -c". 388 * Normally, "zcat" is just "gunzip -c".
389 * But if seamless magic is enabled, then we are much more clever. 389 * But if seamless magic is enabled, then we are much more clever.
390 */ 390 */
391 if (ENABLE_ZCAT && (!ENABLE_GUNZIP || applet_name[1] == 'c')) 391 if (ENABLE_ZCAT && applet_name[1] == 'c')
392 option_mask32 |= BBUNPK_OPT_STDOUT | BBUNPK_SEAMLESS_MAGIC; 392 option_mask32 |= BBUNPK_OPT_STDOUT | BBUNPK_SEAMLESS_MAGIC;
393 393
394 return bbunpack(argv, unpack_gz_stream, make_new_name_gunzip, /*unused:*/ NULL); 394 return bbunpack(argv, unpack_gz_stream, make_new_name_gunzip, /*unused:*/ NULL);
diff --git a/archival/cpio.c b/archival/cpio.c
index 0f37ffbb9..94b4b8174 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -516,6 +516,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
516 if (archive_handle->cpio__blocks != (off_t)-1 516 if (archive_handle->cpio__blocks != (off_t)-1
517 && !(opt & OPT_QUIET) 517 && !(opt & OPT_QUIET)
518 ) { 518 ) {
519 fflush_all();
519 fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks); 520 fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
520 } 521 }
521 522
diff --git a/archival/dpkg.c b/archival/dpkg.c
index 6f28b994c..61631bd4d 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -1209,6 +1209,27 @@ static char **create_list(const char *filename)
1209 return file_list; 1209 return file_list;
1210} 1210}
1211 1211
1212/** This tests if the filename is an "important" directory, which might be symlinked.
1213 * Debians dpkg test if directories are used by other packages, this
1214 * implementation doesn't and would remove for ex. an lib -> usr/lib symlink.
1215 */
1216static int is_builtin_exclude(const char *name)
1217{
1218 if (*name++ != '/')
1219 return 0;
1220 if (index_in_strings(".\0" "etc\0" "opt\0" "srv\0" "var\0" "var/lib\0",
1221 name) >= 0)
1222 return 1;
1223 if (is_prefixed_with(name, "usr/")) {
1224 name += sizeof("usr/") - 1;
1225 if (is_prefixed_with(name, "local/"))
1226 name += sizeof("local/") - 1;
1227 }
1228
1229 return index_in_strings("bin\0" "lib\0" "lib32\0" "lib64\0" "sbin\0",
1230 name) >= 0;
1231}
1232
1212/* maybe i should try and hook this into remove_file.c somehow */ 1233/* maybe i should try and hook this into remove_file.c somehow */
1213static int remove_file_array(char **remove_names, char **exclude_names) 1234static int remove_file_array(char **remove_names, char **exclude_names)
1214{ 1235{
@@ -1220,6 +1241,8 @@ static int remove_file_array(char **remove_names, char **exclude_names)
1220 return 0; 1241 return 0;
1221 } 1242 }
1222 for (i = 0; remove_names[i] != NULL; i++) { 1243 for (i = 0; remove_names[i] != NULL; i++) {
1244 if (is_builtin_exclude(remove_names[i]))
1245 continue;
1223 if (exclude_names != NULL) { 1246 if (exclude_names != NULL) {
1224 for (j = 0; exclude_names[j] != NULL; j++) { 1247 for (j = 0; exclude_names[j] != NULL; j++) {
1225 if (strcmp(remove_names[i], exclude_names[j]) == 0) { 1248 if (strcmp(remove_names[i], exclude_names[j]) == 0) {
diff --git a/coreutils/expand.c b/coreutils/expand.c
index 4fa974df8..5f5993921 100644
--- a/coreutils/expand.c
+++ b/coreutils/expand.c
@@ -160,7 +160,7 @@ static void unexpand(FILE *file, unsigned tab_size, unsigned opt)
160 putchar('\t'); 160 putchar('\t');
161 } 161 }
162 162
163 if ((opt & OPT_INITIAL) && ptr != line) { 163 if (!(opt & OPT_ALL) && ptr != line) {
164 printf("%*s%s", len, "", ptr); 164 printf("%*s%s", len, "", ptr);
165 break; 165 break;
166 } 166 }
@@ -207,13 +207,13 @@ int expand_main(int argc UNUSED_PARAM, char **argv)
207 "ft:a" 207 "ft:a"
208 "\0" 208 "\0"
209 "ta" /* -t NUM sets -a */, 209 "ta" /* -t NUM sets -a */,
210 "first-only\0" No_argument "i" 210 "first-only\0" No_argument "f"
211 "tabs\0" Required_argument "t" 211 "tabs\0" Required_argument "t"
212 "all\0" No_argument "a" 212 "all\0" No_argument "a"
213 , &opt_t 213 , &opt_t
214 ); 214 );
215 /* -f --first-only is the default */ 215 /* -t implies -a, but an explicit -f overrides */
216 if (!(opt & OPT_ALL)) opt |= OPT_INITIAL; 216 if (opt & OPT_INITIAL) opt &= ~OPT_ALL;
217 } 217 }
218 tab_size = xatou_range(opt_t, 1, UINT_MAX); 218 tab_size = xatou_range(opt_t, 1, UINT_MAX);
219 219
diff --git a/editors/awk.c b/editors/awk.c
index 76385f33b..509f4ddd8 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -1363,8 +1363,10 @@ static node *parse_expr(uint32_t iexp)
1363 v = cn->l.v = xzalloc(sizeof(var)); 1363 v = cn->l.v = xzalloc(sizeof(var));
1364 if (tc & TC_NUMBER) 1364 if (tc & TC_NUMBER)
1365 setvar_i(v, t_double); 1365 setvar_i(v, t_double);
1366 else 1366 else {
1367 setvar_s(v, t_string); 1367 setvar_s(v, t_string);
1368 xtc &= ~TC_UOPPOST; /* "str"++ is not allowed */
1369 }
1368 break; 1370 break;
1369 1371
1370 case TC_REGEXP: 1372 case TC_REGEXP:
diff --git a/editors/patch.c b/editors/patch.c
index 0ce0210fd..aaa253591 100644
--- a/editors/patch.c
+++ b/editors/patch.c
@@ -264,7 +264,7 @@ static int apply_one_hunk(void)
264 if (!plist && matcheof) break; 264 if (!plist && matcheof) break;
265 265
266 if (backwarn) 266 if (backwarn)
267 fdprintf(2,"Possibly reversed hunk %d at %ld\n", 267 fdprintf(2, "Possibly reversed hunk %d at %ld\n",
268 TT.hunknum, TT.linenum); 268 TT.hunknum, TT.linenum);
269 269
270 // File ended before we found a place for this hunk. 270 // File ended before we found a place for this hunk.
@@ -593,6 +593,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
593 TT.linenum = 0; 593 TT.linenum = 0;
594 TT.hunknum = 0; 594 TT.hunknum = 0;
595 } 595 }
596 fflush_all(); // make "patching file F" visible
596 } 597 }
597 598
598 TT.hunknum++; 599 TT.hunknum++;
diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script
index 6658fbeef..f079ec8b8 100755
--- a/examples/udhcp/simple.script
+++ b/examples/udhcp/simple.script
@@ -18,7 +18,7 @@ case "$1" in
18 deconfig) 18 deconfig)
19 echo "Clearing IP addresses on $interface, upping it" 19 echo "Clearing IP addresses on $interface, upping it"
20 if command -v ip >/dev/null; then 20 if command -v ip >/dev/null; then
21 ip addr flush dev $interface 21 ip -4 addr flush dev $interface
22 ip link set dev $interface up 22 ip link set dev $interface up
23 else 23 else
24 ifconfig $interface 0.0.0.0 24 ifconfig $interface 0.0.0.0
diff --git a/include/libbb.h b/include/libbb.h
index 7077f0e0d..32f4c4126 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -316,6 +316,7 @@ typedef unsigned long uoff_t;
316/* scary. better ideas? (but do *test* them first!) */ 316/* scary. better ideas? (but do *test* them first!) */
317#define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1))) 317#define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1)))
318/* Users report bionic to use 32-bit off_t even if LARGEFILE support is requested. 318/* Users report bionic to use 32-bit off_t even if LARGEFILE support is requested.
319 * On musl, !ENABLE_LFS on 32-bit arches thinks that off_t is 32-bit.
319 * We misdetected that. Don't let it build: 320 * We misdetected that. Don't let it build:
320 */ 321 */
321struct BUG_off_t_size_is_misdetected { 322struct BUG_off_t_size_is_misdetected {
@@ -1428,8 +1429,10 @@ static inline void __attribute__ ((deprecated("use bb_simple_info_msg instead"))
1428#define bb_perror_msg_and_die(...) BB_MSG(_perror_msg_and_die, BB_MSG_KIND(__VA_ARGS__), __VA_ARGS__) 1429#define bb_perror_msg_and_die(...) BB_MSG(_perror_msg_and_die, BB_MSG_KIND(__VA_ARGS__), __VA_ARGS__)
1429#define bb_herror_msg(...) BB_MSG(_herror_msg, BB_MSG_KIND(__VA_ARGS__), __VA_ARGS__) 1430#define bb_herror_msg(...) BB_MSG(_herror_msg, BB_MSG_KIND(__VA_ARGS__), __VA_ARGS__)
1430#define bb_herror_msg_and_die(...) BB_MSG(_herror_msg_and_die, BB_MSG_KIND(__VA_ARGS__), __VA_ARGS__) 1431#define bb_herror_msg_and_die(...) BB_MSG(_herror_msg_and_die, BB_MSG_KIND(__VA_ARGS__), __VA_ARGS__)
1432#if ENABLE_FEATURE_SYSLOG_INFO
1431#define bb_info_msg(...) BB_MSG(_info_msg, BB_MSG_KIND(__VA_ARGS__), __VA_ARGS__) 1433#define bb_info_msg(...) BB_MSG(_info_msg, BB_MSG_KIND(__VA_ARGS__), __VA_ARGS__)
1432#endif 1434#endif
1435#endif
1433 1436
1434/* We need to export XXX_main from libbusybox 1437/* We need to export XXX_main from libbusybox
1435 * only if we build "individual" binaries 1438 * only if we build "individual" binaries
diff --git a/include/platform.h b/include/platform.h
index afd8cf292..f1c09c4d2 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -39,6 +39,10 @@
39# endif 39# endif
40#endif 40#endif
41 41
42#if !__GNUC_PREREQ(5,0)
43# define deprecated(msg) deprecated
44#endif
45
42#undef inline 46#undef inline
43#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L 47#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L
44/* it's a keyword */ 48/* it's a keyword */
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 8c46d0d1b..d2f98567e 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -794,7 +794,9 @@ static void install_links(const char *busybox UNUSED_PARAM,
794} 794}
795# endif 795# endif
796 796
797# if ENABLE_BUSYBOX || NUM_APPLETS > 0
797static void run_applet_and_exit(const char *name, char **argv) NORETURN; 798static void run_applet_and_exit(const char *name, char **argv) NORETURN;
799#endif
798 800
799# if NUM_SCRIPTS > 0 801# if NUM_SCRIPTS > 0
800static int find_script_by_name(const char *name) 802static int find_script_by_name(const char *name)
@@ -815,13 +817,13 @@ int scripted_main(int argc UNUSED_PARAM, char **argv)
815{ 817{
816 int script = find_script_by_name(applet_name); 818 int script = find_script_by_name(applet_name);
817 if (script >= 0) 819 if (script >= 0)
818#if ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH 820# if ENABLE_SHELL_ASH
819 exit(ash_main(-script - 1, argv)); 821 exit(ash_main(-script - 1, argv));
820#elif ENABLE_HUSH || ENABLE_SH_IS_HUSH || ENABLE_BASH_IS_HUSH 822# elif ENABLE_SHELL_HUSH
821 exit(hush_main(-script - 1, argv)); 823 exit(hush_main(-script - 1, argv));
822#else 824# else
823 return 1; 825 return 1;
824#endif 826# endif
825 return 0; 827 return 0;
826} 828}
827 829
@@ -1160,7 +1162,33 @@ static NORETURN void run_applet_and_exit(const char *name, char **argv)
1160} 1162}
1161# endif 1163# endif
1162 1164
1163#endif /* !defined(SINGLE_APPLET_MAIN) */ 1165#else /* defined(SINGLE_APPLET_MAIN) */
1166
1167# if NUM_SCRIPTS > 0
1168/* if SINGLE_APPLET_MAIN, these two functions are simpler: */
1169int scripted_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE;
1170int scripted_main(int argc UNUSED_PARAM, char **argv)
1171{
1172# if ENABLE_SHELL_ASH
1173 int script = 0;
1174 exit(ash_main(-script - 1, argv));
1175# elif ENABLE_SHELL_HUSH
1176 int script = 0;
1177 exit(hush_main(-script - 1, argv));
1178# else
1179 return 1;
1180# endif
1181}
1182char* FAST_FUNC
1183get_script_content(unsigned n UNUSED_PARAM)
1184{
1185 char *t = unpack_bz2_data(packed_scripts, sizeof(packed_scripts),
1186 UNPACKED_SCRIPTS_LENGTH);
1187 return t;
1188}
1189# endif /* NUM_SCRIPTS > 0 */
1190
1191#endif /* defined(SINGLE_APPLET_MAIN) */
1164 1192
1165 1193
1166#if ENABLE_BUILD_LIBBUSYBOX 1194#if ENABLE_BUILD_LIBBUSYBOX
diff --git a/libbb/compare_string_array.c b/libbb/compare_string_array.c
index 856739c41..ede5a97e3 100644
--- a/libbb/compare_string_array.c
+++ b/libbb/compare_string_array.c
@@ -158,8 +158,11 @@ int FAST_FUNC index_in_substrings(const char *strings, const char *key)
158const char* FAST_FUNC nth_string(const char *strings, int n) 158const char* FAST_FUNC nth_string(const char *strings, int n)
159{ 159{
160 while (n) { 160 while (n) {
161 n--; 161 if (*strings++ == '\0') {
162 strings += strlen(strings) + 1; 162 if (*strings == '\0') /* reached end of strings */
163 break;
164 n--;
165 }
163 } 166 }
164 return strings; 167 return strings;
165} 168}
diff --git a/libbb/duration.c b/libbb/duration.c
index 5acd0dba3..22b209f4d 100644
--- a/libbb/duration.c
+++ b/libbb/duration.c
@@ -17,6 +17,7 @@
17//kbuild:lib-$(CONFIG_TIMEOUT) += duration.o 17//kbuild:lib-$(CONFIG_TIMEOUT) += duration.o
18//kbuild:lib-$(CONFIG_PING) += duration.o 18//kbuild:lib-$(CONFIG_PING) += duration.o
19//kbuild:lib-$(CONFIG_PING6) += duration.o 19//kbuild:lib-$(CONFIG_PING6) += duration.o
20//kbuild:lib-$(CONFIG_WATCH) += duration.o
20 21
21#include "libbb.h" 22#include "libbb.h"
22 23
diff --git a/libbb/last_char_is.c b/libbb/last_char_is.c
index 66f2e3635..918526e6c 100644
--- a/libbb/last_char_is.c
+++ b/libbb/last_char_is.c
@@ -8,16 +8,17 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11/* Find out if the last character of a string matches the one given. 11/* Find out if the last character of a string matches the one given */
12 * Don't underrun the buffer if the string length is 0.
13 */
14char* FAST_FUNC last_char_is(const char *s, int c) 12char* FAST_FUNC last_char_is(const char *s, int c)
15{ 13{
16 if (s && *s) { 14 if (s) {
17 size_t sz = strlen(s) - 1; 15 size_t sz = strlen(s);
18 s += sz; 16 /* Don't underrun the buffer if the string length is 0 */
19 if ( (unsigned char)*s == c) 17 if (sz != 0) {
20 return (char*)s; 18 s += sz - 1;
19 if ((unsigned char)*s == c)
20 return (char*)s;
21 }
21 } 22 }
22 return NULL; 23 return NULL;
23} 24}
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index f4247d237..a36a1647d 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -99,7 +99,7 @@ static bool BB_ispunct(CHAR_T c)
99# if ENABLE_FEATURE_EDITING_VI 99# if ENABLE_FEATURE_EDITING_VI
100static bool BB_isalnum_or_underscore(CHAR_T c) 100static bool BB_isalnum_or_underscore(CHAR_T c)
101{ 101{
102 return ((unsigned)c < 256 && isalnum(c)) || c == '_'; 102 return isalnum(c) || c == '_';
103} 103}
104# endif 104# endif
105# define BB_ispunct(c) ispunct(c) 105# define BB_ispunct(c) ispunct(c)
diff --git a/libbb/procps.c b/libbb/procps.c
index e6892d7ff..4f9705bc1 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -178,6 +178,15 @@ static char *skip_fields(char *str, int count)
178} 178}
179#endif 179#endif
180 180
181static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix)
182{
183 char *tp = is_prefixed_with(buf, prefix);
184 if (tp) {
185 tp = skip_whitespace(tp);
186 }
187 return tp;
188}
189
181#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 190#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
182int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, 191int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
183 void (*cb)(struct smaprec *, void *), void *data) 192 void (*cb)(struct smaprec *, void *), void *data)
@@ -208,8 +217,7 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
208 char *tp, *p; 217 char *tp, *p;
209 218
210#define SCAN(S, X) \ 219#define SCAN(S, X) \
211 if ((tp = is_prefixed_with(buf, S)) != NULL) { \ 220 if ((tp = skip_whitespace_if_prefixed_with(buf, S)) != NULL) { \
212 tp = skip_whitespace(tp); \
213 total->X += currec.X = fast_strtoul_10(&tp); \ 221 total->X += currec.X = fast_strtoul_10(&tp); \
214 continue; \ 222 continue; \
215 } 223 }
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index cfe062a47..6fdc0f6a4 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -93,26 +93,17 @@ char* FAST_FUNC xstrdup(const char *s)
93// the (possibly truncated to length n) string into it. 93// the (possibly truncated to length n) string into it.
94char* FAST_FUNC xstrndup(const char *s, int n) 94char* FAST_FUNC xstrndup(const char *s, int n)
95{ 95{
96 int m;
97 char *t; 96 char *t;
98 97
99 if (ENABLE_DEBUG && s == NULL) 98 if (ENABLE_DEBUG && s == NULL)
100 bb_simple_error_msg_and_die("xstrndup bug"); 99 bb_simple_error_msg_and_die("xstrndup bug");
101 100
102 /* We can just xmalloc(n+1) and strncpy into it, */ 101 t = strndup(s, n);
103 /* but think about xstrndup("abc", 10000) wastage! */
104 m = n;
105 t = (char*) s;
106 while (m) {
107 if (!*t) break;
108 m--;
109 t++;
110 }
111 n -= m;
112 t = xmalloc(n + 1);
113 t[n] = '\0';
114 102
115 return memcpy(t, s, n); 103 if (t == NULL)
104 bb_die_memory_exhausted();
105
106 return t;
116} 107}
117 108
118void* FAST_FUNC xmemdup(const void *s, int n) 109void* FAST_FUNC xmemdup(const void *s, int n)
diff --git a/loginutils/deluser.c b/loginutils/deluser.c
index 56bc7eaa6..8e7df737c 100644
--- a/loginutils/deluser.c
+++ b/loginutils/deluser.c
@@ -99,8 +99,14 @@ int deluser_main(int argc, char **argv)
99 pfile = bb_path_passwd_file; 99 pfile = bb_path_passwd_file;
100 if (ENABLE_FEATURE_SHADOWPASSWDS) 100 if (ENABLE_FEATURE_SHADOWPASSWDS)
101 sfile = bb_path_shadow_file; 101 sfile = bb_path_shadow_file;
102 if (opt_delhome) 102 if (opt_delhome) {
103 remove_file(pw->pw_dir, FILEUTILS_RECUR); 103 struct stat st;
104
105 /* Make sure home is an actual directory before
106 * removing it (e.g. users with /dev/null as home) */
107 if (stat(pw->pw_dir, &st) == 0 && S_ISDIR(st.st_mode))
108 remove_file(pw->pw_dir, FILEUTILS_RECUR);
109 }
104 } else { 110 } else {
105 struct group *gr; 111 struct group *gr;
106 do_delgroup: 112 do_delgroup:
diff --git a/make_single_applets.sh b/make_single_applets.sh
index a37168cdf..7df53397e 100755
--- a/make_single_applets.sh
+++ b/make_single_applets.sh
@@ -29,6 +29,8 @@ for app in $apps; do
29done 29done
30# remove "busybox" as well 30# remove "busybox" as well
31allno="`echo "$allno" | sed "s/^CONFIG_BUSYBOX=y\$/# CONFIG_BUSYBOX is not set/"`" 31allno="`echo "$allno" | sed "s/^CONFIG_BUSYBOX=y\$/# CONFIG_BUSYBOX is not set/"`"
32# disable any CONFIG_script_DEPENDENCIES as well
33allno="`echo "$allno" | sed "s/^\(CONFIG_.*_DEPENDENCIES\)=y\$/# \1 is not set/"`"
32#echo "$allno" >.config_allno 34#echo "$allno" >.config_allno
33 35
34trap 'test -f .config.SV && mv .config.SV .config && touch .config' EXIT 36trap 'test -f .config.SV && mv .config.SV .config && touch .config' EXIT
diff --git a/miscutils/bc.c b/miscutils/bc.c
index c7246ea1a..4d987325e 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -2522,7 +2522,9 @@ static void xc_read_line(BcVec *vec, FILE *fp)
2522 2522
2523#if ENABLE_FEATURE_BC_INTERACTIVE 2523#if ENABLE_FEATURE_BC_INTERACTIVE
2524 if (G_interrupt) { // ^C was pressed 2524 if (G_interrupt) { // ^C was pressed
2525# if ENABLE_FEATURE_EDITING
2525 intr: 2526 intr:
2527# endif
2526 if (fp != stdin) { 2528 if (fp != stdin) {
2527 // ^C while running a script (bc SCRIPT): die. 2529 // ^C while running a script (bc SCRIPT): die.
2528 // We do not return to interactive prompt: 2530 // We do not return to interactive prompt:
diff --git a/miscutils/devfsd.c b/miscutils/devfsd.c
index f3d935b2e..d47ee4d47 100644
--- a/miscutils/devfsd.c
+++ b/miscutils/devfsd.c
@@ -353,6 +353,7 @@ static const char bb_msg_variable_not_found[] ALIGN1 = "variable: %s not found";
353#define error_logger_and_die(p, fmt, args...) bb_perror_msg_and_die(fmt, ## args) 353#define error_logger_and_die(p, fmt, args...) bb_perror_msg_and_die(fmt, ## args)
354#else 354#else
355#define info_logger(p, fmt, args...) 355#define info_logger(p, fmt, args...)
356#define simple_info_logger(p, msg)
356#define msg_logger(p, fmt, args...) 357#define msg_logger(p, fmt, args...)
357#define simple_msg_logger(p, msg) 358#define simple_msg_logger(p, msg)
358#define msg_logger_and_die(p, fmt, args...) exit(EXIT_FAILURE) 359#define msg_logger_and_die(p, fmt, args...) exit(EXIT_FAILURE)
diff --git a/networking/brctl.c b/networking/brctl.c
index 25640246d..2f4ac4a87 100644
--- a/networking/brctl.c
+++ b/networking/brctl.c
@@ -107,7 +107,7 @@ static unsigned str_to_jiffies(const char *time_str)
107 107
108#define filedata bb_common_bufsiz1 108#define filedata bb_common_bufsiz1
109 109
110#if ENABLE_FEATURE_BRCTL_SHOW 110#if ENABLE_FEATURE_BRCTL_SHOW || ENABLE_FEATURE_BRCTL_FANCY
111static int read_file(const char *name) 111static int read_file(const char *name)
112{ 112{
113 int n = open_read_close(name, filedata, COMMON_BUFSIZE - 1); 113 int n = open_read_close(name, filedata, COMMON_BUFSIZE - 1);
@@ -120,7 +120,9 @@ static int read_file(const char *name)
120 } 120 }
121 return n; 121 return n;
122} 122}
123#endif
123 124
125#if ENABLE_FEATURE_BRCTL_SHOW
124/* NB: we are in /sys/class/net 126/* NB: we are in /sys/class/net
125 */ 127 */
126static int show_bridge(const char *name, int need_hdr) 128static int show_bridge(const char *name, int need_hdr)
@@ -591,6 +593,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
591 return EXIT_SUCCESS; 593 return EXIT_SUCCESS;
592 } 594 }
593 595
596#if ENABLE_FEATURE_BRCTL_FANCY
594 if (key == ARG_showmacs) { 597 if (key == ARG_showmacs) {
595 show_bridge_macs(br); 598 show_bridge_macs(br);
596 return EXIT_SUCCESS; 599 return EXIT_SUCCESS;
@@ -599,6 +602,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
599 show_bridge_stp(br); 602 show_bridge_stp(br);
600 return EXIT_SUCCESS; 603 return EXIT_SUCCESS;
601 } 604 }
605#endif
602 606
603 if (!*argv) /* All of the below need at least two arguments */ 607 if (!*argv) /* All of the below need at least two arguments */
604 bb_show_usage(); 608 bb_show_usage();
diff --git a/networking/httpd.c b/networking/httpd.c
index eeaa4bec1..5105eedac 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -2871,6 +2871,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2871#if !BB_MMU 2871#if !BB_MMU
2872 if (!(opt & OPT_FOREGROUND)) { 2872 if (!(opt & OPT_FOREGROUND)) {
2873 bb_daemonize_or_rexec(0, argv); /* don't change current directory */ 2873 bb_daemonize_or_rexec(0, argv); /* don't change current directory */
2874 re_execed = 0; /* for the following chdir to work */
2874 } 2875 }
2875#endif 2876#endif
2876#else /* ENABLE_PLATFORM_MINGW32 */ 2877#else /* ENABLE_PLATFORM_MINGW32 */
@@ -2878,8 +2879,8 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2878 mingw_daemonize(argv); 2879 mingw_daemonize(argv);
2879#endif 2880#endif
2880 2881
2881 /* Chdir to home (unless we were re-execed for NOMMU case: 2882 /* Chdir to home (unless we were re_exec()ed for NOMMU case
2882 * we are already in the home dir then). 2883 * in mini_httpd_nommu(): we are already in the home dir then).
2883 */ 2884 */
2884#if ENABLE_PLATFORM_MINGW32 2885#if ENABLE_PLATFORM_MINGW32
2885 if (!(opt & OPT_INETD)) 2886 if (!(opt & OPT_INETD))
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 034e03d21..88eda6b28 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -84,6 +84,7 @@
84//usage: ) 84//usage: )
85//usage: "\n -n Don't do DNS resolution" 85//usage: "\n -n Don't do DNS resolution"
86//usage: "\n -u UDP mode" 86//usage: "\n -u UDP mode"
87//usage: "\n -b Allow broadcasts"
87//usage: "\n -v Verbose" 88//usage: "\n -v Verbose"
88//usage: IF_NC_EXTRA( 89//usage: IF_NC_EXTRA(
89//usage: "\n -o FILE Hex dump traffic" 90//usage: "\n -o FILE Hex dump traffic"
@@ -171,17 +172,19 @@ enum {
171 OPT_p = (1 << 1), 172 OPT_p = (1 << 1),
172 OPT_s = (1 << 2), 173 OPT_s = (1 << 2),
173 OPT_u = (1 << 3), 174 OPT_u = (1 << 3),
174 OPT_v = (1 << 4), 175 OPT_b = (1 << 4),
175 OPT_w = (1 << 5), 176 OPT_v = (1 << 5),
176 OPT_l = (1 << 6) * ENABLE_NC_SERVER, 177 OPT_w = (1 << 6),
177 OPT_k = (1 << 7) * ENABLE_NC_SERVER, 178 OPT_l = (1 << 7) * ENABLE_NC_SERVER,
178 OPT_i = (1 << (6+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, 179 OPT_k = (1 << 8) * ENABLE_NC_SERVER,
179 OPT_o = (1 << (7+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, 180 OPT_i = (1 << (7+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
180 OPT_z = (1 << (8+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, 181 OPT_o = (1 << (8+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
182 OPT_z = (1 << (9+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
181}; 183};
182 184
183#define o_nflag (option_mask32 & OPT_n) 185#define o_nflag (option_mask32 & OPT_n)
184#define o_udpmode (option_mask32 & OPT_u) 186#define o_udpmode (option_mask32 & OPT_u)
187#define o_bcmode (option_mask32 & OPT_b)
185#if ENABLE_NC_EXTRA 188#if ENABLE_NC_EXTRA
186#define o_ofile (option_mask32 & OPT_o) 189#define o_ofile (option_mask32 & OPT_o)
187#define o_zero (option_mask32 & OPT_z) 190#define o_zero (option_mask32 & OPT_z)
@@ -788,7 +791,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv)
788 791
789 // -g -G -t -r deleted, unimplemented -a deleted too 792 // -g -G -t -r deleted, unimplemented -a deleted too
790 getopt32(argv, "^" 793 getopt32(argv, "^"
791 "np:s:uvw:+"/* -w N */ IF_NC_SERVER("lk") 794 "np:s:ubvw:+"/* -w N */ IF_NC_SERVER("lk")
792 IF_NC_EXTRA("i:o:z") 795 IF_NC_EXTRA("i:o:z")
793 "\0" 796 "\0"
794 "?2:vv"IF_NC_SERVER(":ll"), /* max 2 params; -v and -l are counters */ 797 "?2:vv"IF_NC_SERVER(":ll"), /* max 2 params; -v and -l are counters */
@@ -851,8 +854,11 @@ int nc_main(int argc UNUSED_PARAM, char **argv)
851 } 854 }
852 xmove_fd(x, netfd); 855 xmove_fd(x, netfd);
853 setsockopt_reuseaddr(netfd); 856 setsockopt_reuseaddr(netfd);
854 if (o_udpmode) 857 if (o_udpmode) {
858 if (o_bcmode)
859 setsockopt_broadcast(netfd);
855 socket_want_pktinfo(netfd); 860 socket_want_pktinfo(netfd);
861 }
856 if (!ENABLE_FEATURE_UNIX_LOCAL 862 if (!ENABLE_FEATURE_UNIX_LOCAL
857 || cnt_l != 0 /* listen */ 863 || cnt_l != 0 /* listen */
858 || ouraddr->u.sa.sa_family != AF_UNIX 864 || ouraddr->u.sa.sa_family != AF_UNIX
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 9ec752dfc..20d843bab 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -15,7 +15,7 @@ const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = {
15}; 15};
16 16
17#if ENABLE_UDHCPC || ENABLE_UDHCPD 17#if ENABLE_UDHCPC || ENABLE_UDHCPD
18/* Supported options are easily added here. 18/* Supported options are easily added here, they need to be sorted.
19 * See RFC2132 for more options. 19 * See RFC2132 for more options.
20 * OPTION_REQ: these options are requested by udhcpc (unless -o). 20 * OPTION_REQ: these options are requested by udhcpc (unless -o).
21 */ 21 */
@@ -222,79 +222,91 @@ unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings
222 } 222 }
223} 223}
224 224
225/* Get an option with bounds checking (warning, result is not aligned) */ 225/* Initialize state to be used between subsequent udhcp_scan_options calls */
226uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) 226void FAST_FUNC init_scan_state(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state)
227{
228 scan_state->overload = 0;
229 scan_state->rem = sizeof(packet->options);
230 scan_state->optionptr = packet->options;
231}
232
233/* Iterate over packet's options, each call returning the next option.
234 * scan_state needs to be initialized with init_scan_state beforehand.
235 * Warning, result is not aligned. */
236uint8_t* FAST_FUNC udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state)
227{ 237{
228 uint8_t *optionptr;
229 int len; 238 int len;
230 int rem;
231 int overload = 0;
232 enum { 239 enum {
233 FILE_FIELD101 = FILE_FIELD * 0x101, 240 FILE_FIELD101 = FILE_FIELD * 0x101,
234 SNAME_FIELD101 = SNAME_FIELD * 0x101, 241 SNAME_FIELD101 = SNAME_FIELD * 0x101,
235 }; 242 };
236 243
237 /* option bytes: [code][len][data1][data2]..[dataLEN] */ 244 /* option bytes: [code][len][data1][data2]..[dataLEN] */
238 optionptr = packet->options;
239 rem = sizeof(packet->options);
240 while (1) { 245 while (1) {
241 if (rem <= 0) { 246 if (scan_state->rem <= 0) {
242 complain: 247 complain:
243 bb_simple_error_msg("bad packet, malformed option field"); 248 bb_simple_error_msg("bad packet, malformed option field");
244 return NULL; 249 return NULL;
245 } 250 }
246 251
247 /* DHCP_PADDING and DHCP_END have no [len] byte */ 252 /* DHCP_PADDING and DHCP_END have no [len] byte */
248 if (optionptr[OPT_CODE] == DHCP_PADDING) { 253 if (scan_state->optionptr[OPT_CODE] == DHCP_PADDING) {
249 rem--; 254 scan_state->rem--;
250 optionptr++; 255 scan_state->optionptr++;
251 continue; 256 continue;
252 } 257 }
253 if (optionptr[OPT_CODE] == DHCP_END) { 258 if (scan_state->optionptr[OPT_CODE] == DHCP_END) {
254 if ((overload & FILE_FIELD101) == FILE_FIELD) { 259 if ((scan_state->overload & FILE_FIELD101) == FILE_FIELD) {
255 /* can use packet->file, and didn't look at it yet */ 260 /* can use packet->file, and didn't look at it yet */
256 overload |= FILE_FIELD101; /* "we looked at it" */ 261 scan_state->overload |= FILE_FIELD101; /* "we looked at it" */
257 optionptr = packet->file; 262 scan_state->optionptr = packet->file;
258 rem = sizeof(packet->file); 263 scan_state->rem = sizeof(packet->file);
259 continue; 264 continue;
260 } 265 }
261 if ((overload & SNAME_FIELD101) == SNAME_FIELD) { 266 if ((scan_state->overload & SNAME_FIELD101) == SNAME_FIELD) {
262 /* can use packet->sname, and didn't look at it yet */ 267 /* can use packet->sname, and didn't look at it yet */
263 overload |= SNAME_FIELD101; /* "we looked at it" */ 268 scan_state->overload |= SNAME_FIELD101; /* "we looked at it" */
264 optionptr = packet->sname; 269 scan_state->optionptr = packet->sname;
265 rem = sizeof(packet->sname); 270 scan_state->rem = sizeof(packet->sname);
266 continue; 271 continue;
267 } 272 }
268 break; 273 break;
269 } 274 }
270 275
271 if (rem <= OPT_LEN) 276 if (scan_state->rem <= OPT_LEN)
272 goto complain; /* complain and return NULL */ 277 goto complain; /* complain and return NULL */
273 len = 2 + optionptr[OPT_LEN]; 278 len = 2 + scan_state->optionptr[OPT_LEN];
274 rem -= len; 279 scan_state->rem -= len;
275 if (rem < 0) 280 /* So far no valid option with length 0 known. */
281 if (scan_state->rem < 0 || scan_state->optionptr[OPT_LEN] == 0)
276 goto complain; /* complain and return NULL */ 282 goto complain; /* complain and return NULL */
277 283
278 if (optionptr[OPT_CODE] == code) { 284 if (scan_state->optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
279 if (optionptr[OPT_LEN] == 0) { 285 if (len >= 3)
280 /* So far no valid option with length 0 known. 286 scan_state->overload |= scan_state->optionptr[OPT_DATA];
281 * Having this check means that searching 287 } else {
282 * for DHCP_MESSAGE_TYPE need not worry 288 uint8_t *return_ptr = scan_state->optionptr;
283 * that returned pointer might be unsafe 289 scan_state->optionptr += len;
284 * to dereference. 290 return return_ptr;
285 */
286 goto complain; /* complain and return NULL */
287 }
288 log_option("option found", optionptr);
289 return optionptr + OPT_DATA;
290 } 291 }
292 scan_state->optionptr += len;
293 }
291 294
292 if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) { 295 return NULL;
293 if (len >= 3) 296}
294 overload |= optionptr[OPT_DATA]; 297
295 /* fall through */ 298/* Get an option with bounds checking (warning, result is not aligned) */
299uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
300{
301 uint8_t *optptr;
302 struct dhcp_scan_state scan_state;
303
304 init_scan_state(packet, &scan_state);
305 while ((optptr = udhcp_scan_options(packet, &scan_state)) != NULL) {
306 if (optptr[OPT_CODE] == code) {
307 log_option("option found", optptr);
308 return optptr + OPT_DATA;
296 } 309 }
297 optionptr += len;
298 } 310 }
299 311
300 /* log3 because udhcpc uses it a lot - very noisy */ 312 /* log3 because udhcpc uses it a lot - very noisy */
@@ -431,7 +443,7 @@ static NOINLINE void attach_option(
431#if ENABLE_FEATURE_UDHCP_RFC3397 443#if ENABLE_FEATURE_UDHCP_RFC3397
432 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { 444 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
433 /* reuse buffer and length for RFC1035-formatted string */ 445 /* reuse buffer and length for RFC1035-formatted string */
434 allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length); 446 allocated = buffer = (char *)dname_enc(/*NULL, 0,*/ buffer, &length);
435 } 447 }
436#endif 448#endif
437 449
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 60255eefa..81c1dcbdc 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -78,7 +78,7 @@ struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet {
78/*** Options ***/ 78/*** Options ***/
79 79
80enum { 80enum {
81 OPTION_IP = 1, 81 OPTION_IP = 0,
82 OPTION_IP_PAIR, 82 OPTION_IP_PAIR,
83 OPTION_STRING, 83 OPTION_STRING,
84 /* Opts of STRING_HOST type will be sanitized before they are passed 84 /* Opts of STRING_HOST type will be sanitized before they are passed
@@ -107,6 +107,12 @@ enum {
107 OPTION_LIST = 0x20, 107 OPTION_LIST = 0x20,
108}; 108};
109 109
110struct dhcp_scan_state {
111 int overload;
112 int rem;
113 uint8_t *optionptr;
114};
115
110/* DHCP option codes (partial list). See RFC 2132 and 116/* DHCP option codes (partial list). See RFC 2132 and
111 * http://www.iana.org/assignments/bootp-dhcp-parameters/ 117 * http://www.iana.org/assignments/bootp-dhcp-parameters/
112 * Commented out options are handled by common option machinery, 118 * Commented out options are handled by common option machinery,
@@ -206,6 +212,8 @@ extern const uint8_t dhcp_option_lengths[] ALIGN1;
206 212
207unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings); 213unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings);
208 214
215void init_scan_state(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state) FAST_FUNC;
216uint8_t *udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_scan_state *scan_state) FAST_FUNC;
209uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC; 217uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC;
210/* Same as above + ensures that option length is 4 bytes 218/* Same as above + ensures that option length is 4 bytes
211 * (returns NULL if size is different) 219 * (returns NULL if size is different)
@@ -218,7 +226,7 @@ void udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t
218#endif 226#endif
219#if ENABLE_FEATURE_UDHCP_RFC3397 || ENABLE_FEATURE_UDHCPC6_RFC3646 || ENABLE_FEATURE_UDHCPC6_RFC4704 227#if ENABLE_FEATURE_UDHCP_RFC3397 || ENABLE_FEATURE_UDHCPC6_RFC3646 || ENABLE_FEATURE_UDHCPC6_RFC4704
220char *dname_dec(const uint8_t *cstr, int clen, const char *pre) FAST_FUNC; 228char *dname_dec(const uint8_t *cstr, int clen, const char *pre) FAST_FUNC;
221uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) FAST_FUNC; 229uint8_t *dname_enc(/*const uint8_t *cstr, int clen,*/ const char *src, int *retlen) FAST_FUNC;
222#endif 230#endif
223struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) FAST_FUNC; 231struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) FAST_FUNC;
224 232
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 85c410a7c..fc2d672b7 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -553,11 +553,15 @@ static int d6_mcast_from_client_data_ifindex(struct d6_packet *packet, uint8_t *
553 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 553 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 554 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
555 }; 555 };
556 /* IPv6 requires different multicast contents in Ethernet Frame (RFC 2464) */
557 static const uint8_t MAC_DHCP6MCAST_ADDR[6] ALIGN2 = {
558 0x33, 0x33, 0x00, 0x01, 0x00, 0x02,
559 };
556 560
557 return d6_send_raw_packet( 561 return d6_send_raw_packet(
558 packet, (end - (uint8_t*) packet), 562 packet, (end - (uint8_t*) packet),
559 /*src*/ &client6_data.ll_ip6, CLIENT_PORT6, 563 /*src*/ &client6_data.ll_ip6, CLIENT_PORT6,
560 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_BCAST_ADDR, 564 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_DHCP6MCAST_ADDR,
561 client_data.ifindex 565 client_data.ifindex
562 ); 566 );
563} 567}
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 5a1f8fd7a..50dfead63 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -159,61 +159,27 @@ static int mton(uint32_t mask)
159} 159}
160 160
161#if ENABLE_FEATURE_UDHCPC_SANITIZEOPT 161#if ENABLE_FEATURE_UDHCPC_SANITIZEOPT
162/* Check if a given label represents a valid DNS label 162/* Check if a given name represents a valid DNS name */
163 * Return pointer to the first character after the label 163/* See RFC1035, 2.3.1 */
164 * (NUL or dot) upon success, NULL otherwise.
165 * See RFC1035, 2.3.1
166 */
167/* We don't need to be particularly anal. For example, allowing _, hyphen 164/* We don't need to be particularly anal. For example, allowing _, hyphen
168 * at the end, or leading and trailing dots would be ok, since it 165 * at the end, or leading and trailing dots would be ok, since it
169 * can't be used for attacks. (Leading hyphen can be, if someone uses 166 * can't be used for attacks. (Leading hyphen can be, if someone uses cmd "$hostname"
170 * cmd "$hostname"
171 * in the script: then hostname may be treated as an option) 167 * in the script: then hostname may be treated as an option)
172 */ 168 */
173static const char *valid_domain_label(const char *label)
174{
175 unsigned char ch;
176 //unsigned pos = 0;
177
178 if (label[0] == '-')
179 return NULL;
180 for (;;) {
181 ch = *label;
182 if ((ch|0x20) < 'a' || (ch|0x20) > 'z') {
183 if (ch < '0' || ch > '9') {
184 if (ch == '\0' || ch == '.')
185 return label;
186 /* DNS allows only '-', but we are more permissive */
187 if (ch != '-' && ch != '_')
188 return NULL;
189 }
190 }
191 label++;
192 //pos++;
193 //Do we want this?
194 //if (pos > 63) /* NS_MAXLABEL; labels must be 63 chars or less */
195 // return NULL;
196 }
197}
198
199/* Check if a given name represents a valid DNS name */
200/* See RFC1035, 2.3.1 */
201static int good_hostname(const char *name) 169static int good_hostname(const char *name)
202{ 170{
203 //const char *start = name; 171 if (*name == '-') /* Can't start with '-' */
204 172 return 0;
205 for (;;) { 173
206 name = valid_domain_label(name); 174 while (*name) {
207 if (!name) 175 unsigned char ch = *name++;
208 return 0; 176 if (!isalnum(ch))
209 if (!name[0]) 177 /* DNS allows only '-', but we are more permissive */
210 return 1; 178 if (ch != '-' && ch != '_' && ch != '.')
211 //Do we want this? 179 return 0;
212 //return ((name - start) < 1025); /* NS_MAXDNAME */ 180 // TODO: do we want to validate lengths against NS_MAXLABEL and NS_MAXDNAME?
213 name++;
214 if (*name == '\0')
215 return 1; // We allow trailing dot too
216 } 181 }
182 return 1;
217} 183}
218#else 184#else
219# define good_hostname(name) 1 185# define good_hostname(name) 1
@@ -242,9 +208,8 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
242 case OPTION_IP: 208 case OPTION_IP:
243 case OPTION_IP_PAIR: 209 case OPTION_IP_PAIR:
244 dest += sprint_nip(dest, "", option); 210 dest += sprint_nip(dest, "", option);
245 if (type == OPTION_IP) 211 if (type == OPTION_IP_PAIR)
246 break; 212 dest += sprint_nip(dest, "/", option + 4);
247 dest += sprint_nip(dest, "/", option + 4);
248 break; 213 break;
249// case OPTION_BOOLEAN: 214// case OPTION_BOOLEAN:
250// dest += sprintf(dest, *option ? "yes" : "no"); 215// dest += sprintf(dest, *option ? "yes" : "no");
@@ -346,7 +311,7 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
346 * IPv4MaskLen <= 32, 311 * IPv4MaskLen <= 32,
347 * 6rdPrefixLen <= 128, 312 * 6rdPrefixLen <= 128,
348 * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128 313 * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128
349 * (2nd condition need no check - it follows from 1st and 3rd). 314 * (2nd condition needs no check - it follows from 1st and 3rd).
350 * Else, return envvar with empty value ("optname=") 315 * Else, return envvar with empty value ("optname=")
351 */ 316 */
352 if (len >= (1 + 1 + 16 + 4) 317 if (len >= (1 + 1 + 16 + 4)
@@ -360,17 +325,12 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
360 /* 6rdPrefix */ 325 /* 6rdPrefix */
361 dest += sprint_nip6(dest, /* "", */ option); 326 dest += sprint_nip6(dest, /* "", */ option);
362 option += 16; 327 option += 16;
363 len -= 1 + 1 + 16 + 4; 328 len -= 1 + 1 + 16;
364 /* "+ 4" above corresponds to the length of IPv4 addr 329 *dest++ = ' ';
365 * we consume in the loop below */ 330 /* 6rdBRIPv4Address(es), use common IPv4 logic to process them */
366 while (1) { 331 type = OPTION_IP;
367 /* 6rdBRIPv4Address(es) */ 332 optlen = 4;
368 dest += sprint_nip(dest, " ", option); 333 continue;
369 option += 4;
370 len -= 4; /* do we have yet another 4+ bytes? */
371 if (len < 0)
372 break; /* no */
373 }
374 } 334 }
375 335
376 return ret; 336 return ret;
@@ -392,23 +352,18 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
392 */ 352 */
393 option++; 353 option++;
394 len--; 354 len--;
355 if (option[-1] == 1) {
356 /* use common IPv4 logic to process IP addrs */
357 type = OPTION_IP;
358 optlen = 4;
359 continue;
360 }
395 if (option[-1] == 0) { 361 if (option[-1] == 0) {
396 dest = dname_dec(option, len, ret); 362 dest = dname_dec(option, len, ret);
397 if (dest) { 363 if (dest) {
398 free(ret); 364 free(ret);
399 return dest; 365 return dest;
400 } 366 }
401 } else
402 if (option[-1] == 1) {
403 const char *pfx = "";
404 while (1) {
405 len -= 4;
406 if (len < 0)
407 break;
408 dest += sprint_nip(dest, pfx, option);
409 pfx = " ";
410 option += 4;
411 }
412 } 367 }
413 return ret; 368 return ret;
414#endif 369#endif
@@ -431,59 +386,78 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
431 return ret; 386 return ret;
432} 387}
433 388
434/* put all the parameters into the environment */ 389static void putenvp(llist_t **envp, char *new_opt)
435static char **fill_envp(struct dhcp_packet *packet) 390{
391 putenv(new_opt);
392 log2(" %s", new_opt);
393 llist_add_to(envp, new_opt);
394}
395
396static const char* get_optname(uint8_t code, const struct dhcp_optflag **dh)
436{ 397{
437 int envc; 398 /* Find the option:
438 int i; 399 * dhcp_optflags is sorted so we stop searching when dh->code >= code, which is faster
439 char **envp, **curr; 400 * than iterating over the entire array.
440 const char *opt_name; 401 * Options which don't have a match in dhcp_option_strings[], e.g DHCP_REQUESTED_IP,
441 uint8_t *temp; 402 * are located after the sorted array, so these entries will never be reached
442 uint8_t overload = 0; 403 * and they'll count as unknown options.
443
444#define BITMAP unsigned
445#define BBITS (sizeof(BITMAP) * 8)
446#define BMASK(i) (1 << (i & (sizeof(BITMAP) * 8 - 1)))
447#define FOUND_OPTS(i) (found_opts[(unsigned)i / BBITS])
448 BITMAP found_opts[256 / BBITS];
449
450 memset(found_opts, 0, sizeof(found_opts));
451
452 /* We need 7 elements for:
453 * "interface=IFACE"
454 * "ip=N.N.N.N" from packet->yiaddr
455 * "giaddr=IP" from packet->gateway_nip (unless 0)
456 * "siaddr=IP" from packet->siaddr_nip (unless 0)
457 * "boot_file=FILE" from packet->file (unless overloaded)
458 * "sname=SERVER_HOSTNAME" from packet->sname (unless overloaded)
459 * terminating NULL
460 */ 404 */
461 envc = 7; 405 for (*dh = dhcp_optflags; (*dh)->code && (*dh)->code < code; (*dh)++)
462 /* +1 element for each option, +2 for subnet option: */ 406 continue;
463 if (packet) { 407
464 /* note: do not search for "pad" (0) and "end" (255) options */ 408 if ((*dh)->code == code)
465//TODO: change logic to scan packet _once_ 409 return nth_string(dhcp_option_strings, (*dh - dhcp_optflags));
466 for (i = 1; i < 255; i++) { 410
467 temp = udhcp_get_option(packet, i); 411 return NULL;
468 if (temp) { 412}
469 if (i == DHCP_OPTION_OVERLOAD) 413
470 overload |= *temp; 414/* put all the parameters into the environment */
471 else if (i == DHCP_SUBNET) 415static llist_t *fill_envp(struct dhcp_packet *packet)
472 envc++; /* for $mask */ 416{
473 envc++; 417 uint8_t *optptr;
474 /*if (i != DHCP_MESSAGE_TYPE)*/ 418 struct dhcp_scan_state scan_state;
475 FOUND_OPTS(i) |= BMASK(i); 419 char *new_opt;
476 } 420 llist_t *envp = NULL;
477 }
478 }
479 curr = envp = xzalloc(sizeof(envp[0]) * envc);
480 421
481 *curr = xasprintf("interface=%s", client_data.interface); 422 putenvp(&envp, xasprintf("interface=%s", client_data.interface));
482 putenv(*curr++);
483 423
484 if (!packet) 424 if (!packet)
485 return envp; 425 return envp;
486 426
427 init_scan_state(packet, &scan_state);
428
429 /* Iterate over the packet options.
430 * Handle each option based on whether it's an unknown / known option.
431 * There may be (although unlikely) duplicate options. For now, only the last
432 * appearing option will be stored in the environment, and all duplicates
433 * are freed properly.
434 * Long options may be implemented in the future (see RFC 3396) if needed.
435 */
436 while ((optptr = udhcp_scan_options(packet, &scan_state)) != NULL) {
437 const struct dhcp_optflag *dh;
438 const char *opt_name;
439 uint8_t code = optptr[OPT_CODE];
440 uint8_t len = optptr[OPT_LEN];
441 uint8_t *data = optptr + OPT_DATA;
442
443 opt_name = get_optname(code, &dh);
444 if (opt_name) {
445 new_opt = xmalloc_optname_optval(data, dh, opt_name);
446 if (code == DHCP_SUBNET && len == 4) {
447 uint32_t subnet;
448 putenvp(&envp, new_opt);
449 move_from_unaligned32(subnet, data);
450 new_opt = xasprintf("mask=%u", mton(subnet));
451 }
452 } else {
453 unsigned ofs;
454 new_opt = xmalloc(sizeof("optNNN=") + 1 + len*2);
455 ofs = sprintf(new_opt, "opt%u=", code);
456 bin2hex(new_opt + ofs, (char *)data, len)[0] = '\0';
457 }
458 putenvp(&envp, new_opt);
459 }
460
487 /* Export BOOTP fields. Fields we don't (yet?) export: 461 /* Export BOOTP fields. Fields we don't (yet?) export:
488 * uint8_t op; // always BOOTREPLY 462 * uint8_t op; // always BOOTREPLY
489 * uint8_t htype; // hardware address type. 1 = 10mb ethernet 463 * uint8_t htype; // hardware address type. 1 = 10mb ethernet
@@ -497,77 +471,31 @@ static char **fill_envp(struct dhcp_packet *packet)
497 * uint8_t chaddr[16]; // link-layer client hardware address (MAC) 471 * uint8_t chaddr[16]; // link-layer client hardware address (MAC)
498 */ 472 */
499 /* Most important one: yiaddr as $ip */ 473 /* Most important one: yiaddr as $ip */
500 *curr = xmalloc(sizeof("ip=255.255.255.255")); 474 new_opt = xmalloc(sizeof("ip=255.255.255.255"));
501 sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr); 475 sprint_nip(new_opt, "ip=", (uint8_t *) &packet->yiaddr);
502 putenv(*curr++); 476 putenvp(&envp, new_opt);
477
503 if (packet->siaddr_nip) { 478 if (packet->siaddr_nip) {
504 /* IP address of next server to use in bootstrap */ 479 /* IP address of next server to use in bootstrap */
505 *curr = xmalloc(sizeof("siaddr=255.255.255.255")); 480 new_opt = xmalloc(sizeof("siaddr=255.255.255.255"));
506 sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); 481 sprint_nip(new_opt, "siaddr=", (uint8_t *) &packet->siaddr_nip);
507 putenv(*curr++); 482 putenvp(&envp, new_opt);
508 } 483 }
509 if (packet->gateway_nip) { 484 if (packet->gateway_nip) {
510 /* IP address of DHCP relay agent */ 485 /* IP address of DHCP relay agent */
511 *curr = xmalloc(sizeof("giaddr=255.255.255.255")); 486 new_opt = xmalloc(sizeof("giaddr=255.255.255.255"));
512 sprint_nip(*curr, "giaddr=", (uint8_t *) &packet->gateway_nip); 487 sprint_nip(new_opt, "giaddr=", (uint8_t *) &packet->gateway_nip);
513 putenv(*curr++); 488 putenvp(&envp, new_opt);
514 } 489 }
515 if (!(overload & FILE_FIELD) && packet->file[0]) { 490 if (!(scan_state.overload & FILE_FIELD) && packet->file[0]) {
516 /* watch out for invalid packets */ 491 /* watch out for invalid packets */
517 *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); 492 new_opt = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file);
518 putenv(*curr++); 493 putenvp(&envp, new_opt);
519 } 494 }
520 if (!(overload & SNAME_FIELD) && packet->sname[0]) { 495 if (!(scan_state.overload & SNAME_FIELD) && packet->sname[0]) {
521 /* watch out for invalid packets */ 496 /* watch out for invalid packets */
522 *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); 497 new_opt = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname);
523 putenv(*curr++); 498 putenvp(&envp, new_opt);
524 }
525
526 /* Export known DHCP options */
527 opt_name = dhcp_option_strings;
528 i = 0;
529 while (*opt_name) {
530 uint8_t code = dhcp_optflags[i].code;
531 BITMAP *found_ptr = &FOUND_OPTS(code);
532 BITMAP found_mask = BMASK(code);
533 if (!(*found_ptr & found_mask))
534 goto next;
535 *found_ptr &= ~found_mask; /* leave only unknown options */
536 temp = udhcp_get_option(packet, code);
537 *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name);
538 putenv(*curr++);
539 if (code == DHCP_SUBNET && temp[-OPT_DATA + OPT_LEN] == 4) {
540 /* Subnet option: make things like "$ip/$mask" possible */
541 uint32_t subnet;
542 move_from_unaligned32(subnet, temp);
543 *curr = xasprintf("mask=%u", mton(subnet));
544 putenv(*curr++);
545 }
546 next:
547 opt_name += strlen(opt_name) + 1;
548 i++;
549 }
550 /* Export unknown options */
551 for (i = 0; i < 256;) {
552 BITMAP bitmap = FOUND_OPTS(i);
553 if (!bitmap) {
554 i += BBITS;
555 continue;
556 }
557 if (bitmap & BMASK(i)) {
558 unsigned len, ofs;
559
560 temp = udhcp_get_option(packet, i);
561 /* udhcp_get_option returns ptr to data portion,
562 * need to go back to get len
563 */
564 len = temp[-OPT_DATA + OPT_LEN];
565 *curr = xmalloc(sizeof("optNNN=") + 1 + len*2);
566 ofs = sprintf(*curr, "opt%u=", i);
567 *bin2hex(*curr + ofs, (void*) temp, len) = '\0';
568 putenv(*curr++);
569 }
570 i++;
571 } 499 }
572 500
573 return envp; 501 return envp;
@@ -576,7 +504,7 @@ static char **fill_envp(struct dhcp_packet *packet)
576/* Call a script with a par file and env vars */ 504/* Call a script with a par file and env vars */
577static void udhcp_run_script(struct dhcp_packet *packet, const char *name) 505static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
578{ 506{
579 char **envp, **curr; 507 llist_t *envp;
580 char *argv[3]; 508 char *argv[3];
581 509
582 envp = fill_envp(packet); 510 envp = fill_envp(packet);
@@ -588,11 +516,8 @@ static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
588 argv[2] = NULL; 516 argv[2] = NULL;
589 spawn_and_wait(argv); 517 spawn_and_wait(argv);
590 518
591 for (curr = envp; *curr; curr++) { 519 /* Free all allocated environment variables */
592 log2(" %s", *curr); 520 llist_free(envp, (void (*)(void *))bb_unsetenv_and_free);
593 bb_unsetenv_and_free(*curr);
594 }
595 free(envp);
596} 521}
597 522
598 523
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 9d6604943..acfdaa8c3 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -46,6 +46,12 @@
46#include "dhcpc.h" 46#include "dhcpc.h"
47#include "dhcpd.h" 47#include "dhcpd.h"
48 48
49#if ENABLE_PID_FILE_PATH
50#define PID_FILE_PATH CONFIG_PID_FILE_PATH
51#else
52#define PID_FILE_PATH "/var/run"
53#endif
54
49/* globals */ 55/* globals */
50#define g_leases ((struct dyn_lease*)ptr_to_globals) 56#define g_leases ((struct dyn_lease*)ptr_to_globals)
51/* struct server_data_t server_data is in bb_common_bufsiz1 */ 57/* struct server_data_t server_data is in bb_common_bufsiz1 */
@@ -406,7 +412,7 @@ static const struct config_keyword keywords[] = {
406 {"offer_time" , read_u32 , OFS(offer_time ), "60"}, 412 {"offer_time" , read_u32 , OFS(offer_time ), "60"},
407 {"min_lease" , read_u32 , OFS(min_lease_sec), "60"}, 413 {"min_lease" , read_u32 , OFS(min_lease_sec), "60"},
408 {"lease_file" , read_str , OFS(lease_file ), LEASES_FILE}, 414 {"lease_file" , read_str , OFS(lease_file ), LEASES_FILE},
409 {"pidfile" , read_str , OFS(pidfile ), "/var/run/udhcpd.pid"}, 415 {"pidfile" , read_str , OFS(pidfile ), PID_FILE_PATH "/udhcpd.pid"},
410 {"siaddr" , udhcp_str2nip , OFS(siaddr_nip ), "0.0.0.0"}, 416 {"siaddr" , udhcp_str2nip , OFS(siaddr_nip ), "0.0.0.0"},
411 /* keywords with no defaults must be last! */ 417 /* keywords with no defaults must be last! */
412 {"option" , read_optset , OFS(options ), ""}, 418 {"option" , read_optset , OFS(options ), ""},
diff --git a/networking/udhcp/domain_codec.c b/networking/udhcp/domain_codec.c
index b7a3a5353..752c0a863 100644
--- a/networking/udhcp/domain_codec.c
+++ b/networking/udhcp/domain_codec.c
@@ -109,11 +109,11 @@ char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
109 return ret; 109 return ret;
110} 110}
111 111
112/* Convert a domain name (src) from human-readable "foo.blah.com" format into 112/* Convert a domain name (src) from human-readable "foo.BLAH.com" format into
113 * RFC1035 encoding "\003foo\004blah\003com\000". Return allocated string, or 113 * RFC1035 encoding "\003foo\004blah\003com\000". Return allocated string, or
114 * NULL if an error occurs. 114 * NULL if an error occurs.
115 */ 115 */
116static uint8_t *convert_dname(const char *src) 116static uint8_t *convert_dname(const char *src, int *retlen)
117{ 117{
118 uint8_t c, *res, *lenptr, *dst; 118 uint8_t c, *res, *lenptr, *dst;
119 int len; 119 int len;
@@ -129,6 +129,7 @@ static uint8_t *convert_dname(const char *src)
129 /* label too long, too short, or two '.'s in a row? abort */ 129 /* label too long, too short, or two '.'s in a row? abort */
130 if (len > NS_MAXLABEL || len == 0 || (c == '.' && *src == '.')) { 130 if (len > NS_MAXLABEL || len == 0 || (c == '.' && *src == '.')) {
131 free(res); 131 free(res);
132 *retlen = 0;
132 return NULL; 133 return NULL;
133 } 134 }
134 *lenptr = len; 135 *lenptr = len;
@@ -144,13 +145,16 @@ static uint8_t *convert_dname(const char *src)
144 145
145 if (dst - res >= NS_MAXCDNAME) { /* dname too long? abort */ 146 if (dst - res >= NS_MAXCDNAME) { /* dname too long? abort */
146 free(res); 147 free(res);
148 *retlen = 0;
147 return NULL; 149 return NULL;
148 } 150 }
149 151
150 *dst = 0; 152 *dst++ = 0;
153 *retlen = dst - res;
151 return res; 154 return res;
152} 155}
153 156
157#if 0 //UNUSED
154/* Returns the offset within cstr at which dname can be found, or -1 */ 158/* Returns the offset within cstr at which dname can be found, or -1 */
155static int find_offset(const uint8_t *cstr, int clen, const uint8_t *dname) 159static int find_offset(const uint8_t *cstr, int clen, const uint8_t *dname)
156{ 160{
@@ -188,28 +192,27 @@ static int find_offset(const uint8_t *cstr, int clen, const uint8_t *dname)
188 192
189 return -1; 193 return -1;
190} 194}
195#endif
191 196
197uint8_t* FAST_FUNC dname_enc(/*const uint8_t *cstr, int clen,*/ const char *src, int *retlen)
198{
199#if 0 //UNUSED, was intended for long, repetitive DHCP_DOMAIN_SEARCH options?
200 uint8_t *d, *dname;
192/* Computes string to be appended to cstr so that src would be added to 201/* Computes string to be appended to cstr so that src would be added to
193 * the compression (best case, it's a 2-byte pointer to some offset within 202 * the compression (best case, it's a 2-byte pointer to some offset within
194 * cstr; worst case, it's all of src, converted to <4>host<3>com<0> format). 203 * cstr; worst case, it's all of src, converted to <4>host<3>com<0> format).
195 * The computed string is returned directly; its length is returned via retlen; 204 * The computed string is returned directly; its length is returned via retlen;
196 * NULL and 0, respectively, are returned if an error occurs. 205 * NULL and 0, respectively, are returned if an error occurs.
197 */ 206 */
198uint8_t* FAST_FUNC dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) 207 dname = convert_dname(src, retlen);
199{
200 uint8_t *d, *dname;
201 int off;
202
203 dname = convert_dname(src);
204 if (dname == NULL) { 208 if (dname == NULL) {
205 *retlen = 0;
206 return NULL; 209 return NULL;
207 } 210 }
208 211
209 d = dname; 212 d = dname;
210 while (*d) { 213 while (*d) {
211 if (cstr) { 214 if (cstr) {
212 off = find_offset(cstr, clen, d); 215 int off = find_offset(cstr, clen, d);
213 if (off >= 0) { /* found a match, add pointer and return */ 216 if (off >= 0) { /* found a match, add pointer and return */
214 *d++ = NS_CMPRSFLGS | (off >> 8); 217 *d++ = NS_CMPRSFLGS | (off >> 8);
215 *d = off; 218 *d = off;
@@ -221,6 +224,8 @@ uint8_t* FAST_FUNC dname_enc(const uint8_t *cstr, int clen, const char *src, int
221 224
222 *retlen = d - dname + 1; 225 *retlen = d - dname + 1;
223 return dname; 226 return dname;
227#endif
228 return convert_dname(src, retlen);
224} 229}
225 230
226#ifdef DNS_COMPR_TESTING 231#ifdef DNS_COMPR_TESTING
diff --git a/networking/wget.c b/networking/wget.c
index bc237c4a8..8a967fe20 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -679,7 +679,8 @@ static int spawn_https_helper_openssl(const char *host, unsigned port)
679 pid = xvfork(); 679 pid = xvfork();
680 if (pid == 0) { 680 if (pid == 0) {
681 /* Child */ 681 /* Child */
682 char *argv[9]; 682 char *argv[13];
683 char **argp;
683 684
684 close(sp[0]); 685 close(sp[0]);
685 xmove_fd(sp[1], 0); 686 xmove_fd(sp[1], 0);
@@ -702,13 +703,25 @@ static int spawn_https_helper_openssl(const char *host, unsigned port)
702 * TLS server_name (SNI) field are FQDNs (DNS hostnames). 703 * TLS server_name (SNI) field are FQDNs (DNS hostnames).
703 * IPv4 and IPv6 addresses, port numbers are not allowed. 704 * IPv4 and IPv6 addresses, port numbers are not allowed.
704 */ 705 */
706 argp = &argv[5];
705 if (!is_ip_address(servername)) { 707 if (!is_ip_address(servername)) {
706 argv[5] = (char*)"-servername"; 708 *argp++ = (char*)"-servername"; //[5]
707 argv[6] = (char*)servername; 709 *argp++ = (char*)servername; //[6]
708 } 710 }
709 if (!(option_mask32 & WGET_OPT_NO_CHECK_CERT)) { 711 if (!(option_mask32 & WGET_OPT_NO_CHECK_CERT)) {
710 argv[7] = (char*)"-verify_return_error"; 712 /* Abort on bad server certificate */
713 *argp++ = (char*)"-verify"; //[7]
714 *argp++ = (char*)"100"; //[8]
715 *argp++ = (char*)"-verify_return_error"; //[9]
716 if (!is_ip_address(servername)) {
717 *argp++ = (char*)"-verify_hostname"; //[10]
718 *argp++ = (char*)servername; //[11]
719 } else {
720 *argp++ = (char*)"-verify_ip"; //[10]
721 *argp++ = (char*)host; //[11]
722 }
711 } 723 }
724 //[12] (or earlier) is NULL terminator
712 725
713 BB_EXECVP(argv[0], argv); 726 BB_EXECVP(argv[0], argv);
714 xmove_fd(3, 2); 727 xmove_fd(3, 2);
diff --git a/procps/nmeter.c b/procps/nmeter.c
index ae16d8548..856ce0202 100644
--- a/procps/nmeter.c
+++ b/procps/nmeter.c
@@ -37,6 +37,7 @@
37//usage: "\n %[pn] # of processes" 37//usage: "\n %[pn] # of processes"
38//usage: "\n %b Block io" 38//usage: "\n %b Block io"
39//usage: "\n %Nt Time (with N decimal points)" 39//usage: "\n %Nt Time (with N decimal points)"
40//usage: "\n %NT Zero-based timestamp (with N decimal points)"
40//usage: "\n %r Print <cr> instead of <lf> at EOL" 41//usage: "\n %r Print <cr> instead of <lf> at EOL"
41 42
42//TODO: 43//TODO:
@@ -88,6 +89,7 @@ struct globals {
88 int delta; 89 int delta;
89 unsigned deltanz; 90 unsigned deltanz;
90 struct timeval tv; 91 struct timeval tv;
92 struct timeval start;
91#define first_proc_file proc_stat 93#define first_proc_file proc_stat
92 proc_file proc_stat; // Must match the order of proc_name's! 94 proc_file proc_stat; // Must match the order of proc_name's!
93 proc_file proc_loadavg; 95 proc_file proc_loadavg;
@@ -101,7 +103,6 @@ struct globals {
101#define is26 (G.is26 ) 103#define is26 (G.is26 )
102#define need_seconds (G.need_seconds ) 104#define need_seconds (G.need_seconds )
103#define cur_outbuf (G.cur_outbuf ) 105#define cur_outbuf (G.cur_outbuf )
104#define tv (G.tv )
105#define proc_stat (G.proc_stat ) 106#define proc_stat (G.proc_stat )
106#define proc_loadavg (G.proc_loadavg ) 107#define proc_loadavg (G.proc_loadavg )
107#define proc_net_dev (G.proc_net_dev ) 108#define proc_net_dev (G.proc_net_dev )
@@ -754,25 +755,53 @@ S_STAT(time_stat)
754 unsigned scale; 755 unsigned scale;
755S_STAT_END(time_stat) 756S_STAT_END(time_stat)
756 757
757static void FAST_FUNC collect_time(time_stat *s) 758static void FAST_FUNC collect_tv(time_stat *s, struct timeval *tv, int local)
758{ 759{
759 char buf[sizeof("12:34:56.123456")]; 760 char buf[sizeof("12:34:56.123456")];
760 struct tm* tm; 761 struct tm* tm;
761 unsigned us = tv.tv_usec + s->scale/2; 762 unsigned us = tv->tv_usec + s->scale/2;
762 time_t t = tv.tv_sec; 763 time_t t = tv->tv_sec;
763 764
764 if (us >= 1000000) { 765 if (us >= 1000000) {
765 t++; 766 t++;
766 us -= 1000000; 767 us -= 1000000;
767 } 768 }
768 tm = localtime(&t); 769 if (local)
770 tm = localtime(&t);
771 else
772 tm = gmtime(&t);
769 773
770 sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); 774 sprintf(buf, "%02u:%02u:%02u", tm->tm_hour, tm->tm_min, tm->tm_sec);
771 if (s->prec) 775 if (s->prec)
772 sprintf(buf+8, ".%0*d", s->prec, us / s->scale); 776 sprintf(buf+8, ".%0*u", s->prec, us / s->scale);
773 put(buf); 777 put(buf);
774} 778}
775 779
780static void FAST_FUNC collect_time(time_stat *s)
781{
782 collect_tv(s, &G.tv, /*local:*/ 1);
783}
784
785static void FAST_FUNC collect_monotonic(time_stat *s)
786{
787 struct timeval tv_mono;
788
789 tv_mono.tv_sec = G.tv.tv_sec - G.start.tv_sec;
790#if 0 /* Do we want this? */
791 if (tv_mono.tv_sec < 0) {
792 /* Time went backwards, reset start time to "now" */
793 tv_mono.tv_sec = 0;
794 G.start = G.tv;
795 }
796#endif
797 tv_mono.tv_usec = G.tv.tv_usec - G.start.tv_usec;
798 if ((int32_t)tv_mono.tv_usec < 0) {
799 tv_mono.tv_usec += 1000000;
800 tv_mono.tv_sec--;
801 }
802 collect_tv(s, &tv_mono, /*local:*/ 0);
803}
804
776static s_stat* init_time(const char *param) 805static s_stat* init_time(const char *param)
777{ 806{
778 int prec; 807 int prec;
@@ -789,6 +818,13 @@ static s_stat* init_time(const char *param)
789 return (s_stat*)s; 818 return (s_stat*)s;
790} 819}
791 820
821static s_stat* init_monotonic(const char *param)
822{
823 time_stat *s = (void*)init_time(param);
824 s->collect = collect_monotonic;
825 return (s_stat*)s;
826}
827
792static void FAST_FUNC collect_info(s_stat *s) 828static void FAST_FUNC collect_info(s_stat *s)
793{ 829{
794 gen ^= 1; 830 gen ^= 1;
@@ -801,7 +837,7 @@ static void FAST_FUNC collect_info(s_stat *s)
801 837
802typedef s_stat* init_func(const char *param); 838typedef s_stat* init_func(const char *param);
803 839
804static const char options[] ALIGN1 = "ncmsfixptbr"; 840static const char options[] ALIGN1 = "ncmsfixptTbr";
805static init_func *const init_functions[] = { 841static init_func *const init_functions[] = {
806 init_if, 842 init_if,
807 init_cpu, 843 init_cpu,
@@ -812,6 +848,7 @@ static init_func *const init_functions[] = {
812 init_ctx, 848 init_ctx,
813 init_fork, 849 init_fork,
814 init_time, 850 init_time,
851 init_monotonic,
815 init_blk, 852 init_blk,
816 init_cr 853 init_cr
817}; 854};
@@ -913,13 +950,15 @@ int nmeter_main(int argc UNUSED_PARAM, char **argv)
913 // Generate first samples but do not print them, they're bogus 950 // Generate first samples but do not print them, they're bogus
914 collect_info(first); 951 collect_info(first);
915 reset_outbuf(); 952 reset_outbuf();
953
916 if (G.delta >= 0) { 954 if (G.delta >= 0) {
917 gettimeofday(&tv, NULL); 955 gettimeofday(&G.tv, NULL);
918 usleep(G.delta > 1000000 ? 1000000 : G.delta - tv.tv_usec % G.deltanz); 956 usleep(G.delta > 1000000 ? 1000000 : G.delta - G.tv.tv_usec % G.deltanz);
919 } 957 }
920 958
959 gettimeofday(&G.start, NULL);
960 G.tv = G.start;
921 while (1) { 961 while (1) {
922 gettimeofday(&tv, NULL);
923 collect_info(first); 962 collect_info(first);
924 put_c(G.final_char); 963 put_c(G.final_char);
925 print_outbuf(); 964 print_outbuf();
@@ -932,11 +971,11 @@ int nmeter_main(int argc UNUSED_PARAM, char **argv)
932 if (G.delta >= 0) { 971 if (G.delta >= 0) {
933 int rem; 972 int rem;
934 // can be commented out, will sacrifice sleep time precision a bit 973 // can be commented out, will sacrifice sleep time precision a bit
935 gettimeofday(&tv, NULL); 974 gettimeofday(&G.tv, NULL);
936 if (need_seconds) 975 if (need_seconds)
937 rem = G.delta - ((ullong)tv.tv_sec*1000000 + tv.tv_usec) % G.deltanz; 976 rem = G.delta - ((ullong)G.tv.tv_sec*1000000 + G.tv.tv_usec) % G.deltanz;
938 else 977 else
939 rem = G.delta - (unsigned)tv.tv_usec % G.deltanz; 978 rem = G.delta - (unsigned)G.tv.tv_usec % G.deltanz;
940 // Sometimes kernel wakes us up just a tiny bit earlier than asked 979 // Sometimes kernel wakes us up just a tiny bit earlier than asked
941 // Do not go to very short sleep in this case 980 // Do not go to very short sleep in this case
942 if (rem < (unsigned)G.delta / 128) { 981 if (rem < (unsigned)G.delta / 128) {
@@ -944,6 +983,7 @@ int nmeter_main(int argc UNUSED_PARAM, char **argv)
944 } 983 }
945 usleep(rem); 984 usleep(rem);
946 } 985 }
986 gettimeofday(&G.tv, NULL);
947 } 987 }
948 988
949 /*return 0;*/ 989 /*return 0;*/
diff --git a/procps/sysctl.c b/procps/sysctl.c
index 6d77185ca..e16b119e9 100644
--- a/procps/sysctl.c
+++ b/procps/sysctl.c
@@ -169,13 +169,15 @@ static int sysctl_act_on_setting(char *setting)
169 169
170 if (fd < 0) { 170 if (fd < 0) {
171 switch (errno) { 171 switch (errno) {
172 case EACCES:
173 /* Happens for write-only settings, e.g. net.ipv6.route.flush */
174 goto end;
175 case ENOENT: 172 case ENOENT:
176 if (option_mask32 & FLAG_SHOW_KEY_ERRORS) 173 if (option_mask32 & FLAG_SHOW_KEY_ERRORS)
177 bb_error_msg("error: '%s' is an unknown key", outname); 174 bb_error_msg("error: '%s' is an unknown key", outname);
178 break; 175 break;
176 case EACCES:
177 /* Happens for write-only settings, e.g. net.ipv6.route.flush */
178 if (!writing)
179 goto end;
180 /* fall through */
179 default: 181 default:
180 bb_perror_msg("error %sing key '%s'", 182 bb_perror_msg("error %sing key '%s'",
181 writing ? 183 writing ?
@@ -236,6 +238,7 @@ static int sysctl_act_recursive(const char *path)
236 int retval = 0; 238 int retval = 0;
237 239
238 if (!(option_mask32 & FLAG_WRITE) 240 if (!(option_mask32 & FLAG_WRITE)
241 && !strchr(path, '=') /* do not try to resurse on "var=val" */
239 && stat(path, &buf) == 0 242 && stat(path, &buf) == 0
240 && S_ISDIR(buf.st_mode) 243 && S_ISDIR(buf.st_mode)
241 ) { 244 ) {
diff --git a/procps/top.c b/procps/top.c
index 5c41e8e10..8d39526ff 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -979,9 +979,11 @@ static unsigned handle_input(unsigned scan_mask, duration_t interval)
979 IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK) 979 IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK)
980 ) { 980 ) {
981 scan_mask ^= PSSCAN_TASKS; 981 scan_mask ^= PSSCAN_TASKS;
982# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
982 free(prev_hist); 983 free(prev_hist);
983 prev_hist = NULL; 984 prev_hist = NULL;
984 prev_hist_count = 0; 985 prev_hist_count = 0;
986# endif
985 continue; 987 continue;
986 } 988 }
987# endif 989# endif
diff --git a/scripts/randomtest b/scripts/randomtest
index 94709a99f..76550d267 100755
--- a/scripts/randomtest
+++ b/scripts/randomtest
@@ -113,6 +113,31 @@ if test x"$LIBC" = x"uclibc"; then
113 echo 'CONFIG_ASH_INTERNAL_GLOB=y' >>.config 113 echo 'CONFIG_ASH_INTERNAL_GLOB=y' >>.config
114fi 114fi
115 115
116# If musl
117if test x"$LIBC" = x"musl"; then
118 cat .config \
119 | grep -v CONFIG_STATIC \
120 | grep -v CONFIG_DEBUG_SANITIZE \
121 | grep -v CONFIG_LFS \
122 | grep -v CONFIG_EXTRA_COMPAT \
123 | grep -v CONFIG_FEATURE_2_4_MODULES \
124 | grep -v CONFIG_FEATURE_VI_REGEX_SEARCH \
125 | grep -v CONFIG_FEATURE_MOUNT_NFS \
126 | grep -v CONFIG_FEATURE_INETD_RPC \
127 >.config.new
128 mv .config.new .config
129 echo 'CONFIG_STATIC=y' >>.config
130 # "error: cannot specify -static with -fsanitize=address":
131 echo '# CONFIG_DEBUG_SANITIZE is not set' >>.config
132 # with LFS off, uoff_t will have wrong width:
133 echo 'CONFIG_LFS=y' >>.config
134 echo '# CONFIG_EXTRA_COMPAT is not set' >>.config
135 echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config
136 echo '# CONFIG_FEATURE_VI_REGEX_SEARCH is not set' >>.config
137 echo '# CONFIG_FEATURE_MOUNT_NFS is not set' >>.config
138 echo '# CONFIG_FEATURE_INETD_RPC is not set' >>.config
139fi
140
116# If STATIC, remove some things. 141# If STATIC, remove some things.
117# PAM with static linking is probably pointless 142# PAM with static linking is probably pointless
118# (but I need to try - now I don't have libpam.a on my system, only libpam.so) 143# (but I need to try - now I don't have libpam.a on my system, only libpam.so)
diff --git a/shell/Config.src b/shell/Config.src
index d7623f774..5efbf9995 100644
--- a/shell/Config.src
+++ b/shell/Config.src
@@ -17,6 +17,7 @@ choice
17config SH_IS_ASH 17config SH_IS_ASH
18 depends on !NOMMU 18 depends on !NOMMU
19 bool "ash" 19 bool "ash"
20 select SHELL_ASH
20 help 21 help
21 Choose ash to be the shell executed by 'sh' name. 22 Choose ash to be the shell executed by 'sh' name.
22 The ash code will be built into busybox. If you don't select 23 The ash code will be built into busybox. If you don't select
@@ -25,6 +26,7 @@ config SH_IS_ASH
25 26
26config SH_IS_HUSH 27config SH_IS_HUSH
27 bool "hush" 28 bool "hush"
29 select SHELL_HUSH
28 help 30 help
29 Choose hush to be the shell executed by 'sh' name. 31 Choose hush to be the shell executed by 'sh' name.
30 The hush code will be built into busybox. If you don't select 32 The hush code will be built into busybox. If you don't select
@@ -57,6 +59,7 @@ choice
57config BASH_IS_ASH 59config BASH_IS_ASH
58 depends on !NOMMU 60 depends on !NOMMU
59 bool "ash" 61 bool "ash"
62 select SHELL_ASH
60 help 63 help
61 Choose ash to be the shell executed by 'bash' name. 64 Choose ash to be the shell executed by 'bash' name.
62 The ash code will be built into busybox. If you don't select 65 The ash code will be built into busybox. If you don't select
@@ -65,6 +68,7 @@ config BASH_IS_ASH
65 68
66config BASH_IS_HUSH 69config BASH_IS_HUSH
67 bool "hush" 70 bool "hush"
71 select SHELL_HUSH
68 help 72 help
69 Choose hush to be the shell executed by 'bash' name. 73 Choose hush to be the shell executed by 'bash' name.
70 The hush code will be built into busybox. If you don't select 74 The hush code will be built into busybox. If you don't select
@@ -81,12 +85,12 @@ INSERT
81 85
82 86
83comment "Options common to all shells" 87comment "Options common to all shells"
84if ASH || HUSH || SH_IS_ASH || BASH_IS_ASH || SH_IS_HUSH || BASH_IS_HUSH 88if SHELL_ASH || SHELL_HUSH
85 89
86config FEATURE_SH_MATH 90config FEATURE_SH_MATH
87 bool "POSIX math support" 91 bool "POSIX math support"
88 default y 92 default y
89 depends on ASH || HUSH || SH_IS_ASH || BASH_IS_ASH || SH_IS_HUSH || BASH_IS_HUSH 93 depends on SHELL_ASH || SHELL_HUSH
90 help 94 help
91 Enable math support in the shell via $((...)) syntax. 95 Enable math support in the shell via $((...)) syntax.
92 96
@@ -107,14 +111,14 @@ config FEATURE_SH_MATH_BASE
107config FEATURE_SH_EXTRA_QUIET 111config FEATURE_SH_EXTRA_QUIET
108 bool "Hide message on interactive shell startup" 112 bool "Hide message on interactive shell startup"
109 default y 113 default y
110 depends on ASH || HUSH || SH_IS_ASH || BASH_IS_ASH || SH_IS_HUSH || BASH_IS_HUSH 114 depends on SHELL_ASH || SHELL_HUSH
111 help 115 help
112 Remove the busybox introduction when starting a shell. 116 Remove the busybox introduction when starting a shell.
113 117
114config FEATURE_SH_STANDALONE 118config FEATURE_SH_STANDALONE
115 bool "Standalone shell" 119 bool "Standalone shell"
116 default n 120 default n
117 depends on ASH || HUSH || SH_IS_ASH || BASH_IS_ASH || SH_IS_HUSH || BASH_IS_HUSH 121 depends on SHELL_ASH || SHELL_HUSH
118 help 122 help
119 This option causes busybox shells to use busybox applets 123 This option causes busybox shells to use busybox applets
120 in preference to executables in the PATH whenever possible. For 124 in preference to executables in the PATH whenever possible. For
@@ -135,7 +139,7 @@ config FEATURE_SH_STANDALONE
135config FEATURE_SH_NOFORK 139config FEATURE_SH_NOFORK
136 bool "Run 'nofork' applets directly" 140 bool "Run 'nofork' applets directly"
137 default n 141 default n
138 depends on ASH || HUSH || SH_IS_ASH || BASH_IS_ASH || SH_IS_HUSH || BASH_IS_HUSH 142 depends on SHELL_ASH || SHELL_HUSH
139 help 143 help
140 This option causes busybox shells to not execute typical 144 This option causes busybox shells to not execute typical
141 fork/exec/wait sequence, but call <applet>_main directly, 145 fork/exec/wait sequence, but call <applet>_main directly,
@@ -153,14 +157,14 @@ config FEATURE_SH_NOFORK
153config FEATURE_SH_READ_FRAC 157config FEATURE_SH_READ_FRAC
154 bool "read -t N.NNN support (+110 bytes)" 158 bool "read -t N.NNN support (+110 bytes)"
155 default y 159 default y
156 depends on ASH || HUSH || SH_IS_ASH || BASH_IS_ASH || SH_IS_HUSH || BASH_IS_HUSH 160 depends on SHELL_ASH || SHELL_HUSH
157 help 161 help
158 Enable support for fractional second timeout in read builtin. 162 Enable support for fractional second timeout in read builtin.
159 163
160config FEATURE_SH_HISTFILESIZE 164config FEATURE_SH_HISTFILESIZE
161 bool "Use $HISTFILESIZE" 165 bool "Use $HISTFILESIZE"
162 default y 166 default y
163 depends on ASH || HUSH || SH_IS_ASH || BASH_IS_ASH || SH_IS_HUSH || BASH_IS_HUSH 167 depends on SHELL_ASH || SHELL_HUSH
164 help 168 help
165 This option makes busybox shells to use $HISTFILESIZE variable 169 This option makes busybox shells to use $HISTFILESIZE variable
166 to set shell history size. Note that its max value is capped 170 to set shell history size. Note that its max value is capped
@@ -169,7 +173,7 @@ config FEATURE_SH_HISTFILESIZE
169config FEATURE_SH_EMBEDDED_SCRIPTS 173config FEATURE_SH_EMBEDDED_SCRIPTS
170 bool "Embed scripts in the binary" 174 bool "Embed scripts in the binary"
171 default y 175 default y
172 depends on ASH || HUSH || SH_IS_ASH || BASH_IS_ASH || SH_IS_HUSH || BASH_IS_HUSH 176 depends on SHELL_ASH || SHELL_HUSH
173 help 177 help
174 Allow scripts to be compressed and embedded in the busybox 178 Allow scripts to be compressed and embedded in the busybox
175 binary. The scripts should be placed in the 'embed' directory 179 binary. The scripts should be placed in the 'embed' directory
diff --git a/shell/ash.c b/shell/ash.c
index 9c5fbf5ff..d35ae027f 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -29,10 +29,15 @@
29 * - fake $PPID 29 * - fake $PPID
30 */ 30 */
31 31
32//config:config SHELL_ASH
33//config: bool #hidden option
34//config: depends on !NOMMU
35//config:
32//config:config ASH 36//config:config ASH
33//config: bool "ash (78 kb)" 37//config: bool "ash (78 kb)"
34//config: default y 38//config: default y
35//config: depends on !NOMMU 39//config: depends on !NOMMU
40//config: select SHELL_ASH
36//config: help 41//config: help
37//config: The most complete and most pedantically correct shell included with 42//config: The most complete and most pedantically correct shell included with
38//config: busybox. This shell is actually a derivative of the Debian 'dash' 43//config: busybox. This shell is actually a derivative of the Debian 'dash'
@@ -42,17 +47,17 @@
42//config:# ash options 47//config:# ash options
43//config:# note: Don't remove !NOMMU part in the next line; it would break 48//config:# note: Don't remove !NOMMU part in the next line; it would break
44//config:# menuconfig's indenting. 49//config:# menuconfig's indenting.
45//config:if !NOMMU && (ASH || SH_IS_ASH || BASH_IS_ASH) 50//config:if !NOMMU && (SHELL_ASH || ASH || SH_IS_ASH || BASH_IS_ASH)
46//config: 51//config:
47//config:config ASH_OPTIMIZE_FOR_SIZE 52//config:config ASH_OPTIMIZE_FOR_SIZE
48//config: bool "Optimize for size instead of speed" 53//config: bool "Optimize for size instead of speed"
49//config: default y 54//config: default y
50//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 55//config: depends on SHELL_ASH
51//config: 56//config:
52//config:config ASH_INTERNAL_GLOB 57//config:config ASH_INTERNAL_GLOB
53//config: bool "Use internal glob() implementation" 58//config: bool "Use internal glob() implementation"
54//config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now 59//config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now
55//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 60//config: depends on SHELL_ASH
56//config: help 61//config: help
57//config: Do not use glob() function from libc, use internal implementation. 62//config: Do not use glob() function from libc, use internal implementation.
58//config: Use this if you are getting "glob.h: No such file or directory" 63//config: Use this if you are getting "glob.h: No such file or directory"
@@ -63,7 +68,7 @@
63//config:config ASH_BASH_COMPAT 68//config:config ASH_BASH_COMPAT
64//config: bool "bash-compatible extensions" 69//config: bool "bash-compatible extensions"
65//config: default y 70//config: default y
66//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 71//config: depends on SHELL_ASH
67//config: 72//config:
68//config:config ASH_BASH_SOURCE_CURDIR 73//config:config ASH_BASH_SOURCE_CURDIR
69//config: bool "'source' and '.' builtins search current directory after $PATH" 74//config: bool "'source' and '.' builtins search current directory after $PATH"
@@ -84,17 +89,17 @@
84//config:config ASH_JOB_CONTROL 89//config:config ASH_JOB_CONTROL
85//config: bool "Job control" 90//config: bool "Job control"
86//config: default y 91//config: default y
87//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 92//config: depends on SHELL_ASH
88//config: 93//config:
89//config:config ASH_ALIAS 94//config:config ASH_ALIAS
90//config: bool "Alias support" 95//config: bool "Alias support"
91//config: default y 96//config: default y
92//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 97//config: depends on SHELL_ASH
93//config: 98//config:
94//config:config ASH_RANDOM_SUPPORT 99//config:config ASH_RANDOM_SUPPORT
95//config: bool "Pseudorandom generator and $RANDOM variable" 100//config: bool "Pseudorandom generator and $RANDOM variable"
96//config: default y 101//config: default y
97//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 102//config: depends on SHELL_ASH
98//config: help 103//config: help
99//config: Enable pseudorandom generator and dynamic variable "$RANDOM". 104//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
100//config: Each read of "$RANDOM" will generate a new pseudorandom value. 105//config: Each read of "$RANDOM" will generate a new pseudorandom value.
@@ -105,7 +110,7 @@
105//config:config ASH_EXPAND_PRMT 110//config:config ASH_EXPAND_PRMT
106//config: bool "Expand prompt string" 111//config: bool "Expand prompt string"
107//config: default y 112//config: default y
108//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 113//config: depends on SHELL_ASH
109//config: help 114//config: help
110//config: $PS# may contain volatile content, such as backquote commands. 115//config: $PS# may contain volatile content, such as backquote commands.
111//config: This option recreates the prompt string from the environment 116//config: This option recreates the prompt string from the environment
@@ -114,14 +119,14 @@
114//config:config ASH_IDLE_TIMEOUT 119//config:config ASH_IDLE_TIMEOUT
115//config: bool "Idle timeout variable $TMOUT" 120//config: bool "Idle timeout variable $TMOUT"
116//config: default y 121//config: default y
117//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 122//config: depends on SHELL_ASH
118//config: help 123//config: help
119//config: Enable bash-like auto-logout after $TMOUT seconds of idle time. 124//config: Enable bash-like auto-logout after $TMOUT seconds of idle time.
120//config: 125//config:
121//config:config ASH_MAIL 126//config:config ASH_MAIL
122//config: bool "Check for new mail in interactive shell" 127//config: bool "Check for new mail in interactive shell"
123//config: default y 128//config: default y
124//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 129//config: depends on SHELL_ASH
125//config: help 130//config: help
126//config: Enable "check for new mail" function: 131//config: Enable "check for new mail" function:
127//config: if set, $MAIL file and $MAILPATH list of files 132//config: if set, $MAIL file and $MAILPATH list of files
@@ -131,32 +136,32 @@
131//config:config ASH_ECHO 136//config:config ASH_ECHO
132//config: bool "echo builtin" 137//config: bool "echo builtin"
133//config: default y 138//config: default y
134//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 139//config: depends on SHELL_ASH
135//config: 140//config:
136//config:config ASH_PRINTF 141//config:config ASH_PRINTF
137//config: bool "printf builtin" 142//config: bool "printf builtin"
138//config: default y 143//config: default y
139//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 144//config: depends on SHELL_ASH
140//config: 145//config:
141//config:config ASH_TEST 146//config:config ASH_TEST
142//config: bool "test builtin" 147//config: bool "test builtin"
143//config: default y 148//config: default y
144//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 149//config: depends on SHELL_ASH
145//config: 150//config:
146//config:config ASH_HELP 151//config:config ASH_HELP
147//config: bool "help builtin" 152//config: bool "help builtin"
148//config: default y 153//config: default y
149//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 154//config: depends on SHELL_ASH
150//config: 155//config:
151//config:config ASH_GETOPTS 156//config:config ASH_GETOPTS
152//config: bool "getopts builtin" 157//config: bool "getopts builtin"
153//config: default y 158//config: default y
154//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 159//config: depends on SHELL_ASH
155//config: 160//config:
156//config:config ASH_CMDCMD 161//config:config ASH_CMDCMD
157//config: bool "command builtin" 162//config: bool "command builtin"
158//config: default y 163//config: default y
159//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH 164//config: depends on SHELL_ASH
160//config: help 165//config: help
161//config: Enable support for the 'command' builtin, which allows 166//config: Enable support for the 'command' builtin, which allows
162//config: you to run the specified command or builtin, 167//config: you to run the specified command or builtin,
@@ -188,9 +193,7 @@
188//applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) 193//applet:IF_SH_IS_ASH( APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
189//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash)) 194//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
190 195
191//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 196//kbuild:lib-$(CONFIG_SHELL_ASH) += ash.o ash_ptr_hack.o shell_common.o
192//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
193//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
194//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 197//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
195 198
196/* 199/*
diff --git a/shell/hush.c b/shell/hush.c
index cab7ea5b0..e9cec1cc9 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -95,6 +95,7 @@
95//config:config HUSH 95//config:config HUSH
96//config: bool "hush (68 kb)" 96//config: bool "hush (68 kb)"
97//config: default y 97//config: default y
98//config: select SHELL_HUSH
98//config: help 99//config: help
99//config: hush is a small shell. It handles the normal flow control 100//config: hush is a small shell. It handles the normal flow control
100//config: constructs such as if/then/elif/else/fi, for/in/do/done, while loops, 101//config: constructs such as if/then/elif/else/fi, for/in/do/done, while loops,
@@ -106,10 +107,20 @@
106//config: It does not handle select, aliases, tilde expansion, 107//config: It does not handle select, aliases, tilde expansion,
107//config: &>file and >&file redirection of stdout+stderr. 108//config: &>file and >&file redirection of stdout+stderr.
108//config: 109//config:
110// This option is visible (has a description) to make it possible to select
111// a "scripted" applet (such as NOLOGIN) but avoid selecting any shells:
112//config:config SHELL_HUSH
113//config: bool "Internal shell for embedded script support"
114//config: default n
115//config:
116//config:# hush options
117//config:# It's only needed to get "nice" menuconfig indenting.
118//config:if SHELL_HUSH || HUSH || SH_IS_HUSH || BASH_IS_HUSH
119//config:
109//config:config HUSH_BASH_COMPAT 120//config:config HUSH_BASH_COMPAT
110//config: bool "bash-compatible extensions" 121//config: bool "bash-compatible extensions"
111//config: default y 122//config: default y
112//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 123//config: depends on SHELL_HUSH
113//config: 124//config:
114//config:config HUSH_BRACE_EXPANSION 125//config:config HUSH_BRACE_EXPANSION
115//config: bool "Brace expansion" 126//config: bool "Brace expansion"
@@ -133,7 +144,7 @@
133//config:config HUSH_INTERACTIVE 144//config:config HUSH_INTERACTIVE
134//config: bool "Interactive mode" 145//config: bool "Interactive mode"
135//config: default y 146//config: default y
136//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 147//config: depends on SHELL_HUSH
137//config: help 148//config: help
138//config: Enable interactive mode (prompt and command editing). 149//config: Enable interactive mode (prompt and command editing).
139//config: Without this, hush simply reads and executes commands 150//config: Without this, hush simply reads and executes commands
@@ -159,31 +170,31 @@
159//config:config HUSH_TICK 170//config:config HUSH_TICK
160//config: bool "Support command substitution" 171//config: bool "Support command substitution"
161//config: default y 172//config: default y
162//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 173//config: depends on SHELL_HUSH
163//config: help 174//config: help
164//config: Enable `command` and $(command). 175//config: Enable `command` and $(command).
165//config: 176//config:
166//config:config HUSH_IF 177//config:config HUSH_IF
167//config: bool "Support if/then/elif/else/fi" 178//config: bool "Support if/then/elif/else/fi"
168//config: default y 179//config: default y
169//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 180//config: depends on SHELL_HUSH
170//config: 181//config:
171//config:config HUSH_LOOPS 182//config:config HUSH_LOOPS
172//config: bool "Support for, while and until loops" 183//config: bool "Support for, while and until loops"
173//config: default y 184//config: default y
174//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 185//config: depends on SHELL_HUSH
175//config: 186//config:
176//config:config HUSH_CASE 187//config:config HUSH_CASE
177//config: bool "Support case ... esac statement" 188//config: bool "Support case ... esac statement"
178//config: default y 189//config: default y
179//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 190//config: depends on SHELL_HUSH
180//config: help 191//config: help
181//config: Enable case ... esac statement. +400 bytes. 192//config: Enable case ... esac statement. +400 bytes.
182//config: 193//config:
183//config:config HUSH_FUNCTIONS 194//config:config HUSH_FUNCTIONS
184//config: bool "Support funcname() { commands; } syntax" 195//config: bool "Support funcname() { commands; } syntax"
185//config: default y 196//config: default y
186//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 197//config: depends on SHELL_HUSH
187//config: help 198//config: help
188//config: Enable support for shell functions. +800 bytes. 199//config: Enable support for shell functions. +800 bytes.
189//config: 200//config:
@@ -197,7 +208,7 @@
197//config:config HUSH_RANDOM_SUPPORT 208//config:config HUSH_RANDOM_SUPPORT
198//config: bool "Pseudorandom generator and $RANDOM variable" 209//config: bool "Pseudorandom generator and $RANDOM variable"
199//config: default y 210//config: default y
200//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 211//config: depends on SHELL_HUSH
201//config: help 212//config: help
202//config: Enable pseudorandom generator and dynamic variable "$RANDOM". 213//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
203//config: Each read of "$RANDOM" will generate a new pseudorandom value. 214//config: Each read of "$RANDOM" will generate a new pseudorandom value.
@@ -205,7 +216,7 @@
205//config:config HUSH_MODE_X 216//config:config HUSH_MODE_X
206//config: bool "Support 'hush -x' option and 'set -x' command" 217//config: bool "Support 'hush -x' option and 'set -x' command"
207//config: default y 218//config: default y
208//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 219//config: depends on SHELL_HUSH
209//config: help 220//config: help
210//config: This instructs hush to print commands before execution. 221//config: This instructs hush to print commands before execution.
211//config: Adds ~300 bytes. 222//config: Adds ~300 bytes.
@@ -213,27 +224,27 @@
213//config:config HUSH_ECHO 224//config:config HUSH_ECHO
214//config: bool "echo builtin" 225//config: bool "echo builtin"
215//config: default y 226//config: default y
216//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 227//config: depends on SHELL_HUSH
217//config: 228//config:
218//config:config HUSH_PRINTF 229//config:config HUSH_PRINTF
219//config: bool "printf builtin" 230//config: bool "printf builtin"
220//config: default y 231//config: default y
221//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 232//config: depends on SHELL_HUSH
222//config: 233//config:
223//config:config HUSH_TEST 234//config:config HUSH_TEST
224//config: bool "test builtin" 235//config: bool "test builtin"
225//config: default y 236//config: default y
226//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 237//config: depends on SHELL_HUSH
227//config: 238//config:
228//config:config HUSH_HELP 239//config:config HUSH_HELP
229//config: bool "help builtin" 240//config: bool "help builtin"
230//config: default y 241//config: default y
231//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 242//config: depends on SHELL_HUSH
232//config: 243//config:
233//config:config HUSH_EXPORT 244//config:config HUSH_EXPORT
234//config: bool "export builtin" 245//config: bool "export builtin"
235//config: default y 246//config: default y
236//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 247//config: depends on SHELL_HUSH
237//config: 248//config:
238//config:config HUSH_EXPORT_N 249//config:config HUSH_EXPORT_N
239//config: bool "Support 'export -n' option" 250//config: bool "Support 'export -n' option"
@@ -245,83 +256,83 @@
245//config:config HUSH_READONLY 256//config:config HUSH_READONLY
246//config: bool "readonly builtin" 257//config: bool "readonly builtin"
247//config: default y 258//config: default y
248//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 259//config: depends on SHELL_HUSH
249//config: help 260//config: help
250//config: Enable support for read-only variables. 261//config: Enable support for read-only variables.
251//config: 262//config:
252//config:config HUSH_KILL 263//config:config HUSH_KILL
253//config: bool "kill builtin (supports kill %jobspec)" 264//config: bool "kill builtin (supports kill %jobspec)"
254//config: default y 265//config: default y
255//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 266//config: depends on SHELL_HUSH
256//config: 267//config:
257//config:config HUSH_WAIT 268//config:config HUSH_WAIT
258//config: bool "wait builtin" 269//config: bool "wait builtin"
259//config: default y 270//config: default y
260//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 271//config: depends on SHELL_HUSH
261//config: 272//config:
262//config:config HUSH_COMMAND 273//config:config HUSH_COMMAND
263//config: bool "command builtin" 274//config: bool "command builtin"
264//config: default y 275//config: default y
265//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 276//config: depends on SHELL_HUSH
266//config: 277//config:
267//config:config HUSH_TRAP 278//config:config HUSH_TRAP
268//config: bool "trap builtin" 279//config: bool "trap builtin"
269//config: default y 280//config: default y
270//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 281//config: depends on SHELL_HUSH
271//config: 282//config:
272//config:config HUSH_TYPE 283//config:config HUSH_TYPE
273//config: bool "type builtin" 284//config: bool "type builtin"
274//config: default y 285//config: default y
275//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 286//config: depends on SHELL_HUSH
276//config: 287//config:
277//config:config HUSH_TIMES 288//config:config HUSH_TIMES
278//config: bool "times builtin" 289//config: bool "times builtin"
279//config: default y 290//config: default y
280//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 291//config: depends on SHELL_HUSH
281//config: 292//config:
282//config:config HUSH_READ 293//config:config HUSH_READ
283//config: bool "read builtin" 294//config: bool "read builtin"
284//config: default y 295//config: default y
285//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 296//config: depends on SHELL_HUSH
286//config: 297//config:
287//config:config HUSH_SET 298//config:config HUSH_SET
288//config: bool "set builtin" 299//config: bool "set builtin"
289//config: default y 300//config: default y
290//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 301//config: depends on SHELL_HUSH
291//config: 302//config:
292//config:config HUSH_UNSET 303//config:config HUSH_UNSET
293//config: bool "unset builtin" 304//config: bool "unset builtin"
294//config: default y 305//config: default y
295//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 306//config: depends on SHELL_HUSH
296//config: 307//config:
297//config:config HUSH_ULIMIT 308//config:config HUSH_ULIMIT
298//config: bool "ulimit builtin" 309//config: bool "ulimit builtin"
299//config: default y 310//config: default y
300//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 311//config: depends on SHELL_HUSH
301//config: 312//config:
302//config:config HUSH_UMASK 313//config:config HUSH_UMASK
303//config: bool "umask builtin" 314//config: bool "umask builtin"
304//config: default y 315//config: default y
305//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 316//config: depends on SHELL_HUSH
306//config: 317//config:
307//config:config HUSH_GETOPTS 318//config:config HUSH_GETOPTS
308//config: bool "getopts builtin" 319//config: bool "getopts builtin"
309//config: default y 320//config: default y
310//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 321//config: depends on SHELL_HUSH
311//config: 322//config:
312//config:config HUSH_MEMLEAK 323//config:config HUSH_MEMLEAK
313//config: bool "memleak builtin (debugging)" 324//config: bool "memleak builtin (debugging)"
314//config: default n 325//config: default n
315//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH 326//config: depends on SHELL_HUSH
327//config:
328//config:endif # hush options
316 329
317//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP)) 330//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP))
318// APPLET_ODDNAME:name main location suid_type help 331// APPLET_ODDNAME:name main location suid_type help
319//applet:IF_SH_IS_HUSH( APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, hush)) 332//applet:IF_SH_IS_HUSH( APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, hush))
320//applet:IF_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, hush)) 333//applet:IF_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, hush))
321 334
322//kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o 335//kbuild:lib-$(CONFIG_SHELL_HUSH) += hush.o match.o shell_common.o
323//kbuild:lib-$(CONFIG_SH_IS_HUSH) += hush.o match.o shell_common.o
324//kbuild:lib-$(CONFIG_BASH_IS_HUSH) += hush.o match.o shell_common.o
325//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o 336//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o
326 337
327/* -i (interactive) is also accepted, 338/* -i (interactive) is also accepted,
@@ -7917,7 +7928,7 @@ static const struct built_in_command *find_builtin(const char *name)
7917 return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); 7928 return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]);
7918} 7929}
7919 7930
7920#if EDITING_HAS_get_exe_name 7931#if ENABLE_HUSH_JOB && EDITING_HAS_get_exe_name
7921static const char * FAST_FUNC get_builtin_name(int i) 7932static const char * FAST_FUNC get_builtin_name(int i)
7922{ 7933{
7923 if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { 7934 if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) {
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index b5008290f..87f6b5007 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -390,5 +390,13 @@ testing 'awk negative field access' \
390 '' \ 390 '' \
391 'anything' 391 'anything'
392 392
393# was misinterpreted as (("str"++) i) instead of ("str" (++i))
394# (and was executed: "str"++ is "0", thus concatenating "0" and "1"):
395testing 'awk do not allow "str"++' \
396 'awk -v i=1 "BEGIN {print \"str\" ++i}"' \
397 "str2\n" \
398 '' \
399 'anything'
400
393 401
394exit $FAILCOUNT 402exit $FAILCOUNT
diff --git a/testsuite/cpio.tests b/testsuite/cpio.tests
index 88ec086b6..85e746589 100755
--- a/testsuite/cpio.tests
+++ b/testsuite/cpio.tests
@@ -129,7 +129,7 @@ SKIP=
129 129
130optional FEATURE_CPIO_O 130optional FEATURE_CPIO_O
131testing "cpio uses by default uid/gid" \ 131testing "cpio uses by default uid/gid" \
132"echo $0 | cpio -o -H newc | cpio -tv 2>&1 | tail -n +2 | awk ' { print \$2 } '; echo \$?" \ 132"echo $0 | cpio -o -H newc | cpio -tv 2>&1 | head -n1 | awk ' { print \$2 } '; echo \$?" \
133"\ 133"\
134$user/$group 134$user/$group
1350 1350
@@ -138,7 +138,7 @@ SKIP=
138 138
139optional FEATURE_CPIO_O 139optional FEATURE_CPIO_O
140testing "cpio -R with create" \ 140testing "cpio -R with create" \
141"echo $0 | cpio -o -H newc -R 1234:5678 | cpio -tv 2>&1 | tail -n +2 | awk ' { print \$2 } '; echo \$?" \ 141"echo $0 | cpio -o -H newc -R 1234:5678 | cpio -tv 2>&1 | head -n1 | awk ' { print \$2 } '; echo \$?" \
142"\ 142"\
1431234/5678 1431234/5678
1440 1440
@@ -147,7 +147,7 @@ SKIP=
147 147
148optional FEATURE_CPIO_O 148optional FEATURE_CPIO_O
149testing "cpio -R with extract" \ 149testing "cpio -R with extract" \
150"echo $0 | cpio -o -H newc | cpio -tv -R 8765:4321 2>&1 | tail -n +2 | awk ' { print \$2 } '; echo \$?" \ 150"echo $0 | cpio -o -H newc | cpio -tv -R 8765:4321 2>&1 | head -n1 | awk ' { print \$2 } '; echo \$?" \
151"\ 151"\
1528765/4321 1528765/4321
1530 1530
diff --git a/testsuite/mdev.tests b/testsuite/mdev.tests
index 8e53ec564..44a723024 100755
--- a/testsuite/mdev.tests
+++ b/testsuite/mdev.tests
@@ -93,7 +93,7 @@ SKIP=
93# continuing to use directory structure from prev test 93# continuing to use directory structure from prev test
94rm -rf mdev.testdir/dev/* 94rm -rf mdev.testdir/dev/*
95echo "sda 0:0 444 >disk/scsiA" >mdev.testdir/etc/mdev.conf 95echo "sda 0:0 444 >disk/scsiA" >mdev.testdir/etc/mdev.conf
96optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME 96optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_LS_SORTFILES
97testing "mdev move/symlink rule '>bar/baz'" \ 97testing "mdev move/symlink rule '>bar/baz'" \
98 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; 98 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
99 ls -lnR mdev.testdir/dev | $FILTER_LS2" \ 99 ls -lnR mdev.testdir/dev | $FILTER_LS2" \
@@ -111,7 +111,7 @@ SKIP=
111# continuing to use directory structure from prev test 111# continuing to use directory structure from prev test
112rm -rf mdev.testdir/dev/* 112rm -rf mdev.testdir/dev/*
113echo "sda 0:0 444 >disk/" >mdev.testdir/etc/mdev.conf 113echo "sda 0:0 444 >disk/" >mdev.testdir/etc/mdev.conf
114optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME 114optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_LS_SORTFILES
115testing "mdev move/symlink rule '>bar/'" \ 115testing "mdev move/symlink rule '>bar/'" \
116 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; 116 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
117 ls -lnR mdev.testdir/dev | $FILTER_LS2" \ 117 ls -lnR mdev.testdir/dev | $FILTER_LS2" \
diff --git a/testsuite/patch.tests b/testsuite/patch.tests
index 39205242c..1d48e90be 100755
--- a/testsuite/patch.tests
+++ b/testsuite/patch.tests
@@ -75,12 +75,12 @@ zxc
75testing "patch detects already applied hunk" \ 75testing "patch detects already applied hunk" \
76 'patch 2>&1; echo $?; cat input' \ 76 'patch 2>&1; echo $?; cat input' \
77"\ 77"\
78patching file input
78Possibly reversed hunk 1 at 4 79Possibly reversed hunk 1 at 4
79Hunk 1 FAILED 1/1. 80Hunk 1 FAILED 1/1.
80 abc 81 abc
81+def 82+def
82 123 83 123
83patching file input
841 841
85abc 85abc
86def 86def
@@ -103,12 +103,12 @@ def
103testing "patch detects already applied hunk at the EOF" \ 103testing "patch detects already applied hunk at the EOF" \
104 'patch 2>&1; echo $?; cat input' \ 104 'patch 2>&1; echo $?; cat input' \
105"\ 105"\
106patching file input
106Possibly reversed hunk 1 at 4 107Possibly reversed hunk 1 at 4
107Hunk 1 FAILED 1/1. 108Hunk 1 FAILED 1/1.
108 abc 109 abc
109 123 110 123
110+456 111+456
111patching file input
1121 1121
113abc 113abc
114123 114123
diff --git a/testsuite/unexpand.tests b/testsuite/unexpand.tests
index 7b326dc2c..aeaae13f0 100755
--- a/testsuite/unexpand.tests
+++ b/testsuite/unexpand.tests
@@ -31,6 +31,39 @@ testing "unexpand case 7" "unexpand" \
31testing "unexpand case 8" "unexpand" \ 31testing "unexpand case 8" "unexpand" \
32 "a b\n" "" "a b\n" \ 32 "a b\n" "" "a b\n" \
33 33
34testcase()
35{
36 testing "unexpand flags $*" "unexpand $*" \
37 "$want" "" ' a b c'
38}
39
40# tabs=8, Convert only leading sequences of blanks
41want='\ta b c'
42testcase
43testcase -f
44testcase -f -t8
45testcase -t8 -f
46testcase -t8 --first-only
47
48# tabs=8, Convert all blanks
49want='\ta\tb c'
50testcase -a
51testcase -t8
52testcase -a -t8
53
54# tabs=4, Convert all blanks
55want='\t\ta\t\tb\t c'
56testcase -t4
57testcase -a -t4
58testcase -t4 -a
59
60# tabs=4, Convert only leading sequences of blanks
61want='\t\ta b c'
62testcase -t4 -f
63testcase -f -t4
64testcase -t4 --first-only
65testcase --first-only -t4
66
34test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ 67test x"$CONFIG_UNICODE_SUPPORT" = x"y" \
35&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ 68&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \
36&& testing "unexpand with unicode characher 0x394" "unexpand" \ 69&& testing "unexpand with unicode characher 0x394" "unexpand" \
diff --git a/util-linux/acpid.c b/util-linux/acpid.c
index 95f8150e2..fc8215cce 100644
--- a/util-linux/acpid.c
+++ b/util-linux/acpid.c
@@ -42,7 +42,9 @@
42//usage: "\n -c DIR Config directory [/etc/acpi]" 42//usage: "\n -c DIR Config directory [/etc/acpi]"
43//usage: "\n -e FILE /proc event file [/proc/acpi/event]" 43//usage: "\n -e FILE /proc event file [/proc/acpi/event]"
44//usage: "\n -l FILE Log file [/var/log/acpid.log]" 44//usage: "\n -l FILE Log file [/var/log/acpid.log]"
45//usage: "\n -p FILE Pid file [/var/run/acpid.pid]" 45//usage: IF_FEATURE_PIDFILE(
46//usage: "\n -p FILE Pid file [" CONFIG_PID_FILE_PATH "/acpid.pid]"
47//usage: )
46//usage: "\n -a FILE Action file [/etc/acpid.conf]" 48//usage: "\n -a FILE Action file [/etc/acpid.conf]"
47//usage: "\n -M FILE Map file [/etc/acpi.map]" 49//usage: "\n -M FILE Map file [/etc/acpi.map]"
48//usage: IF_FEATURE_ACPID_COMPAT( 50//usage: IF_FEATURE_ACPID_COMPAT(
diff --git a/util-linux/nologin.c b/util-linux/nologin.c
index 5e5e42305..5a8b047a5 100644
--- a/util-linux/nologin.c
+++ b/util-linux/nologin.c
@@ -7,7 +7,7 @@
7//config: 7//config:
8//config:config NOLOGIN_DEPENDENCIES 8//config:config NOLOGIN_DEPENDENCIES
9//config: bool "Enable dependencies for nologin" 9//config: bool "Enable dependencies for nologin"
10//config: default y 10//config: default n # Y default makes it harder to select single-applet test
11//config: depends on NOLOGIN 11//config: depends on NOLOGIN
12//config: select CAT 12//config: select CAT
13//config: select ECHO 13//config: select ECHO