aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2018-03-01 15:37:12 +0000
committerRon Yorston <rmy@pobox.com>2018-03-01 15:37:12 +0000
commit5b726f8a78c33e117c2a968739b1b4a6964905f8 (patch)
treeaf063c6bf3e99b7480c2fad2dffc2a76c09cb5e0
parent5f8dac68690e92f0be220f8f8d9f797a2aedc806 (diff)
parentcc222747ae7e264cbe9b1c8a9c253860275db8a9 (diff)
downloadbusybox-w32-5b726f8a78c33e117c2a968739b1b4a6964905f8.tar.gz
busybox-w32-5b726f8a78c33e117c2a968739b1b4a6964905f8.tar.bz2
busybox-w32-5b726f8a78c33e117c2a968739b1b4a6964905f8.zip
Merge branch 'busybox' into merge
-rwxr-xr-xapplets/install.sh18
-rw-r--r--archival/libarchive/data_extract_all.c28
-rw-r--r--archival/libarchive/unsafe_symlink_target.c59
-rw-r--r--archival/tar.c2
-rw-r--r--archival/unzip.c25
-rw-r--r--coreutils/df.c32
-rw-r--r--coreutils/od_bloaty.c18
-rw-r--r--coreutils/sort.c97
-rw-r--r--include/bb_archive.h23
-rw-r--r--include/libbb.h6
-rw-r--r--init/halt.c54
-rw-r--r--libbb/capability.c3
-rw-r--r--libbb/progress.c13
-rw-r--r--libbb/skip_whitespace.c5
-rw-r--r--miscutils/less.c6
-rw-r--r--networking/inetd.c6
-rw-r--r--networking/ip.c58
-rw-r--r--networking/libiproute/iplink.c62
-rw-r--r--networking/ping.c105
-rw-r--r--networking/tcpudp.c9
-rw-r--r--networking/tcpudp_perhost.c22
-rw-r--r--networking/tcpudp_perhost.h8
-rw-r--r--networking/tls.c2
-rw-r--r--shell/ash.c23
-rw-r--r--shell/ash_test/ash-quoting/bkslash_case1.right10
-rwxr-xr-xshell/ash_test/ash-quoting/bkslash_case1.tests38
-rw-r--r--shell/hush.c20
-rw-r--r--shell/hush_test/hush-quoting/bkslash_case1.right10
-rwxr-xr-xshell/hush_test/hush-quoting/bkslash_case1.tests38
-rwxr-xr-xtestsuite/tar.tests10
-rw-r--r--util-linux/mkfs_ext2.c6
-rw-r--r--util-linux/mkfs_vfat.c6
-rw-r--r--util-linux/mount.c6
-rw-r--r--util-linux/switch_root.c6
-rw-r--r--util-linux/umount.c8
35 files changed, 604 insertions, 238 deletions
diff --git a/applets/install.sh b/applets/install.sh
index ae99381d7..c75a78e9d 100755
--- a/applets/install.sh
+++ b/applets/install.sh
@@ -38,7 +38,7 @@ while [ ${#} -gt 0 ]; do
38 shift 38 shift
39done 39done
40 40
41if [ -n "$DO_INSTALL_LIBS" ] && [ "$DO_INSTALL_LIBS" != "n" ]; then 41if [ -n "$DO_INSTALL_LIBS" ] && [ x"$DO_INSTALL_LIBS" != x"n" ]; then
42 # get the target dir for the libs 42 # get the target dir for the libs
43 # assume it starts with lib 43 # assume it starts with lib
44 libdir=$($CC -print-file-name=libc.so | \ 44 libdir=$($CC -print-file-name=libc.so | \
@@ -58,7 +58,7 @@ if [ -n "$DO_INSTALL_LIBS" ] && [ "$DO_INSTALL_LIBS" != "n" ]; then
58 done 58 done
59fi 59fi
60 60
61if [ "$cleanup" = "1" ] && [ -e "$prefix/bin/busybox" ]; then 61if [ x"$cleanup" = x"1" ] && [ -e "$prefix/bin/busybox" ]; then
62 inode=`ls -i "$prefix/bin/busybox" | awk '{print $1}'` 62 inode=`ls -i "$prefix/bin/busybox" | awk '{print $1}'`
63 sub_shell_it=` 63 sub_shell_it=`
64 cd "$prefix" 64 cd "$prefix"
@@ -81,13 +81,13 @@ install -m 755 busybox "$prefix/bin/busybox" || exit 1
81for i in $h; do 81for i in $h; do
82 appdir=`dirname "$i"` 82 appdir=`dirname "$i"`
83 app=`basename "$i"` 83 app=`basename "$i"`
84 if [ "$noclobber" = "1" ] && [ -e "$prefix/$i" ]; then 84 if [ x"$noclobber" = x"1" ] && [ -e "$prefix/$i" ]; then
85 echo " $prefix/$i already exists" 85 echo " $prefix/$i already exists"
86 continue 86 continue
87 fi 87 fi
88 mkdir -p "$prefix/$appdir" || exit 1 88 mkdir -p "$prefix/$appdir" || exit 1
89 if [ "$scriptwrapper" = "y" ]; then 89 if [ x"$scriptwrapper" = x"y" ]; then
90 if [ "$swrapall" != "y" ] && [ "$i" = "/bin/sh" ]; then 90 if [ x"$swrapall" != x"y" ] && [ x"$i" = x"/bin/sh" ]; then
91 ln $linkopts busybox "$prefix/$i" || exit 1 91 ln $linkopts busybox "$prefix/$i" || exit 1
92 else 92 else
93 rm -f "$prefix/$i" 93 rm -f "$prefix/$i"
@@ -95,17 +95,17 @@ for i in $h; do
95 chmod +x "$prefix/$i" 95 chmod +x "$prefix/$i"
96 fi 96 fi
97 echo " $prefix/$i" 97 echo " $prefix/$i"
98 elif [ "$binaries" = "y" ]; then 98 elif [ x"$binaries" = x"y" ]; then
99 # Copy the binary over rather 99 # Copy the binary over rather
100 if [ -e $sharedlib_dir/$app ]; then 100 if [ -e "$sharedlib_dir/$app" ]; then
101 echo " Copying $sharedlib_dir/$app to $prefix/$i" 101 echo " Copying $sharedlib_dir/$app to $prefix/$i"
102 cp -pPR $sharedlib_dir/$app $prefix/$i || exit 1 102 cp -pPR "$sharedlib_dir/$app" "$prefix/$i" || exit 1
103 else 103 else
104 echo "Error: Could not find $sharedlib_dir/$app" 104 echo "Error: Could not find $sharedlib_dir/$app"
105 exit 1 105 exit 1
106 fi 106 fi
107 else 107 else
108 if [ "$2" = "--hardlinks" ]; then 108 if [ x"$linkopts" = x"-f" ]; then
109 bb_path="$prefix/bin/busybox" 109 bb_path="$prefix/bin/busybox"
110 else 110 else
111 case "$appdir" in 111 case "$appdir" in
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index d3a6df5e8..8fa69ffaf 100644
--- a/archival/libarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -107,9 +107,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
107 } 107 }
108 } 108 }
109 else if (existing_sb.st_mtime >= file_header->mtime) { 109 else if (existing_sb.st_mtime >= file_header->mtime) {
110 if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) 110 if (!S_ISDIR(file_header->mode)) {
111 && !S_ISDIR(file_header->mode)
112 ) {
113 bb_error_msg("%s not created: newer or " 111 bb_error_msg("%s not created: newer or "
114 "same age file exists", dst_name); 112 "same age file exists", dst_name);
115 } 113 }
@@ -125,7 +123,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
125 /* Handle hard links separately */ 123 /* Handle hard links separately */
126 if (hard_link) { 124 if (hard_link) {
127 res = link(hard_link, dst_name); 125 res = link(hard_link, dst_name);
128 if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { 126 if (res != 0) {
129 /* shared message */ 127 /* shared message */
130 bb_perror_msg("can't create %slink '%s' to '%s'", 128 bb_perror_msg("can't create %slink '%s' to '%s'",
131 "hard", dst_name, hard_link 129 "hard", dst_name, hard_link
@@ -165,10 +163,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
165 } 163 }
166 case S_IFDIR: 164 case S_IFDIR:
167 res = mkdir(dst_name, file_header->mode); 165 res = mkdir(dst_name, file_header->mode);
168 if ((res == -1) 166 if ((res != 0)
169 && (errno != EISDIR) /* btw, Linux doesn't return this */ 167 && (errno != EISDIR) /* btw, Linux doesn't return this */
170 && (errno != EEXIST) 168 && (errno != EEXIST)
171 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
172 ) { 169 ) {
173 bb_perror_msg("can't make dir %s", dst_name); 170 bb_perror_msg("can't make dir %s", dst_name);
174 } 171 }
@@ -198,27 +195,16 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
198 * 195 *
199 * Untarring bug.tar would otherwise place evil.py in '/tmp'. 196 * Untarring bug.tar would otherwise place evil.py in '/tmp'.
200 */ 197 */
201 if (!unsafe_symlink_target(file_header->link_target)) { 198 create_or_remember_symlink(&archive_handle->symlink_placeholders,
202 res = symlink(file_header->link_target, dst_name); 199 file_header->link_target,
203 if (res != 0 200 dst_name);
204 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
205 ) {
206 /* shared message */
207 bb_perror_msg("can't create %slink '%s' to '%s'",
208 "sym",
209 dst_name, file_header->link_target
210 );
211 }
212 }
213 break; 201 break;
214 case S_IFSOCK: 202 case S_IFSOCK:
215 case S_IFBLK: 203 case S_IFBLK:
216 case S_IFCHR: 204 case S_IFCHR:
217 case S_IFIFO: 205 case S_IFIFO:
218 res = mknod(dst_name, file_header->mode, file_header->device); 206 res = mknod(dst_name, file_header->mode, file_header->device);
219 if ((res == -1) 207 if (res != 0) {
220 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
221 ) {
222 bb_perror_msg("can't create node %s", dst_name); 208 bb_perror_msg("can't create node %s", dst_name);
223 } 209 }
224 break; 210 break;
diff --git a/archival/libarchive/unsafe_symlink_target.c b/archival/libarchive/unsafe_symlink_target.c
index 441ba8b24..8dcafeaa1 100644
--- a/archival/libarchive/unsafe_symlink_target.c
+++ b/archival/libarchive/unsafe_symlink_target.c
@@ -5,44 +5,37 @@
5#include "libbb.h" 5#include "libbb.h"
6#include "bb_archive.h" 6#include "bb_archive.h"
7 7
8int FAST_FUNC unsafe_symlink_target(const char *target) 8void FAST_FUNC create_or_remember_symlink(llist_t **symlink_placeholders,
9 const char *target,
10 const char *linkname)
9{ 11{
10 const char *dot; 12 if (target[0] == '/' || strstr(target, "..")) {
11 13 llist_add_to(symlink_placeholders,
12 if (target[0] == '/') { 14 xasprintf("%s%c%s", linkname, '\0', target)
13 const char *var; 15 );
14 unsafe: 16 return;
15 var = getenv("EXTRACT_UNSAFE_SYMLINKS"); 17 }
16 if (var) { 18 if (symlink(target, linkname) != 0) {
17 if (LONE_CHAR(var, '1')) 19 /* shared message */
18 return 0; /* pretend it's safe */ 20 bb_perror_msg_and_die("can't create %slink '%s' to '%s'",
19 return 1; /* "UNSAFE!" */ 21 "sym", linkname, target
20 }
21 bb_error_msg("skipping unsafe symlink to '%s' in archive,"
22 " set %s=1 to extract",
23 target,
24 "EXTRACT_UNSAFE_SYMLINKS"
25 ); 22 );
26 /* Prevent further messages */
27 setenv("EXTRACT_UNSAFE_SYMLINKS", "0", 0);
28 return 1; /* "UNSAFE!" */
29 } 23 }
24}
30 25
31 dot = target; 26void FAST_FUNC create_symlinks_from_list(llist_t *list)
32 for (;;) { 27{
33 dot = strchr(dot, '.'); 28 while (list) {
34 if (!dot) 29 char *target;
35 return 0; /* safe target */
36 30
37 /* Is it a path component starting with ".."? */ 31 target = list->data + strlen(list->data) + 1;
38 if ((dot[1] == '.') 32 if (symlink(target, list->data)) {
39 && (dot == target || dot[-1] == '/') 33 /* shared message */
40 /* Is it exactly ".."? */ 34 bb_error_msg_and_die("can't create %slink '%s' to '%s'",
41 && (dot[2] == '/' || dot[2] == '\0') 35 "sym",
42 ) { 36 list->data, target
43 goto unsafe; 37 );
44 } 38 }
45 /* NB: it can even be trailing ".", should only add 1 */ 39 list = list->link;
46 dot += 1;
47 } 40 }
48} 41}
diff --git a/archival/tar.c b/archival/tar.c
index fbe5e3be8..d0684b69e 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -1279,6 +1279,8 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1279 while (get_header_tar(tar_handle) == EXIT_SUCCESS) 1279 while (get_header_tar(tar_handle) == EXIT_SUCCESS)
1280 bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */ 1280 bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */
1281 1281
1282 create_symlinks_from_list(tar_handle->symlink_placeholders);
1283
1282 /* Check that every file that should have been extracted was */ 1284 /* Check that every file that should have been extracted was */
1283 while (tar_handle->accept) { 1285 while (tar_handle->accept) {
1284 if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) 1286 if (!find_list_entry(tar_handle->reject, tar_handle->accept->data)
diff --git a/archival/unzip.c b/archival/unzip.c
index fb58b62c0..369c6c028 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -348,7 +348,9 @@ static void unzip_create_leading_dirs(const char *fn)
348} 348}
349 349
350#if ENABLE_FEATURE_UNZIP_CDF 350#if ENABLE_FEATURE_UNZIP_CDF
351static void unzip_extract_symlink(zip_header_t *zip, const char *dst_fn) 351static void unzip_extract_symlink(llist_t **symlink_placeholders,
352 zip_header_t *zip,
353 const char *dst_fn)
352{ 354{
353 char *target; 355 char *target;
354 356
@@ -373,15 +375,9 @@ static void unzip_extract_symlink(zip_header_t *zip, const char *dst_fn)
373 target[xstate.mem_output_size] = '\0'; 375 target[xstate.mem_output_size] = '\0';
374#endif 376#endif
375 } 377 }
376 if (!unsafe_symlink_target(target)) { 378 create_or_remember_symlink(symlink_placeholders,
377//TODO: libbb candidate 379 target,
378 if (symlink(target, dst_fn)) { 380 dst_fn);
379 /* shared message */
380 bb_perror_msg_and_die("can't create %slink '%s' to '%s'",
381 "sym", dst_fn, target
382 );
383 }
384 }
385 free(target); 381 free(target);
386} 382}
387#endif 383#endif
@@ -493,6 +489,9 @@ int unzip_main(int argc, char **argv)
493 llist_t *zaccept = NULL; 489 llist_t *zaccept = NULL;
494 llist_t *zreject = NULL; 490 llist_t *zreject = NULL;
495 char *base_dir = NULL; 491 char *base_dir = NULL;
492#if ENABLE_FEATURE_UNZIP_CDF
493 llist_t *symlink_placeholders = NULL;
494#endif
496 int i; 495 int i;
497 char key_buf[80]; /* must match size used by my_fgets80 */ 496 char key_buf[80]; /* must match size used by my_fgets80 */
498 497
@@ -957,7 +956,7 @@ int unzip_main(int argc, char **argv)
957#if ENABLE_FEATURE_UNZIP_CDF 956#if ENABLE_FEATURE_UNZIP_CDF
958 if (S_ISLNK(file_mode)) { 957 if (S_ISLNK(file_mode)) {
959 if (dst_fd != STDOUT_FILENO) /* not -p? */ 958 if (dst_fd != STDOUT_FILENO) /* not -p? */
960 unzip_extract_symlink(&zip, dst_fn); 959 unzip_extract_symlink(&symlink_placeholders, &zip, dst_fn);
961 } else 960 } else
962#endif 961#endif
963 { 962 {
@@ -993,6 +992,10 @@ int unzip_main(int argc, char **argv)
993 total_entries++; 992 total_entries++;
994 } 993 }
995 994
995#if ENABLE_FEATURE_UNZIP_CDF
996 create_symlinks_from_list(symlink_placeholders);
997#endif
998
996 if ((opts & OPT_l) && quiet <= 1) { 999 if ((opts & OPT_l) && quiet <= 1) {
997 if (!verbose) { 1000 if (!verbose) {
998 // " Length Date Time Name\n" 1001 // " Length Date Time Name\n"
diff --git a/coreutils/df.c b/coreutils/df.c
index 4076b5fec..50dccac52 100644
--- a/coreutils/df.c
+++ b/coreutils/df.c
@@ -91,8 +91,6 @@ static unsigned long kscale(unsigned long b, unsigned long bs)
91int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 91int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
92int df_main(int argc UNUSED_PARAM, char **argv) 92int df_main(int argc UNUSED_PARAM, char **argv)
93{ 93{
94 unsigned long blocks_used;
95 unsigned blocks_percent_used;
96 unsigned long df_disp_hr = 1024; 94 unsigned long df_disp_hr = 1024;
97 int status = EXIT_SUCCESS; 95 int status = EXIT_SUCCESS;
98 unsigned opt; 96 unsigned opt;
@@ -208,6 +206,11 @@ int df_main(int argc UNUSED_PARAM, char **argv)
208 } 206 }
209 207
210 device = mount_entry->mnt_fsname; 208 device = mount_entry->mnt_fsname;
209
210 /* GNU coreutils 6.10 skips certain mounts, try to be compatible */
211 if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(device, "rootfs") == 0)
212 continue;
213
211 mount_point = mount_entry->mnt_dir; 214 mount_point = mount_entry->mnt_dir;
212 fs_type = mount_entry->mnt_type; 215 fs_type = mount_entry->mnt_type;
213 216
@@ -222,26 +225,31 @@ int df_main(int argc UNUSED_PARAM, char **argv)
222 s.f_frsize = s.f_bsize; 225 s.f_frsize = s.f_bsize;
223 226
224 if ((s.f_blocks > 0) || !mount_table || (opt & OPT_ALL)) { 227 if ((s.f_blocks > 0) || !mount_table || (opt & OPT_ALL)) {
228 unsigned long long blocks_used;
229 unsigned long long blocks_total;
230 unsigned blocks_percent_used;
231
225 if (opt & OPT_INODE) { 232 if (opt & OPT_INODE) {
226 s.f_blocks = s.f_files; 233 s.f_blocks = s.f_files;
227 s.f_bavail = s.f_bfree = s.f_ffree; 234 s.f_bavail = s.f_bfree = s.f_ffree;
228 s.f_frsize = 1; 235 s.f_frsize = 1;
229
230 if (df_disp_hr) 236 if (df_disp_hr)
231 df_disp_hr = 1; 237 df_disp_hr = 1;
232 } 238 }
233 blocks_used = s.f_blocks - s.f_bfree; 239 blocks_used = s.f_blocks - s.f_bfree;
234 blocks_percent_used = 0; 240 blocks_total = blocks_used + s.f_bavail;
235 if (blocks_used + s.f_bavail) { 241 blocks_percent_used = blocks_total; /* 0% if blocks_total == 0, else... */
236 blocks_percent_used = (blocks_used * 100ULL 242 if (blocks_total != 0) {
237 + (blocks_used + s.f_bavail)/2 243 /* Downscale sizes for narrower division */
238 ) / (blocks_used + s.f_bavail); 244 unsigned u;
245 while (blocks_total >= INT_MAX / 101) {
246 blocks_total >>= 1;
247 blocks_used >>= 1;
248 }
249 u = (unsigned)blocks_used * 100u + (unsigned)blocks_total / 2;
250 blocks_percent_used = u / (unsigned)blocks_total;
239 } 251 }
240 252
241 /* GNU coreutils 6.10 skips certain mounts, try to be compatible. */
242 if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(device, "rootfs") == 0)
243 continue;
244
245#ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY 253#ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY
246 if (strcmp(device, "/dev/root") == 0) { 254 if (strcmp(device, "/dev/root") == 0) {
247 /* Adjusts device to be the real root device, 255 /* Adjusts device to be the real root device,
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c
index 645a05f57..75e14ef7d 100644
--- a/coreutils/od_bloaty.c
+++ b/coreutils/od_bloaty.c
@@ -218,7 +218,14 @@ struct globals {
218 218
219 bool not_first; 219 bool not_first;
220 bool prev_pair_equal; 220 bool prev_pair_equal;
221
222 char address_fmt[sizeof("%0n"OFF_FMT"xc")];
221} FIX_ALIASING; 223} FIX_ALIASING;
224/* Corresponds to 'x' above */
225#define address_base_char G.address_fmt[sizeof(G.address_fmt)-3]
226/* Corresponds to 'n' above */
227#define address_pad_len_char G.address_fmt[2]
228
222#if !ENABLE_LONG_OPTS 229#if !ENABLE_LONG_OPTS
223enum { G_pseudo_offset = 0 }; 230enum { G_pseudo_offset = 0 };
224#endif 231#endif
@@ -227,6 +234,7 @@ enum { G_pseudo_offset = 0 };
227 setup_common_bufsiz(); \ 234 setup_common_bufsiz(); \
228 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \ 235 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
229 G.bytes_per_block = 32; \ 236 G.bytes_per_block = 32; \
237 strcpy(G.address_fmt, "%0n"OFF_FMT"xc"); \
230} while (0) 238} while (0)
231 239
232 240
@@ -851,18 +859,12 @@ format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
851{ 859{
852} 860}
853 861
854static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc";
855/* Corresponds to 'x' above */
856#define address_base_char address_fmt[sizeof(address_fmt)-3]
857/* Corresponds to 'n' above */
858#define address_pad_len_char address_fmt[2]
859
860static void 862static void
861format_address_std(off_t address, char c) 863format_address_std(off_t address, char c)
862{ 864{
863 /* Corresponds to 'c' */ 865 /* Corresponds to 'c' */
864 address_fmt[sizeof(address_fmt)-2] = c; 866 G.address_fmt[sizeof(G.address_fmt)-2] = c;
865 printf(address_fmt, address); 867 printf(G.address_fmt, address);
866} 868}
867 869
868#if ENABLE_LONG_OPTS 870#if ENABLE_LONG_OPTS
diff --git a/coreutils/sort.c b/coreutils/sort.c
index ceea24491..b39297a26 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -62,9 +62,9 @@
62//usage: "\n -u Suppress duplicate lines" 62//usage: "\n -u Suppress duplicate lines"
63//usage: IF_FEATURE_SORT_BIG( 63//usage: IF_FEATURE_SORT_BIG(
64//usage: "\n -z Lines are terminated by NUL, not newline" 64//usage: "\n -z Lines are terminated by NUL, not newline"
65////usage: "\n -m Ignored for GNU compatibility" 65///////: "\n -m Ignored for GNU compatibility"
66////usage: "\n -S BUFSZ Ignored for GNU compatibility" 66///////: "\n -S BUFSZ Ignored for GNU compatibility"
67////usage: "\n -T TMPDIR Ignored for GNU compatibility" 67///////: "\n -T TMPDIR Ignored for GNU compatibility"
68//usage: ) 68//usage: )
69//usage: 69//usage:
70//usage:#define sort_example_usage 70//usage:#define sort_example_usage
@@ -85,16 +85,7 @@
85 85
86#include "libbb.h" 86#include "libbb.h"
87 87
88/* This is a NOEXEC applet. Be very careful! */
89
90
91/*
92 sort [-m][-o output][-bdfinru][-t char][-k keydef]... [file...]
93 sort -c [-bdfinru][-t char][-k keydef][file]
94*/
95
96/* These are sort types */ 88/* These are sort types */
97#define OPT_STR "ngMucszbrdfimS:T:o:k:*t:"
98enum { 89enum {
99 FLAG_n = 1, /* Numeric sort */ 90 FLAG_n = 1, /* Numeric sort */
100 FLAG_g = 2, /* Sort using strtod() */ 91 FLAG_g = 2, /* Sort using strtod() */
@@ -117,8 +108,18 @@ enum {
117 FLAG_k = 0x10000, 108 FLAG_k = 0x10000,
118 FLAG_t = 0x20000, 109 FLAG_t = 0x20000,
119 FLAG_bb = 0x80000000, /* Ignore trailing blanks */ 110 FLAG_bb = 0x80000000, /* Ignore trailing blanks */
111 FLAG_no_tie_break = 0x40000000,
120}; 112};
121 113
114static const char sort_opt_str[] ALIGN1 = "^"
115 "ngMucszbrdfimS:T:o:k:*t:"
116 "\0" "o--o:t--t"/*-t, -o: at most one of each*/;
117/*
118 * OPT_STR must not be string literal, needs to have stable address:
119 * code uses "strchr(OPT_STR,c) - OPT_STR" idiom.
120 */
121#define OPT_STR (sort_opt_str + 1)
122
122#if ENABLE_FEATURE_SORT_BIG 123#if ENABLE_FEATURE_SORT_BIG
123static char key_separator; 124static char key_separator;
124 125
@@ -128,6 +129,10 @@ static struct sort_key {
128 unsigned flags; 129 unsigned flags;
129} *key_list; 130} *key_list;
130 131
132
133/* This is a NOEXEC applet. Be very careful! */
134
135
131static char *get_key(char *str, struct sort_key *key, int flags) 136static char *get_key(char *str, struct sort_key *key, int flags)
132{ 137{
133 int start = start; /* for compiler */ 138 int start = start; /* for compiler */
@@ -340,10 +345,35 @@ static int compare_keys(const void *xarg, const void *yarg)
340#endif 345#endif
341 } /* for */ 346 } /* for */
342 347
343 /* Perform fallback sort if necessary */ 348 if (retval == 0) {
344 if (!retval && !(option_mask32 & FLAG_s)) { 349 /* So far lines are "the same" */
345 flags = option_mask32; 350
346 retval = strcmp(*(char **)xarg, *(char **)yarg); 351 if (option_mask32 & FLAG_s) {
352 /* "Stable sort": later line is "greater than",
353 * IOW: do not allow qsort() to swap equal lines.
354 */
355 uint32_t *p32;
356 uint32_t x32, y32;
357 char *line;
358 unsigned len;
359
360 line = *(char**)xarg;
361 len = (strlen(line) + 4) & (~3u);
362 p32 = (void*)(line + len);
363 x32 = *p32;
364 line = *(char**)yarg;
365 len = (strlen(line) + 4) & (~3u);
366 p32 = (void*)(line + len);
367 y32 = *p32;
368
369 /* If x > y, 1, else -1 */
370 retval = (x32 > y32) * 2 - 1;
371 } else
372 if (!(option_mask32 & FLAG_no_tie_break)) {
373 /* fallback sort */
374 flags = option_mask32;
375 retval = strcmp(*(char **)xarg, *(char **)yarg);
376 }
347 } 377 }
348 378
349 if (flags & FLAG_r) 379 if (flags & FLAG_r)
@@ -368,7 +398,7 @@ static unsigned str2u(char **str)
368int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 398int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
369int sort_main(int argc UNUSED_PARAM, char **argv) 399int sort_main(int argc UNUSED_PARAM, char **argv)
370{ 400{
371 char *line, **lines; 401 char **lines;
372 char *str_ignored, *str_o, *str_t; 402 char *str_ignored, *str_o, *str_t;
373 llist_t *lst_k = NULL; 403 llist_t *lst_k = NULL;
374 int i; 404 int i;
@@ -378,9 +408,8 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
378 xfunc_error_retval = 2; 408 xfunc_error_retval = 2;
379 409
380 /* Parse command line options */ 410 /* Parse command line options */
381 opts = getopt32(argv, "^" 411 opts = getopt32(argv,
382 OPT_STR 412 sort_opt_str,
383 "\0" "o--o:t--t"/*-t, -o: at most one of each*/,
384 &str_ignored, &str_ignored, &str_o, &lst_k, &str_t 413 &str_ignored, &str_ignored, &str_o, &lst_k, &str_t
385 ); 414 );
386 /* global b strips leading and trailing spaces */ 415 /* global b strips leading and trailing spaces */
@@ -457,7 +486,7 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
457 * do not continue to next file: */ 486 * do not continue to next file: */
458 FILE *fp = xfopen_stdin(*argv); 487 FILE *fp = xfopen_stdin(*argv);
459 for (;;) { 488 for (;;) {
460 line = GET_LINE(fp); 489 char *line = GET_LINE(fp);
461 if (!line) 490 if (!line)
462 break; 491 break;
463 lines = xrealloc_vector(lines, 6, linecount); 492 lines = xrealloc_vector(lines, 6, linecount);
@@ -482,15 +511,35 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
482 return EXIT_SUCCESS; 511 return EXIT_SUCCESS;
483 } 512 }
484#endif 513#endif
514
515 /* For stable sort, store original line position beyond terminating NUL */
516 if (option_mask32 & FLAG_s) {
517 for (i = 0; i < linecount; i++) {
518 uint32_t *p32;
519 char *line;
520 unsigned len;
521
522 line = lines[i];
523 len = (strlen(line) + 4) & (~3u);
524 lines[i] = line = xrealloc(line, len + 4);
525 p32 = (void*)(line + len);
526 *p32 = i;
527 }
528 /*option_mask32 |= FLAG_no_tie_break;*/
529 /* ^^^redundant: if FLAG_s, compare_keys() does no tie break */
530 }
531
485 /* Perform the actual sort */ 532 /* Perform the actual sort */
486 qsort(lines, linecount, sizeof(lines[0]), compare_keys); 533 qsort(lines, linecount, sizeof(lines[0]), compare_keys);
487 534
488 /* Handle -u */ 535 /* Handle -u */
489 if (option_mask32 & FLAG_u) { 536 if (option_mask32 & FLAG_u) {
490 int j = 0; 537 int j = 0;
491 /* coreutils 6.3 drop lines for which only key is the same */ 538 /* coreutils 6.3 drop lines for which only key is the same
492 /* -- disabling last-resort compare... */ 539 * -- disabling last-resort compare, or else compare_keys()
493 option_mask32 |= FLAG_s; 540 * will be the same only for completely identical lines.
541 */
542 option_mask32 |= FLAG_no_tie_break;
494 for (i = 1; i < linecount; i++) { 543 for (i = 1; i < linecount; i++) {
495 if (compare_keys(&lines[j], &lines[i]) == 0) 544 if (compare_keys(&lines[j], &lines[i]) == 0)
496 free(lines[i]); 545 free(lines[i]);
diff --git a/include/bb_archive.h b/include/bb_archive.h
index c67a299d1..8028736b8 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -74,6 +74,9 @@ typedef struct archive_handle_t {
74 /* Currently processed file's header */ 74 /* Currently processed file's header */
75 file_header_t *file_header; 75 file_header_t *file_header;
76 76
77 /* List of symlink placeholders */
78 llist_t *symlink_placeholders;
79
77 /* Process the header component, e.g. tar -t */ 80 /* Process the header component, e.g. tar -t */
78 void FAST_FUNC (*action_header)(const file_header_t *); 81 void FAST_FUNC (*action_header)(const file_header_t *);
79 82
@@ -129,15 +132,14 @@ typedef struct archive_handle_t {
129#define ARCHIVE_RESTORE_DATE (1 << 0) 132#define ARCHIVE_RESTORE_DATE (1 << 0)
130#define ARCHIVE_CREATE_LEADING_DIRS (1 << 1) 133#define ARCHIVE_CREATE_LEADING_DIRS (1 << 1)
131#define ARCHIVE_UNLINK_OLD (1 << 2) 134#define ARCHIVE_UNLINK_OLD (1 << 2)
132#define ARCHIVE_EXTRACT_QUIET (1 << 3) 135#define ARCHIVE_EXTRACT_NEWER (1 << 3)
133#define ARCHIVE_EXTRACT_NEWER (1 << 4) 136#define ARCHIVE_DONT_RESTORE_OWNER (1 << 4)
134#define ARCHIVE_DONT_RESTORE_OWNER (1 << 5) 137#define ARCHIVE_DONT_RESTORE_PERM (1 << 5)
135#define ARCHIVE_DONT_RESTORE_PERM (1 << 6) 138#define ARCHIVE_NUMERIC_OWNER (1 << 6)
136#define ARCHIVE_NUMERIC_OWNER (1 << 7) 139#define ARCHIVE_O_TRUNC (1 << 7)
137#define ARCHIVE_O_TRUNC (1 << 8) 140#define ARCHIVE_REMEMBER_NAMES (1 << 8)
138#define ARCHIVE_REMEMBER_NAMES (1 << 9)
139#if ENABLE_RPM 141#if ENABLE_RPM
140#define ARCHIVE_REPLACE_VIA_RENAME (1 << 10) 142#define ARCHIVE_REPLACE_VIA_RENAME (1 << 9)
141#endif 143#endif
142 144
143 145
@@ -207,7 +209,10 @@ void seek_by_jump(int fd, off_t amount) FAST_FUNC;
207void seek_by_read(int fd, off_t amount) FAST_FUNC; 209void seek_by_read(int fd, off_t amount) FAST_FUNC;
208 210
209const char *strip_unsafe_prefix(const char *str) FAST_FUNC; 211const char *strip_unsafe_prefix(const char *str) FAST_FUNC;
210int unsafe_symlink_target(const char *target) FAST_FUNC; 212void create_or_remember_symlink(llist_t **symlink_placeholders,
213 const char *target,
214 const char *linkname) FAST_FUNC;
215void create_symlinks_from_list(llist_t *list) FAST_FUNC;
211 216
212void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC; 217void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC;
213const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_FUNC; 218const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_FUNC;
diff --git a/include/libbb.h b/include/libbb.h
index 4a59ee7d8..f8e54de54 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1536,6 +1536,7 @@ extern void run_shell(const char *shell, int loginshell, const char **args) NORE
1536 */ 1536 */
1537const char *get_shell_name(void) FAST_FUNC; 1537const char *get_shell_name(void) FAST_FUNC;
1538 1538
1539#if ENABLE_FEATURE_SETPRIV_CAPABILITIES || ENABLE_RUN_INIT
1539unsigned cap_name_to_number(const char *cap) FAST_FUNC; 1540unsigned cap_name_to_number(const char *cap) FAST_FUNC;
1540void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC; 1541void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC;
1541void drop_capability(int cap_ordinal) FAST_FUNC; 1542void drop_capability(int cap_ordinal) FAST_FUNC;
@@ -1547,9 +1548,7 @@ struct caps { \
1547 struct __user_cap_data_struct data[2]; \ 1548 struct __user_cap_data_struct data[2]; \
1548} 1549}
1549void getcaps(void *caps) FAST_FUNC; 1550void getcaps(void *caps) FAST_FUNC;
1550 1551#endif
1551unsigned cap_name_to_number(const char *name) FAST_FUNC;
1552void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC;
1553 1552
1554#if ENABLE_SELINUX 1553#if ENABLE_SELINUX
1555extern void renew_current_security_context(void) FAST_FUNC; 1554extern void renew_current_security_context(void) FAST_FUNC;
@@ -2006,6 +2005,7 @@ typedef struct bb_progress_t {
2006 unsigned last_update_sec; 2005 unsigned last_update_sec;
2007 unsigned last_change_sec; 2006 unsigned last_change_sec;
2008 unsigned start_sec; 2007 unsigned start_sec;
2008 /*unsigned last_eta;*/
2009 const char *curfile; 2009 const char *curfile;
2010} bb_progress_t; 2010} bb_progress_t;
2011 2011
diff --git a/init/halt.c b/init/halt.c
index c6c857f08..e6dcb1c67 100644
--- a/init/halt.c
+++ b/init/halt.c
@@ -24,6 +24,17 @@
24//config: help 24//config: help
25//config: Stop all processes and reboot the system. 25//config: Stop all processes and reboot the system.
26//config: 26//config:
27//config:config FEATURE_WAIT_FOR_INIT
28//config: bool "Before signaling init, make sure it is ready for it"
29//config: default y
30//config: depends on HALT || POWEROFF || REBOOT
31//config: help
32//config: In rare cases, poweroff may be commanded by firmware to OS
33//config: even before init process exists. On Linux, this spawns
34//config: "/sbin/poweroff" very early. This option adds code
35//config: which checks that init is ready to receive poweroff
36//config: commands. Code size increase of ~80 bytes.
37//config:
27//config:config FEATURE_CALL_TELINIT 38//config:config FEATURE_CALL_TELINIT
28//config: bool "Call telinit on shutdown and reboot" 39//config: bool "Call telinit on shutdown and reboot"
29//config: default y 40//config: default y
@@ -108,6 +119,47 @@ static void write_wtmp(void)
108#define write_wtmp() ((void)0) 119#define write_wtmp() ((void)0)
109#endif 120#endif
110 121
122#if ENABLE_FEATURE_WAIT_FOR_INIT
123/* In Linux, "poweroff" may be spawned even before init.
124 * For example, with ACPI:
125 * linux/drivers/acpi/bus.c:
126 * static void sb_notify_work(struct work_struct *dummy)
127 * orderly_poweroff(true);
128 * linux/kernel/reboot.c:
129 * static int run_cmd(const char *cmd)
130 * ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
131 * poweroff_cmd[] = "/sbin/poweroff";
132 * static int __orderly_poweroff(bool force)
133 * ret = run_cmd(poweroff_cmd);
134 *
135 * We want to make sure init exists and listens to signals.
136 */
137static int init_was_not_there(void)
138{
139 enum { initial = 5 }; /* 5 seconds should be plenty for timeout */
140 int cnt = initial - 1;
141
142 /* Just existence of PID 1 does not mean it installed
143 * the handlers already.
144 */
145#if 0
146 while (kill(1, 0) != 0 && --cnt >= 0)
147 sleep(1);
148#endif
149 /* ... so let's wait for some evidence a usual startup event,
150 * mounting of /proc, happened. By that time init should be ready
151 * for signals.
152 */
153 while (access("/proc/meminfo", F_OK) != 0 && --cnt >= 0)
154 sleep(1);
155
156 /* Does it look like init wasn't there? */
157 return (cnt != initial - 1);
158}
159#else
160 /* Assume it's always there */
161# define init_was_not_there() 0
162#endif
111 163
112int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 164int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
113int halt_main(int argc UNUSED_PARAM, char **argv) 165int halt_main(int argc UNUSED_PARAM, char **argv)
@@ -171,6 +223,8 @@ int halt_main(int argc UNUSED_PARAM, char **argv)
171 if (!ENABLE_FEATURE_CALL_TELINIT) { 223 if (!ENABLE_FEATURE_CALL_TELINIT) {
172 /* bbox init assumed */ 224 /* bbox init assumed */
173 rc = kill(1, signals[which]); 225 rc = kill(1, signals[which]);
226 if (init_was_not_there())
227 rc = kill(1, signals[which]);
174 } else { 228 } else {
175 /* SysV style init assumed */ 229 /* SysV style init assumed */
176 /* runlevels: 230 /* runlevels:
diff --git a/libbb/capability.c b/libbb/capability.c
index f60062bfc..6587dcbf7 100644
--- a/libbb/capability.c
+++ b/libbb/capability.c
@@ -3,7 +3,8 @@
3 * 3 *
4 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
5 */ 5 */
6//kbuild:lib-$(CONFIG_PLATFORM_LINUX) += capability.o 6//kbuild:lib-$(CONFIG_FEATURE_SETPRIV_CAPABILITIES) += capability.o
7//kbuild:lib-$(CONFIG_RUN_INIT) += capability.o
7 8
8#include <linux/capability.h> 9#include <linux/capability.h>
9// #include <sys/capability.h> 10// #include <sys/capability.h>
diff --git a/libbb/progress.c b/libbb/progress.c
index f1d980d68..23e974ce7 100644
--- a/libbb/progress.c
+++ b/libbb/progress.c
@@ -57,6 +57,9 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile)
57 p->last_update_sec = p->start_sec; 57 p->last_update_sec = p->start_sec;
58 p->last_change_sec = p->start_sec; 58 p->last_change_sec = p->start_sec;
59 p->last_size = 0; 59 p->last_size = 0;
60#if 0
61 p->last_eta = INT_MAX;
62#endif
60} 63}
61 64
62/* File already had beg_size bytes. 65/* File already had beg_size bytes.
@@ -192,6 +195,16 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p,
192 /* if 32bit, can overflow ^^^^^^^^^^, but this would only show bad ETA */ 195 /* if 32bit, can overflow ^^^^^^^^^^, but this would only show bad ETA */
193 if (eta >= 1000*60*60) 196 if (eta >= 1000*60*60)
194 eta = 1000*60*60 - 1; 197 eta = 1000*60*60 - 1;
198#if 0
199 /* To prevent annoying "back-and-forth" estimation jitter,
200 * if new ETA is larger than the last just by a few seconds,
201 * disregard it, and show last one. The end result is that
202 * ETA usually only decreases, unless download slows down a lot.
203 */
204 if ((unsigned)(eta - p->last_eta) < 10)
205 eta = p->last_eta;
206 p->last_eta = eta;
207#endif
195 secs = eta % 3600; 208 secs = eta % 3600;
196 hours = eta / 3600; 209 hours = eta / 3600;
197 fprintf(stderr, "%3u:%02u:%02u ETA", hours, secs / 60, secs % 60); 210 fprintf(stderr, "%3u:%02u:%02u ETA", hours, secs / 60, secs % 60);
diff --git a/libbb/skip_whitespace.c b/libbb/skip_whitespace.c
index 4df5d9e4d..37a24d3be 100644
--- a/libbb/skip_whitespace.c
+++ b/libbb/skip_whitespace.c
@@ -32,7 +32,6 @@ char* FAST_FUNC skip_non_whitespace(const char *s)
32 32
33char* FAST_FUNC skip_dev_pfx(const char *tty_name) 33char* FAST_FUNC skip_dev_pfx(const char *tty_name)
34{ 34{
35 if (is_prefixed_with(tty_name, "/dev/")) 35 char *unprefixed = is_prefixed_with(tty_name, "/dev/");
36 tty_name += 5; 36 return unprefixed ? unprefixed : (char*)tty_name;
37 return (char*)tty_name;
38} 37}
diff --git a/miscutils/less.c b/miscutils/less.c
index 41e4989ad..e4885db77 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -1890,7 +1890,11 @@ int less_main(int argc, char **argv)
1890 * -s: condense many empty lines to one 1890 * -s: condense many empty lines to one
1891 * (used by some setups for manpage display) 1891 * (used by some setups for manpage display)
1892 */ 1892 */
1893 getopt32(argv, "EMmN~I" IF_FEATURE_LESS_TRUNCATE("S") /*ignored:*/"s"); 1893 getopt32(argv, "EMmN~I"
1894 IF_FEATURE_LESS_TRUNCATE("S")
1895 IF_FEATURE_LESS_RAW("R")
1896 /*ignored:*/"s"
1897 );
1894 argv += optind; 1898 argv += optind;
1895 num_files = argc - optind; 1899 num_files = argc - optind;
1896 files = argv; 1900 files = argv;
diff --git a/networking/inetd.c b/networking/inetd.c
index 6843845fb..ca1a97268 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -246,7 +246,11 @@
246#if ENABLE_FEATURE_INETD_RPC 246#if ENABLE_FEATURE_INETD_RPC
247# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__) 247# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
248# warning "You probably need to build uClibc with UCLIBC_HAS_RPC for NFS support" 248# warning "You probably need to build uClibc with UCLIBC_HAS_RPC for NFS support"
249 /* not #error, since user may be using e.g. libtirpc instead */ 249 /* not #error, since user may be using e.g. libtirpc instead.
250 * This might work:
251 * CONFIG_EXTRA_CFLAGS="-I/usr/include/tirpc"
252 * CONFIG_EXTRA_LDLIBS="tirpc"
253 */
250# endif 254# endif
251# include <rpc/rpc.h> 255# include <rpc/rpc.h>
252# include <rpc/pmap_clnt.h> 256# include <rpc/pmap_clnt.h>
diff --git a/networking/ip.c b/networking/ip.c
index 0bc0edc57..accf90759 100644
--- a/networking/ip.c
+++ b/networking/ip.c
@@ -155,11 +155,61 @@
155//usage: 155//usage:
156//--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 156//--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79
157//usage:#define iplink_trivial_usage 157//usage:#define iplink_trivial_usage
158//usage: "set IFACE [up|down] [arp on|off] | show [IFACE]" 158//usage: /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n"
159//usage:#define iplink_full_usage "\n\n" 159//usage: " [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n"
160//usage: "iplink set IFACE [up|down] [arp on|off] [multicast on|off] [promisc on|off]\n" 160//usage: " [master IFACE | nomaster]\n"
161//usage: " [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n" 161// * short help shows only "set" command, long help continues (with just one "\n")
162// * and shows all other commands:
163//usage:#define iplink_full_usage "\n"
164//usage: "iplink add [link IFACE] IFACE [address MAC] type TYPE [ARGS]\n"
165//usage: "iplink delete IFACE type TYPE [ARGS]\n"
166//usage: " TYPE ARGS := vlan VLANARGS | vrf table NUM\n"
167//usage: " VLANARGS := id VLANID [protocol 802.1q|802.1ad] [reorder_hdr on|off]\n"
168//usage: " [gvrp on|off] [mvrp on|off] [loose_binding on|off]\n"
162//usage: "iplink show [IFACE]" 169//usage: "iplink show [IFACE]"
170//upstream man ip-link:
171//=====================
172//ip link add [link DEV] [ name ] NAME
173// [ txqueuelen PACKETS ]
174// [ address LLADDR ]
175// [ broadcast LLADDR ]
176// [ mtu MTU ] [index IDX ]
177// [ numtxqueues QUEUE_COUNT ]
178// [ numrxqueues QUEUE_COUNT ]
179// type TYPE [ ARGS ]
180// ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]
181// ip link set { DEVICE | dev DEVICE | group DEVGROUP } [ { up | down } ]
182// [ arp { on | off } ]
183// [ dynamic { on | off } ]
184// [ multicast { on | off } ]
185// [ allmulticast { on | off } ]
186// [ promisc { on | off } ]
187// [ trailers { on | off } ]
188// [ txqueuelen PACKETS ]
189// [ name NEWNAME ]
190// [ address LLADDR ]
191// [ broadcast LLADDR ]
192// [ mtu MTU ]
193// [ netns { PID | NAME } ]
194// [ link-netnsid ID ]
195// [ alias NAME ]
196// [ vf NUM [ mac LLADDR ]
197// [ vlan VLANID [ qos VLAN-QOS ] ]
198// [ rate TXRATE ]
199// [ spoofchk { on | off} ]
200// [ query_rss { on | off} ]
201// [ state { auto | enable | disable} ] ]
202// [ trust { on | off} ] ]
203// [ master DEVICE ]
204// [ nomaster ]
205// [ addrgenmode { eui64 | none | stable_secret | random } ]
206// [ protodown { on | off } ]
207// ip link show [ DEVICE | group GROUP ] [up] [master DEV] [type TYPE]
208// ip link help [ TYPE ]
209//TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
210// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
211// gre | gretap | ip6gre | ip6gretap | vti | nlmon |
212// bond_slave | ipvlan | geneve | bridge_slave | vrf }
163//usage: 213//usage:
164//--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 214//--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79
165//usage:#define iproute_trivial_usage 215//usage:#define iproute_trivial_usage
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c
index f38fba055..2aa8b683b 100644
--- a/networking/libiproute/iplink.c
+++ b/networking/libiproute/iplink.c
@@ -128,6 +128,31 @@ static void set_mtu(char *dev, int mtu)
128} 128}
129 129
130/* Exits on error */ 130/* Exits on error */
131static void set_master(char *dev, int master)
132{
133 struct rtnl_handle rth;
134 struct {
135 struct nlmsghdr n;
136 struct ifinfomsg i;
137 char buf[1024];
138 } req;
139
140 memset(&req, 0, sizeof(req));
141
142 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
143 req.n.nlmsg_flags = NLM_F_REQUEST;
144 req.n.nlmsg_type = RTM_NEWLINK;
145 req.i.ifi_family = preferred_family;
146
147 xrtnl_open(&rth);
148 req.i.ifi_index = xll_name_to_index(dev);
149 //printf("master %i for %i\n", master, req.i.ifi_index);
150 addattr_l(&req.n, sizeof(req), IFLA_MASTER, &master, 4);
151 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
152 xfunc_die();
153}
154
155/* Exits on error */
131static int get_address(char *dev, int *htype) 156static int get_address(char *dev, int *htype)
132{ 157{
133 struct ifreq ifr; 158 struct ifreq ifr;
@@ -200,6 +225,7 @@ static int do_set(char **argv)
200 uint32_t flags = 0; 225 uint32_t flags = 0;
201 int qlen = -1; 226 int qlen = -1;
202 int mtu = -1; 227 int mtu = -1;
228 int master = -1;
203 char *newaddr = NULL; 229 char *newaddr = NULL;
204 char *newbrd = NULL; 230 char *newbrd = NULL;
205 struct ifreq ifr0, ifr1; 231 struct ifreq ifr0, ifr1;
@@ -209,9 +235,11 @@ static int do_set(char **argv)
209 static const char keywords[] ALIGN1 = 235 static const char keywords[] ALIGN1 =
210 "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0" 236 "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0"
211 "arp\0""promisc\0""address\0" 237 "arp\0""promisc\0""address\0"
238 "master\0""nomaster\0"
212 "dev\0" /* must be last */; 239 "dev\0" /* must be last */;
213 enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast, 240 enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast,
214 ARG_arp, ARG_promisc, ARG_addr, 241 ARG_arp, ARG_promisc, ARG_addr,
242 ARG_master, ARG_nomaster,
215 ARG_dev }; 243 ARG_dev };
216 enum { PARM_on = 0, PARM_off }; 244 enum { PARM_on = 0, PARM_off };
217 smalluint key; 245 smalluint key;
@@ -243,6 +271,11 @@ static int do_set(char **argv)
243 } else if (key == ARG_addr) { 271 } else if (key == ARG_addr) {
244 NEXT_ARG(); 272 NEXT_ARG();
245 newaddr = *argv; 273 newaddr = *argv;
274 } else if (key == ARG_master) {
275 NEXT_ARG();
276 master = xll_name_to_index(*argv);
277 } else if (key == ARG_nomaster) {
278 master = 0;
246 } else if (key >= ARG_dev) { 279 } else if (key >= ARG_dev) {
247 /* ^^^^^^ ">=" here results in "dev IFACE" treated as default */ 280 /* ^^^^^^ ">=" here results in "dev IFACE" treated as default */
248 if (key == ARG_dev) { 281 if (key == ARG_dev) {
@@ -427,6 +460,9 @@ static int do_set(char **argv)
427 if (mtu != -1) { 460 if (mtu != -1) {
428 set_mtu(dev, mtu); 461 set_mtu(dev, mtu);
429 } 462 }
463 if (master != -1) {
464 set_master(dev, master);
465 }
430 if (mask) 466 if (mask)
431 do_chflags(dev, flags, mask); 467 do_chflags(dev, flags, mask);
432 return 0; 468 return 0;
@@ -525,6 +561,24 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
525 addattr_l(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags)); 561 addattr_l(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
526} 562}
527 563
564static void vrf_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
565{
566/* IFLA_VRF_TABLE is an enum, not a define -
567 * can't test "defined(IFLA_VRF_TABLE)".
568 */
569#if !defined(IFLA_VRF_MAX)
570# define IFLA_VRF_TABLE 1
571#endif
572 uint32_t table;
573
574 if (strcmp(*argv, "table") != 0)
575 invarg_1_to_2(*argv, "type vrf");
576
577 NEXT_ARG();
578 table = get_u32(*argv, "table");
579 addattr_l(n, size, IFLA_VRF_TABLE, &table, sizeof(table));
580}
581
528#ifndef NLMSG_TAIL 582#ifndef NLMSG_TAIL
529#define NLMSG_TAIL(nmsg) \ 583#define NLMSG_TAIL(nmsg) \
530 ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) 584 ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
@@ -563,6 +617,8 @@ static int do_add_or_delete(char **argv, const unsigned rtm)
563 if (rtm == RTM_NEWLINK) 617 if (rtm == RTM_NEWLINK)
564 req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; 618 req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
565 619
620 /* NB: update iplink_full_usage if you extend this code */
621
566 while (*argv) { 622 while (*argv) {
567 arg = index_in_substrings(keywords, *argv); 623 arg = index_in_substrings(keywords, *argv);
568 if (arg == ARG_type) { 624 if (arg == ARG_type) {
@@ -582,7 +638,7 @@ static int do_add_or_delete(char **argv, const unsigned rtm)
582 } else if (arg == ARG_address) { 638 } else if (arg == ARG_address) {
583 NEXT_ARG(); 639 NEXT_ARG();
584 address_str = *argv; 640 address_str = *argv;
585 dbg("address_str:'%s'", name_str); 641 dbg("address_str:'%s'", address_str);
586 } else { 642 } else {
587 if (arg == ARG_dev) { 643 if (arg == ARG_dev) {
588 if (dev_str) 644 if (dev_str)
@@ -609,6 +665,8 @@ static int do_add_or_delete(char **argv, const unsigned rtm)
609 665
610 if (strcmp(type_str, "vlan") == 0) 666 if (strcmp(type_str, "vlan") == 0)
611 vlan_parse_opt(argv, &req.n, sizeof(req)); 667 vlan_parse_opt(argv, &req.n, sizeof(req));
668 else if (strcmp(type_str, "vrf") == 0)
669 vrf_parse_opt(argv, &req.n, sizeof(req));
612 670
613 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; 671 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
614 } 672 }
@@ -651,6 +709,8 @@ int FAST_FUNC do_iplink(char **argv)
651{ 709{
652 static const char keywords[] ALIGN1 = 710 static const char keywords[] ALIGN1 =
653 "add\0""delete\0""set\0""show\0""lst\0""list\0"; 711 "add\0""delete\0""set\0""show\0""lst\0""list\0";
712
713 xfunc_error_retval = 2; //TODO: move up to "ip"? Is it the common rule for all "ip" tools?
654 if (*argv) { 714 if (*argv) {
655 int key = index_in_substrings(keywords, *argv); 715 int key = index_in_substrings(keywords, *argv);
656 if (key < 0) /* invalid argument */ 716 if (key < 0) /* invalid argument */
diff --git a/networking/ping.c b/networking/ping.c
index d1d59d545..8f85d3ec2 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -74,6 +74,7 @@
74//usage: ) 74//usage: )
75//usage: "\n -c CNT Send only CNT pings" 75//usage: "\n -c CNT Send only CNT pings"
76//usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)" 76//usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)"
77//usage: "\n -A Ping as soon as reply is recevied"
77//usage: "\n -t TTL Set TTL" 78//usage: "\n -t TTL Set TTL"
78//usage: "\n -I IFACE/IP Source interface or IP address" 79//usage: "\n -I IFACE/IP Source interface or IP address"
79//usage: "\n -W SEC Seconds to wait for the first response (default 10)" 80//usage: "\n -W SEC Seconds to wait for the first response (default 10)"
@@ -90,6 +91,7 @@
90//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" 91//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n"
91//usage: "\n -c CNT Send only CNT pings" 92//usage: "\n -c CNT Send only CNT pings"
92//usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)" 93//usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)"
94//usage: "\n -A Ping as soon as reply is recevied"
93//usage: "\n -I IFACE/IP Source interface or IP address" 95//usage: "\n -I IFACE/IP Source interface or IP address"
94//usage: "\n -q Quiet, only display output at start" 96//usage: "\n -q Quiet, only display output at start"
95//usage: "\n and when finished" 97//usage: "\n and when finished"
@@ -348,20 +350,21 @@ static int common_ping_main(sa_family_t af, char **argv)
348/* Full(er) version */ 350/* Full(er) version */
349 351
350/* -c NUM, -t NUM, -w NUM, -W NUM */ 352/* -c NUM, -t NUM, -w NUM, -W NUM */
351#define OPT_STRING "qvc:+s:t:+w:+W:+I:np:4"IF_PING6("6") 353#define OPT_STRING "qvAc:+s:t:+w:+W:+I:np:4"IF_PING6("6")
352enum { 354enum {
353 OPT_QUIET = 1 << 0, 355 OPT_QUIET = 1 << 0,
354 OPT_VERBOSE = 1 << 1, 356 OPT_VERBOSE = 1 << 1,
355 OPT_c = 1 << 2, 357 OPT_A = 1 << 2,
356 OPT_s = 1 << 3, 358 OPT_c = 1 << 3,
357 OPT_t = 1 << 4, 359 OPT_s = 1 << 4,
358 OPT_w = 1 << 5, 360 OPT_t = 1 << 5,
359 OPT_W = 1 << 6, 361 OPT_w = 1 << 6,
360 OPT_I = 1 << 7, 362 OPT_W = 1 << 7,
361 /*OPT_n = 1 << 8, - ignored */ 363 OPT_I = 1 << 8,
362 OPT_p = 1 << 9, 364 /*OPT_n = 1 << 9, - ignored */
363 OPT_IPV4 = 1 << 10, 365 OPT_p = 1 << 10,
364 OPT_IPV6 = (1 << 11) * ENABLE_PING6, 366 OPT_IPV4 = 1 << 11,
367 OPT_IPV6 = (1 << 12) * ENABLE_PING6,
365}; 368};
366 369
367 370
@@ -377,9 +380,9 @@ struct globals {
377 uint8_t pattern; 380 uint8_t pattern;
378 unsigned tmin, tmax; /* in us */ 381 unsigned tmin, tmax; /* in us */
379 unsigned long long tsum; /* in us, sum of all times */ 382 unsigned long long tsum; /* in us, sum of all times */
380 unsigned deadline; 383 unsigned cur_us; /* low word only, we don't need more */
384 unsigned deadline_us;
381 unsigned timeout; 385 unsigned timeout;
382 unsigned total_secs;
383 unsigned sizeof_rcv_packet; 386 unsigned sizeof_rcv_packet;
384 char *rcv_packet; /* [datalen + MAXIPLEN + MAXICMPLEN] */ 387 char *rcv_packet; /* [datalen + MAXIPLEN + MAXICMPLEN] */
385 void *snd_packet; /* [datalen + ipv4/ipv6_const] */ 388 void *snd_packet; /* [datalen + ipv4/ipv6_const] */
@@ -405,9 +408,7 @@ struct globals {
405#define tmin (G.tmin ) 408#define tmin (G.tmin )
406#define tmax (G.tmax ) 409#define tmax (G.tmax )
407#define tsum (G.tsum ) 410#define tsum (G.tsum )
408#define deadline (G.deadline )
409#define timeout (G.timeout ) 411#define timeout (G.timeout )
410#define total_secs (G.total_secs )
411#define hostname (G.hostname ) 412#define hostname (G.hostname )
412#define dotted (G.dotted ) 413#define dotted (G.dotted )
413#define pingaddr (G.pingaddr ) 414#define pingaddr (G.pingaddr )
@@ -455,7 +456,7 @@ static void print_stats_and_exit(int junk UNUSED_PARAM)
455 tmax / 1000, tmax % 1000); 456 tmax / 1000, tmax % 1000);
456 } 457 }
457 /* if condition is true, exit with 1 -- 'failure' */ 458 /* if condition is true, exit with 1 -- 'failure' */
458 exit(nrecv == 0 || (deadline && nrecv < pingcount)); 459 exit(nrecv == 0 || (G.deadline_us && nrecv < pingcount));
459} 460}
460 461
461static void sendping_tail(void (*sp)(int), int size_pkt) 462static void sendping_tail(void (*sp)(int), int size_pkt)
@@ -467,22 +468,23 @@ static void sendping_tail(void (*sp)(int), int size_pkt)
467 468
468 size_pkt += datalen; 469 size_pkt += datalen;
469 470
471 if (G.deadline_us) {
472 unsigned n = G.cur_us - G.deadline_us;
473 if ((int)n >= 0)
474 print_stats_and_exit(0);
475 }
476
470 /* sizeof(pingaddr) can be larger than real sa size, but I think 477 /* sizeof(pingaddr) can be larger than real sa size, but I think
471 * it doesn't matter */ 478 * it doesn't matter */
472 sz = xsendto(pingsock, G.snd_packet, size_pkt, &pingaddr.sa, sizeof(pingaddr)); 479 sz = xsendto(pingsock, G.snd_packet, size_pkt, &pingaddr.sa, sizeof(pingaddr));
473 if (sz != size_pkt) 480 if (sz != size_pkt)
474 bb_error_msg_and_die(bb_msg_write_error); 481 bb_error_msg_and_die(bb_msg_write_error);
475 482
476 if (pingcount == 0 || deadline || G.ntransmitted < pingcount) { 483 if (pingcount == 0 || G.ntransmitted < pingcount) {
477 /* Didn't send all pings yet - schedule next in 1s */ 484 /* Didn't send all pings yet - schedule next in 1s */
478 signal(SIGALRM, sp); 485 signal(SIGALRM, sp);
479 if (deadline) {
480 total_secs += PINGINTERVAL;
481 if (total_secs >= deadline)
482 signal(SIGALRM, print_stats_and_exit);
483 }
484 alarm(PINGINTERVAL); 486 alarm(PINGINTERVAL);
485 } else { /* -c NN, and all NN are sent (and no deadline) */ 487 } else { /* -c NN, and all NN are sent */
486 /* Wait for the last ping to come back. 488 /* Wait for the last ping to come back.
487 * -W timeout: wait for a response in seconds. 489 * -W timeout: wait for a response in seconds.
488 * Affects only timeout in absence of any responses, 490 * Affects only timeout in absence of any responses,
@@ -516,7 +518,7 @@ static void sendping4(int junk UNUSED_PARAM)
516 */ 518 */
517 /*if (datalen >= 4)*/ 519 /*if (datalen >= 4)*/
518 /* No hton: we'll read it back on the same machine */ 520 /* No hton: we'll read it back on the same machine */
519 *(uint32_t*)&pkt->icmp_dun = monotonic_us(); 521 *(uint32_t*)&pkt->icmp_dun = G.cur_us = monotonic_us();
520 522
521 pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, datalen + ICMP_MINLEN); 523 pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, datalen + ICMP_MINLEN);
522 524
@@ -535,7 +537,7 @@ static void sendping6(int junk UNUSED_PARAM)
535 pkt->icmp6_id = myid; 537 pkt->icmp6_id = myid;
536 538
537 /*if (datalen >= 4)*/ 539 /*if (datalen >= 4)*/
538 *(bb__aliased_uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); 540 *(bb__aliased_uint32_t*)(&pkt->icmp6_data8[4]) = G.cur_us = monotonic_us();
539 541
540 //TODO? pkt->icmp_cksum = inet_cksum(...); 542 //TODO? pkt->icmp_cksum = inet_cksum(...);
541 543
@@ -632,7 +634,7 @@ static void unpack_tail(int sz, uint32_t *tp,
632 puts(dupmsg); 634 puts(dupmsg);
633 fflush_all(); 635 fflush_all();
634} 636}
635static void unpack4(char *buf, int sz, struct sockaddr_in *from) 637static int unpack4(char *buf, int sz, struct sockaddr_in *from)
636{ 638{
637 struct icmp *icmppkt; 639 struct icmp *icmppkt;
638 struct iphdr *iphdr; 640 struct iphdr *iphdr;
@@ -640,7 +642,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from)
640 642
641 /* discard if too short */ 643 /* discard if too short */
642 if (sz < (datalen + ICMP_MINLEN)) 644 if (sz < (datalen + ICMP_MINLEN))
643 return; 645 return 0;
644 646
645 /* check IP header */ 647 /* check IP header */
646 iphdr = (struct iphdr *) buf; 648 iphdr = (struct iphdr *) buf;
@@ -648,7 +650,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from)
648 sz -= hlen; 650 sz -= hlen;
649 icmppkt = (struct icmp *) (buf + hlen); 651 icmppkt = (struct icmp *) (buf + hlen);
650 if (icmppkt->icmp_id != myid) 652 if (icmppkt->icmp_id != myid)
651 return; /* not our ping */ 653 return 0; /* not our ping */
652 654
653 if (icmppkt->icmp_type == ICMP_ECHOREPLY) { 655 if (icmppkt->icmp_type == ICMP_ECHOREPLY) {
654 uint16_t recv_seq = ntohs(icmppkt->icmp_seq); 656 uint16_t recv_seq = ntohs(icmppkt->icmp_seq);
@@ -659,25 +661,28 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from)
659 unpack_tail(sz, tp, 661 unpack_tail(sz, tp,
660 inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), 662 inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr),
661 recv_seq, iphdr->ttl); 663 recv_seq, iphdr->ttl);
662 } else if (icmppkt->icmp_type != ICMP_ECHO) { 664 return 1;
665 }
666 if (icmppkt->icmp_type != ICMP_ECHO) {
663 bb_error_msg("warning: got ICMP %d (%s)", 667 bb_error_msg("warning: got ICMP %d (%s)",
664 icmppkt->icmp_type, 668 icmppkt->icmp_type,
665 icmp_type_name(icmppkt->icmp_type)); 669 icmp_type_name(icmppkt->icmp_type));
666 } 670 }
671 return 0;
667} 672}
668#if ENABLE_PING6 673#if ENABLE_PING6
669static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit) 674static int unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
670{ 675{
671 struct icmp6_hdr *icmppkt; 676 struct icmp6_hdr *icmppkt;
672 char buf[INET6_ADDRSTRLEN]; 677 char buf[INET6_ADDRSTRLEN];
673 678
674 /* discard if too short */ 679 /* discard if too short */
675 if (sz < (datalen + sizeof(struct icmp6_hdr))) 680 if (sz < (datalen + sizeof(struct icmp6_hdr)))
676 return; 681 return 0;
677 682
678 icmppkt = (struct icmp6_hdr *) packet; 683 icmppkt = (struct icmp6_hdr *) packet;
679 if (icmppkt->icmp6_id != myid) 684 if (icmppkt->icmp6_id != myid)
680 return; /* not our ping */ 685 return 0; /* not our ping */
681 686
682 if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) { 687 if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) {
683 uint16_t recv_seq = ntohs(icmppkt->icmp6_seq); 688 uint16_t recv_seq = ntohs(icmppkt->icmp6_seq);
@@ -689,11 +694,14 @@ static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimi
689 inet_ntop(AF_INET6, &from->sin6_addr, 694 inet_ntop(AF_INET6, &from->sin6_addr,
690 buf, sizeof(buf)), 695 buf, sizeof(buf)),
691 recv_seq, hoplimit); 696 recv_seq, hoplimit);
692 } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) { 697 return 1;
698 }
699 if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) {
693 bb_error_msg("warning: got ICMP %d (%s)", 700 bb_error_msg("warning: got ICMP %d (%s)",
694 icmppkt->icmp6_type, 701 icmppkt->icmp6_type,
695 icmp6_type_name(icmppkt->icmp6_type)); 702 icmp6_type_name(icmppkt->icmp6_type));
696 } 703 }
704 return 0;
697} 705}
698#endif 706#endif
699 707
@@ -726,6 +734,7 @@ static void ping4(len_and_sockaddr *lsa)
726 signal(SIGINT, print_stats_and_exit); 734 signal(SIGINT, print_stats_and_exit);
727 735
728 /* start the ping's going ... */ 736 /* start the ping's going ... */
737 send_ping:
729 sendping4(0); 738 sendping4(0);
730 739
731 /* listen for replies */ 740 /* listen for replies */
@@ -741,9 +750,12 @@ static void ping4(len_and_sockaddr *lsa)
741 bb_perror_msg("recvfrom"); 750 bb_perror_msg("recvfrom");
742 continue; 751 continue;
743 } 752 }
744 unpack4(G.rcv_packet, c, &from); 753 c = unpack4(G.rcv_packet, c, &from);
745 if (pingcount && G.nreceived >= pingcount) 754 if (pingcount && G.nreceived >= pingcount)
746 break; 755 break;
756 if (c && (option_mask32 & OPT_A)) {
757 goto send_ping;
758 }
747 } 759 }
748} 760}
749#if ENABLE_PING6 761#if ENABLE_PING6
@@ -794,10 +806,6 @@ static void ping6(len_and_sockaddr *lsa)
794 806
795 signal(SIGINT, print_stats_and_exit); 807 signal(SIGINT, print_stats_and_exit);
796 808
797 /* start the ping's going ... */
798 sendping6(0);
799
800 /* listen for replies */
801 msg.msg_name = &from; 809 msg.msg_name = &from;
802 msg.msg_namelen = sizeof(from); 810 msg.msg_namelen = sizeof(from);
803 msg.msg_iov = &iov; 811 msg.msg_iov = &iov;
@@ -805,12 +813,18 @@ static void ping6(len_and_sockaddr *lsa)
805 msg.msg_control = control_buf; 813 msg.msg_control = control_buf;
806 iov.iov_base = G.rcv_packet; 814 iov.iov_base = G.rcv_packet;
807 iov.iov_len = G.sizeof_rcv_packet; 815 iov.iov_len = G.sizeof_rcv_packet;
816
817 /* start the ping's going ... */
818 send_ping:
819 sendping6(0);
820
821 /* listen for replies */
808 while (1) { 822 while (1) {
809 int c; 823 int c;
810 struct cmsghdr *mp; 824 struct cmsghdr *mp;
811 int hoplimit = -1; 825 int hoplimit = -1;
812 msg.msg_controllen = sizeof(control_buf);
813 826
827 msg.msg_controllen = sizeof(control_buf);
814 c = recvmsg(pingsock, &msg, 0); 828 c = recvmsg(pingsock, &msg, 0);
815 if (c < 0) { 829 if (c < 0) {
816 if (errno != EINTR) 830 if (errno != EINTR)
@@ -827,9 +841,12 @@ static void ping6(len_and_sockaddr *lsa)
827 move_from_unaligned_int(hoplimit, CMSG_DATA(mp)); 841 move_from_unaligned_int(hoplimit, CMSG_DATA(mp));
828 } 842 }
829 } 843 }
830 unpack6(G.rcv_packet, c, &from, hoplimit); 844 c = unpack6(G.rcv_packet, c, &from, hoplimit);
831 if (pingcount && G.nreceived >= pingcount) 845 if (pingcount && G.nreceived >= pingcount)
832 break; 846 break;
847 if (c && (option_mask32 & OPT_A)) {
848 goto send_ping;
849 }
833 } 850 }
834} 851}
835#endif 852#endif
@@ -875,7 +892,7 @@ static int common_ping_main(int opt, char **argv)
875 OPT_STRING 892 OPT_STRING
876 /* exactly one arg; -v and -q don't mix */ 893 /* exactly one arg; -v and -q don't mix */
877 "\0" "=1:q--v:v--q", 894 "\0" "=1:q--v:v--q",
878 &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I, &str_p 895 &pingcount, &str_s, &opt_ttl, &G.deadline_us, &timeout, &str_I, &str_p
879 ); 896 );
880 if (opt & OPT_s) 897 if (opt & OPT_s)
881 datalen = xatou16(str_s); // -s 898 datalen = xatou16(str_s); // -s
@@ -889,6 +906,10 @@ static int common_ping_main(int opt, char **argv)
889 } 906 }
890 if (opt & OPT_p) 907 if (opt & OPT_p)
891 G.pattern = xstrtou_range(str_p, 16, 0, 255); 908 G.pattern = xstrtou_range(str_p, 16, 0, 255);
909 if (G.deadline_us) {
910 unsigned d = G.deadline_us < INT_MAX/1000000 ? G.deadline_us : INT_MAX/1000000;
911 G.deadline_us = 1 | ((d * 1000000) + monotonic_us());
912 }
892 913
893 myid = (uint16_t) getpid(); 914 myid = (uint16_t) getpid();
894 hostname = argv[optind]; 915 hostname = argv[optind];
@@ -911,7 +932,7 @@ static int common_ping_main(int opt, char **argv)
911 932
912 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa); 933 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
913 ping(lsa); 934 ping(lsa);
914 print_stats_and_exit(EXIT_SUCCESS); 935 print_stats_and_exit(0);
915 /*return EXIT_SUCCESS;*/ 936 /*return EXIT_SUCCESS;*/
916} 937}
917#endif /* FEATURE_FANCY_PING */ 938#endif /* FEATURE_FANCY_PING */
diff --git a/networking/tcpudp.c b/networking/tcpudp.c
index d4c69e0f7..a90e3f80a 100644
--- a/networking/tcpudp.c
+++ b/networking/tcpudp.c
@@ -127,6 +127,7 @@ struct globals {
127 unsigned cur_per_host; 127 unsigned cur_per_host;
128 unsigned cnum; 128 unsigned cnum;
129 unsigned cmax; 129 unsigned cmax;
130 struct hcc *cc;
130 char **env_cur; 131 char **env_cur;
131 char *env_var[1]; /* actually bigger */ 132 char *env_var[1]; /* actually bigger */
132} FIX_ALIASING; 133} FIX_ALIASING;
@@ -229,7 +230,7 @@ static void sig_child_handler(int sig UNUSED_PARAM)
229 230
230 while ((pid = wait_any_nohang(&wstat)) > 0) { 231 while ((pid = wait_any_nohang(&wstat)) > 0) {
231 if (max_per_host) 232 if (max_per_host)
232 ipsvd_perhost_remove(pid); 233 ipsvd_perhost_remove(G.cc, pid);
233 if (cnum) 234 if (cnum)
234 cnum--; 235 cnum--;
235 if (verbose) 236 if (verbose)
@@ -318,7 +319,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv)
318 sslser = user; 319 sslser = user;
319 client = 0; 320 client = 0;
320 if ((getuid() == 0) && !(opts & OPT_u)) { 321 if ((getuid() == 0) && !(opts & OPT_u)) {
321 xfunc_exitcode = 100; 322 xfunc_error_retval = 100;
322 bb_error_msg_and_die(bb_msg_you_must_be_root); 323 bb_error_msg_and_die(bb_msg_you_must_be_root);
323 } 324 }
324 if (opts & OPT_u) 325 if (opts & OPT_u)
@@ -347,7 +348,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv)
347 signal(SIGPIPE, SIG_IGN); 348 signal(SIGPIPE, SIG_IGN);
348 349
349 if (max_per_host) 350 if (max_per_host)
350 ipsvd_perhost_init(cmax); 351 G.cc = ipsvd_perhost_init(cmax);
351 352
352 local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0); 353 local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0);
353 lsa = xhost2sockaddr(argv[0], local_port); 354 lsa = xhost2sockaddr(argv[0], local_port);
@@ -422,7 +423,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv)
422 /* Drop connection immediately if cur_per_host > max_per_host 423 /* Drop connection immediately if cur_per_host > max_per_host
423 * (minimizing load under SYN flood) */ 424 * (minimizing load under SYN flood) */
424 remote_addr = xmalloc_sockaddr2dotted_noport(&remote.u.sa); 425 remote_addr = xmalloc_sockaddr2dotted_noport(&remote.u.sa);
425 cur_per_host = ipsvd_perhost_add(remote_addr, max_per_host, &hccp); 426 cur_per_host = ipsvd_perhost_add(G.cc, remote_addr, max_per_host, &hccp);
426 if (cur_per_host > max_per_host) { 427 if (cur_per_host > max_per_host) {
427 /* ipsvd_perhost_add detected that max is exceeded 428 /* ipsvd_perhost_add detected that max is exceeded
428 * (and did not store ip in connection table) */ 429 * (and did not store ip in connection table) */
diff --git a/networking/tcpudp_perhost.c b/networking/tcpudp_perhost.c
index 105410883..2643f8d16 100644
--- a/networking/tcpudp_perhost.c
+++ b/networking/tcpudp_perhost.c
@@ -10,25 +10,21 @@
10#include "libbb.h" 10#include "libbb.h"
11#include "tcpudp_perhost.h" 11#include "tcpudp_perhost.h"
12 12
13static struct hcc *cc; 13struct hcc* FAST_FUNC ipsvd_perhost_init(unsigned c)
14static unsigned cclen;
15
16/* to be optimized */
17
18void ipsvd_perhost_init(unsigned c)
19{ 14{
20// free(cc); 15// free(cc);
21 cc = xzalloc(c * sizeof(*cc)); 16 struct hcc *cc = xzalloc((c + 1) * sizeof(*cc));
22 cclen = c; 17 cc[c].pid = -1; /* "end" marker */
18 return cc;
23} 19}
24 20
25unsigned ipsvd_perhost_add(char *ip, unsigned maxconn, struct hcc **hccpp) 21unsigned FAST_FUNC ipsvd_perhost_add(struct hcc *cc, char *ip, unsigned maxconn, struct hcc **hccpp)
26{ 22{
27 unsigned i; 23 unsigned i;
28 unsigned conn = 1; 24 unsigned conn = 1;
29 int freepos = -1; 25 int freepos = -1;
30 26
31 for (i = 0; i < cclen; ++i) { 27 for (i = 0; cc[i].pid >= 0; ++i) {
32 if (!cc[i].ip) { 28 if (!cc[i].ip) {
33 freepos = i; 29 freepos = i;
34 continue; 30 continue;
@@ -46,10 +42,10 @@ unsigned ipsvd_perhost_add(char *ip, unsigned maxconn, struct hcc **hccpp)
46 return conn; 42 return conn;
47} 43}
48 44
49void ipsvd_perhost_remove(int pid) 45void FAST_FUNC ipsvd_perhost_remove(struct hcc *cc, int pid)
50{ 46{
51 unsigned i; 47 unsigned i;
52 for (i = 0; i < cclen; ++i) { 48 for (i = 0; cc[i].pid >= 0; ++i) {
53 if (cc[i].pid == pid) { 49 if (cc[i].pid == pid) {
54 free(cc[i].ip); 50 free(cc[i].ip);
55 cc[i].ip = NULL; 51 cc[i].ip = NULL;
@@ -59,7 +55,7 @@ void ipsvd_perhost_remove(int pid)
59 } 55 }
60} 56}
61 57
62//void ipsvd_perhost_free(void) 58//void ipsvd_perhost_free(struct hcc *cc)
63//{ 59//{
64// free(cc); 60// free(cc);
65//} 61//}
diff --git a/networking/tcpudp_perhost.h b/networking/tcpudp_perhost.h
index 3e5757678..3b14d9a57 100644
--- a/networking/tcpudp_perhost.h
+++ b/networking/tcpudp_perhost.h
@@ -14,7 +14,7 @@ struct hcc {
14 int pid; 14 int pid;
15}; 15};
16 16
17void ipsvd_perhost_init(unsigned); 17struct hcc* FAST_FUNC ipsvd_perhost_init(unsigned);
18 18
19/* Returns number of already opened connects to this ips, including this one. 19/* Returns number of already opened connects to this ips, including this one.
20 * ip should be a malloc'ed ptr. 20 * ip should be a malloc'ed ptr.
@@ -22,12 +22,12 @@ void ipsvd_perhost_init(unsigned);
22 * and pointer to table entry if stored in *hccpp 22 * and pointer to table entry if stored in *hccpp
23 * (useful for storing pid later). 23 * (useful for storing pid later).
24 * Else ip is NOT inserted (you must take care of it - free() etc) */ 24 * Else ip is NOT inserted (you must take care of it - free() etc) */
25unsigned ipsvd_perhost_add(char *ip, unsigned maxconn, struct hcc **hccpp); 25unsigned FAST_FUNC ipsvd_perhost_add(struct hcc *cc, char *ip, unsigned maxconn, struct hcc **hccpp);
26 26
27/* Finds and frees element with pid */ 27/* Finds and frees element with pid */
28void ipsvd_perhost_remove(int pid); 28void FAST_FUNC ipsvd_perhost_remove(struct hcc *cc, int pid);
29 29
30//unsigned ipsvd_perhost_setpid(int pid); 30//unsigned ipsvd_perhost_setpid(int pid);
31//void ipsvd_perhost_free(void); 31//void ipsvd_perhost_free(struct hcc *cc);
32 32
33POP_SAVED_FUNCTION_VISIBILITY 33POP_SAVED_FUNCTION_VISIBILITY
diff --git a/networking/tls.c b/networking/tls.c
index da7b6058f..99722cfb4 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -806,8 +806,6 @@ static int tls_xread_record(tls_state_t *tls, const char *expected)
806 || xhdr->proto_min != TLS_MIN 806 || xhdr->proto_min != TLS_MIN
807 ) { 807 ) {
808 sz = total < target ? total : target; 808 sz = total < target ? total : target;
809 if (sz > 24)
810 sz = 24; /* don't flood */
811 bad_record_die(tls, expected, sz); 809 bad_record_die(tls, expected, sz);
812 } 810 }
813 dbg("xhdr type:%d ver:%d.%d len:%d\n", 811 dbg("xhdr type:%d ver:%d.%d len:%d\n",
diff --git a/shell/ash.c b/shell/ash.c
index 88834f49a..394022df9 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6517,12 +6517,12 @@ rmescapes(char *str, int flag, int *slash_position)
6517 if (*p == '*' 6517 if (*p == '*'
6518 || *p == '?' 6518 || *p == '?'
6519 || *p == '[' 6519 || *p == '['
6520 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */ 6520 || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
6521 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */ 6521 || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
6522 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */ 6522 || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
6523 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */ 6523 || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
6524 /* Some libc support [^negate], that's why "^" also needs love */ 6524 /* Some libc support [^negate], that's why "^" also needs love */
6525 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */ 6525 || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
6526 ) { 6526 ) {
6527 *q++ = '\\'; 6527 *q++ = '\\';
6528 } 6528 }
@@ -12512,13 +12512,24 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
12512 USTPUTC(CTLESC, out); 12512 USTPUTC(CTLESC, out);
12513 USTPUTC('\\', out); 12513 USTPUTC('\\', out);
12514 } 12514 }
12515 /* Backslash is retained if we are in "str" and next char isn't special */ 12515 /* Backslash is retained if we are in "str"
12516 * and next char isn't dquote-special.
12517 */
12516 if (dblquote 12518 if (dblquote
12517 && c != '\\' 12519 && c != '\\'
12518 && c != '`' 12520 && c != '`'
12519 && c != '$' 12521 && c != '$'
12520 && (c != '"' || eofmark != NULL) 12522 && (c != '"' || eofmark != NULL)
12521 ) { 12523 ) {
12524//dash survives not doing USTPUTC(CTLESC), but merely by chance:
12525//Example: "\z" gets encoded as "\<CTLESC>z".
12526//rmescapes() then emits "\", "\z", protecting z from globbing.
12527//But it's wrong, should protect _both_ from globbing:
12528//everything in double quotes is not globbed.
12529//Unlike dash, we have a fix in rmescapes() which emits bare "z"
12530//for "<CTLESC>z" since "z" is not glob-special (else unicode may break),
12531//and glob would see "\z" and eat "\". Thus:
12532 USTPUTC(CTLESC, out); /* protect '\' from glob */
12522 USTPUTC('\\', out); 12533 USTPUTC('\\', out);
12523 } 12534 }
12524 USTPUTC(CTLESC, out); 12535 USTPUTC(CTLESC, out);
diff --git a/shell/ash_test/ash-quoting/bkslash_case1.right b/shell/ash_test/ash-quoting/bkslash_case1.right
new file mode 100644
index 000000000..1b52491f7
--- /dev/null
+++ b/shell/ash_test/ash-quoting/bkslash_case1.right
@@ -0,0 +1,10 @@
1ok1
2ok2
3ok3
4ok4
5ok5
6Ok:0
7ok6
8ok7
9ok8
10Ok:0
diff --git a/shell/ash_test/ash-quoting/bkslash_case1.tests b/shell/ash_test/ash-quoting/bkslash_case1.tests
new file mode 100755
index 000000000..d0c359927
--- /dev/null
+++ b/shell/ash_test/ash-quoting/bkslash_case1.tests
@@ -0,0 +1,38 @@
1# Case argument is globbed, match patterns are not.
2# This caught some bugs in the past.
3
4case z in
5\z ) echo ok1 ;;
6* ) echo BUG ;;
7esac
8case \z in
9z ) echo ok2 ;;
10* ) echo BUG ;;
11esac
12case \z in
13\z ) echo ok3 ;;
14* ) echo BUG ;;
15esac
16case z in
17\z ) echo ok4 ;;
18* ) echo BUG ;;
19esac
20case \\z in
21\\z ) echo ok5 ;;
22* ) echo BUG ;;
23esac
24echo Ok:$?
25
26case "\z" in
27"\z" ) echo ok6 ;;
28* ) echo BUG ;;
29esac
30case "\\z" in
31"\\z" ) echo ok7 ;;
32* ) echo BUG ;;
33esac
34case "\\\z" in
35"\\\z") echo ok8 ;;
36* ) echo BUG ;;
37esac
38echo Ok:$?
diff --git a/shell/hush.c b/shell/hush.c
index 8f1017e3c..e005b0a20 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -6614,24 +6614,22 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger)
6614static void parse_and_run_string(const char *s) 6614static void parse_and_run_string(const char *s)
6615{ 6615{
6616 struct in_str input; 6616 struct in_str input;
6617 //IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;)
6618
6617 setup_string_in_str(&input, s); 6619 setup_string_in_str(&input, s);
6618 parse_and_run_stream(&input, '\0'); 6620 parse_and_run_stream(&input, '\0');
6621 //IF_HUSH_LINENO_VAR(G.lineno = sv;)
6619} 6622}
6620 6623
6621static void parse_and_run_file(FILE *f) 6624static void parse_and_run_file(FILE *f)
6622{ 6625{
6623 struct in_str input; 6626 struct in_str input;
6624#if ENABLE_HUSH_LINENO_VAR 6627 IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;)
6625 unsigned sv;
6626 6628
6627 sv = G.lineno; 6629 IF_HUSH_LINENO_VAR(G.lineno = 1;)
6628 G.lineno = 1;
6629#endif
6630 setup_file_in_str(&input, f); 6630 setup_file_in_str(&input, f);
6631 parse_and_run_stream(&input, ';'); 6631 parse_and_run_stream(&input, ';');
6632#if ENABLE_HUSH_LINENO_VAR 6632 IF_HUSH_LINENO_VAR(G.lineno = sv;)
6633 G.lineno = sv;
6634#endif
6635} 6633}
6636 6634
6637#if ENABLE_HUSH_TICK 6635#if ENABLE_HUSH_TICK
@@ -6744,16 +6742,16 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p)
6744static int process_command_subs(o_string *dest, const char *s) 6742static int process_command_subs(o_string *dest, const char *s)
6745{ 6743{
6746 FILE *fp; 6744 FILE *fp;
6747 struct in_str pipe_str;
6748 pid_t pid; 6745 pid_t pid;
6749 int status, ch, eol_cnt; 6746 int status, ch, eol_cnt;
6750 6747
6751 fp = generate_stream_from_string(s, &pid); 6748 fp = generate_stream_from_string(s, &pid);
6752 6749
6753 /* Now send results of command back into original context */ 6750 /* Now send results of command back into original context */
6754 setup_file_in_str(&pipe_str, fp);
6755 eol_cnt = 0; 6751 eol_cnt = 0;
6756 while ((ch = i_getch(&pipe_str)) != EOF) { 6752 while ((ch = getc(fp)) != EOF) {
6753 if (ch == '\0')
6754 continue;
6757 if (ch == '\n') { 6755 if (ch == '\n') {
6758 eol_cnt++; 6756 eol_cnt++;
6759 continue; 6757 continue;
diff --git a/shell/hush_test/hush-quoting/bkslash_case1.right b/shell/hush_test/hush-quoting/bkslash_case1.right
new file mode 100644
index 000000000..1b52491f7
--- /dev/null
+++ b/shell/hush_test/hush-quoting/bkslash_case1.right
@@ -0,0 +1,10 @@
1ok1
2ok2
3ok3
4ok4
5ok5
6Ok:0
7ok6
8ok7
9ok8
10Ok:0
diff --git a/shell/hush_test/hush-quoting/bkslash_case1.tests b/shell/hush_test/hush-quoting/bkslash_case1.tests
new file mode 100755
index 000000000..d0c359927
--- /dev/null
+++ b/shell/hush_test/hush-quoting/bkslash_case1.tests
@@ -0,0 +1,38 @@
1# Case argument is globbed, match patterns are not.
2# This caught some bugs in the past.
3
4case z in
5\z ) echo ok1 ;;
6* ) echo BUG ;;
7esac
8case \z in
9z ) echo ok2 ;;
10* ) echo BUG ;;
11esac
12case \z in
13\z ) echo ok3 ;;
14* ) echo BUG ;;
15esac
16case z in
17\z ) echo ok4 ;;
18* ) echo BUG ;;
19esac
20case \\z in
21\\z ) echo ok5 ;;
22* ) echo BUG ;;
23esac
24echo Ok:$?
25
26case "\z" in
27"\z" ) echo ok6 ;;
28* ) echo BUG ;;
29esac
30case "\\z" in
31"\\z" ) echo ok7 ;;
32* ) echo BUG ;;
33esac
34case "\\\z" in
35"\\\z") echo ok8 ;;
36* ) echo BUG ;;
37esac
38echo Ok:$?
diff --git a/testsuite/tar.tests b/testsuite/tar.tests
index b7cd74ca5..1675b07b1 100755
--- a/testsuite/tar.tests
+++ b/testsuite/tar.tests
@@ -279,7 +279,7 @@ optional UUDECODE FEATURE_TAR_AUTODETECT FEATURE_SEAMLESS_BZ2
279testing "tar does not extract into symlinks" "\ 279testing "tar does not extract into symlinks" "\
280>>/tmp/passwd && uudecode -o input && tar xf input 2>&1 && rm passwd; cat /tmp/passwd; echo \$? 280>>/tmp/passwd && uudecode -o input && tar xf input 2>&1 && rm passwd; cat /tmp/passwd; echo \$?
281" "\ 281" "\
282tar: skipping unsafe symlink to '/tmp/passwd' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract 282tar: can't create symlink 'passwd' to '/tmp/passwd'
2830 2830
284" \ 284" \
285"" "\ 285"" "\
@@ -299,7 +299,7 @@ optional UUDECODE FEATURE_TAR_AUTODETECT FEATURE_SEAMLESS_BZ2
299testing "tar -k does not extract into symlinks" "\ 299testing "tar -k does not extract into symlinks" "\
300>>/tmp/passwd && uudecode -o input && tar xf input -k 2>&1 && rm passwd; cat /tmp/passwd; echo \$? 300>>/tmp/passwd && uudecode -o input && tar xf input -k 2>&1 && rm passwd; cat /tmp/passwd; echo \$?
301" "\ 301" "\
302tar: skipping unsafe symlink to '/tmp/passwd' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract 302tar: can't create symlink 'passwd' to '/tmp/passwd'
3030 3030
304" \ 304" \
305"" "\ 305"" "\
@@ -324,11 +324,11 @@ rm -rf etc usr
324' "\ 324' "\
325etc/ssl/certs/3b2716e5.0 325etc/ssl/certs/3b2716e5.0
326etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem 326etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem
327tar: skipping unsafe symlink to '/usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract
328etc/ssl/certs/f80cc7f6.0 327etc/ssl/certs/f80cc7f6.0
329usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt 328usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt
3300 3290
331etc/ssl/certs/3b2716e5.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem 330etc/ssl/certs/3b2716e5.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem
331etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem -> /usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt
332etc/ssl/certs/f80cc7f6.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem 332etc/ssl/certs/f80cc7f6.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem
333" \ 333" \
334"" "" 334"" ""
@@ -346,9 +346,9 @@ ls symlink/bb_test_evilfile
346' "\ 346' "\
347anything.txt 347anything.txt
348symlink 348symlink
349tar: skipping unsafe symlink to '/tmp' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract
350symlink/bb_test_evilfile 349symlink/bb_test_evilfile
3510 350tar: can't create symlink 'symlink' to '/tmp'
3511
352ls: /tmp/bb_test_evilfile: No such file or directory 352ls: /tmp/bb_test_evilfile: No such file or directory
353ls: bb_test_evilfile: No such file or directory 353ls: bb_test_evilfile: No such file or directory
354symlink/bb_test_evilfile 354symlink/bb_test_evilfile
diff --git a/util-linux/mkfs_ext2.c b/util-linux/mkfs_ext2.c
index 8434dd6ad..f524bc239 100644
--- a/util-linux/mkfs_ext2.c
+++ b/util-linux/mkfs_ext2.c
@@ -83,11 +83,11 @@ char BUG_wrong_field_size(void);
83#define STORE_LE(field, value) \ 83#define STORE_LE(field, value) \
84do { \ 84do { \
85 if (sizeof(field) == 4) \ 85 if (sizeof(field) == 4) \
86 field = SWAP_LE32(value); \ 86 field = SWAP_LE32((uint32_t)(value)); \
87 else if (sizeof(field) == 2) \ 87 else if (sizeof(field) == 2) \
88 field = SWAP_LE16(value); \ 88 field = SWAP_LE16((uint16_t)(value)); \
89 else if (sizeof(field) == 1) \ 89 else if (sizeof(field) == 1) \
90 field = (value); \ 90 field = (uint8_t)(value); \
91 else \ 91 else \
92 BUG_wrong_field_size(); \ 92 BUG_wrong_field_size(); \
93} while (0) 93} while (0)
diff --git a/util-linux/mkfs_vfat.c b/util-linux/mkfs_vfat.c
index 426854b1e..26a919536 100644
--- a/util-linux/mkfs_vfat.c
+++ b/util-linux/mkfs_vfat.c
@@ -210,11 +210,11 @@ void BUG_unsupported_field_size(void);
210#define STORE_LE(field, value) \ 210#define STORE_LE(field, value) \
211do { \ 211do { \
212 if (sizeof(field) == 4) \ 212 if (sizeof(field) == 4) \
213 field = SWAP_LE32(value); \ 213 field = SWAP_LE32((uint32_t)(value)); \
214 else if (sizeof(field) == 2) \ 214 else if (sizeof(field) == 2) \
215 field = SWAP_LE16(value); \ 215 field = SWAP_LE16((uint16_t)(value)); \
216 else if (sizeof(field) == 1) \ 216 else if (sizeof(field) == 1) \
217 field = (value); \ 217 field = (uint8_t)(value); \
218 else \ 218 else \
219 BUG_unsupported_field_size(); \ 219 BUG_unsupported_field_size(); \
220} while (0) 220} while (0)
diff --git a/util-linux/mount.c b/util-linux/mount.c
index 4eade0869..fa2e7b114 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -244,7 +244,11 @@
244 * uclibc faq entry rather than in busybox... */ 244 * uclibc faq entry rather than in busybox... */
245# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__) 245# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
246# warning "You probably need to build uClibc with UCLIBC_HAS_RPC for NFS support" 246# warning "You probably need to build uClibc with UCLIBC_HAS_RPC for NFS support"
247 /* not #error, since user may be using e.g. libtirpc instead */ 247 /* not #error, since user may be using e.g. libtirpc instead.
248 * This might work:
249 * CONFIG_EXTRA_CFLAGS="-I/usr/include/tirpc"
250 * CONFIG_EXTRA_LDLIBS="tirpc"
251 */
248# endif 252# endif
249# include <rpc/rpc.h> 253# include <rpc/rpc.h>
250# include <rpc/pmap_prot.h> 254# include <rpc/pmap_prot.h>
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c
index 2d1802b79..947dd0cdc 100644
--- a/util-linux/switch_root.c
+++ b/util-linux/switch_root.c
@@ -39,6 +39,12 @@
39#include <sys/mount.h> 39#include <sys/mount.h>
40#if ENABLE_RUN_INIT 40#if ENABLE_RUN_INIT
41# include <sys/prctl.h> 41# include <sys/prctl.h>
42# ifndef PR_CAPBSET_READ
43# define PR_CAPBSET_READ 23
44# endif
45# ifndef PR_CAPBSET_DROP
46# define PR_CAPBSET_DROP 24
47# endif
42# include <linux/capability.h> 48# include <linux/capability.h>
43// #include <sys/capability.h> 49// #include <sys/capability.h>
44// This header is in libcap, but the functions are in libc. 50// This header is in libcap, but the functions are in libc.
diff --git a/util-linux/umount.c b/util-linux/umount.c
index b45cd8a6b..e2329f8b3 100644
--- a/util-linux/umount.c
+++ b/util-linux/umount.c
@@ -57,6 +57,7 @@
57//usage: IF_FEATURE_MOUNT_LOOP( 57//usage: IF_FEATURE_MOUNT_LOOP(
58//usage: "\n -d Free loop device if it has been used" 58//usage: "\n -d Free loop device if it has been used"
59//usage: ) 59//usage: )
60//usage: "\n -t FSTYPE[,...] Unmount only these filesystem type(s)"
60//usage: 61//usage:
61//usage:#define umount_example_usage 62//usage:#define umount_example_usage
62//usage: "$ umount /dev/hdc1\n" 63//usage: "$ umount /dev/hdc1\n"
@@ -81,8 +82,8 @@ static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
81} 82}
82#endif 83#endif
83 84
84/* ignored: -c -v -t -i */ 85/* ignored: -c -v -i */
85#define OPTION_STRING "fldnra" "cvt:i" 86#define OPTION_STRING "fldnrat:" "cvi"
86#define OPT_FORCE (1 << 0) // Same as MNT_FORCE 87#define OPT_FORCE (1 << 0) // Same as MNT_FORCE
87#define OPT_LAZY (1 << 1) // Same as MNT_DETACH 88#define OPT_LAZY (1 << 1) // Same as MNT_DETACH
88#define OPT_FREELOOP (1 << 2) 89#define OPT_FREELOOP (1 << 2)
@@ -143,7 +144,8 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
143 } 144 }
144 145
145 // If we're not umounting all, we need at least one argument. 146 // If we're not umounting all, we need at least one argument.
146 if (!(opt & OPT_ALL) && !fstype) { 147 // Note: "-t FSTYPE" does not imply -a.
148 if (!(opt & OPT_ALL)) {
147 if (!argv[0]) 149 if (!argv[0])
148 bb_show_usage(); 150 bb_show_usage();
149 m = NULL; 151 m = NULL;