aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-01-14 13:28:49 +0000
committerRon Yorston <rmy@pobox.com>2021-01-14 13:28:49 +0000
commit89963b524d211e1aec12b72b3725be05ee95c8cf (patch)
tree48590aef62b7ee7686b7898256f29def8d9c50b9
parent9aa5a829070392c2ac6494d0c4e674c0c2bc7dab (diff)
parent2b7c1aa92c68524559a2067609d09309d5c09adc (diff)
downloadbusybox-w32-89963b524d211e1aec12b72b3725be05ee95c8cf.tar.gz
busybox-w32-89963b524d211e1aec12b72b3725be05ee95c8cf.tar.bz2
busybox-w32-89963b524d211e1aec12b72b3725be05ee95c8cf.zip
Merge branch 'busybox' into merge
-rw-r--r--Config.in8
-rw-r--r--Makefile2
-rw-r--r--Makefile.flags5
-rw-r--r--applets/applet_tables.c4
-rw-r--r--arch/i386/Makefile8
-rw-r--r--arch/x86_64/Makefile11
-rw-r--r--archival/ar.c61
-rw-r--r--archival/bbunzip.c10
-rw-r--r--archival/bzip2.c2
-rw-r--r--archival/cpio.c2
-rw-r--r--archival/dpkg.c2
-rw-r--r--archival/dpkg_deb.c2
-rw-r--r--archival/libarchive/bz/blocksort.c2
-rw-r--r--archival/libarchive/data_extract_all.c4
-rw-r--r--archival/libarchive/data_extract_to_command.c2
-rw-r--r--archival/libarchive/decompress_gunzip.c4
-rw-r--r--archival/libarchive/get_header_ar.c2
-rw-r--r--archival/libarchive/unpack_ar_archive.c2
-rw-r--r--archival/rpm.c12
-rw-r--r--archival/tar.c27
-rw-r--r--configs/mingw32_defconfig8
-rw-r--r--configs/mingw64_defconfig8
-rw-r--r--coreutils/cp.c2
-rw-r--r--coreutils/date.c102
-rw-r--r--coreutils/dd.c116
-rw-r--r--coreutils/factor.c209
-rw-r--r--coreutils/id.c2
-rw-r--r--coreutils/ln.c4
-rw-r--r--coreutils/md5_sha1_sum.c2
-rw-r--r--coreutils/mkdir.c2
-rw-r--r--coreutils/mknod.c4
-rw-r--r--coreutils/nl.c2
-rw-r--r--coreutils/od_bloaty.c4
-rw-r--r--coreutils/paste.c2
-rw-r--r--coreutils/rmdir.c2
-rw-r--r--coreutils/sort.c2
-rw-r--r--coreutils/split.c2
-rw-r--r--coreutils/stat.c4
-rw-r--r--coreutils/stty.c4
-rw-r--r--coreutils/test.c2
-rw-r--r--coreutils/timeout.c4
-rw-r--r--coreutils/uniq.c2
-rw-r--r--coreutils/uudecode.c162
-rw-r--r--debianutils/which.c4
-rw-r--r--e2fsprogs/e2fs_lib.c2
-rw-r--r--e2fsprogs/fsck.c2
-rw-r--r--editors/awk.c54
-rw-r--r--editors/patch.c2
-rw-r--r--editors/vi.c2
-rw-r--r--examples/inetd.conf2
-rwxr-xr-xexamples/udhcp/sample.bound8
-rwxr-xr-xexamples/udhcp/sample.deconfig2
-rwxr-xr-xexamples/udhcp/sample.renew8
-rw-r--r--findutils/find.c4
-rw-r--r--include/ar_.h (renamed from include/ar.h)0
-rw-r--r--include/libbb.h78
-rw-r--r--include/mingw.h1
-rw-r--r--include/platform.h4
-rw-r--r--include/rtc_.h6
-rw-r--r--include/usage.src.h6
-rw-r--r--init/bootchartd.c10
-rw-r--r--init/halt.c10
-rw-r--r--init/init.c12
-rw-r--r--klibc-utils/nuke.c2
-rw-r--r--libbb/bb_do_delay.c59
-rw-r--r--libbb/capability.c2
-rw-r--r--libbb/copyfd.c5
-rw-r--r--libbb/die_if_bad_username.c4
-rw-r--r--libbb/duration.c2
-rw-r--r--libbb/executable.c9
-rw-r--r--libbb/hash_md5_sha.c22
-rw-r--r--libbb/lineedit.c129
-rw-r--r--libbb/loop.c139
-rw-r--r--libbb/mode_string.c2
-rw-r--r--libbb/platform.c4
-rw-r--r--libbb/procps.c51
-rw-r--r--libbb/pw_encrypt.c15
-rw-r--r--libbb/pw_encrypt_des.c40
-rw-r--r--libbb/rtc.c6
-rw-r--r--libbb/run_shell.c32
-rw-r--r--libbb/speed_table.c2
-rw-r--r--libbb/time.c13
-rw-r--r--libbb/unicode.c22
-rw-r--r--libbb/uuencode.c235
-rw-r--r--libbb/xatonum.c6
-rw-r--r--libbb/xconnect.c20
-rw-r--r--libbb/xfuncs.c12
-rw-r--r--libbb/xfuncs_printf.c71
-rw-r--r--loginutils/chpasswd.c10
-rw-r--r--loginutils/cryptpw.c10
-rw-r--r--loginutils/getty.c8
-rw-r--r--loginutils/login.c18
-rw-r--r--loginutils/passwd.c4
-rw-r--r--loginutils/su.c4
-rw-r--r--loginutils/sulogin.c4
-rw-r--r--loginutils/vlock.c2
-rw-r--r--mailutils/mail.c88
-rw-r--r--mailutils/mail.h5
-rw-r--r--mailutils/makemime.c1
-rw-r--r--mailutils/popmaildir.c6
-rw-r--r--mailutils/reformime.c5
-rw-r--r--mailutils/sendmail.c16
-rw-r--r--miscutils/adjtimex.c2
-rw-r--r--miscutils/bc.c111
-rw-r--r--miscutils/beep.c4
-rw-r--r--miscutils/chat.c6
-rw-r--r--miscutils/crond.c4
-rw-r--r--miscutils/dc.c4
-rw-r--r--miscutils/devfsd.c4
-rw-r--r--miscutils/devmem.c2
-rw-r--r--miscutils/hdparm.c6
-rw-r--r--miscutils/hexedit.c14
-rw-r--r--miscutils/i2c_tools.c31
-rw-r--r--miscutils/man.c41
-rw-r--r--miscutils/mt.c4
-rw-r--r--miscutils/setserial.c3
-rw-r--r--miscutils/time.c7
-rw-r--r--miscutils/ts.c4
-rw-r--r--miscutils/ubi_tools.c2
-rw-r--r--miscutils/watchdog.c4
-rw-r--r--modutils/insmod.c2
-rw-r--r--modutils/modinfo.c2
-rw-r--r--modutils/modprobe-small.c8
-rw-r--r--modutils/modprobe.c19
-rw-r--r--modutils/modutils.c2
-rw-r--r--networking/ftpgetput.c4
-rw-r--r--networking/hostname.c4
-rw-r--r--networking/httpd.c54
-rw-r--r--networking/ifconfig.c6
-rw-r--r--networking/ifplugd.c4
-rw-r--r--networking/ifupdown.c20
-rw-r--r--networking/inetd.c8
-rw-r--r--networking/interface.c2
-rw-r--r--networking/ip.c2
-rw-r--r--networking/ipcalc.c2
-rw-r--r--networking/libiproute/ipaddress.c11
-rw-r--r--networking/libiproute/rt_names.c2
-rw-r--r--networking/libiproute/rtm_map.c53
-rw-r--r--networking/nbd-client.c2
-rw-r--r--networking/nc_bloaty.c2
-rw-r--r--networking/netstat.c2
-rw-r--r--networking/nslookup.c34
-rw-r--r--networking/ntpd.c19
-rw-r--r--networking/ping.c81
-rw-r--r--networking/pscan.c12
-rw-r--r--networking/route.c84
-rw-r--r--networking/slattach.c2
-rw-r--r--networking/telnet.c6
-rw-r--r--networking/tftp.c4
-rw-r--r--networking/tls.c2
-rw-r--r--networking/tls_aes.c6
-rw-r--r--networking/tls_fe.c28
-rw-r--r--networking/traceroute.c871
-rw-r--r--networking/tunctl.c16
-rw-r--r--networking/udhcp/Config.src8
-rw-r--r--networking/udhcp/common.h3
-rw-r--r--networking/udhcp/d6_common.h10
-rw-r--r--networking/udhcp/d6_dhcpc.c23
-rw-r--r--networking/udhcp/d6_packet.c19
-rw-r--r--networking/udhcp/dhcpc.c7
-rw-r--r--networking/udhcp/dhcpd.c9
-rw-r--r--networking/udhcp/dumpleases.c8
-rw-r--r--networking/udhcp/packet.c18
-rw-r--r--networking/wget.c26
-rw-r--r--procps/free.c16
-rw-r--r--procps/fuser.c2
-rw-r--r--procps/nmeter.c10
-rw-r--r--procps/pidof.c2
-rw-r--r--procps/pmap.c12
-rw-r--r--procps/ps.c2
-rw-r--r--runit/runsv.c22
-rw-r--r--runit/svlogd.c6
-rwxr-xr-xscripts/bb_release1
-rw-r--r--selinux/chcon.c8
-rw-r--r--shell/ash.c202
-rw-r--r--shell/ash_test/ash-misc/piped_input.right2
-rwxr-xr-xshell/ash_test/ash-misc/piped_input.tests3
-rw-r--r--shell/ash_test/ash-vars/var_bash_repl_empty_var.right1
-rwxr-xr-xshell/ash_test/ash-vars/var_bash_repl_empty_var.tests2
-rw-r--r--shell/hush.c404
-rw-r--r--shell/hush_test/hush-misc/piped_input.right2
-rwxr-xr-xshell/hush_test/hush-misc/piped_input.tests3
-rw-r--r--shell/hush_test/hush-vars/var_bash_repl_empty_var.right1
-rwxr-xr-xshell/hush_test/hush-vars/var_bash_repl_empty_var.tests2
-rw-r--r--shell/shell_common.c21
-rw-r--r--sysklogd/klogd.c2
-rw-r--r--sysklogd/logger.c2
-rw-r--r--sysklogd/logread.c2
-rw-r--r--sysklogd/syslogd.c6
-rwxr-xr-xtestsuite/awk.tests14
-rw-r--r--testsuite/dc_add_results.txt36
-rw-r--r--testsuite/dc_decimal_results.txt42
-rw-r--r--testsuite/dc_divmod_results.txt8
-rw-r--r--testsuite/dc_multiply_results.txt4
-rw-r--r--testsuite/dc_power_results.txt72
-rw-r--r--testsuite/dc_subtract_results.txt14
-rwxr-xr-xtestsuite/factor.tests23
-rwxr-xr-xtestsuite/mount.tests2
-rwxr-xr-xtestsuite/xargs.tests2
-rw-r--r--util-linux/acpid.c4
-rw-r--r--util-linux/blockdev.c2
-rw-r--r--util-linux/chrt.c36
-rw-r--r--util-linux/fbset.c2
-rw-r--r--util-linux/fdisk.c11
-rw-r--r--util-linux/fdisk_osf.c4
-rw-r--r--util-linux/fdisk_sgi.c2
-rw-r--r--util-linux/fdisk_sun.c4
-rw-r--r--util-linux/fstrim.c8
-rw-r--r--util-linux/hexdump.c2
-rw-r--r--util-linux/hexdump_xxd.c3
-rw-r--r--util-linux/hwclock.c193
-rw-r--r--util-linux/ionice.c8
-rw-r--r--util-linux/mdev.c119
-rw-r--r--util-linux/mkfs_ext2.c2
-rw-r--r--util-linux/mkswap.c2
-rw-r--r--util-linux/mount.c91
-rw-r--r--util-linux/nsenter.c5
-rw-r--r--util-linux/rdate.c7
-rw-r--r--util-linux/rtcwake.c13
-rw-r--r--util-linux/script.c2
-rw-r--r--util-linux/setpriv.c2
-rw-r--r--util-linux/uevent.c50
-rw-r--r--util-linux/umount.c8
-rw-r--r--util-linux/unshare.c6
-rw-r--r--util-linux/volume_id/erofs.c67
-rw-r--r--util-linux/volume_id/volume_id.c11
-rw-r--r--util-linux/volume_id/volume_id_internal.h8
227 files changed, 3296 insertions, 2214 deletions
diff --git a/Config.in b/Config.in
index 495ac4c13..2d1e9bc8b 100644
--- a/Config.in
+++ b/Config.in
@@ -649,6 +649,14 @@ config STACK_OPTIMIZATION_386
649 do not work with it (they use SSE instructions without 649 do not work with it (they use SSE instructions without
650 ensuring stack alignment). 650 ensuring stack alignment).
651 651
652config STATIC_LIBGCC
653 bool "Use -static-libgcc"
654 default y
655 help
656 This option instructs gcc to link in a static version of its
657 support library, libgcc. This means that the binary will require
658 one fewer dynamic library at run time.
659
652comment 'Installation Options ("make install" behavior)' 660comment 'Installation Options ("make install" behavior)'
653 661
654choice 662choice
diff --git a/Makefile b/Makefile
index 892d5411d..a6609ca90 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
1VERSION = 1 1VERSION = 1
2PATCHLEVEL = 33 2PATCHLEVEL = 34
3SUBLEVEL = 0 3SUBLEVEL = 0
4EXTRAVERSION = .git 4EXTRAVERSION = .git
5NAME = Unnamed 5NAME = Unnamed
diff --git a/Makefile.flags b/Makefile.flags
index fdaf5cc79..94ed4e40e 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -59,7 +59,8 @@ CFLAGS += $(call cc-option,-fno-builtin-strlen -fomit-frame-pointer -ffunction-s
59CFLAGS += $(call cc-option,-fno-guess-branch-probability,) 59CFLAGS += $(call cc-option,-fno-guess-branch-probability,)
60CFLAGS += $(call cc-option,-funsigned-char,) 60CFLAGS += $(call cc-option,-funsigned-char,)
61 61
62ifneq ($(CC),clang) 62ifeq ($(CONFIG_STATIC_LIBGCC),y)
63# Disable it, for example, if you get
63# "clang-9: warning: argument unused during compilation: '-static-libgcc'" 64# "clang-9: warning: argument unused during compilation: '-static-libgcc'"
64CFLAGS += $(call cc-option,-static-libgcc,) 65CFLAGS += $(call cc-option,-static-libgcc,)
65endif 66endif
@@ -189,8 +190,10 @@ LDLIBS += $(if $(SELINUX_LIBS),$(SELINUX_LIBS:-l%=%),$(SELINUX_PC_MODULES:lib%=%
189endif 190endif
190 191
191ifeq ($(CONFIG_FEATURE_NSLOOKUP_BIG),y) 192ifeq ($(CONFIG_FEATURE_NSLOOKUP_BIG),y)
193ifeq ($(CONFIG_UNAME_OSNAME),Linux)
192LDLIBS += resolv 194LDLIBS += resolv
193endif 195endif
196endif
194 197
195ifeq ($(CONFIG_EFENCE),y) 198ifeq ($(CONFIG_EFENCE),y)
196LDLIBS += efence 199LDLIBS += efence
diff --git a/applets/applet_tables.c b/applets/applet_tables.c
index ce2037440..7ba929b12 100644
--- a/applets/applet_tables.c
+++ b/applets/applet_tables.c
@@ -20,6 +20,10 @@
20#undef ARRAY_SIZE 20#undef ARRAY_SIZE
21#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) 21#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0])))
22 22
23#ifndef PATH_MAX
24#define PATH_MAX 1024
25#endif
26
23#include "../include/autoconf.h" 27#include "../include/autoconf.h"
24#include "../include/applet_metadata.h" 28#include "../include/applet_metadata.h"
25 29
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index 425361fd9..2fa008fa7 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -11,3 +11,11 @@ ifeq ($(CONFIG_STACK_OPTIMIZATION_386),y)
11# from aligning stack to 16 bytes. (Which is gcc's way of supporting SSE). 11# from aligning stack to 16 bytes. (Which is gcc's way of supporting SSE).
12CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2,) 12CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2,)
13endif 13endif
14
15# "Control how GCC aligns variables.
16# Supported values for type are compat uses increased alignment value
17# compatible uses GCC 4.8 and earlier, abi uses alignment value as specified by the psABI,
18# and cacheline uses increased alignment value to match the cache line size.
19# compat is the default."
20# "abi" seems to be somewhat successful in preventing oversealous data alignment.
21CFLAGS += $(call cc-option,-malign-data=abi,)
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
new file mode 100644
index 000000000..16576fb81
--- /dev/null
+++ b/arch/x86_64/Makefile
@@ -0,0 +1,11 @@
1# ==========================================================================
2# Build system
3# ==========================================================================
4
5# "Control how GCC aligns variables.
6# Supported values for type are compat uses increased alignment value
7# compatible uses GCC 4.8 and earlier, abi uses alignment value as specified by the psABI,
8# and cacheline uses increased alignment value to match the cache line size.
9# compat is the default."
10# "abi" seems to be somewhat successful in preventing oversealous data alignment.
11CFLAGS += $(call cc-option,-malign-data=abi,)
diff --git a/archival/ar.c b/archival/ar.c
index 66930f0b8..eb734a685 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -48,19 +48,9 @@
48 48
49//kbuild:lib-$(CONFIG_AR) += ar.o 49//kbuild:lib-$(CONFIG_AR) += ar.o
50 50
51//usage:#define ar_trivial_usage
52//usage: "[-o] [-v] [-p] [-t] [-x] ARCHIVE FILES"
53//usage:#define ar_full_usage "\n\n"
54//usage: "Extract or list FILES from an ar archive\n"
55//usage: "\n -o Preserve original dates"
56//usage: "\n -p Extract to stdout"
57//usage: "\n -t List"
58//usage: "\n -x Extract"
59//usage: "\n -v Verbose"
60
61#include "libbb.h" 51#include "libbb.h"
62#include "bb_archive.h" 52#include "bb_archive.h"
63#include "ar.h" 53#include "ar_.h"
64 54
65#if ENABLE_FEATURE_AR_CREATE 55#if ENABLE_FEATURE_AR_CREATE
66/* filter out entries with same names as specified on the command line */ 56/* filter out entries with same names as specified on the command line */
@@ -236,23 +226,36 @@ static void FAST_FUNC header_verbose_list_ar(const file_header_t *file_header)
236 ); 226 );
237} 227}
238 228
239#define AR_OPT_VERBOSE (1 << 0) 229//usage:#define ar_trivial_usage
240#define AR_OPT_PRESERVE_DATE (1 << 1) 230//usage: "x|p|t"IF_FEATURE_AR_CREATE("|r")" [-ov] ARCHIVE [FILE]..."
241/* "ar r" implies create, but warns about it. c suppresses warning. 231//usage:#define ar_full_usage "\n\n"
242 * bbox accepts but ignores it: */ 232//usage: "Extract or list FILEs from an ar archive"IF_FEATURE_AR_CREATE(", or create it")"\n"
243#define AR_OPT_CREATE (1 << 2) 233//usage: "\n x Extract"
244 234//usage: "\n p Extract to stdout"
245#define AR_CMD_PRINT (1 << 3) 235//usage: "\n t List"
246#define FIRST_CMD AR_CMD_PRINT 236//usage: IF_FEATURE_AR_CREATE(
247#define AR_CMD_LIST (1 << 4) 237//usage: "\n r Create"
248#define AR_CMD_EXTRACT (1 << 5) 238//usage: )
249#define AR_CMD_INSERT (1 << 6) 239//usage: "\n -o Restore mtime"
240//usage: "\n -v Verbose"
250 241
251int ar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 242int ar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
252int ar_main(int argc UNUSED_PARAM, char **argv) 243int ar_main(int argc UNUSED_PARAM, char **argv)
253{ 244{
254 archive_handle_t *archive_handle; 245 archive_handle_t *archive_handle;
255 unsigned opt, t; 246 unsigned opt, t;
247 enum {
248 OPT_VERBOSE = (1 << 0),
249 OPT_PRESERVE_DATE = (1 << 1),
250 /* "ar r" implies create, but warns about it. c suppresses warning.
251 * bbox accepts but ignores it: */
252 OPT_CREATE = (1 << 2),
253 CMD_PRINT = (1 << 3),
254 FIRST_CMD = CMD_PRINT,
255 CMD_LIST = (1 << 4),
256 CMD_EXTRACT = (1 << 5),
257 CMD_INSERT = ((1 << 6) * ENABLE_FEATURE_AR_CREATE),
258 };
256 259
257 archive_handle = init_handle(); 260 archive_handle = init_handle();
258 261
@@ -272,26 +275,26 @@ int ar_main(int argc UNUSED_PARAM, char **argv)
272 if (t & (t-1)) /* more than one of p,t,x[,r] are specified */ 275 if (t & (t-1)) /* more than one of p,t,x[,r] are specified */
273 bb_show_usage(); 276 bb_show_usage();
274 277
275 if (opt & AR_CMD_PRINT) { 278 if (opt & CMD_PRINT) {
276 archive_handle->action_data = data_extract_to_stdout; 279 archive_handle->action_data = data_extract_to_stdout;
277 } 280 }
278 if (opt & AR_CMD_LIST) { 281 if (opt & CMD_LIST) {
279 archive_handle->action_header = header_list; 282 archive_handle->action_header = header_list;
280 } 283 }
281 if (opt & AR_CMD_EXTRACT) { 284 if (opt & CMD_EXTRACT) {
282 archive_handle->action_data = data_extract_all; 285 archive_handle->action_data = data_extract_all;
283 } 286 }
284 if (opt & AR_OPT_PRESERVE_DATE) { 287 if (opt & OPT_PRESERVE_DATE) {
285 archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE; 288 archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
286 } 289 }
287 if (opt & AR_OPT_VERBOSE) { 290 if (opt & OPT_VERBOSE) {
288 archive_handle->action_header = header_verbose_list_ar; 291 archive_handle->action_header = header_verbose_list_ar;
289 } 292 }
290#if ENABLE_FEATURE_AR_CREATE 293#if ENABLE_FEATURE_AR_CREATE
291 archive_handle->ar__name = *argv; 294 archive_handle->ar__name = *argv;
292#endif 295#endif
293 archive_handle->src_fd = xopen(*argv++, 296 archive_handle->src_fd = xopen(*argv++,
294 (opt & AR_CMD_INSERT) 297 (opt & CMD_INSERT)
295 ? O_RDWR | O_CREAT 298 ? O_RDWR | O_CREAT
296 : O_RDONLY 299 : O_RDONLY
297 ); 300 );
@@ -303,7 +306,7 @@ int ar_main(int argc UNUSED_PARAM, char **argv)
303 } 306 }
304 307
305#if ENABLE_FEATURE_AR_CREATE 308#if ENABLE_FEATURE_AR_CREATE
306 if (opt & AR_CMD_INSERT) 309 if (opt & CMD_INSERT)
307 return write_ar_archive(archive_handle); 310 return write_ar_archive(archive_handle);
308#endif 311#endif
309 312
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index 320fe4fd1..2beb92763 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -221,7 +221,7 @@ char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext)
221//usage:#define uncompress_trivial_usage 221//usage:#define uncompress_trivial_usage
222//usage: "[-cf] [FILE]..." 222//usage: "[-cf] [FILE]..."
223//usage:#define uncompress_full_usage "\n\n" 223//usage:#define uncompress_full_usage "\n\n"
224//usage: "Decompress .Z file[s]\n" 224//usage: "Decompress FILEs (or stdin)\n"
225//usage: "\n -c Write to stdout" 225//usage: "\n -c Write to stdout"
226//usage: "\n -f Overwrite" 226//usage: "\n -f Overwrite"
227 227
@@ -463,7 +463,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
463//usage:#define unlzma_trivial_usage 463//usage:#define unlzma_trivial_usage
464//usage: "[-cfk] [FILE]..." 464//usage: "[-cfk] [FILE]..."
465//usage:#define unlzma_full_usage "\n\n" 465//usage:#define unlzma_full_usage "\n\n"
466//usage: "Decompress FILE (or stdin)\n" 466//usage: "Decompress FILEs (or stdin)\n"
467//usage: "\n -c Write to stdout" 467//usage: "\n -c Write to stdout"
468//usage: "\n -f Force" 468//usage: "\n -f Force"
469//usage: "\n -k Keep input files" 469//usage: "\n -k Keep input files"
@@ -471,7 +471,7 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
471//usage:#define lzma_trivial_usage 471//usage:#define lzma_trivial_usage
472//usage: "-d [-cfk] [FILE]..." 472//usage: "-d [-cfk] [FILE]..."
473//usage:#define lzma_full_usage "\n\n" 473//usage:#define lzma_full_usage "\n\n"
474//usage: "Decompress FILE (or stdin)\n" 474//usage: "Decompress FILEs (or stdin)\n"
475//usage: "\n -d Decompress" 475//usage: "\n -d Decompress"
476//usage: "\n -c Write to stdout" 476//usage: "\n -c Write to stdout"
477//usage: "\n -f Force" 477//usage: "\n -f Force"
@@ -534,7 +534,7 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv)
534//usage:#define unxz_trivial_usage 534//usage:#define unxz_trivial_usage
535//usage: "[-cfk] [FILE]..." 535//usage: "[-cfk] [FILE]..."
536//usage:#define unxz_full_usage "\n\n" 536//usage:#define unxz_full_usage "\n\n"
537//usage: "Decompress FILE (or stdin)\n" 537//usage: "Decompress FILEs (or stdin)\n"
538//usage: "\n -c Write to stdout" 538//usage: "\n -c Write to stdout"
539//usage: "\n -f Force" 539//usage: "\n -f Force"
540//usage: "\n -k Keep input files" 540//usage: "\n -k Keep input files"
@@ -543,7 +543,7 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv)
543//usage:#define xz_trivial_usage 543//usage:#define xz_trivial_usage
544//usage: "-d [-cfk] [FILE]..." 544//usage: "-d [-cfk] [FILE]..."
545//usage:#define xz_full_usage "\n\n" 545//usage:#define xz_full_usage "\n\n"
546//usage: "Decompress FILE (or stdin)\n" 546//usage: "Decompress FILEs (or stdin)\n"
547//usage: "\n -d Decompress" 547//usage: "\n -d Decompress"
548//usage: "\n -c Write to stdout" 548//usage: "\n -c Write to stdout"
549//usage: "\n -f Force" 549//usage: "\n -f Force"
diff --git a/archival/bzip2.c b/archival/bzip2.c
index d0390a92a..ac5db0880 100644
--- a/archival/bzip2.c
+++ b/archival/bzip2.c
@@ -50,7 +50,7 @@
50//kbuild:lib-$(CONFIG_BZIP2) += bzip2.o 50//kbuild:lib-$(CONFIG_BZIP2) += bzip2.o
51 51
52//usage:#define bzip2_trivial_usage 52//usage:#define bzip2_trivial_usage
53//usage: "[OPTIONS] [FILE]..." 53//usage: "[-cfk" IF_FEATURE_BZIP2_DECOMPRESS("dt") "123456789] [FILE]..."
54//usage:#define bzip2_full_usage "\n\n" 54//usage:#define bzip2_full_usage "\n\n"
55//usage: "Compress FILEs (or stdin) with bzip2 algorithm\n" 55//usage: "Compress FILEs (or stdin) with bzip2 algorithm\n"
56//usage: "\n -1..9 Compression level" 56//usage: "\n -1..9 Compression level"
diff --git a/archival/cpio.c b/archival/cpio.c
index 94b4b8174..94303389e 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -68,7 +68,7 @@
68//usage: "\n -H newc Archive format" 68//usage: "\n -H newc Archive format"
69//usage: ) 69//usage: )
70//usage: "\n -d Make leading directories" 70//usage: "\n -d Make leading directories"
71//usage: "\n -m Preserve mtime" 71//usage: "\n -m Restore mtime"
72//usage: "\n -v Verbose" 72//usage: "\n -v Verbose"
73//usage: "\n -u Overwrite" 73//usage: "\n -u Overwrite"
74//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file" 74//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file"
diff --git a/archival/dpkg.c b/archival/dpkg.c
index 61631bd4d..8e1f9431d 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -1309,7 +1309,7 @@ postrm abort-install <old_version>
1309postrm abort-upgrade <old_version> 1309postrm abort-upgrade <old_version>
1310postrm disappear <overwriter> <version> 1310postrm disappear <overwriter> <version>
1311*/ 1311*/
1312static const char *const all_control_files[] = { 1312static const char *const all_control_files[] ALIGN_PTR = {
1313 "preinst", "postinst", "prerm", "postrm", 1313 "preinst", "postinst", "prerm", "postrm",
1314 "list", "md5sums", "shlibs", "conffiles", 1314 "list", "md5sums", "shlibs", "conffiles",
1315 "config", "templates" 1315 "config", "templates"
diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c
index c2c4cbbcc..a5a80439d 100644
--- a/archival/dpkg_deb.c
+++ b/archival/dpkg_deb.c
@@ -28,7 +28,7 @@
28//usage: "\n -f Print control fields" 28//usage: "\n -f Print control fields"
29//usage: "\n -e Extract control files to DIR (default: ./DEBIAN)" 29//usage: "\n -e Extract control files to DIR (default: ./DEBIAN)"
30//usage: "\n -x Extract files to DIR (no default)" 30//usage: "\n -x Extract files to DIR (no default)"
31//usage: "\n -X Verbose -x" 31//usage: "\n -X Verbose extract"
32//usage: 32//usage:
33//usage:#define dpkg_deb_example_usage 33//usage:#define dpkg_deb_example_usage
34//usage: "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n" 34//usage: "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n"
diff --git a/archival/libarchive/bz/blocksort.c b/archival/libarchive/bz/blocksort.c
index 92d6d8251..062fd0f54 100644
--- a/archival/libarchive/bz/blocksort.c
+++ b/archival/libarchive/bz/blocksort.c
@@ -459,7 +459,7 @@ int mainGtU(EState* state,
459 * usually small, typically <= 20. 459 * usually small, typically <= 20.
460 */ 460 */
461static 461static
462const uint32_t incs[14] = { 462const uint32_t incs[14] ALIGN4 = {
463 1, 4, 13, 40, 121, 364, 1093, 3280, 463 1, 4, 13, 40, 121, 364, 1093, 3280,
464 9841, 29524, 88573, 265720, 464 9841, 29524, 88573, 265720,
465 797161, 2391484 465 797161, 2391484
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index 3142405a3..049c2c156 100644
--- a/archival/libarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -159,6 +159,10 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
159 break; 159 break;
160 } 160 }
161 case S_IFDIR: 161 case S_IFDIR:
162//TODO: this causes problems if tarball contains a r-xr-xr-x directory:
163// we create this directory, and then fail to create files inside it
164// (if tar xf isn't run as root).
165// GNU tar works around this by chmod-ing directories *after* all files are extracted.
162 res = mkdir(dst_name, file_header->mode); 166 res = mkdir(dst_name, file_header->mode);
163 if ((res != 0) 167 if ((res != 0)
164 && (errno != EISDIR) /* btw, Linux doesn't return this */ 168 && (errno != EISDIR) /* btw, Linux doesn't return this */
diff --git a/archival/libarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c
index 0fcabb4a9..f8b2ff8d2 100644
--- a/archival/libarchive/data_extract_to_command.c
+++ b/archival/libarchive/data_extract_to_command.c
@@ -20,7 +20,7 @@ enum {
20 TAR_MAX, 20 TAR_MAX,
21}; 21};
22 22
23static const char *const tar_var[] = { 23static const char *const tar_var[] ALIGN_PTR = {
24 // "FILETYPE", 24 // "FILETYPE",
25 "MODE", 25 "MODE",
26 "FILENAME", 26 "FILENAME",
diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c
index c0332d414..b2a3eb1c2 100644
--- a/archival/libarchive/decompress_gunzip.c
+++ b/archival/libarchive/decompress_gunzip.c
@@ -194,14 +194,14 @@ struct cp_ext {
194}; 194};
195/* Copy lengths and extra bits for literal codes 257..285 */ 195/* Copy lengths and extra bits for literal codes 257..285 */
196/* note: see note #13 above about the 258 in this list. */ 196/* note: see note #13 above about the 258 in this list. */
197static const struct cp_ext lit = { 197static const struct cp_ext lit ALIGN2 = {
198 /*257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 */ 198 /*257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 */
199 /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 */ 199 /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 */
200 { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }, 200 { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 },
201 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 } /* 99 == invalid */ 201 { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 } /* 99 == invalid */
202}; 202};
203/* Copy offsets and extra bits for distance codes 0..29 */ 203/* Copy offsets and extra bits for distance codes 0..29 */
204static const struct cp_ext dist = { 204static const struct cp_ext dist ALIGN2 = {
205 /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 */ 205 /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 */
206 { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 }, 206 { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 },
207 { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 } 207 { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }
diff --git a/archival/libarchive/get_header_ar.c b/archival/libarchive/get_header_ar.c
index b6ecd596c..3a19d6ff7 100644
--- a/archival/libarchive/get_header_ar.c
+++ b/archival/libarchive/get_header_ar.c
@@ -6,7 +6,7 @@
6 */ 6 */
7#include "libbb.h" 7#include "libbb.h"
8#include "bb_archive.h" 8#include "bb_archive.h"
9#include "ar.h" 9#include "ar_.h"
10 10
11/* WARNING: Clobbers str[len], so fields must be read in reverse order! */ 11/* WARNING: Clobbers str[len], so fields must be read in reverse order! */
12static unsigned read_num(char *str, int base, int len) 12static unsigned read_num(char *str, int base, int len)
diff --git a/archival/libarchive/unpack_ar_archive.c b/archival/libarchive/unpack_ar_archive.c
index 584c18ce8..125d424c9 100644
--- a/archival/libarchive/unpack_ar_archive.c
+++ b/archival/libarchive/unpack_ar_archive.c
@@ -4,7 +4,7 @@
4 */ 4 */
5#include "libbb.h" 5#include "libbb.h"
6#include "bb_archive.h" 6#include "bb_archive.h"
7#include "ar.h" 7#include "ar_.h"
8 8
9void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive) 9void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive)
10{ 10{
diff --git a/archival/rpm.c b/archival/rpm.c
index 0d8f641b9..63d13d0e1 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -83,7 +83,9 @@ struct globals {
83 void *map; 83 void *map;
84 rpm_index *mytags; 84 rpm_index *mytags;
85 int tagcount; 85 int tagcount;
86 unsigned mapsize, pagesize; 86 unsigned mapsize;
87 IF_VARIABLE_ARCH_PAGESIZE(unsigned pagesize;)
88#define G_pagesize cached_pagesize(G.pagesize)
87} FIX_ALIASING; 89} FIX_ALIASING;
88#define G (*(struct globals*)bb_common_bufsiz1) 90#define G (*(struct globals*)bb_common_bufsiz1)
89#define INIT_G() do { setup_common_bufsiz(); } while (0) 91#define INIT_G() do { setup_common_bufsiz(); } while (0)
@@ -142,11 +144,11 @@ static int rpm_gettags(const char *filename)
142 144
143#if !ENABLE_PLATFORM_MINGW32 145#if !ENABLE_PLATFORM_MINGW32
144 /* Map the store */ 146 /* Map the store */
145 storepos = (storepos + G.pagesize) & -(int)G.pagesize; 147 storepos = (storepos + G_pagesize) & -(int)G_pagesize;
146 /* remember size for munmap */ 148 /* remember size for munmap */
147 G.mapsize = storepos; 149 G.mapsize = storepos;
148 /* some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ 150 /* some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */
149 G.map = mmap(0, storepos, PROT_READ, MAP_PRIVATE, fd, 0); 151 G.map = mmap_read(fd, storepos);
150 if (G.map == MAP_FAILED) 152 if (G.map == MAP_FAILED)
151 bb_perror_msg_and_die("mmap '%s'", filename); 153 bb_perror_msg_and_die("mmap '%s'", filename);
152#else 154#else
@@ -368,7 +370,7 @@ int rpm_main(int argc, char **argv)
368 int opt, func = 0; 370 int opt, func = 0;
369 371
370 INIT_G(); 372 INIT_G();
371 G.pagesize = getpagesize(); 373 INIT_PAGESIZE(G.pagesize);
372 374
373 while ((opt = getopt(argc, argv, "iqpldc")) != -1) { 375 while ((opt = getopt(argc, argv, "iqpldc")) != -1) {
374 switch (opt) { 376 switch (opt) {
@@ -535,7 +537,7 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
535 int rpm_fd; 537 int rpm_fd;
536 538
537 INIT_G(); 539 INIT_G();
538 G.pagesize = getpagesize(); 540 INIT_PAGESIZE(G.pagesize);
539 541
540 rpm_fd = rpm_gettags(argv[1]); 542 rpm_fd = rpm_gettags(argv[1]);
541 543
diff --git a/archival/tar.c b/archival/tar.c
index 1796d4c60..6c1591bdc 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -794,7 +794,7 @@ static llist_t *append_file_list_to_list(llist_t *list)
794//usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m") 794//usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m")
795//usage: "vokO] " 795//usage: "vokO] "
796//usage: "[-f TARFILE] [-C DIR] " 796//usage: "[-f TARFILE] [-C DIR] "
797//usage: IF_FEATURE_TAR_FROM("[-T FILE] [-X FILE] "IF_FEATURE_TAR_LONG_OPTIONS("[--exclude PATTERN]... ")) 797//usage: IF_FEATURE_TAR_FROM("[-T FILE] [-X FILE] "IF_FEATURE_TAR_LONG_OPTIONS("[OPTION]... "))
798//usage: "[FILE]..." 798//usage: "[FILE]..."
799//usage:#define tar_full_usage "\n\n" 799//usage:#define tar_full_usage "\n\n"
800//usage: IF_FEATURE_TAR_CREATE("Create, extract, ") 800//usage: IF_FEATURE_TAR_CREATE("Create, extract, ")
@@ -828,6 +828,11 @@ static llist_t *append_file_list_to_list(llist_t *list)
828//usage: IF_FEATURE_SEAMLESS_BZ2( 828//usage: IF_FEATURE_SEAMLESS_BZ2(
829//usage: "\n -j (De)compress using bzip2" 829//usage: "\n -j (De)compress using bzip2"
830//usage: ) 830//usage: )
831//usage: IF_FEATURE_SEAMLESS_LZMA(
832//usage: IF_FEATURE_TAR_LONG_OPTIONS(
833//usage: "\n --lzma (De)compress using lzma"
834//usage: )
835//usage: )
831//usage: "\n -a (De)compress based on extension" 836//usage: "\n -a (De)compress based on extension"
832//usage: IF_FEATURE_TAR_CREATE( 837//usage: IF_FEATURE_TAR_CREATE(
833//usage: "\n -h Follow symlinks" 838//usage: "\n -h Follow symlinks"
@@ -839,21 +844,21 @@ static llist_t *append_file_list_to_list(llist_t *list)
839//usage: "\n --exclude PATTERN Glob pattern to exclude" 844//usage: "\n --exclude PATTERN Glob pattern to exclude"
840//usage: ) 845//usage: )
841//usage: ) 846//usage: )
847//usage: IF_FEATURE_TAR_LONG_OPTIONS(
848//usage: "\n --overwrite Replace existing files"
849//usage: "\n --strip-components NUM NUM of leading components to strip"
850//usage: "\n --no-recursion Don't descend in directories"
851//usage: "\n --numeric-owner Use numeric user:group"
852//usage: "\n --no-same-permissions Don't restore access permissions"
853//usage: IF_FEATURE_TAR_TO_COMMAND(
854//usage: "\n --to-command COMMAND Pipe files to COMMAND"
855//usage: )
856//usage: )
842//usage: 857//usage:
843//usage:#define tar_example_usage 858//usage:#define tar_example_usage
844//usage: "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" 859//usage: "$ zcat /tmp/tarball.tar.gz | tar -xf -\n"
845//usage: "$ tar -cf /tmp/tarball.tar /usr/local\n" 860//usage: "$ tar -cf /tmp/tarball.tar /usr/local\n"
846 861
847// Supported but aren't in --help:
848// lzma
849// no-recursion
850// numeric-owner
851// no-same-permissions
852// overwrite
853//IF_FEATURE_TAR_TO_COMMAND(
854// to-command
855//)
856
857enum { 862enum {
858 OPTBIT_KEEP_OLD = 8, 863 OPTBIT_KEEP_OLD = 8,
859 IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,) 864 IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,)
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig
index d3a974706..f95f71607 100644
--- a/configs/mingw32_defconfig
+++ b/configs/mingw32_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Busybox version: 1.33.0.git 3# Busybox version: 1.34.0.git
4# Thu Nov 12 08:15:02 2020 4# Thu Jan 14 12:07:38 2021
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set 7# CONFIG_PLATFORM_POSIX is not set
@@ -72,6 +72,7 @@ CONFIG_EXTRA_LDFLAGS=""
72CONFIG_EXTRA_LDLIBS="" 72CONFIG_EXTRA_LDLIBS=""
73CONFIG_USE_PORTABLE_CODE=y 73CONFIG_USE_PORTABLE_CODE=y
74CONFIG_STACK_OPTIMIZATION_386=y 74CONFIG_STACK_OPTIMIZATION_386=y
75CONFIG_STATIC_LIBGCC=y
75 76
76# 77#
77# Installation Options ("make install" behavior) 78# Installation Options ("make install" behavior)
@@ -348,6 +349,7 @@ CONFIG_UNIQ=y
348CONFIG_UNLINK=y 349CONFIG_UNLINK=y
349CONFIG_USLEEP=y 350CONFIG_USLEEP=y
350CONFIG_UUDECODE=y 351CONFIG_UUDECODE=y
352CONFIG_BASE32=y
351CONFIG_BASE64=y 353CONFIG_BASE64=y
352CONFIG_UUENCODE=y 354CONFIG_UUENCODE=y
353CONFIG_WC=y 355CONFIG_WC=y
@@ -720,6 +722,7 @@ CONFIG_REV=y
720# CONFIG_FEATURE_VOLUMEID_BCACHE is not set 722# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
721# CONFIG_FEATURE_VOLUMEID_BTRFS is not set 723# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
722# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set 724# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
725# CONFIG_FEATURE_VOLUMEID_EROFS is not set
723# CONFIG_FEATURE_VOLUMEID_EXFAT is not set 726# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
724# CONFIG_FEATURE_VOLUMEID_EXT is not set 727# CONFIG_FEATURE_VOLUMEID_EXT is not set
725# CONFIG_FEATURE_VOLUMEID_F2FS is not set 728# CONFIG_FEATURE_VOLUMEID_F2FS is not set
@@ -1002,6 +1005,7 @@ CONFIG_UDHCPC_DEFAULT_SCRIPT=""
1002# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set 1005# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
1003# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set 1006# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
1004# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set 1007# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set
1008CONFIG_UDHCPC_DEFAULT_INTERFACE=""
1005# CONFIG_FEATURE_UDHCP_PORT is not set 1009# CONFIG_FEATURE_UDHCP_PORT is not set
1006CONFIG_UDHCP_DEBUG=0 1010CONFIG_UDHCP_DEBUG=0
1007CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 1011CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig
index da2419c62..cf0e3ec8e 100644
--- a/configs/mingw64_defconfig
+++ b/configs/mingw64_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Busybox version: 1.33.0.git 3# Busybox version: 1.34.0.git
4# Thu Nov 12 08:15:02 2020 4# Thu Jan 14 12:07:38 2021
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set 7# CONFIG_PLATFORM_POSIX is not set
@@ -72,6 +72,7 @@ CONFIG_EXTRA_LDFLAGS=""
72CONFIG_EXTRA_LDLIBS="" 72CONFIG_EXTRA_LDLIBS=""
73CONFIG_USE_PORTABLE_CODE=y 73CONFIG_USE_PORTABLE_CODE=y
74CONFIG_STACK_OPTIMIZATION_386=y 74CONFIG_STACK_OPTIMIZATION_386=y
75CONFIG_STATIC_LIBGCC=y
75 76
76# 77#
77# Installation Options ("make install" behavior) 78# Installation Options ("make install" behavior)
@@ -348,6 +349,7 @@ CONFIG_UNIQ=y
348CONFIG_UNLINK=y 349CONFIG_UNLINK=y
349CONFIG_USLEEP=y 350CONFIG_USLEEP=y
350CONFIG_UUDECODE=y 351CONFIG_UUDECODE=y
352CONFIG_BASE32=y
351CONFIG_BASE64=y 353CONFIG_BASE64=y
352CONFIG_UUENCODE=y 354CONFIG_UUENCODE=y
353CONFIG_WC=y 355CONFIG_WC=y
@@ -720,6 +722,7 @@ CONFIG_REV=y
720# CONFIG_FEATURE_VOLUMEID_BCACHE is not set 722# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
721# CONFIG_FEATURE_VOLUMEID_BTRFS is not set 723# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
722# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set 724# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
725# CONFIG_FEATURE_VOLUMEID_EROFS is not set
723# CONFIG_FEATURE_VOLUMEID_EXFAT is not set 726# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
724# CONFIG_FEATURE_VOLUMEID_EXT is not set 727# CONFIG_FEATURE_VOLUMEID_EXT is not set
725# CONFIG_FEATURE_VOLUMEID_F2FS is not set 728# CONFIG_FEATURE_VOLUMEID_F2FS is not set
@@ -1002,6 +1005,7 @@ CONFIG_UDHCPC_DEFAULT_SCRIPT=""
1002# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set 1005# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
1003# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set 1006# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
1004# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set 1007# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set
1008CONFIG_UDHCPC_DEFAULT_INTERFACE=""
1005# CONFIG_FEATURE_UDHCP_PORT is not set 1009# CONFIG_FEATURE_UDHCP_PORT is not set
1006CONFIG_UDHCP_DEBUG=0 1010CONFIG_UDHCP_DEBUG=0
1007CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 1011CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
diff --git a/coreutils/cp.c b/coreutils/cp.c
index cfeb19fc4..9b9b8f7bf 100644
--- a/coreutils/cp.c
+++ b/coreutils/cp.c
@@ -38,7 +38,7 @@
38/* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */ 38/* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */
39 39
40//usage:#define cp_trivial_usage 40//usage:#define cp_trivial_usage
41//usage: "[OPTIONS] SOURCE... DEST" 41//usage: "[-arPLHpfilsTu] SOURCE... DEST"
42//usage:#define cp_full_usage "\n\n" 42//usage:#define cp_full_usage "\n\n"
43//usage: "Copy SOURCE(s) to DEST\n" 43//usage: "Copy SOURCE(s) to DEST\n"
44//usage: "\n -a Same as -dpR" 44//usage: "\n -a Same as -dpR"
diff --git a/coreutils/date.c b/coreutils/date.c
index 1a3ae506c..d64ff94b9 100644
--- a/coreutils/date.c
+++ b/coreutils/date.c
@@ -93,40 +93,27 @@
93 */ 93 */
94 94
95//usage:#define date_trivial_usage 95//usage:#define date_trivial_usage
96//usage: "[OPTIONS] [+FMT] [TIME]" 96//usage: "[OPTIONS] [+FMT] [[-s] TIME]"
97//usage:#define date_full_usage "\n\n" 97//usage:#define date_full_usage "\n\n"
98//usage: "Display time (using +FMT), or set time\n" 98//usage: "Display time (using +FMT), or set time\n"
99//usage: IF_NOT_LONG_OPTS(
100//usage: IF_NOT_PLATFORM_MINGW32(
101//usage: "\n [-s] TIME Set time to TIME"
102//usage: )
103//usage: "\n -u Work in UTC (don't convert to local time)" 99//usage: "\n -u Work in UTC (don't convert to local time)"
104//usage: "\n -R Output RFC-2822 compliant date string" 100//usage: IF_NOT_PLATFORM_MINGW32(
105//usage: ) IF_LONG_OPTS( 101//usage: "\n [-s] TIME Set time to TIME"
106//usage: IF_NOT_PLATFORM_MINGW32(
107//usage: "\n [-s,--set] TIME Set time to TIME"
108//usage: )
109//usage: "\n -u,--utc Work in UTC (don't convert to local time)"
110//usage: "\n -R,--rfc-2822 Output RFC-2822 compliant date string"
111//usage: ) 102//usage: )
103//usage: "\n -d TIME Display TIME, not 'now'"
112//usage: IF_FEATURE_DATE_ISOFMT( 104//usage: IF_FEATURE_DATE_ISOFMT(
113//usage: "\n -I[SPEC] Output ISO-8601 compliant date string" 105//usage: "\n -D FMT FMT (strptime format) for -s/-d TIME conversion"
114//usage: "\n SPEC='date' (default) for date only," 106////////^^^^^^^^^^^^^^^^^^^^^^ busybox invention, not compat
115//usage: "\n 'hours', 'minutes', or 'seconds' for date and"
116//usage: "\n time to the indicated precision"
117//usage: ) 107//usage: )
118//usage: IF_NOT_LONG_OPTS(
119//usage: "\n -r FILE Display last modification time of FILE" 108//usage: "\n -r FILE Display last modification time of FILE"
120//usage: "\n -d TIME Display TIME, not 'now'" 109//usage: "\n -R Output RFC-2822 date"
121//usage: ) IF_LONG_OPTS(
122//usage: "\n -r,--reference FILE Display last modification time of FILE"
123//usage: "\n -d,--date TIME Display TIME, not 'now'"
124//usage: )
125//usage: IF_FEATURE_DATE_ISOFMT( 110//usage: IF_FEATURE_DATE_ISOFMT(
126//usage: "\n -D FMT Use FMT (strptime format) for -d TIME conversion" 111//usage: "\n -I[SPEC] Output ISO-8601 date"
112//usage: "\n SPEC=date (default), hours, minutes, seconds or ns"
127//usage: ) 113//usage: )
128//usage: "\n" 114//usage: "\n"
129//usage: "\nRecognized TIME formats:" 115//usage: "\nRecognized TIME formats:"
116//usage: "\n @seconds_since_1970"
130//usage: "\n hh:mm[:ss]" 117//usage: "\n hh:mm[:ss]"
131//usage: "\n [YYYY.]MM.DD-hh:mm[:ss]" 118//usage: "\n [YYYY.]MM.DD-hh:mm[:ss]"
132//usage: "\n YYYY-MM-DD hh:mm[:ss]" 119//usage: "\n YYYY-MM-DD hh:mm[:ss]"
@@ -152,15 +139,15 @@ enum {
152 OPT_UTC = (1 << 2), /* u */ 139 OPT_UTC = (1 << 2), /* u */
153 OPT_DATE = (1 << 3), /* d */ 140 OPT_DATE = (1 << 3), /* d */
154 OPT_REFERENCE = (1 << 4), /* r */ 141 OPT_REFERENCE = (1 << 4), /* r */
155 OPT_TIMESPEC = (1 << 5) * ENABLE_FEATURE_DATE_ISOFMT, /* I */ 142 OPT_ISO8601 = (1 << 5) * ENABLE_FEATURE_DATE_ISOFMT, /* I */
156 OPT_HINT = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT, /* D */ 143 OPT_STR2DT = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT, /* D */
157#else 144#else
158 OPT_SET = (0), /* s */ 145 OPT_SET = (0), /* s */
159 OPT_UTC = (1 << 1), /* u */ 146 OPT_UTC = (1 << 1), /* u */
160 OPT_DATE = (1 << 2), /* d */ 147 OPT_DATE = (1 << 2), /* d */
161 OPT_REFERENCE = (1 << 3), /* r */ 148 OPT_REFERENCE = (1 << 3), /* r */
162 OPT_TIMESPEC = (1 << 4) * ENABLE_FEATURE_DATE_ISOFMT, /* I */ 149 OPT_ISO8601 = (1 << 4) * ENABLE_FEATURE_DATE_ISOFMT, /* I */
163 OPT_HINT = (1 << 5) * ENABLE_FEATURE_DATE_ISOFMT, /* D */ 150 OPT_STR2DT = (1 << 5) * ENABLE_FEATURE_DATE_ISOFMT, /* D */
164#endif 151#endif
165}; 152};
166 153
@@ -185,12 +172,6 @@ static const char date_longopts[] ALIGN1 =
185 * - after xasprintf we use other xfuncs 172 * - after xasprintf we use other xfuncs
186 */ 173 */
187 174
188static void maybe_set_utc(int opt)
189{
190 if (opt & OPT_UTC)
191 putenv((char*)"TZ=UTC0");
192}
193
194int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 175int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
195int date_main(int argc UNUSED_PARAM, char **argv) 176int date_main(int argc UNUSED_PARAM, char **argv)
196{ 177{
@@ -198,7 +179,7 @@ int date_main(int argc UNUSED_PARAM, char **argv)
198 struct tm tm_time; 179 struct tm tm_time;
199 char buf_fmt_dt2str[64]; 180 char buf_fmt_dt2str[64];
200 unsigned opt; 181 unsigned opt;
201 int ifmt = -1; 182 int isofmt = -1;
202 char *date_str; 183 char *date_str;
203 char *fmt_dt2str; 184 char *fmt_dt2str;
204 char *fmt_str2dt; 185 char *fmt_str2dt;
@@ -229,15 +210,16 @@ int date_main(int argc UNUSED_PARAM, char **argv)
229 ); 210 );
230 argv += optind; 211 argv += optind;
231 212
232 maybe_set_utc(opt); 213 if (opt & OPT_UTC)
214 putenv((char*)"TZ=UTC0");
233 215
234 if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_TIMESPEC)) { 216 if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_ISO8601)) {
235 ifmt = 0; /* default is date */ 217 isofmt = 0; /* default is date */
236 if (isofmt_arg) { 218 if (isofmt_arg) {
237 static const char isoformats[] ALIGN1 = 219 static const char isoformats[] ALIGN1 =
238 "date\0""hours\0""minutes\0""seconds\0"; /* ns? */ 220 "date\0""hours\0""minutes\0""seconds\0ns\0";
239 ifmt = index_in_substrings(isoformats, isofmt_arg); 221 isofmt = index_in_substrings(isoformats, isofmt_arg);
240 if (ifmt < 0) 222 if (isofmt < 0)
241 bb_show_usage(); 223 bb_show_usage();
242 } 224 }
243 } 225 }
@@ -247,7 +229,7 @@ int date_main(int argc UNUSED_PARAM, char **argv)
247 fmt_dt2str = &argv[0][1]; /* skip over the '+' */ 229 fmt_dt2str = &argv[0][1]; /* skip over the '+' */
248 argv++; 230 argv++;
249 } 231 }
250 if (!(opt & (OPT_SET | OPT_DATE))) { 232 if (!(opt & (OPT_SET | OPT_DATE))) { /* neither -s TIME nor -d TIME? */
251 opt |= OPT_SET; 233 opt |= OPT_SET;
252 date_str = argv[0]; /* can be NULL */ 234 date_str = argv[0]; /* can be NULL */
253 if (date_str) { 235 if (date_str) {
@@ -315,7 +297,7 @@ int date_main(int argc UNUSED_PARAM, char **argv)
315 tm_time.tm_hour = 0; 297 tm_time.tm_hour = 0;
316 298
317 /* Process any date input to UNIX time since 1 Jan 1970 */ 299 /* Process any date input to UNIX time since 1 Jan 1970 */
318 if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_HINT)) { 300 if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_STR2DT)) {
319 if (strptime(date_str, fmt_str2dt, &tm_time) == NULL) 301 if (strptime(date_str, fmt_str2dt, &tm_time) == NULL)
320 bb_error_msg_and_die(bb_msg_invalid_date, date_str); 302 bb_error_msg_and_die(bb_msg_invalid_date, date_str);
321 } else { 303 } else {
@@ -341,24 +323,34 @@ int date_main(int argc UNUSED_PARAM, char **argv)
341 if (fmt_dt2str == NULL) { 323 if (fmt_dt2str == NULL) {
342 int i; 324 int i;
343 fmt_dt2str = buf_fmt_dt2str; 325 fmt_dt2str = buf_fmt_dt2str;
344 if (ENABLE_FEATURE_DATE_ISOFMT && ifmt >= 0) { 326 if (ENABLE_FEATURE_DATE_ISOFMT && isofmt >= 0) {
345 /* -I[SPEC]: 0:date 1:hours 2:minutes 3:seconds */ 327 /* -I[SPEC]: 0:date 1:hours 2:minutes 3:seconds 4:ns*/
346 strcpy(fmt_dt2str, "%Y-%m-%dT%H:%M:%S"); 328 strcpy(fmt_dt2str, "%Y-%m-%dT%H:%M:%S");
347 i = 8 + 3 * ifmt; 329 i = 8 + 3 * isofmt;
348 if (ifmt != 0) { 330 if (isofmt != 0) {
349 /* TODO: if (ifmt==4) i += sprintf(&fmt_dt2str[i], ",%09u", nanoseconds); */ 331 int n;
350 format_utc: 332 if (isofmt == 4) {
351 fmt_dt2str[i++] = '%'; 333 i -= 3;
352 fmt_dt2str[i++] = (opt & OPT_UTC) ? 'Z' : 'z'; 334 i += sprintf(&fmt_dt2str[i], ",%09u", (unsigned)ts.tv_nsec);
335 }
336 /* %z prints "+hhmm" timezone, but coreutils-8.30 prints "+hh:mm"! */
337 /* ...therefore this atrocity: */
338 n = strftime(&fmt_dt2str[i], 8, "%z", &tm_time);
339 i += n;
340 if (n == 5 && (fmt_dt2str[i-5] == '+' || fmt_dt2str[i-5] == '-')) {
341 /* "mm" -> ":mm" */
342 fmt_dt2str[i ] = fmt_dt2str[i - 1];
343 fmt_dt2str[i - 1] = fmt_dt2str[i - 2];
344 fmt_dt2str[i - 2] = ':';
345 i++;
346 }
353 } 347 }
354 fmt_dt2str[i] = '\0'; 348 fmt_dt2str[i] = '\0';
355 } else if (opt & OPT_RFC2822) { 349 } else if (opt & OPT_RFC2822) {
356 /* -R. undo busybox.c setlocale */ 350 /* -R. undo busybox.c setlocale */
357 if (ENABLE_LOCALE_SUPPORT) 351 if (ENABLE_LOCALE_SUPPORT)
358 setlocale(LC_TIME, "C"); 352 setlocale(LC_TIME, "C");
359 strcpy(fmt_dt2str, "%a, %d %b %Y %H:%M:%S "); 353 fmt_dt2str = (char*)"%a, %d %b %Y %H:%M:%S %z";
360 i = sizeof("%a, %d %b %Y %H:%M:%S ")-1;
361 goto format_utc;
362 } else { /* default case */ 354 } else { /* default case */
363 fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y"; 355 fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y";
364 } 356 }
@@ -410,10 +402,6 @@ int date_main(int argc UNUSED_PARAM, char **argv)
410 /* With no format string, just print a blank line */ 402 /* With no format string, just print a blank line */
411 date_buf[0] = '\0'; 403 date_buf[0] = '\0';
412 } else { 404 } else {
413 /* Handle special conversions */
414 if (is_prefixed_with(fmt_dt2str, "%f")) {
415 fmt_dt2str = (char*)"%Y.%m.%d-%H:%M:%S";
416 }
417 /* Generate output string */ 405 /* Generate output string */
418 strftime(date_buf, COMMON_BUFSIZE, fmt_dt2str, &tm_time); 406 strftime(date_buf, COMMON_BUFSIZE, fmt_dt2str, &tm_time);
419 } 407 }
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 042355e24..c150ef5bc 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -59,7 +59,7 @@
59//usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]\n" 59//usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]\n"
60//usage: IF_FEATURE_DD_IBS_OBS( 60//usage: IF_FEATURE_DD_IBS_OBS(
61//usage: " [conv=notrunc|noerror|sync|fsync]\n" 61//usage: " [conv=notrunc|noerror|sync|fsync]\n"
62//usage: " [iflag=skip_bytes|fullblock] [oflag=seek_bytes|append]" 62//usage: " [iflag=skip_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]"
63//usage: ) 63//usage: )
64//usage:#define dd_full_usage "\n\n" 64//usage:#define dd_full_usage "\n\n"
65//usage: "Copy a file with converting and formatting\n" 65//usage: "Copy a file with converting and formatting\n"
@@ -82,9 +82,11 @@
82//usage: "\n conv=fsync Physically write data out before finishing" 82//usage: "\n conv=fsync Physically write data out before finishing"
83//usage: "\n conv=swab Swap every pair of bytes" 83//usage: "\n conv=swab Swap every pair of bytes"
84//usage: "\n iflag=skip_bytes skip=N is in bytes" 84//usage: "\n iflag=skip_bytes skip=N is in bytes"
85//usage: "\n iflag=fullblock Read full blocks"
86//usage: "\n oflag=seek_bytes seek=N is in bytes" 85//usage: "\n oflag=seek_bytes seek=N is in bytes"
87//usage: "\n oflag=append Open output file in append mode" 86//usage: "\n iflag=direct O_DIRECT input"
87//usage: "\n oflag=direct O_DIRECT output"
88//usage: "\n iflag=fullblock Read full blocks"
89//usage: "\n oflag=append Open output in append mode"
88//usage: ) 90//usage: )
89//usage: IF_FEATURE_DD_STATUS( 91//usage: IF_FEATURE_DD_STATUS(
90//usage: "\n status=noxfer Suppress rate output" 92//usage: "\n status=noxfer Suppress rate output"
@@ -140,16 +142,18 @@ enum {
140 FLAG_IFLAG_SHIFT = 5, 142 FLAG_IFLAG_SHIFT = 5,
141 FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, 143 FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
142 FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, 144 FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS,
145 FLAG_IDIRECT = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS,
143 /* end of input flags */ 146 /* end of input flags */
144 /* start of output flags */ 147 /* start of output flags */
145 FLAG_OFLAG_SHIFT = 7, 148 FLAG_OFLAG_SHIFT = 8,
146 FLAG_SEEK_BYTES = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, 149 FLAG_SEEK_BYTES = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS,
147 FLAG_APPEND = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, 150 FLAG_APPEND = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS,
151 FLAG_ODIRECT = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS,
148 /* end of output flags */ 152 /* end of output flags */
149 FLAG_TWOBUFS = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, 153 FLAG_TWOBUFS = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS,
150 FLAG_COUNT = 1 << 10, 154 FLAG_COUNT = 1 << 12,
151 FLAG_STATUS_NONE = 1 << 11, 155 FLAG_STATUS_NONE = 1 << 13,
152 FLAG_STATUS_NOXFER = 1 << 12, 156 FLAG_STATUS_NOXFER = 1 << 14,
153}; 157};
154 158
155static void dd_output_status(int UNUSED_PARAM cur_signal) 159static void dd_output_status(int UNUSED_PARAM cur_signal)
@@ -195,12 +199,50 @@ static void dd_output_status(int UNUSED_PARAM cur_signal)
195#endif 199#endif
196} 200}
197 201
202#if ENABLE_FEATURE_DD_IBS_OBS
203static int clear_O_DIRECT(int fd)
204{
205 if (errno == EINVAL) {
206 int fl = fcntl(fd, F_GETFL);
207 if (fl & O_DIRECT) {
208 fcntl(fd, F_SETFL, fl & ~O_DIRECT);
209 return 1;
210 }
211 }
212 return 0;
213}
214#endif
215
216static ssize_t dd_read(void *ibuf, size_t ibs)
217{
218 ssize_t n;
219
220#if ENABLE_FEATURE_DD_IBS_OBS
221 read_again:
222 if (G.flags & FLAG_FULLBLOCK)
223 n = full_read(ifd, ibuf, ibs);
224 else
225#endif
226 n = safe_read(ifd, ibuf, ibs);
227#if ENABLE_FEATURE_DD_IBS_OBS
228 if (n < 0 && (G.flags & FLAG_IDIRECT) && clear_O_DIRECT(ifd))
229 goto read_again;
230#endif
231 return n;
232}
233
198static bool write_and_stats(const void *buf, size_t len, size_t obs, 234static bool write_and_stats(const void *buf, size_t len, size_t obs,
199 const char *filename) 235 const char *filename)
200{ 236{
201 ssize_t n; 237 ssize_t n;
202 238
239 IF_FEATURE_DD_IBS_OBS(write_again:)
203 n = full_write(ofd, buf, len); 240 n = full_write(ofd, buf, len);
241#if ENABLE_FEATURE_DD_IBS_OBS
242 if (n < 0 && (G.flags & FLAG_ODIRECT) && clear_O_DIRECT(ofd))
243 goto write_again;
244#endif
245
204#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE 246#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
205 if (n > 0) 247 if (n > 0)
206 G.total_bytes += n; 248 G.total_bytes += n;
@@ -257,6 +299,16 @@ static int parse_comma_flags(char *val, const char *words, const char *error_in)
257} 299}
258#endif 300#endif
259 301
302static void *alloc_buf(size_t size)
303{
304#if !ENABLE_PLATFORM_MINGW32
305 /* Important for "{i,o}flag=direct" - buffers must be page aligned */
306 if (size >= bb_getpagesize())
307 return xmmap_anon(size);
308#endif
309 return xmalloc(size);
310}
311
260int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 312int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
261int dd_main(int argc UNUSED_PARAM, char **argv) 313int dd_main(int argc UNUSED_PARAM, char **argv)
262{ 314{
@@ -270,9 +322,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
270 static const char conv_words[] ALIGN1 = 322 static const char conv_words[] ALIGN1 =
271 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; 323 "notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
272 static const char iflag_words[] ALIGN1 = 324 static const char iflag_words[] ALIGN1 =
273 "skip_bytes\0""fullblock\0"; 325 "skip_bytes\0""fullblock\0""direct\0";
274 static const char oflag_words[] ALIGN1 = 326 static const char oflag_words[] ALIGN1 =
275 "seek_bytes\0append\0"; 327 "seek_bytes\0append\0""direct\0";
276#endif 328#endif
277#if ENABLE_FEATURE_DD_STATUS 329#if ENABLE_FEATURE_DD_STATUS
278 static const char status_words[] ALIGN1 = 330 static const char status_words[] ALIGN1 =
@@ -313,7 +365,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
313 //swab swap every pair of input bytes: will abort on non-even reads 365 //swab swap every pair of input bytes: will abort on non-even reads
314 OP_iflag_skip_bytes, 366 OP_iflag_skip_bytes,
315 OP_iflag_fullblock, 367 OP_iflag_fullblock,
368 OP_iflag_direct,
316 OP_oflag_seek_bytes, 369 OP_oflag_seek_bytes,
370 OP_oflag_direct,
317#endif 371#endif
318 }; 372 };
319 smallint exitcode = EXIT_FAILURE; 373 smallint exitcode = EXIT_FAILURE;
@@ -429,13 +483,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
429#endif 483#endif
430 } /* end of "for (argv[i])" */ 484 } /* end of "for (argv[i])" */
431 485
432//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever 486 ibuf = alloc_buf(ibs);
433 ibuf = xmalloc(ibs);
434 obuf = ibuf; 487 obuf = ibuf;
435#if ENABLE_FEATURE_DD_IBS_OBS 488#if ENABLE_FEATURE_DD_IBS_OBS
436 if (ibs != obs) { 489 if (ibs != obs) {
437 G.flags |= FLAG_TWOBUFS; 490 G.flags |= FLAG_TWOBUFS;
438 obuf = xmalloc(obs); 491 obuf = alloc_buf(obs);
439 } 492 }
440#endif 493#endif
441 494
@@ -447,10 +500,15 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
447#endif 500#endif
448 501
449 if (infile) { 502 if (infile) {
503 int iflag = O_RDONLY;
504#if ENABLE_FEATURE_DD_IBS_OBS
505 if (G.flags & FLAG_IDIRECT)
506 iflag |= O_DIRECT;
507#endif
450#if !ENABLE_PLATFORM_MINGW32 508#if !ENABLE_PLATFORM_MINGW32
451 xmove_fd(xopen(infile, O_RDONLY), ifd); 509 xmove_fd(xopen(infile, iflag), ifd);
452#else 510#else
453 xmove_fd(mingw_xopen(infile, O_RDONLY), ifd); 511 xmove_fd(mingw_xopen(infile, iflag), ifd);
454 update_dev_fd(get_dev_type(infile), ifd); 512 update_dev_fd(get_dev_type(infile), ifd);
455#endif 513#endif
456 } else { 514 } else {
@@ -463,7 +521,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
463 oflag |= O_TRUNC; 521 oflag |= O_TRUNC;
464 if (G.flags & FLAG_APPEND) 522 if (G.flags & FLAG_APPEND)
465 oflag |= O_APPEND; 523 oflag |= O_APPEND;
466 524#if ENABLE_FEATURE_DD_IBS_OBS
525 if (G.flags & FLAG_ODIRECT)
526 oflag |= O_DIRECT;
527#endif
467 xmove_fd(xopen(outfile, oflag), ofd); 528 xmove_fd(xopen(outfile, oflag), ofd);
468 529
469#if ENABLE_PLATFORM_MINGW32 530#if ENABLE_PLATFORM_MINGW32
@@ -508,13 +569,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
508 size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs; 569 size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs;
509 if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) { 570 if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) {
510 do { 571 do {
511 ssize_t n; 572 ssize_t n = dd_read(ibuf, blocksz);
512#if ENABLE_FEATURE_DD_IBS_OBS
513 if (G.flags & FLAG_FULLBLOCK)
514 n = full_read(ifd, ibuf, blocksz);
515 else
516#endif
517 n = safe_read(ifd, ibuf, blocksz);
518 if (n < 0) 573 if (n < 0)
519 goto die_infile; 574 goto die_infile;
520 if (n == 0) 575 if (n == 0)
@@ -529,14 +584,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
529 } 584 }
530 585
531 while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { 586 while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
532 ssize_t n; 587 ssize_t n = dd_read(ibuf, ibs);
533
534#if ENABLE_FEATURE_DD_IBS_OBS
535 if (G.flags & FLAG_FULLBLOCK)
536 n = full_read(ifd, ibuf, ibs);
537 else
538#endif
539 n = safe_read(ifd, ibuf, ibs);
540 if (n == 0) 588 if (n == 0)
541 break; 589 break;
542 if (n < 0) { 590 if (n < 0) {
@@ -631,11 +679,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
631 if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE)) 679 if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE))
632 dd_output_status(0); 680 dd_output_status(0);
633 681
682#if 0 /* can't just free(), they can be mmap()ed */
634 if (ENABLE_FEATURE_CLEAN_UP) { 683 if (ENABLE_FEATURE_CLEAN_UP) {
635 free(obuf); 684 free(obuf);
636 if (G.flags & FLAG_TWOBUFS) 685 if (G.flags & FLAG_TWOBUFS)
637 free(ibuf); 686 free(ibuf);
638 } 687 }
688#endif
639 689
640 return exitcode; 690 return exitcode;
641} 691}
diff --git a/coreutils/factor.c b/coreutils/factor.c
index 47fe179dc..a7a5a5030 100644
--- a/coreutils/factor.c
+++ b/coreutils/factor.c
@@ -19,6 +19,7 @@
19//usage: "Print prime factors" 19//usage: "Print prime factors"
20 20
21#include "libbb.h" 21#include "libbb.h"
22#include "common_bufsiz.h"
22 23
23#if 0 24#if 0
24# define dbg(...) bb_error_msg(__VA_ARGS__) 25# define dbg(...) bb_error_msg(__VA_ARGS__)
@@ -42,9 +43,116 @@ typedef unsigned long half_t;
42#error Cant find an integer type which is half as wide as ullong 43#error Cant find an integer type which is half as wide as ullong
43#endif 44#endif
44 45
46/* The trial divisor increment wheel. Use it to skip over divisors that
47 * are composites of 2, 3, 5, 7, or 11.
48 * Larger wheels improve sieving only slightly, but quickly grow in size
49 * (adding just one prime, 13, results in 5766 element sieve).
50 */
51#define R(a,b,c,d,e,f,g,h,i,j,A,B,C,D,E,F,G,H,I,J) \
52 (((uint64_t)(a<<0) | (b<<3) | (c<<6) | (d<<9) | (e<<12) | (f<<15) | (g<<18) | (h<<21) | (i<<24) | (j<<27)) << 1) | \
53 (((uint64_t)(A<<0) | (B<<3) | (C<<6) | (D<<9) | (E<<12) | (F<<15) | (G<<18) | (H<<21) | (I<<24) | (J<<27)) << 31)
54#define P(a,b,c,d,e,f,g,h,i,j,A,B,C,D,E,F,G,H,I,J) \
55 R( (a/2),(b/2),(c/2),(d/2),(e/2),(f/2),(g/2),(h/2),(i/2),(j/2), \
56 (A/2),(B/2),(C/2),(D/2),(E/2),(F/2),(G/2),(H/2),(I/2),(J/2) )
57static const uint64_t packed_wheel[] = {
58 /*1, 2, 2, 4, 2,*/
59 P( 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, 2, 6, 4, 6, 8, 4), //01
60 P( 2, 4, 2, 4,14, 4, 6, 2,10, 2, 6, 6, 4, 2, 4, 6, 2,10, 2, 4), //02
61 P( 2,12,10, 2, 4, 2, 4, 6, 2, 6, 4, 6, 6, 6, 2, 6, 4, 2, 6, 4), //03
62 P( 6, 8, 4, 2, 4, 6, 8, 6,10, 2, 4, 6, 2, 6, 6, 4, 2, 4, 6, 2), //04
63 P( 6, 4, 2, 6,10, 2,10, 2, 4, 2, 4, 6, 8, 4, 2, 4,12, 2, 6, 4), //05
64 P( 2, 6, 4, 6,12, 2, 4, 2, 4, 8, 6, 4, 6, 2, 4, 6, 2, 6,10, 2), //06
65 P( 4, 6, 2, 6, 4, 2, 4, 2,10, 2,10, 2, 4, 6, 6, 2, 6, 6, 4, 6), //07
66 P( 6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 6, 4, 8, 6, 4, 6, 2, 4, 6), //08
67 P( 8, 6, 4, 2,10, 2, 6, 4, 2, 4, 2,10, 2,10, 2, 4, 2, 4, 8, 6), //09
68 P( 4, 2, 4, 6, 6, 2, 6, 4, 8, 4, 6, 8, 4, 2, 4, 2, 4, 8, 6, 4), //10
69 P( 6, 6, 6, 2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 4, 2,10, 2,10, 2), //11
70 P( 6, 4, 6, 2, 6, 4, 2, 4, 6, 6, 8, 4, 2, 6,10, 8, 4, 2, 4, 2), //12
71 P( 4, 8,10, 6, 2, 4, 8, 6, 6, 4, 2, 4, 6, 2, 6, 4, 6, 2,10, 2), //13
72 P(10, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 6, 6, 4, 6, 8), //14
73 P( 4, 2, 4, 2, 4, 8, 6, 4, 8, 4, 6, 2, 6, 6, 4, 2, 4, 6, 8, 4), //15
74 P( 2, 4, 2,10, 2,10, 2, 4, 2, 4, 6, 2,10, 2, 4, 6, 8, 6, 4, 2), //16
75 P( 6, 4, 6, 8, 4, 6, 2, 4, 8, 6, 4, 6, 2, 4, 6, 2, 6, 6, 4, 6), //17
76 P( 6, 2, 6, 6, 4, 2,10, 2,10, 2, 4, 2, 4, 6, 2, 6, 4, 2,10, 6), //18
77 P( 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 4, 2,12, 6, 4, 6, 2, 4, 6, 2), //19
78 P(12, 4, 2, 4, 8, 6, 4, 2, 4, 2,10, 2,10, 6, 2, 4, 6, 2, 6, 4), //20
79 P( 2, 4, 6, 6, 2, 6, 4, 2,10, 6, 8, 6, 4, 2, 4, 8, 6, 4, 6, 2), //21
80 P( 4, 6, 2, 6, 6, 6, 4, 6, 2, 6, 4, 2, 4, 2,10,12, 2, 4, 2,10), //22
81 P( 2, 6, 4, 2, 4, 6, 6, 2,10, 2, 6, 4,14, 4, 2, 4, 2, 4, 8, 6), //23
82 P( 4, 6, 2, 4, 6, 2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 4,12, 2,12), //24
83};
84#undef P
85#undef R
86#define WHEEL_START 5
87#define WHEEL_SIZE (5 + 24 * 20)
88#define square_count (((uint8_t*)&bb_common_bufsiz1)[0])
89#define wheel_tab (((uint8_t*)&bb_common_bufsiz1) + 1)
90/*
91 * Why, you ask?
92 * plain byte array:
93 * function old new delta
94 * wheel_tab - 485 +485
95 * 3-bit-packed insanity:
96 * packed_wheel - 192 +192
97 * factor_main 108 171 +63
98 */
99static void unpack_wheel(void)
100{
101 int i;
102 uint8_t *p;
103
104 setup_common_bufsiz();
105 wheel_tab[0] = 1;
106 wheel_tab[1] = 2;
107 wheel_tab[2] = 2;
108 wheel_tab[3] = 4;
109 wheel_tab[4] = 2;
110 p = &wheel_tab[5];
111 for (i = 0; i < ARRAY_SIZE(packed_wheel); i++) {
112 uint64_t v = packed_wheel[i];
113 while ((v & 0xe) != 0) {
114 *p = v & 0xe;
115 //printf("%2u,", *p);
116 p++;
117 v >>= 3;
118 }
119 //printf("\n");
120 }
121}
122
123/* Prevent inlining, factorize() needs all help it can get with reducing register pressure */
124static NOINLINE void print_w(wide_t n)
125{
126 unsigned rep = square_count;
127 do
128 printf(" %"LL_FMT"u", n);
129 while (--rep != 0);
130}
131static NOINLINE void print_h(half_t n)
132{
133 print_w(n);
134}
135
136static void factorize(wide_t N);
137
45static half_t isqrt_odd(wide_t N) 138static half_t isqrt_odd(wide_t N)
46{ 139{
47 half_t s = isqrt(N); 140 half_t s = isqrt(N);
141 /* s^2 is <= N, (s+1)^2 > N */
142
143 /* If s^2 in fact is EQUAL to N, it's very lucky.
144 * Examples:
145 * factor 18446743988964486098 = 2 * 3037000493 * 3037000493
146 * factor 18446743902517389507 = 3 * 2479700513 * 2479700513
147 */
148 if ((wide_t)s * s == N) {
149 /* factorize sqrt(N), printing each factor twice */
150 square_count *= 2;
151 factorize(s);
152 /* Let caller know we recursed */
153 return 0;
154 }
155
48 /* Subtract 1 from even s, odd s won't change: */ 156 /* Subtract 1 from even s, odd s won't change: */
49 /* (doesnt work for zero, but we know that s != 0 here) */ 157 /* (doesnt work for zero, but we know that s != 0 here) */
50 s = (s - 1) | 1; 158 s = (s - 1) | 1;
@@ -53,43 +161,20 @@ static half_t isqrt_odd(wide_t N)
53 161
54static NOINLINE void factorize(wide_t N) 162static NOINLINE void factorize(wide_t N)
55{ 163{
164 unsigned w;
56 half_t factor; 165 half_t factor;
57 half_t max_factor; 166 half_t max_factor;
58 // unsigned count3;
59 // unsigned count5;
60 // unsigned count7;
61 // ^^^^^^^^^^^^^^^ commented-out simple sieving code (easier to grasp).
62 // Faster sieving, using one word for potentially up to 6 counters:
63 // count upwards in each mask, counter "triggers" when it sets its mask to "100[0]..."
64 // 10987654321098765432109876543210 - bits 31-0 in 32-bit word
65 // 17777713333311111777775555333 - bit masks for counters for primes 3,5,7,11,13,17
66 // 100000100001000010001001 - value for adding 1 to each mask
67 // 10000010000010000100001000100 - value for checking that any mask reached msb
68 enum {
69 SHIFT_3 = 1 << 0,
70 SHIFT_5 = 1 << 3,
71 SHIFT_7 = 1 << 7,
72 INCREMENT_EACH = SHIFT_3 | SHIFT_5 | SHIFT_7,
73 MULTIPLE_OF_3 = 1 << 2,
74 MULTIPLE_OF_5 = 1 << 6,
75 MULTIPLE_OF_7 = 1 << 11,
76 MULTIPLE_DETECTED = MULTIPLE_OF_3 | MULTIPLE_OF_5 | MULTIPLE_OF_7,
77 };
78 unsigned sieve_word;
79 167
80 if (N < 4) 168 if (N < 4)
81 goto end; 169 goto end;
82 170
83 while (!(N & 1)) {
84 printf(" 2");
85 N >>= 1;
86 }
87
88 /* The code needs to be optimized for the case where 171 /* The code needs to be optimized for the case where
89 * there are large prime factors. For example, 172 * there are large prime factors. For example,
90 * this is not hard: 173 * this is not hard:
91 * 8262075252869367027 = 3 7 17 23 47 101 113 127 131 137 823 174 * 8262075252869367027 = 3 7 17 23 47 101 113 127 131 137 823
92 * (the largest factor to test is only ~sqrt(823) = 28) 175 * (the largest divisor to test for largest factor 823
176 * is only ~sqrt(823) = 28, the entire factorization needs
177 * only ~33 trial divisions)
93 * but this is: 178 * but this is:
94 * 18446744073709551601 = 53 348051774975651917 179 * 18446744073709551601 = 53 348051774975651917
95 * the last factor requires testing up to 180 * the last factor requires testing up to
@@ -98,70 +183,37 @@ static NOINLINE void factorize(wide_t N)
98 * factor 18446744073709551557 (0xffffffffffffffc5). 183 * factor 18446744073709551557 (0xffffffffffffffc5).
99 */ 184 */
100 max_factor = isqrt_odd(N); 185 max_factor = isqrt_odd(N);
101 // count3 = 3; 186 if (!max_factor)
102 // count5 = 6; 187 return; /* square was detected and recursively factored */
103 // count7 = 9; 188 factor = 2;
104 sieve_word = 0 189 w = 0;
105 /* initial count for SHIFT_n is (n-1)/2*3: */
106 + (MULTIPLE_OF_3 - 3 * SHIFT_3)
107 + (MULTIPLE_OF_5 - 6 * SHIFT_5)
108 + (MULTIPLE_OF_7 - 9 * SHIFT_7)
109 //+ (MULTIPLE_OF_11 - 15 * SHIFT_11)
110 //+ (MULTIPLE_OF_13 - 18 * SHIFT_13)
111 //+ (MULTIPLE_OF_17 - 24 * SHIFT_17)
112 ;
113 factor = 3;
114 for (;;) { 190 for (;;) {
191 half_t fw;
192
115 /* The division is the most costly part of the loop. 193 /* The division is the most costly part of the loop.
116 * On 64bit CPUs, takes at best 12 cycles, often ~20. 194 * On 64bit CPUs, takes at best 12 cycles, often ~20.
117 */ 195 */
118 while ((N % factor) == 0) { /* not likely */ 196 while ((N % factor) == 0) { /* not likely */
119 N = N / factor; 197 N = N / factor;
120 printf(" %"HALF_FMT"u", factor); 198 print_h(factor);
121 max_factor = isqrt_odd(N); 199 max_factor = isqrt_odd(N);
200 if (!max_factor)
201 return; /* square was detected */
122 } 202 }
123 next_factor:
124 if (factor >= max_factor) 203 if (factor >= max_factor)
125 break; 204 break;
126 factor += 2; 205 fw = factor + wheel_tab[w];
127 /* Rudimentary wheel sieving: skip multiples of 3, 5 and 7: 206 if (fw < factor)
128 * Every third odd number is divisible by three and thus isn't a prime: 207 break; /* overflow */
129 * 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47... 208 factor = fw;
130 * ^ ^ ^ ^ ^ ^ ^ _ ^ ^ _ ^ ^ ^ ^ 209 w++;
131 * (^ = primes, _ = would-be-primes-if-not-divisible-by-5) 210 if (w < WHEEL_SIZE)
132 * The numbers with space under them are excluded by sieve 3.
133 */
134 // count7--;
135 // count5--;
136 // count3--;
137 // if (count3 && count5 && count7)
138 // continue;
139 sieve_word += INCREMENT_EACH;
140 if (!(sieve_word & MULTIPLE_DETECTED))
141 continue; 211 continue;
142 /* 212 w = WHEEL_START;
143 * "factor" is multiple of 3 33% of the time (count3 reached 0),
144 * else, multiple of 5 13% of the time,
145 * else, multiple of 7 7.6% of the time.
146 * Cumulatively, with 3,5,7 sieving we are here 54.3% of the time.
147 */
148 // if (count3 == 0)
149 // count3 = 3;
150 if (sieve_word & MULTIPLE_OF_3)
151 sieve_word -= SHIFT_3 * 3;
152 // if (count5 == 0)
153 // count5 = 5;
154 if (sieve_word & MULTIPLE_OF_5)
155 sieve_word -= SHIFT_5 * 5;
156 // if (count7 == 0)
157 // count7 = 7;
158 if (sieve_word & MULTIPLE_OF_7)
159 sieve_word -= SHIFT_7 * 7;
160 goto next_factor;
161 } 213 }
162 end: 214 end:
163 if (N > 1) 215 if (N > 1)
164 printf(" %"LL_FMT"u", N); 216 print_w(N);
165 bb_putchar('\n'); 217 bb_putchar('\n');
166} 218}
167 219
@@ -176,12 +228,15 @@ static void factorize_numstr(const char *numstr)
176 if (errno) 228 if (errno)
177 bb_show_usage(); 229 bb_show_usage();
178 printf("%"LL_FMT"u:", N); 230 printf("%"LL_FMT"u:", N);
231 square_count = 1;
179 factorize(N); 232 factorize(N);
180} 233}
181 234
182int factor_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 235int factor_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
183int factor_main(int argc UNUSED_PARAM, char **argv) 236int factor_main(int argc UNUSED_PARAM, char **argv)
184{ 237{
238 unpack_wheel();
239
185 //// coreutils has undocumented option ---debug (three dashes) 240 //// coreutils has undocumented option ---debug (three dashes)
186 //getopt32(argv, ""); 241 //getopt32(argv, "");
187 //argv += optind; 242 //argv += optind;
diff --git a/coreutils/id.c b/coreutils/id.c
index f20cd7d09..78d5f2a50 100644
--- a/coreutils/id.c
+++ b/coreutils/id.c
@@ -33,7 +33,7 @@
33/* BB_AUDIT SUSv3 compliant. */ 33/* BB_AUDIT SUSv3 compliant. */
34 34
35//usage:#define id_trivial_usage 35//usage:#define id_trivial_usage
36//usage: "[OPTIONS] [USER]" 36//usage: "[-ugGnr"IF_SELINUX("Z")"] [USER]"
37//usage:#define id_full_usage "\n\n" 37//usage:#define id_full_usage "\n\n"
38//usage: "Print information about USER or the current user\n" 38//usage: "Print information about USER or the current user\n"
39//usage: IF_SELINUX( 39//usage: IF_SELINUX(
diff --git a/coreutils/ln.c b/coreutils/ln.c
index 5591e8335..2dcf79c07 100644
--- a/coreutils/ln.c
+++ b/coreutils/ln.c
@@ -21,14 +21,14 @@
21/* http://www.opengroup.org/onlinepubs/007904975/utilities/ln.html */ 21/* http://www.opengroup.org/onlinepubs/007904975/utilities/ln.html */
22 22
23//usage:#define ln_trivial_usage 23//usage:#define ln_trivial_usage
24//usage: "[OPTIONS] TARGET... LINK|DIR" 24//usage: "[-sfnbtv] [-S SUF] TARGET... LINK|DIR"
25//usage:#define ln_full_usage "\n\n" 25//usage:#define ln_full_usage "\n\n"
26//usage: "Create a link LINK or DIR/TARGET to the specified TARGET(s)\n" 26//usage: "Create a link LINK or DIR/TARGET to the specified TARGET(s)\n"
27//usage: "\n -s Make symlinks instead of hardlinks" 27//usage: "\n -s Make symlinks instead of hardlinks"
28//usage: "\n -f Remove existing destinations" 28//usage: "\n -f Remove existing destinations"
29//usage: "\n -n Don't dereference symlinks - treat like normal file" 29//usage: "\n -n Don't dereference symlinks - treat like normal file"
30//usage: "\n -b Make a backup of the target (if exists) before link operation" 30//usage: "\n -b Make a backup of the target (if exists) before link operation"
31//usage: "\n -S suf Use suffix instead of ~ when making backup files" 31//usage: "\n -S SUF Use suffix instead of ~ when making backup files"
32//usage: "\n -T Treat LINK as a file, not DIR" 32//usage: "\n -T Treat LINK as a file, not DIR"
33//usage: "\n -v Verbose" 33//usage: "\n -v Verbose"
34//usage: 34//usage:
diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c
index ba26c985a..4efa23061 100644
--- a/coreutils/md5_sha1_sum.c
+++ b/coreutils/md5_sha1_sum.c
@@ -117,8 +117,8 @@
117//usage: "\n -c Check sums against list in FILEs" 117//usage: "\n -c Check sums against list in FILEs"
118//usage: "\n -s Don't output anything, status code shows success" 118//usage: "\n -s Don't output anything, status code shows success"
119//usage: "\n -w Warn about improperly formatted checksum lines" 119//usage: "\n -w Warn about improperly formatted checksum lines"
120//usage: "\n -a BITS 224 (default), 256, 384, 512"
121//usage: ) 120//usage: )
121//usage: "\n -a BITS 224 (default), 256, 384, 512"
122 122
123//FIXME: GNU coreutils 8.25 has no -s option, it has only these two long opts: 123//FIXME: GNU coreutils 8.25 has no -s option, it has only these two long opts:
124// --quiet don't print OK for each successfully verified file 124// --quiet don't print OK for each successfully verified file
diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c
index 0ee1d1f72..d5e0f512b 100644
--- a/coreutils/mkdir.c
+++ b/coreutils/mkdir.c
@@ -27,7 +27,7 @@
27/* http://www.opengroup.org/onlinepubs/007904975/utilities/mkdir.html */ 27/* http://www.opengroup.org/onlinepubs/007904975/utilities/mkdir.html */
28 28
29//usage:#define mkdir_trivial_usage 29//usage:#define mkdir_trivial_usage
30//usage: "[OPTIONS] DIRECTORY..." 30//usage: "[-m MODE] [-p] DIRECTORY..."
31//usage:#define mkdir_full_usage "\n\n" 31//usage:#define mkdir_full_usage "\n\n"
32//usage: "Create DIRECTORY\n" 32//usage: "Create DIRECTORY\n"
33//usage: "\n -m MODE Mode" 33//usage: "\n -m MODE Mode"
diff --git a/coreutils/mknod.c b/coreutils/mknod.c
index eee0ac71d..b10fe4fc3 100644
--- a/coreutils/mknod.c
+++ b/coreutils/mknod.c
@@ -36,7 +36,9 @@
36//usage: "$ mknod /dev/fd0 b 2 0\n" 36//usage: "$ mknod /dev/fd0 b 2 0\n"
37//usage: "$ mknod -m 644 /tmp/pipe p\n" 37//usage: "$ mknod -m 644 /tmp/pipe p\n"
38 38
39#include <sys/sysmacros.h> // For makedev 39#ifdef __linux__
40# include <sys/sysmacros.h> // For makedev
41#endif
40 42
41#include "libbb.h" 43#include "libbb.h"
42#include "libcoreutils/coreutils.h" 44#include "libcoreutils/coreutils.h"
diff --git a/coreutils/nl.c b/coreutils/nl.c
index aea019c56..800b73c26 100644
--- a/coreutils/nl.c
+++ b/coreutils/nl.c
@@ -19,7 +19,7 @@
19//usage:#define nl_full_usage "\n\n" 19//usage:#define nl_full_usage "\n\n"
20//usage: "Write FILEs to standard output with line numbers added\n" 20//usage: "Write FILEs to standard output with line numbers added\n"
21//usage: "\n -b STYLE Which lines to number - a: all, t: nonempty, n: none" 21//usage: "\n -b STYLE Which lines to number - a: all, t: nonempty, n: none"
22//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^TODO: support "pBRE": number only lines thatmatch regexp BRE" 22//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^TODO: support "pBRE": number only lines that match regexp BRE"
23////usage: "\n -f STYLE footer lines" 23////usage: "\n -f STYLE footer lines"
24////usage: "\n -h STYLE header lines" 24////usage: "\n -h STYLE header lines"
25////usage: "\n -d CC use CC for separating logical pages" 25////usage: "\n -d CC use CC for separating logical pages"
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c
index ea1ab9de8..76ee5137a 100644
--- a/coreutils/od_bloaty.c
+++ b/coreutils/od_bloaty.c
@@ -634,7 +634,7 @@ decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
634 bytes_to_unsigned_dec_digits, 634 bytes_to_unsigned_dec_digits,
635 bytes_to_hex_digits, 635 bytes_to_hex_digits,
636 }; 636 };
637 static const char doux_fmtstring[][sizeof(" %%0%u%s")] = { 637 static const char doux_fmtstring[][sizeof(" %%0%u%s")] ALIGN1 = {
638 " %%%u%s", 638 " %%%u%s",
639 " %%0%u%s", 639 " %%0%u%s",
640 " %%%u%s", 640 " %%%u%s",
@@ -1155,7 +1155,7 @@ dump_strings(off_t address, off_t end_offset)
1155static int 1155static int
1156parse_old_offset(const char *s, off_t *offset) 1156parse_old_offset(const char *s, off_t *offset)
1157{ 1157{
1158 static const struct suffix_mult Bb[] = { 1158 static const struct suffix_mult Bb[] ALIGN_SUFFIX = {
1159 { "B", 1024 }, 1159 { "B", 1024 },
1160 { "b", 512 }, 1160 { "b", 512 },
1161 { "", 0 } 1161 { "", 0 }
diff --git a/coreutils/paste.c b/coreutils/paste.c
index 11743297a..fd2aa5027 100644
--- a/coreutils/paste.c
+++ b/coreutils/paste.c
@@ -18,7 +18,7 @@
18//kbuild:lib-$(CONFIG_PASTE) += paste.o 18//kbuild:lib-$(CONFIG_PASTE) += paste.o
19 19
20//usage:#define paste_trivial_usage 20//usage:#define paste_trivial_usage
21//usage: "[OPTIONS] [FILE]..." 21//usage: "[-d LIST] [-s] [FILE]..."
22//usage:#define paste_full_usage "\n\n" 22//usage:#define paste_full_usage "\n\n"
23//usage: "Paste lines from each input file, separated with tab\n" 23//usage: "Paste lines from each input file, separated with tab\n"
24//usage: "\n -d LIST Use delimiters from LIST, not tab" 24//usage: "\n -d LIST Use delimiters from LIST, not tab"
diff --git a/coreutils/rmdir.c b/coreutils/rmdir.c
index 5092a5dfc..addf41188 100644
--- a/coreutils/rmdir.c
+++ b/coreutils/rmdir.c
@@ -20,7 +20,7 @@
20/* http://www.opengroup.org/onlinepubs/007904975/utilities/rmdir.html */ 20/* http://www.opengroup.org/onlinepubs/007904975/utilities/rmdir.html */
21 21
22//usage:#define rmdir_trivial_usage 22//usage:#define rmdir_trivial_usage
23//usage: "[OPTIONS] DIRECTORY..." 23//usage: "[-p] DIRECTORY..."
24//usage:#define rmdir_full_usage "\n\n" 24//usage:#define rmdir_full_usage "\n\n"
25//usage: "Remove DIRECTORY if it is empty\n" 25//usage: "Remove DIRECTORY if it is empty\n"
26//usage: "\n -p Include parents" 26//usage: "\n -p Include parents"
diff --git a/coreutils/sort.c b/coreutils/sort.c
index 07c327645..b194847d1 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -43,7 +43,7 @@
43 43
44//usage:#define sort_trivial_usage 44//usage:#define sort_trivial_usage
45//usage: "[-nru" 45//usage: "[-nru"
46//usage: IF_FEATURE_SORT_BIG("gMcszbdfiokt] [-o FILE] [-k start[.offset][opts][,end[.offset][opts]] [-t CHAR") 46//usage: IF_FEATURE_SORT_BIG("gMcszbdfiokt] [-o FILE] [-k START[.OFS][OPTS][,END[.OFS][OPTS]] [-t CHAR")
47//usage: "] [FILE]..." 47//usage: "] [FILE]..."
48//usage:#define sort_full_usage "\n\n" 48//usage:#define sort_full_usage "\n\n"
49//usage: "Sort lines of text\n" 49//usage: "Sort lines of text\n"
diff --git a/coreutils/split.c b/coreutils/split.c
index ecbc9d2d8..3fcfd95f2 100644
--- a/coreutils/split.c
+++ b/coreutils/split.c
@@ -44,7 +44,7 @@
44#include "common_bufsiz.h" 44#include "common_bufsiz.h"
45 45
46#if ENABLE_FEATURE_SPLIT_FANCY 46#if ENABLE_FEATURE_SPLIT_FANCY
47static const struct suffix_mult split_suffixes[] = { 47static const struct suffix_mult split_suffixes[] ALIGN_SUFFIX = {
48 { "b", 512 }, 48 { "b", 512 },
49 { "k", 1024 }, 49 { "k", 1024 },
50 { "m", 1024*1024 }, 50 { "m", 1024*1024 },
diff --git a/coreutils/stat.c b/coreutils/stat.c
index c332e5dc8..0a3f251f3 100644
--- a/coreutils/stat.c
+++ b/coreutils/stat.c
@@ -40,7 +40,7 @@
40//kbuild:lib-$(CONFIG_STAT) += stat.o 40//kbuild:lib-$(CONFIG_STAT) += stat.o
41 41
42//usage:#define stat_trivial_usage 42//usage:#define stat_trivial_usage
43//usage: "[OPTIONS] FILE..." 43//usage: "[-lt"IF_FEATURE_STAT_FILESYSTEM("f")"] "IF_FEATURE_STAT_FORMAT("[-c FMT] ")"FILE..."
44//usage:#define stat_full_usage "\n\n" 44//usage:#define stat_full_usage "\n\n"
45//usage: "Display file" 45//usage: "Display file"
46//usage: IF_FEATURE_STAT_FILESYSTEM(" (default) or filesystem") 46//usage: IF_FEATURE_STAT_FILESYSTEM(" (default) or filesystem")
@@ -209,7 +209,7 @@ FS_TYPE(0x62656572, "sysfs")
209static const char *human_fstype(uint32_t f_type) 209static const char *human_fstype(uint32_t f_type)
210{ 210{
211# define FS_TYPE(type, name) type, 211# define FS_TYPE(type, name) type,
212 static const uint32_t fstype[] = { 212 static const uint32_t fstype[] ALIGN4 = {
213 FS_TYPE_LIST 213 FS_TYPE_LIST
214 }; 214 };
215# undef FS_TYPE 215# undef FS_TYPE
diff --git a/coreutils/stty.c b/coreutils/stty.c
index 40e812799..19253964c 100644
--- a/coreutils/stty.c
+++ b/coreutils/stty.c
@@ -487,7 +487,7 @@ static const char mode_name[] ALIGN1 =
487#undef MI_ENTRY 487#undef MI_ENTRY
488#define MI_ENTRY(N,T,F,B,M) { T, F, M, B }, 488#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
489 489
490static const struct mode_info mode_info[] = { 490static const struct mode_info mode_info[] ALIGN4 = {
491 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */ 491 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
492 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) 492 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
493 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) 493 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
@@ -905,7 +905,7 @@ static void display_window_size(int fancy)
905 } 905 }
906} 906}
907 907
908static const struct suffix_mult stty_suffixes[] = { 908static const struct suffix_mult stty_suffixes[] ALIGN_SUFFIX = {
909 { "b", 512 }, 909 { "b", 512 },
910 { "k", 1024 }, 910 { "k", 1024 },
911 { "B", 1024 }, 911 { "B", 1024 },
diff --git a/coreutils/test.c b/coreutils/test.c
index ac7b546a3..7c6574334 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -306,7 +306,7 @@ struct operator_t {
306 unsigned char op_num, op_type; 306 unsigned char op_num, op_type;
307}; 307};
308 308
309static const struct operator_t ops_table[] = { 309static const struct operator_t ops_table[] ALIGN2 = {
310 { /* "-r" */ FILRD , UNOP }, 310 { /* "-r" */ FILRD , UNOP },
311 { /* "-w" */ FILWR , UNOP }, 311 { /* "-w" */ FILWR , UNOP },
312 { /* "-x" */ FILEX , UNOP }, 312 { /* "-x" */ FILEX , UNOP },
diff --git a/coreutils/timeout.c b/coreutils/timeout.c
index 06c134a37..204a7ab92 100644
--- a/coreutils/timeout.c
+++ b/coreutils/timeout.c
@@ -41,7 +41,7 @@
41//usage:#define timeout_trivial_usage 41//usage:#define timeout_trivial_usage
42//usage: "[-s SIG] SECS PROG ARGS" 42//usage: "[-s SIG] SECS PROG ARGS"
43//usage:#define timeout_full_usage "\n\n" 43//usage:#define timeout_full_usage "\n\n"
44//usage: "Runs PROG. Sends SIG to it if it is not gone in SECS seconds.\n" 44//usage: "Run PROG. Send SIG to it if it is not gone in SECS seconds.\n"
45//usage: "Default SIG: TERM." 45//usage: "Default SIG: TERM."
46 46
47#include "libbb.h" 47#include "libbb.h"
@@ -130,7 +130,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
130 grandchild: 130 grandchild:
131 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ 131 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
132 while (1) { 132 while (1) {
133 sleep(1); 133 sleep1();
134 if (--timeout <= 0) 134 if (--timeout <= 0)
135 break; 135 break;
136 if (kill(parent, 0)) { 136 if (kill(parent, 0)) {
diff --git a/coreutils/uniq.c b/coreutils/uniq.c
index 317f45531..e1594286f 100644
--- a/coreutils/uniq.c
+++ b/coreutils/uniq.c
@@ -20,7 +20,7 @@
20/* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */ 20/* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */
21 21
22//usage:#define uniq_trivial_usage 22//usage:#define uniq_trivial_usage
23//usage: "[-cdu][-f,s,w N] [INPUT [OUTPUT]]" 23//usage: "[-cdui] [-f,s,w N] [INPUT [OUTPUT]]"
24//usage:#define uniq_full_usage "\n\n" 24//usage:#define uniq_full_usage "\n\n"
25//usage: "Discard duplicate lines\n" 25//usage: "Discard duplicate lines\n"
26//usage: "\n -c Prefix lines by the number of occurrences" 26//usage: "\n -c Prefix lines by the number of occurrences"
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c
index 5b2edd649..164b208ea 100644
--- a/coreutils/uudecode.c
+++ b/coreutils/uudecode.c
@@ -168,9 +168,11 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv)
168} 168}
169#endif 169#endif
170 170
171//applet:IF_BASE64(APPLET(base64, BB_DIR_BIN, BB_SUID_DROP)) 171//config:config BASE32
172 172//config: bool "base32 (4.9 kb)"
173//kbuild:lib-$(CONFIG_BASE64) += uudecode.o 173//config: default y
174//config: help
175//config: Base32 encode and decode
174 176
175//config:config BASE64 177//config:config BASE64
176//config: bool "base64 (4.9 kb)" 178//config: bool "base64 (4.9 kb)"
@@ -178,49 +180,165 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv)
178//config: help 180//config: help
179//config: Base64 encode and decode 181//config: Base64 encode and decode
180 182
183//usage:#define base32_trivial_usage
184//usage: "[-d] [-w COL] [FILE]"
185//usage:#define base32_full_usage "\n\n"
186//usage: "Base32 encode or decode FILE to standard output"
187//usage: "\n -d Decode data"
188//usage: "\n -w COL Wrap lines at COL (default 76, 0 disables)"
189////usage: "\n -i When decoding, ignore non-alphabet characters"
190
181//usage:#define base64_trivial_usage 191//usage:#define base64_trivial_usage
182//usage: "[-d] [FILE]" 192//usage: "[-d] [-w COL] [FILE]"
183//usage:#define base64_full_usage "\n\n" 193//usage:#define base64_full_usage "\n\n"
184//usage: "Base64 encode or decode FILE to standard output" 194//usage: "Base64 encode or decode FILE to standard output"
185//usage: "\n -d Decode data" 195//usage: "\n -d Decode data"
186////usage: "\n -w COL Wrap lines at COL (default 76, 0 disables)" 196//usage: "\n -w COL Wrap lines at COL (default 76, 0 disables)"
187////usage: "\n -i When decoding, ignore non-alphabet characters" 197////usage: "\n -i When decoding, ignore non-alphabet characters"
188 198
189#if ENABLE_BASE64 199// APPLET_ODDNAME:name main location suid_type help
190int base64_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 200//applet:IF_BASE32(APPLET_ODDNAME(base32, baseNUM, BB_DIR_BIN, BB_SUID_DROP, base32))
191int base64_main(int argc UNUSED_PARAM, char **argv) 201//applet:IF_BASE64(APPLET_ODDNAME(base64, baseNUM, BB_DIR_BIN, BB_SUID_DROP, base64))
202
203//kbuild:lib-$(CONFIG_BASE64) += uudecode.o
204//kbuild:lib-$(CONFIG_BASE32) += uudecode.o
205
206#if ENABLE_BASE32 || ENABLE_BASE64
207
208# if ENABLE_BASE32
209static void bb_b32encode(char *p, const void *src, int length)
210{
211#define tbl bb_uuenc_tbl_base32
212 const unsigned char *s = src;
213
214 /* Transform 5x8 bits to 8x5 bits */
215 while (length > 0) {
216 unsigned cur, next;
217
218 length--;
219 cur = *s++;
220 *p++ = tbl[cur >> 3]; // xxxxx--- -------- -------- -------- --------
221 cur &= 7;
222
223 next = 0;
224 if (--length >= 0)
225 next = *s++;
226 *p++ = tbl[(cur << 2) + (next >> 6)]; // -----xxx xx------ -------- -------- --------
227 cur = next & 0x3f;
228
229 *p++ = tbl[cur >> 1]; // -------- --xxxxx- -------- -------- --------
230 cur &= 1;
231
232 next = 0;
233 if (--length >= 0)
234 next = *s++;
235 *p++ = tbl[(cur << 4) + (next >> 4)]; // -------- -------x xxxx---- -------- --------
236 cur = next & 0xf;
237
238 next = 0;
239 if (--length >= 0)
240 next = *s++;
241 *p++ = tbl[(cur << 1) + (next >> 7)]; // -------- -------- ----xxxx x------- --------
242 cur = next & 0x7f;
243
244 *p++ = tbl[cur >> 2]; // -------- -------- -------- -xxxxx-- --------
245 cur &= 3;
246
247 next = 0;
248 if (--length >= 0)
249 next = *s++;
250 *p++ = tbl[(cur << 3) + (next >> 5)]; // -------- -------- -------- ------xx xxx-----
251 cur = next & 0x1f;
252
253 *p++ = tbl[cur]; // -------- -------- -------- -------- ---xxxxx
254 }
255#undef tbl
256 /* Zero-terminate */
257 *p = '\0';
258 /* Pad as necessary */
259 length = ((-length) * 3) >> 1; /* -4 => 6 pad chars, -3 => 4, -2 => 3, -1 => 1 */
260 while (length--) {
261 *--p = '=';
262 }
263}
264# else
265void bb_b32encode(char *p, const void *src, int length); /* undefined */
266# endif
267
268int baseNUM_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
269int baseNUM_main(int argc UNUSED_PARAM, char **argv)
192{ 270{
193 FILE *src_stream; 271 FILE *src_stream;
194 unsigned opts; 272 unsigned opts;
273 unsigned col = 76;
195 274
196 opts = getopt32(argv, "^" "d" "\0" "?1"/* 1 arg max*/); 275 opts = getopt32(argv, "^" "dw:+" "\0" "?1"/* 1 arg max*/, &col);
197 argv += optind; 276 argv += optind;
198 277
199 if (!argv[0]) 278 if (!argv[0])
200 *--argv = (char*)"-"; 279 *--argv = (char*)"-";
201 src_stream = xfopen_stdin(argv[0]); 280 src_stream = xfopen_stdin(argv[0]);
202 if (opts) { 281 if (opts & 1) {
203 read_base64(src_stream, stdout, /*flags:*/ (unsigned char)EOF); 282 /* -d: decode */
283 int flags = (unsigned char)EOF;
284 if (ENABLE_BASE32 && (!ENABLE_BASE64 || applet_name[4] == '3'))
285 flags = ((unsigned char)EOF) | BASE64_32;
286 read_base64(src_stream, stdout, flags);
204 } else { 287 } else {
205 enum { 288 enum {
206 SRC_BUF_SIZE = 76 / 4 * 3, /* this *MUST* be a multiple of 3 */ 289 SRC_BUF_SIZE = 3 * 5 * 32, /* this *MUST* be a multiple of 3 and 5 */
207 DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), 290 DST_BUF_SIZE = 8 * ((SRC_BUF_SIZE + 4) / 5), /* max growth on encode (base32 case) */
208 }; 291 };
209 char src_buf[SRC_BUF_SIZE]; 292 /* Use one buffer for both input and output:
210 char dst_buf[DST_BUF_SIZE + 1]; 293 * encoding reads input "left-to-right",
211 int src_fd = fileno(src_stream); 294 * it's safe to place source at the end of the buffer and
295 * overwrite it while encoding, just be careful to have a gap.
296 */
297 char dst_buf[((DST_BUF_SIZE + /*gap:*/ 16) /*round up to 16:*/ | 0xf) + 1];
298#define src_buf (dst_buf + sizeof(dst_buf) - SRC_BUF_SIZE)
299 int src_fd, rem;
300
301 src_fd = fileno(src_stream);
302 rem = 0;
212 while (1) { 303 while (1) {
213 size_t size = full_read(src_fd, src_buf, SRC_BUF_SIZE); 304 size_t size = full_read(src_fd, src_buf, SRC_BUF_SIZE);
214 if (!size)
215 break;
216 if ((ssize_t)size < 0) 305 if ((ssize_t)size < 0)
217 bb_simple_perror_msg_and_die(bb_msg_read_error); 306 bb_simple_perror_msg_and_die(bb_msg_read_error);
307 if (size == 0) {
308 if (rem != 0) bb_putchar('\n');
309 break;
310 }
311
218 /* Encode the buffer we just read in */ 312 /* Encode the buffer we just read in */
219 bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64); 313 if (ENABLE_BASE32 && (!ENABLE_BASE64 || applet_name[4] == '3')) {
220 xwrite(STDOUT_FILENO, dst_buf, 4 * ((size + 2) / 3)); 314 bb_b32encode(dst_buf, src_buf, size);
221 bb_putchar('\n'); 315 size = 8 * ((size + 4) / 5);
222 fflush(stdout); 316 } else {
317 bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64);
318 size = 4 * ((size + 2) / 3);
319 }
320
321 if (col == 0) {
322 fputs(dst_buf, stdout);
323 } else {
324 char *result = dst_buf;
325 if (rem == 0)
326 rem = col;
327 while (1) {
328 int out = size < rem ? size : rem;
329 rem -= out;
330 printf(rem != 0 ? "%.*s" : "%.*s\n", out, result);
331 if (rem != 0)
332 break;
333 size -= out;
334 if (size == 0)
335 break;
336 result += out;
337 rem = col;
338 }
339 }
223 } 340 }
341#undef src_buf
224 } 342 }
225 343
226 fflush_stdout_and_exit(EXIT_SUCCESS); 344 fflush_stdout_and_exit(EXIT_SUCCESS);
diff --git a/debianutils/which.c b/debianutils/which.c
index 1d23786b8..f5ea17198 100644
--- a/debianutils/which.c
+++ b/debianutils/which.c
@@ -17,9 +17,9 @@
17//kbuild:lib-$(CONFIG_WHICH) += which.o 17//kbuild:lib-$(CONFIG_WHICH) += which.o
18 18
19//usage:#define which_trivial_usage 19//usage:#define which_trivial_usage
20//usage: "[COMMAND]..." 20//usage: "COMMAND..."
21//usage:#define which_full_usage "\n\n" 21//usage:#define which_full_usage "\n\n"
22//usage: "Locate a COMMAND" 22//usage: "Locate COMMAND"
23//usage: 23//usage:
24//usage:#define which_example_usage 24//usage:#define which_example_usage
25//usage: "$ which login\n" 25//usage: "$ which login\n"
diff --git a/e2fsprogs/e2fs_lib.c b/e2fsprogs/e2fs_lib.c
index 3b776bc97..d0cacf14c 100644
--- a/e2fsprogs/e2fs_lib.c
+++ b/e2fsprogs/e2fs_lib.c
@@ -159,7 +159,7 @@ int fgetsetflags(const char *name, unsigned long *get_flags, unsigned long set_f
159 159
160#if !ENABLE_PLATFORM_MINGW32 160#if !ENABLE_PLATFORM_MINGW32
161/* Print file attributes on an ext2 file system */ 161/* Print file attributes on an ext2 file system */
162const uint32_t e2attr_flags_value[] = { 162const uint32_t e2attr_flags_value[] ALIGN4 = {
163#ifdef ENABLE_COMPRESSION 163#ifdef ENABLE_COMPRESSION
164 EXT2_COMPRBLK_FL, 164 EXT2_COMPRBLK_FL,
165 EXT2_DIRTY_FL, 165 EXT2_DIRTY_FL,
diff --git a/e2fsprogs/fsck.c b/e2fsprogs/fsck.c
index fc53a9043..96c1e51e0 100644
--- a/e2fsprogs/fsck.c
+++ b/e2fsprogs/fsck.c
@@ -480,7 +480,7 @@ static int wait_one(int flags)
480 * time to set up the signal handler 480 * time to set up the signal handler
481 */ 481 */
482 if (inst2->start_time >= time(NULL) - 1) 482 if (inst2->start_time >= time(NULL) - 1)
483 sleep(1); 483 sleep1();
484 kill(inst2->pid, SIGUSR1); 484 kill(inst2->pid, SIGUSR1);
485 inst2->flags |= FLAG_PROGRESS; 485 inst2->flags |= FLAG_PROGRESS;
486 break; 486 break;
diff --git a/editors/awk.c b/editors/awk.c
index 509f4ddd8..4799091ec 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -405,7 +405,7 @@ static const char tokenlist[] ALIGN1 =
405 405
406#define OC_B OC_BUILTIN 406#define OC_B OC_BUILTIN
407 407
408static const uint32_t tokeninfo[] = { 408static const uint32_t tokeninfo[] ALIGN4 = {
409 0, 409 0,
410 0, 410 0,
411 OC_REGEXP, 411 OC_REGEXP,
@@ -1767,12 +1767,34 @@ static void fsrealloc(int size)
1767 nfields = size; 1767 nfields = size;
1768} 1768}
1769 1769
1770static int regexec1_nonempty(const regex_t *preg, const char *s, regmatch_t pmatch[])
1771{
1772 int r = regexec(preg, s, 1, pmatch, 0);
1773 if (r == 0 && pmatch[0].rm_eo == 0) {
1774 /* For example, happens when FS can match
1775 * an empty string (awk -F ' *'). Logically,
1776 * this should split into one-char fields.
1777 * However, gawk 5.0.1 searches for first
1778 * _non-empty_ separator string match:
1779 */
1780 size_t ofs = 0;
1781 do {
1782 ofs++;
1783 if (!s[ofs])
1784 return REG_NOMATCH;
1785 regexec(preg, s + ofs, 1, pmatch, 0);
1786 } while (pmatch[0].rm_eo == 0);
1787 pmatch[0].rm_so += ofs;
1788 pmatch[0].rm_eo += ofs;
1789 }
1790 return r;
1791}
1792
1770static int awk_split(const char *s, node *spl, char **slist) 1793static int awk_split(const char *s, node *spl, char **slist)
1771{ 1794{
1772 int l, n; 1795 int n;
1773 char c[4]; 1796 char c[4];
1774 char *s1; 1797 char *s1;
1775 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
1776 1798
1777 /* in worst case, each char would be a separate field */ 1799 /* in worst case, each char would be a separate field */
1778 *slist = s1 = xzalloc(strlen(s) * 2 + 3); 1800 *slist = s1 = xzalloc(strlen(s) * 2 + 3);
@@ -1789,29 +1811,31 @@ static int awk_split(const char *s, node *spl, char **slist)
1789 return n; /* "": zero fields */ 1811 return n; /* "": zero fields */
1790 n++; /* at least one field will be there */ 1812 n++; /* at least one field will be there */
1791 do { 1813 do {
1814 int l;
1815 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
1816
1792 l = strcspn(s, c+2); /* len till next NUL or \n */ 1817 l = strcspn(s, c+2); /* len till next NUL or \n */
1793 if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0 1818 if (regexec1_nonempty(icase ? spl->r.ire : spl->l.re, s, pmatch) == 0
1794 && pmatch[0].rm_so <= l 1819 && pmatch[0].rm_so <= l
1795 ) { 1820 ) {
1821 /* if (pmatch[0].rm_eo == 0) ... - impossible */
1796 l = pmatch[0].rm_so; 1822 l = pmatch[0].rm_so;
1797 if (pmatch[0].rm_eo == 0) {
1798 l++;
1799 pmatch[0].rm_eo++;
1800 }
1801 n++; /* we saw yet another delimiter */ 1823 n++; /* we saw yet another delimiter */
1802 } else { 1824 } else {
1803 pmatch[0].rm_eo = l; 1825 pmatch[0].rm_eo = l;
1804 if (s[l]) 1826 if (s[l])
1805 pmatch[0].rm_eo++; 1827 pmatch[0].rm_eo++;
1806 } 1828 }
1807 memcpy(s1, s, l); 1829 s1 = mempcpy(s1, s, l);
1808 /* make sure we remove *all* of the separator chars */ 1830 *s1++ = '\0';
1809 do {
1810 s1[l] = '\0';
1811 } while (++l < pmatch[0].rm_eo);
1812 nextword(&s1);
1813 s += pmatch[0].rm_eo; 1831 s += pmatch[0].rm_eo;
1814 } while (*s); 1832 } while (*s);
1833
1834 /* echo a-- | awk -F-- '{ print NF, length($NF), $NF }'
1835 * should print "2 0 ":
1836 */
1837 *s1 = '\0';
1838
1815 return n; 1839 return n;
1816 } 1840 }
1817 if (c[0] == '\0') { /* null split */ 1841 if (c[0] == '\0') { /* null split */
@@ -2030,7 +2054,7 @@ static ssize_t FAST_FUNC safe_read_strip_cr(int fd, void *buf, size_t count)
2030static int awk_getline(rstream *rsm, var *v) 2054static int awk_getline(rstream *rsm, var *v)
2031{ 2055{
2032 char *b; 2056 char *b;
2033 regmatch_t pmatch[2]; 2057 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
2034 int size, a, p, pp = 0; 2058 int size, a, p, pp = 0;
2035 int fd, so, eo, r, rp; 2059 int fd, so, eo, r, rp;
2036 char c, *m, *s; 2060 char c, *m, *s;
diff --git a/editors/patch.c b/editors/patch.c
index aaa253591..110176630 100644
--- a/editors/patch.c
+++ b/editors/patch.c
@@ -31,7 +31,7 @@
31//kbuild:lib-$(CONFIG_PATCH) += patch.o 31//kbuild:lib-$(CONFIG_PATCH) += patch.o
32 32
33//usage:#define patch_trivial_usage 33//usage:#define patch_trivial_usage
34//usage: "[OPTIONS] [ORIGFILE [PATCHFILE]]" 34//usage: "[-RNE] [-p N] [-i DIFF] [ORIGFILE [PATCHFILE]]"
35//usage:#define patch_full_usage "\n\n" 35//usage:#define patch_full_usage "\n\n"
36//usage: " -p N Strip N leading components from file names" 36//usage: " -p N Strip N leading components from file names"
37//usage: "\n -i DIFF Read DIFF instead of stdin" 37//usage: "\n -i DIFF Read DIFF instead of stdin"
diff --git a/editors/vi.c b/editors/vi.c
index 131c018a2..bfe05d613 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -166,7 +166,7 @@
166//kbuild:lib-$(CONFIG_VI) += vi.o 166//kbuild:lib-$(CONFIG_VI) += vi.o
167 167
168//usage:#define vi_trivial_usage 168//usage:#define vi_trivial_usage
169//usage: "[OPTIONS] [FILE]..." 169//usage: IF_FEATURE_VI_COLON("[-c CMD] ")IF_FEATURE_VI_READONLY("[-R] ")"[FILE]..."
170//usage:#define vi_full_usage "\n\n" 170//usage:#define vi_full_usage "\n\n"
171//usage: "Edit FILE\n" 171//usage: "Edit FILE\n"
172//usage: IF_FEATURE_VI_COLON( 172//usage: IF_FEATURE_VI_COLON(
diff --git a/examples/inetd.conf b/examples/inetd.conf
index ca7e3d8e1..78b10e3ac 100644
--- a/examples/inetd.conf
+++ b/examples/inetd.conf
@@ -31,7 +31,7 @@ time dgram udp wait root internal
31#ftp stream tcp nowait root /usr/sbin/tcpd in.ftpd 31#ftp stream tcp nowait root /usr/sbin/tcpd in.ftpd
32#telnet stream tcp nowait root /sbin/telnetd /sbin/telnetd 32#telnet stream tcp nowait root /sbin/telnetd /sbin/telnetd
33#nntp stream tcp nowait root tcpd in.nntpd 33#nntp stream tcp nowait root tcpd in.nntpd
34#smtp stream tcp nowait root tcpd sendmail -v 34#smtp stream tcp nowait root tcpd sendmail -v
35# 35#
36# Shell, login, exec and talk are BSD protocols. 36# Shell, login, exec and talk are BSD protocols.
37# 37#
diff --git a/examples/udhcp/sample.bound b/examples/udhcp/sample.bound
index efd98cf15..15a7775e9 100755
--- a/examples/udhcp/sample.bound
+++ b/examples/udhcp/sample.bound
@@ -6,12 +6,12 @@ RESOLV_CONF="/etc/udhcpc/resolv.conf"
6[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" 6[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
7[ -n "$subnet" ] && NETMASK="netmask $subnet" 7[ -n "$subnet" ] && NETMASK="netmask $subnet"
8 8
9/sbin/ifconfig $interface $ip $BROADCAST $NETMASK 9ifconfig $interface $ip $BROADCAST $NETMASK
10 10
11if [ -n "$router" ] 11if [ -n "$router" ]
12then 12then
13 echo "deleting routers" 13 echo "deleting routers"
14 while /sbin/route del default gw 0.0.0.0 dev $interface 14 while route del default gw 0.0.0.0 dev $interface
15 do : 15 do :
16 done 16 done
17 17
@@ -23,9 +23,9 @@ then
23 # /32 instructs kernel to always use routing for all outgoing packets 23 # /32 instructs kernel to always use routing for all outgoing packets
24 # (they can never be sent to local subnet - there is no local subnet for /32). 24 # (they can never be sent to local subnet - there is no local subnet for /32).
25 # Used in datacenters, avoids the need for private ip-addresses between two hops. 25 # Used in datacenters, avoids the need for private ip-addresses between two hops.
26 /sbin/ip route add $i dev $interface 26 ip route add $i dev $interface
27 fi 27 fi
28 /sbin/route add default gw $i dev $interface metric $((metric++)) 28 route add default gw $i dev $interface metric $((metric++))
29 done 29 done
30fi 30fi
31 31
diff --git a/examples/udhcp/sample.deconfig b/examples/udhcp/sample.deconfig
index b221bcf12..a893de83f 100755
--- a/examples/udhcp/sample.deconfig
+++ b/examples/udhcp/sample.deconfig
@@ -1,4 +1,4 @@
1#!/bin/sh 1#!/bin/sh
2# Sample udhcpc deconfig script 2# Sample udhcpc deconfig script
3 3
4/sbin/ifconfig $interface 0.0.0.0 4ifconfig $interface 0.0.0.0
diff --git a/examples/udhcp/sample.renew b/examples/udhcp/sample.renew
index efd98cf15..15a7775e9 100755
--- a/examples/udhcp/sample.renew
+++ b/examples/udhcp/sample.renew
@@ -6,12 +6,12 @@ RESOLV_CONF="/etc/udhcpc/resolv.conf"
6[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" 6[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
7[ -n "$subnet" ] && NETMASK="netmask $subnet" 7[ -n "$subnet" ] && NETMASK="netmask $subnet"
8 8
9/sbin/ifconfig $interface $ip $BROADCAST $NETMASK 9ifconfig $interface $ip $BROADCAST $NETMASK
10 10
11if [ -n "$router" ] 11if [ -n "$router" ]
12then 12then
13 echo "deleting routers" 13 echo "deleting routers"
14 while /sbin/route del default gw 0.0.0.0 dev $interface 14 while route del default gw 0.0.0.0 dev $interface
15 do : 15 do :
16 done 16 done
17 17
@@ -23,9 +23,9 @@ then
23 # /32 instructs kernel to always use routing for all outgoing packets 23 # /32 instructs kernel to always use routing for all outgoing packets
24 # (they can never be sent to local subnet - there is no local subnet for /32). 24 # (they can never be sent to local subnet - there is no local subnet for /32).
25 # Used in datacenters, avoids the need for private ip-addresses between two hops. 25 # Used in datacenters, avoids the need for private ip-addresses between two hops.
26 /sbin/ip route add $i dev $interface 26 ip route add $i dev $interface
27 fi 27 fi
28 /sbin/route add default gw $i dev $interface metric $((metric++)) 28 route add default gw $i dev $interface metric $((metric++))
29 done 29 done
30fi 30fi
31 31
diff --git a/findutils/find.c b/findutils/find.c
index f26c01c1e..188865e05 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -1445,7 +1445,7 @@ static action*** parse_params(char **argv)
1445#else 1445#else
1446#define XATOU_SFX xatoul_sfx 1446#define XATOU_SFX xatoul_sfx
1447#endif 1447#endif
1448 static const struct suffix_mult find_suffixes[] = { 1448 static const struct suffix_mult find_suffixes[] ALIGN_SUFFIX = {
1449 { "c", 1 }, 1449 { "c", 1 },
1450 { "w", 2 }, 1450 { "w", 2 },
1451 { "", 512 }, 1451 { "", 512 },
@@ -1526,7 +1526,7 @@ int find_main(int argc UNUSED_PARAM, char **argv)
1526 } 1526 }
1527 *past_HLP = NULL; 1527 *past_HLP = NULL;
1528 /* "+": stop on first non-option */ 1528 /* "+": stop on first non-option */
1529 i = getopt32(argv, "+HLP"); 1529 i = getopt32(argv, "+""HLP");
1530 if (i & (1<<0)) 1530 if (i & (1<<0))
1531 G.recurse_flags |= ACTION_FOLLOWLINKS_L0 | ACTION_DANGLING_OK; 1531 G.recurse_flags |= ACTION_FOLLOWLINKS_L0 | ACTION_DANGLING_OK;
1532 if (i & (1<<1)) 1532 if (i & (1<<1))
diff --git a/include/ar.h b/include/ar_.h
index 386fe0456..386fe0456 100644
--- a/include/ar.h
+++ b/include/ar_.h
diff --git a/include/libbb.h b/include/libbb.h
index eb8b63895..3d6a6a0cf 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -106,7 +106,11 @@
106# define updwtmpx updwtmp 106# define updwtmpx updwtmp
107# define _PATH_UTMPX _PATH_UTMP 107# define _PATH_UTMPX _PATH_UTMP
108# else 108# else
109# include <utmp.h> 109# if !defined(__FreeBSD__)
110# include <utmp.h>
111# else
112# define _PATH_UTMPX "/var/run/utx.active"
113# endif
110# include <utmpx.h> 114# include <utmpx.h>
111# if defined _PATH_UTMP && !defined _PATH_UTMPX 115# if defined _PATH_UTMP && !defined _PATH_UTMPX
112# define _PATH_UTMPX _PATH_UTMP 116# define _PATH_UTMPX _PATH_UTMP
@@ -405,6 +409,32 @@ void* xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx) F
405char *xstrdup(const char *s) FAST_FUNC RETURNS_MALLOC; 409char *xstrdup(const char *s) FAST_FUNC RETURNS_MALLOC;
406char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC; 410char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC;
407void *xmemdup(const void *s, int n) FAST_FUNC RETURNS_MALLOC; 411void *xmemdup(const void *s, int n) FAST_FUNC RETURNS_MALLOC;
412void *mmap_read(int fd, size_t size) FAST_FUNC;
413void *mmap_anon(size_t size) FAST_FUNC;
414void *xmmap_anon(size_t size) FAST_FUNC;
415
416#if defined(__x86_64__) || defined(i386)
417# define BB_ARCH_FIXED_PAGESIZE 4096
418#elif defined(__arm__) /* only 32bit, 64bit ARM has variable page size */
419# define BB_ARCH_FIXED_PAGESIZE 4096
420#else /* if defined(ARCH) */
421/* add you favorite arch today! */
422//From Linux kernel inspection:
423//xtenza,s390[x],riscv,nios2,csky,sparc32: fixed 4k pages
424//sparc64,alpha,openrisc: fixed 8k pages
425#endif
426
427#if defined BB_ARCH_FIXED_PAGESIZE
428# define IF_VARIABLE_ARCH_PAGESIZE(...) /*nothing*/
429# define bb_getpagesize() BB_ARCH_FIXED_PAGESIZE
430# define INIT_PAGESIZE(var) ((void)0)
431# define cached_pagesize(var) BB_ARCH_FIXED_PAGESIZE
432#else
433# define IF_VARIABLE_ARCH_PAGESIZE(...) __VA_ARGS__
434# define bb_getpagesize() getpagesize()
435# define INIT_PAGESIZE(var) ((var) = getpagesize())
436# define cached_pagesize(var) (var)
437#endif
408 438
409 439
410//TODO: supply a pointer to char[11] buffer (avoid statics)? 440//TODO: supply a pointer to char[11] buffer (avoid statics)?
@@ -670,6 +700,9 @@ void parse_datestr(const char *date_str, struct tm *ptm) FAST_FUNC;
670time_t validate_tm_time(const char *date_str, struct tm *ptm) FAST_FUNC; 700time_t validate_tm_time(const char *date_str, struct tm *ptm) FAST_FUNC;
671char *strftime_HHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC; 701char *strftime_HHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC;
672char *strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC; 702char *strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC;
703void xgettimeofday(struct timeval *tv) FAST_FUNC;
704void xsettimeofday(const struct timeval *tv) FAST_FUNC;
705
673 706
674int xsocket(int domain, int type, int protocol) FAST_FUNC; 707int xsocket(int domain, int type, int protocol) FAST_FUNC;
675void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC; 708void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC;
@@ -1065,8 +1098,9 @@ void generate_uuid(uint8_t *buf) FAST_FUNC;
1065/* Last element is marked by mult == 0 */ 1098/* Last element is marked by mult == 0 */
1066struct suffix_mult { 1099struct suffix_mult {
1067 char suffix[4]; 1100 char suffix[4];
1068 unsigned mult; 1101 uint32_t mult;
1069}; 1102};
1103#define ALIGN_SUFFIX ALIGN4
1070extern const struct suffix_mult bkm_suffixes[]; 1104extern const struct suffix_mult bkm_suffixes[];
1071#define km_suffixes (bkm_suffixes + 1) 1105#define km_suffixes (bkm_suffixes + 1)
1072extern const struct suffix_mult cwbkMG_suffixes[]; 1106extern const struct suffix_mult cwbkMG_suffixes[];
@@ -1178,7 +1212,6 @@ int BB_EXECVP(const char *file, char *const argv[]) FAST_FUNC;
1178#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd,__VA_ARGS__) 1212#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd,__VA_ARGS__)
1179#endif 1213#endif
1180void BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC; 1214void BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC;
1181void exec_prog_or_SHELL(char **argv) NORETURN FAST_FUNC;
1182 1215
1183/* xvfork() can't be a _function_, return after vfork in child mangles stack 1216/* xvfork() can't be a _function_, return after vfork in child mangles stack
1184 * in the parent. It must be a macro. */ 1217 * in the parent. It must be a macro. */
@@ -1644,12 +1677,14 @@ char *bb_simplify_path(const char *path) FAST_FUNC;
1644/* Returns ptr to NUL */ 1677/* Returns ptr to NUL */
1645char *bb_simplify_abs_path_inplace(char *path) FAST_FUNC; 1678char *bb_simplify_abs_path_inplace(char *path) FAST_FUNC;
1646 1679
1647#ifndef LOGIN_FAIL_DELAY 1680void pause_after_failed_login(void) FAST_FUNC;
1648#define LOGIN_FAIL_DELAY 3 1681void bb_do_delay(unsigned seconds) FAST_FUNC;
1649#endif 1682void msleep(unsigned ms) FAST_FUNC;
1650extern void bb_do_delay(int seconds) FAST_FUNC; 1683void sleep1(void) FAST_FUNC;
1651extern void change_identity(const struct passwd *pw) FAST_FUNC; 1684void change_identity(const struct passwd *pw) FAST_FUNC;
1652extern void run_shell(const char *shell, int loginshell, const char **args) NORETURN FAST_FUNC; 1685void exec_shell(const char *shell, int loginshell, const char **args) NORETURN FAST_FUNC;
1686void exec_login_shell(const char *shell) NORETURN FAST_FUNC;
1687void exec_prog_or_SHELL(char **argv) NORETURN FAST_FUNC;
1653 1688
1654/* Returns $SHELL, getpwuid(getuid())->pw_shell, or DEFAULT_SHELL. 1689/* Returns $SHELL, getpwuid(getuid())->pw_shell, or DEFAULT_SHELL.
1655 * Note that getpwuid result might need xstrdup'ing 1690 * Note that getpwuid result might need xstrdup'ing
@@ -1884,14 +1919,20 @@ typedef const char *get_exe_name_t(int i) FAST_FUNC;
1884typedef struct line_input_t { 1919typedef struct line_input_t {
1885 int flags; 1920 int flags;
1886 int timeout; 1921 int timeout;
1922# if ENABLE_FEATURE_TAB_COMPLETION
1923# if ENABLE_SHELL_ASH
1887 const char *path_lookup; 1924 const char *path_lookup;
1888# if ENABLE_FEATURE_TAB_COMPLETION \ 1925# define EDITING_HAS_path_lookup 1
1889&& (ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH \ 1926# else
1890|| ENABLE_HUSH || ENABLE_SH_IS_HUSH || ENABLE_BASH_IS_HUSH \ 1927# define EDITING_HAS_path_lookup 0
1891) 1928# endif
1929# if ENABLE_SHELL_ASH || ENABLE_SHELL_HUSH
1892 /* function to fetch additional application-specific names to match */ 1930 /* function to fetch additional application-specific names to match */
1893 get_exe_name_t *get_exe_name; 1931 get_exe_name_t *get_exe_name;
1894# define EDITING_HAS_get_exe_name 1 1932# define EDITING_HAS_get_exe_name 1
1933# else
1934# define EDITING_HAS_get_exe_name 0
1935# endif
1895# endif 1936# endif
1896# if MAX_HISTORY 1937# if MAX_HISTORY
1897 int cnt_history; 1938 int cnt_history;
@@ -1919,7 +1960,11 @@ enum {
1919 FOR_SHELL = DO_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION, 1960 FOR_SHELL = DO_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION,
1920}; 1961};
1921line_input_t *new_line_input_t(int flags) FAST_FUNC; 1962line_input_t *new_line_input_t(int flags) FAST_FUNC;
1963#if ENABLE_FEATURE_EDITING_SAVEHISTORY
1922void free_line_input_t(line_input_t *n) FAST_FUNC; 1964void free_line_input_t(line_input_t *n) FAST_FUNC;
1965#else
1966# define free_line_input_t(n) free(n)
1967#endif
1923/* 1968/*
1924 * maxsize must be >= 2. 1969 * maxsize must be >= 2.
1925 * Returns: 1970 * Returns:
@@ -2079,14 +2124,17 @@ char *percent_decode_in_place(char *str, int strict) FAST_FUNC;
2079 2124
2080 2125
2081extern const char bb_uuenc_tbl_base64[] ALIGN1; 2126extern const char bb_uuenc_tbl_base64[] ALIGN1;
2127extern const char bb_uuenc_tbl_base32[] ALIGN1;
2082extern const char bb_uuenc_tbl_std[] ALIGN1; 2128extern const char bb_uuenc_tbl_std[] ALIGN1;
2083void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC; 2129void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC;
2084enum { 2130enum {
2085 BASE64_FLAG_UU_STOP = 0x100, 2131 BASE64_FLAG_UU_STOP = 0x100,
2132 BASE64_32 = 0x200, /* base32 */
2086 /* Sign-extends to a value which never matches fgetc result: */ 2133 /* Sign-extends to a value which never matches fgetc result: */
2087 BASE64_FLAG_NO_STOP_CHAR = 0x80, 2134 BASE64_FLAG_NO_STOP_CHAR = 0x80,
2088}; 2135};
2089const char *decode_base64(char **pp_dst, const char *src) FAST_FUNC; 2136char *decode_base64(char *dst, const char **pp_src) FAST_FUNC;
2137char *decode_base32(char *dst, const char **pp_src) FAST_FUNC;
2090void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC; 2138void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC;
2091 2139
2092typedef struct md5_ctx_t { 2140typedef struct md5_ctx_t {
diff --git a/include/mingw.h b/include/mingw.h
index 8af2e3938..d1e638231 100644
--- a/include/mingw.h
+++ b/include/mingw.h
@@ -31,6 +31,7 @@ int inet_pton(int af, const char *src, void *dst);
31#define O_NONBLOCK 0 31#define O_NONBLOCK 0
32#define O_NOFOLLOW 0 32#define O_NOFOLLOW 0
33#define O_NOCTTY 0 33#define O_NOCTTY 0
34#define O_DIRECT 0
34#define O_SPECIAL 0x800000 35#define O_SPECIAL 0x800000
35 36
36/* 37/*
diff --git a/include/platform.h b/include/platform.h
index f1c09c4d2..ea97d2682 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -335,7 +335,7 @@ typedef unsigned smalluint;
335#endif 335#endif
336 336
337/* Define bb_setpgrp */ 337/* Define bb_setpgrp */
338#if defined(__digital__) && defined(__unix__) 338#if (defined(__digital__) && defined(__unix__)) || defined(__FreeBSD__)
339/* use legacy setpgrp(pid_t, pid_t) for now. move to platform.c */ 339/* use legacy setpgrp(pid_t, pid_t) for now. move to platform.c */
340# define bb_setpgrp() do { pid_t __me = getpid(); setpgrp(__me, __me); } while (0) 340# define bb_setpgrp() do { pid_t __me = getpid(); setpgrp(__me, __me); } while (0)
341#else 341#else
@@ -358,6 +358,8 @@ typedef unsigned smalluint;
358# define ALIGN2 358# define ALIGN2
359# define ALIGN4 359# define ALIGN4
360#endif 360#endif
361#define ALIGN8 __attribute__((aligned(8)))
362#define ALIGN_PTR __attribute__((aligned(sizeof(void*))))
361 363
362/* 364/*
363 * For 0.9.29 and svn, __ARCH_USE_MMU__ indicates no-mmu reliably. 365 * For 0.9.29 and svn, __ARCH_USE_MMU__ indicates no-mmu reliably.
diff --git a/include/rtc_.h b/include/rtc_.h
index 750fc20ec..24ff5363f 100644
--- a/include/rtc_.h
+++ b/include/rtc_.h
@@ -11,6 +11,12 @@
11 11
12PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 12PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
13 13
14#if ENABLE_FEATURE_HWCLOCK_ADJTIME_FHS
15# define ADJTIME_PATH "/var/lib/hwclock/adjtime"
16#else
17# define ADJTIME_PATH "/etc/adjtime"
18#endif
19
14int rtc_adjtime_is_utc(void) FAST_FUNC; 20int rtc_adjtime_is_utc(void) FAST_FUNC;
15int rtc_xopen(const char **default_rtc, int flags) FAST_FUNC; 21int rtc_xopen(const char **default_rtc, int flags) FAST_FUNC;
16void rtc_read_tm(struct tm *ptm, int fd) FAST_FUNC; 22void rtc_read_tm(struct tm *ptm, int fd) FAST_FUNC;
diff --git a/include/usage.src.h b/include/usage.src.h
index d22efd3ba..1ac252d1b 100644
--- a/include/usage.src.h
+++ b/include/usage.src.h
@@ -25,6 +25,12 @@
25 " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")" 25 " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")"
26#endif 26#endif
27 27
28#if ENABLE_FEATURE_HWCLOCK_ADJTIME_FHS
29# define ADJTIME_PATH "/var/lib/hwclock/adjtime"
30#else
31# define ADJTIME_PATH "/etc/adjtime"
32#endif
33
28INSERT 34INSERT
29 35
30#define busybox_notes_usage \ 36#define busybox_notes_usage \
diff --git a/init/bootchartd.c b/init/bootchartd.c
index 750f67356..ae1ee9d9a 100644
--- a/init/bootchartd.c
+++ b/init/bootchartd.c
@@ -218,10 +218,10 @@ static char *make_tempdir(void)
218 218
219static void do_logging(unsigned sample_period_us, int process_accounting) 219static void do_logging(unsigned sample_period_us, int process_accounting)
220{ 220{
221 FILE *proc_stat = xfopen("proc_stat.log", "w"); 221 FILE *proc_stat = xfopen_for_write("proc_stat.log");
222 FILE *proc_diskstats = xfopen("proc_diskstats.log", "w"); 222 FILE *proc_diskstats = xfopen_for_write("proc_diskstats.log");
223 //FILE *proc_netdev = xfopen("proc_netdev.log", "w"); 223 //FILE *proc_netdev = xfopen_for_write("proc_netdev.log");
224 FILE *proc_ps = xfopen("proc_ps.log", "w"); 224 FILE *proc_ps = xfopen_for_write("proc_ps.log");
225 int look_for_login_process = (getppid() == 1); 225 int look_for_login_process = (getppid() == 1);
226 unsigned count = 60*1000*1000 / sample_period_us; /* ~1 minute */ 226 unsigned count = 60*1000*1000 / sample_period_us; /* ~1 minute */
227 227
@@ -268,7 +268,7 @@ static void finalize(char *tempdir, const char *prog, int process_accounting)
268 //local pacct= 268 //local pacct=
269 //[ -e kernel_pacct ] && pacct=kernel_pacct 269 //[ -e kernel_pacct ] && pacct=kernel_pacct
270 270
271 FILE *header_fp = xfopen("header", "w"); 271 FILE *header_fp = xfopen_for_write("header");
272 272
273 if (process_accounting) 273 if (process_accounting)
274 acct(NULL); 274 acct(NULL);
diff --git a/init/halt.c b/init/halt.c
index 785c38130..fe3cb9e75 100644
--- a/init/halt.c
+++ b/init/halt.c
@@ -65,7 +65,7 @@
65//kbuild:lib-$(CONFIG_REBOOT) += halt.o 65//kbuild:lib-$(CONFIG_REBOOT) += halt.o
66 66
67//usage:#define halt_trivial_usage 67//usage:#define halt_trivial_usage
68//usage: "[-d DELAY] [-n] [-f]" IF_FEATURE_WTMP(" [-w]") 68//usage: "[-d DELAY] [-nf"IF_FEATURE_WTMP("w")"]"
69//usage:#define halt_full_usage "\n\n" 69//usage:#define halt_full_usage "\n\n"
70//usage: "Halt the system\n" 70//usage: "Halt the system\n"
71//usage: "\n -d SEC Delay interval" 71//usage: "\n -d SEC Delay interval"
@@ -76,7 +76,7 @@
76//usage: ) 76//usage: )
77//usage: 77//usage:
78//usage:#define poweroff_trivial_usage 78//usage:#define poweroff_trivial_usage
79//usage: "[-d DELAY] [-n] [-f]" 79//usage: "[-d DELAY] [-nf]"
80//usage:#define poweroff_full_usage "\n\n" 80//usage:#define poweroff_full_usage "\n\n"
81//usage: "Halt and shut off power\n" 81//usage: "Halt and shut off power\n"
82//usage: "\n -d SEC Delay interval" 82//usage: "\n -d SEC Delay interval"
@@ -84,7 +84,7 @@
84//usage: "\n -f Force (don't go through init)" 84//usage: "\n -f Force (don't go through init)"
85//usage: 85//usage:
86//usage:#define reboot_trivial_usage 86//usage:#define reboot_trivial_usage
87//usage: "[-d DELAY] [-n] [-f]" 87//usage: "[-d DELAY] [-nf]"
88//usage:#define reboot_full_usage "\n\n" 88//usage:#define reboot_full_usage "\n\n"
89//usage: "Reboot the system\n" 89//usage: "Reboot the system\n"
90//usage: "\n -d SEC Delay interval" 90//usage: "\n -d SEC Delay interval"
@@ -144,14 +144,14 @@ static int init_was_not_there(void)
144 */ 144 */
145#if 0 145#if 0
146 while (kill(1, 0) != 0 && --cnt >= 0) 146 while (kill(1, 0) != 0 && --cnt >= 0)
147 sleep(1); 147 sleep1();
148#endif 148#endif
149 /* ... so let's wait for some evidence a usual startup event, 149 /* ... so let's wait for some evidence a usual startup event,
150 * mounting of /proc, happened. By that time init should be ready 150 * mounting of /proc, happened. By that time init should be ready
151 * for signals. 151 * for signals.
152 */ 152 */
153 while (access("/proc/meminfo", F_OK) != 0 && --cnt >= 0) 153 while (access("/proc/meminfo", F_OK) != 0 && --cnt >= 0)
154 sleep(1); 154 sleep1();
155 155
156 /* Does it look like init wasn't there? */ 156 /* Does it look like init wasn't there? */
157 return (cnt != initial - 1); 157 return (cnt != initial - 1);
diff --git a/init/init.c b/init/init.c
index 28775a65c..efab5dcb4 100644
--- a/init/init.c
+++ b/init/init.c
@@ -736,7 +736,7 @@ static void pause_and_low_level_reboot(unsigned magic)
736 pid_t pid; 736 pid_t pid;
737 737
738 /* Allow time for last message to reach serial console, etc */ 738 /* Allow time for last message to reach serial console, etc */
739 sleep(1); 739 sleep1();
740 740
741 /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS) 741 /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS)
742 * in linux/kernel/sys.c, which can cause the machine to panic when 742 * in linux/kernel/sys.c, which can cause the machine to panic when
@@ -751,7 +751,7 @@ static void pause_and_low_level_reboot(unsigned magic)
751 * we would eternally sleep here - not what we want. 751 * we would eternally sleep here - not what we want.
752 */ 752 */
753 waitpid(pid, NULL, 0); 753 waitpid(pid, NULL, 0);
754 sleep(1); /* paranoia */ 754 sleep1(); /* paranoia */
755 _exit(EXIT_SUCCESS); 755 _exit(EXIT_SUCCESS);
756} 756}
757 757
@@ -768,12 +768,12 @@ static void run_shutdown_and_kill_processes(void)
768 kill(-1, SIGTERM); 768 kill(-1, SIGTERM);
769 message(L_CONSOLE, "Sent SIG%s to all processes", "TERM"); 769 message(L_CONSOLE, "Sent SIG%s to all processes", "TERM");
770 sync(); 770 sync();
771 sleep(1); 771 sleep1();
772 772
773 kill(-1, SIGKILL); 773 kill(-1, SIGKILL);
774 message(L_CONSOLE, "Sent SIG%s to all processes", "KILL"); 774 message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
775 sync(); 775 sync();
776 /*sleep(1); - callers take care about making a pause */ 776 /*sleep1(); - callers take care about making a pause */
777} 777}
778 778
779/* Signal handling by init: 779/* Signal handling by init:
@@ -904,7 +904,7 @@ static void stop_handler(int sig UNUSED_PARAM)
904 wpid = wait_any_nohang(NULL); 904 wpid = wait_any_nohang(NULL);
905 mark_terminated(wpid); 905 mark_terminated(wpid);
906 if (wpid <= 0) /* no processes exited? sleep a bit */ 906 if (wpid <= 0) /* no processes exited? sleep a bit */
907 sleep(1); 907 sleep1();
908 } 908 }
909 909
910 signal(SIGCONT, SIG_DFL); 910 signal(SIGCONT, SIG_DFL);
@@ -1209,7 +1209,7 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1209 } 1209 }
1210 1210
1211 /* Don't consume all CPU time - sleep a bit */ 1211 /* Don't consume all CPU time - sleep a bit */
1212 sleep(1); 1212 sleep1();
1213 } /* while (1) */ 1213 } /* while (1) */
1214} 1214}
1215 1215
diff --git a/klibc-utils/nuke.c b/klibc-utils/nuke.c
index d7c16f5cf..8c20c5e11 100644
--- a/klibc-utils/nuke.c
+++ b/klibc-utils/nuke.c
@@ -5,7 +5,7 @@
5 */ 5 */
6//config:config NUKE 6//config:config NUKE
7//config: bool "nuke (2.9 kb)" 7//config: bool "nuke (2.9 kb)"
8//config: default y 8//config: default n # off by default: too "accidentally destructive"
9//config: help 9//config: help
10//config: Alias to "rm -rf". 10//config: Alias to "rm -rf".
11 11
diff --git a/libbb/bb_do_delay.c b/libbb/bb_do_delay.c
index 65541704b..9a84fa24b 100644
--- a/libbb/bb_do_delay.c
+++ b/libbb/bb_do_delay.c
@@ -8,13 +8,60 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11void FAST_FUNC bb_do_delay(int seconds) 11/* void FAST_FUNC bb_do_delay(unsigned seconds) { ... } - no users yet */
12
13#ifndef LOGIN_FAIL_DELAY
14#define LOGIN_FAIL_DELAY 3
15#endif
16void FAST_FUNC pause_after_failed_login(void)
12{ 17{
13 time_t start, now; 18#if 0 /* over-engineered madness */
19 time_t end, diff;
14 20
15 start = time(NULL); 21 end = time(NULL) + LOGIN_FAIL_DELAY;
22 diff = LOGIN_FAIL_DELAY;
16 do { 23 do {
17 sleep(seconds); 24 sleep(diff);
18 now = time(NULL); 25 diff = end - time(NULL);
19 } while ((now - start) < seconds); 26 } while (diff > 0);
27#else
28 sleep(LOGIN_FAIL_DELAY);
29#endif
30}
31
32void FAST_FUNC sleep1(void)
33{
34 sleep(1);
35}
36
37void FAST_FUNC msleep(unsigned ms)
38{
39#if 0
40 /* 1. usleep(n) is not guaranteed by standards to accept n >= 1000000
41 * 2. multiplication in usleep(ms * 1000) can overflow if ms > 4294967
42 * (sleep of ~71.5 minutes)
43 * Let's play safe and loop:
44 */
45 while (ms > 500) {
46 usleep(500000);
47 ms -= 500;
48 }
49 usleep(ms * 1000);
50#else
51//usleep is often implemented as a call to nanosleep.
52//Simply do the same to implement msleep.
53//it's marginally larger, but wakes your CPU less often:
54//function old new delta
55//msleep 45 52 +7
56 struct timespec ts;
57 ts.tv_sec = ms / 1000;
58 ts.tv_nsec = (ms % 1000) * 1000000;
59 /*
60 * If a signal has non-default handler, nanosleep returns early.
61 * Our version of msleep doesn't return early
62 * if interrupted by such signals:
63 */
64 while (nanosleep(&ts, &ts) != 0)
65 continue;
66#endif
20} 67}
diff --git a/libbb/capability.c b/libbb/capability.c
index 23afd8eb9..e3c252a5a 100644
--- a/libbb/capability.c
+++ b/libbb/capability.c
@@ -17,7 +17,7 @@ extern int capget(cap_user_header_t header, const cap_user_data_t data);
17// This way, libcap needs not be installed in build environment. 17// This way, libcap needs not be installed in build environment.
18#include "libbb.h" 18#include "libbb.h"
19 19
20static const char *const capabilities[] = { 20static const char *const capabilities[] ALIGN_PTR = {
21 "chown", 21 "chown",
22 "dac_override", 22 "dac_override",
23 "dac_read_search", 23 "dac_read_search",
diff --git a/libbb/copyfd.c b/libbb/copyfd.c
index d41fd10f0..7f9d92ea9 100644
--- a/libbb/copyfd.c
+++ b/libbb/copyfd.c
@@ -75,10 +75,7 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
75 goto use_small_buf; 75 goto use_small_buf;
76 /* We want page-aligned buffer, just in case kernel is clever 76 /* We want page-aligned buffer, just in case kernel is clever
77 * and can do page-aligned io more efficiently */ 77 * and can do page-aligned io more efficiently */
78 buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024, 78 buffer = mmap_anon(CONFIG_FEATURE_COPYBUF_KB * 1024);
79 PROT_READ | PROT_WRITE,
80 MAP_PRIVATE | MAP_ANON,
81 /* ignored: */ -1, 0);
82 buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024; 79 buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
83 if (buffer == MAP_FAILED) { 80 if (buffer == MAP_FAILED) {
84 use_small_buf: 81 use_small_buf:
diff --git a/libbb/die_if_bad_username.c b/libbb/die_if_bad_username.c
index e5e1160c4..d05dc74c5 100644
--- a/libbb/die_if_bad_username.c
+++ b/libbb/die_if_bad_username.c
@@ -8,6 +8,10 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11#ifndef LOGIN_NAME_MAX
12#define LOGIN_NAME_MAX 256
13#endif
14
11/* To avoid problems, the username should consist only of 15/* To avoid problems, the username should consist only of
12 * letters, digits, underscores, periods, at signs and dashes, 16 * letters, digits, underscores, periods, at signs and dashes,
13 * and not start with a dash (as defined by IEEE Std 1003.1-2001). 17 * and not start with a dash (as defined by IEEE Std 1003.1-2001).
diff --git a/libbb/duration.c b/libbb/duration.c
index 22b209f4d..086da15fb 100644
--- a/libbb/duration.c
+++ b/libbb/duration.c
@@ -21,7 +21,7 @@
21 21
22#include "libbb.h" 22#include "libbb.h"
23 23
24static const struct suffix_mult duration_suffixes[] = { 24static const struct suffix_mult duration_suffixes[] ALIGN_SUFFIX = {
25 { "s", 1 }, 25 { "s", 1 },
26 { "m", 60 }, 26 { "m", 60 },
27 { "h", 60*60 }, 27 { "h", 60*60 },
diff --git a/libbb/executable.c b/libbb/executable.c
index f549a7aae..bd3022b13 100644
--- a/libbb/executable.c
+++ b/libbb/executable.c
@@ -100,12 +100,3 @@ void FAST_FUNC BB_EXECVP_or_die(char **argv)
100 xfunc_error_retval = (errno == ENOENT) ? 127 : 126; 100 xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
101 bb_perror_msg_and_die("can't execute '%s'", argv[0]); 101 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
102} 102}
103
104/* Typical idiom for applets which exec *optional* PROG [ARGS] */
105void FAST_FUNC exec_prog_or_SHELL(char **argv)
106{
107 if (argv[0]) {
108 BB_EXECVP_or_die(argv);
109 }
110 run_shell(getenv("SHELL"), /*login:*/ 1, NULL);
111}
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index d8f210173..e0db8ce67 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -111,7 +111,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
111 They are defined in RFC 1321 as 111 They are defined in RFC 1321 as
112 T[i] = (int)(2^32 * fabs(sin(i))), i=1..64 112 T[i] = (int)(2^32 * fabs(sin(i))), i=1..64
113 */ 113 */
114 static const uint32_t C_array[] = { 114 static const uint32_t C_array[] ALIGN4 = {
115 /* round 1 */ 115 /* round 1 */
116 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 116 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
117 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 117 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
@@ -492,7 +492,7 @@ unsigned FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf)
492 492
493static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) 493static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx)
494{ 494{
495 static const uint32_t rconsts[] = { 495 static const uint32_t rconsts[] ALIGN4 = {
496 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 496 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6
497 }; 497 };
498 int i, j; 498 int i, j;
@@ -567,7 +567,7 @@ typedef uint64_t sha_K_int;
567typedef uint32_t sha_K_int; 567typedef uint32_t sha_K_int;
568# define K(v) (uint32_t)(v >> 32) 568# define K(v) (uint32_t)(v >> 32)
569#endif 569#endif
570static const sha_K_int sha_K[] = { 570static const sha_K_int sha_K[] ALIGN8 = {
571 K(0x428a2f98d728ae22ULL), K(0x7137449123ef65cdULL), 571 K(0x428a2f98d728ae22ULL), K(0x7137449123ef65cdULL),
572 K(0xb5c0fbcfec4d3b2fULL), K(0xe9b5dba58189dbbcULL), 572 K(0xb5c0fbcfec4d3b2fULL), K(0xe9b5dba58189dbbcULL),
573 K(0x3956c25bf348b538ULL), K(0x59f111f1b605d019ULL), 573 K(0x3956c25bf348b538ULL), K(0x59f111f1b605d019ULL),
@@ -760,7 +760,7 @@ void FAST_FUNC sha1_begin(sha1_ctx_t *ctx)
760 ctx->process_block = sha1_process_block64; 760 ctx->process_block = sha1_process_block64;
761} 761}
762 762
763static const uint32_t init256[] = { 763static const uint32_t init256[] ALIGN4 = {
764 0, 764 0,
765 0, 765 0,
766 0x6a09e667, 766 0x6a09e667,
@@ -773,7 +773,7 @@ static const uint32_t init256[] = {
773 0x5be0cd19, 773 0x5be0cd19,
774}; 774};
775#if NEED_SHA512 775#if NEED_SHA512
776static const uint32_t init512_lo[] = { 776static const uint32_t init512_lo[] ALIGN4 = {
777 0, 777 0,
778 0, 778 0,
779 0xf3bcc908, 779 0xf3bcc908,
@@ -1009,7 +1009,7 @@ static void sha3_process_block72(uint64_t *state)
1009 1009
1010#if OPTIMIZE_SHA3_FOR_32 1010#if OPTIMIZE_SHA3_FOR_32
1011 /* 1011 /*
1012 static const uint32_t IOTA_CONST_0[NROUNDS] = { 1012 static const uint32_t IOTA_CONST_0[NROUNDS] ALIGN4 = {
1013 0x00000001UL, 1013 0x00000001UL,
1014 0x00000000UL, 1014 0x00000000UL,
1015 0x00000000UL, 1015 0x00000000UL,
@@ -1038,7 +1038,7 @@ static void sha3_process_block72(uint64_t *state)
1038 ** bits are in lsb: 0101 0000 1111 0100 1111 0001 1038 ** bits are in lsb: 0101 0000 1111 0100 1111 0001
1039 */ 1039 */
1040 uint32_t IOTA_CONST_0bits = (uint32_t)(0x0050f4f1); 1040 uint32_t IOTA_CONST_0bits = (uint32_t)(0x0050f4f1);
1041 static const uint32_t IOTA_CONST_1[NROUNDS] = { 1041 static const uint32_t IOTA_CONST_1[NROUNDS] ALIGN4 = {
1042 0x00000000UL, 1042 0x00000000UL,
1043 0x00000089UL, 1043 0x00000089UL,
1044 0x8000008bUL, 1044 0x8000008bUL,
@@ -1174,7 +1174,7 @@ static void sha3_process_block72(uint64_t *state)
1174 combine_halves(state); 1174 combine_halves(state);
1175#else 1175#else
1176 /* Native 64-bit algorithm */ 1176 /* Native 64-bit algorithm */
1177 static const uint16_t IOTA_CONST[NROUNDS] = { 1177 static const uint16_t IOTA_CONST[NROUNDS] ALIGN2 = {
1178 /* Elements should be 64-bit, but top half is always zero 1178 /* Elements should be 64-bit, but top half is always zero
1179 * or 0x80000000. We encode 63rd bits in a separate word below. 1179 * or 0x80000000. We encode 63rd bits in a separate word below.
1180 * Same is true for 31th bits, which lets us use 16-bit table 1180 * Same is true for 31th bits, which lets us use 16-bit table
@@ -1210,15 +1210,15 @@ static void sha3_process_block72(uint64_t *state)
1210 /* bit for CONST[0] is in msb: 0001 0110 0011 1000 0001 1011 */ 1210 /* bit for CONST[0] is in msb: 0001 0110 0011 1000 0001 1011 */
1211 const uint32_t IOTA_CONST_bit31 = (uint32_t)(0x16381b00); 1211 const uint32_t IOTA_CONST_bit31 = (uint32_t)(0x16381b00);
1212 1212
1213 static const uint8_t ROT_CONST[24] = { 1213 static const uint8_t ROT_CONST[24] ALIGN1 = {
1214 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 1214 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
1215 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44, 1215 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
1216 }; 1216 };
1217 static const uint8_t PI_LANE[24] = { 1217 static const uint8_t PI_LANE[24] ALIGN1 = {
1218 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 1218 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
1219 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1, 1219 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
1220 }; 1220 };
1221 /*static const uint8_t MOD5[10] = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, };*/ 1221 /*static const uint8_t MOD5[10] ALIGN1 = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, };*/
1222 1222
1223 unsigned x; 1223 unsigned x;
1224 unsigned round; 1224 unsigned round;
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index b35da1874..f3cbc512c 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -57,12 +57,23 @@
57#if ENABLE_FEATURE_EDITING 57#if ENABLE_FEATURE_EDITING
58 58
59 59
60#if !ENABLE_SHELL_ASH && !ENABLE_SHELL_HUSH
61/* so far only shells use these features */
62# undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
63# undef ENABLE_FEATURE_TAB_COMPLETION
64# undef ENABLE_FEATURE_USERNAME_COMPLETION
65# define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
66# define ENABLE_FEATURE_TAB_COMPLETION 0
67# define ENABLE_FEATURE_USERNAME_COMPLETION 0
68#endif
69
70
60#define ENABLE_USERNAME_OR_HOMEDIR \ 71#define ENABLE_USERNAME_OR_HOMEDIR \
61 (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT) 72 (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT)
62#define IF_USERNAME_OR_HOMEDIR(...)
63#if ENABLE_USERNAME_OR_HOMEDIR 73#if ENABLE_USERNAME_OR_HOMEDIR
64# undef IF_USERNAME_OR_HOMEDIR
65# define IF_USERNAME_OR_HOMEDIR(...) __VA_ARGS__ 74# define IF_USERNAME_OR_HOMEDIR(...) __VA_ARGS__
75#else
76# define IF_USERNAME_OR_HOMEDIR(...) /*nothing*/
66#endif 77#endif
67 78
68 79
@@ -205,9 +216,6 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics;
205#define INIT_S() do { \ 216#define INIT_S() do { \
206 (*(struct lineedit_statics**)not_const_pp(&lineedit_ptr_to_statics)) = xzalloc(sizeof(S)); \ 217 (*(struct lineedit_statics**)not_const_pp(&lineedit_ptr_to_statics)) = xzalloc(sizeof(S)); \
207 barrier(); \ 218 barrier(); \
208 cmdedit_termw = 80; \
209 IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \
210 IF_FEATURE_EDITING_VI(delptr = delbuf;) \
211} while (0) 219} while (0)
212 220
213static void deinit_S(void) 221static void deinit_S(void)
@@ -796,16 +804,18 @@ enum {
796 FIND_FILE_ONLY = 2, 804 FIND_FILE_ONLY = 2,
797}; 805};
798 806
799static int path_parse(char ***p) 807static unsigned path_parse(char ***p)
800{ 808{
801 int npth; 809 unsigned npth;
802 const char *pth; 810 const char *pth;
803 char *tmp; 811 char *tmp;
804 char **res; 812 char **res;
805 813
814# if EDITING_HAS_path_lookup
806 if (state->flags & WITH_PATH_LOOKUP) 815 if (state->flags & WITH_PATH_LOOKUP)
807 pth = state->path_lookup; 816 pth = state->path_lookup;
808 else 817 else
818# endif
809 pth = getenv("PATH"); 819 pth = getenv("PATH");
810 820
811 /* PATH="" or PATH=":"? */ 821 /* PATH="" or PATH=":"? */
@@ -824,7 +834,7 @@ static int path_parse(char ***p)
824 npth++; 834 npth++;
825 } 835 }
826 836
827 *p = res = xmalloc(npth * sizeof(res[0])); 837 *p = res = xzalloc((npth + 1) * sizeof(res[0]));
828 res[0] = tmp = xstrdup(pth); 838 res[0] = tmp = xstrdup(pth);
829 npth = 1; 839 npth = 1;
830 while (1) { 840 while (1) {
@@ -836,6 +846,8 @@ static int path_parse(char ***p)
836 break; /* :<empty> */ 846 break; /* :<empty> */
837 res[npth++] = tmp; 847 res[npth++] = tmp;
838 } 848 }
849 /* special case: "match subdirectories of the current directory" */
850 /*res[npth++] = NULL; - filled by xzalloc() */
839 return npth; 851 return npth;
840} 852}
841 853
@@ -846,49 +858,49 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
846{ 858{
847 char *path1[1]; 859 char *path1[1];
848 char **paths = path1; 860 char **paths = path1;
849 int npaths; 861 unsigned npaths;
850 int i; 862 unsigned i;
851 unsigned pf_len; 863 unsigned baselen;
852 const char *pfind; 864 const char *basecmd;
853 char *dirbuf = NULL; 865 char *dirbuf = NULL;
854 866
855 npaths = 1; 867 npaths = 1;
856 path1[0] = (char*)"."; 868 path1[0] = (char*)".";
857 869
858 pfind = strrchr(command, '/'); 870 basecmd = strrchr(command, '/');
859#if ENABLE_PLATFORM_MINGW32 871#if ENABLE_PLATFORM_MINGW32
860 if (!pfind && has_dos_drive_prefix(command) && command[2] != '\0') { 872 if (!basecmd && has_dos_drive_prefix(command) && command[2] != '\0') {
861 char buffer[PATH_MAX]; 873 char buffer[PATH_MAX];
862 874
863 /* path is of form c:path with no '/' */ 875 /* path is of form c:path with no '/' */
864 if (get_drive_cwd(command, buffer, PATH_MAX)) { 876 if (get_drive_cwd(command, buffer, PATH_MAX)) {
865 pfind = command + 2; 877 basecmd = command + 2;
866 path1[0] = dirbuf = xstrdup(buffer); 878 path1[0] = dirbuf = xstrdup(buffer);
867 } 879 }
868 } else 880 } else
869#endif 881#endif
870 if (!pfind) { 882 if (!basecmd) {
871 if (type == FIND_EXE_ONLY) 883 if (type == FIND_EXE_ONLY)
872 npaths = path_parse(&paths); 884 npaths = path_parse(&paths);
873 pfind = command; 885 basecmd = command;
874 } else { 886 } else {
875 /* point to 'l' in "..../last_component" */ 887 /* point to 'l' in "..../last_component" */
876 pfind++; 888 basecmd++;
877 /* dirbuf = ".../.../.../" */ 889 /* dirbuf = ".../.../.../" */
878 dirbuf = xstrndup(command, pfind - command); 890 dirbuf = xstrndup(command, basecmd - command);
879# if ENABLE_FEATURE_USERNAME_COMPLETION 891# if ENABLE_FEATURE_USERNAME_COMPLETION
880 if (dirbuf[0] == '~') /* ~/... or ~user/... */ 892 if (dirbuf[0] == '~') /* ~/... or ~user/... */
881 dirbuf = username_path_completion(dirbuf); 893 dirbuf = username_path_completion(dirbuf);
882# endif 894# endif
883 path1[0] = dirbuf; 895 path1[0] = dirbuf;
884 } 896 }
885 pf_len = strlen(pfind); 897 baselen = strlen(basecmd);
886 898
887 if (type == FIND_EXE_ONLY && !dirbuf) { 899 if (type == FIND_EXE_ONLY && !dirbuf) {
888# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 900# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1
889 const char *p = applet_names; 901 const char *p = applet_names;
890 while (*p) { 902 while (*p) {
891 if (strncmp(pfind, p, pf_len) == 0) 903 if (strncmp(basecmd, p, baselen) == 0)
892 add_match(xstrdup(p)); 904 add_match(xstrdup(p));
893 while (*p++ != '\0') 905 while (*p++ != '\0')
894 continue; 906 continue;
@@ -901,7 +913,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
901 const char *b = state->get_exe_name(i++); 913 const char *b = state->get_exe_name(i++);
902 if (!b) 914 if (!b)
903 break; 915 break;
904 if (strncmp(pfind, b, pf_len) == 0) 916 if (strncmp(basecmd, b, baselen) == 0)
905 add_match(xstrdup(b)); 917 add_match(xstrdup(b));
906 } 918 }
907 } 919 }
@@ -913,9 +925,20 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
913 struct dirent *next; 925 struct dirent *next;
914 struct stat st; 926 struct stat st;
915 char *found; 927 char *found;
928#if ENABLE_PLATFORM_MINGW32
929 char *lpath;
930#endif
931
932 if (paths[i] == NULL) { /* path_parse()'s last component? */
933 /* in PATH completion, current dir's subdir names
934 * can be completions (but only subdirs, not files).
935 */
936 type = FIND_DIR_ONLY;
937 paths[i] = (char *)".";
938 }
916 939
917#if ENABLE_PLATFORM_MINGW32 940#if ENABLE_PLATFORM_MINGW32
918 char *lpath = auto_string(alloc_system_drive(paths[i])); 941 lpath = auto_string(alloc_system_drive(paths[i]));
919 dir = opendir(lpath); 942 dir = opendir(lpath);
920#else 943#else
921 dir = opendir(paths[i]); 944 dir = opendir(paths[i]);
@@ -928,10 +951,10 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
928 const char *name_found = next->d_name; 951 const char *name_found = next->d_name;
929 952
930 /* .../<tab>: bash 3.2.0 shows dotfiles, but not . and .. */ 953 /* .../<tab>: bash 3.2.0 shows dotfiles, but not . and .. */
931 if (!pfind[0] && DOT_OR_DOTDOT(name_found)) 954 if (!basecmd[0] && DOT_OR_DOTDOT(name_found))
932 continue; 955 continue;
933 /* match? */ 956 /* match? */
934 if (!is_prefixed_with(name_found, pfind)) 957 if (strncmp(basecmd, name_found, baselen) != 0)
935 continue; /* no */ 958 continue; /* no */
936 959
937#if ENABLE_PLATFORM_MINGW32 960#if ENABLE_PLATFORM_MINGW32
@@ -957,6 +980,9 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
957 strcpy(found, name_found); 980 strcpy(found, name_found);
958 981
959 if (S_ISDIR(st.st_mode)) { 982 if (S_ISDIR(st.st_mode)) {
983 /* skip directories if searching PATH */
984 if (type == FIND_EXE_ONLY && !dirbuf)
985 goto cont;
960 /* name is a directory, add slash */ 986 /* name is a directory, add slash */
961 found[len] = '/'; 987 found[len] = '/';
962 found[len + 1] = '\0'; 988 found[len + 1] = '\0';
@@ -980,7 +1006,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
980 } 1006 }
981 free(dirbuf); 1007 free(dirbuf);
982 1008
983 return pf_len; 1009 return baselen;
984} 1010}
985 1011
986/* build_match_prefix: 1012/* build_match_prefix:
@@ -1492,15 +1518,19 @@ void FAST_FUNC show_history(const line_input_t *st)
1492 printf("%4d %s\n", i, st->history[i]); 1518 printf("%4d %s\n", i, st->history[i]);
1493} 1519}
1494 1520
1521# if ENABLE_FEATURE_EDITING_SAVEHISTORY
1495void FAST_FUNC free_line_input_t(line_input_t *n) 1522void FAST_FUNC free_line_input_t(line_input_t *n)
1496{ 1523{
1497# if ENABLE_FEATURE_EDITING_SAVEHISTORY 1524 if (n) {
1498 int i = n->cnt_history; 1525 int i = n->cnt_history;
1499 while (i > 0) 1526 while (i > 0)
1500 free(n->history[--i]); 1527 free(n->history[--i]);
1501#endif 1528 free(n);
1502 free(n); 1529 }
1503} 1530}
1531# else
1532/* #defined to free() in libbb.h */
1533# endif
1504 1534
1505# if ENABLE_FEATURE_EDITING_SAVEHISTORY 1535# if ENABLE_FEATURE_EDITING_SAVEHISTORY
1506/* We try to ensure that concurrent additions to the history 1536/* We try to ensure that concurrent additions to the history
@@ -1581,7 +1611,7 @@ void save_history(line_input_t *st)
1581{ 1611{
1582 FILE *fp; 1612 FILE *fp;
1583 1613
1584 if (!st->hist_file) 1614 if (!st || !st->hist_file)
1585 return; 1615 return;
1586 if (st->cnt_history <= st->cnt_history_in_file) 1616 if (st->cnt_history <= st->cnt_history_in_file)
1587 return; 1617 return;
@@ -1971,9 +2001,7 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1971{ 2001{
1972 int prmt_size = 0; 2002 int prmt_size = 0;
1973 char *prmt_mem_ptr = xzalloc(1); 2003 char *prmt_mem_ptr = xzalloc(1);
1974# if ENABLE_USERNAME_OR_HOMEDIR
1975 char *cwd_buf = NULL; 2004 char *cwd_buf = NULL;
1976# endif
1977 char flg_not_length = '['; 2005 char flg_not_length = '[';
1978 char cbuf[2]; 2006 char cbuf[2];
1979 2007
@@ -2040,11 +2068,9 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2040 c = *prmt_ptr++; 2068 c = *prmt_ptr++;
2041 2069
2042 switch (c) { 2070 switch (c) {
2043# if ENABLE_USERNAME_OR_HOMEDIR
2044 case 'u': 2071 case 'u':
2045 pbuf = user_buf ? user_buf : (char*)""; 2072 pbuf = user_buf ? user_buf : (char*)"";
2046 break; 2073 break;
2047# endif
2048 case 'H': 2074 case 'H':
2049 case 'h': 2075 case 'h':
2050 pbuf = free_me = safe_gethostname(); 2076 pbuf = free_me = safe_gethostname();
@@ -2062,7 +2088,6 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2062 strftime_HHMMSS(timebuf, sizeof(timebuf), NULL)[-3] = '\0'; 2088 strftime_HHMMSS(timebuf, sizeof(timebuf), NULL)[-3] = '\0';
2063 pbuf = timebuf; 2089 pbuf = timebuf;
2064 break; 2090 break;
2065# if ENABLE_USERNAME_OR_HOMEDIR
2066 case 'w': /* current dir */ 2091 case 'w': /* current dir */
2067 case 'W': /* basename of cur dir */ 2092 case 'W': /* basename of cur dir */
2068 if (!cwd_buf) { 2093 if (!cwd_buf) {
@@ -2089,7 +2114,6 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2089 if (cp) 2114 if (cp)
2090 pbuf = (char*)cp + 1; 2115 pbuf = (char*)cp + 1;
2091 break; 2116 break;
2092# endif
2093// bb_process_escape_sequence does this now: 2117// bb_process_escape_sequence does this now:
2094// case 'e': case 'E': /* \e \E = \033 */ 2118// case 'e': case 'E': /* \e \E = \033 */
2095// c = '\033'; 2119// c = '\033';
@@ -2130,10 +2154,17 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2130 if (c == '\n') 2154 if (c == '\n')
2131 cmdedit_prmt_len = 0; 2155 cmdedit_prmt_len = 0;
2132 else if (flg_not_length != ']') { 2156 else if (flg_not_length != ']') {
2133#if 0 /*ENABLE_UNICODE_SUPPORT*/ 2157#if ENABLE_UNICODE_SUPPORT
2134/* Won't work, pbuf is one BYTE string here instead of an one Unicode char string. */ 2158 if (n == 1) {
2135/* FIXME */ 2159 /* Only count single-byte characters and the first of multi-byte characters */
2136 cmdedit_prmt_len += unicode_strwidth(pbuf); 2160 if ((unsigned char)*pbuf < 0x80 /* single byte character */
2161 || (unsigned char)*pbuf >= 0xc0 /* first of multi-byte characters */
2162 ) {
2163 cmdedit_prmt_len += n;
2164 }
2165 } else {
2166 cmdedit_prmt_len += unicode_strwidth(pbuf);
2167 }
2137#else 2168#else
2138 cmdedit_prmt_len += n; 2169 cmdedit_prmt_len += n;
2139#endif 2170#endif
@@ -2143,10 +2174,8 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2143 free(free_me); 2174 free(free_me);
2144 } /* while */ 2175 } /* while */
2145 2176
2146# if ENABLE_USERNAME_OR_HOMEDIR
2147 if (cwd_buf != (char *)bb_msg_unknown) 2177 if (cwd_buf != (char *)bb_msg_unknown)
2148 free(cwd_buf); 2178 free(cwd_buf);
2149# endif
2150 /* see comment (above this function) about multiline prompt redrawing */ 2179 /* see comment (above this function) about multiline prompt redrawing */
2151 cmdedit_prompt = prompt_last_line = prmt_mem_ptr; 2180 cmdedit_prompt = prompt_last_line = prmt_mem_ptr;
2152 prmt_ptr = strrchr(cmdedit_prompt, '\n'); 2181 prmt_ptr = strrchr(cmdedit_prompt, '\n');
@@ -2154,7 +2183,7 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2154 prompt_last_line = prmt_ptr + 1; 2183 prompt_last_line = prmt_ptr + 1;
2155 put_prompt(); 2184 put_prompt();
2156} 2185}
2157#endif 2186#endif /* FEATURE_EDITING_FANCY_PROMPT */
2158 2187
2159#if ENABLE_FEATURE_EDITING_WINCH 2188#if ENABLE_FEATURE_EDITING_WINCH
2160static void cmdedit_setwidth(void) 2189static void cmdedit_setwidth(void)
@@ -2467,6 +2496,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2467 char read_key_buffer[KEYCODE_BUFFER_SIZE]; 2496 char read_key_buffer[KEYCODE_BUFFER_SIZE];
2468 2497
2469 INIT_S(); 2498 INIT_S();
2499 //command_len = 0; - done by INIT_S()
2500 //cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
2501 cmdedit_termw = 80;
2502 IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;)
2503 IF_FEATURE_EDITING_VI(delptr = delbuf;)
2470 2504
2471#if !ENABLE_PLATFORM_MINGW32 2505#if !ENABLE_PLATFORM_MINGW32
2472 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0 2506 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0
@@ -2521,8 +2555,6 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2521#endif 2555#endif
2522 2556
2523 /* prepare before init handlers */ 2557 /* prepare before init handlers */
2524 cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
2525 command_len = 0;
2526#if ENABLE_UNICODE_SUPPORT 2558#if ENABLE_UNICODE_SUPPORT
2527 command_ps = xzalloc(maxsize * sizeof(command_ps[0])); 2559 command_ps = xzalloc(maxsize * sizeof(command_ps[0]));
2528#else 2560#else
@@ -3005,6 +3037,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
3005 * before it comes in. UGLY! 3037 * before it comes in. UGLY!
3006 */ 3038 */
3007 usleep(20*1000); 3039 usleep(20*1000);
3040// MAYBE? tcflush(STDIN_FILENO, TCIFLUSH); /* flushes data received but not read */
3008 } 3041 }
3009#endif 3042#endif
3010 3043
diff --git a/libbb/loop.c b/libbb/loop.c
index 85b2724e5..cb8fa2442 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -98,9 +98,7 @@ int FAST_FUNC get_free_loop(void)
98 98
99/* Returns opened fd to the loop device, <0 on error. 99/* Returns opened fd to the loop device, <0 on error.
100 * *device is loop device to use, or if *device==NULL finds a loop device to 100 * *device is loop device to use, or if *device==NULL finds a loop device to
101 * mount it on and sets *device to a strdup of that loop device name. This 101 * mount it on and sets *device to a strdup of that loop device name.
102 * search will re-use an existing loop device already bound to that
103 * file/offset if it finds one.
104 */ 102 */
105int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, 103int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset,
106 unsigned long long sizelimit, unsigned flags) 104 unsigned long long sizelimit, unsigned flags)
@@ -109,9 +107,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
109 char *try; 107 char *try;
110 bb_loop_info loopinfo; 108 bb_loop_info loopinfo;
111 struct stat statbuf; 109 struct stat statbuf;
112 int i, dfd, ffd, mode, rc; 110 int i, lfd, ffd, mode, rc;
113
114 rc = dfd = -1;
115 111
116 /* Open the file. Barf if this doesn't work. */ 112 /* Open the file. Barf if this doesn't work. */
117 mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; 113 mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR;
@@ -127,24 +123,23 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
127 123
128 try = *device; 124 try = *device;
129 if (!try) { 125 if (!try) {
126 get_free_loopN:
130 i = get_free_loop(); 127 i = get_free_loop();
131 if (i == -2) { /* no /dev/loop-control */
132 i = 0;
133 try = dev;
134 goto old_style;
135 }
136 if (i == -1) { 128 if (i == -1) {
137 close(ffd); 129 close(ffd);
138 return -1; /* no free loop devices */ 130 return -1; /* no free loop devices */
139 } 131 }
140 try = *device = xasprintf(LOOP_FORMAT, i); 132 if (i >= 0) {
141 goto try_to_open; 133 try = xasprintf(LOOP_FORMAT, i);
134 goto open_lfd;
135 }
136 /* i == -2: no /dev/loop-control. Do an old-style search for a free device */
137 try = dev;
142 } 138 }
143 139
144 old_style: 140 /* Find a loop device */
145 /* Find a loop device. */ 141 /* 0xfffff is a max possible minor number in Linux circa 2010 */
146 /* 1048575 (0xfffff) is a max possible minor number in Linux circa 2010 */ 142 for (i = 0; i <= 0xfffff; i++) {
147 for (i = 0; rc && i < 1048576; i++) {
148 sprintf(dev, LOOP_FORMAT, i); 143 sprintf(dev, LOOP_FORMAT, i);
149 144
150 IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) 145 IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;)
@@ -153,72 +148,86 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
153 && errno == ENOENT 148 && errno == ENOENT
154 && try == dev 149 && try == dev
155 ) { 150 ) {
156 /* Node doesn't exist, try to create it. */ 151 /* Node doesn't exist, try to create it */
157 if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) 152 if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0)
158 goto try_to_open; 153 goto open_lfd;
159 } 154 }
160 /* Ran out of block devices, return failure. */ 155 /* Ran out of block devices, return failure */
161 rc = -1; 156 rc = -1;
162 break; 157 break;
163 } 158 }
164 try_to_open: 159 open_lfd:
165 /* Open the sucker and check its loopiness. */ 160 /* Open the sucker and check its loopiness */
166 dfd = open(try, mode); 161 lfd = rc = open(try, mode);
167 if (dfd < 0 && errno == EROFS) { 162 if (lfd < 0 && errno == EROFS) {
168 mode = O_RDONLY; 163 mode = O_RDONLY;
169 dfd = open(try, mode); 164 lfd = rc = open(try, mode);
170 } 165 }
171 if (dfd < 0) { 166 if (lfd < 0) {
172 if (errno == ENXIO) { 167 if (errno == ENXIO) {
173 /* Happens if loop module is not loaded */ 168 /* Happens if loop module is not loaded */
174 rc = -1; 169 /* rc is -1; */
175 break; 170 break;
176 } 171 }
177 goto try_again; 172 goto try_next_loopN;
178 } 173 }
179 174
180 rc = ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo); 175 rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo);
181 176
182 /* If device is free, claim it. */ 177 /* If device is free, try to claim it */
183 if (rc && errno == ENXIO) { 178 if (rc && errno == ENXIO) {
184 /* Associate free loop device with file. */ 179 /* Associate free loop device with file */
185 if (ioctl(dfd, LOOP_SET_FD, ffd) == 0) { 180 if (ioctl(lfd, LOOP_SET_FD, ffd)) {
186 memset(&loopinfo, 0, sizeof(loopinfo)); 181 /* Ouch. Are we racing with other mount? */
187 safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); 182 if (!*device /* yes */
188 loopinfo.lo_offset = offset; 183 && try != dev /* tried a _kernel-offered_ loopN? */
189 loopinfo.lo_sizelimit = sizelimit; 184 ) {
190 /* 185 free(try);
191 * Used by mount to set LO_FLAGS_AUTOCLEAR. 186 close(lfd);
192 * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. 187//TODO: add "if (--failcount != 0) ..."?
193 * Note that closing LO_FLAGS_AUTOCLEARed dfd before mount 188 goto get_free_loopN;
194 * is wrong (would free the loop device!)
195 */
196 loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY);
197 rc = ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo);
198 if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) {
199 /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */
200 /* (this code path is not tested) */
201 loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR;
202 rc = ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo);
203 }
204 if (rc != 0) {
205 ioctl(dfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary
206 } 189 }
190 goto close_and_try_next_loopN;
207 } 191 }
208 } else { 192 memset(&loopinfo, 0, sizeof(loopinfo));
209 rc = -1; 193 safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
210 } 194 loopinfo.lo_offset = offset;
211 if (rc != 0) { 195 loopinfo.lo_sizelimit = sizelimit;
212 close(dfd); 196 /*
197 * Used by mount to set LO_FLAGS_AUTOCLEAR.
198 * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file.
199 * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount
200 * is wrong (would free the loop device!)
201 */
202 loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY);
203 rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo);
204 if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) {
205 /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */
206 /* (this code path is not tested) */
207 loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR;
208 rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo);
209 }
210 if (rc == 0) {
211 /* SUCCESS! */
212 if (try != dev) /* tried a kernel-offered free loopN? */
213 *device = try; /* malloced */
214 if (!*device) /* was looping in search of free "/dev/loopN"? */
215 *device = xstrdup(dev);
216 rc = lfd; /* return this */
217 break;
218 }
219 /* failure, undo LOOP_SET_FD */
220 ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary
213 } 221 }
214 try_again: 222 /* else: device is not free (rc == 0) or error other than ENXIO */
215 if (*device) break; 223 close_and_try_next_loopN:
216 } 224 close(lfd);
225 try_next_loopN:
226 rc = -1;
227 if (*device) /* was looking for a particular "/dev/loopN"? */
228 break; /* yes, do not try other names */
229 } /* for() */
230
217 close(ffd); 231 close(ffd);
218 if (rc == 0) {
219 if (!*device)
220 *device = xstrdup(dev);
221 return dfd;
222 }
223 return rc; 232 return rc;
224} 233}
diff --git a/libbb/mode_string.c b/libbb/mode_string.c
index 6c5c08acd..dc3f9f88c 100644
--- a/libbb/mode_string.c
+++ b/libbb/mode_string.c
@@ -27,7 +27,7 @@
27#define mode_t unsigned short 27#define mode_t unsigned short
28#endif 28#endif
29 29
30static const mode_t mode_flags[] = { 30static const mode_t mode_flags[] ALIGN4 = {
31 S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID, 31 S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID,
32 S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID, 32 S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID,
33 S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX 33 S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX
diff --git a/libbb/platform.c b/libbb/platform.c
index 03bbb798b..329b0237e 100644
--- a/libbb/platform.c
+++ b/libbb/platform.c
@@ -27,7 +27,6 @@ int FAST_FUNC usleep(unsigned usec)
27 * If a signal has non-default handler, nanosleep returns early. 27 * If a signal has non-default handler, nanosleep returns early.
28 * Our version of usleep doesn't return early 28 * Our version of usleep doesn't return early
29 * if interrupted by such signals: 29 * if interrupted by such signals:
30 *
31 */ 30 */
32 while (nanosleep(&ts, &ts) != 0) 31 while (nanosleep(&ts, &ts) != 0)
33 continue; 32 continue;
@@ -107,7 +106,8 @@ void* FAST_FUNC memrchr(const void *s, int c, size_t n)
107/* This is now actually part of POSIX.1, but was only added in 2008 */ 106/* This is now actually part of POSIX.1, but was only added in 2008 */
108char* FAST_FUNC mkdtemp(char *template) 107char* FAST_FUNC mkdtemp(char *template)
109{ 108{
110 if (mktemp(template) == NULL || mkdir(template, 0700) != 0) 109 /* NB: on error, mktemp returns an empty string, not NULL */
110 if (mktemp(template)[0] == '\0' || mkdir(template, 0700) != 0)
111 return NULL; 111 return NULL;
112 return template; 112 return template;
113} 113}
diff --git a/libbb/procps.c b/libbb/procps.c
index 4f9705bc1..8c9cac125 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -21,40 +21,29 @@ typedef struct cache_t {
21 int size; 21 int size;
22} cache_t; 22} cache_t;
23 23
24static cache_t username, groupname; 24static cache_t *cache_user_group;
25 25
26static void clear_cache(cache_t *cp)
27{
28 free(cp->cache);
29 cp->cache = NULL;
30 cp->size = 0;
31}
32void FAST_FUNC clear_username_cache(void) 26void FAST_FUNC clear_username_cache(void)
33{ 27{
34 clear_cache(&username); 28 if (cache_user_group) {
35 clear_cache(&groupname); 29 free(cache_user_group[0].cache);
36} 30 free(cache_user_group[1].cache);
37 31 free(cache_user_group);
38#if 0 /* more generic, but we don't need that yet */ 32 cache_user_group = NULL;
39/* Returns -N-1 if not found. */ 33 }
40/* cp->cache[N] is allocated and must be filled in this case */
41static int get_cached(cache_t *cp, uid_t id)
42{
43 int i;
44 for (i = 0; i < cp->size; i++)
45 if (cp->cache[i].id == id)
46 return i;
47 i = cp->size++;
48 cp->cache = xrealloc_vector(cp->cache, 2, i);
49 cp->cache[i++].id = id;
50 return -i;
51} 34}
52#endif
53 35
54static char* get_cached(cache_t *cp, uid_t id, 36static char* get_cached(int user_group, uid_t id,
55 char* FAST_FUNC x2x_utoa(uid_t id)) 37 char* FAST_FUNC x2x_utoa(uid_t id))
56{ 38{
39 cache_t *cp;
57 int i; 40 int i;
41
42 if (!cache_user_group)
43 cache_user_group = xzalloc(sizeof(cache_user_group[0]) * 2);
44
45 cp = &cache_user_group[user_group];
46
58 for (i = 0; i < cp->size; i++) 47 for (i = 0; i < cp->size; i++)
59 if (cp->cache[i].id == id) 48 if (cp->cache[i].id == id)
60 return cp->cache[i].name; 49 return cp->cache[i].name;
@@ -67,11 +56,11 @@ static char* get_cached(cache_t *cp, uid_t id,
67} 56}
68const char* FAST_FUNC get_cached_username(uid_t uid) 57const char* FAST_FUNC get_cached_username(uid_t uid)
69{ 58{
70 return get_cached(&username, uid, uid2uname_utoa); 59 return get_cached(0, uid, uid2uname_utoa);
71} 60}
72const char* FAST_FUNC get_cached_groupname(gid_t gid) 61const char* FAST_FUNC get_cached_groupname(gid_t gid)
73{ 62{
74 return get_cached(&groupname, gid, gid2group_utoa); 63 return get_cached(1, gid, gid2group_utoa);
75} 64}
76 65
77#if !ENABLE_PLATFORM_MINGW32 66#if !ENABLE_PLATFORM_MINGW32
@@ -95,15 +84,15 @@ static int read_to_buf(const char *filename, void *buf)
95 84
96static procps_status_t* FAST_FUNC alloc_procps_scan(void) 85static procps_status_t* FAST_FUNC alloc_procps_scan(void)
97{ 86{
98 unsigned n = getpagesize();
99 procps_status_t* sp = xzalloc(sizeof(procps_status_t)); 87 procps_status_t* sp = xzalloc(sizeof(procps_status_t));
100 sp->dir = xopendir("/proc"); 88 unsigned n = bb_getpagesize();
101 while (1) { 89 while (1) {
102 n >>= 1; 90 n >>= 1;
103 if (!n) break; 91 if (!n) break;
104 sp->shift_pages_to_bytes++; 92 sp->shift_pages_to_bytes++;
105 } 93 }
106 sp->shift_pages_to_kb = sp->shift_pages_to_bytes - 10; 94 sp->shift_pages_to_kb = sp->shift_pages_to_bytes - 10;
95 sp->dir = xopendir("/proc");
107 return sp; 96 return sp;
108} 97}
109 98
@@ -178,6 +167,7 @@ static char *skip_fields(char *str, int count)
178} 167}
179#endif 168#endif
180 169
170#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
181static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix) 171static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix)
182{ 172{
183 char *tp = is_prefixed_with(buf, prefix); 173 char *tp = is_prefixed_with(buf, prefix);
@@ -187,7 +177,6 @@ static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix)
187 return tp; 177 return tp;
188} 178}
189 179
190#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
191int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, 180int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
192 void (*cb)(struct smaprec *, void *), void *data) 181 void (*cb)(struct smaprec *, void *), void *data)
193{ 182{
diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c
index 47c20690f..3463fd95b 100644
--- a/libbb/pw_encrypt.c
+++ b/libbb/pw_encrypt.c
@@ -7,7 +7,9 @@
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9#if !ENABLE_USE_BB_CRYPT 9#if !ENABLE_USE_BB_CRYPT
10#include <crypt.h> 10# if !defined(__FreeBSD__)
11# include <crypt.h>
12# endif
11#endif 13#endif
12#include "libbb.h" 14#include "libbb.h"
13 15
@@ -120,6 +122,7 @@ static char *my_crypt(const char *key, const char *salt)
120 if (!des_cctx) 122 if (!des_cctx)
121 des_cctx = const_des_init(); 123 des_cctx = const_des_init();
122 des_ctx = des_init(des_ctx, des_cctx); 124 des_ctx = des_init(des_ctx, des_cctx);
125 /* Can return NULL if salt is bad ("" or "<one_char>") */
123 return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); 126 return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
124} 127}
125 128
@@ -137,6 +140,8 @@ char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
137 char *encrypted; 140 char *encrypted;
138 141
139 encrypted = my_crypt(clear, salt); 142 encrypted = my_crypt(clear, salt);
143 if (!encrypted)
144 bb_simple_error_msg_and_die("bad salt");
140 145
141 if (cleanup) 146 if (cleanup)
142 my_crypt_cleanup(); 147 my_crypt_cleanup();
@@ -148,14 +153,16 @@ char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
148 153
149char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup) 154char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
150{ 155{
151 char *s; 156 char *encrypted;
152 157
153 s = crypt(clear, salt); 158 encrypted = crypt(clear, salt);
154 /* 159 /*
155 * glibc used to return "" on malformed salts (for example, ""), 160 * glibc used to return "" on malformed salts (for example, ""),
156 * but since 2.17 it returns NULL. 161 * but since 2.17 it returns NULL.
157 */ 162 */
158 return xstrdup(s ? s : ""); 163 if (!encrypted || !encrypted[0])
164 bb_simple_error_msg_and_die("bad salt");
165 return xstrdup(encrypted);
159} 166}
160 167
161#endif 168#endif
diff --git a/libbb/pw_encrypt_des.c b/libbb/pw_encrypt_des.c
index 19a9ab15b..dcd3521e2 100644
--- a/libbb/pw_encrypt_des.c
+++ b/libbb/pw_encrypt_des.c
@@ -65,25 +65,25 @@
65 65
66 66
67/* A pile of data */ 67/* A pile of data */
68static const uint8_t IP[64] = { 68static const uint8_t IP[64] ALIGN1 = {
69 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 69 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
70 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 70 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
71 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 71 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
72 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 72 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
73}; 73};
74 74
75static const uint8_t key_perm[56] = { 75static const uint8_t key_perm[56] ALIGN1 = {
76 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 76 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
77 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 77 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
78 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 78 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
79 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 79 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
80}; 80};
81 81
82static const uint8_t key_shifts[16] = { 82static const uint8_t key_shifts[16] ALIGN1 = {
83 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 83 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
84}; 84};
85 85
86static const uint8_t comp_perm[48] = { 86static const uint8_t comp_perm[48] ALIGN1 = {
87 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 87 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
88 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 88 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
89 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 89 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
@@ -181,13 +181,12 @@ static const uint8_t u_sbox[8][32] = {
181}; 181};
182#endif 182#endif
183 183
184static const uint8_t pbox[32] = { 184static const uint8_t pbox[32] ALIGN1 = {
185 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 185 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
186 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 186 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
187}; 187};
188 188
189static const uint32_t bits32[32] = 189static const uint32_t bits32[32] ALIGN4 = {
190{
191 0x80000000, 0x40000000, 0x20000000, 0x10000000, 190 0x80000000, 0x40000000, 0x20000000, 0x10000000,
192 0x08000000, 0x04000000, 0x02000000, 0x01000000, 191 0x08000000, 0x04000000, 0x02000000, 0x01000000,
193 0x00800000, 0x00400000, 0x00200000, 0x00100000, 192 0x00800000, 0x00400000, 0x00200000, 0x00100000,
@@ -198,7 +197,7 @@ static const uint32_t bits32[32] =
198 0x00000008, 0x00000004, 0x00000002, 0x00000001 197 0x00000008, 0x00000004, 0x00000002, 0x00000001
199}; 198};
200 199
201static const uint8_t bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; 200static const uint8_t bits8[8] ALIGN1 = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
202 201
203 202
204static int 203static int
@@ -714,11 +713,15 @@ to64_msb_first(char *s, unsigned v)
714static char * 713static char *
715NOINLINE 714NOINLINE
716des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE], 715des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
717 const unsigned char *key, const unsigned char *setting) 716 const unsigned char *key, const unsigned char *salt_str)
718{ 717{
719 uint32_t salt, r0, r1, keybuf[2]; 718 uint32_t salt, r0, r1, keybuf[2];
720 uint8_t *q; 719 uint8_t *q;
721 720
721 /* Bad salt? Mimic crypt() API - return NULL */
722 if (!salt_str[0] || !salt_str[1])
723 return NULL;
724
722 /* 725 /*
723 * Copy the key, shifting each character up by one bit 726 * Copy the key, shifting each character up by one bit
724 * and padding with zeros. 727 * and padding with zeros.
@@ -733,22 +736,15 @@ des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
733 des_setkey(ctx, (char *)keybuf); 736 des_setkey(ctx, (char *)keybuf);
734 737
735 /* 738 /*
736 * setting - 2 bytes of salt 739 * salt_str - 2 bytes of salt
737 * key - up to 8 characters 740 * key - up to 8 characters
738 */ 741 */
739 salt = (ascii_to_bin(setting[1]) << 6) 742 output[0] = salt_str[0];
740 | ascii_to_bin(setting[0]); 743 output[1] = salt_str[1];
741 744 salt = (ascii_to_bin(salt_str[1]) << 6)
742 output[0] = setting[0]; 745 | ascii_to_bin(salt_str[0]);
743 /*
744 * If the encrypted password that the salt was extracted from
745 * is only 1 character long, the salt will be corrupted. We
746 * need to ensure that the output string doesn't have an extra
747 * NUL in it!
748 */
749 output[1] = setting[1] ? setting[1] : output[0];
750
751 setup_salt(ctx, salt); 746 setup_salt(ctx, salt);
747
752 /* Do it. */ 748 /* Do it. */
753 do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */); 749 do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */);
754 750
diff --git a/libbb/rtc.c b/libbb/rtc.c
index c4117ba34..54b52f23a 100644
--- a/libbb/rtc.c
+++ b/libbb/rtc.c
@@ -7,12 +7,6 @@
7#include "libbb.h" 7#include "libbb.h"
8#include "rtc_.h" 8#include "rtc_.h"
9 9
10#if ENABLE_FEATURE_HWCLOCK_ADJTIME_FHS
11# define ADJTIME_PATH "/var/lib/hwclock/adjtime"
12#else
13# define ADJTIME_PATH "/etc/adjtime"
14#endif
15
16int FAST_FUNC rtc_adjtime_is_utc(void) 10int FAST_FUNC rtc_adjtime_is_utc(void)
17{ 11{
18 int utc = 0; 12 int utc = 0;
diff --git a/libbb/run_shell.c b/libbb/run_shell.c
index a0420d982..c22bba87b 100644
--- a/libbb/run_shell.c
+++ b/libbb/run_shell.c
@@ -48,10 +48,10 @@ void FAST_FUNC set_current_security_context(security_context_t sid)
48 48
49#endif 49#endif
50 50
51/* Run SHELL, or DEFAULT_SHELL if SHELL is "" or NULL. 51/* Exec SHELL, or DEFAULT_SHELL if SHELL is "" or NULL.
52 * If ADDITIONAL_ARGS is not NULL, pass them to the shell. 52 * If ADDITIONAL_ARGS is not NULL, pass them to the shell.
53 */ 53 */
54void FAST_FUNC run_shell(const char *shell, int loginshell, const char **additional_args) 54void FAST_FUNC exec_shell(const char *shell, int loginshell, const char **additional_args)
55{ 55{
56 const char **args; 56 const char **args;
57 57
@@ -59,7 +59,7 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char **additio
59 while (args && *args) 59 while (args && *args)
60 args++; 60 args++;
61 61
62 args = xmalloc(sizeof(char*) * (2 + (args - additional_args))); 62 args = xzalloc(sizeof(args[0]) * (2 + (args - additional_args)));
63 63
64 if (!shell || !shell[0]) 64 if (!shell || !shell[0])
65 shell = DEFAULT_SHELL; 65 shell = DEFAULT_SHELL;
@@ -67,12 +67,11 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char **additio
67 args[0] = bb_get_last_path_component_nostrip(shell); 67 args[0] = bb_get_last_path_component_nostrip(shell);
68 if (loginshell) 68 if (loginshell)
69 args[0] = xasprintf("-%s", args[0]); 69 args[0] = xasprintf("-%s", args[0]);
70 args[1] = NULL; 70 /*args[1] = NULL; - already is */
71 if (additional_args) { 71 if (additional_args) {
72 int cnt = 1; 72 int cnt = 0;
73 for (;;) 73 while (*additional_args)
74 if ((args[cnt++] = *additional_args++) == NULL) 74 args[++cnt] = *additional_args++;
75 break;
76 } 75 }
77 76
78#if ENABLE_SELINUX 77#if ENABLE_SELINUX
@@ -84,3 +83,20 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char **additio
84 execv(shell, (char **) args); 83 execv(shell, (char **) args);
85 bb_perror_msg_and_die("can't execute '%s'", shell); 84 bb_perror_msg_and_die("can't execute '%s'", shell);
86} 85}
86
87void FAST_FUNC exec_login_shell(const char *shell)
88{
89 exec_shell(shell, 1, NULL);
90}
91
92/* Typical idiom for applets which exec *optional* PROG [ARGS] */
93void FAST_FUNC exec_prog_or_SHELL(char **argv)
94{
95 if (argv[0]) {
96 BB_EXECVP_or_die(argv);
97 }
98 /* Both users (nsenter and unshare) do indeed exec
99 * a _login_ shell (with dash in argv[0])!
100 */
101 exec_login_shell(getenv("SHELL"));
102}
diff --git a/libbb/speed_table.c b/libbb/speed_table.c
index 967cf8de8..cf7101e64 100644
--- a/libbb/speed_table.c
+++ b/libbb/speed_table.c
@@ -28,7 +28,7 @@ struct speed_map {
28}; 28};
29 29
30/* On Linux, Bxx constants are 0..15 (up to B38400) and 0x1001..0x100f */ 30/* On Linux, Bxx constants are 0..15 (up to B38400) and 0x1001..0x100f */
31static const struct speed_map speeds[] = { 31static const struct speed_map speeds[] ALIGN4 = {
32 {B0, 0}, 32 {B0, 0},
33 {B50, 50}, 33 {B50, 50},
34 {B75, 75}, 34 {B75, 75},
diff --git a/libbb/time.c b/libbb/time.c
index e66a9cba8..cf5f2e5c8 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -90,7 +90,11 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
90 ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ 90 ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
91 } else 91 } else
92 if (date_str[0] == '@') { 92 if (date_str[0] == '@') {
93 time_t t = bb_strtol(date_str + 1, NULL, 10); 93 time_t t;
94 if (sizeof(t) <= sizeof(long))
95 t = bb_strtol(date_str + 1, NULL, 10);
96 else /* time_t is 64 bits but longs are smaller */
97 t = bb_strtoll(date_str + 1, NULL, 10);
94 if (!errno) { 98 if (!errno) {
95 struct tm *lt = localtime(&t); 99 struct tm *lt = localtime(&t);
96 if (lt) { 100 if (lt) {
@@ -246,7 +250,6 @@ char* FAST_FUNC strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp)
246 250
247#if ENABLE_MONOTONIC_SYSCALL 251#if ENABLE_MONOTONIC_SYSCALL
248 252
249#include <sys/syscall.h>
250/* Old glibc (< 2.3.4) does not provide this constant. We use syscall 253/* Old glibc (< 2.3.4) does not provide this constant. We use syscall
251 * directly so this definition is safe. */ 254 * directly so this definition is safe. */
252#ifndef CLOCK_MONOTONIC 255#ifndef CLOCK_MONOTONIC
@@ -288,19 +291,19 @@ unsigned FAST_FUNC monotonic_sec(void)
288unsigned long long FAST_FUNC monotonic_ns(void) 291unsigned long long FAST_FUNC monotonic_ns(void)
289{ 292{
290 struct timeval tv; 293 struct timeval tv;
291 gettimeofday(&tv, NULL); 294 xgettimeofday(&tv);
292 return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000; 295 return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
293} 296}
294unsigned long long FAST_FUNC monotonic_us(void) 297unsigned long long FAST_FUNC monotonic_us(void)
295{ 298{
296 struct timeval tv; 299 struct timeval tv;
297 gettimeofday(&tv, NULL); 300 xgettimeofday(&tv);
298 return tv.tv_sec * 1000000ULL + tv.tv_usec; 301 return tv.tv_sec * 1000000ULL + tv.tv_usec;
299} 302}
300unsigned long long FAST_FUNC monotonic_ms(void) 303unsigned long long FAST_FUNC monotonic_ms(void)
301{ 304{
302 struct timeval tv; 305 struct timeval tv;
303 gettimeofday(&tv, NULL); 306 xgettimeofday(&tv);
304 return tv.tv_sec * 1000ULL + tv.tv_usec / 1000; 307 return tv.tv_sec * 1000ULL + tv.tv_usec / 1000;
305} 308}
306unsigned FAST_FUNC monotonic_sec(void) 309unsigned FAST_FUNC monotonic_sec(void)
diff --git a/libbb/unicode.c b/libbb/unicode.c
index 79481f159..e98cbbf35 100644
--- a/libbb/unicode.c
+++ b/libbb/unicode.c
@@ -25,7 +25,7 @@ uint8_t unicode_status;
25 25
26void FAST_FUNC reinit_unicode(const char *LANG) 26void FAST_FUNC reinit_unicode(const char *LANG)
27{ 27{
28 static const char unicode_0x394[] = { 0xce, 0x94, 0 }; 28 static const char unicode_0x394[] ALIGN1 = { 0xce, 0x94, 0 };
29 size_t width; 29 size_t width;
30 30
31 /* We pass "" instead of "C" because some libc's have 31 /* We pass "" instead of "C" because some libc's have
@@ -306,8 +306,10 @@ static int in_uint16_table(unsigned ucs, const uint16_t *table, unsigned max)
306 unsigned first, last; 306 unsigned first, last;
307 307
308 first = table[0] >> 2; 308 first = table[0] >> 2;
309 last = first + (table[0] & 3); 309 if (ucs < first)
310 if (ucs < first || ucs > last) 310 return 0;
311 last = (table[max] >> 2) + (table[max] & 3);
312 if (ucs > last)
311 return 0; 313 return 0;
312 314
313 min = 0; 315 min = 0;
@@ -587,12 +589,12 @@ int FAST_FUNC wcwidth(unsigned ucs)
587 BIG_(0xFE20, 0xFE23) \ 589 BIG_(0xFE20, 0xFE23) \
588 BIG_(0xFEFF, 0xFEFF) \ 590 BIG_(0xFEFF, 0xFEFF) \
589 BIG_(0xFFF9, 0xFFFB) 591 BIG_(0xFFF9, 0xFFFB)
590 static const struct interval combining[] = { ARRAY }; 592 static const struct interval combining[] ALIGN4 = { ARRAY };
591# undef BIG_ 593# undef BIG_
592# undef PAIR 594# undef PAIR
593# define BIG_(a,b) 595# define BIG_(a,b)
594# define PAIR(a,b) (a << 2) | (b-a), 596# define PAIR(a,b) (a << 2) | (b-a),
595 static const uint16_t combining1[] = { ARRAY }; 597 static const uint16_t combining1[] ALIGN2 = { ARRAY };
596# undef BIG_ 598# undef BIG_
597# undef PAIR 599# undef PAIR
598# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1]; 600# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1];
@@ -646,7 +648,7 @@ int FAST_FUNC wcwidth(unsigned ucs)
646# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x10000 648# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x10000
647 if (ucs >= 0x10000) { 649 if (ucs >= 0x10000) {
648 /* Combining chars in Supplementary Multilingual Plane 0x1xxxx */ 650 /* Combining chars in Supplementary Multilingual Plane 0x1xxxx */
649 static const struct interval combining0x10000[] = { 651 static const struct interval combining0x10000[] ALIGN4 = {
650 { 0x0A01, 0x0A03 }, { 0x0A05, 0x0A06 }, { 0x0A0C, 0x0A0F }, 652 { 0x0A01, 0x0A03 }, { 0x0A05, 0x0A06 }, { 0x0A0C, 0x0A0F },
651 { 0x0A38, 0x0A3A }, { 0x0A3F, 0x0A3F }, { 0xD167, 0xD169 }, 653 { 0x0A38, 0x0A3A }, { 0x0A3F, 0x0A3F }, { 0xD167, 0xD169 },
652 { 0xD173, 0xD182 }, { 0xD185, 0xD18B }, { 0xD1AA, 0xD1AD }, 654 { 0xD173, 0xD182 }, { 0xD185, 0xD18B }, { 0xD1AA, 0xD1AD },
@@ -757,12 +759,12 @@ int FAST_FUNC unicode_bidi_isrtl(wint_t wc)
757 {0x10E7F, 0x10FFF}, 759 {0x10E7F, 0x10FFF},
758 {0x1E800, 0x1EFFF} 760 {0x1E800, 0x1EFFF}
759 */ 761 */
760 static const struct interval rtl_b[] = { ARRAY }; 762 static const struct interval rtl_b[] ALIGN4 = { ARRAY };
761# undef BIG_ 763# undef BIG_
762# undef PAIR 764# undef PAIR
763# define BIG_(a,b) 765# define BIG_(a,b)
764# define PAIR(a,b) (a << 2) | (b-a), 766# define PAIR(a,b) (a << 2) | (b-a),
765 static const uint16_t rtl_p[] = { ARRAY }; 767 static const uint16_t rtl_p[] ALIGN2 = { ARRAY };
766# undef BIG_ 768# undef BIG_
767# undef PAIR 769# undef PAIR
768# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1]; 770# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1];
@@ -961,12 +963,12 @@ int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc)
961 {0x1F030, 0x1F093}, 963 {0x1F030, 0x1F093},
962 {0x1F100, 0x1F10A} 964 {0x1F100, 0x1F10A}
963 */ 965 */
964 static const struct interval neutral_b[] = { ARRAY }; 966 static const struct interval neutral_b[] ALIGN4 = { ARRAY };
965# undef BIG_ 967# undef BIG_
966# undef PAIR 968# undef PAIR
967# define BIG_(a,b) 969# define BIG_(a,b)
968# define PAIR(a,b) (a << 2) | (b-a), 970# define PAIR(a,b) (a << 2) | (b-a),
969 static const uint16_t neutral_p[] = { ARRAY }; 971 static const uint16_t neutral_p[] ALIGN2 = { ARRAY };
970# undef BIG_ 972# undef BIG_
971# undef PAIR 973# undef PAIR
972# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1]; 974# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1];
diff --git a/libbb/uuencode.c b/libbb/uuencode.c
index d36b34f63..21af7a8c9 100644
--- a/libbb/uuencode.c
+++ b/libbb/uuencode.c
@@ -8,8 +8,18 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11/* Conversion table. for base 64 */ 11/* Conversion tables */
12const char bb_uuenc_tbl_base64[65 + 1] ALIGN1 = { 12#if ENABLE_BASE32
13const char bb_uuenc_tbl_base32[] ALIGN1 = {
14 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
15 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
16 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
17 'Y', 'Z', '2', '3', '4', '5', '6', '7',
18 /* unused: '=', */
19};
20#endif
21/* for base 64 */
22const char bb_uuenc_tbl_base64[] ALIGN1 = {
13 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 23 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
14 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 24 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
15 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 25 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
@@ -18,11 +28,9 @@ const char bb_uuenc_tbl_base64[65 + 1] ALIGN1 = {
18 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 28 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
19 'w', 'x', 'y', 'z', '0', '1', '2', '3', 29 'w', 'x', 'y', 'z', '0', '1', '2', '3',
20 '4', '5', '6', '7', '8', '9', '+', '/', 30 '4', '5', '6', '7', '8', '9', '+', '/',
21 '=' /* termination character */, 31 '=' /* termination character */
22 '\0' /* needed for uudecode.c only */
23}; 32};
24 33const char bb_uuenc_tbl_std[] ALIGN1 = {
25const char bb_uuenc_tbl_std[65] ALIGN1 = {
26 '`', '!', '"', '#', '$', '%', '&', '\'', 34 '`', '!', '"', '#', '$', '%', '&', '\'',
27 '(', ')', '*', '+', ',', '-', '.', '/', 35 '(', ')', '*', '+', ',', '-', '.', '/',
28 '0', '1', '2', '3', '4', '5', '6', '7', 36 '0', '1', '2', '3', '4', '5', '6', '7',
@@ -30,7 +38,7 @@ const char bb_uuenc_tbl_std[65] ALIGN1 = {
30 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 38 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
31 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 39 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
32 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 40 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
33 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', 41 'X', 'Y', 'Z', '[', '\\',']', '^', '_',
34 '`' /* termination character */ 42 '`' /* termination character */
35}; 43};
36 44
@@ -72,86 +80,124 @@ void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl
72} 80}
73 81
74/* 82/*
75 * Decode base64 encoded string. Stops on '\0'. 83 * Decode base64 encoded string.
76 * 84 *
77 * Returns: pointer to the undecoded part of source. 85 * Returns: pointer past the last written output byte,
86 * the result is not NUL-terminated.
87 * (*pp_src) is advanced past the last read byte.
78 * If points to '\0', then the source was fully decoded. 88 * If points to '\0', then the source was fully decoded.
79 * (*pp_dst): advanced past the last written byte.
80 */ 89 */
81const char* FAST_FUNC decode_base64(char **pp_dst, const char *src) 90char* FAST_FUNC decode_base64(char *dst, const char **pp_src)
82{ 91{
83 char *dst = *pp_dst; 92 const char *src = pp_src ? *pp_src : dst; /* for httpd.c, support NULL 2nd param */
84 const char *src_tail; 93 unsigned ch = 0;
94 unsigned t;
95 int i = 0;
85 96
86 while (1) { 97 while ((t = (unsigned char)*src) != '\0') {
87 unsigned char six_bit[4]; 98 src++;
88 int count = 0;
89
90 /* Fetch up to four 6-bit values */
91 src_tail = src;
92 while (count < 4) {
93 char *table_ptr;
94 int ch;
95
96 /* Get next _valid_ character.
97 * bb_uuenc_tbl_base64[] contains this string:
98 * 0 1 2 3 4 5 6
99 * 01234567890123456789012345678901234567890123456789012345678901234
100 * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
101 */
102 do {
103 ch = *src;
104 if (ch == '\0') {
105 if (count == 0) {
106 /* Example:
107 * If we decode "QUJD <NUL>", we want
108 * to return ptr to NUL, not to ' ',
109 * because we did fully decode
110 * the string (to "ABC").
111 */
112 src_tail = src;
113 }
114 goto ret;
115 }
116 src++;
117 table_ptr = strchr(bb_uuenc_tbl_base64, ch);
118//TODO: add BASE64_FLAG_foo to die on bad char?
119 } while (!table_ptr);
120 99
121 /* Convert encoded character to decimal */ 100 /* "if" forest is faster than strchr(bb_uuenc_tbl_base64, t) */
122 ch = table_ptr - bb_uuenc_tbl_base64; 101 if (t >= '0' && t <= '9')
102 t = t - '0' + 52;
103 else if (t >= 'A' && t <= 'Z')
104 t = t - 'A';
105 else if (t >= 'a' && t <= 'z')
106 t = t - 'a' + 26;
107 else if (t == '+')
108 t = 62;
109 else if (t == '/')
110 t = 63;
111 else if (t == '=' && (i == 3 || (i == 2 && *src == '=')))
112 /* the above disallows "==AA", "A===", "AA=A" etc */
113 t = 0x1000000;
114 else
115//TODO: add BASE64_FLAG_foo to die on bad char?
116 continue;
123 117
124 /* ch is 64 if char was '=', otherwise 0..63 */ 118 ch = (ch << 6) | t;
125 if (ch == 64) 119 i = (i + 1) & 3;
120 if (i == 0) {
121 *dst++ = (char) (ch >> 16);
122 *dst++ = (char) (ch >> 8);
123 *dst++ = (char) ch;
124 if (ch & 0x1000000) { /* was last input char '='? */
125 dst--;
126 if (ch & (0x1000000 << 6)) /* was it "=="? */
127 dst--;
126 break; 128 break;
127 six_bit[count] = ch; 129 }
128 count++; 130 ch = 0;
131 }
132 }
133 /* i is zero here if full 4-char block was decoded */
134 if (pp_src)
135 *pp_src = src - i; /* -i signals truncation: e.g. "MQ" and "MQ=" (correct encoding is "MQ==" -> "1") */
136 return dst;
137}
138
139#if ENABLE_BASE32
140char* FAST_FUNC decode_base32(char *dst, const char **pp_src)
141{
142 const char *src = *pp_src;
143 uint64_t ch = 0;
144 unsigned t;
145 int i = 0;
146
147 while ((t = (unsigned char)*src) != '\0') {
148 src++;
149
150 /* "if" forest is faster than strchr(bb_uuenc_tbl_base32, t) */
151 if (t >= '2' && t <= '7')
152 t = t - '2' + 26;
153 else if (t == '=' && i > 1)
154 t = 0;
155 else {
156 t = (t | 0x20) - 'a';
157 if (t > 25)
158//TODO: add BASE64_FLAG_foo to die on bad char?
159 continue;
129 } 160 }
130 161
131 /* Transform 6-bit values to 8-bit ones. 162 ch = (ch << 5) | t;
132 * count can be < 4 when we decode the tail: 163 i = (i + 1) & 7;
133 * "eQ==" -> "y", not "y NUL NUL". 164 if (i == 0) {
134 * Note that (count > 1) is always true, 165 *dst++ = (char) (ch >> 32);
135 * "x===" encoding is not valid: 166 if (src[-1] == '=') /* was last input char '='? */
136 * even a single zero byte encodes as "AA==". 167 goto tail;
137 * However, with current logic we come here with count == 1 168 *dst++ = (char) (ch >> 24);
138 * when we decode "==" tail. 169 *dst++ = (char) (ch >> 16);
139 */ 170 *dst++ = (char) (ch >> 8);
140 if (count > 1) 171 *dst++ = (char) ch;
141 *dst++ = six_bit[0] << 2 | six_bit[1] >> 4; 172 }
142 if (count > 2) 173 }
143 *dst++ = six_bit[1] << 4 | six_bit[2] >> 2; 174 /* i is zero here if full 8-char block was decoded */
144 if (count > 3) 175 *pp_src = src - i;
145 *dst++ = six_bit[2] << 6 | six_bit[3]; 176 return dst;
146 /* Note that if we decode "AA==" and ate first '=', 177 tail:
147 * we just decoded one char (count == 2) and now we'll 178 {
148 * do the loop once more to decode second '='. 179 const char *s = src;
180 while (*--s == '=')
181 i++;
182 /* Why duplicate the below code? Testcase:
183 * echo ' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18' | base32 | base32 -d
184 * IOW, decoding of
185 * EAYSAMRAGMQDIIBVEA3CANZAHAQDSIBRGAQDCMJAGEZCAMJTEAYTIIBRGUQDCNRAGE3SAMJYBI==
186 * ====
187 * must correctly stitch together the tail, must not overwrite
188 * the tail before it is analyzed! (we can be decoding in-place)
189 * Else testcase fails, prints trailing extra NUL bytes.
149 */ 190 */
150 } /* while (1) */ 191 *dst++ = (char) (ch >> 24);
151 ret: 192 *dst++ = (char) (ch >> 16);
152 *pp_dst = dst; 193 *dst++ = (char) (ch >> 8);
153 return src_tail; 194 *dst++ = (char) ch;
195 dst -= (i+1) * 2 / 3; /* discard last 1, 2, 3 or 4 bytes */
196 }
197 *pp_src = src;
198 return dst;
154} 199}
200#endif
155 201
156/* 202/*
157 * Decode base64 encoded stream. 203 * Decode base64 encoded stream.
@@ -163,20 +209,22 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
163/* Note that EOF _can_ be passed as exit_char too */ 209/* Note that EOF _can_ be passed as exit_char too */
164#define exit_char ((int)(signed char)flags) 210#define exit_char ((int)(signed char)flags)
165#define uu_style_end (flags & BASE64_FLAG_UU_STOP) 211#define uu_style_end (flags & BASE64_FLAG_UU_STOP)
212#define base32 (flags & BASE64_32)
166 213
167 /* uuencoded files have 61 byte lines. Use 64 byte buffer 214 /* uuencoded files have 61 byte lines.
168 * to process line at a time. 215 * base32/64 have 76 byte lines by default.
216 * Use 80 byte buffer to process one line at a time.
169 */ 217 */
170 enum { BUFFER_SIZE = 64 }; 218 enum { BUFFER_SIZE = 80 };
171 219 /* decoded data is shorter than input, can use single buffer for both */
172 char in_buf[BUFFER_SIZE + 2]; 220 char buf[BUFFER_SIZE + 2];
173 char out_buf[BUFFER_SIZE / 4 * 3 + 2];
174 char *out_tail;
175 const char *in_tail;
176 int term_seen = 0; 221 int term_seen = 0;
177 int in_count = 0; 222 int in_count = 0;
178 223
179 while (1) { 224 while (1) {
225 char *out_tail;
226 const char *in_tail;
227
180 while (in_count < BUFFER_SIZE) { 228 while (in_count < BUFFER_SIZE) {
181 int ch = fgetc(src_stream); 229 int ch = fgetc(src_stream);
182 if (ch == exit_char) { 230 if (ch == exit_char) {
@@ -195,29 +243,34 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
195 */ 243 */
196 if (ch <= ' ') 244 if (ch <= ' ')
197 break; 245 break;
198 in_buf[in_count++] = ch; 246 buf[in_count++] = ch;
199 } 247 }
200 in_buf[in_count] = '\0'; 248 buf[in_count] = '\0';
201 249
202 /* Did we encounter "====" line? */ 250 /* Did we encounter "====" line? */
203 if (uu_style_end && strcmp(in_buf, "====") == 0) 251 if (uu_style_end && strcmp(buf, "====") == 0)
204 return; 252 return;
205 253
206 out_tail = out_buf; 254 in_tail = buf;
207 in_tail = decode_base64(&out_tail, in_buf); 255#if ENABLE_BASE32
256 if (base32)
257 out_tail = decode_base32(buf, &in_tail);
258 else
259#endif
260 out_tail = decode_base64(buf, &in_tail);
208 261
209 fwrite(out_buf, (out_tail - out_buf), 1, dst_stream); 262 fwrite(buf, (out_tail - buf), 1, dst_stream);
210 263
211 if (term_seen) { 264 if (term_seen) {
212 /* Did we consume ALL characters? */ 265 /* Did we consume ALL characters? */
213 if (*in_tail == '\0') 266 if (*in_tail == '\0')
214 return; 267 return;
215 /* No */ 268 /* No */
216 bb_simple_error_msg_and_die("truncated base64 input"); 269 bb_simple_error_msg_and_die("truncated input");
217 } 270 }
218 271
219 /* It was partial decode */ 272 /* It was partial decode */
220 in_count = strlen(in_tail); 273 in_count = strlen(in_tail);
221 memmove(in_buf, in_tail, in_count); 274 memmove(buf, in_tail, in_count);
222 } 275 }
223} 276}
diff --git a/libbb/xatonum.c b/libbb/xatonum.c
index 7639a62aa..36b06c849 100644
--- a/libbb/xatonum.c
+++ b/libbb/xatonum.c
@@ -68,14 +68,14 @@ uint16_t FAST_FUNC xatou16(const char *numstr)
68 return xatou_range(numstr, 0, 0xffff); 68 return xatou_range(numstr, 0, 0xffff);
69} 69}
70 70
71const struct suffix_mult bkm_suffixes[] = { 71const struct suffix_mult bkm_suffixes[] ALIGN_SUFFIX = {
72 { "b", 512 }, 72 { "b", 512 },
73 { "k", 1024 }, 73 { "k", 1024 },
74 { "m", 1024*1024 }, 74 { "m", 1024*1024 },
75 { "", 0 } 75 { "", 0 }
76}; 76};
77 77
78const struct suffix_mult cwbkMG_suffixes[] = { 78const struct suffix_mult cwbkMG_suffixes[] ALIGN_SUFFIX = {
79 { "c", 1 }, 79 { "c", 1 },
80 { "w", 2 }, 80 { "w", 2 },
81 { "b", 512 }, 81 { "b", 512 },
@@ -96,7 +96,7 @@ const struct suffix_mult cwbkMG_suffixes[] = {
96 { "", 0 } 96 { "", 0 }
97}; 97};
98 98
99const struct suffix_mult kmg_i_suffixes[] = { 99const struct suffix_mult kmg_i_suffixes[] ALIGN_SUFFIX = {
100 { "KiB", 1024 }, 100 { "KiB", 1024 },
101 { "kiB", 1024 }, 101 { "kiB", 1024 },
102 { "K", 1024 }, 102 { "K", 1024 },
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 38faef38e..f5c514b2c 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -428,17 +428,14 @@ int FAST_FUNC create_and_bind_to_netlink(int proto, int grp, unsigned rcvbuf)
428 struct sockaddr_nl sa; 428 struct sockaddr_nl sa;
429 int fd; 429 int fd;
430 430
431 memset(&sa, 0, sizeof(sa));
432 sa.nl_family = AF_NETLINK;
433 sa.nl_pid = getpid();
434 sa.nl_groups = grp;
435 fd = xsocket(AF_NETLINK, SOCK_DGRAM, proto); 431 fd = xsocket(AF_NETLINK, SOCK_DGRAM, proto);
436 xbind(fd, (struct sockaddr *) &sa, sizeof(sa));
437 close_on_exec_on(fd);
438 432
433 /* Set receive buffer size before binding the socket
434 * We want to have enough space before we start receiving messages.
435 */
439 if (rcvbuf != 0) { 436 if (rcvbuf != 0) {
440 // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl 437 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, rcvbuf);
441 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, rcvbuf); 438 /* SO_RCVBUFFORCE (root only) can go above net.core.rmem_max */
442 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, rcvbuf); 439 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, rcvbuf);
443# if 0 440# if 0
444 { 441 {
@@ -450,6 +447,13 @@ int FAST_FUNC create_and_bind_to_netlink(int proto, int grp, unsigned rcvbuf)
450# endif 447# endif
451 } 448 }
452 449
450 memset(&sa, 0, sizeof(sa));
451 sa.nl_family = AF_NETLINK;
452 sa.nl_pid = getpid();
453 sa.nl_groups = grp;
454 xbind(fd, (struct sockaddr *) &sa, sizeof(sa));
455 close_on_exec_on(fd);
456
453 return fd; 457 return fd;
454} 458}
455#endif 459#endif
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index c92436683..ef990118e 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -421,15 +421,3 @@ int FAST_FUNC wait4pid(pid_t pid)
421 return WTERMSIG(status) + 0x180; 421 return WTERMSIG(status) + 0x180;
422 return 0; 422 return 0;
423} 423}
424
425// Useful when we do know that pid is valid, and we just want to wait
426// for it to exit. Not existing pid is fatal. waitpid() status is not returned.
427int FAST_FUNC wait_for_exitstatus(pid_t pid)
428{
429 int exit_status, n;
430
431 n = safe_waitpid(pid, &exit_status, 0);
432 if (n < 0)
433 bb_simple_perror_msg_and_die("waitpid");
434 return exit_status;
435}
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 6fdc0f6a4..4bd19d471 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -111,6 +111,29 @@ void* FAST_FUNC xmemdup(const void *s, int n)
111 return memcpy(xmalloc(n), s, n); 111 return memcpy(xmalloc(n), s, n);
112} 112}
113 113
114#if !ENABLE_PLATFORM_MINGW32
115void* FAST_FUNC mmap_read(int fd, size_t size)
116{
117 return mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
118}
119
120void* FAST_FUNC mmap_anon(size_t size)
121{
122 return mmap(NULL, size,
123 PROT_READ | PROT_WRITE,
124 MAP_PRIVATE | MAP_ANONYMOUS,
125 /* ignored: */ -1, 0);
126}
127
128void* FAST_FUNC xmmap_anon(size_t size)
129{
130 void *p = mmap_anon(size);
131 if (p == MAP_FAILED)
132 bb_die_memory_exhausted();
133 return p;
134}
135#endif
136
114// Die if we can't open a file and return a FILE* to it. 137// Die if we can't open a file and return a FILE* to it.
115// Notice we haven't got xfread(), This is for use with fscanf() and friends. 138// Notice we haven't got xfread(), This is for use with fscanf() and friends.
116FILE* FAST_FUNC xfopen(const char *path, const char *mode) 139FILE* FAST_FUNC xfopen(const char *path, const char *mode)
@@ -502,22 +525,22 @@ void FAST_FUNC xfstat(int fd, struct stat *stat_buf, const char *errmsg)
502 bb_simple_perror_msg_and_die(errmsg); 525 bb_simple_perror_msg_and_die(errmsg);
503} 526}
504 527
505#if !ENABLE_PLATFORM_MINGW32 528#if ENABLE_SELINUX
506// selinux_or_die() - die if SELinux is disabled. 529// selinux_or_die() - die if SELinux is disabled.
507void FAST_FUNC selinux_or_die(void) 530void FAST_FUNC selinux_or_die(void)
508{ 531{
509#if ENABLE_SELINUX
510 int rc = is_selinux_enabled(); 532 int rc = is_selinux_enabled();
511 if (rc == 0) { 533 if (rc == 0) {
512 bb_simple_error_msg_and_die("SELinux is disabled"); 534 bb_simple_error_msg_and_die("SELinux is disabled");
513 } else if (rc < 0) { 535 } else if (rc < 0) {
514 bb_simple_error_msg_and_die("is_selinux_enabled() failed"); 536 bb_simple_error_msg_and_die("is_selinux_enabled() failed");
515 } 537 }
538}
516#else 539#else
517 bb_simple_error_msg_and_die("SELinux support is disabled"); 540/* not defined, other code must have no calls to it */
518#endif 541#endif
519}
520 542
543#if !ENABLE_PLATFORM_MINGW32
521int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...) 544int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...)
522{ 545{
523 int ret; 546 int ret;
@@ -634,14 +657,11 @@ void FAST_FUNC generate_uuid(uint8_t *buf)
634 pid_t pid; 657 pid_t pid;
635 int i; 658 int i;
636 659
637 i = open("/dev/urandom", O_RDONLY); 660 open_read_close("/dev/urandom", buf, 16);
638 if (i >= 0) {
639 read(i, buf, 16);
640 close(i);
641 }
642 /* Paranoia. /dev/urandom may be missing. 661 /* Paranoia. /dev/urandom may be missing.
643 * rand() is guaranteed to generate at least [0, 2^15) range, 662 * rand() is guaranteed to generate at least [0, 2^15) range,
644 * but lowest bits in some libc are not so "random". */ 663 * but lowest bits in some libc are not so "random".
664 */
645 srand(monotonic_us()); /* pulls in printf */ 665 srand(monotonic_us()); /* pulls in printf */
646 pid = getpid(); 666 pid = getpid();
647 while (1) { 667 while (1) {
@@ -686,3 +706,34 @@ void FAST_FUNC xvfork_parent_waits_and_exits(void)
686 /* Child continues */ 706 /* Child continues */
687} 707}
688#endif /* !ENABLE_PLATFORM_MINGW32 */ 708#endif /* !ENABLE_PLATFORM_MINGW32 */
709
710// Useful when we do know that pid is valid, and we just want to wait
711// for it to exit. Not existing pid is fatal. waitpid() status is not returned.
712int FAST_FUNC wait_for_exitstatus(pid_t pid)
713{
714 int exit_status, n;
715
716 n = safe_waitpid(pid, &exit_status, 0);
717 if (n < 0)
718 bb_simple_perror_msg_and_die("waitpid");
719 return exit_status;
720}
721
722#if !ENABLE_PLATFORM_MINGW32
723void FAST_FUNC xsettimeofday(const struct timeval *tv)
724{
725 if (settimeofday(tv, NULL))
726 bb_simple_perror_msg_and_die("settimeofday");
727}
728#endif
729
730void FAST_FUNC xgettimeofday(struct timeval *tv)
731{
732#if 0
733 if (gettimeofday(tv, NULL))
734 bb_simple_perror_msg_and_die("gettimeofday");
735#else
736 /* Never fails on Linux */
737 gettimeofday(tv, NULL);
738#endif
739}
diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c
index 4e70b2557..a032abbed 100644
--- a/loginutils/chpasswd.c
+++ b/loginutils/chpasswd.c
@@ -24,21 +24,13 @@
24//kbuild:lib-$(CONFIG_CHPASSWD) += chpasswd.o 24//kbuild:lib-$(CONFIG_CHPASSWD) += chpasswd.o
25 25
26//usage:#define chpasswd_trivial_usage 26//usage:#define chpasswd_trivial_usage
27//usage: IF_LONG_OPTS("[--md5|--encrypted|--crypt-method|--root]") IF_NOT_LONG_OPTS("[-m|-e|-c|-R]") 27//usage: "[-me] [-c ALG] [-R DIR]"
28//usage:#define chpasswd_full_usage "\n\n" 28//usage:#define chpasswd_full_usage "\n\n"
29//usage: "Read user:password from stdin and update /etc/passwd\n" 29//usage: "Read user:password from stdin and update /etc/passwd\n"
30//usage: IF_LONG_OPTS(
31//usage: "\n -e,--encrypted Supplied passwords are in encrypted form"
32//usage: "\n -m,--md5 Encrypt using md5, not des"
33//usage: "\n -c,--crypt-method ALG "CRYPT_METHODS_HELP_STR
34//usage: "\n -R,--root DIR Directory to chroot into"
35//usage: )
36//usage: IF_NOT_LONG_OPTS(
37//usage: "\n -e Supplied passwords are in encrypted form" 30//usage: "\n -e Supplied passwords are in encrypted form"
38//usage: "\n -m Encrypt using md5, not des" 31//usage: "\n -m Encrypt using md5, not des"
39//usage: "\n -c ALG "CRYPT_METHODS_HELP_STR 32//usage: "\n -c ALG "CRYPT_METHODS_HELP_STR
40//usage: "\n -R DIR Directory to chroot into" 33//usage: "\n -R DIR Directory to chroot into"
41//usage: )
42 34
43#include "libbb.h" 35#include "libbb.h"
44 36
diff --git a/loginutils/cryptpw.c b/loginutils/cryptpw.c
index fbb7f0515..645f1bb09 100644
--- a/loginutils/cryptpw.c
+++ b/loginutils/cryptpw.c
@@ -32,22 +32,14 @@
32//kbuild:lib-$(CONFIG_MKPASSWD) += cryptpw.o 32//kbuild:lib-$(CONFIG_MKPASSWD) += cryptpw.o
33 33
34//usage:#define cryptpw_trivial_usage 34//usage:#define cryptpw_trivial_usage
35//usage: "[OPTIONS] [PASSWORD] [SALT]" 35//usage: "[-s] [-p N] [-m TYPE] [-S SALT] [PASSWORD] [SALT]"
36/* We do support -s, we just don't mention it */ 36/* We do support -s, we just don't mention it */
37//usage:#define cryptpw_full_usage "\n\n" 37//usage:#define cryptpw_full_usage "\n\n"
38//usage: "Print crypt(3) hashed PASSWORD\n" 38//usage: "Print crypt(3) hashed PASSWORD\n"
39//usage: IF_LONG_OPTS(
40//usage: "\n -P,--password-fd N Read password from fd N"
41/* //usage: "\n -s,--stdin Use stdin; like -P0" */
42//usage: "\n -m,--method TYPE "CRYPT_METHODS_HELP_STR
43//usage: "\n -S,--salt SALT"
44//usage: )
45//usage: IF_NOT_LONG_OPTS(
46//usage: "\n -P N Read password from fd N" 39//usage: "\n -P N Read password from fd N"
47/* //usage: "\n -s Use stdin; like -P0" */ 40/* //usage: "\n -s Use stdin; like -P0" */
48//usage: "\n -m TYPE "CRYPT_METHODS_HELP_STR 41//usage: "\n -m TYPE "CRYPT_METHODS_HELP_STR
49//usage: "\n -S SALT" 42//usage: "\n -S SALT"
50//usage: )
51 43
52#include "libbb.h" 44#include "libbb.h"
53 45
diff --git a/loginutils/getty.c b/loginutils/getty.c
index 7393a3d1c..6c6d409f4 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -404,7 +404,7 @@ static void finalize_tty_attrs(void)
404 set_tty_attrs(); 404 set_tty_attrs();
405 405
406 /* Now the newline character should be properly written */ 406 /* Now the newline character should be properly written */
407 full_write(STDOUT_FILENO, "\n", 1); 407 full_write1_str("\n");
408} 408}
409 409
410/* extract baud rate from modem status message */ 410/* extract baud rate from modem status message */
@@ -434,7 +434,7 @@ static void auto_baud(void)
434 * Wait for a while, then read everything the modem has said so far and 434 * Wait for a while, then read everything the modem has said so far and
435 * try to extract the speed of the dial-in call. 435 * try to extract the speed of the dial-in call.
436 */ 436 */
437 sleep(1); 437 sleep1();
438 nread = safe_read(STDIN_FILENO, G.line_buf, sizeof(G.line_buf) - 1); 438 nread = safe_read(STDIN_FILENO, G.line_buf, sizeof(G.line_buf) - 1);
439 if (nread > 0) { 439 if (nread > 0) {
440 int speed; 440 int speed;
@@ -498,13 +498,13 @@ static char *get_logname(void)
498 case 0x7f: 498 case 0x7f:
499 G.tty_attrs.c_cc[VERASE] = c; 499 G.tty_attrs.c_cc[VERASE] = c;
500 if (bp > G.line_buf) { 500 if (bp > G.line_buf) {
501 full_write(STDOUT_FILENO, "\010 \010", 3); 501 full_write1_str("\010 \010");
502 bp--; 502 bp--;
503 } 503 }
504 break; 504 break;
505 case CTL('U'): 505 case CTL('U'):
506 while (bp > G.line_buf) { 506 while (bp > G.line_buf) {
507 full_write(STDOUT_FILENO, "\010 \010", 3); 507 full_write1_str("\010 \010");
508 bp--; 508 bp--;
509 } 509 }
510 break; 510 break;
diff --git a/loginutils/login.c b/loginutils/login.c
index 4e65b3a19..21c32fc25 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -341,6 +341,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
341#if ENABLE_LOGIN_SESSION_AS_CHILD 341#if ENABLE_LOGIN_SESSION_AS_CHILD
342 pid_t child_pid; 342 pid_t child_pid;
343#endif 343#endif
344 IF_FEATURE_UTMP(pid_t my_pid;)
344 345
345 INIT_G(); 346 INIT_G();
346 347
@@ -504,16 +505,14 @@ int login_main(int argc UNUSED_PARAM, char **argv)
504#endif /* ENABLE_PAM */ 505#endif /* ENABLE_PAM */
505 auth_failed: 506 auth_failed:
506 opt &= ~LOGIN_OPT_f; 507 opt &= ~LOGIN_OPT_f;
507 bb_do_delay(LOGIN_FAIL_DELAY); 508 pause_after_failed_login();
508 /* TODO: doesn't sound like correct English phrase to me */ 509 /* TODO: doesn't sound like correct English phrase to me */
509 puts("Login incorrect"); 510 puts("Login incorrect");
511 syslog(LOG_WARNING, "invalid password for '%s'%s",
512 username, fromhost);
510 if (++count == 3) { 513 if (++count == 3) {
511 syslog(LOG_WARNING, "invalid password for '%s'%s",
512 username, fromhost);
513
514 if (ENABLE_FEATURE_CLEAN_UP) 514 if (ENABLE_FEATURE_CLEAN_UP)
515 free(fromhost); 515 free(fromhost);
516
517 return EXIT_FAILURE; 516 return EXIT_FAILURE;
518 } 517 }
519 username[0] = '\0'; 518 username[0] = '\0';
@@ -525,6 +524,9 @@ int login_main(int argc UNUSED_PARAM, char **argv)
525 if (pw->pw_uid != 0) 524 if (pw->pw_uid != 0)
526 die_if_nologin(); 525 die_if_nologin();
527 526
527 IF_FEATURE_UTMP(my_pid = getpid();)
528 update_utmp(my_pid, USER_PROCESS, short_tty, username, run_by_root ? opt_host : NULL);
529
528#if ENABLE_LOGIN_SESSION_AS_CHILD 530#if ENABLE_LOGIN_SESSION_AS_CHILD
529 child_pid = vfork(); 531 child_pid = vfork();
530 if (child_pid != 0) { 532 if (child_pid != 0) {
@@ -532,8 +534,8 @@ int login_main(int argc UNUSED_PARAM, char **argv)
532 bb_simple_perror_msg("vfork"); 534 bb_simple_perror_msg("vfork");
533 else { 535 else {
534 wait_for_exitstatus(child_pid); 536 wait_for_exitstatus(child_pid);
535 update_utmp_DEAD_PROCESS(child_pid);
536 } 537 }
538 update_utmp_DEAD_PROCESS(my_pid);
537 login_pam_end(pamh); 539 login_pam_end(pamh);
538 return 0; 540 return 0;
539 } 541 }
@@ -546,8 +548,6 @@ int login_main(int argc UNUSED_PARAM, char **argv)
546 fchown(0, pw->pw_uid, pw->pw_gid); 548 fchown(0, pw->pw_uid, pw->pw_gid);
547 fchmod(0, 0600); 549 fchmod(0, 0600);
548 550
549 update_utmp(getpid(), USER_PROCESS, short_tty, username, run_by_root ? opt_host : NULL);
550
551 /* We trust environment only if we run by root */ 551 /* We trust environment only if we run by root */
552 if (ENABLE_LOGIN_SCRIPTS && run_by_root) 552 if (ENABLE_LOGIN_SCRIPTS && run_by_root)
553 run_login_script(pw, full_tty); 553 run_login_script(pw, full_tty);
@@ -602,7 +602,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
602 signal(SIGINT, SIG_DFL); 602 signal(SIGINT, SIG_DFL);
603 603
604 /* Exec login shell with no additional parameters */ 604 /* Exec login shell with no additional parameters */
605 run_shell(pw->pw_shell, 1, NULL); 605 exec_login_shell(pw->pw_shell);
606 606
607 /* return EXIT_FAILURE; - not reached */ 607 /* return EXIT_FAILURE; - not reached */
608} 608}
diff --git a/loginutils/passwd.c b/loginutils/passwd.c
index 6c643d3d0..acc942275 100644
--- a/loginutils/passwd.c
+++ b/loginutils/passwd.c
@@ -28,7 +28,7 @@
28//kbuild:lib-$(CONFIG_PASSWD) += passwd.o 28//kbuild:lib-$(CONFIG_PASSWD) += passwd.o
29 29
30//usage:#define passwd_trivial_usage 30//usage:#define passwd_trivial_usage
31//usage: "[OPTIONS] [USER]" 31//usage: "[-a ALG] [-dlu] [USER]"
32//usage:#define passwd_full_usage "\n\n" 32//usage:#define passwd_full_usage "\n\n"
33//usage: "Change USER's password (default: current user)" 33//usage: "Change USER's password (default: current user)"
34//usage: "\n" 34//usage: "\n"
@@ -57,7 +57,7 @@ static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo
57 encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */ 57 encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */
58 if (strcmp(encrypted, pw->pw_passwd) != 0) { 58 if (strcmp(encrypted, pw->pw_passwd) != 0) {
59 syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name); 59 syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name);
60 bb_do_delay(LOGIN_FAIL_DELAY); 60 pause_after_failed_login();
61 puts("Incorrect password"); 61 puts("Incorrect password");
62 goto err_ret; 62 goto err_ret;
63 } 63 }
diff --git a/loginutils/su.c b/loginutils/su.c
index 79edbc44a..e46bbf78b 100644
--- a/loginutils/su.c
+++ b/loginutils/su.c
@@ -147,7 +147,7 @@ int su_main(int argc UNUSED_PARAM, char **argv)
147 if (ENABLE_FEATURE_SU_SYSLOG) 147 if (ENABLE_FEATURE_SU_SYSLOG)
148 syslog(LOG_NOTICE, "%c %s %s:%s", 148 syslog(LOG_NOTICE, "%c %s %s:%s",
149 '-', tty, old_user, opt_username); 149 '-', tty, old_user, opt_username);
150 bb_do_delay(LOGIN_FAIL_DELAY); 150 pause_after_failed_login();
151 bb_simple_error_msg_and_die("incorrect password"); 151 bb_simple_error_msg_and_die("incorrect password");
152 } 152 }
153 153
@@ -205,7 +205,7 @@ int su_main(int argc UNUSED_PARAM, char **argv)
205 */ 205 */
206 206
207 /* Never returns */ 207 /* Never returns */
208 run_shell(opt_shell, flags & SU_OPT_l, (const char**)argv); 208 exec_shell(opt_shell, flags & SU_OPT_l, (const char**)argv);
209 209
210 /* return EXIT_FAILURE; - not reached */ 210 /* return EXIT_FAILURE; - not reached */
211} 211}
diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c
index 099085340..69d8b5ec7 100644
--- a/loginutils/sulogin.c
+++ b/loginutils/sulogin.c
@@ -74,7 +74,7 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv)
74 if (r > 0) { 74 if (r > 0) {
75 break; 75 break;
76 } 76 }
77 bb_do_delay(LOGIN_FAIL_DELAY); 77 pause_after_failed_login();
78 bb_simple_info_msg("Login incorrect"); 78 bb_simple_info_msg("Login incorrect");
79 } 79 }
80 80
@@ -89,5 +89,5 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv)
89 shell = pwd->pw_shell; 89 shell = pwd->pw_shell;
90 90
91 /* Exec login shell with no additional parameters. Never returns. */ 91 /* Exec login shell with no additional parameters. Never returns. */
92 run_shell(shell, 1, NULL); 92 exec_login_shell(shell);
93} 93}
diff --git a/loginutils/vlock.c b/loginutils/vlock.c
index 9e319fe61..334b7d2ad 100644
--- a/loginutils/vlock.c
+++ b/loginutils/vlock.c
@@ -120,7 +120,7 @@ int vlock_main(int argc UNUSED_PARAM, char **argv)
120 if (ask_and_check_password(pw) > 0) { 120 if (ask_and_check_password(pw) > 0) {
121 break; 121 break;
122 } 122 }
123 bb_do_delay(LOGIN_FAIL_DELAY); 123 pause_after_failed_login();
124 puts("Incorrect password"); 124 puts("Incorrect password");
125 } 125 }
126 126
diff --git a/mailutils/mail.c b/mailutils/mail.c
index 3a1fd6949..f48b41bab 100644
--- a/mailutils/mail.c
+++ b/mailutils/mail.c
@@ -6,39 +6,45 @@
6 * 6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree. 7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */ 8 */
9#include <sys/prctl.h> 9#if defined(__linux__)
10# include <sys/prctl.h>
11# define PRCTL
12#elif defined(__FreeBSD__)
13# include <sys/procctl.h>
14# define PROCCTL
15#endif
10#include "libbb.h" 16#include "libbb.h"
11#include "mail.h" 17#include "mail.h"
12 18
13// generic signal handler 19// common signal handler
14static void signal_handler(int signo) 20static void signal_handler(int signo)
15{ 21{
16#define err signo
17 if (SIGALRM == signo) { 22 if (SIGALRM == signo) {
18 bb_simple_error_msg_and_die("timed out"); 23 bb_simple_error_msg_and_die("timed out");
19 } 24 }
20 25
21 // SIGCHLD. reap zombies 26 // SIGCHLD. reap the zombie if we expect one
22 if (safe_waitpid(G.helper_pid, &err, WNOHANG) > 0) { 27 if (G.helper_pid == 0)
23 if (WIFSIGNALED(err)) 28 return;
24 bb_error_msg_and_die("helper killed by signal %u", WTERMSIG(err)); 29#define status signo
25 if (WIFEXITED(err)) { 30 if (safe_waitpid(G.helper_pid, &status, WNOHANG) > 0) {
26 G.helper_pid = 0; 31 G.helper_pid = 0;
27 if (WEXITSTATUS(err)) 32 if (WIFSIGNALED(status))
28 bb_error_msg_and_die("helper exited (%u)", WEXITSTATUS(err)); 33 bb_error_msg_and_die("helper killed by signal %u", WTERMSIG(status));
29 } 34 if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
35 bb_error_msg_and_die("helper exited (%u)", WEXITSTATUS(status));
30 } 36 }
31#undef err 37#undef status
32} 38}
33 39
34void FAST_FUNC launch_helper(const char **argv) 40void FAST_FUNC launch_helper(const char **argv)
35{ 41{
36 // setup vanilla unidirectional pipes interchange 42 pid_t pid;
37 int i; 43 struct fd_pair child_out;
38 int pipes[4]; 44 struct fd_pair child_in;
39 45
40 xpipe(pipes); 46 xpiped_pair(child_out);
41 xpipe(pipes + 2); 47 xpiped_pair(child_in);
42 48
43 // NB: handler must be installed before vfork 49 // NB: handler must be installed before vfork
44 bb_signals(0 50 bb_signals(0
@@ -46,40 +52,52 @@ void FAST_FUNC launch_helper(const char **argv)
46 + (1 << SIGALRM) 52 + (1 << SIGALRM)
47 , signal_handler); 53 , signal_handler);
48 54
49 G.helper_pid = xvfork(); 55 fflush_all();
50 56 pid = xvfork();
51 i = (!G.helper_pid) * 2; // for parent:0, for child:2 57 if (pid == 0) {
52 close(pipes[i + 1]); // 1 or 3 - closing one write end
53 close(pipes[2 - i]); // 2 or 0 - closing one read end
54 xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end
55 xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - using other write end
56 // End result:
57 // parent stdout [3] -> child stdin [2]
58 // child stdout [1] -> parent stdin [0]
59
60 if (!G.helper_pid) {
61 // child 58 // child
59 close(child_in.wr);
60 close(child_out.rd);
61 xmove_fd(child_in.rd, STDIN_FILENO);
62 xmove_fd(child_out.wr, STDOUT_FILENO);
62 // if parent dies, get SIGTERM 63 // if parent dies, get SIGTERM
64#if defined(PRCTL)
63 prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); 65 prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
66#elif defined(PROCCTL)
67 {
68 int signum = SIGTERM;
69 procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
70 }
71#endif
64 // try to execute connection helper 72 // try to execute connection helper
65 // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec 73 // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec
66 BB_EXECVP_or_die((char**)argv); 74 BB_EXECVP_or_die((char**)argv);
67 } 75 }
76 G.helper_pid = pid;
77 close(child_out.wr);
78 close(child_in.rd);
79 xmove_fd(child_out.rd, STDIN_FILENO);
80 xmove_fd(child_in.wr, STDOUT_FILENO);
68 81
69 // parent goes on 82 // parent goes on
70} 83}
71 84
85void FAST_FUNC send_r_n(const char *s)
86{
87 if (G.verbose)
88 bb_error_msg("send:'%s'", s);
89 printf("%s\r\n", s);
90}
91
72char* FAST_FUNC send_mail_command(const char *fmt, const char *param) 92char* FAST_FUNC send_mail_command(const char *fmt, const char *param)
73{ 93{
74 char *msg; 94 char *msg;
75 if (timeout) 95 if (G.timeout)
76 alarm(timeout); 96 alarm(G.timeout);
77 msg = (char*)fmt; 97 msg = (char*)fmt;
78 if (fmt) { 98 if (fmt) {
79 msg = xasprintf(fmt, param); 99 msg = xasprintf(fmt, param);
80 if (verbose) 100 send_r_n(msg);
81 bb_error_msg("send:'%s'", msg);
82 printf("%s\r\n", msg);
83 } 101 }
84 fflush_all(); 102 fflush_all();
85 return msg; 103 return msg;
diff --git a/mailutils/mail.h b/mailutils/mail.h
index b14228a4a..a07d535cf 100644
--- a/mailutils/mail.h
+++ b/mailutils/mail.h
@@ -11,7 +11,6 @@ struct globals {
11 pid_t helper_pid; 11 pid_t helper_pid;
12 unsigned timeout; 12 unsigned timeout;
13 unsigned verbose; 13 unsigned verbose;
14 unsigned opts;
15 char *user; 14 char *user;
16 char *pass; 15 char *pass;
17 FILE *fp0; // initial stdin 16 FILE *fp0; // initial stdin
@@ -19,9 +18,6 @@ struct globals {
19}; 18};
20 19
21#define G (*ptr_to_globals) 20#define G (*ptr_to_globals)
22#define timeout (G.timeout )
23#define verbose (G.verbose )
24#define opts (G.opts )
25#define INIT_G() do { \ 21#define INIT_G() do { \
26 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 22 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
27 G.opt_charset = (char *)CONFIG_FEATURE_MIME_CHARSET; \ 23 G.opt_charset = (char *)CONFIG_FEATURE_MIME_CHARSET; \
@@ -32,6 +28,7 @@ struct globals {
32void launch_helper(const char **argv) FAST_FUNC; 28void launch_helper(const char **argv) FAST_FUNC;
33void get_cred_or_die(int fd) FAST_FUNC; 29void get_cred_or_die(int fd) FAST_FUNC;
34 30
31void send_r_n(const char *s) FAST_FUNC;
35char *send_mail_command(const char *fmt, const char *param) FAST_FUNC; 32char *send_mail_command(const char *fmt, const char *param) FAST_FUNC;
36 33
37void printbuf_base64(const char *buf, unsigned len) FAST_FUNC; 34void printbuf_base64(const char *buf, unsigned len) FAST_FUNC;
diff --git a/mailutils/makemime.c b/mailutils/makemime.c
index 53a1820f1..1ff2012d5 100644
--- a/mailutils/makemime.c
+++ b/mailutils/makemime.c
@@ -173,6 +173,7 @@ Content-Transfer-Encoding: 7bit
173int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 173int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
174int makemime_main(int argc UNUSED_PARAM, char **argv) 174int makemime_main(int argc UNUSED_PARAM, char **argv)
175{ 175{
176 unsigned opts;
176 llist_t *opt_headers = NULL, *l; 177 llist_t *opt_headers = NULL, *l;
177 const char *opt_output; 178 const char *opt_output;
178 const char *content_type = "application/octet-stream"; 179 const char *content_type = "application/octet-stream";
diff --git a/mailutils/popmaildir.c b/mailutils/popmaildir.c
index c5522f1b7..1f2db2892 100644
--- a/mailutils/popmaildir.c
+++ b/mailutils/popmaildir.c
@@ -68,10 +68,11 @@
68static void pop3_checkr(const char *fmt, const char *param, char **ret) 68static void pop3_checkr(const char *fmt, const char *param, char **ret)
69{ 69{
70 char *msg = send_mail_command(fmt, param); 70 char *msg = send_mail_command(fmt, param);
71//FIXME: limit max len!!!
71 char *answer = xmalloc_fgetline(stdin); 72 char *answer = xmalloc_fgetline(stdin);
72 if (answer && '+' == answer[0]) { 73 if (answer && '+' == answer[0]) {
73 free(msg); 74 free(msg);
74 if (timeout) 75 if (G.timeout)
75 alarm(0); 76 alarm(0);
76 if (ret) { 77 if (ret) {
77 // skip "+OK " 78 // skip "+OK "
@@ -92,6 +93,7 @@ static void pop3_check(const char *fmt, const char *param)
92int popmaildir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 93int popmaildir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
93int popmaildir_main(int argc UNUSED_PARAM, char **argv) 94int popmaildir_main(int argc UNUSED_PARAM, char **argv)
94{ 95{
96 unsigned opts;
95 char *buf; 97 char *buf;
96 unsigned nmsg; 98 unsigned nmsg;
97 char *hostname; 99 char *hostname;
@@ -128,7 +130,7 @@ int popmaildir_main(int argc UNUSED_PARAM, char **argv)
128 opts = getopt32(argv, "^" 130 opts = getopt32(argv, "^"
129 "bdmVcasTkt:+" "R:+Z:L:+H:+" IF_FEATURE_POPMAILDIR_DELIVERY("M:F:") 131 "bdmVcasTkt:+" "R:+Z:L:+H:+" IF_FEATURE_POPMAILDIR_DELIVERY("M:F:")
130 "\0" "-1:dd", 132 "\0" "-1:dd",
131 &timeout, NULL, NULL, NULL, &opt_nlines 133 &G.timeout, NULL, NULL, NULL, &opt_nlines
132 IF_FEATURE_POPMAILDIR_DELIVERY(, &delivery, &delivery) // we treat -M and -F the same 134 IF_FEATURE_POPMAILDIR_DELIVERY(, &delivery, &delivery) // we treat -M and -F the same
133 ); 135 );
134 //argc -= optind; 136 //argc -= optind;
diff --git a/mailutils/reformime.c b/mailutils/reformime.c
index 307656a15..a1d3f4e8b 100644
--- a/mailutils/reformime.c
+++ b/mailutils/reformime.c
@@ -166,7 +166,7 @@ static int parse(const char *boundary, char **argv)
166 else 166 else
167 filename = bb_get_last_path_component_strip(xstrdup(filename)); 167 filename = bb_get_last_path_component_strip(xstrdup(filename));
168 168
169 if (opts & OPT_X) { 169 if (option_mask32 & OPT_X) {
170 int fd[2]; 170 int fd[2];
171 171
172 /* start external helper */ 172 /* start external helper */
@@ -219,7 +219,7 @@ static int parse(const char *boundary, char **argv)
219 fclose(fp); 219 fclose(fp);
220 220
221 /* Wait for child */ 221 /* Wait for child */
222 if (opts & OPT_X) { 222 if (option_mask32 & OPT_X) {
223 int rc; 223 int rc;
224 signal(SIGPIPE, SIG_DFL); 224 signal(SIGPIPE, SIG_DFL);
225 rc = (wait4pid(pid) & 0xff); 225 rc = (wait4pid(pid) & 0xff);
@@ -275,6 +275,7 @@ Usage: reformime [options]
275int reformime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 275int reformime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
276int reformime_main(int argc UNUSED_PARAM, char **argv) 276int reformime_main(int argc UNUSED_PARAM, char **argv)
277{ 277{
278 unsigned opts;
278 const char *opt_prefix = ""; 279 const char *opt_prefix = "";
279 280
280 INIT_G(); 281 INIT_G();
diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c
index 1bdc1c300..1a01b7110 100644
--- a/mailutils/sendmail.c
+++ b/mailutils/sendmail.c
@@ -102,13 +102,6 @@
102// set to 0 to not limit 102// set to 0 to not limit
103#define MAX_HEADERS 256 103#define MAX_HEADERS 256
104 104
105static void send_r_n(const char *s)
106{
107 if (verbose)
108 bb_error_msg("send:'%s'", s);
109 printf("%s\r\n", s);
110}
111
112static int smtp_checkp(const char *fmt, const char *param, int code) 105static int smtp_checkp(const char *fmt, const char *param, int code)
113{ 106{
114 char *answer; 107 char *answer;
@@ -119,8 +112,9 @@ static int smtp_checkp(const char *fmt, const char *param, int code)
119 // if code = -1 then just return this number 112 // if code = -1 then just return this number
120 // if code != -1 then checks whether the number equals the code 113 // if code != -1 then checks whether the number equals the code
121 // if not equal -> die saying msg 114 // if not equal -> die saying msg
115//FIXME: limit max len!!!
122 while ((answer = xmalloc_fgetline(stdin)) != NULL) { 116 while ((answer = xmalloc_fgetline(stdin)) != NULL) {
123 if (verbose) 117 if (G.verbose)
124 bb_error_msg("recv:'%.*s'", (int)(strchrnul(answer, '\r') - answer), answer); 118 bb_error_msg("recv:'%.*s'", (int)(strchrnul(answer, '\r') - answer), answer);
125 if (strlen(answer) <= 3 || '-' != answer[3]) 119 if (strlen(answer) <= 3 || '-' != answer[3])
126 break; 120 break;
@@ -128,7 +122,7 @@ static int smtp_checkp(const char *fmt, const char *param, int code)
128 } 122 }
129 if (answer) { 123 if (answer) {
130 int n = atoi(answer); 124 int n = atoi(answer);
131 if (timeout) 125 if (G.timeout)
132 alarm(0); 126 alarm(0);
133 free(answer); 127 free(answer);
134 if (-1 == code || n == code) { 128 if (-1 == code || n == code) {
@@ -223,6 +217,7 @@ static void rcptto_list(const char *list)
223int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 217int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
224int sendmail_main(int argc UNUSED_PARAM, char **argv) 218int sendmail_main(int argc UNUSED_PARAM, char **argv)
225{ 219{
220 unsigned opts;
226 char *opt_connect; 221 char *opt_connect;
227 char *opt_from = NULL; 222 char *opt_from = NULL;
228 char *s; 223 char *s;
@@ -276,7 +271,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
276 // -v is a counter, -H and -S are mutually exclusive, -a is a list 271 // -v is a counter, -H and -S are mutually exclusive, -a is a list
277 "vv:H--S:S--H", 272 "vv:H--S:S--H",
278 &opt_from, NULL, 273 &opt_from, NULL,
279 &timeout, &opt_connect, &opt_connect, &list, &verbose 274 &G.timeout, &opt_connect, &opt_connect, &list, &G.verbose
280 ); 275 );
281 //argc -= optind; 276 //argc -= optind;
282 argv += optind; 277 argv += optind;
@@ -425,6 +420,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
425 // this means we scan stdin for To:, Cc:, Bcc: lines until an empty line 420 // this means we scan stdin for To:, Cc:, Bcc: lines until an empty line
426 // and then use the rest of stdin as message body 421 // and then use the rest of stdin as message body
427 code = 0; // set "analyze headers" mode 422 code = 0; // set "analyze headers" mode
423//FIXME: limit max len!!!
428 while ((s = xmalloc_fgetline(G.fp0)) != NULL) { 424 while ((s = xmalloc_fgetline(G.fp0)) != NULL) {
429 dump: 425 dump:
430 // put message lines doubling leading dots 426 // put message lines doubling leading dots
diff --git a/miscutils/adjtimex.c b/miscutils/adjtimex.c
index a9de0f9aa..209d1d560 100644
--- a/miscutils/adjtimex.c
+++ b/miscutils/adjtimex.c
@@ -22,7 +22,7 @@
22//kbuild:lib-$(CONFIG_ADJTIMEX) += adjtimex.o 22//kbuild:lib-$(CONFIG_ADJTIMEX) += adjtimex.o
23 23
24//usage:#define adjtimex_trivial_usage 24//usage:#define adjtimex_trivial_usage
25//usage: "[-q] [-o OFF] [-f FREQ] [-p TCONST] [-t TICK]" 25//usage: "[-q] [-o OFS] [-f FREQ] [-p TCONST] [-t TICK]"
26//usage:#define adjtimex_full_usage "\n\n" 26//usage:#define adjtimex_full_usage "\n\n"
27//usage: "Read or set kernel time variables. See adjtimex(2)\n" 27//usage: "Read or set kernel time variables. See adjtimex(2)\n"
28//usage: "\n -q Quiet" 28//usage: "\n -q Quiet"
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 4d987325e..53eb5c799 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -231,7 +231,7 @@ typedef struct BcNum {
231#define BC_NUM_MAX_IBASE 36 231#define BC_NUM_MAX_IBASE 36
232// larger value might speed up BIGNUM calculations a bit: 232// larger value might speed up BIGNUM calculations a bit:
233#define BC_NUM_DEF_SIZE 16 233#define BC_NUM_DEF_SIZE 16
234#define BC_NUM_PRINT_WIDTH 69 234#define BC_NUM_PRINT_WIDTH 70
235 235
236#define BC_NUM_KARATSUBA_LEN 32 236#define BC_NUM_KARATSUBA_LEN 32
237 237
@@ -517,7 +517,7 @@ struct BcLexKeyword {
517}; 517};
518#define LEX_KW_ENTRY(a, b) \ 518#define LEX_KW_ENTRY(a, b) \
519 { .name8 = a /*, .posix = b */ } 519 { .name8 = a /*, .posix = b */ }
520static const struct BcLexKeyword bc_lex_kws[20] = { 520static const struct BcLexKeyword bc_lex_kws[20] ALIGN8 = {
521 LEX_KW_ENTRY("auto" , 1), // 0 521 LEX_KW_ENTRY("auto" , 1), // 0
522 LEX_KW_ENTRY("break" , 1), // 1 522 LEX_KW_ENTRY("break" , 1), // 1
523 LEX_KW_ENTRY("continue", 0), // 2 note: this one has no terminating NUL 523 LEX_KW_ENTRY("continue", 0), // 2 note: this one has no terminating NUL
@@ -1827,7 +1827,7 @@ static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
1827#define zbc_num_k(...) (zbc_num_k(__VA_ARGS__) COMMA_SUCCESS) 1827#define zbc_num_k(...) (zbc_num_k(__VA_ARGS__) COMMA_SUCCESS)
1828{ 1828{
1829 BcStatus s; 1829 BcStatus s;
1830 size_t max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2; 1830 size_t max, max2;
1831 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp; 1831 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1832 bool aone; 1832 bool aone;
1833 1833
@@ -1841,9 +1841,9 @@ static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
1841 RETURN_STATUS(BC_STATUS_SUCCESS); 1841 RETURN_STATUS(BC_STATUS_SUCCESS);
1842 } 1842 }
1843 1843
1844 if (a->len + b->len < BC_NUM_KARATSUBA_LEN 1844 if (a->len < BC_NUM_KARATSUBA_LEN
1845 || a->len < BC_NUM_KARATSUBA_LEN
1846 || b->len < BC_NUM_KARATSUBA_LEN 1845 || b->len < BC_NUM_KARATSUBA_LEN
1846 /* || a->len + b->len < BC_NUM_KARATSUBA_LEN - redundant check */
1847 ) { 1847 ) {
1848 size_t i, j, len; 1848 size_t i, j, len;
1849 1849
@@ -1877,6 +1877,7 @@ static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
1877 RETURN_STATUS(BC_STATUS_SUCCESS); 1877 RETURN_STATUS(BC_STATUS_SUCCESS);
1878 } 1878 }
1879 1879
1880 max = BC_MAX(a->len, b->len);
1880 bc_num_init(&l1, max); 1881 bc_num_init(&l1, max);
1881 bc_num_init(&h1, max); 1882 bc_num_init(&h1, max);
1882 bc_num_init(&l2, max); 1883 bc_num_init(&l2, max);
@@ -1888,6 +1889,7 @@ static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
1888 bc_num_init(&z2, max); 1889 bc_num_init(&z2, max);
1889 bc_num_init(&temp, max + max); 1890 bc_num_init(&temp, max + max);
1890 1891
1892 max2 = (max + 1) / 2;
1891 bc_num_split(a, max2, &l1, &h1); 1893 bc_num_split(a, max2, &l1, &h1);
1892 bc_num_split(b, max2, &l2, &h2); 1894 bc_num_split(b, max2, &l2, &h2);
1893 1895
@@ -2201,8 +2203,8 @@ static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2201 BcStatus s; 2203 BcStatus s;
2202 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp; 2204 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2203 BcDig half_digs[1]; 2205 BcDig half_digs[1];
2204 size_t pow, len, digs, digs1, resrdx, req, times = 0; 2206 size_t pow, len, digs, digs1, resrdx, req, times;
2205 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX; 2207 ssize_t cmp, cmp1, cmp2;
2206 2208
2207 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1; 2209 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2208 bc_num_expand(b, req); 2210 bc_num_expand(b, req);
@@ -2255,11 +2257,12 @@ static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2255 x0->rdx -= pow; 2257 x0->rdx -= pow;
2256 } 2258 }
2257 2259
2258 x0->rdx = digs = digs1 = 0; 2260 x0->rdx = digs = digs1 = times = 0;
2259 resrdx = scale + 2; 2261 resrdx = scale + 2;
2260 len = BC_NUM_INT(x0) + resrdx - 1; 2262 len = x0->len + resrdx - 1;
2261 2263 cmp = 1;
2262 while (cmp != 0 || digs < len) { 2264 cmp1 = cmp2 = SSIZE_MAX;
2265 do {
2263 s = zbc_num_div(a, x0, &f, resrdx); 2266 s = zbc_num_div(a, x0, &f, resrdx);
2264 if (s) goto err; 2267 if (s) goto err;
2265 s = zbc_num_add(x0, &f, &fprime, resrdx); 2268 s = zbc_num_add(x0, &f, &fprime, resrdx);
@@ -2284,11 +2287,12 @@ static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2284 temp = x0; 2287 temp = x0;
2285 x0 = x1; 2288 x0 = x1;
2286 x1 = temp; 2289 x1 = temp;
2287 } 2290 } while (cmp != 0 || digs < len);
2288 2291
2289 bc_num_copy(b, x0); 2292 bc_num_copy(b, x0);
2290 scale -= 1; 2293 scale -= 1;
2291 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale); 2294 if (b->rdx > scale)
2295 bc_num_truncate(b, b->rdx - scale);
2292 err: 2296 err:
2293 bc_num_free(&fprime); 2297 bc_num_free(&fprime);
2294 bc_num_free(&f); 2298 bc_num_free(&f);
@@ -2522,9 +2526,6 @@ static void xc_read_line(BcVec *vec, FILE *fp)
2522 2526
2523#if ENABLE_FEATURE_BC_INTERACTIVE 2527#if ENABLE_FEATURE_BC_INTERACTIVE
2524 if (G_interrupt) { // ^C was pressed 2528 if (G_interrupt) { // ^C was pressed
2525# if ENABLE_FEATURE_EDITING
2526 intr:
2527# endif
2528 if (fp != stdin) { 2529 if (fp != stdin) {
2529 // ^C while running a script (bc SCRIPT): die. 2530 // ^C while running a script (bc SCRIPT): die.
2530 // We do not return to interactive prompt: 2531 // We do not return to interactive prompt:
@@ -2535,22 +2536,25 @@ static void xc_read_line(BcVec *vec, FILE *fp)
2535 // the shell would be unexpected. 2536 // the shell would be unexpected.
2536 xfunc_die(); 2537 xfunc_die();
2537 } 2538 }
2538 // ^C while interactive input 2539 // There was ^C while running calculations
2539 G_interrupt = 0; 2540 G_interrupt = 0;
2540 // GNU bc says "interrupted execution." 2541 // GNU bc says "interrupted execution." (to stdout, not stderr)
2541 // GNU dc says "Interrupt!" 2542 // GNU dc says "Interrupt!"
2542 fputs("\ninterrupted execution\n", stderr); 2543 puts("\ninterrupted execution");
2543 } 2544 }
2544 2545
2545# if ENABLE_FEATURE_EDITING 2546# if ENABLE_FEATURE_EDITING
2546 if (G_ttyin && fp == stdin) { 2547 if (G_ttyin && fp == stdin) {
2547 int n, i; 2548 int n, i;
2549 if (!G.line_input_state)
2550 G.line_input_state = new_line_input_t(DO_HISTORY);
2548# define line_buf bb_common_bufsiz1 2551# define line_buf bb_common_bufsiz1
2549 n = read_line_input(G.line_input_state, "", line_buf, COMMON_BUFSIZE); 2552 n = read_line_input(G.line_input_state, "", line_buf, COMMON_BUFSIZE);
2550 if (n <= 0) { // read errors or EOF, or ^D, or ^C 2553 if (n <= 0) { // read errors or EOF, or ^D, or ^C
2551 if (n == 0) // ^C 2554 //GNU bc prints this on ^C:
2552 goto intr; 2555 //if (n == 0) // ^C
2553 bc_vec_pushZeroByte(vec); // ^D or EOF (or error) 2556 // puts("(interrupt) Exiting bc.");
2557 bc_vec_pushZeroByte(vec);
2554 return; 2558 return;
2555 } 2559 }
2556 i = 0; 2560 i = 0;
@@ -6872,22 +6876,6 @@ static BC_STATUS zxc_program_exec(void)
6872} 6876}
6873#define zxc_program_exec(...) (zxc_program_exec(__VA_ARGS__) COMMA_SUCCESS) 6877#define zxc_program_exec(...) (zxc_program_exec(__VA_ARGS__) COMMA_SUCCESS)
6874 6878
6875static unsigned xc_vm_envLen(const char *var)
6876{
6877 char *lenv;
6878 unsigned len;
6879
6880 lenv = getenv(var);
6881 len = BC_NUM_PRINT_WIDTH;
6882 if (!lenv) return len;
6883
6884 len = bb_strtou(lenv, NULL, 10) - 1;
6885 if (errno || len < 2 || len >= INT_MAX)
6886 len = BC_NUM_PRINT_WIDTH;
6887
6888 return len;
6889}
6890
6891static BC_STATUS zxc_vm_process(const char *text) 6879static BC_STATUS zxc_vm_process(const char *text)
6892{ 6880{
6893 BcStatus s; 6881 BcStatus s;
@@ -7377,12 +7365,43 @@ static void xc_program_init(void)
7377 bc_char_vec_init(&G.input_buffer); 7365 bc_char_vec_init(&G.input_buffer);
7378} 7366}
7379 7367
7368static unsigned xc_vm_envLen(const char *var)
7369{
7370 char *lenv;
7371 unsigned len;
7372
7373 lenv = getenv(var);
7374 len = BC_NUM_PRINT_WIDTH;
7375 if (lenv) {
7376 len = bb_strtou(lenv, NULL, 10);
7377 if (len == 0 || len > INT_MAX)
7378 len = INT_MAX;
7379 if (errno)
7380 len = BC_NUM_PRINT_WIDTH;
7381 }
7382
7383 // dc (GNU bc 1.07.1) 1.4.1 seems to use width
7384 // 1 char wider than bc from the same package.
7385 // Both default width, and xC_LINE_LENGTH=N are wider:
7386 // "DC_LINE_LENGTH=5 dc -e'123456 p'" prints:
7387 // |1234\ |
7388 // |56 |
7389 // "echo '123456' | BC_LINE_LENGTH=5 bc" prints:
7390 // |123\ |
7391 // |456 |
7392 // Do the same, but it might be a bug in GNU package
7393 if (IS_BC)
7394 len--;
7395
7396 if (len < 2)
7397 len = IS_BC ? BC_NUM_PRINT_WIDTH - 1 : BC_NUM_PRINT_WIDTH;
7398
7399 return len;
7400}
7401
7380static int xc_vm_init(const char *env_len) 7402static int xc_vm_init(const char *env_len)
7381{ 7403{
7382 G.prog.len = xc_vm_envLen(env_len); 7404 G.prog.len = xc_vm_envLen(env_len);
7383#if ENABLE_FEATURE_EDITING
7384 G.line_input_state = new_line_input_t(DO_HISTORY);
7385#endif
7386 bc_vec_init(&G.files, sizeof(char *), NULL); 7405 bc_vec_init(&G.files, sizeof(char *), NULL);
7387 7406
7388 xc_program_init(); 7407 xc_program_init();
@@ -7466,16 +7485,6 @@ int dc_main(int argc UNUSED_PARAM, char **argv)
7466 7485
7467 INIT_G(); 7486 INIT_G();
7468 7487
7469 // TODO: dc (GNU bc 1.07.1) 1.4.1 seems to use width
7470 // 1 char wider than bc from the same package.
7471 // Both default width, and xC_LINE_LENGTH=N are wider:
7472 // "DC_LINE_LENGTH=5 dc -e'123456 p'" prints:
7473 // |1234\ |
7474 // |56 |
7475 // "echo '123456' | BC_LINE_LENGTH=5 bc" prints:
7476 // |123\ |
7477 // |456 |
7478 // Do the same, or it's a bug?
7479 xc_vm_init("DC_LINE_LENGTH"); 7488 xc_vm_init("DC_LINE_LENGTH");
7480 7489
7481 // Run -e'SCRIPT' and -fFILE in order of appearance, then handle FILEs 7490 // Run -e'SCRIPT' and -fFILE in order of appearance, then handle FILEs
diff --git a/miscutils/beep.c b/miscutils/beep.c
index 1669332fd..7c60aed08 100644
--- a/miscutils/beep.c
+++ b/miscutils/beep.c
@@ -114,10 +114,10 @@ int beep_main(int argc, char **argv)
114 while (rep) { 114 while (rep) {
115//bb_error_msg("rep[%d] freq=%d, length=%d, delay=%d", rep, freq, length, delay); 115//bb_error_msg("rep[%d] freq=%d, length=%d, delay=%d", rep, freq, length, delay);
116 xioctl(speaker, KIOCSOUND, (void*)(uintptr_t)tickrate_div_freq); 116 xioctl(speaker, KIOCSOUND, (void*)(uintptr_t)tickrate_div_freq);
117 usleep(1000 * length); 117 msleep(length);
118 ioctl(speaker, KIOCSOUND, (void*)0); 118 ioctl(speaker, KIOCSOUND, (void*)0);
119 if (--rep) 119 if (--rep)
120 usleep(1000 * delay); 120 msleep(delay);
121 } 121 }
122 } 122 }
123 123
diff --git a/miscutils/chat.c b/miscutils/chat.c
index a04565063..86a114df6 100644
--- a/miscutils/chat.c
+++ b/miscutils/chat.c
@@ -379,7 +379,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
379 // dump device input if ECHO ON 379 // dump device input if ECHO ON
380 if (echo) { 380 if (echo) {
381// if (buf[buf_len] < ' ') { 381// if (buf[buf_len] < ' ') {
382// full_write(STDERR_FILENO, "^", 1); 382// full_write2_str("^");
383// buf[buf_len] += '@'; 383// buf[buf_len] += '@';
384// } 384// }
385 full_write(STDERR_FILENO, buf+buf_len, 1); 385 full_write(STDERR_FILENO, buf+buf_len, 1);
@@ -473,7 +473,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
473 if ('\\' == c) { 473 if ('\\' == c) {
474 c = *++buf; 474 c = *++buf;
475 if ('d' == c) { 475 if ('d' == c) {
476 sleep(1); 476 sleep1();
477 len--; 477 len--;
478 continue; 478 continue;
479 } 479 }
@@ -509,7 +509,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
509#if ENABLE_FEATURE_CHAT_IMPLICIT_CR 509#if ENABLE_FEATURE_CHAT_IMPLICIT_CR
510 // or terminate command with \r (if not inhibited) 510 // or terminate command with \r (if not inhibited)
511 else if (!nocr) 511 else if (!nocr)
512 xwrite(STDOUT_FILENO, "\r", 1); 512 xwrite_str(STDOUT_FILENO, "\r");
513#endif 513#endif
514 // bail out unless we sent command successfully 514 // bail out unless we sent command successfully
515 if (exitcode) 515 if (exitcode)
diff --git a/miscutils/crond.c b/miscutils/crond.c
index 2e8ca8b68..b74427351 100644
--- a/miscutils/crond.c
+++ b/miscutils/crond.c
@@ -63,7 +63,7 @@
63//kbuild:lib-$(CONFIG_CROND) += crond.o 63//kbuild:lib-$(CONFIG_CROND) += crond.o
64 64
65//usage:#define crond_trivial_usage 65//usage:#define crond_trivial_usage
66//usage: "-fbS -l N " IF_FEATURE_CROND_D("-d N ") "-L LOGFILE -c DIR" 66//usage: "[-fbS] [-l N] " IF_FEATURE_CROND_D("[-d N] ") "[-L LOGFILE] [-c DIR]"
67//usage:#define crond_full_usage "\n\n" 67//usage:#define crond_full_usage "\n\n"
68//usage: " -f Foreground" 68//usage: " -f Foreground"
69//usage: "\n -b Background (default)" 69//usage: "\n -b Background (default)"
@@ -492,7 +492,7 @@ static void load_crontab(const char *fileName)
492 const char *name; 492 const char *name;
493 const char tokens[8]; 493 const char tokens[8];
494 } SpecialEntry; 494 } SpecialEntry;
495 static const SpecialEntry SpecAry[] = { 495 static const SpecialEntry SpecAry[] ALIGN8 = {
496 /* hour day month weekday */ 496 /* hour day month weekday */
497 { "yearly", "0\0" "1\0" "1\0" "*" }, 497 { "yearly", "0\0" "1\0" "1\0" "*" },
498 { "annually", "0\0" "1\0" "1\0" "*" }, 498 { "annually", "0\0" "1\0" "1\0" "*" },
diff --git a/miscutils/dc.c b/miscutils/dc.c
index b6c6795b6..918f2b5c8 100644
--- a/miscutils/dc.c
+++ b/miscutils/dc.c
@@ -100,7 +100,7 @@ static void mod(void)
100 * 0 100 * 0
101 */ 101 */
102 if (d == 0) { 102 if (d == 0) {
103 bb_error_msg("remainder by zero"); 103 bb_simple_error_msg("remainder by zero");
104 pop(); 104 pop();
105 push(0); 105 push(0);
106 return; 106 return;
@@ -195,7 +195,7 @@ struct op {
195 void (*function) (void); 195 void (*function) (void);
196}; 196};
197 197
198static const struct op operators[] = { 198static const struct op operators[] ALIGN_PTR = {
199#if ENABLE_FEATURE_DC_LIBM 199#if ENABLE_FEATURE_DC_LIBM
200 {"^", power}, 200 {"^", power},
201// {"exp", power}, 201// {"exp", power},
diff --git a/miscutils/devfsd.c b/miscutils/devfsd.c
index 17d8fb6b9..e5bb8a2d8 100644
--- a/miscutils/devfsd.c
+++ b/miscutils/devfsd.c
@@ -362,7 +362,7 @@ static const char bb_msg_variable_not_found[] ALIGN1 = "variable: %s not found";
362 362
363static void safe_memcpy(char *dest, const char *src, int len) 363static void safe_memcpy(char *dest, const char *src, int len)
364{ 364{
365 memcpy(dest , src, len); 365 memcpy(dest, src, len);
366 dest[len] = '\0'; 366 dest[len] = '\0';
367} 367}
368 368
@@ -1106,7 +1106,7 @@ static int copy_inode(const char *destpath, const struct stat *dest_stat,
1106do_chown: 1106do_chown:
1107 if (chown(destpath, source_stat->st_uid, source_stat->st_gid) == 0) 1107 if (chown(destpath, source_stat->st_uid, source_stat->st_gid) == 0)
1108 return TRUE; 1108 return TRUE;
1109 /*break;*/ 1109 /*break;*/
1110 } 1110 }
1111 return FALSE; 1111 return FALSE;
1112} /* End Function copy_inode */ 1112} /* End Function copy_inode */
diff --git a/miscutils/devmem.c b/miscutils/devmem.c
index e8dce5225..f9f0276bc 100644
--- a/miscutils/devmem.c
+++ b/miscutils/devmem.c
@@ -75,7 +75,7 @@ int devmem_main(int argc UNUSED_PARAM, char **argv)
75 bb_show_usage(); /* one of bb_strtouXX failed */ 75 bb_show_usage(); /* one of bb_strtouXX failed */
76 76
77 fd = xopen("/dev/mem", argv[3] ? (O_RDWR | O_SYNC) : (O_RDONLY | O_SYNC)); 77 fd = xopen("/dev/mem", argv[3] ? (O_RDWR | O_SYNC) : (O_RDONLY | O_SYNC));
78 mapped_size = page_size = getpagesize(); 78 mapped_size = page_size = bb_getpagesize();
79 offset_in_page = (unsigned)target & (page_size - 1); 79 offset_in_page = (unsigned)target & (page_size - 1);
80 if (offset_in_page + width > page_size) { 80 if (offset_in_page + width > page_size) {
81 /* This access spans pages. 81 /* This access spans pages.
diff --git a/miscutils/hdparm.c b/miscutils/hdparm.c
index d25a2466e..01b4e8e2e 100644
--- a/miscutils/hdparm.c
+++ b/miscutils/hdparm.c
@@ -1366,7 +1366,7 @@ static NOINLINE void dump_identity(const struct hd_driveid *id)
1366 } 1366 }
1367 if (id->capability & 1) { 1367 if (id->capability & 1) {
1368 if (id->dma_1word | id->dma_mword) { 1368 if (id->dma_1word | id->dma_mword) {
1369 static const int dma_wmode_masks[] = { 0x100, 1, 0x200, 2, 0x400, 4, 0xf800, 0xf8 }; 1369 static const int dma_wmode_masks[] ALIGN4 = { 0x100, 1, 0x200, 2, 0x400, 4, 0xf800, 0xf8 };
1370 printf("\n DMA modes: "); 1370 printf("\n DMA modes: ");
1371 print_flags_separated(dma_wmode_masks, 1371 print_flags_separated(dma_wmode_masks,
1372 "*\0""sdma0 \0""*\0""sdma1 \0""*\0""sdma2 \0""*\0""sdma? \0", 1372 "*\0""sdma0 \0""*\0""sdma1 \0""*\0""sdma2 \0""*\0""sdma? \0",
@@ -1436,7 +1436,7 @@ static void flush_buffer_cache(/*int fd*/ void)
1436 fsync(fd); /* flush buffers */ 1436 fsync(fd); /* flush buffers */
1437 ioctl_or_warn(fd, BLKFLSBUF, NULL); /* do it again, big time */ 1437 ioctl_or_warn(fd, BLKFLSBUF, NULL); /* do it again, big time */
1438#ifdef HDIO_DRIVE_CMD 1438#ifdef HDIO_DRIVE_CMD
1439 sleep(1); 1439 sleep1();
1440 if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL) { /* await completion */ 1440 if (ioctl(fd, HDIO_DRIVE_CMD, NULL) && errno != EINVAL) { /* await completion */
1441 if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */ 1441 if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
1442 bb_simple_perror_msg("HDIO_DRIVE_CMD"); 1442 bb_simple_perror_msg("HDIO_DRIVE_CMD");
@@ -1511,7 +1511,7 @@ static void do_time(int cache /*,int fd*/)
1511 * NB: *small* delay. User is expected to have a clue and to not run 1511 * NB: *small* delay. User is expected to have a clue and to not run
1512 * heavy io in parallel with measurements. */ 1512 * heavy io in parallel with measurements. */
1513 sync(); 1513 sync();
1514 sleep(1); 1514 sleep1();
1515 if (cache) { /* Time cache */ 1515 if (cache) { /* Time cache */
1516 seek_to_zero(); 1516 seek_to_zero();
1517 read_big_block(buf); 1517 read_big_block(buf);
diff --git a/miscutils/hexedit.c b/miscutils/hexedit.c
index 898d77376..f8ff9b62b 100644
--- a/miscutils/hexedit.c
+++ b/miscutils/hexedit.c
@@ -31,7 +31,8 @@ struct globals {
31 int fd; 31 int fd;
32 unsigned height; 32 unsigned height;
33 unsigned row; 33 unsigned row;
34 unsigned pagesize; 34 IF_VARIABLE_ARCH_PAGESIZE(unsigned pagesize;)
35#define G_pagesize cached_pagesize(G.pagesize)
35 uint8_t *baseaddr; 36 uint8_t *baseaddr;
36 uint8_t *current_byte; 37 uint8_t *current_byte;
37 uint8_t *eof_byte; 38 uint8_t *eof_byte;
@@ -46,15 +47,6 @@ struct globals {
46 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 47 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
47} while (0) 48} while (0)
48 49
49//TODO: move to libbb
50#if defined(__x86_64__) || defined(i386)
51# define G_pagesize 4096
52# define INIT_PAGESIZE() ((void)0)
53#else
54# define G_pagesize (G.pagesize)
55# define INIT_PAGESIZE() ((void)(G.pagesize = getpagesize()))
56#endif
57
58/* hopefully there aren't arches with PAGE_SIZE > 64k */ 50/* hopefully there aren't arches with PAGE_SIZE > 64k */
59#define G_mapsize (64*1024) 51#define G_mapsize (64*1024)
60 52
@@ -262,7 +254,7 @@ int hexedit_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
262int hexedit_main(int argc UNUSED_PARAM, char **argv) 254int hexedit_main(int argc UNUSED_PARAM, char **argv)
263{ 255{
264 INIT_G(); 256 INIT_G();
265 INIT_PAGESIZE(); 257 INIT_PAGESIZE(G.pagesize);
266 258
267 get_terminal_width_height(-1, NULL, &G.height); 259 get_terminal_width_height(-1, NULL, &G.height);
268 if (1) { 260 if (1) {
diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c
index cc8b99a92..48135921d 100644
--- a/miscutils/i2c_tools.c
+++ b/miscutils/i2c_tools.c
@@ -273,7 +273,7 @@ static int i2c_bus_lookup(const char *bus_str)
273 return xstrtou_range(bus_str, 10, 0, 0xfffff); 273 return xstrtou_range(bus_str, 10, 0, 0xfffff);
274} 274}
275 275
276#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP || ENABLE_I2CTRANSFER 276#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP
277static int i2c_parse_bus_addr(const char *addr_str) 277static int i2c_parse_bus_addr(const char *addr_str)
278{ 278{
279 /* Slave address must be in range 0x03 - 0x77. */ 279 /* Slave address must be in range 0x03 - 0x77. */
@@ -286,14 +286,16 @@ static void i2c_set_pec(int fd, int pec)
286 itoptr(pec ? 1 : 0), 286 itoptr(pec ? 1 : 0),
287 "can't set PEC"); 287 "can't set PEC");
288} 288}
289#endif
289 290
291#if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP || ENABLE_I2CTRANSFER
290static void i2c_set_slave_addr(int fd, int addr, int force) 292static void i2c_set_slave_addr(int fd, int addr, int force)
291{ 293{
292 ioctl_or_perror_and_die(fd, force ? I2C_SLAVE_FORCE : I2C_SLAVE, 294 ioctl_or_perror_and_die(fd, force ? I2C_SLAVE_FORCE : I2C_SLAVE,
293 itoptr(addr), 295 itoptr(addr),
294 "can't set address to 0x%02x", addr); 296 "can't set address to 0x%02x", addr);
295} 297}
296#endif /* ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP */ 298#endif
297 299
298#if ENABLE_I2CGET || ENABLE_I2CSET 300#if ENABLE_I2CGET || ENABLE_I2CSET
299static int i2c_parse_data_addr(const char *data_addr) 301static int i2c_parse_data_addr(const char *data_addr)
@@ -1052,24 +1054,19 @@ struct adap_desc {
1052 const char *algo; 1054 const char *algo;
1053}; 1055};
1054 1056
1055static const struct adap_desc adap_descs[] = { 1057static const struct adap_desc adap_descs[] ALIGN_PTR = {
1056 { .funcs = "dummy", 1058 { .funcs = "dummy", .algo = "Dummy bus", },
1057 .algo = "Dummy bus", }, 1059 { .funcs = "isa", .algo = "ISA bus", },
1058 { .funcs = "isa", 1060 { .funcs = "i2c", .algo = "I2C adapter", },
1059 .algo = "ISA bus", }, 1061 { .funcs = "smbus", .algo = "SMBus adapter", },
1060 { .funcs = "i2c",
1061 .algo = "I2C adapter", },
1062 { .funcs = "smbus",
1063 .algo = "SMBus adapter", },
1064}; 1062};
1065 1063
1066struct i2c_func 1064struct i2c_func {
1067{
1068 long value; 1065 long value;
1069 const char* name; 1066 const char* name;
1070}; 1067};
1071 1068
1072static const struct i2c_func i2c_funcs_tab[] = { 1069static const struct i2c_func i2c_funcs_tab[] ALIGN_PTR = {
1073 { .value = I2C_FUNC_I2C, 1070 { .value = I2C_FUNC_I2C,
1074 .name = "I2C" }, 1071 .name = "I2C" },
1075 { .value = I2C_FUNC_SMBUS_QUICK, 1072 { .value = I2C_FUNC_SMBUS_QUICK,
@@ -1152,12 +1149,12 @@ static void NORETURN list_i2c_busses_and_exit(void)
1152 /* Simple version for ISA chips. */ 1149 /* Simple version for ISA chips. */
1153 snprintf(path, NAME_MAX, "%s/%s/name", 1150 snprintf(path, NAME_MAX, "%s/%s/name",
1154 i2cdev_path, de->d_name); 1151 i2cdev_path, de->d_name);
1155 fp = fopen(path, "r"); 1152 fp = fopen_for_read(path);
1156 if (fp == NULL) { 1153 if (fp == NULL) {
1157 snprintf(path, NAME_MAX, 1154 snprintf(path, NAME_MAX,
1158 "%s/%s/device/name", 1155 "%s/%s/device/name",
1159 i2cdev_path, de->d_name); 1156 i2cdev_path, de->d_name);
1160 fp = fopen(path, "r"); 1157 fp = fopen_for_read(path);
1161 } 1158 }
1162 1159
1163 /* Non-ISA chips require the hard-way. */ 1160 /* Non-ISA chips require the hard-way. */
@@ -1178,7 +1175,7 @@ static void NORETURN list_i2c_busses_and_exit(void)
1178 "%s/%s/device/%s/name", 1175 "%s/%s/device/%s/name",
1179 i2cdev_path, de->d_name, 1176 i2cdev_path, de->d_name,
1180 subde->d_name); 1177 subde->d_name);
1181 fp = fopen(path, "r"); 1178 fp = fopen_for_read(path);
1182 break; 1179 break;
1183 } 1180 }
1184 } 1181 }
diff --git a/miscutils/man.c b/miscutils/man.c
index 6724b4b5d..052b50054 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -13,7 +13,7 @@
13//kbuild:lib-$(CONFIG_MAN) += man.o 13//kbuild:lib-$(CONFIG_MAN) += man.o
14 14
15//usage:#define man_trivial_usage 15//usage:#define man_trivial_usage
16//usage: "[-aw] MANPAGE..." 16//usage: "[-aw] [SECTION] MANPAGE[.SECTION]..."
17//usage:#define man_full_usage "\n\n" 17//usage:#define man_full_usage "\n\n"
18//usage: "Display manual page\n" 18//usage: "Display manual page\n"
19//usage: "\n -a Display all pages" 19//usage: "\n -a Display all pages"
@@ -239,10 +239,21 @@ static const char *if_redefined(const char *var, const char *key, const char *li
239 return xstrdup(skip_whitespace(line)); 239 return xstrdup(skip_whitespace(line));
240} 240}
241 241
242static int is_section_name(const char *sections, const char *str)
243{
244 const char *s = strstr(sections, str);
245 if (s) {
246 int l = strlen(str);
247 return (s[l] == ':' || s[l] == '\0');
248 }
249 return 0;
250}
251
242int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 252int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
243int man_main(int argc UNUSED_PARAM, char **argv) 253int man_main(int argc UNUSED_PARAM, char **argv)
244{ 254{
245 parser_t *parser; 255 parser_t *parser;
256 char *conf_sec_list;
246 char *sec_list; 257 char *sec_list;
247 char **man_path_list; 258 char **man_path_list;
248 int count_mp; 259 int count_mp;
@@ -267,7 +278,7 @@ int man_main(int argc UNUSED_PARAM, char **argv)
267 chdir_system_drive(); 278 chdir_system_drive();
268#endif 279#endif
269 280
270 sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9"); 281 conf_sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9");
271 282
272 count_mp = 0; 283 count_mp = 0;
273 man_path_list = add_MANPATH(NULL, &count_mp, 284 man_path_list = add_MANPATH(NULL, &count_mp,
@@ -297,8 +308,8 @@ int man_main(int argc UNUSED_PARAM, char **argv)
297 man_path_list = add_MANPATH(man_path_list, &count_mp, token[1]); 308 man_path_list = add_MANPATH(man_path_list, &count_mp, token[1]);
298 } 309 }
299 if (strcmp("MANSECT", token[0]) == 0) { 310 if (strcmp("MANSECT", token[0]) == 0) {
300 free(sec_list); 311 free(conf_sec_list);
301 sec_list = xstrdup(token[1]); 312 conf_sec_list = xstrdup(token[1]);
302 } 313 }
303 } 314 }
304 config_close(parser); 315 config_close(parser);
@@ -337,6 +348,13 @@ int man_main(int argc UNUSED_PARAM, char **argv)
337 G.pager = xasprintf("%s -b -p -x", G.col); 348 G.pager = xasprintf("%s -b -p -x", G.col);
338 } 349 }
339 350
351 /* is 1st ARG a SECTION? */
352 sec_list = conf_sec_list;
353 if (is_section_name(conf_sec_list, *argv)) {
354 /* yes */
355 sec_list = *argv++;
356 }
357
340 not_found = 0; 358 not_found = 0;
341 do { /* for each argv[] */ 359 do { /* for each argv[] */
342 const char *cur_path; 360 const char *cur_path;
@@ -347,11 +365,20 @@ int man_main(int argc UNUSED_PARAM, char **argv)
347 found = show_manpage(*argv, /*man:*/ 1, 0); 365 found = show_manpage(*argv, /*man:*/ 1, 0);
348 goto check_found; 366 goto check_found;
349 } 367 }
368
369 /* for each MANPATH */
350 cur_mp = 0; 370 cur_mp = 0;
351 while ((cur_path = man_path_list[cur_mp++]) != NULL) { 371 while ((cur_path = man_path_list[cur_mp++]) != NULL) {
352 /* for each MANPATH */
353 const char *cur_sect = sec_list; 372 const char *cur_sect = sec_list;
354 do { /* for each section */ 373
374 /* is MANPAGE of the form NAME.SECTION? */
375 char *sect_ext = strrchr(*argv, '.');
376 if (sect_ext && is_section_name(conf_sec_list, sect_ext + 1)) {
377 *sect_ext = '\0';
378 cur_sect = sect_ext + 1;
379 }
380
381 do { /* for each SECTION in cur_sect */
355 char *next_sect = strchrnul(cur_sect, ':'); 382 char *next_sect = strchrnul(cur_sect, ':');
356 int sect_len = next_sect - cur_sect; 383 int sect_len = next_sect - cur_sect;
357 char *man_filename; 384 char *man_filename;
@@ -378,6 +405,8 @@ int man_main(int argc UNUSED_PARAM, char **argv)
378 while (*cur_sect == ':') 405 while (*cur_sect == ':')
379 cur_sect++; 406 cur_sect++;
380 } while (*cur_sect); 407 } while (*cur_sect);
408
409 if (sect_ext) *sect_ext = '.';
381 } 410 }
382 check_found: 411 check_found:
383 if (!found) { 412 if (!found) {
diff --git a/miscutils/mt.c b/miscutils/mt.c
index 9f1aecfca..1a4214664 100644
--- a/miscutils/mt.c
+++ b/miscutils/mt.c
@@ -15,7 +15,7 @@
15//kbuild:lib-$(CONFIG_MT) += mt.o 15//kbuild:lib-$(CONFIG_MT) += mt.o
16 16
17//usage:#define mt_trivial_usage 17//usage:#define mt_trivial_usage
18//usage: "[-f device] opcode value" 18//usage: "[-f DEVICE] OPCODE VALUE"
19//usage:#define mt_full_usage "\n\n" 19//usage:#define mt_full_usage "\n\n"
20//usage: "Control magnetic tape drive operation\n" 20//usage: "Control magnetic tape drive operation\n"
21//usage: "\n" 21//usage: "\n"
@@ -30,7 +30,7 @@
30#include <sys/mtio.h> 30#include <sys/mtio.h>
31 31
32/* missing: eod/seod, stoptions, stwrthreshold, densities */ 32/* missing: eod/seod, stoptions, stwrthreshold, densities */
33static const short opcode_value[] = { 33static const short opcode_value[] ALIGN2 = {
34 MTBSF, 34 MTBSF,
35 MTBSFM, 35 MTBSFM,
36 MTBSR, 36 MTBSR,
diff --git a/miscutils/setserial.c b/miscutils/setserial.c
index 1e75bf433..2006861e2 100644
--- a/miscutils/setserial.c
+++ b/miscutils/setserial.c
@@ -381,8 +381,7 @@ static bool cmd_needs_arg(int cmd)
381# error "Unexpected flags size" 381# error "Unexpected flags size"
382#endif 382#endif
383 383
384static const uint16_t setbits[CMD_FLAG_LAST + 1] = 384static const uint16_t setbits[CMD_FLAG_LAST + 1] ALIGN2 = {
385{
386 0, 385 0,
387 ASYNC_SPD_HI, 386 ASYNC_SPD_HI,
388 ASYNC_SPD_VHI, 387 ASYNC_SPD_VHI,
diff --git a/miscutils/time.c b/miscutils/time.c
index dcc3a5b4c..12c540211 100644
--- a/miscutils/time.c
+++ b/miscutils/time.c
@@ -127,6 +127,10 @@ static void printargv(char *const *argv)
127 This is funky since the pagesize could be less than 1K. 127 This is funky since the pagesize could be less than 1K.
128 Note: Some machines express getrusage statistics in terms of K, 128 Note: Some machines express getrusage statistics in terms of K,
129 others in terms of pages. */ 129 others in terms of pages. */
130#ifdef BB_ARCH_FIXED_PAGESIZE
131# define pagesize BB_ARCH_FIXED_PAGESIZE
132# define ptok(pagesize, pages) ptok(pages)
133#endif
130static unsigned long ptok(const unsigned pagesize, const unsigned long pages) 134static unsigned long ptok(const unsigned pagesize, const unsigned long pages)
131{ 135{
132 unsigned long tmp; 136 unsigned long tmp;
@@ -140,6 +144,7 @@ static unsigned long ptok(const unsigned pagesize, const unsigned long pages)
140 tmp = pages * pagesize; /* Larger first, */ 144 tmp = pages * pagesize; /* Larger first, */
141 return tmp / 1024; /* then smaller. */ 145 return tmp / 1024; /* then smaller. */
142} 146}
147#undef pagesize
143#endif 148#endif
144 149
145/* summarize: Report on the system use of a command. 150/* summarize: Report on the system use of a command.
@@ -199,7 +204,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp)
199#if !ENABLE_PLATFORM_MINGW32 204#if !ENABLE_PLATFORM_MINGW32
200 unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */ 205 unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */
201 unsigned cpu_ticks; /* Same, in "CPU ticks" */ 206 unsigned cpu_ticks; /* Same, in "CPU ticks" */
202 unsigned pagesize = getpagesize(); 207 unsigned pagesize = bb_getpagesize();
203#endif 208#endif
204 209
205 /* Impossible: we do not use WUNTRACED flag in wait()... 210 /* Impossible: we do not use WUNTRACED flag in wait()...
diff --git a/miscutils/ts.c b/miscutils/ts.c
index f769d663b..3eecb7464 100644
--- a/miscutils/ts.c
+++ b/miscutils/ts.c
@@ -50,13 +50,13 @@ int ts_main(int argc UNUSED_PARAM, char **argv)
50 50
51#define date_buf bb_common_bufsiz1 51#define date_buf bb_common_bufsiz1
52 setup_common_bufsiz(); 52 setup_common_bufsiz();
53 gettimeofday(&base, NULL); 53 xgettimeofday(&base);
54 54
55 while ((line = xmalloc_fgets(stdin)) != NULL) { 55 while ((line = xmalloc_fgets(stdin)) != NULL) {
56 struct timeval ts; 56 struct timeval ts;
57 struct tm tm_time; 57 struct tm tm_time;
58 58
59 gettimeofday(&ts, NULL); 59 xgettimeofday(&ts);
60 if (opt) { 60 if (opt) {
61 /* -i and/or -s */ 61 /* -i and/or -s */
62 struct timeval ts1 = ts1; 62 struct timeval ts1 = ts1;
diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c
index 94a637eee..69ead7a13 100644
--- a/miscutils/ubi_tools.c
+++ b/miscutils/ubi_tools.c
@@ -97,7 +97,7 @@ static unsigned get_num_from_file(const char *path, unsigned max)
97int ubi_tools_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 97int ubi_tools_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
98int ubi_tools_main(int argc UNUSED_PARAM, char **argv) 98int ubi_tools_main(int argc UNUSED_PARAM, char **argv)
99{ 99{
100 static const struct suffix_mult size_suffixes[] = { 100 static const struct suffix_mult size_suffixes[] ALIGN_SUFFIX = {
101 { "KiB", 1024 }, 101 { "KiB", 1024 },
102 { "MiB", 1024*1024 }, 102 { "MiB", 1024*1024 },
103 { "GiB", 1024*1024*1024 }, 103 { "GiB", 1024*1024*1024 },
diff --git a/miscutils/watchdog.c b/miscutils/watchdog.c
index 8c8d7217f..0ed10bcf1 100644
--- a/miscutils/watchdog.c
+++ b/miscutils/watchdog.c
@@ -88,7 +88,7 @@ int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
88int watchdog_main(int argc UNUSED_PARAM, char **argv) 88int watchdog_main(int argc UNUSED_PARAM, char **argv)
89{ 89{
90 static const int enable = WDIOS_ENABLECARD; 90 static const int enable = WDIOS_ENABLECARD;
91 static const struct suffix_mult suffixes[] = { 91 static const struct suffix_mult suffixes[] ALIGN_SUFFIX = {
92 { "ms", 1 }, 92 { "ms", 1 },
93 { "", 1000 }, 93 { "", 1000 },
94 { "", 0 } 94 { "", 0 }
@@ -143,7 +143,7 @@ int watchdog_main(int argc UNUSED_PARAM, char **argv)
143 * as the counter value is undefined at this point -- PFM 143 * as the counter value is undefined at this point -- PFM
144 */ 144 */
145 write(3, "", 1); /* write zero byte */ 145 write(3, "", 1); /* write zero byte */
146 usleep(stimer_duration * 1000L); 146 msleep(stimer_duration);
147 } 147 }
148 return EXIT_SUCCESS; /* - not reached, but gcc 4.2.1 is too dumb! */ 148 return EXIT_SUCCESS; /* - not reached, but gcc 4.2.1 is too dumb! */
149} 149}
diff --git a/modutils/insmod.c b/modutils/insmod.c
index bd79a0f26..8f7163e25 100644
--- a/modutils/insmod.c
+++ b/modutils/insmod.c
@@ -26,7 +26,7 @@
26 26
27//usage:#if !ENABLE_MODPROBE_SMALL 27//usage:#if !ENABLE_MODPROBE_SMALL
28//usage:#define insmod_trivial_usage 28//usage:#define insmod_trivial_usage
29//usage: IF_FEATURE_2_4_MODULES("[OPTIONS] MODULE") 29//usage: IF_FEATURE_2_4_MODULES("[-fkvqLx] MODULE")
30//usage: IF_NOT_FEATURE_2_4_MODULES("FILE") 30//usage: IF_NOT_FEATURE_2_4_MODULES("FILE")
31//usage: IF_FEATURE_CMDLINE_MODULE_OPTIONS(" [SYMBOL=VALUE]...") 31//usage: IF_FEATURE_CMDLINE_MODULE_OPTIONS(" [SYMBOL=VALUE]...")
32//usage:#define insmod_full_usage "\n\n" 32//usage:#define insmod_full_usage "\n\n"
diff --git a/modutils/modinfo.c b/modutils/modinfo.c
index c5cdc7980..d15772f0d 100644
--- a/modutils/modinfo.c
+++ b/modutils/modinfo.c
@@ -20,7 +20,7 @@
20#include "libbb.h" 20#include "libbb.h"
21#include "modutils.h" 21#include "modutils.h"
22 22
23static const char *const shortcuts[] = { 23static const char *const shortcuts[] ALIGN_PTR = {
24 "filename", // -n 24 "filename", // -n
25 "author", // -a 25 "author", // -a
26 "description", // -d 26 "description", // -d
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index 18cfac481..db44a2ed0 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -377,11 +377,11 @@ static int parse_module(module_info *info, const char *pathname)
377 return info->open_read_failed; 377 return info->open_read_failed;
378} 378}
379 379
380static FAST_FUNC int fileAction(const char *pathname, 380static FAST_FUNC int fileAction(struct recursive_state *state,
381 struct stat *sb UNUSED_PARAM, 381 const char *pathname,
382 void *modname_to_match, 382 struct stat *sb UNUSED_PARAM)
383 int depth UNUSED_PARAM)
384{ 383{
384 const char *modname_to_match = state->userData;
385 int cur; 385 int cur;
386 const char *fname; 386 const char *fname;
387 bool is_remove = (ENABLE_RMMOD && ONLY_APPLET) 387 bool is_remove = (ENABLE_RMMOD && ONLY_APPLET)
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index eeeff7609..c334186b8 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -663,6 +663,25 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
663 load_modules_dep(); 663 load_modules_dep();
664 } 664 }
665 665
666 /* Handle modprobe.blacklist=module1,module2,... */
667 if (ENABLE_FEATURE_MODPROBE_BLACKLIST) {
668 char *options;
669 char *substr;
670
671 options = parse_and_add_kcmdline_module_options(NULL, "modprobe");
672 while ((substr = strsep(&options, " ")) != NULL) {
673 char *fn = is_prefixed_with(substr, "blacklist=");
674 if (!fn)
675 continue;
676 while ((substr = strsep(&fn, ",")) != NULL) {
677 /* blacklist <modulename> */
678 get_or_add_modentry(substr)->flags |= MODULE_FLAG_BLACKLISTED;
679 DBG("blacklist: %s", substr);
680 }
681 }
682 /*free(options); - WRONG, strsep may have advanced it */
683 }
684
666 rc = 0; 685 rc = 0;
667 while ((me = llist_pop(&G.probes)) != NULL) { 686 while ((me = llist_pop(&G.probes)) != NULL) {
668 if (me->realnames == NULL) { 687 if (me->realnames == NULL) {
diff --git a/modutils/modutils.c b/modutils/modutils.c
index 6f7cd9721..f7ad5e805 100644
--- a/modutils/modutils.c
+++ b/modutils/modutils.c
@@ -169,7 +169,7 @@ void* FAST_FUNC try_to_mmap_module(const char *filename, size_t *image_size_p)
169 /* st.st_size is off_t, we can't just pass it to mmap */ 169 /* st.st_size is off_t, we can't just pass it to mmap */
170 if (st.st_size <= *image_size_p) { 170 if (st.st_size <= *image_size_p) {
171 size_t image_size = st.st_size; 171 size_t image_size = st.st_size;
172 image = mmap(NULL, image_size, PROT_READ, MAP_PRIVATE, fd, 0); 172 image = mmap_read(fd, image_size);
173 if (image == MAP_FAILED) { 173 if (image == MAP_FAILED) {
174 image = NULL; 174 image = NULL;
175 } else if (*(uint32_t*)image != SWAP_BE32(0x7f454C46)) { 175 } else if (*(uint32_t*)image != SWAP_BE32(0x7f454C46)) {
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index 7b6b89057..f1d5ca571 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -43,7 +43,7 @@
43//usage: "\n -v Verbose" 43//usage: "\n -v Verbose"
44//usage: "\n -u USER Username" 44//usage: "\n -u USER Username"
45//usage: "\n -p PASS Password" 45//usage: "\n -p PASS Password"
46//usage: "\n -P NUM Port" 46//usage: "\n -P PORT"
47//usage: 47//usage:
48//usage:#define ftpput_trivial_usage 48//usage:#define ftpput_trivial_usage
49//usage: "[OPTIONS] HOST [REMOTE_FILE] LOCAL_FILE" 49//usage: "[OPTIONS] HOST [REMOTE_FILE] LOCAL_FILE"
@@ -52,7 +52,7 @@
52//usage: "\n -v Verbose" 52//usage: "\n -v Verbose"
53//usage: "\n -u USER Username" 53//usage: "\n -u USER Username"
54//usage: "\n -p PASS Password" 54//usage: "\n -p PASS Password"
55//usage: "\n -P NUM Port number" 55//usage: "\n -P PORT"
56 56
57#include "libbb.h" 57#include "libbb.h"
58#include "common_bufsiz.h" 58#include "common_bufsiz.h"
diff --git a/networking/hostname.c b/networking/hostname.c
index f96daed95..549103485 100644
--- a/networking/hostname.c
+++ b/networking/hostname.c
@@ -29,9 +29,9 @@
29//kbuild: lib-$(CONFIG_DNSDOMAINNAME) += hostname.o 29//kbuild: lib-$(CONFIG_DNSDOMAINNAME) += hostname.o
30 30
31//usage:#define hostname_trivial_usage 31//usage:#define hostname_trivial_usage
32//usage: "[OPTIONS] [HOSTNAME | -F FILE]" 32//usage: "[-sidf] [HOSTNAME | -F FILE]"
33//usage:#define hostname_full_usage "\n\n" 33//usage:#define hostname_full_usage "\n\n"
34//usage: "Get or set hostname or DNS domain name\n" 34//usage: "Show or set hostname or DNS domain name\n"
35//usage: "\n -s Short" 35//usage: "\n -s Short"
36//usage: "\n -i Addresses for the hostname" 36//usage: "\n -i Addresses for the hostname"
37//usage: "\n -d DNS domain name" 37//usage: "\n -d DNS domain name"
diff --git a/networking/httpd.c b/networking/httpd.c
index daa3ca1d0..02f544593 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -305,6 +305,11 @@
305# include <sys/sendfile.h> 305# include <sys/sendfile.h>
306#endif 306#endif
307 307
308/* see sys/netinet6/in6.h */
309#if defined(__FreeBSD__)
310# define s6_addr32 __u6_addr.__u6_addr32
311#endif
312
308#define DEBUG 0 313#define DEBUG 0
309 314
310#define IOBUF_SIZE 8192 315#define IOBUF_SIZE 8192
@@ -1036,48 +1041,9 @@ static char *encodeString(const char *string)
1036 * Parameter: a pointer to a base64 encoded string. 1041 * Parameter: a pointer to a base64 encoded string.
1037 * Decoded data is stored in-place. 1042 * Decoded data is stored in-place.
1038 */ 1043 */
1039static void decodeBase64(char *Data) 1044static void decodeBase64(char *data)
1040{ 1045{
1041# if ENABLE_BASE64 || ENABLE_UUDECODE 1046 decode_base64(data, NULL)[0] = '\0';
1042 /* Call decode_base64() from uuencode.c */
1043 char *eptr = Data;
1044 decode_base64(&eptr, Data);
1045 *eptr = '\0';
1046# else
1047 const unsigned char *in = (const unsigned char *)Data;
1048 /* The decoded size will be at most 3/4 the size of the encoded */
1049 unsigned ch = 0;
1050 int i = 0;
1051
1052 while (*in) {
1053 int t = *in++;
1054
1055 if (t >= '0' && t <= '9')
1056 t = t - '0' + 52;
1057 else if (t >= 'A' && t <= 'Z')
1058 t = t - 'A';
1059 else if (t >= 'a' && t <= 'z')
1060 t = t - 'a' + 26;
1061 else if (t == '+')
1062 t = 62;
1063 else if (t == '/')
1064 t = 63;
1065 else if (t == '=')
1066 t = 0;
1067 else
1068 continue;
1069
1070 ch = (ch << 6) | t;
1071 i++;
1072 if (i == 4) {
1073 *Data++ = (char) (ch >> 16);
1074 *Data++ = (char) (ch >> 8);
1075 *Data++ = (char) ch;
1076 i = 0;
1077 }
1078 }
1079 *Data = '\0';
1080# endif
1081} 1047}
1082#endif 1048#endif
1083 1049
@@ -1945,7 +1911,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1945 send_headers(HTTP_OK); 1911 send_headers(HTTP_OK);
1946#if ENABLE_FEATURE_USE_SENDFILE 1912#if ENABLE_FEATURE_USE_SENDFILE
1947 { 1913 {
1948 off_t offset = range_start; 1914 off_t offset = (range_start < 0) ? 0 : range_start;
1949 while (1) { 1915 while (1) {
1950 /* sz is rounded down to 64k */ 1916 /* sz is rounded down to 64k */
1951 ssize_t sz = MAXINT(ssize_t) - 0xffff; 1917 ssize_t sz = MAXINT(ssize_t) - 0xffff;
@@ -2590,8 +2556,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2590 if (STRNCASECMP(iobuf, "Range:") == 0) { 2556 if (STRNCASECMP(iobuf, "Range:") == 0) {
2591 /* We know only bytes=NNN-[MMM] */ 2557 /* We know only bytes=NNN-[MMM] */
2592 char *s = skip_whitespace(iobuf + sizeof("Range:")-1); 2558 char *s = skip_whitespace(iobuf + sizeof("Range:")-1);
2593 if (is_prefixed_with(s, "bytes=")) { 2559 s = is_prefixed_with(s, "bytes=");
2594 s += sizeof("bytes=")-1; 2560 if (s) {
2595 range_start = BB_STRTOOFF(s, &s, 10); 2561 range_start = BB_STRTOOFF(s, &s, 10);
2596 if (s[0] != '-' || range_start < 0) { 2562 if (s[0] != '-' || range_start < 0) {
2597 range_start = -1; 2563 range_start = -1;
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
index 3c9a2dfb3..9ee232a66 100644
--- a/networking/ifconfig.c
+++ b/networking/ifconfig.c
@@ -76,7 +76,7 @@
76//kbuild:lib-$(CONFIG_IFCONFIG) += ifconfig.o interface.o 76//kbuild:lib-$(CONFIG_IFCONFIG) += ifconfig.o interface.o
77 77
78//usage:#define ifconfig_trivial_usage 78//usage:#define ifconfig_trivial_usage
79//usage: IF_FEATURE_IFCONFIG_STATUS("[-a]") " interface [address]" 79//usage: IF_FEATURE_IFCONFIG_STATUS("[-a]") " [IFACE] [ADDRESS]"
80//usage:#define ifconfig_full_usage "\n\n" 80//usage:#define ifconfig_full_usage "\n\n"
81//usage: "Configure a network interface\n" 81//usage: "Configure a network interface\n"
82//usage: "\n" 82//usage: "\n"
@@ -247,7 +247,7 @@ struct options {
247 * Set up the tables. Warning! They must have corresponding order! 247 * Set up the tables. Warning! They must have corresponding order!
248 */ 248 */
249 249
250static const struct arg1opt Arg1Opt[] = { 250static const struct arg1opt Arg1Opt[] ALIGN_PTR = {
251 { "SIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric) }, 251 { "SIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric) },
252 { "SIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu) }, 252 { "SIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu) },
253 { "SIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen) }, 253 { "SIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen) },
@@ -277,7 +277,7 @@ static const struct arg1opt Arg1Opt[] = {
277 { "SIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr) }, 277 { "SIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr) },
278}; 278};
279 279
280static const struct options OptArray[] = { 280static const struct options OptArray[] ALIGN_PTR = {
281 { "metric", N_ARG, ARG_METRIC, 0 }, 281 { "metric", N_ARG, ARG_METRIC, 0 },
282 { "mtu", N_ARG, ARG_MTU, 0 }, 282 { "mtu", N_ARG, ARG_MTU, 0 },
283 { "txqueuelen", N_ARG, ARG_TXQUEUELEN, 0 }, 283 { "txqueuelen", N_ARG, ARG_TXQUEUELEN, 0 },
diff --git a/networking/ifplugd.c b/networking/ifplugd.c
index 0d17b7d8c..18dcaff96 100644
--- a/networking/ifplugd.c
+++ b/networking/ifplugd.c
@@ -304,7 +304,7 @@ static const char api_modes[] ALIGN1 = "empwia";
304static const struct { 304static const struct {
305 const char *name; 305 const char *name;
306 smallint (*func)(void); 306 smallint (*func)(void);
307} method_table[] = { 307} method_table[] ALIGN_PTR = {
308 { "SIOCETHTOOL" , &detect_link_ethtool }, 308 { "SIOCETHTOOL" , &detect_link_ethtool },
309 { "SIOCGMIIPHY" , &detect_link_mii }, 309 { "SIOCGMIIPHY" , &detect_link_mii },
310 { "SIOCDEVPRIVATE" , &detect_link_priv }, 310 { "SIOCDEVPRIVATE" , &detect_link_priv },
@@ -735,7 +735,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
735 delay_time += G.delay_down; 735 delay_time += G.delay_down;
736#if 0 /* if you are back in 1970... */ 736#if 0 /* if you are back in 1970... */
737 if (delay_time == 0) { 737 if (delay_time == 0) {
738 sleep(1); 738 sleep1();
739 delay_time = 1; 739 delay_time = 1;
740 } 740 }
741#endif 741#endif
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 60ceb5a1f..737113dd4 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -113,30 +113,30 @@
113//kbuild:lib-$(CONFIG_IFDOWN) += ifupdown.o 113//kbuild:lib-$(CONFIG_IFDOWN) += ifupdown.o
114 114
115//usage:#define ifup_trivial_usage 115//usage:#define ifup_trivial_usage
116//usage: "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..." 116//usage: "[-n"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] -a | IFACE..."
117//usage:#define ifup_full_usage "\n\n" 117//usage:#define ifup_full_usage "\n\n"
118//usage: " -a Configure all interfaces" 118//usage: " -a Configure all interfaces"
119//usage: "\n -i FILE Use FILE instead of /etc/network/interfaces" 119//usage: "\n -i FILE Use FILE instead of /etc/network/interfaces"
120//usage: "\n -n Print out what would happen, but don't do it" 120//usage: "\n -n Dry run"
121//usage: IF_FEATURE_IFUPDOWN_MAPPING( 121//usage: IF_FEATURE_IFUPDOWN_MAPPING(
122//usage: "\n (note: doesn't disable mappings)" 122//usage: "\n (note: doesn't disable mappings)"
123//usage: "\n -m Don't run any mappings" 123//usage: "\n -m Don't run any mappings"
124//usage: ) 124//usage: )
125//usage: "\n -v Print out what would happen before doing it" 125//usage: "\n -v Print out what would happen before doing it"
126//usage: "\n -f Force configuration" 126//usage: "\n -f Force"
127//usage: 127//usage:
128//usage:#define ifdown_trivial_usage 128//usage:#define ifdown_trivial_usage
129//usage: "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..." 129//usage: "[-n"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] -a | IFACE..."
130//usage:#define ifdown_full_usage "\n\n" 130//usage:#define ifdown_full_usage "\n\n"
131//usage: " -a Deconfigure all interfaces" 131//usage: " -a Deconfigure all interfaces"
132//usage: "\n -i FILE Use FILE for interface definitions" 132//usage: "\n -i FILE Use FILE instead of /etc/network/interfaces"
133//usage: "\n -n Print out what would happen, but don't do it" 133//usage: "\n -n Dry run"
134//usage: IF_FEATURE_IFUPDOWN_MAPPING( 134//usage: IF_FEATURE_IFUPDOWN_MAPPING(
135//usage: "\n (note: doesn't disable mappings)" 135//usage: "\n (note: doesn't disable mappings)"
136//usage: "\n -m Don't run any mappings" 136//usage: "\n -m Don't run any mappings"
137//usage: ) 137//usage: )
138//usage: "\n -v Print out what would happen before doing it" 138//usage: "\n -v Print out what would happen before doing it"
139//usage: "\n -f Force deconfiguration" 139//usage: "\n -f Force"
140 140
141#include <net/if.h> 141#include <net/if.h>
142#include "libbb.h" 142#include "libbb.h"
@@ -1357,15 +1357,15 @@ static FILE *open_new_state_file(void)
1357 IFSTATE_FILE_PATH".new"); 1357 IFSTATE_FILE_PATH".new");
1358 } 1358 }
1359 /* Someone else created the .new file */ 1359 /* Someone else created the .new file */
1360 if (cnt > 30 * 1000) { 1360 if (cnt > 30) {
1361 /* Waited for 30*30/2 = 450 milliseconds, still EEXIST. 1361 /* Waited for 30*30/2 = 450 milliseconds, still EEXIST.
1362 * Assuming a stale file, rewriting it. 1362 * Assuming a stale file, rewriting it.
1363 */ 1363 */
1364 flags = (O_WRONLY | O_CREAT | O_TRUNC); 1364 flags = (O_WRONLY | O_CREAT | O_TRUNC);
1365 continue; 1365 continue;
1366 } 1366 }
1367 usleep(cnt); 1367 msleep(cnt);
1368 cnt += 1000; 1368 cnt++;
1369 } 1369 }
1370 1370
1371 return xfdopen_for_write(fd); 1371 return xfdopen_for_write(fd);
diff --git a/networking/inetd.c b/networking/inetd.c
index 3cd2b11f0..febfb7b73 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -361,7 +361,7 @@ struct builtin {
361 void (*bi_dgram_fn)(int, servtab_t *) FAST_FUNC; 361 void (*bi_dgram_fn)(int, servtab_t *) FAST_FUNC;
362}; 362};
363 363
364static const struct builtin builtins[] = { 364static const struct builtin builtins[] ALIGN_PTR = {
365#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 365#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
366 { "echo", 1, echo_stream, echo_dg }, 366 { "echo", 1, echo_stream, echo_dg },
367#endif 367#endif
@@ -1305,7 +1305,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1305 if (ready_fd_cnt < 0) { 1305 if (ready_fd_cnt < 0) {
1306 if (errno != EINTR) { 1306 if (errno != EINTR) {
1307 bb_simple_perror_msg("select"); 1307 bb_simple_perror_msg("select");
1308 sleep(1); 1308 sleep1();
1309 } 1309 }
1310 continue; 1310 continue;
1311 } 1311 }
@@ -1406,7 +1406,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1406 1406
1407 if (pid < 0) { /* fork error */ 1407 if (pid < 0) { /* fork error */
1408 bb_simple_perror_msg("vfork"+1); 1408 bb_simple_perror_msg("vfork"+1);
1409 sleep(1); 1409 sleep1();
1410 restore_sigmask(&omask); 1410 restore_sigmask(&omask);
1411 maybe_close(new_udp_fd); 1411 maybe_close(new_udp_fd);
1412 maybe_close(accepted_fd); 1412 maybe_close(accepted_fd);
@@ -1701,7 +1701,7 @@ static uint32_t machtime(void)
1701{ 1701{
1702 struct timeval tv; 1702 struct timeval tv;
1703 1703
1704 gettimeofday(&tv, NULL); 1704 xgettimeofday(&tv);
1705 return htonl((uint32_t)(tv.tv_sec + 2208988800U)); 1705 return htonl((uint32_t)(tv.tv_sec + 2208988800U));
1706} 1706}
1707/* ARGSUSED */ 1707/* ARGSUSED */
diff --git a/networking/interface.c b/networking/interface.c
index e5e55d8d4..ea6a2c8a8 100644
--- a/networking/interface.c
+++ b/networking/interface.c
@@ -746,7 +746,7 @@ static const struct hwtype *const hwtypes[] = {
746}; 746};
747 747
748#ifdef IFF_PORTSEL 748#ifdef IFF_PORTSEL
749static const char *const if_port_text[] = { 749static const char *const if_port_text[] ALIGN_PTR = {
750 /* Keep in step with <linux/netdevice.h> */ 750 /* Keep in step with <linux/netdevice.h> */
751 "unknown", 751 "unknown",
752 "10base2", 752 "10base2",
diff --git a/networking/ip.c b/networking/ip.c
index 33bea5f49..85b1ba080 100644
--- a/networking/ip.c
+++ b/networking/ip.c
@@ -400,7 +400,7 @@ int ip_main(int argc UNUSED_PARAM, char **argv)
400 IF_FEATURE_IP_RULE("rule\0") 400 IF_FEATURE_IP_RULE("rule\0")
401 IF_FEATURE_IP_NEIGH("neigh\0") 401 IF_FEATURE_IP_NEIGH("neigh\0")
402 ; 402 ;
403 static const ip_func_ptr_t ip_func_ptrs[] = { 403 static const ip_func_ptr_t ip_func_ptrs[] ALIGN_PTR = {
404 ip_print_help, 404 ip_print_help,
405 IF_FEATURE_IP_ADDRESS(do_ipaddr,) 405 IF_FEATURE_IP_ADDRESS(do_ipaddr,)
406 IF_FEATURE_IP_ROUTE(do_iproute,) 406 IF_FEATURE_IP_ROUTE(do_iproute,)
diff --git a/networking/ipcalc.c b/networking/ipcalc.c
index 09b146872..e82e35dd5 100644
--- a/networking/ipcalc.c
+++ b/networking/ipcalc.c
@@ -36,7 +36,7 @@
36//kbuild:lib-$(CONFIG_IPCALC) += ipcalc.o 36//kbuild:lib-$(CONFIG_IPCALC) += ipcalc.o
37 37
38//usage:#define ipcalc_trivial_usage 38//usage:#define ipcalc_trivial_usage
39//usage: "[OPTIONS] ADDRESS" 39//usage: "[-bnm"IF_FEATURE_IPCALC_FANCY("phs")"] ADDRESS"
40//usage: IF_FEATURE_IPCALC_FANCY("[/PREFIX]") " [NETMASK]" 40//usage: IF_FEATURE_IPCALC_FANCY("[/PREFIX]") " [NETMASK]"
41//usage:#define ipcalc_full_usage "\n\n" 41//usage:#define ipcalc_full_usage "\n\n"
42//usage: "Calculate and display network settings from IP address\n" 42//usage: "Calculate and display network settings from IP address\n"
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index 71e8fb6a7..dfd84c000 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -21,6 +21,17 @@
21#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ 21#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
22#endif 22#endif
23 23
24/* for old uclibc */
25#ifndef IFA_F_NOPREFIXROUTE
26# define IFA_FLAGS 8
27# define IFA_F_NOPREFIXROUTE 0x200
28enum { /* can't do this with preporcessor, IFA_MAX is an (enum - 1), not preprocessor constant */
29 REAL_IFA_MAX = (IFA_MAX >= IFA_FLAGS) ? IFA_MAX : IFA_FLAGS,
30};
31# undef IFA_MAX
32# define IFA_MAX REAL_IFA_MAX
33#endif
34
24struct filter_t { 35struct filter_t {
25 char *label; 36 char *label;
26 /* Flush cmd buf. If !NULL, print_addrinfo() constructs flush commands in it */ 37 /* Flush cmd buf. If !NULL, print_addrinfo() constructs flush commands in it */
diff --git a/networking/libiproute/rt_names.c b/networking/libiproute/rt_names.c
index 51f2e9bdb..3c2fad912 100644
--- a/networking/libiproute/rt_names.c
+++ b/networking/libiproute/rt_names.c
@@ -77,7 +77,7 @@ static rtnl_tab_t *rtnl_rtprot_tab;
77 77
78static void rtnl_rtprot_initialize(void) 78static void rtnl_rtprot_initialize(void)
79{ 79{
80 static const char *const init_tab[] = { 80 static const char *const init_tab[] ALIGN_PTR = {
81 "none", 81 "none",
82 "redirect", 82 "redirect",
83 "kernel", 83 "kernel",
diff --git a/networking/libiproute/rtm_map.c b/networking/libiproute/rtm_map.c
index e94c99ab6..8b94c2f24 100644
--- a/networking/libiproute/rtm_map.c
+++ b/networking/libiproute/rtm_map.c
@@ -11,33 +11,55 @@
11#include "rt_names.h" 11#include "rt_names.h"
12#include "utils.h" 12#include "utils.h"
13 13
14static const char keywords[] ALIGN1 =
15 "local\0""nat\0""broadcast\0""brd\0""anycast\0"
16 "multicast\0""prohibit\0""unreachable\0""blackhole\0"
17 "xresolve\0""unicast\0""throw\0";
18enum {
19 ARG_local = 1, ARG_nat, ARG_broadcast, ARG_brd, ARG_anycast,
20 ARG_multicast, ARG_prohibit, ARG_unreachable, ARG_blackhole,
21 ARG_xresolve, ARG_unicast, ARG_throw
22};
23#define str_local keywords
24#define str_nat (str_local + sizeof("local"))
25#define str_broadcast (str_nat + sizeof("nat"))
26#define str_brd (str_broadcast + sizeof("broadcast"))
27#define str_anycast (str_brd + sizeof("brd"))
28#define str_multicast (str_anycast + sizeof("anycast"))
29#define str_prohibit (str_multicast + sizeof("multicast"))
30#define str_unreachable (str_prohibit + sizeof("prohibit"))
31#define str_blackhole (str_unreachable + sizeof("unreachable"))
32#define str_xresolve (str_blackhole + sizeof("blackhole"))
33#define str_unicast (str_xresolve + sizeof("xresolve"))
34#define str_throw (str_unicast + sizeof("unicast"))
35
14const char* FAST_FUNC rtnl_rtntype_n2a(int id) 36const char* FAST_FUNC rtnl_rtntype_n2a(int id)
15{ 37{
16 switch (id) { 38 switch (id) {
17 case RTN_UNSPEC: 39 case RTN_UNSPEC:
18 return "none"; 40 return "none";
19 case RTN_UNICAST: 41 case RTN_UNICAST:
20 return "unicast"; 42 return str_unicast;
21 case RTN_LOCAL: 43 case RTN_LOCAL:
22 return "local"; 44 return str_local;
23 case RTN_BROADCAST: 45 case RTN_BROADCAST:
24 return "broadcast"; 46 return str_broadcast;
25 case RTN_ANYCAST: 47 case RTN_ANYCAST:
26 return "anycast"; 48 return str_anycast;
27 case RTN_MULTICAST: 49 case RTN_MULTICAST:
28 return "multicast"; 50 return str_multicast;
29 case RTN_BLACKHOLE: 51 case RTN_BLACKHOLE:
30 return "blackhole"; 52 return str_blackhole;
31 case RTN_UNREACHABLE: 53 case RTN_UNREACHABLE:
32 return "unreachable"; 54 return str_unreachable;
33 case RTN_PROHIBIT: 55 case RTN_PROHIBIT:
34 return "prohibit"; 56 return str_prohibit;
35 case RTN_THROW: 57 case RTN_THROW:
36 return "throw"; 58 return str_throw;
37 case RTN_NAT: 59 case RTN_NAT:
38 return "nat"; 60 return str_nat;
39 case RTN_XRESOLVE: 61 case RTN_XRESOLVE:
40 return "xresolve"; 62 return str_xresolve;
41 default: 63 default:
42 return itoa(id); 64 return itoa(id);
43 } 65 }
@@ -45,15 +67,6 @@ const char* FAST_FUNC rtnl_rtntype_n2a(int id)
45 67
46int FAST_FUNC rtnl_rtntype_a2n(int *id, char *arg) 68int FAST_FUNC rtnl_rtntype_a2n(int *id, char *arg)
47{ 69{
48 static const char keywords[] ALIGN1 =
49 "local\0""nat\0""broadcast\0""brd\0""anycast\0"
50 "multicast\0""prohibit\0""unreachable\0""blackhole\0"
51 "xresolve\0""unicast\0""throw\0";
52 enum {
53 ARG_local = 1, ARG_nat, ARG_broadcast, ARG_brd, ARG_anycast,
54 ARG_multicast, ARG_prohibit, ARG_unreachable, ARG_blackhole,
55 ARG_xresolve, ARG_unicast, ARG_throw
56 };
57 const smalluint key = index_in_substrings(keywords, arg) + 1; 70 const smalluint key = index_in_substrings(keywords, arg) + 1;
58 char *end; 71 char *end;
59 unsigned long res; 72 unsigned long res;
diff --git a/networking/nbd-client.c b/networking/nbd-client.c
index 3db3b46f9..755b42ccd 100644
--- a/networking/nbd-client.c
+++ b/networking/nbd-client.c
@@ -270,7 +270,7 @@ int nbdclient_main(int argc, char **argv)
270 close(fd); 270 close(fd);
271 break; 271 break;
272 } 272 }
273 sleep(1); 273 sleep1();
274 } 274 }
275 open(device, O_RDONLY); 275 open(device, O_RDONLY);
276 return 0; 276 return 0;
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 88eda6b28..25b95246f 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -196,7 +196,7 @@ enum {
196/* Debug: squirt whatever message and sleep a bit so we can see it go by. */ 196/* Debug: squirt whatever message and sleep a bit so we can see it go by. */
197/* Beware: writes to stdOUT... */ 197/* Beware: writes to stdOUT... */
198#if 0 198#if 0
199#define Debug(...) do { printf(__VA_ARGS__); printf("\n"); fflush_all(); sleep(1); } while (0) 199#define Debug(...) do { printf(__VA_ARGS__); printf("\n"); fflush_all(); sleep1(); } while (0)
200#else 200#else
201#define Debug(...) do { } while (0) 201#define Debug(...) do { } while (0)
202#endif 202#endif
diff --git a/networking/netstat.c b/networking/netstat.c
index 3ab7b0d21..807800a62 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -114,7 +114,7 @@ enum {
114 TCP_CLOSING, /* now a valid state */ 114 TCP_CLOSING, /* now a valid state */
115}; 115};
116 116
117static const char *const tcp_state[] = { 117static const char *const tcp_state[] ALIGN_PTR = {
118 "", 118 "",
119 "ESTABLISHED", 119 "ESTABLISHED",
120 "SYN_SENT", 120 "SYN_SENT",
diff --git a/networking/nslookup.c b/networking/nslookup.c
index 759de5c83..c43ad46f3 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -273,7 +273,7 @@ struct query {
273static const struct { 273static const struct {
274 unsigned char type; 274 unsigned char type;
275 char name[7]; 275 char name[7];
276} qtypes[] = { 276} qtypes[] ALIGN1 = {
277 { ns_t_soa, "SOA" }, 277 { ns_t_soa, "SOA" },
278 { ns_t_ns, "NS" }, 278 { ns_t_ns, "NS" },
279 { ns_t_a, "A" }, 279 { ns_t_a, "A" },
@@ -288,7 +288,7 @@ static const struct {
288 { ns_t_any, "ANY" }, 288 { ns_t_any, "ANY" },
289}; 289};
290 290
291static const char *const rcodes[] = { 291static const char *const rcodes[] ALIGN_PTR = {
292 "NOERROR", // 0 292 "NOERROR", // 0
293 "FORMERR", // 1 293 "FORMERR", // 1
294 "SERVFAIL", // 2 294 "SERVFAIL", // 2
@@ -349,6 +349,8 @@ static int parse_reply(const unsigned char *msg, size_t len)
349 header = (HEADER *)msg; 349 header = (HEADER *)msg;
350 if (!header->aa) 350 if (!header->aa)
351 printf("Non-authoritative answer:\n"); 351 printf("Non-authoritative answer:\n");
352 else if (option_mask32 & OPT_debug)
353 printf("Non-authoritative answer:\n" + 4);
352 354
353 if (ns_initparse(msg, len, &handle) != 0) { 355 if (ns_initparse(msg, len, &handle) != 0) {
354 //printf("Unable to parse reply: %s\n", strerror(errno)); 356 //printf("Unable to parse reply: %s\n", strerror(errno));
@@ -381,7 +383,7 @@ static int parse_reply(const unsigned char *msg, size_t len)
381 return -1; 383 return -1;
382 } 384 }
383 inet_ntop(AF_INET6, ns_rr_rdata(rr), astr, sizeof(astr)); 385 inet_ntop(AF_INET6, ns_rr_rdata(rr), astr, sizeof(astr));
384 /* bind-utils-9.11.3 uses the same format for A and AAAA answers */ 386 /* bind-utils 9.11.3 uses the same format for A and AAAA answers */
385 printf("Name:\t%s\nAddress: %s\n", ns_rr_name(rr), astr); 387 printf("Name:\t%s\nAddress: %s\n", ns_rr_name(rr), astr);
386 break; 388 break;
387#endif 389#endif
@@ -580,7 +582,7 @@ static int send_queries(struct ns *ns)
580 printf("Address:\t%s\n\n", 582 printf("Address:\t%s\n\n",
581 auto_string(xmalloc_sockaddr2dotted(&ns->lsa->u.sa)) 583 auto_string(xmalloc_sockaddr2dotted(&ns->lsa->u.sa))
582 ); 584 );
583 /* In "Address", bind-utils-9.11.3 show port after a hash: "1.2.3.4#53" */ 585 /* In "Address", bind-utils 9.11.3 show port after a hash: "1.2.3.4#53" */
584 /* Should we do the same? */ 586 /* Should we do the same? */
585 } 587 }
586 588
@@ -640,12 +642,26 @@ static int send_queries(struct ns *ns)
640 printf("*** Can't find %s: Parse error\n", G.query[qn].name); 642 printf("*** Can't find %s: Parse error\n", G.query[qn].name);
641 G.exitcode = EXIT_FAILURE; 643 G.exitcode = EXIT_FAILURE;
642 break; 644 break;
643 645 /* bind-utils 9.11.25 just says nothing in this case */
644 case 0: 646 //case 0:
645 printf("*** Can't find %s: No answer\n", G.query[qn].name); 647 // break;
646 break;
647 } 648 }
648 } 649 }
650/* NB: in case of authoritative, empty answer (NODATA), IOW: one with
651 * ns_msg_count() == 0, bind-utils 9.11.25 shows no trace of this answer
652 * (unless -debug, where it says:
653 * ------------
654 * QUESTIONS:
655 * host.com, type = AAAA, class = IN
656 * ANSWERS:
657 * AUTHORITY RECORDS:
658 * ADDITIONAL RECORDS:
659 * ------------
660 * ). Due to printing of below '\n', we do show an additional empty line.
661 * This is better than not showing any indication of this reply at all,
662 * yet maintains "compatibility". I wonder whether it's better to break compat
663 * and emit something more meaningful, e.g. print "Empty answer (NODATA)"?
664 */
649 bb_putchar('\n'); 665 bb_putchar('\n');
650 n_replies++; 666 n_replies++;
651 if (n_replies >= G.query_count) 667 if (n_replies >= G.query_count)
@@ -697,7 +713,7 @@ static void parse_resolvconf(void)
697{ 713{
698 FILE *resolv; 714 FILE *resolv;
699 715
700 resolv = fopen("/etc/resolv.conf", "r"); 716 resolv = fopen_for_read("/etc/resolv.conf");
701 if (resolv) { 717 if (resolv) {
702 char line[512]; /* "search" is defined to be up to 256 chars */ 718 char line[512]; /* "search" is defined to be up to 256 chars */
703 719
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 44e711232..1f17b08ef 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -77,7 +77,7 @@
77//usage: IF_FEATURE_NTP_AUTH(" [-k KEYFILE] [-p [keyno:N:]PEER]...") 77//usage: IF_FEATURE_NTP_AUTH(" [-k KEYFILE] [-p [keyno:N:]PEER]...")
78//usage:#define ntpd_full_usage "\n\n" 78//usage:#define ntpd_full_usage "\n\n"
79//usage: "NTP client/server\n" 79//usage: "NTP client/server\n"
80//usage: "\n -d Verbose (may be repeated)" 80//usage: "\n -d[d] Verbose"
81//usage: "\n -n Do not daemonize" 81//usage: "\n -n Do not daemonize"
82//usage: "\n -q Quit after clock is set" 82//usage: "\n -q Quit after clock is set"
83//usage: "\n -N Run at high priority" 83//usage: "\n -N Run at high priority"
@@ -113,6 +113,13 @@
113# define IPTOS_DSCP_AF21 0x48 113# define IPTOS_DSCP_AF21 0x48
114#endif 114#endif
115 115
116#if defined(__FreeBSD__)
117/* see sys/timex.h */
118# define adjtimex ntp_adjtime
119# define ADJ_OFFSET MOD_OFFSET
120# define ADJ_STATUS MOD_STATUS
121# define ADJ_TIMECONST MOD_TIMECONST
122#endif
116 123
117/* Verbosity control (max level of -dddd options accepted). 124/* Verbosity control (max level of -dddd options accepted).
118 * max 6 is very talkative (and bloated). 3 is non-bloated, 125 * max 6 is very talkative (and bloated). 3 is non-bloated,
@@ -560,7 +567,7 @@ static double
560gettime1900d(void) 567gettime1900d(void)
561{ 568{
562 struct timeval tv; 569 struct timeval tv;
563 gettimeofday(&tv, NULL); /* never fails */ 570 xgettimeofday(&tv);
564 G.cur_time = tv.tv_sec + (1.0e-6 * tv.tv_usec) + OFFSET_1900_1970; 571 G.cur_time = tv.tv_sec + (1.0e-6 * tv.tv_usec) + OFFSET_1900_1970;
565 return G.cur_time; 572 return G.cur_time;
566} 573}
@@ -1144,11 +1151,10 @@ step_time(double offset)
1144 char buf[sizeof("yyyy-mm-dd hh:mm:ss") + /*paranoia:*/ 4]; 1151 char buf[sizeof("yyyy-mm-dd hh:mm:ss") + /*paranoia:*/ 4];
1145 time_t tval; 1152 time_t tval;
1146 1153
1147 gettimeofday(&tvc, NULL); /* never fails */ 1154 xgettimeofday(&tvc);
1148 dtime = tvc.tv_sec + (1.0e-6 * tvc.tv_usec) + offset; 1155 dtime = tvc.tv_sec + (1.0e-6 * tvc.tv_usec) + offset;
1149 d_to_tv(dtime, &tvn); 1156 d_to_tv(dtime, &tvn);
1150 if (settimeofday(&tvn, NULL) == -1) 1157 xsettimeofday(&tvn);
1151 bb_simple_perror_msg_and_die("settimeofday");
1152 1158
1153 VERB2 { 1159 VERB2 {
1154 tval = tvc.tv_sec; 1160 tval = tvc.tv_sec;
@@ -2462,9 +2468,6 @@ static NOINLINE void ntp_init(char **argv)
2462 2468
2463 srand(getpid()); 2469 srand(getpid());
2464 2470
2465 if (getuid())
2466 bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
2467
2468 /* Set some globals */ 2471 /* Set some globals */
2469 G.discipline_jitter = G_precision_sec; 2472 G.discipline_jitter = G_precision_sec;
2470 G.stratum = MAXSTRAT; 2473 G.stratum = MAXSTRAT;
diff --git a/networking/ping.c b/networking/ping.c
index 5f7e5b9b5..86d8088de 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -58,16 +58,16 @@
58//usage:# define ping_trivial_usage 58//usage:# define ping_trivial_usage
59//usage: "HOST" 59//usage: "HOST"
60//usage:# define ping_full_usage "\n\n" 60//usage:# define ping_full_usage "\n\n"
61//usage: "Send ICMP ECHO_REQUEST packets to network hosts" 61//usage: "Send ICMP ECHO_REQUESTs to HOST"
62//usage:# define ping6_trivial_usage 62//usage:# define ping6_trivial_usage
63//usage: "HOST" 63//usage: "HOST"
64//usage:# define ping6_full_usage "\n\n" 64//usage:# define ping6_full_usage "\n\n"
65//usage: "Send ICMP ECHO_REQUEST packets to network hosts" 65//usage: "Send ICMP ECHO_REQUESTs to HOST"
66//usage:#else 66//usage:#else
67//usage:# define ping_trivial_usage 67//usage:# define ping_trivial_usage
68//usage: "[OPTIONS] HOST" 68//usage: "[OPTIONS] HOST"
69//usage:# define ping_full_usage "\n\n" 69//usage:# define ping_full_usage "\n\n"
70//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" 70//usage: "Send ICMP ECHO_REQUESTs to HOST\n"
71//usage: IF_PING6( 71//usage: IF_PING6(
72//usage: "\n -4,-6 Force IP or IPv6 name resolution" 72//usage: "\n -4,-6 Force IP or IPv6 name resolution"
73//usage: ) 73//usage: )
@@ -81,22 +81,26 @@
81//usage: "\n (after all -c CNT packets are sent)" 81//usage: "\n (after all -c CNT packets are sent)"
82//usage: "\n -w SEC Seconds until ping exits (default:infinite)" 82//usage: "\n -w SEC Seconds until ping exits (default:infinite)"
83//usage: "\n (can exit earlier with -c CNT)" 83//usage: "\n (can exit earlier with -c CNT)"
84//usage: "\n -q Quiet, only display output at start" 84//usage: "\n -q Quiet, only display output at start/finish"
85//usage: "\n and when finished" 85//usage: "\n -p HEXBYTE Payload pattern"
86//usage: "\n -p HEXBYTE Pattern to use for payload"
87//usage: 86//usage:
88//usage:# define ping6_trivial_usage 87//usage:# define ping6_trivial_usage
89//usage: "[OPTIONS] HOST" 88//usage: "[OPTIONS] HOST"
90//usage:# define ping6_full_usage "\n\n" 89//usage:# define ping6_full_usage "\n\n"
91//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" 90//usage: "Send ICMP ECHO_REQUESTs to HOST\n"
92//usage: "\n -c CNT Send only CNT pings" 91//usage: "\n -c CNT Send only CNT pings"
93//usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)" 92//usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)"
94//usage: "\n -i SECS Interval" 93//usage: "\n -i SECS Interval"
95//usage: "\n -A Ping as soon as reply is recevied" 94//usage: "\n -A Ping as soon as reply is recevied"
95///////: "\n -t TTL Set TTL"
96///////^^^^^ -t not tested for IPv6, might be not working
96//usage: "\n -I IFACE/IP Source interface or IP address" 97//usage: "\n -I IFACE/IP Source interface or IP address"
97//usage: "\n -q Quiet, only display output at start" 98//usage: "\n -W SEC Seconds to wait for the first response (default 10)"
98//usage: "\n and when finished" 99//usage: "\n (after all -c CNT packets are sent)"
99//usage: "\n -p HEXBYTE Pattern to use for payload" 100//usage: "\n -w SEC Seconds until ping exits (default:infinite)"
101//usage: "\n (can exit earlier with -c CNT)"
102//usage: "\n -q Quiet, only display output at start/finish"
103//usage: "\n -p HEXBYTE Payload pattern"
100//usage: 104//usage:
101//usage:#endif 105//usage:#endif
102//usage: 106//usage:
@@ -118,6 +122,10 @@
118//usage: "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" 122//usage: "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
119 123
120#include <net/if.h> 124#include <net/if.h>
125#if defined(__FreeBSD__)
126# include <netinet/in.h> /* struct ip and friends */
127# include <netinet/ip.h>
128#endif
121#include <netinet/ip_icmp.h> 129#include <netinet/ip_icmp.h>
122#include "libbb.h" 130#include "libbb.h"
123#include "common_bufsiz.h" 131#include "common_bufsiz.h"
@@ -156,6 +164,40 @@
156# endif 164# endif
157#endif 165#endif
158 166
167#if defined(__FreeBSD__)
168/**
169 * On BSD the IPv4 struct is called struct ip and instead of iXX
170 * the members are called ip_XX. One could change this code to use
171 * struct ip but that would require to define _BSD_SOURCE and that
172 * might have other complications. Instead make sure struct iphdr
173 * is present on FreeBSD. The below is taken from GLIBC.
174 *
175 * The GNU C Library is free software; you can redistribute it and/or
176 * modify it under the terms of the GNU Lesser General Public
177 * License as published by the Free Software Foundation; either
178 * version 2.1 of the License, or (at your option) any later version.
179 */
180struct iphdr {
181# if BYTE_ORDER == LITTLE_ENDIAN
182 unsigned int ihl:4;
183 unsigned int version:4;
184# elif BYTE_ORDER == BIG_ENDIAN
185 unsigned int version:4;
186 unsigned int ihl:4;
187# endif
188 uint8_t tos;
189 uint16_t tot_len;
190 uint16_t id;
191 uint16_t frag_off;
192 uint8_t ttl;
193 uint8_t protocol;
194 uint16_t check;
195 uint32_t saddr;
196 uint32_t daddr;
197 /*The options start here. */
198};
199#endif
200
159enum { 201enum {
160 DEFDATALEN = 56, 202 DEFDATALEN = 56,
161 MAXIPLEN = 60, 203 MAXIPLEN = 60,
@@ -332,6 +374,11 @@ static int common_ping_main(sa_family_t af, char **argv)
332 374
333 create_icmp_socket(lsa); 375 create_icmp_socket(lsa);
334 G.myid = (uint16_t) getpid(); 376 G.myid = (uint16_t) getpid();
377 /* we can use native-endian ident, but other Unix ping/traceroute
378 * utils use *big-endian pid*, and e.g. traceroute on our machine may be
379 * *not* from busybox, idents may collide. Follow the convention:
380 */
381 G.myid = htons(G.myid);
335#if ENABLE_PING6 382#if ENABLE_PING6
336 if (lsa->u.sa.sa_family == AF_INET6) 383 if (lsa->u.sa.sa_family == AF_INET6)
337 ping6(lsa); 384 ping6(lsa);
@@ -466,17 +513,16 @@ static void sendping_tail(void (*sp)(int), int size_pkt)
466{ 513{
467 int sz; 514 int sz;
468 515
469 CLR((uint16_t)G.ntransmitted % MAX_DUP_CHK);
470 G.ntransmitted++;
471
472 size_pkt += datalen;
473
474 if (G.deadline_us) { 516 if (G.deadline_us) {
475 unsigned n = G.cur_us - G.deadline_us; 517 unsigned n = G.cur_us - G.deadline_us;
476 if ((int)n >= 0) 518 if ((int)n >= 0)
477 print_stats_and_exit(0); 519 print_stats_and_exit(0);
478 } 520 }
479 521
522 CLR((uint16_t)G.ntransmitted % MAX_DUP_CHK);
523 G.ntransmitted++;
524 size_pkt += datalen;
525
480 /* sizeof(pingaddr) can be larger than real sa size, but I think 526 /* sizeof(pingaddr) can be larger than real sa size, but I think
481 * it doesn't matter */ 527 * it doesn't matter */
482 sz = xsendto(pingsock, G.snd_packet, size_pkt, &pingaddr.sa, sizeof(pingaddr)); 528 sz = xsendto(pingsock, G.snd_packet, size_pkt, &pingaddr.sa, sizeof(pingaddr));
@@ -927,6 +973,11 @@ static int common_ping_main(int opt, char **argv)
927 G.interval_us = interval * 1000000; 973 G.interval_us = interval * 1000000;
928 974
929 myid = (uint16_t) getpid(); 975 myid = (uint16_t) getpid();
976 /* we can use native-endian ident, but other Unix ping/traceroute
977 * utils use *big-endian pid*, and e.g. traceroute on our machine may be
978 * *not* from busybox, idents may collide. Follow the convention:
979 */
980 myid = htons(myid);
930 hostname = argv[optind]; 981 hostname = argv[optind];
931#if ENABLE_PING6 982#if ENABLE_PING6
932 { 983 {
diff --git a/networking/pscan.c b/networking/pscan.c
index 2715ef2df..816178bbc 100644
--- a/networking/pscan.c
+++ b/networking/pscan.c
@@ -18,13 +18,13 @@
18//usage:#define pscan_trivial_usage 18//usage:#define pscan_trivial_usage
19//usage: "[-cb] [-p MIN_PORT] [-P MAX_PORT] [-t TIMEOUT] [-T MIN_RTT] HOST" 19//usage: "[-cb] [-p MIN_PORT] [-P MAX_PORT] [-t TIMEOUT] [-T MIN_RTT] HOST"
20//usage:#define pscan_full_usage "\n\n" 20//usage:#define pscan_full_usage "\n\n"
21//usage: "Scan a host, print all open ports\n" 21//usage: "Scan HOST, print all open ports\n"
22//usage: "\n -c Show closed ports too" 22//usage: "\n -c Show closed ports too"
23//usage: "\n -b Show blocked ports too" 23//usage: "\n -b Show blocked ports too"
24//usage: "\n -p Scan from this port (default 1)" 24//usage: "\n -p PORT Scan from this port (default 1)"
25//usage: "\n -P Scan up to this port (default 1024)" 25//usage: "\n -P PORT Scan up to this port (default 1024)"
26//usage: "\n -t Timeout (default 5000 ms)" 26//usage: "\n -t MS Timeout (default 5000 ms)"
27//usage: "\n -T Minimum rtt (default 5 ms, increase for congested hosts)" 27//usage: "\n -T MS Minimum rtt (default 5 ms)"
28 28
29#include "libbb.h" 29#include "libbb.h"
30 30
@@ -139,7 +139,7 @@ int pscan_main(int argc UNUSED_PARAM, char **argv)
139 * We check rtt BEFORE we usleep, otherwise 139 * We check rtt BEFORE we usleep, otherwise
140 * on localhost we'll have no writes done (!) 140 * on localhost we'll have no writes done (!)
141 * before we exceed (rather small) rtt */ 141 * before we exceed (rather small) rtt */
142 usleep(rtt_4/8); 142 usleep(rtt_4 / 8);
143 open: 143 open:
144 diff = MONOTONIC_US() - start; 144 diff = MONOTONIC_US() - start;
145 DMSG("write to port %u @%u", port, diff - start); 145 DMSG("write to port %u @%u", port, diff - start);
diff --git a/networking/route.c b/networking/route.c
index 4d9aad6cc..ff5daa8a7 100644
--- a/networking/route.c
+++ b/networking/route.c
@@ -34,14 +34,6 @@
34 34
35//kbuild:lib-$(CONFIG_ROUTE) += route.o 35//kbuild:lib-$(CONFIG_ROUTE) += route.o
36 36
37//usage:#define route_trivial_usage
38//usage: "[{add|del|delete}]"
39//usage:#define route_full_usage "\n\n"
40//usage: "Edit kernel routing tables\n"
41//usage: "\n -n Don't resolve names"
42//usage: "\n -e Display other/more information"
43//usage: "\n -A inet" IF_FEATURE_IPV6("{6}") " Select address family"
44
45#include <net/route.h> 37#include <net/route.h>
46#include <net/if.h> 38#include <net/if.h>
47 39
@@ -83,17 +75,15 @@
83#define RTACTION_ADD 1 75#define RTACTION_ADD 1
84#define RTACTION_DEL 2 76#define RTACTION_DEL 2
85 77
86/* For the various tbl_*[] arrays, the 1st byte is the offset to 78/* For the various tbl_*[] arrays, the 1st byte is return value. */
87 * the next entry and the 2nd byte is return value. */
88 79
89#define NET_FLAG 1 80#define NET_FLAG 1
90#define HOST_FLAG 2 81#define HOST_FLAG 2
91 82
92/* We remap '-' to '#' to avoid problems with getopt. */ 83/* We remap '-' to '#' to avoid problems with getopt. */
93static const char tbl_hash_net_host[] ALIGN1 = 84static const char tbl_hash_net_host[] ALIGN1 =
94 "\007\001#net\0" 85 "\001#net\0"
95/* "\010\002#host\0" */ 86 "\002#host\0"
96 "\007\002#host" /* Since last, we can save a byte. */
97; 87;
98 88
99#define KW_TAKES_ARG 020 89#define KW_TAKES_ARG 020
@@ -116,29 +106,28 @@ static const char tbl_hash_net_host[] ALIGN1 =
116static const char tbl_ipvx[] ALIGN1 = 106static const char tbl_ipvx[] ALIGN1 =
117 /* 020 is the "takes an arg" bit */ 107 /* 020 is the "takes an arg" bit */
118#if HAVE_NEW_ADDRT 108#if HAVE_NEW_ADDRT
119 "\011\020metric\0" 109 "\020metric\0"
120#endif 110#endif
121 "\012\021netmask\0" 111 "\021netmask\0"
122 "\005\022gw\0" 112 "\022gw\0"
123 "\012\022gateway\0" 113 "\022gateway\0"
124 "\006\023mss\0" 114 "\023mss\0"
125 "\011\024window\0" 115 "\024window\0"
126#ifdef RTF_IRTT 116#ifdef RTF_IRTT
127 "\007\025irtt\0" 117 "\025irtt\0"
128#endif 118#endif
129 "\006\026dev\0" 119 "\026dev\0"
130 "\011\026device\0" 120 "\026device\0"
131 /* 040 is the "sets a flag" bit - MUST match flags_ipvx[] values below. */ 121 /* 040 is the "sets a flag" bit - MUST match flags_ipvx[] values below. */
132#ifdef RTF_REJECT 122#ifdef RTF_REJECT
133 "\011\040reject\0" 123 "\040reject\0"
134#endif 124#endif
135 "\006\041mod\0" 125 "\041mod\0"
136 "\006\042dyn\0" 126 "\042dyn\0"
137/* "\014\043reinstate\0" */ 127 "\043reinstate\0"
138 "\013\043reinstate" /* Since last, we can save a byte. */
139; 128;
140 129
141static const uint16_t flags_ipvx[] = { /* MUST match tbl_ipvx[] values above. */ 130static const uint16_t flags_ipvx[] ALIGN2 = { /* MUST match tbl_ipvx[] values above. */
142#ifdef RTF_REJECT 131#ifdef RTF_REJECT
143 RTF_REJECT, 132 RTF_REJECT,
144#endif 133#endif
@@ -151,17 +140,17 @@ static int kw_lookup(const char *kwtbl, char ***pargs)
151{ 140{
152 if (**pargs) { 141 if (**pargs) {
153 do { 142 do {
154 if (strcmp(kwtbl+2, **pargs) == 0) { /* Found a match. */ 143 if (strcmp(kwtbl + 1, **pargs) == 0) { /* Found a match. */
155 *pargs += 1; 144 *pargs += 1;
156 if (kwtbl[1] & KW_TAKES_ARG) { 145 if (kwtbl[0] & KW_TAKES_ARG) {
157 if (!**pargs) { /* No more args! */ 146 if (!**pargs) { /* No more args! */
158 bb_show_usage(); 147 bb_show_usage();
159 } 148 }
160 *pargs += 1; /* Calling routine will use args[-1]. */ 149 *pargs += 1; /* Calling routine will use args[-1]. */
161 } 150 }
162 return kwtbl[1]; 151 return kwtbl[0];
163 } 152 }
164 kwtbl += *kwtbl; 153 kwtbl += strlen(kwtbl) + 1;
165 } while (*kwtbl); 154 } while (*kwtbl);
166 } 155 }
167 return 0; 156 return 0;
@@ -208,7 +197,7 @@ static NOINLINE void INET_setroute(int action, char **args)
208 /* Default netmask. */ 197 /* Default netmask. */
209 netmask = "default"; 198 netmask = "default";
210 } 199 }
211 /* Prefer hostname lookup is -host flag (xflag==1) was given. */ 200 /* Prefer hostname lookup if -host flag (xflag==1) was given. */
212 isnet = INET_resolve(target, (struct sockaddr_in *) &rt->rt_dst, 201 isnet = INET_resolve(target, (struct sockaddr_in *) &rt->rt_dst,
213 (xflag & HOST_FLAG)); 202 (xflag & HOST_FLAG));
214 if (isnet < 0) { 203 if (isnet < 0) {
@@ -460,9 +449,9 @@ static NOINLINE void INET6_setroute(int action, char **args)
460#endif 449#endif
461 450
462static const 451static const
463IF_NOT_FEATURE_IPV6(uint16_t) 452IF_NOT_FEATURE_IPV6(uint16_t flagvals[] ALIGN2 = )
464IF_FEATURE_IPV6(unsigned) 453IF_FEATURE_IPV6(uint32_t flagvals[] ALIGN4 = )
465flagvals[] = { /* Must agree with flagchars[]. */ 454{ /* Must agree with flagchars[]. */
466 RTF_UP, 455 RTF_UP,
467 RTF_GATEWAY, 456 RTF_GATEWAY,
468 RTF_HOST, 457 RTF_HOST,
@@ -544,7 +533,6 @@ void FAST_FUNC bb_displayroutes(int noresolve, int netstatfmt)
544 flags[0] = '!'; 533 flags[0] = '!';
545 } 534 }
546#endif 535#endif
547
548 memset(&s_addr, 0, sizeof(struct sockaddr_in)); 536 memset(&s_addr, 0, sizeof(struct sockaddr_in));
549 s_addr.sin_family = AF_INET; 537 s_addr.sin_family = AF_INET;
550 s_addr.sin_addr.s_addr = d; 538 s_addr.sin_addr.s_addr = d;
@@ -634,7 +622,6 @@ static void INET6_displayroutes(void)
634 naddr6 = INET6_rresolve((struct sockaddr_in6 *) &snaddr6, 622 naddr6 = INET6_rresolve((struct sockaddr_in6 *) &snaddr6,
635 0x0fff /* Apparently, upstream never resolves. */ 623 0x0fff /* Apparently, upstream never resolves. */
636 ); 624 );
637
638 if (!r) { /* 1st pass */ 625 if (!r) { /* 1st pass */
639 snprintf(addr6, sizeof(addr6), "%s/%d", naddr6, prefix_len); 626 snprintf(addr6, sizeof(addr6), "%s/%d", naddr6, prefix_len);
640 r += 40; 627 r += 40;
@@ -653,18 +640,27 @@ static void INET6_displayroutes(void)
653 640
654#endif 641#endif
655 642
643//usage:#define route_trivial_usage
644///////: "[-ne]"IF_FEATURE_IPV6(" [-A inet[6]]")" [{add|del|delete} [-net|-host] TARGET [netmask MASK] [gw GATEWAY] [metric N] [mss BYTES] [window BYTES] [irtt MSEC] [reject] [mod] [dyn] [reinstate] [[dev] IFACE]]"
645///////too wordy
646//usage: "[-ne]"IF_FEATURE_IPV6(" [-A inet[6]]")" [{add|del} [-net|-host] TARGET [netmask MASK]\n"
647//usage: " [gw GATEWAY] [metric N] [mss BYTES] [window BYTES] [reject] [IFACE]]"
648//usage:#define route_full_usage "\n\n"
649//usage: "Show or edit kernel routing tables\n"
650//usage: "\n -n Don't resolve names"
651//usage: "\n -e Display other/more information"
652//usage: "\n -A inet" IF_FEATURE_IPV6("[6]") " Select address family"
653
656#define ROUTE_OPT_A 0x01 654#define ROUTE_OPT_A 0x01
657#define ROUTE_OPT_n 0x02 655#define ROUTE_OPT_n 0x02
658#define ROUTE_OPT_e 0x04 656#define ROUTE_OPT_e 0x04
659#define ROUTE_OPT_INET6 0x08 /* Not an actual option. See below. */ 657#define ROUTE_OPT_INET6 0x08 /* Not an actual option. See below. */
660 658
661/* 1st byte is offset to next entry offset. 2nd byte is return value. */ 659/* 1st byte is return value, matches RTACTION_* code */
662/* 2nd byte matches RTACTION_* code */
663static const char tbl_verb[] ALIGN1 = 660static const char tbl_verb[] ALIGN1 =
664 "\006\001add\0" 661 "\001add\0"
665 "\006\002del\0" 662 "\002del\0"
666/* "\011\002delete\0" */ 663 "\002delete\0"
667 "\010\002delete" /* Since it's last, we can save a byte. */
668; 664;
669 665
670int route_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 666int route_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
diff --git a/networking/slattach.c b/networking/slattach.c
index 51fbc1f49..6d2a252fc 100644
--- a/networking/slattach.c
+++ b/networking/slattach.c
@@ -76,7 +76,7 @@ static void restore_state_and_exit(int exitcode)
76 cfsetispeed(&state, B0); 76 cfsetispeed(&state, B0);
77 cfsetospeed(&state, B0); 77 cfsetospeed(&state, B0);
78 exitcode |= tcsetattr_serial_or_warn(&state); 78 exitcode |= tcsetattr_serial_or_warn(&state);
79 sleep(1); 79 sleep1();
80 80
81 /* Restore line status */ 81 /* Restore line status */
82 if (tcsetattr_serial_or_warn(&G.saved_state)) 82 if (tcsetattr_serial_or_warn(&G.saved_state))
diff --git a/networking/telnet.c b/networking/telnet.c
index 9fc85050b..7a0253525 100644
--- a/networking/telnet.c
+++ b/networking/telnet.c
@@ -368,12 +368,16 @@ static void put_iac2_msb_lsb(unsigned x_y)
368} 368}
369#define put_iac2_x_y(x,y) put_iac2_msb_lsb(((x)<<8) + (y)) 369#define put_iac2_x_y(x,y) put_iac2_msb_lsb(((x)<<8) + (y))
370 370
371#if ENABLE_FEATURE_TELNET_WIDTH \
372 || ENABLE_FEATURE_TELNET_TTYPE \
373 || ENABLE_FEATURE_TELNET_AUTOLOGIN
371static void put_iac4_msb_lsb(unsigned x_y_z_t) 374static void put_iac4_msb_lsb(unsigned x_y_z_t)
372{ 375{
373 put_iac2_msb_lsb(x_y_z_t >> 16); 376 put_iac2_msb_lsb(x_y_z_t >> 16);
374 put_iac2_msb_lsb(x_y_z_t); /* "... & 0xffff" is implicit */ 377 put_iac2_msb_lsb(x_y_z_t); /* "... & 0xffff" is implicit */
375} 378}
376#define put_iac4_x_y_z_t(x,y,z,t) put_iac4_msb_lsb(((x)<<24) + ((y)<<16) + ((z)<<8) + (t)) 379#define put_iac4_x_y_z_t(x,y,z,t) put_iac4_msb_lsb(((x)<<24) + ((y)<<16) + ((z)<<8) + (t))
380#endif
377 381
378static void put_iac3_IAC_x_y_merged(unsigned wwdd_and_c) 382static void put_iac3_IAC_x_y_merged(unsigned wwdd_and_c)
379{ 383{
@@ -673,7 +677,7 @@ int telnet_main(int argc UNUSED_PARAM, char **argv)
673 if (bb_got_signal) 677 if (bb_got_signal)
674 con_escape(); 678 con_escape();
675 else 679 else
676 sleep(1); 680 sleep1();
677 continue; 681 continue;
678 } 682 }
679 683
diff --git a/networking/tftp.c b/networking/tftp.c
index 60fdff232..4b86ed9de 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -104,7 +104,7 @@
104//usage: "\n -p Put file" 104//usage: "\n -p Put file"
105//usage: ) 105//usage: )
106//usage: IF_FEATURE_TFTP_BLOCKSIZE( 106//usage: IF_FEATURE_TFTP_BLOCKSIZE(
107//usage: "\n -b SIZE Transfer blocks of SIZE octets" 107//usage: "\n -b SIZE Transfer blocks in bytes"
108//usage: ) 108//usage: )
109///////: "\n -m STR Accepted and ignored ('-m binary' compat with tftp-hpa 5.2)" 109///////: "\n -m STR Accepted and ignored ('-m binary' compat with tftp-hpa 5.2)"
110//usage: 110//usage:
@@ -120,7 +120,7 @@
120//usage: " udpsvd -vE 0.0.0.0 69 tftpd /files/to/serve\n" 120//usage: " udpsvd -vE 0.0.0.0 69 tftpd /files/to/serve\n"
121//usage: "\n -r Prohibit upload" 121//usage: "\n -r Prohibit upload"
122//usage: "\n -c Allow file creation via upload" 122//usage: "\n -c Allow file creation via upload"
123//usage: "\n -u Access files as USER" 123//usage: "\n -u USER Access files as USER"
124//usage: "\n -l Log to syslog (inetd mode requires this)" 124//usage: "\n -l Log to syslog (inetd mode requires this)"
125 125
126#include "libbb.h" 126#include "libbb.h"
diff --git a/networking/tls.c b/networking/tls.c
index c00ef5db0..869456a6a 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -1959,7 +1959,7 @@ static void send_client_key_exchange(tls_state_t *tls)
1959 premaster_size = sizeof(rsa_premaster); 1959 premaster_size = sizeof(rsa_premaster);
1960 } else { 1960 } else {
1961 /* ECDHE */ 1961 /* ECDHE */
1962 static const uint8_t basepoint9[CURVE25519_KEYSIZE] = {9}; 1962 static const uint8_t basepoint9[CURVE25519_KEYSIZE] ALIGN1 = {9};
1963 uint8_t privkey[CURVE25519_KEYSIZE]; //[32] 1963 uint8_t privkey[CURVE25519_KEYSIZE]; //[32]
1964 1964
1965 if (!(tls->flags & GOT_EC_KEY)) 1965 if (!(tls->flags & GOT_EC_KEY))
diff --git a/networking/tls_aes.c b/networking/tls_aes.c
index 5400ad9b5..feb618fb7 100644
--- a/networking/tls_aes.c
+++ b/networking/tls_aes.c
@@ -313,15 +313,15 @@ static void InvMixColumns(unsigned astate[16])
313 d = astate[i + 3]; 313 d = astate[i + 3];
314 x = (a << 1) ^ (a << 2) ^ (a << 3) ^ b ^ (b << 1) ^ (b << 3) 314 x = (a << 1) ^ (a << 2) ^ (a << 3) ^ b ^ (b << 1) ^ (b << 3)
315 /***/ ^ c ^ (c << 2) ^ (c << 3) ^ d ^ (d << 3); 315 /***/ ^ c ^ (c << 2) ^ (c << 3) ^ d ^ (d << 3);
316 astate[i + 0] = Multiply(x);
316 y = a ^ (a << 3) ^ (b << 1) ^ (b << 2) ^ (b << 3) 317 y = a ^ (a << 3) ^ (b << 1) ^ (b << 2) ^ (b << 3)
317 /***/ ^ c ^ (c << 1) ^ (c << 3) ^ d ^ (d << 2) ^ (d << 3); 318 /***/ ^ c ^ (c << 1) ^ (c << 3) ^ d ^ (d << 2) ^ (d << 3);
319 astate[i + 1] = Multiply(y);
318 z = a ^ (a << 2) ^ (a << 3) ^ b ^ (b << 3) 320 z = a ^ (a << 2) ^ (a << 3) ^ b ^ (b << 3)
319 /***/ ^ (c << 1) ^ (c << 2) ^ (c << 3) ^ d ^ (d << 1) ^ (d << 3); 321 /***/ ^ (c << 1) ^ (c << 2) ^ (c << 3) ^ d ^ (d << 1) ^ (d << 3);
322 astate[i + 2] = Multiply(z);
320 t = a ^ (a << 1) ^ (a << 3) ^ b ^ (b << 2) ^ (b << 3) 323 t = a ^ (a << 1) ^ (a << 3) ^ b ^ (b << 2) ^ (b << 3)
321 /***/ ^ c ^ (c << 3) ^ (d << 1) ^ (d << 2) ^ (d << 3); 324 /***/ ^ c ^ (c << 3) ^ (d << 1) ^ (d << 2) ^ (d << 3);
322 astate[i + 0] = Multiply(x);
323 astate[i + 1] = Multiply(y);
324 astate[i + 2] = Multiply(z);
325 astate[i + 3] = Multiply(t); 325 astate[i + 3] = Multiply(t);
326 } 326 }
327} 327}
diff --git a/networking/tls_fe.c b/networking/tls_fe.c
index 10971bbff..f810e112a 100644
--- a/networking/tls_fe.c
+++ b/networking/tls_fe.c
@@ -383,12 +383,10 @@ static void fe_inv__distinct(byte *r, const byte *x)
383 * to avoid copying temporaries. 383 * to avoid copying temporaries.
384 */ 384 */
385 385
386 /* 1 1 */ 386 lm_copy(r, x);
387 fe_mul__distinct(s, x, x);
388 fe_mul__distinct(r, s, x);
389 387
390 /* 1 x 248 */ 388 /* 1, 1 x 249 */
391 for (i = 0; i < 248; i++) { 389 for (i = 0; i < 249; i++) {
392 fe_mul__distinct(s, r, r); 390 fe_mul__distinct(s, r, r);
393 fe_mul__distinct(r, s, x); 391 fe_mul__distinct(r, s, x);
394 } 392 }
@@ -403,13 +401,11 @@ static void fe_inv__distinct(byte *r, const byte *x)
403 /* 0 */ 401 /* 0 */
404 fe_mul__distinct(r, s, s); 402 fe_mul__distinct(r, s, s);
405 403
406 /* 1 */ 404 /* 1, 1 */
407 fe_mul__distinct(s, r, r); 405 for (i = 0; i < 2; i++) {
408 fe_mul__distinct(r, s, x); 406 fe_mul__distinct(s, r, r);
409 407 fe_mul__distinct(r, s, x);
410 /* 1 */ 408 }
411 fe_mul__distinct(s, r, r);
412 fe_mul__distinct(r, s, x);
413} 409}
414 410
415#if 0 //UNUSED 411#if 0 //UNUSED
@@ -435,12 +431,10 @@ static void exp2523(byte *r, const byte *x, byte *s)
435 * 111111... 01 431 * 111111... 01
436 */ 432 */
437 433
438 /* 1 1 */ 434 lm_copy(s, x);
439 fe_mul__distinct(r, x, x);
440 fe_mul__distinct(s, r, x);
441 435
442 /* 1 x 248 */ 436 /* 1, 1 x 249 */
443 for (i = 0; i < 248; i++) { 437 for (i = 0; i < 249; i++) {
444 fe_mul__distinct(r, s, s); 438 fe_mul__distinct(r, s, s);
445 fe_mul__distinct(s, r, x); 439 fe_mul__distinct(s, r, x);
446 } 440 }
diff --git a/networking/traceroute.c b/networking/traceroute.c
index 1c4dc3e4a..8f5cd0bf2 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -243,7 +243,7 @@
243//kbuild:lib-$(CONFIG_TRACEROUTE6) += traceroute.o 243//kbuild:lib-$(CONFIG_TRACEROUTE6) += traceroute.o
244 244
245//usage:#define traceroute_trivial_usage 245//usage:#define traceroute_trivial_usage
246//usage: "[-"IF_TRACEROUTE6("46")"FIlnrv] [-f 1ST_TTL] [-m MAXTTL] [-q PROBES] [-p PORT]\n" 246//usage: "[-"IF_TRACEROUTE6("46")IF_FEATURE_TRACEROUTE_USE_ICMP("I")"Flnrv] [-f 1ST_TTL] [-m MAXTTL] [-q PROBES] [-p PORT]\n"
247//usage: " [-t TOS] [-w WAIT_SEC] [-s SRC_IP] [-i IFACE]\n" 247//usage: " [-t TOS] [-w WAIT_SEC] [-s SRC_IP] [-i IFACE]\n"
248//usage: " [-z PAUSE_MSEC] HOST [BYTES]" 248//usage: " [-z PAUSE_MSEC] HOST [BYTES]"
249//usage:#define traceroute_full_usage "\n\n" 249//usage:#define traceroute_full_usage "\n\n"
@@ -271,15 +271,20 @@
271//usage: "\n -s IP Source address" 271//usage: "\n -s IP Source address"
272//usage: "\n -i IFACE Source interface" 272//usage: "\n -i IFACE Source interface"
273//usage: "\n -t N Type-of-service in probe packets (default 0)" 273//usage: "\n -t N Type-of-service in probe packets (default 0)"
274//usage: "\n -w SEC Time to wait for a response (default 3)" 274//usage: "\n -w SEC Wait for a response (default 3)"
275//usage: "\n -g IP Loose source route gateway (8 max)" 275//usage: "\n -z MSEC Wait before each send"
276//usage: 276//usage:
277//usage:#define traceroute6_trivial_usage 277//usage:#define traceroute6_trivial_usage
278//usage: "[-nrv] [-m MAXTTL] [-q PROBES] [-p PORT]\n" 278//usage: "[-"IF_FEATURE_TRACEROUTE_USE_ICMP("I")"nrv] [-f 1ST_TTL] [-m MAXTTL] [-q PROBES] [-p PORT]\n"
279//usage: " [-t TOS] [-w WAIT_SEC] [-s SRC_IP] [-i IFACE]\n" 279//usage: " [-t TOS] [-w WAIT_SEC] [-s SRC_IP] [-i IFACE]\n"
280//usage: " HOST [BYTES]" 280//usage: " [-z PAUSE_MSEC] HOST [BYTES]"
281//usage:#define traceroute6_full_usage "\n\n" 281//usage:#define traceroute6_full_usage "\n\n"
282//usage: "Trace the route to HOST\n" 282//usage: "Trace the route to HOST\n"
283////NOP? "\n -F Set don't fragment bit"
284//usage: IF_FEATURE_TRACEROUTE_USE_ICMP(
285//usage: "\n -I Use ICMP ECHO instead of UDP datagrams"
286//usage: )
287////NOP: "\n -l Display TTL value of the returned packet"
283//Currently disabled (TRACEROUTE_SO_DEBUG==0) 288//Currently disabled (TRACEROUTE_SO_DEBUG==0)
284////usage: "\n -d Set SO_DEBUG options to socket" 289////usage: "\n -d Set SO_DEBUG options to socket"
285//usage: "\n -n Print numeric addresses" 290//usage: "\n -n Print numeric addresses"
@@ -287,6 +292,7 @@
287//usage: IF_FEATURE_TRACEROUTE_VERBOSE( 292//usage: IF_FEATURE_TRACEROUTE_VERBOSE(
288//usage: "\n -v Verbose" 293//usage: "\n -v Verbose"
289//usage: ) 294//usage: )
295//usage: "\n -f N First number of hops (default 1)"
290//usage: "\n -m N Max number of hops" 296//usage: "\n -m N Max number of hops"
291//usage: "\n -q N Number of probes per hop (default 3)" 297//usage: "\n -q N Number of probes per hop (default 3)"
292//usage: "\n -p N Base UDP port number used in probes" 298//usage: "\n -p N Base UDP port number used in probes"
@@ -294,7 +300,8 @@
294//usage: "\n -s IP Source address" 300//usage: "\n -s IP Source address"
295//usage: "\n -i IFACE Source interface" 301//usage: "\n -i IFACE Source interface"
296//usage: "\n -t N Type-of-service in probe packets (default 0)" 302//usage: "\n -t N Type-of-service in probe packets (default 0)"
297//usage: "\n -w SEC Time wait for a response (default 3)" 303//usage: "\n -w SEC Wait for a response (default 3)"
304//usage: "\n -z MSEC Wait before each send"
298 305
299#define TRACEROUTE_SO_DEBUG 0 306#define TRACEROUTE_SO_DEBUG 0
300 307
@@ -324,7 +331,6 @@
324#ifndef IPPROTO_IP 331#ifndef IPPROTO_IP
325# define IPPROTO_IP 0 332# define IPPROTO_IP 0
326#endif 333#endif
327
328/* Some operating systems, like GNU/Hurd, don't define SOL_RAW, but do have 334/* Some operating systems, like GNU/Hurd, don't define SOL_RAW, but do have
329 * IPPROTO_RAW. Since the IPPROTO definitions are also valid to use for 335 * IPPROTO_RAW. Since the IPPROTO definitions are also valid to use for
330 * setsockopt (and take the same value as their corresponding SOL definitions, 336 * setsockopt (and take the same value as their corresponding SOL definitions,
@@ -335,7 +341,7 @@
335 341
336 342
337#define OPT_STRING \ 343#define OPT_STRING \
338 "FIlnrdvxt:i:m:p:q:s:w:z:f:" \ 344 "FIlnrdvt:i:m:p:q:s:w:z:f:" \
339 "4" IF_TRACEROUTE6("6") 345 "4" IF_TRACEROUTE6("6")
340enum { 346enum {
341 OPT_DONT_FRAGMNT = (1 << 0), /* F */ 347 OPT_DONT_FRAGMNT = (1 << 0), /* F */
@@ -345,20 +351,23 @@ enum {
345 OPT_BYPASS_ROUTE = (1 << 4), /* r */ 351 OPT_BYPASS_ROUTE = (1 << 4), /* r */
346 OPT_DEBUG = (1 << 5), /* d */ 352 OPT_DEBUG = (1 << 5), /* d */
347 OPT_VERBOSE = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE, /* v */ 353 OPT_VERBOSE = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE, /* v */
348 OPT_IP_CHKSUM = (1 << 7), /* x */ 354 OPT_TOS = (1 << 7), /* t */
349 OPT_TOS = (1 << 8), /* t */ 355 OPT_DEVICE = (1 << 8), /* i */
350 OPT_DEVICE = (1 << 9), /* i */ 356 OPT_MAX_TTL = (1 << 9), /* m */
351 OPT_MAX_TTL = (1 << 10), /* m */ 357 OPT_PORT = (1 << 10), /* p */
352 OPT_PORT = (1 << 11), /* p */ 358 OPT_NPROBES = (1 << 11), /* q */
353 OPT_NPROBES = (1 << 12), /* q */ 359 OPT_SOURCE = (1 << 12), /* s */
354 OPT_SOURCE = (1 << 13), /* s */ 360 OPT_WAITTIME = (1 << 13), /* w */
355 OPT_WAITTIME = (1 << 14), /* w */ 361 OPT_PAUSE_MS = (1 << 14), /* z */
356 OPT_PAUSE_MS = (1 << 15), /* z */ 362 OPT_FIRST_TTL = (1 << 15), /* f */
357 OPT_FIRST_TTL = (1 << 16), /* f */ 363 OPT_IPV4 = (1 << 16), /* 4 */
358 OPT_IPV4 = (1 << 17), /* 4 */ 364 OPT_IPV6 = (1 << 17) * ENABLE_TRACEROUTE6, /* 6 */
359 OPT_IPV6 = (1 << 18) * ENABLE_TRACEROUTE6, /* 6 */
360}; 365};
361#define verbose (option_mask32 & OPT_VERBOSE) 366#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
367# define verbose (option_mask32 & OPT_VERBOSE)
368#else
369# define verbose 0
370#endif
362 371
363enum { 372enum {
364 SIZEOF_ICMP_HDR = 8, 373 SIZEOF_ICMP_HDR = 8,
@@ -387,13 +396,26 @@ struct globals {
387 struct ip *outip; 396 struct ip *outip;
388 /* Pointer to ICMP or UDP payload (not header): */ 397 /* Pointer to ICMP or UDP payload (not header): */
389 struct outdata_t *outdata; 398 struct outdata_t *outdata;
390
391 len_and_sockaddr *dest_lsa; 399 len_and_sockaddr *dest_lsa;
400 len_and_sockaddr *from_lsa; /* response came from this address */
401#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
402 struct sockaddr *to; /* response came to this (local) address */
403#endif
404 uint32_t ident;
405 uint16_t port; /* start udp dest port # for probe packets */
406#if ENABLE_TRACEROUTE6
407 smallint ipv6;
408# define G_ipv6 G.ipv6
409#else
410# define G_ipv6 0
411#endif
392 int packlen; /* total length of packet */ 412 int packlen; /* total length of packet */
393 int pmtu; /* Path MTU Discovery (RFC1191) */ 413 int pmtu; /* Path MTU Discovery (RFC1191) */
394 uint32_t ident; 414 int waittime; /* time to wait for response (in seconds) */
395 uint16_t port; // 33434; /* start udp dest port # for probe packets */ 415 int first_ttl;
396 int waittime; // 5; /* time to wait for response (in seconds) */ 416 int nprobes;
417 int max_ttl;
418 unsigned pausemsecs;
397 unsigned char recv_pkt[512]; /* last inbound (icmp) packet */ 419 unsigned char recv_pkt[512]; /* last inbound (icmp) packet */
398}; 420};
399 421
@@ -407,19 +429,39 @@ struct globals {
407#define port (G.port ) 429#define port (G.port )
408#define waittime (G.waittime ) 430#define waittime (G.waittime )
409#define recv_pkt (G.recv_pkt ) 431#define recv_pkt (G.recv_pkt )
410#define gwlist (G.gwlist )
411#define INIT_G() do { \ 432#define INIT_G() do { \
412 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 433 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
413 port = 33434; \
414 waittime = 5; \
415} while (0) 434} while (0)
416 435
417#define outicmp ((struct icmp *)(outip + 1)) 436#define outudp ((struct udphdr *)(outip + 1))
418#define outudp ((struct udphdr *)(outip + 1)) 437#define outudp6 ((struct udphdr *)(((struct ip6_hdr*)outip) + 1))
419 438#define outicmp ((struct icmp *)(outip + 1))
439#define outicmp6 ((struct icmp *)(((struct ip6_hdr*)outip) + 1))
440/* NB: for icmp echo, IPv4 and IPv6 fields are the same size and offset:
441 * struct icmp:
442 * uint8_t icmp_type;
443 * uint8_t icmp_code;
444 * uint16_t icmp_cksum;
445 * uint16_t icmp_id;
446 * uint16_t icmp_seq;
447 * struct icmp6_hdr:
448 * uint8_t icmp6_type;
449 * uint8_t icmp6_code;
450 * uint16_t icmp6_cksum;
451 * uint16_t icmp6_id;
452 * uint16_t icmp6_seq;
453 * therefore both outicmp and outicmp6 are pointers to *IPv4* icmp struct.
454 * SIZEOF_ICMP_HDR == 8 is the same for both, as well.
455 * However, values of these pointers are not the same (since IPv6 IP header is larger),
456 * and icmp_type constants are not the same:
457 * #define ICMP_ECHO 8
458 * #define ICMP_ECHOREPLY 0
459 * #define ICMP6_ECHO_REQUEST 128
460 * #define ICMP6_ECHO_REPLY 129
461 */
420 462
421static int 463static int
422wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms) 464wait_for_reply(unsigned *timestamp_us, int *left_ms)
423{ 465{
424 struct pollfd pfd[1]; 466 struct pollfd pfd[1];
425 int read_len = 0; 467 int read_len = 0;
@@ -429,10 +471,19 @@ wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timest
429 if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) { 471 if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) {
430 unsigned t; 472 unsigned t;
431 473
474#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
432 read_len = recv_from_to(rcvsock, 475 read_len = recv_from_to(rcvsock,
433 recv_pkt, sizeof(recv_pkt), 476 recv_pkt, sizeof(recv_pkt),
434 /*flags:*/ MSG_DONTWAIT, 477 /*flags:*/ MSG_DONTWAIT,
435 &from_lsa->u.sa, to, from_lsa->len); 478 &G.from_lsa->u.sa, G.to, G.from_lsa->len);
479#else
480 read_len = recvfrom(rcvsock,
481 recv_pkt, sizeof(recv_pkt),
482 /*flags:*/ MSG_DONTWAIT,
483 &G.from_lsa->u.sa, &G.from_lsa->len);
484#endif
485 if (read_len < 0)
486 bb_simple_perror_msg_and_die("recv");
436 t = monotonic_us(); 487 t = monotonic_us();
437 *left_ms -= (t - *timestamp_us) / 1000; 488 *left_ms -= (t - *timestamp_us) / 1000;
438 *timestamp_us = t; 489 *timestamp_us = t;
@@ -446,14 +497,16 @@ send_probe(int seq, int ttl)
446{ 497{
447 int len, res; 498 int len, res;
448 void *out; 499 void *out;
500 struct icmp *icp;
449 501
450 /* Payload */ 502 /* Payload */
451#if ENABLE_TRACEROUTE6 503#if ENABLE_TRACEROUTE6
452 if (dest_lsa->u.sa.sa_family == AF_INET6) { 504 if (G_ipv6) {
453 struct outdata6_t *pkt = (struct outdata6_t *) outdata; 505 struct outdata6_t *pkt = (void *) outdata;
454 pkt->ident6 = htonl(ident); 506 pkt->ident6 = ident;
455 pkt->seq6 = htonl(seq); 507 pkt->seq6 = htonl(seq);
456 /*gettimeofday(&pkt->tv, &tz);*/ 508 /*xgettimeofday(&pkt->tv);*/
509 icp = outicmp6;
457 } else 510 } else
458#endif 511#endif
459 { 512 {
@@ -461,19 +514,23 @@ send_probe(int seq, int ttl)
461 outdata->ttl = ttl; 514 outdata->ttl = ttl;
462// UNUSED: was storing gettimeofday's result there, but never ever checked it 515// UNUSED: was storing gettimeofday's result there, but never ever checked it
463 /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ 516 /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/
464 517 icp = outicmp;
465 if (option_mask32 & OPT_USE_ICMP) { 518 }
466 outicmp->icmp_seq = htons(seq); 519 out = outdata;
467 520 if (option_mask32 & OPT_USE_ICMP) {
468 /* Always calculate checksum for icmp packets */ 521 out = icp;
469 outicmp->icmp_cksum = 0; 522 /*icp->icmp_type = ICMP[6]_ECHO; - already set */
470 outicmp->icmp_cksum = inet_cksum( 523 /*icp->icmp_code = 0; - already set */
471 outicmp, 524 /*icp->icmp_id = ident; - already set */
472 ((char*)outip + packlen) - (char*)outicmp 525 icp->icmp_seq = htons(seq);
473 ); 526 /* Always calculate checksum for icmp packets */
474 if (outicmp->icmp_cksum == 0) 527 icp->icmp_cksum = 0;
475 outicmp->icmp_cksum = 0xffff; 528 icp->icmp_cksum = inet_cksum(
476 } 529 icp,
530 ((char*)outip + packlen) - (char*)icp
531 );
532 if (icp->icmp_cksum == 0)
533 icp->icmp_cksum = 0xffff;
477 } 534 }
478 535
479//BUG! verbose is (x & OPT_VERBOSE), not a counter! 536//BUG! verbose is (x & OPT_VERBOSE), not a counter!
@@ -502,9 +559,8 @@ send_probe(int seq, int ttl)
502 } 559 }
503#endif 560#endif
504 561
505 out = outdata;
506#if ENABLE_TRACEROUTE6 562#if ENABLE_TRACEROUTE6
507 if (dest_lsa->u.sa.sa_family == AF_INET6) { 563 if (G_ipv6) {
508 res = setsockopt_int(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, ttl); 564 res = setsockopt_int(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, ttl);
509 if (res != 0) 565 if (res != 0)
510 bb_perror_msg_and_die("setsockopt(%s) %d", "UNICAST_HOPS", ttl); 566 bb_perror_msg_and_die("setsockopt(%s) %d", "UNICAST_HOPS", ttl);
@@ -516,8 +572,6 @@ send_probe(int seq, int ttl)
516 if (res != 0) 572 if (res != 0)
517 bb_perror_msg_and_die("setsockopt(%s) %d", "TTL", ttl); 573 bb_perror_msg_and_die("setsockopt(%s) %d", "TTL", ttl);
518#endif 574#endif
519 if (option_mask32 & OPT_USE_ICMP)
520 out = outicmp;
521 } 575 }
522 576
523 if (!(option_mask32 & OPT_USE_ICMP)) { 577 if (!(option_mask32 & OPT_USE_ICMP)) {
@@ -530,13 +584,11 @@ send_probe(int seq, int ttl)
530} 584}
531 585
532#if ENABLE_FEATURE_TRACEROUTE_VERBOSE 586#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
533/* 587/* Convert an ICMP "type" field to a printable string */
534 * Convert an ICMP "type" field to a printable string.
535 */
536static const char * 588static const char *
537pr_type(unsigned char t) 589pr_type(unsigned char t)
538{ 590{
539 static const char *const ttab[] = { 591 static const char *const ttab[] ALIGN_PTR = {
540 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", 592 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
541 "Source Quench", "Redirect", "ICMP 6", "ICMP 7", 593 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
542 "Echo", "Router Advert", "Router Solicit", "Time Exceeded", 594 "Echo", "Router Advert", "Router Solicit", "Time Exceeded",
@@ -544,7 +596,7 @@ pr_type(unsigned char t)
544 "Info Reply", "Mask Request", "Mask Reply" 596 "Info Reply", "Mask Request", "Mask Reply"
545 }; 597 };
546# if ENABLE_TRACEROUTE6 598# if ENABLE_TRACEROUTE6
547 static const char *const ttab6[] = { 599 static const char *const ttab6[] ALIGN_PTR = {
548[0] = "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded", 600[0] = "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded",
549[4] = "Param Problem", 601[4] = "Param Problem",
550[8] = "Echo Request", "Echo Reply", "Membership Query", "Membership Report", 602[8] = "Echo Request", "Echo Reply", "Membership Query", "Membership Report",
@@ -552,7 +604,7 @@ pr_type(unsigned char t)
552[16] = "Neighbor Advert", "Redirect", 604[16] = "Neighbor Advert", "Redirect",
553 }; 605 };
554 606
555 if (dest_lsa->u.sa.sa_family == AF_INET6) { 607 if (G_ipv6) {
556 if (t < 5) 608 if (t < 5)
557 return ttab6[t]; 609 return ttab6[t];
558 if (t < 128 || t > ND_REDIRECT) 610 if (t < 128 || t > ND_REDIRECT)
@@ -565,28 +617,54 @@ pr_type(unsigned char t)
565 617
566 return ttab[t]; 618 return ttab[t];
567} 619}
568#endif 620static int
621hexdump_if_verbose(const struct icmp *icp, int len)
622{
623 const unsigned char *p;
624 int i;
569 625
570#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE 626 if (!verbose)
571#define packet4_ok(read_len, from, seq) \ 627 return 0;
572 packet4_ok(read_len, seq) 628
629 printf("\n%d bytes from %s to %s: icmp type %u (%s) code %u\n",
630 len,
631 auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa)),
632 auto_string(xmalloc_sockaddr2dotted_noport(G.to)),
633 icp->icmp_type, pr_type(icp->icmp_type),
634 icp->icmp_code
635 );
636 p = (const void *)icp;
637 for (i = 0; i < len; i++) {
638 if (!(i & 0xf))
639 printf("\n%04x:" + (i==0), i);
640 printf(" %02x", p[i]);
641 }
642 bb_putchar('\n');
643 return 0;
644}
645#else
646# define hexdump_if_verbose(...) 0
573#endif 647#endif
648
574static int 649static int
575packet4_ok(int read_len, const struct sockaddr_in *from, int seq) 650packet4_ok(int read_len, int seq)
576{ 651{
577 const struct icmp *icp; 652 const struct icmp *icp;
578 unsigned char type, code; 653 unsigned char type, code;
579 int hlen; 654 int hlen;
580 const struct ip *ip; 655 const struct ip *ip;
581 656
657 /* NB: reads from (AF_INET, SOCK_RAW, IPPROTO_ICMP) socket
658 * return the entire IP packet (IOW: they do not strip IP header).
659 * This differs from (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) sockets!?
660 */
582 ip = (struct ip *) recv_pkt; 661 ip = (struct ip *) recv_pkt;
662
583 hlen = ip->ip_hl << 2; 663 hlen = ip->ip_hl << 2;
584 if (read_len < hlen + ICMP_MINLEN) { 664 if (read_len < hlen + ICMP_MINLEN) {
585#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
586 if (verbose) 665 if (verbose)
587 printf("packet too short (%d bytes) from %s\n", read_len, 666 printf("packet too short (%d bytes) from %s\n", read_len,
588 inet_ntoa(from->sin_addr)); 667 inet_ntoa(G.from_lsa->u.sin.sin_addr));
589#endif
590 return 0; 668 return 0;
591 } 669 }
592 read_len -= hlen; 670 read_len -= hlen;
@@ -598,9 +676,22 @@ packet4_ok(int read_len, const struct sockaddr_in *from, int seq)
598 if (code == ICMP_UNREACH_NEEDFRAG) 676 if (code == ICMP_UNREACH_NEEDFRAG)
599 pmtu = ntohs(icp->icmp_nextmtu); 677 pmtu = ntohs(icp->icmp_nextmtu);
600 678
679 if ((option_mask32 & OPT_USE_ICMP)
680 && type == ICMP_ECHOREPLY
681 && icp->icmp_seq == htons(seq)
682 ) {
683 if (icp->icmp_id != ident)
684 /* reply to another ping/traceroute from this box? */
685 return 0; /* ignore, silently */
686 /* In UDP mode, when we reach the machine, we (usually)
687 * would get "port unreachable" - in ICMP we got "echo reply".
688 * Simulate "port unreachable" for caller:
689 */
690 return ICMP_UNREACH_PORT+1;
691 }
692
601 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) 693 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS)
602 || type == ICMP_UNREACH 694 || type == ICMP_UNREACH
603 || type == ICMP_ECHOREPLY
604 ) { 695 ) {
605 const struct ip *hip; 696 const struct ip *hip;
606 const struct udphdr *up; 697 const struct udphdr *up;
@@ -610,18 +701,10 @@ packet4_ok(int read_len, const struct sockaddr_in *from, int seq)
610 if (option_mask32 & OPT_USE_ICMP) { 701 if (option_mask32 & OPT_USE_ICMP) {
611 struct icmp *hicmp; 702 struct icmp *hicmp;
612 703
613 /* XXX */
614 if (type == ICMP_ECHOREPLY
615 && icp->icmp_id == htons(ident)
616 && icp->icmp_seq == htons(seq)
617 ) {
618 return ICMP_UNREACH_PORT+1;
619 }
620
621 hicmp = (struct icmp *)((unsigned char *)hip + hlen); 704 hicmp = (struct icmp *)((unsigned char *)hip + hlen);
622 if (hlen + SIZEOF_ICMP_HDR <= read_len 705 if (hlen + SIZEOF_ICMP_HDR <= read_len
623 && hip->ip_p == IPPROTO_ICMP 706 && hip->ip_p == IPPROTO_ICMP
624 && hicmp->icmp_id == htons(ident) 707 && hicmp->icmp_id == ident
625 && hicmp->icmp_seq == htons(seq) 708 && hicmp->icmp_seq == htons(seq)
626 ) { 709 ) {
627 return (type == ICMP_TIMXCEED ? -1 : code + 1); 710 return (type == ICMP_TIMXCEED ? -1 : code + 1);
@@ -633,51 +716,54 @@ packet4_ok(int read_len, const struct sockaddr_in *from, int seq)
633// Off: since we do not form the entire IP packet, 716// Off: since we do not form the entire IP packet,
634// but defer it to kernel, we can't set source port, 717// but defer it to kernel, we can't set source port,
635// and thus can't check it here in the reply 718// and thus can't check it here in the reply
636 /* && up->source == htons(ident) */ 719 /* && up->uh_sport == ident */
637 && up->dest == htons(port + seq) 720 && up->uh_dport == htons(port + seq)
638 ) { 721 ) {
639 return (type == ICMP_TIMXCEED ? -1 : code + 1); 722 return (type == ICMP_TIMXCEED ? -1 : code + 1);
640 } 723 }
641 } 724 }
642 } 725 }
643#if ENABLE_FEATURE_TRACEROUTE_VERBOSE 726 /* testcase: traceroute -vI 127.0.0.1 (sees its own echo requests) */
644 if (verbose) { 727 return hexdump_if_verbose(icp, read_len);
645 int i;
646 uint32_t *lp = (uint32_t *)&icp->icmp_ip;
647
648 printf("\n%d bytes from %s to "
649 "%s: icmp type %d (%s) code %d\n",
650 read_len, inet_ntoa(from->sin_addr),
651 inet_ntoa(ip->ip_dst),
652 type, pr_type(type), icp->icmp_code);
653 for (i = 4; i < read_len; i += sizeof(*lp))
654 printf("%2d: x%8.8x\n", i, *lp++);
655 }
656#endif
657 return 0;
658} 728}
659 729
660#if ENABLE_TRACEROUTE6 730#if ENABLE_TRACEROUTE6
661# if !ENABLE_FEATURE_TRACEROUTE_VERBOSE 731
662#define packet_ok(read_len, from_lsa, to, seq) \
663 packet_ok(read_len, from_lsa, seq)
664# endif
665static int 732static int
666packet_ok(int read_len, len_and_sockaddr *from_lsa, 733packet6_ok(int read_len, int seq)
667 struct sockaddr *to,
668 int seq)
669{ 734{
670 const struct icmp6_hdr *icp; 735 const struct icmp6_hdr *icp;
671 unsigned char type, code; 736 unsigned char type, code;
672 737
673 if (from_lsa->u.sa.sa_family == AF_INET) 738 /* NB: reads from (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) socket
674 return packet4_ok(read_len, &from_lsa->u.sin, seq); 739 * return only ICMP packet (IOW: they strip IPv6 header).
675 740 * This differs from (AF_INET, SOCK_RAW, IPPROTO_ICMP) sockets!?
741 */
742 if (read_len < ICMP_MINLEN) {
743 if (verbose)
744 printf("packet too short (%d bytes) from %s\n", read_len,
745 auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa)));
746 return 0;
747 }
676 icp = (struct icmp6_hdr *) recv_pkt; 748 icp = (struct icmp6_hdr *) recv_pkt;
677 749
678 type = icp->icmp6_type; 750 type = icp->icmp6_type;
679 code = icp->icmp6_code; 751 code = icp->icmp6_code;
680 752
753 if ((option_mask32 & OPT_USE_ICMP)
754 && type == ICMP6_ECHO_REPLY
755 && icp->icmp6_seq == htons(seq)
756 ) {
757 if (icp->icmp6_id != ident)
758 /* reply to another ping/traceroute from this box? */
759 return 0; /* ignore, silently */
760 /* In UDP mode, when we reach the machine, we (usually)
761 * would get "port unreachable" - in ICMP we got "echo reply".
762 * Simulate "port unreachable" for caller:
763 */
764 return (ICMP6_DST_UNREACH_NOPORT << 8) + 1;
765 }
766
681 if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) 767 if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
682 || type == ICMP6_DST_UNREACH 768 || type == ICMP6_DST_UNREACH
683 ) { 769 ) {
@@ -698,106 +784,75 @@ packet_ok(int read_len, len_and_sockaddr *from_lsa,
698 784
699 pkt = (struct outdata6_t *) (up + 1); 785 pkt = (struct outdata6_t *) (up + 1);
700 786
701 if (ntohl(pkt->ident6) == ident 787 if (pkt->ident6 == ident
702 && ntohl(pkt->seq6) == seq 788 && ntohl(pkt->seq6) == seq
703 ) { 789 ) {
704 return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1); 790 return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1);
705 } 791 }
706 } 792 }
707 } 793 }
708 794 /* cast is safe since the beginning of icmp4 and icmp6 layouts match */
709# if ENABLE_FEATURE_TRACEROUTE_VERBOSE 795 return hexdump_if_verbose((const struct icmp *)icp, read_len);
710 if (verbose) {
711# ifndef MAXHOSTNAMELEN
712# define MAXHOSTNAMELEN 80
713# endif
714 unsigned char *p;
715 char pa1[MAXHOSTNAMELEN];
716 char pa2[MAXHOSTNAMELEN];
717 int i;
718
719 p = (unsigned char *) (icp + 1);
720
721 printf("\n%d bytes from %s to "
722 "%s: icmp type %d (%s) code %d\n",
723 read_len,
724 inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)),
725 inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)),
726 type, pr_type(type), icp->icmp6_code);
727
728 read_len -= sizeof(struct icmp6_hdr);
729 for (i = 0; i < read_len; i++) {
730 if (i % 16 == 0)
731 printf("%04x:", i);
732 if (i % 4 == 0)
733 bb_putchar(' ');
734 printf("%02x", p[i]);
735 if ((i % 16 == 15) && (i + 1 < read_len))
736 bb_putchar('\n');
737 }
738 bb_putchar('\n');
739 }
740# endif
741
742 return 0;
743} 796}
744#else /* !ENABLE_TRACEROUTE6 */ 797
745static ALWAYS_INLINE int 798static int
746packet_ok(int read_len, 799packet_ok(int read_len, int seq)
747 len_and_sockaddr *from_lsa IF_NOT_FEATURE_TRACEROUTE_VERBOSE(UNUSED_PARAM),
748 struct sockaddr *to UNUSED_PARAM,
749 int seq)
750{ 800{
751 return packet4_ok(read_len, &from_lsa->u.sin, seq); 801 if (!G_ipv6)
802 return packet4_ok(read_len, seq);
803 return packet6_ok(read_len, seq);
752} 804}
805
806#else /* !ENABLE_TRACEROUTE6 */
807
808# define packet_ok(read_len, seq) packet4_ok(read_len, seq)
809
753#endif 810#endif
754 811
755/*
756 * Construct an Internet address representation.
757 * If the -n flag has been supplied, give
758 * numeric value, otherwise try for symbolic name.
759 */
760static void 812static void
761print_inetname(const struct sockaddr *from) 813#if !ENABLE_FEATURE_TRACEROUTE_VERBOSE
814print(void)
815# define print(len) print()
816#else
817print(int read_len)
818#endif
762{ 819{
763 char *ina = xmalloc_sockaddr2dotted_noport(from); 820 char *ina = auto_string(xmalloc_sockaddr2dotted_noport(&G.from_lsa->u.sa));
764 821
765 if (option_mask32 & OPT_ADDR_NUM) { 822 if (option_mask32 & OPT_ADDR_NUM) {
766 printf(" %s", ina); 823 printf(" %s", ina);
767 } else { 824 } else {
768 char *n = NULL; 825 char *n = NULL;
769 826 if (G_ipv6
770 if (from->sa_family != AF_INET 827 || G.from_lsa->u.sin.sin_addr.s_addr != INADDR_ANY
771 || ((struct sockaddr_in*)from)->sin_addr.s_addr != INADDR_ANY
772 ) { 828 ) {
773 /* Try to reverse resolve if it is not 0.0.0.0 */ 829 /* Reverse resolve if IPV6 or not 0.0.0.0 */
774 n = xmalloc_sockaddr2host_noport((struct sockaddr*)from); 830 n = auto_string(xmalloc_sockaddr2host_noport(&G.from_lsa->u.sa));
775 } 831 }
776 printf(" %s (%s)", (n ? n : ina), ina); 832 printf(" %s (%s)", (n ? n : ina), ina);
777 free(n);
778 } 833 }
779 free(ina);
780}
781
782static void
783print(int read_len, const struct sockaddr *from, const struct sockaddr *to)
784{
785 print_inetname(from);
786 834
835#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
787 if (verbose) { 836 if (verbose) {
788 char *ina = xmalloc_sockaddr2dotted_noport(to); 837# if ENABLE_TRACEROUTE6
789#if ENABLE_TRACEROUTE6 838 /* NB: reads from (AF_INET, SOCK_RAW, IPPROTO_ICMP) socket
790 if (to->sa_family == AF_INET6) { 839 * return the entire IP packet (IOW: they do not strip IP header).
791 read_len -= sizeof(struct ip6_hdr); 840 * Reads from (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) do strip IPv6
841 * header and return only ICMP6 packet. Weird.
842 */
843 if (G_ipv6) {
844 /* read_len -= sizeof(struct ip6_hdr); - WRONG! */
792 } else 845 } else
793#endif 846# endif
794 { 847 {
795 struct ip *ip4packet = (struct ip*)recv_pkt; 848 struct ip *ip4packet = (struct ip*)recv_pkt;
796 read_len -= ip4packet->ip_hl << 2; 849 read_len -= ip4packet->ip_hl << 2;
797 } 850 }
798 printf(" %d bytes to %s", read_len, ina); 851 printf(" %d bytes to %s", read_len,
799 free(ina); 852 auto_string(xmalloc_sockaddr2dotted_noport(G.to))
853 );
800 } 854 }
855#endif
801} 856}
802 857
803static void 858static void
@@ -807,22 +862,12 @@ print_delta_ms(unsigned t1p, unsigned t2p)
807 printf(" %u.%03u ms", tt / 1000, tt % 1000); 862 printf(" %u.%03u ms", tt / 1000, tt % 1000);
808} 863}
809 864
810/* 865/* Keeping init code in a separate (not inlined!) function
811 * Usage: [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl] 866 * for stack use reduction and better register allocation in main loop.
812 * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]
813 * [-w waittime] [-z pausemsecs] host [packetlen]"
814 */ 867 */
815static int 868static NOINLINE void
816common_traceroute_main(int op, char **argv) 869traceroute_init(int op, char **argv)
817{ 870{
818 int minpacket;
819#ifdef IP_TOS
820 int tos = 0;
821#endif
822 int max_ttl = 30;
823 int nprobes = 3;
824 int first_ttl = 1;
825 unsigned pausemsecs = 0;
826 char *source; 871 char *source;
827 char *device; 872 char *device;
828 char *tos_str; 873 char *tos_str;
@@ -838,13 +883,16 @@ common_traceroute_main(int op, char **argv)
838#else 883#else
839 enum { af = AF_INET }; 884 enum { af = AF_INET };
840#endif 885#endif
841 int ttl; 886
842 int seq; 887 /* Ensure the socket fds won't be 0, 1 or 2 */
843 len_and_sockaddr *from_lsa; 888 bb_sanitize_stdio();
844 struct sockaddr *lastaddr;
845 struct sockaddr *to;
846 889
847 INIT_G(); 890 INIT_G();
891 port = 33434;
892 waittime = 5;
893 G.first_ttl = 1;
894 G.nprobes = 3;
895 G.max_ttl = 30;
848 896
849 op |= getopt32(argv, "^" 897 op |= getopt32(argv, "^"
850 OPT_STRING 898 OPT_STRING
@@ -854,43 +902,29 @@ common_traceroute_main(int op, char **argv)
854 ); 902 );
855 argv += optind; 903 argv += optind;
856 904
857#if 0 /* IGNORED */
858 if (op & OPT_IP_CHKSUM)
859 bb_error_msg("warning: ip checksums disabled");
860#endif
861#ifdef IP_TOS
862 if (op & OPT_TOS)
863 tos = xatou_range(tos_str, 0, 255);
864#endif
865 if (op & OPT_MAX_TTL) 905 if (op & OPT_MAX_TTL)
866 max_ttl = xatou_range(max_ttl_str, 1, 255); 906 G.max_ttl = xatou_range(max_ttl_str, 1, 255);
867 if (op & OPT_PORT) 907 if (op & OPT_PORT)
868 port = xatou16(port_str); 908 port = xatou16(port_str);
869 if (op & OPT_NPROBES) 909 if (op & OPT_NPROBES)
870 nprobes = xatou_range(nprobes_str, 1, INT_MAX); 910 G.nprobes = xatou_range(nprobes_str, 1, INT_MAX);
871 if (op & OPT_SOURCE) {
872 /*
873 * set the ip source address of the outbound
874 * probe (e.g., on a multi-homed host).
875 */
876 if (getuid() != 0)
877 bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
878 }
879 if (op & OPT_WAITTIME) 911 if (op & OPT_WAITTIME)
880 waittime = xatou_range(waittime_str, 1, 24 * 60 * 60); 912 waittime = xatou_range(waittime_str, 1, 24 * 60 * 60);
881 if (op & OPT_PAUSE_MS) 913 if (op & OPT_PAUSE_MS)
882 pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000); 914 G.pausemsecs = xatou_range(pausemsecs_str, 0, 60 * 60 * 1000);
883 if (op & OPT_FIRST_TTL) 915 if (op & OPT_FIRST_TTL)
884 first_ttl = xatou_range(first_ttl_str, 1, max_ttl); 916 G.first_ttl = xatou_range(first_ttl_str, 1, G.max_ttl);
885 917
886 /* Process destination and optional packet size */ 918 /* Process destination and optional packet size */
887 minpacket = sizeof(struct ip) 919 packlen = sizeof(struct ip)
888 + SIZEOF_ICMP_HDR
889 + sizeof(struct outdata_t);
890 if (!(op & OPT_USE_ICMP))
891 minpacket = sizeof(struct ip)
892 + sizeof(struct udphdr) 920 + sizeof(struct udphdr)
893 + sizeof(struct outdata_t); 921 + sizeof(struct outdata_t);
922 if (op & OPT_USE_ICMP) {
923 packlen = sizeof(struct ip)
924 + SIZEOF_ICMP_HDR
925 + sizeof(struct outdata_t);
926 port = 0; /* on ICMP6 sockets, sendto(ipv6.nonzero_port) throws EINVAL! */
927 }
894#if ENABLE_TRACEROUTE6 928#if ENABLE_TRACEROUTE6
895 af = AF_UNSPEC; 929 af = AF_UNSPEC;
896 if (op & OPT_IPV4) 930 if (op & OPT_IPV4)
@@ -899,49 +933,73 @@ common_traceroute_main(int op, char **argv)
899 af = AF_INET6; 933 af = AF_INET6;
900 dest_lsa = xhost_and_af2sockaddr(argv[0], port, af); 934 dest_lsa = xhost_and_af2sockaddr(argv[0], port, af);
901 af = dest_lsa->u.sa.sa_family; 935 af = dest_lsa->u.sa.sa_family;
902 if (af == AF_INET6) 936//TODO: make sure af == AF_INET[6]? (FEATURE_UNIX_LOCAL=y allows "local:/PATH" to be translated to AF_UNIX)
903 minpacket = sizeof(struct ip6_hdr) 937 if (af == AF_INET6) {
904 + sizeof(struct udphdr) 938 G_ipv6 = 1;
905 + sizeof(struct outdata6_t); 939 packlen = sizeof(struct ip6_hdr)
940 + sizeof(struct udphdr)
941 + sizeof(struct outdata6_t);
942 if (op & OPT_USE_ICMP)
943 packlen = sizeof(struct ip6_hdr)
944 + SIZEOF_ICMP_HDR
945 + sizeof(struct outdata6_t);
946 }
906#else 947#else
907 dest_lsa = xhost2sockaddr(argv[0], port); 948 /* accept only IPv4 addresses */
949 dest_lsa = xhost_and_af2sockaddr(argv[0], port, AF_INET);
950#endif
951 G.from_lsa = xmemdup(dest_lsa, LSA_LEN_SIZE + dest_lsa->len);
952#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
953 G.to = xzalloc(dest_lsa->len);
908#endif 954#endif
909 packlen = minpacket;
910 if (argv[1]) 955 if (argv[1])
911 packlen = xatoul_range(argv[1], minpacket, 32 * 1024); 956 packlen = xatoul_range(argv[1], packlen, 32 * 1024);
912
913 /* Ensure the socket fds won't be 0, 1 or 2 */
914 bb_sanitize_stdio();
915 957
958 if (af == AF_INET) {
959 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
960#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
961 /* want recvmsg to report target local address (for -v) */
962 setsockopt_1(rcvsock, IPPROTO_IP, IP_PKTINFO);
963#endif
964 }
916#if ENABLE_TRACEROUTE6 965#if ENABLE_TRACEROUTE6
917 if (af == AF_INET6) { 966 else {
918 xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock); 967 xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
968# if ENABLE_FEATURE_TRACEROUTE_VERBOSE
969 /* want recvmsg to report target local address (for -v) */
919 setsockopt_1(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO); 970 setsockopt_1(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO);
920 } else 971# endif
921#endif
922 {
923 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock);
924 } 972 }
925 973#endif
926#if TRACEROUTE_SO_DEBUG 974#if TRACEROUTE_SO_DEBUG
927 if (op & OPT_DEBUG) 975 if (op & OPT_DEBUG)
928 setsockopt_SOL_SOCKET_1(rcvsock, SO_DEBUG); 976 setsockopt_SOL_SOCKET_1(rcvsock, SO_DEBUG);
929#endif 977#endif
930 if (op & OPT_BYPASS_ROUTE)
931 setsockopt_SOL_SOCKET_1(rcvsock, SO_DONTROUTE);
932 978
979 {
980 int snd;
981 if (af == AF_INET) {
982 if (op & OPT_USE_ICMP)
983 snd = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
984 else
985 snd = xsocket(AF_INET, SOCK_DGRAM, 0);
986 }
933#if ENABLE_TRACEROUTE6 987#if ENABLE_TRACEROUTE6
934 if (af == AF_INET6) { 988# if defined(__FreeBSD__)
935 if (setsockopt_int(rcvsock, SOL_RAW, IPV6_CHECKSUM, 2) != 0) 989# define SOL_V6_OPTION SOL_IPV6
936 bb_perror_msg_and_die("setsockopt(%s)", "IPV6_CHECKSUM"); 990# else
937 xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock); 991# define SOL_V6_OPTION SOL_RAW
938 } else 992# endif
993 else {
994 if (setsockopt_int(rcvsock, SOL_V6_OPTION, IPV6_CHECKSUM, 2) != 0)
995 bb_perror_msg_and_die("setsockopt(%s)", "IPV6_CHECKSUM");
996 if (op & OPT_USE_ICMP)
997 snd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
998 else
999 snd = xsocket(AF_INET6, SOCK_DGRAM, 0);
1000 }
939#endif 1001#endif
940 { 1002 xmove_fd(snd, sndsock);
941 if (op & OPT_USE_ICMP)
942 xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock);
943 else
944 xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock);
945 } 1003 }
946 1004
947#ifdef SO_SNDBUF 1005#ifdef SO_SNDBUF
@@ -950,8 +1008,10 @@ common_traceroute_main(int op, char **argv)
950 } 1008 }
951#endif 1009#endif
952#ifdef IP_TOS 1010#ifdef IP_TOS
953 if ((op & OPT_TOS) && setsockopt_int(sndsock, IPPROTO_IP, IP_TOS, tos) != 0) { 1011 if (op & OPT_TOS) {
954 bb_perror_msg_and_die("setsockopt(%s) %d", "TOS", tos); 1012 int tos = xatou_range(tos_str, 0, 255);
1013 if (setsockopt_int(sndsock, IPPROTO_IP, IP_TOS, tos) != 0)
1014 bb_perror_msg_and_die("setsockopt(%s,%d)", "TOS", tos);
955 } 1015 }
956#endif 1016#endif
957#ifdef IP_DONTFRAG 1017#ifdef IP_DONTFRAG
@@ -968,23 +1028,30 @@ common_traceroute_main(int op, char **argv)
968 outip = xzalloc(packlen); 1028 outip = xzalloc(packlen);
969 1029
970 ident = getpid(); 1030 ident = getpid();
971 1031 /* we can use native-endian ident, but other Unix ping/traceroute
972 if (!ENABLE_TRACEROUTE6 || af == AF_INET) { 1032 * utils use *big-endian pid*, and e.g. ping on our machine may be
1033 * *not* from busybox, idents may collide. Follow the convention:
1034 */
1035 ident = htons(ident);
1036
1037 outdata = (void*)(outudp + 1);
1038 if (af == AF_INET) {
973 if (op & OPT_USE_ICMP) { 1039 if (op & OPT_USE_ICMP) {
974 ident |= 0x8000;
975 outicmp->icmp_type = ICMP_ECHO; 1040 outicmp->icmp_type = ICMP_ECHO;
976 outicmp->icmp_id = htons(ident); 1041 /*outicmp->icmp_code = 0; - set by xzalloc */
977 outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR); 1042 outicmp->icmp_id = ident;
978 } else { 1043 outdata = (void*)((char *)outicmp + SIZEOF_ICMP_HDR);
979 outdata = (struct outdata_t *)(outudp + 1);
980 } 1044 }
981 } 1045 }
982#if ENABLE_TRACEROUTE6 1046#if ENABLE_TRACEROUTE6
983 if (af == AF_INET6) { 1047 else {
984 outdata = (void*)((char*)outip 1048 outdata = (void*)(outudp6 + 1);
985 + sizeof(struct ip6_hdr) 1049 if (op & OPT_USE_ICMP) {
986 + sizeof(struct udphdr) 1050 outicmp6->icmp_type = ICMP6_ECHO_REQUEST;
987 ); 1051 /*outicmp->icmp_code = 0; - set by xzalloc */
1052 outicmp6->icmp_id = ident;
1053 outdata = (void*)((char *)outicmp6 + SIZEOF_ICMP_HDR);
1054 }
988 } 1055 }
989#endif 1056#endif
990 1057
@@ -998,6 +1065,8 @@ common_traceroute_main(int op, char **argv)
998#else 1065#else
999 len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0); 1066 len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0);
1000#endif 1067#endif
1068 if (getuid() != 0)
1069 bb_simple_error_msg_and_die(bb_msg_you_must_be_root);
1001 /* Ping4 does this (why?) */ 1070 /* Ping4 does this (why?) */
1002 if (af == AF_INET) 1071 if (af == AF_INET)
1003 if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF, 1072 if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF,
@@ -1006,36 +1075,24 @@ common_traceroute_main(int op, char **argv)
1006//TODO: we can query source port we bound to, 1075//TODO: we can query source port we bound to,
1007// and check it in replies... if we care enough 1076// and check it in replies... if we care enough
1008 xbind(sndsock, &source_lsa->u.sa, source_lsa->len); 1077 xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1009 free(source_lsa); 1078 if (ENABLE_FEATURE_CLEAN_UP)
1010 } 1079 free(source_lsa);
1011#if ENABLE_TRACEROUTE6 1080 } else {
1012 else if (af == AF_INET6) {
1013//TODO: why we don't do it for IPv4?
1014 len_and_sockaddr *source_lsa; 1081 len_and_sockaddr *source_lsa;
1015 1082
1016 int probe_fd = xsocket(af, SOCK_DGRAM, 0);
1017 if (op & OPT_DEVICE)
1018 setsockopt_bindtodevice(probe_fd, device);
1019 set_nport(&dest_lsa->u.sa, htons(1025));
1020 /* dummy connect. makes kernel pick source IP (and port) */
1021 xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len);
1022 set_nport(&dest_lsa->u.sa, htons(port)); 1083 set_nport(&dest_lsa->u.sa, htons(port));
1023 1084 /* Connect makes kernel pick source IP (and port if UDP) */
1024 /* read IP and port */ 1085 xconnect(sndsock, &dest_lsa->u.sa, dest_lsa->len);
1025 source_lsa = get_sock_lsa(probe_fd); 1086 /* Read IP and port */
1087 source_lsa = get_sock_lsa(sndsock);
1026 if (source_lsa == NULL) 1088 if (source_lsa == NULL)
1027 bb_simple_error_msg_and_die("can't get probe addr"); 1089 bb_simple_perror_msg_and_die("getsockname");
1028 1090 /* bind our recv ICMP socket to this IP (but not port, ICMP has no ports) */
1029 close(probe_fd); 1091 //set_nport(&source_lsa->u.sa, 0); - paranoia, seems to work without this for both ipv4 and ipv6
1030
1031 /* bind our sockets to this IP (but not port) */
1032 set_nport(&source_lsa->u.sa, 0);
1033 xbind(sndsock, &source_lsa->u.sa, source_lsa->len);
1034 xbind(rcvsock, &source_lsa->u.sa, source_lsa->len); 1092 xbind(rcvsock, &source_lsa->u.sa, source_lsa->len);
1035 1093 if (ENABLE_FEATURE_CLEAN_UP)
1036 free(source_lsa); 1094 free(source_lsa);
1037 } 1095 }
1038#endif
1039 1096
1040 /* Revert to non-privileged user after opening sockets */ 1097 /* Revert to non-privileged user after opening sockets */
1041 xsetgid(getgid()); 1098 xsetgid(getgid());
@@ -1043,169 +1100,177 @@ common_traceroute_main(int op, char **argv)
1043 1100
1044 dest_str = xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa); 1101 dest_str = xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa);
1045 printf("traceroute to %s (%s)", argv[0], dest_str); 1102 printf("traceroute to %s (%s)", argv[0], dest_str);
1046 if (ENABLE_FEATURE_CLEAN_UP) { 1103 if (ENABLE_FEATURE_CLEAN_UP)
1047 free(dest_str); 1104 free(dest_str);
1048 }
1049 1105
1050 if (op & OPT_SOURCE) 1106 if (op & OPT_SOURCE)
1051 printf(" from %s", source); 1107 printf(" from %s", source);
1052 printf(", %d hops max, %d byte packets\n", max_ttl, packlen); 1108 printf(", %d hops max, %d byte packets\n", G.max_ttl, packlen);
1109}
1110
1111static int
1112common_traceroute_main(int op, char **argv)
1113{
1114 int ttl;
1115 int seq;
1116 struct sockaddr *lastaddr;
1117
1118 traceroute_init(op, argv);
1053 1119
1054 from_lsa = xmemdup(dest_lsa, LSA_LEN_SIZE + dest_lsa->len);
1055 lastaddr = xzalloc(dest_lsa->len); 1120 lastaddr = xzalloc(dest_lsa->len);
1056 to = xzalloc(dest_lsa->len);
1057 seq = 0; 1121 seq = 0;
1058 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { 1122 for (ttl = G.first_ttl; ttl <= G.max_ttl; ++ttl) {
1059 int probe; 1123 int probe;
1060 int unreachable = 0; /* counter */ 1124 int unreachable = 0; /* counter */
1061 int gotlastaddr = 0; /* flags */
1062 int got_there = 0; 1125 int got_there = 0;
1063 1126
1064 printf("%2d", ttl); 1127 printf("%2d", ttl);
1065 for (probe = 0; probe < nprobes; ++probe) { 1128 for (probe = 0; probe < G.nprobes; ++probe) {
1066 int read_len;
1067 unsigned t1; 1129 unsigned t1;
1068 unsigned t2; 1130 unsigned t2;
1069 int left_ms; 1131 int left_ms;
1070 struct ip *ip; 1132 int read_len;
1133 int icmp_code;
1071 1134
1072 fflush_all(); 1135 fflush_all();
1073 if (probe != 0 && pausemsecs > 0) 1136 if (probe != 0)
1074 usleep(pausemsecs * 1000); 1137 msleep(G.pausemsecs);
1075 1138
1076 send_probe(++seq, ttl); 1139 send_probe(++seq, ttl);
1077 t2 = t1 = monotonic_us();
1078 1140
1141 t2 = t1 = monotonic_us();
1079 left_ms = waittime * 1000; 1142 left_ms = waittime * 1000;
1080 while ((read_len = wait_for_reply(from_lsa, to, &t2, &left_ms)) != 0) { 1143 for (;;) {
1081 int icmp_code; 1144 /* NB: wait_for_reply() fills "G.from_lsa" and "G.to" with
1082 1145 * "where it came from" and "what local address it arrived to"
1083 /* Recv'ed a packet, or read error */ 1146 * addresses. Sets t2 = monotonic_us(), updates left_ms.
1084 /* t2 = monotonic_us() - set by wait_for_reply */ 1147 */
1085 1148 read_len = wait_for_reply(&t2, &left_ms);
1086 if (read_len < 0) 1149
1087 continue; 1150 if (read_len == 0) { /* there was no packet at all? */
1088 icmp_code = packet_ok(read_len, from_lsa, to, seq); 1151 printf(" *");
1089 /* Skip short packet */ 1152 goto next_probe;
1090 if (icmp_code == 0)
1091 continue;
1092
1093 if (!gotlastaddr
1094 || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0)
1095 ) {
1096 print(read_len, &from_lsa->u.sa, to);
1097 memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len);
1098 gotlastaddr = 1;
1099 } 1153 }
1154 icmp_code = packet_ok(read_len, seq);
1155 if (icmp_code != 0)
1156 break; /* got a good response */
1157 /* unrecognized type/code or too short, back to recv */
1158 }
1100 1159
1101 print_delta_ms(t1, t2); 1160 if (probe == 0
1102 ip = (struct ip *)recv_pkt; 1161 || (memcmp(lastaddr, &G.from_lsa->u.sa, G.from_lsa->len) != 0)
1162 ) {
1163 print(read_len);
1164 memcpy(lastaddr, &G.from_lsa->u.sa, G.from_lsa->len);
1165 }
1166 print_delta_ms(t1, t2);
1167 if (!G_ipv6) {
1168 if (op & OPT_TTL_FLAG) {
1169 struct ip *ip = (struct ip *)recv_pkt;
1170 printf(" (%d)", ip->ip_ttl);
1171 }
1172 }
1103 1173
1104 if (from_lsa->u.sa.sa_family == AF_INET) 1174 /* Got a "time exceeded in transit" icmp message? */
1105 if (op & OPT_TTL_FLAG) 1175 if (icmp_code == -1)
1106 printf(" (%d)", ip->ip_ttl); 1176 continue;
1107 1177
1108 /* time exceeded in transit */ 1178 icmp_code--;
1109 if (icmp_code == -1) 1179 switch (icmp_code) {
1110 break;
1111 icmp_code--;
1112 switch (icmp_code) {
1113#if ENABLE_TRACEROUTE6 1180#if ENABLE_TRACEROUTE6
1114 case ICMP6_DST_UNREACH_NOPORT << 8: 1181 case ICMP6_DST_UNREACH_NOPORT << 8:
1115 got_there = 1; 1182 got_there = 1;
1116 break; 1183 break;
1117#endif 1184#endif
1118 case ICMP_UNREACH_PORT: 1185 case ICMP_UNREACH_PORT: {
1119 if (ip->ip_ttl <= 1) 1186 struct ip *ip = (struct ip *)recv_pkt;
1120 printf(" !"); 1187 if (ip->ip_ttl <= 1)
1121 got_there = 1; 1188 printf(" !");
1122 break; 1189 got_there = 1;
1123 1190 break;
1124 case ICMP_UNREACH_NET: 1191 }
1192 case ICMP_UNREACH_NET:
1125#if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET) 1193#if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET)
1126 case ICMP6_DST_UNREACH_NOROUTE << 8: 1194 case ICMP6_DST_UNREACH_NOROUTE << 8:
1127#endif 1195#endif
1128 printf(" !N"); 1196 printf(" !N");
1129 ++unreachable; 1197 ++unreachable;
1130 break; 1198 break;
1131 case ICMP_UNREACH_HOST: 1199 case ICMP_UNREACH_HOST:
1132#if ENABLE_TRACEROUTE6 1200#if ENABLE_TRACEROUTE6
1133 case ICMP6_DST_UNREACH_ADDR << 8: 1201 case ICMP6_DST_UNREACH_ADDR << 8:
1134#endif 1202#endif
1135 printf(" !H"); 1203 printf(" !H");
1136 ++unreachable; 1204 ++unreachable;
1137 break; 1205 break;
1138 case ICMP_UNREACH_PROTOCOL: 1206 case ICMP_UNREACH_PROTOCOL:
1139 printf(" !P"); 1207 printf(" !P");
1140 got_there = 1; 1208 got_there = 1;
1141 break; 1209 break;
1142 case ICMP_UNREACH_NEEDFRAG: 1210 case ICMP_UNREACH_NEEDFRAG:
1143 printf(" !F-%d", pmtu); 1211 printf(" !F-%d", pmtu);
1144 ++unreachable; 1212 ++unreachable;
1145 break; 1213 break;
1146 case ICMP_UNREACH_SRCFAIL: 1214 case ICMP_UNREACH_SRCFAIL:
1147#if ENABLE_TRACEROUTE6 1215#if ENABLE_TRACEROUTE6
1148 case ICMP6_DST_UNREACH_ADMIN << 8: 1216 case ICMP6_DST_UNREACH_ADMIN << 8:
1149#endif 1217#endif
1150 printf(" !S"); 1218 printf(" !S");
1151 ++unreachable; 1219 ++unreachable;
1152 break;
1153 case ICMP_UNREACH_FILTER_PROHIB:
1154 case ICMP_UNREACH_NET_PROHIB: /* misuse */
1155 printf(" !A");
1156 ++unreachable;
1157 break;
1158 case ICMP_UNREACH_HOST_PROHIB:
1159 printf(" !C");
1160 ++unreachable;
1161 break;
1162 case ICMP_UNREACH_HOST_PRECEDENCE:
1163 printf(" !V");
1164 ++unreachable;
1165 break;
1166 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1167 printf(" !C");
1168 ++unreachable;
1169 break;
1170 case ICMP_UNREACH_NET_UNKNOWN:
1171 case ICMP_UNREACH_HOST_UNKNOWN:
1172 printf(" !U");
1173 ++unreachable;
1174 break;
1175 case ICMP_UNREACH_ISOLATED:
1176 printf(" !I");
1177 ++unreachable;
1178 break;
1179 case ICMP_UNREACH_TOSNET:
1180 case ICMP_UNREACH_TOSHOST:
1181 printf(" !T");
1182 ++unreachable;
1183 break;
1184 default:
1185 printf(" !<%d>", icmp_code);
1186 ++unreachable;
1187 break;
1188 }
1189 break; 1220 break;
1190 } /* while (wait and read a packet) */ 1221 case ICMP_UNREACH_FILTER_PROHIB:
1191 1222 case ICMP_UNREACH_NET_PROHIB: /* misuse */
1192 /* there was no packet at all? */ 1223 printf(" !A");
1193 if (read_len == 0) 1224 ++unreachable;
1194 printf(" *"); 1225 break;
1226 case ICMP_UNREACH_HOST_PROHIB:
1227 printf(" !C");
1228 ++unreachable;
1229 break;
1230 case ICMP_UNREACH_HOST_PRECEDENCE:
1231 printf(" !V");
1232 ++unreachable;
1233 break;
1234 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1235 printf(" !C");
1236 ++unreachable;
1237 break;
1238 case ICMP_UNREACH_NET_UNKNOWN:
1239 case ICMP_UNREACH_HOST_UNKNOWN:
1240 printf(" !U");
1241 ++unreachable;
1242 break;
1243 case ICMP_UNREACH_ISOLATED:
1244 printf(" !I");
1245 ++unreachable;
1246 break;
1247 case ICMP_UNREACH_TOSNET:
1248 case ICMP_UNREACH_TOSHOST:
1249 printf(" !T");
1250 ++unreachable;
1251 break;
1252 default:
1253 printf(" !<%d>", icmp_code);
1254 ++unreachable;
1255 break;
1256 }
1257 next_probe: ;
1195 } /* for (nprobes) */ 1258 } /* for (nprobes) */
1196 1259
1197 bb_putchar('\n'); 1260 bb_putchar('\n');
1198 if (got_there 1261 if (got_there
1199 || (unreachable > 0 && unreachable >= nprobes - 1) 1262 || (unreachable > 0 && unreachable >= G.nprobes - 1)
1200 ) { 1263 ) {
1201 break; 1264 break;
1202 } 1265 }
1203 } 1266 }
1204 1267
1205 if (ENABLE_FEATURE_CLEAN_UP) { 1268 if (ENABLE_FEATURE_CLEAN_UP) {
1206 free(to); 1269#if ENABLE_FEATURE_TRACEROUTE_VERBOSE
1270 free(G.to);
1271#endif
1207 free(lastaddr); 1272 free(lastaddr);
1208 free(from_lsa); 1273 free(G.from_lsa);
1209 } 1274 }
1210 1275
1211 return 0; 1276 return 0;
diff --git a/networking/tunctl.c b/networking/tunctl.c
index 0f010e196..97e6917aa 100644
--- a/networking/tunctl.c
+++ b/networking/tunctl.c
@@ -28,16 +28,16 @@
28//kbuild:lib-$(CONFIG_TUNCTL) += tunctl.o 28//kbuild:lib-$(CONFIG_TUNCTL) += tunctl.o
29 29
30//usage:#define tunctl_trivial_usage 30//usage:#define tunctl_trivial_usage
31//usage: "[-f device] ([-t name] | -d name)" IF_FEATURE_TUNCTL_UG(" [-u owner] [-g group] [-b]") 31//usage: "[-f DEVICE] [-t NAME | -d NAME]" IF_FEATURE_TUNCTL_UG(" [-u USER] [-g GRP] [-b]")
32//usage:#define tunctl_full_usage "\n\n" 32//usage:#define tunctl_full_usage "\n\n"
33//usage: "Create or delete tun interfaces\n" 33//usage: "Create or delete TUN/TAP interfaces\n"
34//usage: "\n -f name tun device (/dev/net/tun)" 34//usage: "\n -f DEV TUN device (default /dev/net/tun)"
35//usage: "\n -t name Create iface 'name'" 35//usage: "\n -t NAME Create iface (default: tapN)"
36//usage: "\n -d name Delete iface 'name'" 36//usage: "\n -d NAME Delete iface"
37//usage: IF_FEATURE_TUNCTL_UG( 37//usage: IF_FEATURE_TUNCTL_UG(
38//usage: "\n -u owner Set iface owner" 38//usage: "\n -u USER Set iface owner"
39//usage: "\n -g group Set iface group" 39//usage: "\n -g GRP Set iface group"
40//usage: "\n -b Brief output" 40//usage: "\n -b Brief output"
41//usage: ) 41//usage: )
42//usage: 42//usage:
43//usage:#define tunctl_example_usage 43//usage:#define tunctl_example_usage
diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src
index 7d04bb246..8c8c11c26 100644
--- a/networking/udhcp/Config.src
+++ b/networking/udhcp/Config.src
@@ -104,6 +104,14 @@ INSERT
104comment "Common options for DHCP applets" 104comment "Common options for DHCP applets"
105 depends on UDHCPD || UDHCPC || UDHCPC6 || DHCPRELAY 105 depends on UDHCPD || UDHCPC || UDHCPC6 || DHCPRELAY
106 106
107config UDHCPC_DEFAULT_INTERFACE
108 string "Default interface name"
109 default "eth0"
110 depends on UDHCPC || UDHCPC6
111 help
112 The interface that will be used if no other interface is
113 specified on the commandline.
114
107config FEATURE_UDHCP_PORT 115config FEATURE_UDHCP_PORT
108 bool "Enable '-P port' option for udhcpd and udhcpc" 116 bool "Enable '-P port' option for udhcpd and udhcpc"
109 default n 117 default n
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 3cbd2d3c8..cc0abd269 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -343,7 +343,8 @@ int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
343 343
344int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 344int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
345 uint32_t source_nip, int source_port, 345 uint32_t source_nip, int source_port,
346 uint32_t dest_nip, int dest_port) FAST_FUNC; 346 uint32_t dest_nip, int dest_port,
347 const char *ifname) FAST_FUNC;
347 348
348void udhcp_sp_setup(void) FAST_FUNC; 349void udhcp_sp_setup(void) FAST_FUNC;
349void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC; 350void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC;
diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h
index 688f5d6c7..9dfde7709 100644
--- a/networking/udhcp/d6_common.h
+++ b/networking/udhcp/d6_common.h
@@ -159,18 +159,16 @@ int FAST_FUNC d6_recv_kernel_packet(
159 struct d6_packet *packet, int fd 159 struct d6_packet *packet, int fd
160); 160);
161 161
162int FAST_FUNC d6_send_raw_packet( 162int FAST_FUNC d6_send_raw_packet_from_client_data_ifindex(
163 struct d6_packet *d6_pkt, unsigned d6_pkt_size, 163 struct d6_packet *d6_pkt, unsigned d6_pkt_size,
164 struct in6_addr *src_ipv6, int source_port, 164 struct in6_addr *src_ipv6, int source_port,
165 struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp, 165 struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp
166 int ifindex
167); 166);
168 167
169int FAST_FUNC d6_send_kernel_packet( 168int FAST_FUNC d6_send_kernel_packet_from_client_data_ifindex(
170 struct d6_packet *d6_pkt, unsigned d6_pkt_size, 169 struct d6_packet *d6_pkt, unsigned d6_pkt_size,
171 struct in6_addr *src_ipv6, int source_port, 170 struct in6_addr *src_ipv6, int source_port,
172 struct in6_addr *dst_ipv6, int dest_port, 171 struct in6_addr *dst_ipv6, int dest_port
173 int ifindex
174); 172);
175 173
176#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 174#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index ac8af91d3..fbdaa99bd 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -558,11 +558,10 @@ static int d6_mcast_from_client_data_ifindex(struct d6_packet *packet, uint8_t *
558 0x33, 0x33, 0x00, 0x01, 0x00, 0x02, 558 0x33, 0x33, 0x00, 0x01, 0x00, 0x02,
559 }; 559 };
560 560
561 return d6_send_raw_packet( 561 return d6_send_raw_packet_from_client_data_ifindex(
562 packet, (end - (uint8_t*) packet), 562 packet, (end - (uint8_t*) packet),
563 /*src*/ &client6_data.ll_ip6, CLIENT_PORT6, 563 /*src*/ &client6_data.ll_ip6, CLIENT_PORT6,
564 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_DHCP6MCAST_ADDR, 564 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_DHCP6MCAST_ADDR
565 client_data.ifindex
566 ); 565 );
567} 566}
568 567
@@ -864,11 +863,10 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st
864 863
865 bb_info_msg("sending %s", "renew"); 864 bb_info_msg("sending %s", "renew");
866 if (server_ipv6) 865 if (server_ipv6)
867 return d6_send_kernel_packet( 866 return d6_send_kernel_packet_from_client_data_ifindex(
868 &packet, (opt_ptr - (uint8_t*) &packet), 867 &packet, (opt_ptr - (uint8_t*) &packet),
869 our_cur_ipv6, CLIENT_PORT6, 868 our_cur_ipv6, CLIENT_PORT6,
870 server_ipv6, SERVER_PORT6, 869 server_ipv6, SERVER_PORT6
871 client_data.ifindex
872 ); 870 );
873 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); 871 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
874} 872}
@@ -893,11 +891,10 @@ int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
893 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2); 891 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
894 892
895 bb_info_msg("sending %s", "release"); 893 bb_info_msg("sending %s", "release");
896 return d6_send_kernel_packet( 894 return d6_send_kernel_packet_from_client_data_ifindex(
897 &packet, (opt_ptr - (uint8_t*) &packet), 895 &packet, (opt_ptr - (uint8_t*) &packet),
898 our_cur_ipv6, CLIENT_PORT6, 896 our_cur_ipv6, CLIENT_PORT6,
899 server_ipv6, SERVER_PORT6, 897 server_ipv6, SERVER_PORT6
900 client_data.ifindex
901 ); 898 );
902} 899}
903 900
@@ -1164,9 +1161,9 @@ static void client_background(void)
1164//usage:#endif 1161//usage:#endif
1165//usage:#define udhcpc6_trivial_usage 1162//usage:#define udhcpc6_trivial_usage
1166//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"odR] [-i IFACE] [-r IPv6] [-s PROG] [-p PIDFILE]\n" 1163//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"odR] [-i IFACE] [-r IPv6] [-s PROG] [-p PIDFILE]\n"
1167//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") 1164//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P PORT]")
1168//usage:#define udhcpc6_full_usage "\n" 1165//usage:#define udhcpc6_full_usage "\n"
1169//usage: "\n -i IFACE Interface to use (default eth0)" 1166//usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")"
1170//usage: "\n -p FILE Create pidfile" 1167//usage: "\n -p FILE Create pidfile"
1171//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" 1168//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
1172//usage: "\n -B Request broadcast replies" 1169//usage: "\n -B Request broadcast replies"
@@ -1182,7 +1179,7 @@ static void client_background(void)
1182//usage: "\n -R Release IP on exit" 1179//usage: "\n -R Release IP on exit"
1183//usage: "\n -S Log to syslog too" 1180//usage: "\n -S Log to syslog too"
1184//usage: IF_FEATURE_UDHCP_PORT( 1181//usage: IF_FEATURE_UDHCP_PORT(
1185//usage: "\n -P N Use port N (default 546)" 1182//usage: "\n -P PORT Use PORT (default 546)"
1186//usage: ) 1183//usage: )
1187////usage: IF_FEATURE_UDHCPC_ARPING( 1184////usage: IF_FEATURE_UDHCPC_ARPING(
1188////usage: "\n -a Use arping to validate offered address" 1185////usage: "\n -a Use arping to validate offered address"
@@ -1234,7 +1231,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1234 /* Default options */ 1231 /* Default options */
1235 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;) 1232 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;)
1236 IF_FEATURE_UDHCP_PORT(CLIENT_PORT6 = 546;) 1233 IF_FEATURE_UDHCP_PORT(CLIENT_PORT6 = 546;)
1237 client_data.interface = "eth0"; 1234 client_data.interface = CONFIG_UDHCPC_DEFAULT_INTERFACE;
1238 client_data.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; 1235 client_data.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
1239 client_data.sockfd = -1; 1236 client_data.sockfd = -1;
1240 1237
diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c
index 167a813e3..172f8e1ab 100644
--- a/networking/udhcp/d6_packet.c
+++ b/networking/udhcp/d6_packet.c
@@ -6,6 +6,7 @@
6 */ 6 */
7#include "common.h" 7#include "common.h"
8#include "d6_common.h" 8#include "d6_common.h"
9#include "dhcpc.h"
9#include "dhcpd.h" 10#include "dhcpd.h"
10#include <netinet/in.h> 11#include <netinet/in.h>
11#include <netinet/if_ether.h> 12#include <netinet/if_ether.h>
@@ -50,11 +51,10 @@ int FAST_FUNC d6_recv_kernel_packet(struct in6_addr *peer_ipv6
50} 51}
51 52
52/* Construct a ipv6+udp header for a packet, send packet */ 53/* Construct a ipv6+udp header for a packet, send packet */
53int FAST_FUNC d6_send_raw_packet( 54int FAST_FUNC d6_send_raw_packet_from_client_data_ifindex(
54 struct d6_packet *d6_pkt, unsigned d6_pkt_size, 55 struct d6_packet *d6_pkt, unsigned d6_pkt_size,
55 struct in6_addr *src_ipv6, int source_port, 56 struct in6_addr *src_ipv6, int source_port,
56 struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp, 57 struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp)
57 int ifindex)
58{ 58{
59 struct sockaddr_ll dest_sll; 59 struct sockaddr_ll dest_sll;
60 struct ip6_udp_d6_packet packet; 60 struct ip6_udp_d6_packet packet;
@@ -74,7 +74,7 @@ int FAST_FUNC d6_send_raw_packet(
74 74
75 dest_sll.sll_family = AF_PACKET; 75 dest_sll.sll_family = AF_PACKET;
76 dest_sll.sll_protocol = htons(ETH_P_IPV6); 76 dest_sll.sll_protocol = htons(ETH_P_IPV6);
77 dest_sll.sll_ifindex = ifindex; 77 dest_sll.sll_ifindex = client_data.ifindex;
78 /*dest_sll.sll_hatype = ARPHRD_???;*/ 78 /*dest_sll.sll_hatype = ARPHRD_???;*/
79 /*dest_sll.sll_pkttype = PACKET_???;*/ 79 /*dest_sll.sll_pkttype = PACKET_???;*/
80 dest_sll.sll_halen = 6; 80 dest_sll.sll_halen = 6;
@@ -103,8 +103,8 @@ int FAST_FUNC d6_send_raw_packet(
103 */ 103 */
104 packet.ip6.ip6_hlim = IPPROTO_UDP; 104 packet.ip6.ip6_hlim = IPPROTO_UDP;
105 packet.udp.check = inet_cksum( 105 packet.udp.check = inet_cksum(
106 (uint8_t *)&packet + 4, 106 (uint8_t *)&packet + 4,
107 offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size 107 offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size
108 ); 108 );
109 /* fix 'hop limit' and 'next header' after UDP checksumming */ 109 /* fix 'hop limit' and 'next header' after UDP checksumming */
110 packet.ip6.ip6_hlim = 1; /* observed Windows machines to use hlim=1 */ 110 packet.ip6.ip6_hlim = 1; /* observed Windows machines to use hlim=1 */
@@ -126,11 +126,10 @@ int FAST_FUNC d6_send_raw_packet(
126} 126}
127 127
128/* Let the kernel do all the work for packet generation */ 128/* Let the kernel do all the work for packet generation */
129int FAST_FUNC d6_send_kernel_packet( 129int FAST_FUNC d6_send_kernel_packet_from_client_data_ifindex(
130 struct d6_packet *d6_pkt, unsigned d6_pkt_size, 130 struct d6_packet *d6_pkt, unsigned d6_pkt_size,
131 struct in6_addr *src_ipv6, int source_port, 131 struct in6_addr *src_ipv6, int source_port,
132 struct in6_addr *dst_ipv6, int dest_port, 132 struct in6_addr *dst_ipv6, int dest_port)
133 int ifindex)
134{ 133{
135 struct sockaddr_in6 sa; 134 struct sockaddr_in6 sa;
136 int fd; 135 int fd;
@@ -157,7 +156,7 @@ int FAST_FUNC d6_send_kernel_packet(
157 sa.sin6_family = AF_INET6; 156 sa.sin6_family = AF_INET6;
158 sa.sin6_port = htons(dest_port); 157 sa.sin6_port = htons(dest_port);
159 sa.sin6_addr = *dst_ipv6; /* struct copy */ 158 sa.sin6_addr = *dst_ipv6; /* struct copy */
160 sa.sin6_scope_id = ifindex; 159 sa.sin6_scope_id = client_data.ifindex;
161 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { 160 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
162 msg = "connect"; 161 msg = "connect";
163 goto ret_close; 162 goto ret_close;
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 66aa38c20..922c71ebd 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -702,7 +702,8 @@ static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t
702 if (server) 702 if (server)
703 return udhcp_send_kernel_packet(packet, 703 return udhcp_send_kernel_packet(packet,
704 ciaddr, CLIENT_PORT, 704 ciaddr, CLIENT_PORT,
705 server, SERVER_PORT); 705 server, SERVER_PORT,
706 client_data.interface);
706 return raw_bcast_from_client_data_ifindex(packet, ciaddr); 707 return raw_bcast_from_client_data_ifindex(packet, ciaddr);
707} 708}
708 709
@@ -1195,7 +1196,7 @@ static void client_background(void)
1195//usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n" 1196//usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n"
1196//usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..." 1197//usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..."
1197//usage:#define udhcpc_full_usage "\n" 1198//usage:#define udhcpc_full_usage "\n"
1198//usage: "\n -i IFACE Interface to use (default eth0)" 1199//usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")"
1199//usage: IF_FEATURE_UDHCP_PORT( 1200//usage: IF_FEATURE_UDHCP_PORT(
1200//usage: "\n -P PORT Use PORT (default 68)" 1201//usage: "\n -P PORT Use PORT (default 68)"
1201//usage: ) 1202//usage: )
@@ -1264,7 +1265,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1264 /* Default options */ 1265 /* Default options */
1265 IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) 1266 IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
1266 IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) 1267 IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
1267 client_data.interface = "eth0"; 1268 client_data.interface = CONFIG_UDHCPC_DEFAULT_INTERFACE;
1268 client_data.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; 1269 client_data.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
1269 client_data.sockfd = -1; 1270 client_data.sockfd = -1;
1270 str_V = "udhcp "BB_VER; 1271 str_V = "udhcp "BB_VER;
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index acfdaa8c3..cd32cb437 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -27,7 +27,7 @@
27//kbuild:lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o 27//kbuild:lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o
28 28
29//usage:#define udhcpd_trivial_usage 29//usage:#define udhcpd_trivial_usage
30//usage: "[-fS] [-I ADDR]" IF_FEATURE_UDHCP_PORT(" [-P N]") " [CONFFILE]" 30//usage: "[-fS] [-I ADDR]" IF_FEATURE_UDHCP_PORT(" [-P PORT]") " [CONFFILE]"
31//usage:#define udhcpd_full_usage "\n\n" 31//usage:#define udhcpd_full_usage "\n\n"
32//usage: "DHCP server\n" 32//usage: "DHCP server\n"
33//usage: "\n -f Run in foreground" 33//usage: "\n -f Run in foreground"
@@ -35,7 +35,7 @@
35//usage: "\n -I ADDR Local address" 35//usage: "\n -I ADDR Local address"
36//usage: "\n -a MSEC Timeout for ARP ping (default 2000)" 36//usage: "\n -a MSEC Timeout for ARP ping (default 2000)"
37//usage: IF_FEATURE_UDHCP_PORT( 37//usage: IF_FEATURE_UDHCP_PORT(
38//usage: "\n -P N Use port N (default 67)" 38//usage: "\n -P PORT Use PORT (default 67)"
39//usage: ) 39//usage: )
40//usage: "\nSignals:" 40//usage: "\nSignals:"
41//usage: "\n USR1 Update lease file" 41//usage: "\n USR1 Update lease file"
@@ -398,7 +398,7 @@ struct config_keyword {
398 398
399#define OFS(field) offsetof(struct server_data_t, field) 399#define OFS(field) offsetof(struct server_data_t, field)
400 400
401static const struct config_keyword keywords[] = { 401static const struct config_keyword keywords[] ALIGN_PTR = {
402 /* keyword handler variable address default */ 402 /* keyword handler variable address default */
403 {"start" , udhcp_str2nip , OFS(start_ip ), "192.168.0.20"}, 403 {"start" , udhcp_str2nip , OFS(start_ip ), "192.168.0.20"},
404 {"end" , udhcp_str2nip , OFS(end_ip ), "192.168.0.254"}, 404 {"end" , udhcp_str2nip , OFS(end_ip ), "192.168.0.254"},
@@ -612,7 +612,8 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
612 612
613 udhcp_send_kernel_packet(dhcp_pkt, 613 udhcp_send_kernel_packet(dhcp_pkt,
614 server_data.server_nip, SERVER_PORT, 614 server_data.server_nip, SERVER_PORT,
615 dhcp_pkt->gateway_nip, SERVER_PORT); 615 dhcp_pkt->gateway_nip, SERVER_PORT,
616 server_data.interface);
616} 617}
617 618
618static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) 619static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
diff --git a/networking/udhcp/dumpleases.c b/networking/udhcp/dumpleases.c
index 70d2d1434..1e9405205 100644
--- a/networking/udhcp/dumpleases.c
+++ b/networking/udhcp/dumpleases.c
@@ -10,18 +10,10 @@
10//usage: "[-r|-a] [-d] [-f LEASEFILE]" 10//usage: "[-r|-a] [-d] [-f LEASEFILE]"
11//usage:#define dumpleases_full_usage "\n\n" 11//usage:#define dumpleases_full_usage "\n\n"
12//usage: "Display DHCP leases granted by udhcpd\n" 12//usage: "Display DHCP leases granted by udhcpd\n"
13//usage: IF_LONG_OPTS(
14//usage: "\n -f,--file FILE Lease file"
15//usage: "\n -r,--remaining Show remaining time"
16//usage: "\n -a,--absolute Show expiration time"
17//usage: "\n -d,--decimal Show time in seconds"
18//usage: )
19//usage: IF_NOT_LONG_OPTS(
20//usage: "\n -f FILE Lease file" 13//usage: "\n -f FILE Lease file"
21//usage: "\n -r Show remaining time" 14//usage: "\n -r Show remaining time"
22//usage: "\n -a Show expiration time" 15//usage: "\n -a Show expiration time"
23//usage: "\n -d Show time in seconds" 16//usage: "\n -d Show time in seconds"
24//usage: )
25 17
26#include "common.h" 18#include "common.h"
27#include "dhcpd.h" 19#include "dhcpd.h"
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c
index 51374646d..4d8e005d4 100644
--- a/networking/udhcp/packet.c
+++ b/networking/udhcp/packet.c
@@ -189,7 +189,8 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
189/* Let the kernel do all the work for packet generation */ 189/* Let the kernel do all the work for packet generation */
190int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 190int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
191 uint32_t source_nip, int source_port, 191 uint32_t source_nip, int source_port,
192 uint32_t dest_nip, int dest_port) 192 uint32_t dest_nip, int dest_port,
193 const char *ifname)
193{ 194{
194 struct sockaddr_in sa; 195 struct sockaddr_in sa;
195 unsigned padding; 196 unsigned padding;
@@ -204,6 +205,21 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
204 } 205 }
205 setsockopt_reuseaddr(fd); 206 setsockopt_reuseaddr(fd);
206 207
208 /* If interface carrier goes down, unless we
209 * bind socket to a particular netdev, the packet
210 * can go out through another interface, eg. via
211 * default route despite being bound to a specific
212 * source IP. As such, bind to device hard and fail
213 * otherwise. Sending renewal packets on foreign
214 * interfaces makes no sense.
215 */
216 if (ifname) {
217 if (setsockopt_bindtodevice(fd, ifname) < 0) {
218 msg = "bindtodevice";
219 goto ret_close;
220 }
221 }
222
207 memset(&sa, 0, sizeof(sa)); 223 memset(&sa, 0, sizeof(sa));
208 sa.sin_family = AF_INET; 224 sa.sin_family = AF_INET;
209 sa.sin_port = htons(source_port); 225 sa.sin_port = htons(source_port);
diff --git a/networking/wget.c b/networking/wget.c
index 8a967fe20..270eab141 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -128,19 +128,14 @@
128 128
129//usage:#define wget_trivial_usage 129//usage:#define wget_trivial_usage
130//usage: IF_FEATURE_WGET_LONG_OPTIONS( 130//usage: IF_FEATURE_WGET_LONG_OPTIONS(
131//usage: "[-c|--continue] [--spider] [-q|--quiet] [-O|--output-document FILE]\n" 131//usage: "[-cqS] [--spider] [-O FILE] [-o LOGFILE] [--header 'HEADER: VALUE'] [-Y on/off]\n"
132//usage: " [-o|--output-file FILE] [--header 'header: value'] [-Y|--proxy on/off]\n"
133//usage: IF_FEATURE_WGET_OPENSSL(
134//usage: " [--no-check-certificate]\n"
135//usage: )
136/* Since we ignore these opts, we don't show them in --help */ 132/* Since we ignore these opts, we don't show them in --help */
137/* //usage: " [--no-cache] [--passive-ftp] [-t TRIES]" */ 133/* //usage: " [--no-cache] [--passive-ftp] [-t TRIES]" */
138/* //usage: " [-nv] [-nc] [-nH] [-np]" */ 134/* //usage: " [-nv] [-nc] [-nH] [-np]" */
139//usage: " [-P DIR] [-S|--server-response] [-U|--user-agent AGENT]" IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..." 135//usage: " "IF_FEATURE_WGET_OPENSSL("[--no-check-certificate] ")"[-P DIR] [-U AGENT]"IF_FEATURE_WGET_TIMEOUT(" [-T SEC]")" URL..."
140//usage: ) 136//usage: )
141//usage: IF_NOT_FEATURE_WGET_LONG_OPTIONS( 137//usage: IF_NOT_FEATURE_WGET_LONG_OPTIONS(
142//usage: "[-cq] [-O FILE] [-o FILE] [-Y on/off] [-P DIR] [-S] [-U AGENT]" 138//usage: "[-cqS] [-O FILE] [-o LOGFILE] [-Y on/off] [-P DIR] [-U AGENT]"IF_FEATURE_WGET_TIMEOUT(" [-T SEC]")" URL..."
143//usage: IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..."
144//usage: ) 139//usage: )
145//usage:#define wget_full_usage "\n\n" 140//usage:#define wget_full_usage "\n\n"
146//usage: "Retrieve files via HTTP or FTP\n" 141//usage: "Retrieve files via HTTP or FTP\n"
@@ -158,7 +153,7 @@
158//usage: "\n -T SEC Network read timeout is SEC seconds" 153//usage: "\n -T SEC Network read timeout is SEC seconds"
159//usage: ) 154//usage: )
160//usage: "\n -O FILE Save to FILE ('-' for stdout)" 155//usage: "\n -O FILE Save to FILE ('-' for stdout)"
161//usage: "\n -o FILE Log messages to FILE" 156//usage: "\n -o LOGFILE Log messages to FILE"
162//usage: "\n -U STR Use STR for User-Agent header" 157//usage: "\n -U STR Use STR for User-Agent header"
163//usage: "\n -Y on/off Use proxy" 158//usage: "\n -Y on/off Use proxy"
164 159
@@ -287,6 +282,8 @@ enum {
287 WGET_OPT_POST_DATA = (1 << 12) * ENABLE_FEATURE_WGET_LONG_OPTIONS, 282 WGET_OPT_POST_DATA = (1 << 12) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
288 WGET_OPT_SPIDER = (1 << 13) * ENABLE_FEATURE_WGET_LONG_OPTIONS, 283 WGET_OPT_SPIDER = (1 << 13) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
289 WGET_OPT_NO_CHECK_CERT = (1 << 14) * ENABLE_FEATURE_WGET_LONG_OPTIONS, 284 WGET_OPT_NO_CHECK_CERT = (1 << 14) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
285 /* hijack this bit for other than opts purposes: */
286 WGET_NO_FTRUNCATE = (1 << 31)
290}; 287};
291 288
292enum { 289enum {
@@ -1085,8 +1082,13 @@ static void NOINLINE retrieve_file_data(FILE *dfp)
1085 */ 1082 */
1086 { 1083 {
1087 off_t pos = lseek(G.output_fd, 0, SEEK_CUR); 1084 off_t pos = lseek(G.output_fd, 0, SEEK_CUR);
1088 if (pos != (off_t)-1) 1085 if (pos != (off_t)-1) {
1089 ftruncate(G.output_fd, pos); 1086 /* do not truncate if -O- is in use, a user complained about
1087 * "wget -qO- 'http://example.com/empty' >>FILE" truncating FILE.
1088 */
1089 if (!(option_mask32 & WGET_NO_FTRUNCATE))
1090 ftruncate(G.output_fd, pos);
1091 }
1090 } 1092 }
1091 1093
1092 if (!(option_mask32 & WGET_OPT_QUIET)) { 1094 if (!(option_mask32 & WGET_OPT_QUIET)) {
@@ -1599,7 +1601,7 @@ IF_DESKTOP( "no-parent\0" No_argument "\xf0")
1599 if (G.fname_out) { /* -O FILE ? */ 1601 if (G.fname_out) { /* -O FILE ? */
1600 if (LONE_DASH(G.fname_out)) { /* -O - ? */ 1602 if (LONE_DASH(G.fname_out)) { /* -O - ? */
1601 G.output_fd = 1; 1603 G.output_fd = 1;
1602 option_mask32 &= ~WGET_OPT_CONTINUE; 1604 option_mask32 = (option_mask32 & (~WGET_OPT_CONTINUE)) | WGET_NO_FTRUNCATE;
1603 } 1605 }
1604 /* compat with wget: -O FILE can overwrite */ 1606 /* compat with wget: -O FILE can overwrite */
1605 G.o_flags = O_WRONLY | O_CREAT | O_TRUNC; 1607 G.o_flags = O_WRONLY | O_CREAT | O_TRUNC;
diff --git a/procps/free.c b/procps/free.c
index b33506b9e..0adef501f 100644
--- a/procps/free.c
+++ b/procps/free.c
@@ -97,10 +97,10 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
97 case 'k': /* 2^10 */ 97 case 'k': /* 2^10 */
98 /* G.unit_steps = 10; - already is */ 98 /* G.unit_steps = 10; - already is */
99 break; 99 break;
100 case 'm': /* 2^(2*10) */ 100 case 'm': /* 2^20 */
101 G.unit_steps = 20; 101 G.unit_steps = 20;
102 break; 102 break;
103 case 'g': /* 2^(3*10) */ 103 case 'g': /* 2^30 */
104 G.unit_steps = 30; 104 G.unit_steps = 30;
105 break; 105 break;
106 default: 106 default:
@@ -117,16 +117,24 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
117 ); 117 );
118 118
119 sysinfo(&info); 119 sysinfo(&info);
120 /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */
121 G.mem_unit = (info.mem_unit ? info.mem_unit : 1);
122 /* Extract cached and memavailable from /proc/meminfo and convert to mem_units */ 120 /* Extract cached and memavailable from /proc/meminfo and convert to mem_units */
123 seen_available = parse_meminfo(&G); 121 seen_available = parse_meminfo(&G);
122 G.mem_unit = (info.mem_unit ? info.mem_unit : 1); /* kernels < 2.4.x return mem_unit==0, so cope */
124 available = ((unsigned long long) G.available_kb * 1024) / G.mem_unit; 123 available = ((unsigned long long) G.available_kb * 1024) / G.mem_unit;
125 cached = ((unsigned long long) G.cached_kb * 1024) / G.mem_unit; 124 cached = ((unsigned long long) G.cached_kb * 1024) / G.mem_unit;
126 cached += info.bufferram; 125 cached += info.bufferram;
127 cached += ((unsigned long long) G.reclaimable_kb * 1024) / G.mem_unit; 126 cached += ((unsigned long long) G.reclaimable_kb * 1024) / G.mem_unit;
128 cached_plus_free = cached + info.freeram; 127 cached_plus_free = cached + info.freeram;
129 128
129/* In case (long long * G.mem_unit) can overflow, this can be used to reduce the chances */
130#if 0 //ENABLE_DESKTOP
131 while (!(G.mem_unit & 1) && G.unit_steps != 0) {
132 G.mem_unit >>= 1;
133 G.unit_steps--;
134 //bb_error_msg("mem_unit:%d unit_steps:%d", G.mem_unit, G.unit_steps);
135 }
136#endif
137
130#define FIELDS_6 "%12llu %11llu %11llu %11llu %11llu %11llu\n" 138#define FIELDS_6 "%12llu %11llu %11llu %11llu %11llu %11llu\n"
131#define FIELDS_3 (FIELDS_6 + 6 + 7 + 7) 139#define FIELDS_3 (FIELDS_6 + 6 + 7 + 7)
132#define FIELDS_2 (FIELDS_6 + 6 + 7 + 7 + 7) 140#define FIELDS_2 (FIELDS_6 + 6 + 7 + 7 + 7)
diff --git a/procps/fuser.c b/procps/fuser.c
index 418f57b57..191746751 100644
--- a/procps/fuser.c
+++ b/procps/fuser.c
@@ -19,7 +19,7 @@
19//kbuild:lib-$(CONFIG_FUSER) += fuser.o 19//kbuild:lib-$(CONFIG_FUSER) += fuser.o
20 20
21//usage:#define fuser_trivial_usage 21//usage:#define fuser_trivial_usage
22//usage: "[OPTIONS] FILE or PORT/PROTO" 22//usage: "[-msk46] [-SIGNAL] FILE or PORT/PROTO"
23//usage:#define fuser_full_usage "\n\n" 23//usage:#define fuser_full_usage "\n\n"
24//usage: "Find processes which use FILEs or PORTs\n" 24//usage: "Find processes which use FILEs or PORTs\n"
25//usage: "\n -m Find processes which use same fs as FILEs" 25//usage: "\n -m Find processes which use same fs as FILEs"
diff --git a/procps/nmeter.c b/procps/nmeter.c
index 856ce0202..f08938654 100644
--- a/procps/nmeter.c
+++ b/procps/nmeter.c
@@ -838,7 +838,7 @@ static void FAST_FUNC collect_info(s_stat *s)
838typedef s_stat* init_func(const char *param); 838typedef s_stat* init_func(const char *param);
839 839
840static const char options[] ALIGN1 = "ncmsfixptTbr"; 840static const char options[] ALIGN1 = "ncmsfixptTbr";
841static init_func *const init_functions[] = { 841static init_func *const init_functions[] ALIGN_PTR = {
842 init_if, 842 init_if,
843 init_cpu, 843 init_cpu,
844 init_mem, 844 init_mem,
@@ -952,11 +952,11 @@ int nmeter_main(int argc UNUSED_PARAM, char **argv)
952 reset_outbuf(); 952 reset_outbuf();
953 953
954 if (G.delta >= 0) { 954 if (G.delta >= 0) {
955 gettimeofday(&G.tv, NULL); 955 xgettimeofday(&G.tv);
956 usleep(G.delta > 1000000 ? 1000000 : G.delta - G.tv.tv_usec % G.deltanz); 956 usleep(G.delta > 1000000 ? 1000000 : G.delta - G.tv.tv_usec % G.deltanz);
957 } 957 }
958 958
959 gettimeofday(&G.start, NULL); 959 xgettimeofday(&G.start);
960 G.tv = G.start; 960 G.tv = G.start;
961 while (1) { 961 while (1) {
962 collect_info(first); 962 collect_info(first);
@@ -971,7 +971,7 @@ int nmeter_main(int argc UNUSED_PARAM, char **argv)
971 if (G.delta >= 0) { 971 if (G.delta >= 0) {
972 int rem; 972 int rem;
973 // can be commented out, will sacrifice sleep time precision a bit 973 // can be commented out, will sacrifice sleep time precision a bit
974 gettimeofday(&G.tv, NULL); 974 xgettimeofday(&G.tv);
975 if (need_seconds) 975 if (need_seconds)
976 rem = G.delta - ((ullong)G.tv.tv_sec*1000000 + G.tv.tv_usec) % G.deltanz; 976 rem = G.delta - ((ullong)G.tv.tv_sec*1000000 + G.tv.tv_usec) % G.deltanz;
977 else 977 else
@@ -983,7 +983,7 @@ int nmeter_main(int argc UNUSED_PARAM, char **argv)
983 } 983 }
984 usleep(rem); 984 usleep(rem);
985 } 985 }
986 gettimeofday(&G.tv, NULL); 986 xgettimeofday(&G.tv);
987 } 987 }
988 988
989 /*return 0;*/ 989 /*return 0;*/
diff --git a/procps/pidof.c b/procps/pidof.c
index 5595e3421..b81709a81 100644
--- a/procps/pidof.c
+++ b/procps/pidof.c
@@ -39,7 +39,7 @@
39 39
40//usage:#if (ENABLE_FEATURE_PIDOF_SINGLE || ENABLE_FEATURE_PIDOF_OMIT) 40//usage:#if (ENABLE_FEATURE_PIDOF_SINGLE || ENABLE_FEATURE_PIDOF_OMIT)
41//usage:#define pidof_trivial_usage 41//usage:#define pidof_trivial_usage
42//usage: "[OPTIONS] [NAME]..." 42//usage: IF_FEATURE_PIDOF_SINGLE("[-s] ")IF_FEATURE_PIDOF_OMIT("[-o PID] ")"[NAME]..."
43//usage:#define USAGE_PIDOF "\n" 43//usage:#define USAGE_PIDOF "\n"
44//usage:#else 44//usage:#else
45//usage:#define pidof_trivial_usage 45//usage:#define pidof_trivial_usage
diff --git a/procps/pmap.c b/procps/pmap.c
index 9e541c707..408cbfce7 100644
--- a/procps/pmap.c
+++ b/procps/pmap.c
@@ -27,20 +27,14 @@
27 27
28#include "libbb.h" 28#include "libbb.h"
29 29
30#if ULONG_MAX == 0xffffffff 30#if ULLONG_MAX == 0xffffffff
31# define TABS "\t" 31# define TABS "\t"
32# define AFMT "8" 32# define AFMTLL "8"
33# define DASHES "" 33# define DASHES ""
34#else 34#else
35# define TABS "\t\t" 35# define TABS "\t\t"
36# define AFMT "16"
37# define DASHES "--------"
38#endif
39
40#if ULLONG_MAX == 0xffffffff
41# define AFMTLL "8"
42#else
43# define AFMTLL "16" 36# define AFMTLL "16"
37# define DASHES "--------"
44#endif 38#endif
45 39
46enum { 40enum {
diff --git a/procps/ps.c b/procps/ps.c
index a4de11379..f84060447 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -381,7 +381,7 @@ static void func_pcpu(char *buf, int size, const procps_status_t *ps)
381} 381}
382*/ 382*/
383 383
384static const ps_out_t out_spec[] = { 384static const ps_out_t out_spec[] ALIGN_PTR = {
385/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */ 385/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */
386 { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, 386 { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID },
387 { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, 387 { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID },
diff --git a/runit/runsv.c b/runit/runsv.c
index 36d85101e..ecab8cdf5 100644
--- a/runit/runsv.c
+++ b/runit/runsv.c
@@ -58,11 +58,19 @@ static void gettimeofday_ns(struct timespec *ts)
58#else 58#else
59static void gettimeofday_ns(struct timespec *ts) 59static void gettimeofday_ns(struct timespec *ts)
60{ 60{
61 BUILD_BUG_ON(sizeof(struct timeval) != sizeof(struct timespec)); 61 if (sizeof(struct timeval) == sizeof(struct timespec)
62 BUILD_BUG_ON(sizeof(((struct timeval*)ts)->tv_usec) != sizeof(ts->tv_nsec)); 62 && sizeof(((struct timeval*)ts)->tv_usec) == sizeof(ts->tv_nsec)
63 /* Cheat */ 63 ) {
64 gettimeofday((void*)ts, NULL); 64 /* Cheat */
65 ts->tv_nsec *= 1000; 65 xgettimeofday((void*)ts);
66 ts->tv_nsec *= 1000;
67 } else {
68 /* For example, musl has "incompatible" layouts */
69 struct timeval tv;
70 xgettimeofday(&tv);
71 ts->tv_sec = tv.tv_sec;
72 ts->tv_nsec = tv.tv_usec * 1000;
73 }
66} 74}
67#endif 75#endif
68 76
@@ -651,7 +659,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
651 gettimeofday_ns(&svd[0].start); 659 gettimeofday_ns(&svd[0].start);
652 update_status(&svd[0]); 660 update_status(&svd[0]);
653 if (LESS(svd[0].start.tv_sec, deadline)) 661 if (LESS(svd[0].start.tv_sec, deadline))
654 sleep(1); 662 sleep1();
655 } 663 }
656 if (haslog) { 664 if (haslog) {
657 if (child == svd[1].pid) { 665 if (child == svd[1].pid) {
@@ -664,7 +672,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
664 gettimeofday_ns(&svd[1].start); 672 gettimeofday_ns(&svd[1].start);
665 update_status(&svd[1]); 673 update_status(&svd[1]);
666 if (LESS(svd[1].start.tv_sec, deadline)) 674 if (LESS(svd[1].start.tv_sec, deadline))
667 sleep(1); 675 sleep1();
668 } 676 }
669 } 677 }
670 } /* for (;;) */ 678 } /* for (;;) */
diff --git a/runit/svlogd.c b/runit/svlogd.c
index a250058a1..294e31aca 100644
--- a/runit/svlogd.c
+++ b/runit/svlogd.c
@@ -351,7 +351,7 @@ static void fmt_time_human_30nul(char *s, char dt_delim)
351 struct tm *ptm; 351 struct tm *ptm;
352 struct timeval tv; 352 struct timeval tv;
353 353
354 gettimeofday(&tv, NULL); 354 xgettimeofday(&tv);
355 ptm = gmtime_r(&tv.tv_sec, &tm); 355 ptm = gmtime_r(&tv.tv_sec, &tm);
356 /* ^^^ using gmtime_r() instead of gmtime() to not use static data */ 356 /* ^^^ using gmtime_r() instead of gmtime() to not use static data */
357 sprintf(s, "%04u-%02u-%02u%c%02u:%02u:%02u.%06u000", 357 sprintf(s, "%04u-%02u-%02u%c%02u:%02u:%02u.%06u000",
@@ -376,7 +376,7 @@ static void fmt_time_bernstein_25(char *s)
376 struct timeval tv; 376 struct timeval tv;
377 unsigned sec_hi; 377 unsigned sec_hi;
378 378
379 gettimeofday(&tv, NULL); 379 xgettimeofday(&tv);
380 sec_hi = (0x400000000000000aULL + tv.tv_sec) >> 32; 380 sec_hi = (0x400000000000000aULL + tv.tv_sec) >> 32;
381 tv.tv_sec = (time_t)(0x400000000000000aULL) + tv.tv_sec; 381 tv.tv_sec = (time_t)(0x400000000000000aULL) + tv.tv_sec;
382 tv.tv_usec *= 1000; 382 tv.tv_usec *= 1000;
@@ -775,7 +775,7 @@ static NOINLINE unsigned logdir_open(struct logdir *ld, const char *fn)
775 ld->nmin = xatoi_positive(&s[1]); 775 ld->nmin = xatoi_positive(&s[1]);
776 break; 776 break;
777 case 't': { 777 case 't': {
778 static const struct suffix_mult mh_suffixes[] = { 778 static const struct suffix_mult mh_suffixes[] ALIGN_SUFFIX = {
779 { "m", 60 }, 779 { "m", 60 },
780 { "h", 60*60 }, 780 { "h", 60*60 },
781 /*{ "d", 24*60*60 },*/ 781 /*{ "d", 24*60*60 },*/
diff --git a/scripts/bb_release b/scripts/bb_release
index 2e146bf84..545440d3a 100755
--- a/scripts/bb_release
+++ b/scripts/bb_release
@@ -8,6 +8,7 @@
8 8
9#svn co svn://busybox.net/trunk/busybox 9#svn co svn://busybox.net/trunk/busybox
10cd busybox || { echo "cd busybox failed"; exit 1; } 10cd busybox || { echo "cd busybox failed"; exit 1; }
11chmod -Rc u+w,a+rX,go-w .
11make release || { echo "make release failed"; exit 1; } 12make release || { echo "make release failed"; exit 1; }
12cd .. 13cd ..
13 14
diff --git a/selinux/chcon.c b/selinux/chcon.c
index 9b13679b8..2e4f94c0f 100644
--- a/selinux/chcon.c
+++ b/selinux/chcon.c
@@ -19,10 +19,10 @@
19//kbuild:lib-$(CONFIG_CHCON) += chcon.o 19//kbuild:lib-$(CONFIG_CHCON) += chcon.o
20 20
21//usage:#define chcon_trivial_usage 21//usage:#define chcon_trivial_usage
22//usage: "[OPTIONS] CONTEXT FILE..." 22//usage: "[-chfRv] CONTEXT FILE..."
23//usage: "\n chcon [OPTIONS] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..." 23//usage: "\n chcon [-chfRv] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..."
24//usage: IF_LONG_OPTS( 24//usage: IF_LONG_OPTS(
25//usage: "\n chcon [OPTIONS] --reference=RFILE FILE..." 25//usage: "\n chcon [-chfRv] --reference=RFILE FILE..."
26//usage: ) 26//usage: )
27//usage: 27//usage:
28//usage:#define chcon_full_usage "\n\n" 28//usage:#define chcon_full_usage "\n\n"
@@ -37,7 +37,7 @@
37//usage: "\n -u USER Set user/role/type/range in the target security context" 37//usage: "\n -u USER Set user/role/type/range in the target security context"
38//usage: "\n -r ROLE" 38//usage: "\n -r ROLE"
39//usage: "\n -t TYPE" 39//usage: "\n -t TYPE"
40//usage: "\n -l RNG" 40//usage: "\n -l RANGE"
41//usage: "\n -R Recurse" 41//usage: "\n -R Recurse"
42 42
43#include <selinux/context.h> 43#include <selinux/context.h>
diff --git a/shell/ash.c b/shell/ash.c
index 897548f3c..780900b40 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -418,9 +418,12 @@ static void forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes)
418 418
419/* ============ Shell options */ 419/* ============ Shell options */
420 420
421/* If you add/change options hare, update --help text too */
421static const char *const optletters_optnames[] = { 422static const char *const optletters_optnames[] = {
422 "e" "errexit", 423 "e" "errexit",
423 "f" "noglob", 424 "f" "noglob",
425/* bash has '-o ignoreeof', but no short synonym -I for it */
426/* (in bash, set -I disables invisible variables (what's that?)) */
424 "I" "ignoreeof", 427 "I" "ignoreeof",
425/* The below allowed this invocation: 428/* The below allowed this invocation:
426 * ash -c 'set -i; echo $-; sleep 5; echo $-' 429 * ash -c 'set -i; echo $-; sleep 5; echo $-'
@@ -429,9 +432,10 @@ static const char *const optletters_optnames[] = {
429 * In our code, this is denoted by empty long name: 432 * In our code, this is denoted by empty long name:
430 */ 433 */
431 "i" "", 434 "i" "",
435/* (removing "i" altogether would remove it from "$-", not good) */
432 "m" "monitor", 436 "m" "monitor",
433 "n" "noexec", 437 "n" "noexec",
434/* Ditto: bash has no "set -s" */ 438/* Ditto: bash has no "set -s", "set -c" */
435#if !ENABLE_PLATFORM_MINGW32 439#if !ENABLE_PLATFORM_MINGW32
436 "s" "", 440 "s" "",
437#else 441#else
@@ -707,6 +711,63 @@ var_end(const char *var)
707} 711}
708 712
709 713
714/* ============ Parser data */
715
716/*
717 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
718 */
719struct strlist {
720 struct strlist *next;
721 char *text;
722};
723
724struct alias;
725
726struct strpush {
727 struct strpush *prev; /* preceding string on stack */
728 char *prev_string;
729 int prev_left_in_line;
730#if ENABLE_ASH_ALIAS
731 struct alias *ap; /* if push was associated with an alias */
732#endif
733 char *string; /* remember the string since it may change */
734
735 /* Remember last two characters for pungetc. */
736 int lastc[2];
737
738 /* Number of outstanding calls to pungetc. */
739 int unget;
740};
741
742/*
743 * The parsefile structure pointed to by the global variable parsefile
744 * contains information about the current file being read.
745 */
746struct parsefile {
747 struct parsefile *prev; /* preceding file on stack */
748 int linno; /* current line */
749 int pf_fd; /* file descriptor (or -1 if string) */
750 int left_in_line; /* number of chars left in this line */
751 int left_in_buffer; /* number of chars left in this buffer past the line */
752 char *next_to_pgetc; /* next char in buffer */
753 char *buf; /* input buffer */
754 struct strpush *strpush; /* for pushing strings at this level */
755 struct strpush basestrpush; /* so pushing one is fast */
756
757 /* Remember last two characters for pungetc. */
758 int lastc[2];
759
760 /* Number of outstanding calls to pungetc. */
761 int unget;
762};
763
764static struct parsefile basepf; /* top level input file */
765static struct parsefile *g_parsefile = &basepf; /* current input file */
766#if ENABLE_PLATFORM_POSIX
767static char *commandname; /* currently executing command */
768#endif
769
770
710/* ============ Interrupts / exceptions */ 771/* ============ Interrupts / exceptions */
711 772
712static void exitshell(void) NORETURN; 773static void exitshell(void) NORETURN;
@@ -1466,63 +1527,6 @@ showtree(union node *n)
1466#endif /* DEBUG */ 1527#endif /* DEBUG */
1467 1528
1468 1529
1469/* ============ Parser data */
1470
1471/*
1472 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1473 */
1474struct strlist {
1475 struct strlist *next;
1476 char *text;
1477};
1478
1479struct alias;
1480
1481struct strpush {
1482 struct strpush *prev; /* preceding string on stack */
1483 char *prev_string;
1484 int prev_left_in_line;
1485#if ENABLE_ASH_ALIAS
1486 struct alias *ap; /* if push was associated with an alias */
1487#endif
1488 char *string; /* remember the string since it may change */
1489
1490 /* Remember last two characters for pungetc. */
1491 int lastc[2];
1492
1493 /* Number of outstanding calls to pungetc. */
1494 int unget;
1495};
1496
1497/*
1498 * The parsefile structure pointed to by the global variable parsefile
1499 * contains information about the current file being read.
1500 */
1501struct parsefile {
1502 struct parsefile *prev; /* preceding file on stack */
1503 int linno; /* current line */
1504 int pf_fd; /* file descriptor (or -1 if string) */
1505 int left_in_line; /* number of chars left in this line */
1506 int left_in_buffer; /* number of chars left in this buffer past the line */
1507 char *next_to_pgetc; /* next char in buffer */
1508 char *buf; /* input buffer */
1509 struct strpush *strpush; /* for pushing strings at this level */
1510 struct strpush basestrpush; /* so pushing one is fast */
1511
1512 /* Remember last two characters for pungetc. */
1513 int lastc[2];
1514
1515 /* Number of outstanding calls to pungetc. */
1516 int unget;
1517};
1518
1519static struct parsefile basepf; /* top level input file */
1520static struct parsefile *g_parsefile = &basepf; /* current input file */
1521#if ENABLE_PLATFORM_POSIX
1522static char *commandname; /* currently executing command */
1523#endif
1524
1525
1526/* ============ Message printing */ 1530/* ============ Message printing */
1527 1531
1528static void 1532static void
@@ -2284,7 +2288,7 @@ static const struct {
2284 int flags; 2288 int flags;
2285 const char *var_text; 2289 const char *var_text;
2286 void (*var_func)(const char *) FAST_FUNC; 2290 void (*var_func)(const char *) FAST_FUNC;
2287} varinit_data[] = { 2291} varinit_data[] ALIGN_PTR = {
2288 /* 2292 /*
2289 * Note: VEXPORT would not work correctly here for NOFORK applets: 2293 * Note: VEXPORT would not work correctly here for NOFORK applets:
2290 * some environment strings may be constant. 2294 * some environment strings may be constant.
@@ -5137,7 +5141,7 @@ getstatus(struct job *job)
5137 job->sigint = 1; 5141 job->sigint = 1;
5138#endif 5142#endif
5139 } 5143 }
5140 retval += 128; 5144 retval |= 128;
5141 } 5145 }
5142 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n", 5146 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
5143 jobno(job), job->nprocs, status, retval)); 5147 jobno(job), job->nprocs, status, retval));
@@ -5203,7 +5207,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
5203 if (status != -1 && !WIFSTOPPED(status)) { 5207 if (status != -1 && !WIFSTOPPED(status)) {
5204 retval = WEXITSTATUS(status); 5208 retval = WEXITSTATUS(status);
5205 if (WIFSIGNALED(status)) 5209 if (WIFSIGNALED(status))
5206 retval = WTERMSIG(status) + 128; 5210 retval = 128 | WTERMSIG(status);
5207 goto ret; 5211 goto ret;
5208 } 5212 }
5209 } 5213 }
@@ -5238,7 +5242,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
5238 ret: 5242 ret:
5239 return retval; 5243 return retval;
5240 sigout: 5244 sigout:
5241 retval = 128 + pending_sig; 5245 retval = 128 | pending_sig;
5242 return retval; 5246 return retval;
5243} 5247}
5244 5248
@@ -5340,7 +5344,7 @@ static char *cmdnextc;
5340static void 5344static void
5341cmdputs(const char *s) 5345cmdputs(const char *s)
5342{ 5346{
5343 static const char vstype[VSTYPE + 1][3] = { 5347 static const char vstype[VSTYPE + 1][3] ALIGN1 = {
5344 "", "}", "-", "+", "?", "=", 5348 "", "}", "-", "+", "?", "=",
5345 "%", "%%", "#", "##" 5349 "%", "%%", "#", "##"
5346 IF_BASH_SUBSTR(, ":") 5350 IF_BASH_SUBSTR(, ":")
@@ -7578,7 +7582,8 @@ subevalvar(char *start, char *str, int strloc,
7578 slash_pos = -1; 7582 slash_pos = -1;
7579 if (repl) { 7583 if (repl) {
7580 slash_pos = expdest - ((char *)stackblock() + strloc); 7584 slash_pos = expdest - ((char *)stackblock() + strloc);
7581 STPUTC('/', expdest); 7585 if (!(flag & EXP_DISCARD))
7586 STPUTC('/', expdest);
7582 //bb_error_msg("repl+1:'%s'", repl + 1); 7587 //bb_error_msg("repl+1:'%s'", repl + 1);
7583 p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */ 7588 p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */
7584 *repl = '/'; 7589 *repl = '/';
@@ -7740,7 +7745,7 @@ subevalvar(char *start, char *str, int strloc,
7740 len = 0; 7745 len = 0;
7741 idx = startp; 7746 idx = startp;
7742 end = str - 1; 7747 end = str - 1;
7743 while (idx < end) { 7748 while (idx <= end) {
7744 try_to_match: 7749 try_to_match:
7745 loc = scanright(idx, rmesc, rmescend, str, quotes, 1); 7750 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
7746 //bb_error_msg("scanright('%s'):'%s'", str, loc); 7751 //bb_error_msg("scanright('%s'):'%s'", str, loc);
@@ -7748,6 +7753,8 @@ subevalvar(char *start, char *str, int strloc,
7748 /* No match, advance */ 7753 /* No match, advance */
7749 char *restart_detect = stackblock(); 7754 char *restart_detect = stackblock();
7750 skip_matching: 7755 skip_matching:
7756 if (idx >= end)
7757 break;
7751 STPUTC(*idx, expdest); 7758 STPUTC(*idx, expdest);
7752 if (quotes && (unsigned char)*idx == CTLESC) { 7759 if (quotes && (unsigned char)*idx == CTLESC) {
7753 idx++; 7760 idx++;
@@ -7760,8 +7767,6 @@ subevalvar(char *start, char *str, int strloc,
7760 len++; 7767 len++;
7761 rmesc++; 7768 rmesc++;
7762 /* continue; - prone to quadratic behavior, smarter code: */ 7769 /* continue; - prone to quadratic behavior, smarter code: */
7763 if (idx >= end)
7764 break;
7765 if (str[0] == '*') { 7770 if (str[0] == '*') {
7766 /* Pattern is "*foo". If "*foo" does not match "long_string", 7771 /* Pattern is "*foo". If "*foo" does not match "long_string",
7767 * it would never match "ong_string" etc, no point in trying. 7772 * it would never match "ong_string" etc, no point in trying.
@@ -7844,7 +7849,9 @@ subevalvar(char *start, char *str, int strloc,
7844 out: 7849 out:
7845 amount = loc - expdest; 7850 amount = loc - expdest;
7846 STADJUST(amount, expdest); 7851 STADJUST(amount, expdest);
7852#if BASH_PATTERN_SUBST
7847 out1: 7853 out1:
7854#endif
7848 /* Remove any recorded regions beyond start of variable */ 7855 /* Remove any recorded regions beyond start of variable */
7849 removerecordregions(startloc); 7856 removerecordregions(startloc);
7850 7857
@@ -9127,7 +9134,7 @@ enum {
9127 , /* thus far 29 bits used */ 9134 , /* thus far 29 bits used */
9128}; 9135};
9129 9136
9130static const char *const tokname_array[] = { 9137static const char *const tokname_array[] ALIGN_PTR = {
9131 "end of file", 9138 "end of file",
9132 "newline", 9139 "newline",
9133 "redirection", 9140 "redirection",
@@ -11360,7 +11367,7 @@ preadfd(void)
11360 11367
11361 g_parsefile->next_to_pgetc = buf; 11368 g_parsefile->next_to_pgetc = buf;
11362#if ENABLE_FEATURE_EDITING 11369#if ENABLE_FEATURE_EDITING
11363 retry: 11370 /* retry: */
11364 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 11371 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
11365 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 11372 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
11366 else { 11373 else {
@@ -11382,17 +11389,16 @@ preadfd(void)
11382 if (nr == 0) { 11389 if (nr == 0) {
11383 /* ^C pressed, "convert" to SIGINT */ 11390 /* ^C pressed, "convert" to SIGINT */
11384 write(STDOUT_FILENO, "^C", 2); 11391 write(STDOUT_FILENO, "^C", 2);
11392# if !ENABLE_PLATFORM_MINGW32
11393 raise(SIGINT);
11394# endif
11385 if (trap[SIGINT]) { 11395 if (trap[SIGINT]) {
11386 buf[0] = '\n'; 11396 buf[0] = '\n';
11387 buf[1] = '\0'; 11397 buf[1] = '\0';
11388# if !ENABLE_PLATFORM_MINGW32
11389 raise(SIGINT);
11390# endif
11391 return 1; 11398 return 1;
11392 } 11399 }
11393 exitstatus = 128 + SIGINT; 11400 exitstatus = 128 + SIGINT;
11394 bb_putchar('\n'); 11401 return -1;
11395 goto retry;
11396 } 11402 }
11397 if (nr < 0) { 11403 if (nr < 0) {
11398 if (errno == 0) { 11404 if (errno == 0) {
@@ -12164,10 +12170,10 @@ static void FAST_FUNC
12164change_epoch(struct var *vepoch, const char *fmt) 12170change_epoch(struct var *vepoch, const char *fmt)
12165{ 12171{
12166 struct timeval tv; 12172 struct timeval tv;
12167 char buffer[sizeof("%lu.nnnnnn") + sizeof(long)*3]; 12173 char buffer[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
12168 12174
12169 gettimeofday(&tv, NULL); 12175 xgettimeofday(&tv);
12170 sprintf(buffer, fmt, (unsigned long)tv.tv_sec, (unsigned)tv.tv_usec); 12176 sprintf(buffer, fmt, (unsigned long long)tv.tv_sec, (unsigned)tv.tv_usec);
12171 setvar(vepoch->var_text, buffer, VNOFUNC); 12177 setvar(vepoch->var_text, buffer, VNOFUNC);
12172 vepoch->flags &= ~VNOFUNC; 12178 vepoch->flags &= ~VNOFUNC;
12173} 12179}
@@ -12175,13 +12181,13 @@ change_epoch(struct var *vepoch, const char *fmt)
12175static void FAST_FUNC 12181static void FAST_FUNC
12176change_seconds(const char *value UNUSED_PARAM) 12182change_seconds(const char *value UNUSED_PARAM)
12177{ 12183{
12178 change_epoch(&vepochs, "%lu"); 12184 change_epoch(&vepochs, "%llu");
12179} 12185}
12180 12186
12181static void FAST_FUNC 12187static void FAST_FUNC
12182change_realtime(const char *value UNUSED_PARAM) 12188change_realtime(const char *value UNUSED_PARAM)
12183{ 12189{
12184 change_epoch(&vepochr, "%lu.%06u"); 12190 change_epoch(&vepochr, "%llu.%06u");
12185} 12191}
12186#endif 12192#endif
12187 12193
@@ -15001,6 +15007,7 @@ reset(void)
15001 /* from input.c: */ 15007 /* from input.c: */
15002 g_parsefile->left_in_buffer = 0; 15008 g_parsefile->left_in_buffer = 0;
15003 g_parsefile->left_in_line = 0; /* clear input buffer */ 15009 g_parsefile->left_in_line = 0; /* clear input buffer */
15010 g_parsefile->unget = 0;
15004 popallfiles(); 15011 popallfiles();
15005 15012
15006 /* from var.c: */ 15013 /* from var.c: */
@@ -15017,8 +15024,7 @@ exitshell(void)
15017 char *p; 15024 char *p;
15018 15025
15019#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 15026#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
15020 if (line_input_state) 15027 save_history(line_input_state); /* may be NULL */
15021 save_history(line_input_state);
15022#endif 15028#endif
15023 savestatus = exitstatus; 15029 savestatus = exitstatus;
15024 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); 15030 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
@@ -15197,7 +15203,8 @@ init(void)
15197 15203
15198 15204
15199//usage:#define ash_trivial_usage 15205//usage:#define ash_trivial_usage
15200//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]" 15206//usage: "[-il] [-/+Cabefmnuvx] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]"
15207//////// comes from ^^^^^^^^^^optletters
15201//usage:#define ash_full_usage "\n\n" 15208//usage:#define ash_full_usage "\n\n"
15202//usage: "Unix shell interpreter" 15209//usage: "Unix shell interpreter"
15203 15210
@@ -15246,9 +15253,9 @@ procargs(char **argv)
15246 } 15253 }
15247 if (mflag == 2) 15254 if (mflag == 2)
15248 mflag = iflag; 15255 mflag = iflag;
15256 /* Unset options which weren't explicitly set or unset */
15249 for (i = 0; i < NOPTS; i++) 15257 for (i = 0; i < NOPTS; i++)
15250 if (optlist[i] == 2) 15258 optlist[i] &= 1; /* same effect as "if (optlist[i] == 2) optlist[i] = 0;" */
15251 optlist[i] = 0;
15252#if DEBUG == 2 15259#if DEBUG == 2
15253 debug = 1; 15260 debug = 1;
15254#endif 15261#endif
@@ -15277,6 +15284,19 @@ procargs(char **argv)
15277 shellparam.nparam++; 15284 shellparam.nparam++;
15278 xargv++; 15285 xargv++;
15279 } 15286 }
15287
15288 /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
15289 * Try:
15290 * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect
15291 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed
15292 * NB: must do it before setting up signals (in optschanged())
15293 * and reading .profile etc (after we return from here):
15294 */
15295#if !ENABLE_PLATFORM_MINGW32
15296 if (iflag)
15297 signal(SIGHUP, SIG_DFL);
15298#endif
15299
15280 optschanged(); 15300 optschanged();
15281 15301
15282 return login_sh; 15302 return login_sh;
@@ -15493,7 +15513,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
15493 15513
15494 if (sflag || minusc == NULL) { 15514 if (sflag || minusc == NULL) {
15495#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY 15515#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
15496 if (iflag) { 15516 if (line_input_state) {
15497 const char *hp = lookupvar("HISTFILE"); 15517 const char *hp = lookupvar("HISTFILE");
15498 if (!hp) { 15518 if (!hp) {
15499 hp = lookupvar("HOME"); 15519 hp = lookupvar("HOME");
@@ -15507,7 +15527,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
15507 } 15527 }
15508 } 15528 }
15509 if (hp) 15529 if (hp)
15510 line_input_state->hist_file = hp; 15530 line_input_state->hist_file = xstrdup(hp);
15511# if ENABLE_FEATURE_SH_HISTFILESIZE 15531# if ENABLE_FEATURE_SH_HISTFILESIZE
15512 hp = lookupvar("HISTFILESIZE"); 15532 hp = lookupvar("HISTFILESIZE");
15513 line_input_state->max_history = size_from_HISTFILESIZE(hp); 15533 line_input_state->max_history = size_from_HISTFILESIZE(hp);
@@ -15515,16 +15535,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
15515 } 15535 }
15516#endif 15536#endif
15517 state4: /* XXX ??? - why isn't this before the "if" statement */ 15537 state4: /* XXX ??? - why isn't this before the "if" statement */
15518
15519 /* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
15520 * Try:
15521 * trap '' hup; bash; echo RET # type "kill -hup $$", see SIGHUP having effect
15522 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE' # here SIGHUP is SIG_IGNed
15523 */
15524#if !ENABLE_PLATFORM_MINGW32
15525 signal(SIGHUP, SIG_DFL);
15526#endif
15527
15528 cmdloop(1); 15538 cmdloop(1);
15529 } 15539 }
15530#if PROFILE 15540#if PROFILE
diff --git a/shell/ash_test/ash-misc/piped_input.right b/shell/ash_test/ash-misc/piped_input.right
new file mode 100644
index 000000000..7b8bf6758
--- /dev/null
+++ b/shell/ash_test/ash-misc/piped_input.right
@@ -0,0 +1,2 @@
1TEST
2One:1
diff --git a/shell/ash_test/ash-misc/piped_input.tests b/shell/ash_test/ash-misc/piped_input.tests
new file mode 100755
index 000000000..929fec0db
--- /dev/null
+++ b/shell/ash_test/ash-misc/piped_input.tests
@@ -0,0 +1,3 @@
1exec 2>&1
2echo 'echo TEST; false' | $THIS_SH
3echo One:$?
diff --git a/shell/ash_test/ash-vars/var_bash_repl_empty_var.right b/shell/ash_test/ash-vars/var_bash_repl_empty_var.right
index 892916783..a8d1a3bef 100644
--- a/shell/ash_test/ash-vars/var_bash_repl_empty_var.right
+++ b/shell/ash_test/ash-vars/var_bash_repl_empty_var.right
@@ -1,2 +1,3 @@
1 1
2w
2Ok:0 3Ok:0
diff --git a/shell/ash_test/ash-vars/var_bash_repl_empty_var.tests b/shell/ash_test/ash-vars/var_bash_repl_empty_var.tests
index 73a43d38e..22aaba560 100755
--- a/shell/ash_test/ash-vars/var_bash_repl_empty_var.tests
+++ b/shell/ash_test/ash-vars/var_bash_repl_empty_var.tests
@@ -1,3 +1,5 @@
1unset v
2echo ${v/*/w}
1v='' 3v=''
2echo ${v/*/w} 4echo ${v/*/w}
3echo Ok:$? 5echo Ok:$?
diff --git a/shell/hush.c b/shell/hush.c
index ab7263381..77f90f82f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -596,10 +596,10 @@ typedef struct in_str {
596/* The descrip member of this structure is only used to make 596/* The descrip member of this structure is only used to make
597 * debugging output pretty */ 597 * debugging output pretty */
598static const struct { 598static const struct {
599 int mode; 599 int32_t mode;
600 signed char default_fd; 600 signed char default_fd;
601 char descrip[3]; 601 char descrip[3];
602} redir_table[] = { 602} redir_table[] ALIGN4 = {
603 { O_RDONLY, 0, "<" }, 603 { O_RDONLY, 0, "<" },
604 { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" }, 604 { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" },
605 { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" }, 605 { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" },
@@ -653,7 +653,7 @@ struct command {
653/* used for "[[ EXPR ]]" */ 653/* used for "[[ EXPR ]]" */
654# define CMD_TEST2_SINGLEWORD_NOGLOB 2 654# define CMD_TEST2_SINGLEWORD_NOGLOB 2
655#endif 655#endif
656#if ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY 656#if BASH_TEST2 || ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY
657/* used to prevent word splitting and globbing in "export v=t*" */ 657/* used to prevent word splitting and globbing in "export v=t*" */
658# define CMD_SINGLEWORD_NOGLOB 3 658# define CMD_SINGLEWORD_NOGLOB 3
659#endif 659#endif
@@ -1027,7 +1027,7 @@ struct globals {
1027 struct sigaction sa; 1027 struct sigaction sa;
1028 char optstring_buf[sizeof("eixcs")]; 1028 char optstring_buf[sizeof("eixcs")];
1029#if BASH_EPOCH_VARS 1029#if BASH_EPOCH_VARS
1030 char epoch_buf[sizeof("%lu.nnnnnn") + sizeof(long)*3]; 1030 char epoch_buf[sizeof("%llu.nnnnnn") + sizeof(long long)*3];
1031#endif 1031#endif
1032#if ENABLE_FEATURE_EDITING 1032#if ENABLE_FEATURE_EDITING
1033 char user_input_buf[CONFIG_FEATURE_EDITING_MAX_LEN]; 1033 char user_input_buf[CONFIG_FEATURE_EDITING_MAX_LEN];
@@ -1140,7 +1140,7 @@ struct built_in_command {
1140#endif 1140#endif
1141}; 1141};
1142 1142
1143static const struct built_in_command bltins1[] = { 1143static const struct built_in_command bltins1[] ALIGN_PTR = {
1144 BLTIN("." , builtin_source , "Run commands in file"), 1144 BLTIN("." , builtin_source , "Run commands in file"),
1145 BLTIN(":" , builtin_true , NULL), 1145 BLTIN(":" , builtin_true , NULL),
1146#if ENABLE_HUSH_JOB 1146#if ENABLE_HUSH_JOB
@@ -1225,7 +1225,7 @@ static const struct built_in_command bltins1[] = {
1225/* These builtins won't be used if we are on NOMMU and need to re-exec 1225/* These builtins won't be used if we are on NOMMU and need to re-exec
1226 * (it's cheaper to run an external program in this case): 1226 * (it's cheaper to run an external program in this case):
1227 */ 1227 */
1228static const struct built_in_command bltins2[] = { 1228static const struct built_in_command bltins2[] ALIGN_PTR = {
1229#if ENABLE_HUSH_TEST 1229#if ENABLE_HUSH_TEST
1230 BLTIN("[" , builtin_test , NULL), 1230 BLTIN("[" , builtin_test , NULL),
1231#endif 1231#endif
@@ -1649,13 +1649,33 @@ static int refill_HFILE_and_getc(HFILE *fp)
1649 /* Already saw EOF */ 1649 /* Already saw EOF */
1650 return EOF; 1650 return EOF;
1651 } 1651 }
1652#if ENABLE_HUSH_INTERACTIVE && !ENABLE_FEATURE_EDITING
1653 /* If user presses ^C, read() restarts after SIGINT (we use SA_RESTART).
1654 * IOW: ^C will not immediately stop line input.
1655 * But poll() is different: it does NOT restart after signals.
1656 */
1657 if (fp == G.HFILE_stdin) {
1658 struct pollfd pfd[1];
1659 pfd[0].fd = fp->fd;
1660 pfd[0].events = POLLIN;
1661 n = poll(pfd, 1, -1);
1662 if (n < 0
1663 /*&& errno == EINTR - assumed true */
1664 && sigismember(&G.pending_set, SIGINT)
1665 ) {
1666 return '\0';
1667 }
1668 }
1669#else
1670/* if FEATURE_EDITING=y, we do not use this routine for interactive input */
1671#endif
1652 /* Try to buffer more input */ 1672 /* Try to buffer more input */
1653 fp->cur = fp->buf;
1654 n = safe_read(fp->fd, fp->buf, sizeof(fp->buf)); 1673 n = safe_read(fp->fd, fp->buf, sizeof(fp->buf));
1655 if (n < 0) { 1674 if (n < 0) {
1656 bb_simple_perror_msg("read error"); 1675 bb_simple_perror_msg("read error");
1657 n = 0; 1676 n = 0;
1658 } 1677 }
1678 fp->cur = fp->buf;
1659 fp->end = fp->buf + n; 1679 fp->end = fp->buf + n;
1660 if (n == 0) { 1680 if (n == 0) {
1661 /* EOF/error */ 1681 /* EOF/error */
@@ -2050,8 +2070,7 @@ static sighandler_t pick_sighandler(unsigned sig)
2050static void hush_exit(int exitcode) 2070static void hush_exit(int exitcode)
2051{ 2071{
2052#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 2072#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
2053 if (G.line_input_state) 2073 save_history(G.line_input_state); /* may be NULL */
2054 save_history(G.line_input_state);
2055#endif 2074#endif
2056 2075
2057 fflush_all(); 2076 fflush_all();
@@ -2091,7 +2110,6 @@ static void hush_exit(int exitcode)
2091#endif 2110#endif
2092} 2111}
2093 2112
2094
2095//TODO: return a mask of ALL handled sigs? 2113//TODO: return a mask of ALL handled sigs?
2096static int check_and_run_traps(void) 2114static int check_and_run_traps(void)
2097{ 2115{
@@ -2259,13 +2277,13 @@ static const char* FAST_FUNC get_local_var_value(const char *name)
2259 { 2277 {
2260 const char *fmt = NULL; 2278 const char *fmt = NULL;
2261 if (strcmp(name, "EPOCHSECONDS") == 0) 2279 if (strcmp(name, "EPOCHSECONDS") == 0)
2262 fmt = "%lu"; 2280 fmt = "%llu";
2263 else if (strcmp(name, "EPOCHREALTIME") == 0) 2281 else if (strcmp(name, "EPOCHREALTIME") == 0)
2264 fmt = "%lu.%06u"; 2282 fmt = "%llu.%06u";
2265 if (fmt) { 2283 if (fmt) {
2266 struct timeval tv; 2284 struct timeval tv;
2267 gettimeofday(&tv, NULL); 2285 xgettimeofday(&tv);
2268 sprintf(G.epoch_buf, fmt, (unsigned long)tv.tv_sec, 2286 sprintf(G.epoch_buf, fmt, (unsigned long long)tv.tv_sec,
2269 (unsigned)tv.tv_usec); 2287 (unsigned)tv.tv_usec);
2270 return G.epoch_buf; 2288 return G.epoch_buf;
2271 } 2289 }
@@ -2614,7 +2632,7 @@ static const char *setup_prompt_string(void)
2614 /* bash uses $PWD value, even if it is set by user. 2632 /* bash uses $PWD value, even if it is set by user.
2615 * It uses current dir only if PWD is unset. 2633 * It uses current dir only if PWD is unset.
2616 * We always use current dir. */ 2634 * We always use current dir. */
2617 G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#'); 2635 prompt_str = G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#');
2618 } 2636 }
2619# endif 2637# endif
2620 debug_printf("prompt_str '%s'\n", prompt_str); 2638 debug_printf("prompt_str '%s'\n", prompt_str);
@@ -2622,33 +2640,33 @@ static const char *setup_prompt_string(void)
2622} 2640}
2623static int get_user_input(struct in_str *i) 2641static int get_user_input(struct in_str *i)
2624{ 2642{
2643# if ENABLE_FEATURE_EDITING
2644 /* In EDITING case, this function reads next input line,
2645 * saves it in i->p, then returns 1st char of it.
2646 */
2625 int r; 2647 int r;
2626 const char *prompt_str; 2648 const char *prompt_str;
2627 2649
2628 prompt_str = setup_prompt_string(); 2650 prompt_str = setup_prompt_string();
2629# if ENABLE_FEATURE_EDITING
2630 for (;;) { 2651 for (;;) {
2631 reinit_unicode_for_hush(); 2652 reinit_unicode_for_hush();
2632 if (G.flag_SIGINT) { 2653 G.flag_SIGINT = 0;
2633 /* There was ^C'ed, make it look prettier: */
2634 bb_putchar('\n');
2635 G.flag_SIGINT = 0;
2636 }
2637 /* buglet: SIGINT will not make new prompt to appear _at once_, 2654 /* buglet: SIGINT will not make new prompt to appear _at once_,
2638 * only after <Enter>. (^C works immediately) */ 2655 * only after <Enter>. (^C works immediately) */
2639 r = read_line_input(G.line_input_state, prompt_str, 2656 r = read_line_input(G.line_input_state, prompt_str,
2640 G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1 2657 G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1
2641 ); 2658 );
2642 /* read_line_input intercepts ^C, "convert" it to SIGINT */ 2659 /* read_line_input intercepts ^C, "convert" it to SIGINT */
2643 if (r == 0) 2660 if (r == 0) {
2644 raise(SIGINT); 2661 raise(SIGINT);
2662 }
2645 check_and_run_traps(); 2663 check_and_run_traps();
2646 if (r != 0 && !G.flag_SIGINT) 2664 if (r != 0 && !G.flag_SIGINT)
2647 break; 2665 break;
2648 /* ^C or SIGINT: repeat */ 2666 /* ^C or SIGINT: repeat */
2649 /* bash prints ^C even on real SIGINT (non-kbd generated) */ 2667 /* bash prints ^C even on real SIGINT (non-kbd generated) */
2650 write(STDOUT_FILENO, "^C", 2); 2668 write(STDOUT_FILENO, "^C\n", 3);
2651 G.last_exitcode = 128 + SIGINT; 2669 G.last_exitcode = 128 | SIGINT;
2652 } 2670 }
2653 if (r < 0) { 2671 if (r < 0) {
2654 /* EOF/error detected */ 2672 /* EOF/error detected */
@@ -2659,9 +2677,15 @@ static int get_user_input(struct in_str *i)
2659 i->p = G.user_input_buf; 2677 i->p = G.user_input_buf;
2660 return (unsigned char)*i->p++; 2678 return (unsigned char)*i->p++;
2661# else 2679# else
2680 /* In !EDITING case, this function gets called for every char.
2681 * Buffering happens deeper in the call chain, in hfgetc(i->file).
2682 */
2683 int r;
2684
2662 for (;;) { 2685 for (;;) {
2663 G.flag_SIGINT = 0; 2686 G.flag_SIGINT = 0;
2664 if (i->last_char == '\0' || i->last_char == '\n') { 2687 if (i->last_char == '\0' || i->last_char == '\n') {
2688 const char *prompt_str = setup_prompt_string();
2665 /* Why check_and_run_traps here? Try this interactively: 2689 /* Why check_and_run_traps here? Try this interactively:
2666 * $ trap 'echo INT' INT; (sleep 2; kill -INT $$) & 2690 * $ trap 'echo INT' INT; (sleep 2; kill -INT $$) &
2667 * $ <[enter], repeatedly...> 2691 * $ <[enter], repeatedly...>
@@ -2669,19 +2693,23 @@ static int get_user_input(struct in_str *i)
2669 */ 2693 */
2670 check_and_run_traps(); 2694 check_and_run_traps();
2671 fputs(prompt_str, stdout); 2695 fputs(prompt_str, stdout);
2696 fflush_all();
2672 } 2697 }
2673 fflush_all();
2674//FIXME: here ^C or SIGINT will have effect only after <Enter>
2675 r = hfgetc(i->file); 2698 r = hfgetc(i->file);
2676 /* In !ENABLE_FEATURE_EDITING we don't use read_line_input, 2699 /* In !ENABLE_FEATURE_EDITING we don't use read_line_input,
2677 * no ^C masking happens during fgetc, no special code for ^C: 2700 * no ^C masking happens during fgetc, no special code for ^C:
2678 * it generates SIGINT as usual. 2701 * it generates SIGINT as usual.
2679 */ 2702 */
2680 check_and_run_traps(); 2703 check_and_run_traps();
2681 if (G.flag_SIGINT) 2704 if (r != '\0' && !G.flag_SIGINT)
2682 G.last_exitcode = 128 + SIGINT;
2683 if (r != '\0')
2684 break; 2705 break;
2706 if (G.flag_SIGINT) {
2707 /* ^C or SIGINT: repeat */
2708 /* bash prints ^C even on real SIGINT (non-kbd generated) */
2709 /* kernel prints "^C" itself, just print newline: */
2710 write(STDOUT_FILENO, "\n", 1);
2711 G.last_exitcode = 128 | SIGINT;
2712 }
2685 } 2713 }
2686 return r; 2714 return r;
2687# endif 2715# endif
@@ -2703,14 +2731,14 @@ static int fgetc_interactive(struct in_str *i)
2703 } 2731 }
2704 return ch; 2732 return ch;
2705} 2733}
2706#else 2734#else /* !INTERACTIVE */
2707static ALWAYS_INLINE int fgetc_interactive(struct in_str *i) 2735static ALWAYS_INLINE int fgetc_interactive(struct in_str *i)
2708{ 2736{
2709 int ch; 2737 int ch;
2710 do ch = hfgetc(i->file); while (ch == '\0'); 2738 do ch = hfgetc(i->file); while (ch == '\0');
2711 return ch; 2739 return ch;
2712} 2740}
2713#endif /* INTERACTIVE */ 2741#endif /* !INTERACTIVE */
2714 2742
2715static int i_getch(struct in_str *i) 2743static int i_getch(struct in_str *i)
2716{ 2744{
@@ -3888,7 +3916,7 @@ struct reserved_combo {
3888 char literal[6]; 3916 char literal[6];
3889 unsigned char res; 3917 unsigned char res;
3890 unsigned char assignment_flag; 3918 unsigned char assignment_flag;
3891 int flag; 3919 uint32_t flag;
3892}; 3920};
3893enum { 3921enum {
3894 FLAG_END = (1 << RES_NONE ), 3922 FLAG_END = (1 << RES_NONE ),
@@ -3921,7 +3949,7 @@ static const struct reserved_combo* match_reserved_word(o_string *word)
3921 * to turn the compound list into a command. 3949 * to turn the compound list into a command.
3922 * FLAG_START means the word must start a new compound list. 3950 * FLAG_START means the word must start a new compound list.
3923 */ 3951 */
3924 static const struct reserved_combo reserved_list[] = { 3952 static const struct reserved_combo reserved_list[] ALIGN4 = {
3925# if ENABLE_HUSH_IF 3953# if ENABLE_HUSH_IF
3926 { "!", RES_NONE, NOT_ASSIGNMENT , 0 }, 3954 { "!", RES_NONE, NOT_ASSIGNMENT , 0 },
3927 { "if", RES_IF, MAYBE_ASSIGNMENT, FLAG_THEN | FLAG_START }, 3955 { "if", RES_IF, MAYBE_ASSIGNMENT, FLAG_THEN | FLAG_START },
@@ -5263,19 +5291,19 @@ static struct pipe *parse_stream(char **pstring,
5263 5291
5264 if (heredoc_cnt) { 5292 if (heredoc_cnt) {
5265 syntax_error_unterm_str("here document"); 5293 syntax_error_unterm_str("here document");
5266 goto parse_error; 5294 goto parse_error_exitcode1;
5267 } 5295 }
5268 if (end_trigger == ')') { 5296 if (end_trigger == ')') {
5269 syntax_error_unterm_ch('('); 5297 syntax_error_unterm_ch('(');
5270 goto parse_error; 5298 goto parse_error_exitcode1;
5271 } 5299 }
5272 if (end_trigger == '}') { 5300 if (end_trigger == '}') {
5273 syntax_error_unterm_ch('{'); 5301 syntax_error_unterm_ch('{');
5274 goto parse_error; 5302 goto parse_error_exitcode1;
5275 } 5303 }
5276 5304
5277 if (done_word(&ctx)) { 5305 if (done_word(&ctx)) {
5278 goto parse_error; 5306 goto parse_error_exitcode1;
5279 } 5307 }
5280 o_free_and_set_NULL(&ctx.word); 5308 o_free_and_set_NULL(&ctx.word);
5281 done_pipe(&ctx, PIPE_SEQ); 5309 done_pipe(&ctx, PIPE_SEQ);
@@ -5345,7 +5373,7 @@ static struct pipe *parse_stream(char **pstring,
5345 while (1) { 5373 while (1) {
5346 if (ch == EOF) { 5374 if (ch == EOF) {
5347 syntax_error_unterm_ch('\''); 5375 syntax_error_unterm_ch('\'');
5348 goto parse_error; 5376 goto parse_error_exitcode1;
5349 } 5377 }
5350 nommu_addchr(&ctx.as_string, ch); 5378 nommu_addchr(&ctx.as_string, ch);
5351 if (ch == '\'') 5379 if (ch == '\'')
@@ -5424,7 +5452,7 @@ static struct pipe *parse_stream(char **pstring,
5424 /* ch == last eaten whitespace char */ 5452 /* ch == last eaten whitespace char */
5425#endif 5453#endif
5426 if (done_word(&ctx)) { 5454 if (done_word(&ctx)) {
5427 goto parse_error; 5455 goto parse_error_exitcode1;
5428 } 5456 }
5429 if (ch == '\n') { 5457 if (ch == '\n') {
5430 /* Is this a case when newline is simply ignored? 5458 /* Is this a case when newline is simply ignored?
@@ -5467,7 +5495,7 @@ static struct pipe *parse_stream(char **pstring,
5467 if (heredoc_cnt) { 5495 if (heredoc_cnt) {
5468 heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input); 5496 heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input);
5469 if (heredoc_cnt != 0) 5497 if (heredoc_cnt != 0)
5470 goto parse_error; 5498 goto parse_error_exitcode1;
5471 } 5499 }
5472 ctx.is_assignment = MAYBE_ASSIGNMENT; 5500 ctx.is_assignment = MAYBE_ASSIGNMENT;
5473 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); 5501 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
@@ -5517,7 +5545,7 @@ static struct pipe *parse_stream(char **pstring,
5517#endif 5545#endif
5518 ) { 5546 ) {
5519 if (done_word(&ctx)) { 5547 if (done_word(&ctx)) {
5520 goto parse_error; 5548 goto parse_error_exitcode1;
5521 } 5549 }
5522 done_pipe(&ctx, PIPE_SEQ); 5550 done_pipe(&ctx, PIPE_SEQ);
5523 ctx.is_assignment = MAYBE_ASSIGNMENT; 5551 ctx.is_assignment = MAYBE_ASSIGNMENT;
@@ -5538,7 +5566,7 @@ static struct pipe *parse_stream(char **pstring,
5538 /* Example: bare "{ }", "()" */ 5566 /* Example: bare "{ }", "()" */
5539 G.last_exitcode = 2; /* bash compat */ 5567 G.last_exitcode = 2; /* bash compat */
5540 syntax_error_unexpected_ch(ch); 5568 syntax_error_unexpected_ch(ch);
5541 goto parse_error2; 5569 goto parse_error;
5542 } 5570 }
5543 if (heredoc_cnt_ptr) 5571 if (heredoc_cnt_ptr)
5544 *heredoc_cnt_ptr = heredoc_cnt; 5572 *heredoc_cnt_ptr = heredoc_cnt;
@@ -5560,7 +5588,7 @@ static struct pipe *parse_stream(char **pstring,
5560 case '>': 5588 case '>':
5561 redir_fd = redirect_opt_num(&ctx.word); 5589 redir_fd = redirect_opt_num(&ctx.word);
5562 if (done_word(&ctx)) { 5590 if (done_word(&ctx)) {
5563 goto parse_error; 5591 goto parse_error_exitcode1;
5564 } 5592 }
5565 redir_style = REDIRECT_OVERWRITE; 5593 redir_style = REDIRECT_OVERWRITE;
5566 if (next == '>') { 5594 if (next == '>') {
@@ -5571,16 +5599,16 @@ static struct pipe *parse_stream(char **pstring,
5571#if 0 5599#if 0
5572 else if (next == '(') { 5600 else if (next == '(') {
5573 syntax_error(">(process) not supported"); 5601 syntax_error(">(process) not supported");
5574 goto parse_error; 5602 goto parse_error_exitcode1;
5575 } 5603 }
5576#endif 5604#endif
5577 if (parse_redirect(&ctx, redir_fd, redir_style, input)) 5605 if (parse_redirect(&ctx, redir_fd, redir_style, input))
5578 goto parse_error; 5606 goto parse_error_exitcode1;
5579 continue; /* get next char */ 5607 continue; /* get next char */
5580 case '<': 5608 case '<':
5581 redir_fd = redirect_opt_num(&ctx.word); 5609 redir_fd = redirect_opt_num(&ctx.word);
5582 if (done_word(&ctx)) { 5610 if (done_word(&ctx)) {
5583 goto parse_error; 5611 goto parse_error_exitcode1;
5584 } 5612 }
5585 redir_style = REDIRECT_INPUT; 5613 redir_style = REDIRECT_INPUT;
5586 if (next == '<') { 5614 if (next == '<') {
@@ -5597,11 +5625,11 @@ static struct pipe *parse_stream(char **pstring,
5597#if 0 5625#if 0
5598 else if (next == '(') { 5626 else if (next == '(') {
5599 syntax_error("<(process) not supported"); 5627 syntax_error("<(process) not supported");
5600 goto parse_error; 5628 goto parse_error_exitcode1;
5601 } 5629 }
5602#endif 5630#endif
5603 if (parse_redirect(&ctx, redir_fd, redir_style, input)) 5631 if (parse_redirect(&ctx, redir_fd, redir_style, input))
5604 goto parse_error; 5632 goto parse_error_exitcode1;
5605 continue; /* get next char */ 5633 continue; /* get next char */
5606 case '#': 5634 case '#':
5607 if (ctx.word.length == 0 && !ctx.word.has_quoted_part) { 5635 if (ctx.word.length == 0 && !ctx.word.has_quoted_part) {
@@ -5655,7 +5683,7 @@ static struct pipe *parse_stream(char **pstring,
5655 if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) { 5683 if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) {
5656 debug_printf_parse("parse_stream parse error: " 5684 debug_printf_parse("parse_stream parse error: "
5657 "parse_dollar returned 0 (error)\n"); 5685 "parse_dollar returned 0 (error)\n");
5658 goto parse_error; 5686 goto parse_error_exitcode1;
5659 } 5687 }
5660 continue; /* get next char */ 5688 continue; /* get next char */
5661 case '"': 5689 case '"':
@@ -5671,7 +5699,7 @@ static struct pipe *parse_stream(char **pstring,
5671 if (ctx.is_assignment == NOT_ASSIGNMENT) 5699 if (ctx.is_assignment == NOT_ASSIGNMENT)
5672 ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; 5700 ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS;
5673 if (!encode_string(&ctx.as_string, &ctx.word, input, '"')) 5701 if (!encode_string(&ctx.as_string, &ctx.word, input, '"'))
5674 goto parse_error; 5702 goto parse_error_exitcode1;
5675 ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; 5703 ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS;
5676 continue; /* get next char */ 5704 continue; /* get next char */
5677#if ENABLE_HUSH_TICK 5705#if ENABLE_HUSH_TICK
@@ -5682,7 +5710,7 @@ static struct pipe *parse_stream(char **pstring,
5682 o_addchr(&ctx.word, '`'); 5710 o_addchr(&ctx.word, '`');
5683 USE_FOR_NOMMU(pos = ctx.word.length;) 5711 USE_FOR_NOMMU(pos = ctx.word.length;)
5684 if (!add_till_backquote(&ctx.word, input, /*in_dquote:*/ 0)) 5712 if (!add_till_backquote(&ctx.word, input, /*in_dquote:*/ 0))
5685 goto parse_error; 5713 goto parse_error_exitcode1;
5686# if !BB_MMU 5714# if !BB_MMU
5687 o_addstr(&ctx.as_string, ctx.word.data + pos); 5715 o_addstr(&ctx.as_string, ctx.word.data + pos);
5688 o_addchr(&ctx.as_string, '`'); 5716 o_addchr(&ctx.as_string, '`');
@@ -5697,7 +5725,7 @@ static struct pipe *parse_stream(char **pstring,
5697 case_semi: 5725 case_semi:
5698#endif 5726#endif
5699 if (done_word(&ctx)) { 5727 if (done_word(&ctx)) {
5700 goto parse_error; 5728 goto parse_error_exitcode1;
5701 } 5729 }
5702 done_pipe(&ctx, PIPE_SEQ); 5730 done_pipe(&ctx, PIPE_SEQ);
5703#if ENABLE_HUSH_CASE 5731#if ENABLE_HUSH_CASE
@@ -5724,7 +5752,7 @@ static struct pipe *parse_stream(char **pstring,
5724 continue; /* get next char */ 5752 continue; /* get next char */
5725 case '&': 5753 case '&':
5726 if (done_word(&ctx)) { 5754 if (done_word(&ctx)) {
5727 goto parse_error; 5755 goto parse_error_exitcode1;
5728 } 5756 }
5729 if (next == '&') { 5757 if (next == '&') {
5730 ch = i_getch(input); 5758 ch = i_getch(input);
@@ -5736,7 +5764,7 @@ static struct pipe *parse_stream(char **pstring,
5736 goto new_cmd; 5764 goto new_cmd;
5737 case '|': 5765 case '|':
5738 if (done_word(&ctx)) { 5766 if (done_word(&ctx)) {
5739 goto parse_error; 5767 goto parse_error_exitcode1;
5740 } 5768 }
5741#if ENABLE_HUSH_CASE 5769#if ENABLE_HUSH_CASE
5742 if (ctx.ctx_res_w == RES_MATCH) 5770 if (ctx.ctx_res_w == RES_MATCH)
@@ -5768,7 +5796,7 @@ static struct pipe *parse_stream(char **pstring,
5768 case '{': { 5796 case '{': {
5769 int n = parse_group(&ctx, input, ch); 5797 int n = parse_group(&ctx, input, ch);
5770 if (n < 0) { 5798 if (n < 0) {
5771 goto parse_error; 5799 goto parse_error_exitcode1;
5772 } 5800 }
5773 debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n); 5801 debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n);
5774 heredoc_cnt += n; 5802 heredoc_cnt += n;
@@ -5786,16 +5814,16 @@ static struct pipe *parse_stream(char **pstring,
5786 * and it will match } earlier (not here). */ 5814 * and it will match } earlier (not here). */
5787 G.last_exitcode = 2; 5815 G.last_exitcode = 2;
5788 syntax_error_unexpected_ch(ch); 5816 syntax_error_unexpected_ch(ch);
5789 goto parse_error2; 5817 goto parse_error;
5790 default: 5818 default:
5791 if (HUSH_DEBUG) 5819 if (HUSH_DEBUG)
5792 bb_error_msg_and_die("BUG: unexpected %c", ch); 5820 bb_error_msg_and_die("BUG: unexpected %c", ch);
5793 } 5821 }
5794 } /* while (1) */ 5822 } /* while (1) */
5795 5823
5796 parse_error: 5824 parse_error_exitcode1:
5797 G.last_exitcode = 1; 5825 G.last_exitcode = 1;
5798 parse_error2: 5826 parse_error:
5799 { 5827 {
5800 struct parse_context *pctx; 5828 struct parse_context *pctx;
5801 IF_HAS_KEYWORDS(struct parse_context *p2;) 5829 IF_HAS_KEYWORDS(struct parse_context *p2;)
@@ -6490,9 +6518,11 @@ static NOINLINE int expand_one_var(o_string *output, int n,
6490 * Word is expanded to produce a glob pattern. 6518 * Word is expanded to produce a glob pattern.
6491 * Then var's value is matched to it and matching part removed. 6519 * Then var's value is matched to it and matching part removed.
6492 */ 6520 */
6493//FIXME: ${x#...${...}...} 6521 /* bash compat: if x is "" and no shrinking of it is possible,
6494//should evaluate inner ${...} even if x is "" and no shrinking of it is possible - 6522 * inner ${...} is not evaluated. Example:
6495//inner ${...} may have side effects! 6523 * unset b; : ${a%${b=B}}; echo $b
6524 * assignment b=B only happens if $a is not "".
6525 */
6496 if (val && val[0]) { 6526 if (val && val[0]) {
6497 char *t; 6527 char *t;
6498 char *exp_exp_word; 6528 char *exp_exp_word;
@@ -6531,7 +6561,12 @@ static NOINLINE int expand_one_var(o_string *output, int n,
6531 * and if // is used, it is encoded as \: 6561 * and if // is used, it is encoded as \:
6532 * var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL> 6562 * var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL>
6533 */ 6563 */
6534 if (val && val[0]) { 6564 /* bash compat: if var is "", both pattern and repl
6565 * are still evaluated, if it is unset, then not:
6566 * unset b; a=; : ${a/z/${b=3}}; echo $b # b=3
6567 * unset b; unset a; : ${a/z/${b=3}}; echo $b # b not set
6568 */
6569 if (val /*&& val[0]*/) {
6535 /* pattern uses non-standard expansion. 6570 /* pattern uses non-standard expansion.
6536 * repl should be unbackslashed and globbed 6571 * repl should be unbackslashed and globbed
6537 * by the usual expansion rules: 6572 * by the usual expansion rules:
@@ -6567,8 +6602,9 @@ static NOINLINE int expand_one_var(o_string *output, int n,
6567 free(pattern); 6602 free(pattern);
6568 free(repl); 6603 free(repl);
6569 } else { 6604 } else {
6570 /* Empty variable always gives nothing */ 6605 /* Unset variable always gives nothing */
6571 // "v=''; echo ${v/*/w}" prints "", not "w" 6606 // a=; echo ${a/*/w} # "w"
6607 // unset a; echo ${a/*/w} # ""
6572 /* Just skip "replace" part */ 6608 /* Just skip "replace" part */
6573 *p++ = SPECIAL_VAR_SYMBOL; 6609 *p++ = SPECIAL_VAR_SYMBOL;
6574 p = strchr(p, SPECIAL_VAR_SYMBOL); 6610 p = strchr(p, SPECIAL_VAR_SYMBOL);
@@ -6583,40 +6619,48 @@ static NOINLINE int expand_one_var(o_string *output, int n,
6583 * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL> 6619 * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL>
6584 */ 6620 */
6585 arith_t beg, len; 6621 arith_t beg, len;
6622 unsigned vallen;
6586 const char *errmsg; 6623 const char *errmsg;
6587 6624
6588 beg = expand_and_evaluate_arith(exp_word, &errmsg); 6625 beg = expand_and_evaluate_arith(exp_word, &errmsg);
6589 if (errmsg) 6626 if (errmsg)
6590 goto arith_err; 6627 goto empty_result;
6591 debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg); 6628 debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg);
6592 *p++ = SPECIAL_VAR_SYMBOL; 6629 *p++ = SPECIAL_VAR_SYMBOL;
6593 exp_word = p; 6630 exp_word = p;
6594 p = strchr(p, SPECIAL_VAR_SYMBOL); 6631 p = strchr(p, SPECIAL_VAR_SYMBOL);
6595 *p = '\0'; 6632 *p = '\0';
6596 len = expand_and_evaluate_arith(exp_word, &errmsg); 6633 vallen = val ? strlen(val) : 0;
6597 if (errmsg)
6598 goto arith_err;
6599 debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
6600 if (beg < 0) { 6634 if (beg < 0) {
6601 /* negative beg counts from the end */ 6635 /* negative beg counts from the end */
6602 beg = (arith_t)strlen(val) + beg; 6636 beg = (arith_t)vallen + beg;
6603 if (beg < 0) /* ${v: -999999} is "" */ 6637 }
6604 beg = len = 0; 6638 /* If expansion will be empty, do not even evaluate len */
6639 if (!val || beg < 0 || beg > vallen) {
6640 /* Why > vallen, not >=? bash:
6641 * unset b; a=ab; : ${a:2:${b=3}}; echo $b # "", b=3 (!!!)
6642 * unset b; a=a; : ${a:2:${b=3}}; echo $b # "", b not set
6643 */
6644 goto empty_result;
6605 } 6645 }
6646 len = expand_and_evaluate_arith(exp_word, &errmsg);
6647 if (errmsg)
6648 goto empty_result;
6649 debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
6606 debug_printf_varexp("from val:'%s'\n", val); 6650 debug_printf_varexp("from val:'%s'\n", val);
6607 if (len < 0) { 6651 if (len < 0) {
6608 /* in bash, len=-n means strlen()-n */ 6652 /* in bash, len=-n means strlen()-n */
6609 len = (arith_t)strlen(val) - beg + len; 6653 len = (arith_t)vallen - beg + len;
6610 if (len < 0) /* bash compat */ 6654 if (len < 0) /* bash compat */
6611 msg_and_die_if_script("%s: substring expression < 0", var); 6655 msg_and_die_if_script("%s: substring expression < 0", var);
6612 } 6656 }
6613 if (len <= 0 || !val || beg >= strlen(val)) { 6657 if (len <= 0 || !val /*|| beg >= vallen*/) {
6614 arith_err: 6658 empty_result:
6615 val = NULL; 6659 val = NULL;
6616 } else { 6660 } else {
6617 /* Paranoia. What if user entered 9999999999999 6661 /* Paranoia. What if user entered 9999999999999
6618 * which fits in arith_t but not int? */ 6662 * which fits in arith_t but not int? */
6619 if (len >= INT_MAX) 6663 if (len > INT_MAX)
6620 len = INT_MAX; 6664 len = INT_MAX;
6621 val = to_be_freed = xstrndup(val + beg, len); 6665 val = to_be_freed = xstrndup(val + beg, len);
6622 } 6666 }
@@ -6650,12 +6694,13 @@ static NOINLINE int expand_one_var(o_string *output, int n,
6650 * 6694 *
6651 * Word-splitting and single quote behavior: 6695 * Word-splitting and single quote behavior:
6652 * 6696 *
6653 * $ f() { for i; do echo "|$i|"; done; }; 6697 * $ f() { for i; do echo "|$i|"; done; }
6654 * 6698 *
6655 * $ x=; f ${x:?'x y' z} 6699 * $ x=; f ${x:?'x y' z}; echo $?
6656 * bash: x: x y z #BUG: does not abort, ${} results in empty expansion 6700 * bash: x: x y z # neither f nor "echo $?" executes
6701 * (if interactive, bash does not exit, but merely aborts to prompt. $? is set to 1)
6657 * $ x=; f "${x:?'x y' z}" 6702 * $ x=; f "${x:?'x y' z}"
6658 * bash: x: x y z # dash prints: dash: x: 'x y' z #BUG: does not abort, ${} results in "" 6703 * bash: x: x y z # dash prints: dash: x: 'x y' z
6659 * 6704 *
6660 * $ x=; f ${x:='x y' z} 6705 * $ x=; f ${x:='x y' z}
6661 * |x| 6706 * |x|
@@ -7743,7 +7788,11 @@ static void restore_redirects(struct squirrel *sq)
7743 free(sq); 7788 free(sq);
7744 } 7789 }
7745 if (G.HFILE_stdin 7790 if (G.HFILE_stdin
7746 && G.HFILE_stdin->fd != STDIN_FILENO 7791 && G.HFILE_stdin->fd > STDIN_FILENO
7792 /* we compare > STDIN, not == STDIN, since hfgetc()
7793 * closes fd and sets ->fd to -1 if EOF is reached.
7794 * Testcase: echo 'pwd' | hush
7795 */
7747 ) { 7796 ) {
7748 /* Testcase: interactive "read r <FILE; echo $r; read r; echo $r". 7797 /* Testcase: interactive "read r <FILE; echo $r; read r; echo $r".
7749 * Redirect moves ->fd to e.g. 10, 7798 * Redirect moves ->fd to e.g. 10,
@@ -8136,7 +8185,6 @@ static void exec_function(char ***to_free,
8136 8185
8137 /* On MMU, funcp->body is always non-NULL */ 8186 /* On MMU, funcp->body is always non-NULL */
8138 n = run_list(funcp->body); 8187 n = run_list(funcp->body);
8139 fflush_all();
8140 _exit(n); 8188 _exit(n);
8141# else 8189# else
8142//? close_saved_fds_and_FILE_fds(); 8190//? close_saved_fds_and_FILE_fds();
@@ -8211,7 +8259,6 @@ static void exec_builtin(char ***to_free,
8211{ 8259{
8212#if BB_MMU 8260#if BB_MMU
8213 int rcode; 8261 int rcode;
8214 fflush_all();
8215//? close_saved_fds_and_FILE_fds(); 8262//? close_saved_fds_and_FILE_fds();
8216 rcode = x->b_function(argv); 8263 rcode = x->b_function(argv);
8217 fflush_all(); 8264 fflush_all();
@@ -8715,6 +8762,7 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status)
8715 */ 8762 */
8716 if (WIFSIGNALED(status)) { 8763 if (WIFSIGNALED(status)) {
8717 int sig = WTERMSIG(status); 8764 int sig = WTERMSIG(status);
8765#if ENABLE_HUSH_JOB
8718 if (G.run_list_level == 1 8766 if (G.run_list_level == 1
8719 /* ^^^^^ Do not print in nested contexts, example: 8767 /* ^^^^^ Do not print in nested contexts, example:
8720 * echo `sleep 1; sh -c 'kill -9 $$'` - prints "137", NOT "Killed 137" 8768 * echo `sleep 1; sh -c 'kill -9 $$'` - prints "137", NOT "Killed 137"
@@ -8724,10 +8772,12 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status)
8724 /* strsignal() is for bash compat. ~600 bloat versus bbox's get_signame() */ 8772 /* strsignal() is for bash compat. ~600 bloat versus bbox's get_signame() */
8725 puts(sig == SIGINT || sig == SIGPIPE ? "" : strsignal(sig)); 8773 puts(sig == SIGINT || sig == SIGPIPE ? "" : strsignal(sig));
8726 } 8774 }
8775#endif
8727 /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ 8776 /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */
8728 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? 8777 /* MIPS has 128 sigs (1..128), if sig==128,
8729 * Maybe we need to use sig | 128? */ 8778 * 128 + sig would result in exitcode 256 -> 0!
8730 ex = sig + 128; 8779 */
8780 ex = 128 | sig;
8731 } 8781 }
8732 fg_pipe->cmds[i].cmd_exitcode = ex; 8782 fg_pipe->cmds[i].cmd_exitcode = ex;
8733 } else { 8783 } else {
@@ -8774,7 +8824,8 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status)
8774 /* child exited */ 8824 /* child exited */
8775 int rcode = WEXITSTATUS(status); 8825 int rcode = WEXITSTATUS(status);
8776 if (WIFSIGNALED(status)) 8826 if (WIFSIGNALED(status))
8777 rcode = 128 + WTERMSIG(status); 8827 /* NB: not 128 + sig, MIPS has sig 128 */
8828 rcode = 128 | WTERMSIG(status);
8778 pi->cmds[i].cmd_exitcode = rcode; 8829 pi->cmds[i].cmd_exitcode = rcode;
8779 if (G.last_bg_pid == pi->cmds[i].pid) 8830 if (G.last_bg_pid == pi->cmds[i].pid)
8780 G.last_bg_pid_exitcode = rcode; 8831 G.last_bg_pid_exitcode = rcode;
@@ -8894,10 +8945,10 @@ static int checkjobs(struct pipe *fg_pipe, pid_t waitfor_pid)
8894 debug_printf_exec("childpid==waitfor_pid:%d status:0x%08x\n", childpid, status); 8945 debug_printf_exec("childpid==waitfor_pid:%d status:0x%08x\n", childpid, status);
8895 rcode = WEXITSTATUS(status); 8946 rcode = WEXITSTATUS(status);
8896 if (WIFSIGNALED(status)) 8947 if (WIFSIGNALED(status))
8897 rcode = 128 + WTERMSIG(status); 8948 rcode = 128 | WTERMSIG(status);
8898 if (WIFSTOPPED(status)) 8949 if (WIFSTOPPED(status))
8899 /* bash: "cmd & wait $!" and cmd stops: $? = 128 + stopsig */ 8950 /* bash: "cmd & wait $!" and cmd stops: $? = 128 | stopsig */
8900 rcode = 128 + WSTOPSIG(status); 8951 rcode = 128 | WSTOPSIG(status);
8901 rcode++; 8952 rcode++;
8902 break; /* "wait PID" called us, give it exitcode+1 */ 8953 break; /* "wait PID" called us, give it exitcode+1 */
8903 } 8954 }
@@ -9287,7 +9338,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
9287 * during builtin/nofork. 9338 * during builtin/nofork.
9288 */ 9339 */
9289 if (sigismember(&G.pending_set, SIGINT)) 9340 if (sigismember(&G.pending_set, SIGINT))
9290 rcode = 128 + SIGINT; 9341 rcode = 128 | SIGINT;
9291 } 9342 }
9292 free(argv_expanded); 9343 free(argv_expanded);
9293 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) 9344 IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
@@ -9972,11 +10023,14 @@ static int set_mode(int state, char mode, const char *o_opt)
9972int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 10023int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
9973int hush_main(int argc, char **argv) 10024int hush_main(int argc, char **argv)
9974{ 10025{
10026 pid_t cached_getpid;
9975 enum { 10027 enum {
9976 OPT_login = (1 << 0), 10028 OPT_login = (1 << 0),
9977 }; 10029 };
9978 unsigned flags; 10030 unsigned flags;
9979 unsigned builtin_argc; 10031#if !BB_MMU
10032 unsigned builtin_argc = 0;
10033#endif
9980 char **e; 10034 char **e;
9981 struct variable *cur_var; 10035 struct variable *cur_var;
9982 struct variable *shell_ver; 10036 struct variable *shell_ver;
@@ -9998,6 +10052,10 @@ int hush_main(int argc, char **argv)
9998 G.argv0_for_re_execing = argv[0]; 10052 G.argv0_for_re_execing = argv[0];
9999#endif 10053#endif
10000 10054
10055 cached_getpid = getpid(); /* for tcsetpgrp() during init */
10056 G.root_pid = cached_getpid; /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */
10057 G.root_ppid = getppid(); /* for $PPID (NOMMU can override) */
10058
10001 /* Deal with HUSH_VERSION */ 10059 /* Deal with HUSH_VERSION */
10002 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); 10060 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
10003 unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ 10061 unsetenv("HUSH_VERSION"); /* in case it exists in initial env */
@@ -10080,6 +10138,17 @@ int hush_main(int argc, char **argv)
10080 * PS4='+ ' 10138 * PS4='+ '
10081 */ 10139 */
10082 10140
10141#if NUM_SCRIPTS > 0
10142 if (argc < 0) {
10143 char *script = get_script_content(-argc - 1);
10144 G.global_argv = argv;
10145 G.global_argc = string_array_len(argv);
10146 //install_special_sighandlers(); - needed?
10147 parse_and_run_string(script);
10148 goto final_return;
10149 }
10150#endif
10151
10083 /* Initialize some more globals to non-zero values */ 10152 /* Initialize some more globals to non-zero values */
10084 die_func = restore_ttypgrp_and__exit; 10153 die_func = restore_ttypgrp_and__exit;
10085 10154
@@ -10093,17 +10162,9 @@ int hush_main(int argc, char **argv)
10093 /* Parse options */ 10162 /* Parse options */
10094 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ 10163 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */
10095 flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; 10164 flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0;
10096 builtin_argc = 0;
10097#if NUM_SCRIPTS > 0
10098 if (argc < 0) {
10099 optarg = get_script_content(-argc - 1);
10100 optind = 0;
10101 argc = string_array_len(argv);
10102 goto run_script;
10103 }
10104#endif
10105 while (1) { 10165 while (1) {
10106 int opt = getopt(argc, argv, "+c:exinsl" 10166 int opt = getopt(argc, argv, "+" /* stop at 1st non-option */
10167 "cexinsl"
10107#if !BB_MMU 10168#if !BB_MMU
10108 "<:$:R:V:" 10169 "<:$:R:V:"
10109# if ENABLE_HUSH_FUNCTIONS 10170# if ENABLE_HUSH_FUNCTIONS
@@ -10115,50 +10176,11 @@ int hush_main(int argc, char **argv)
10115 break; 10176 break;
10116 switch (opt) { 10177 switch (opt) {
10117 case 'c': 10178 case 'c':
10118 /* Possibilities: 10179 /* Note: -c is not an option with param!
10119 * sh ... -c 'script' 10180 * "hush -c -l SCRIPT" is valid. "hush -cSCRIPT" is not.
10120 * sh ... -c 'script' ARG0 [ARG1...]
10121 * On NOMMU, if builtin_argc != 0,
10122 * sh ... -c 'builtin' BARGV... "" ARG0 [ARG1...]
10123 * "" needs to be replaced with NULL
10124 * and BARGV vector fed to builtin function.
10125 * Note: the form without ARG0 never happens:
10126 * sh ... -c 'builtin' BARGV... ""
10127 */ 10181 */
10128#if NUM_SCRIPTS > 0
10129 run_script:
10130#endif
10131 if (!G.root_pid) {
10132 G.root_pid = getpid();
10133 G.root_ppid = getppid();
10134 }
10135 G.global_argv = argv + optind;
10136 G.global_argc = argc - optind;
10137 if (builtin_argc) {
10138 /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */
10139 const struct built_in_command *x;
10140
10141 install_special_sighandlers();
10142 x = find_builtin(optarg);
10143 if (x) { /* paranoia */
10144 G.global_argc -= builtin_argc; /* skip [BARGV...] "" */
10145 G.global_argv += builtin_argc;
10146 G.global_argv[-1] = NULL; /* replace "" */
10147 fflush_all();
10148 G.last_exitcode = x->b_function(argv + optind - 1);
10149 }
10150 goto final_return;
10151 }
10152 G.opt_c = 1; 10182 G.opt_c = 1;
10153 if (!G.global_argv[0]) { 10183 break;
10154 /* -c 'script' (no params): prevent empty $0 */
10155 G.global_argv--; /* points to argv[i] of 'script' */
10156 G.global_argv[0] = argv[0];
10157 G.global_argc++;
10158 } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */
10159 install_special_sighandlers();
10160 parse_and_run_string(optarg);
10161 goto final_return;
10162 case 'i': 10184 case 'i':
10163 /* Well, we cannot just declare interactiveness, 10185 /* Well, we cannot just declare interactiveness,
10164 * we have to have some stuff (ctty, etc) */ 10186 * we have to have some stuff (ctty, etc) */
@@ -10205,6 +10227,11 @@ int hush_main(int argc, char **argv)
10205 optarg++; 10227 optarg++;
10206 G.depth_of_loop = bb_strtou(optarg, &optarg, 16); 10228 G.depth_of_loop = bb_strtou(optarg, &optarg, 16);
10207# endif 10229# endif
10230 /* Suppress "killed by signal" message, -$ hack is used
10231 * for subshells: echo `sh -c 'kill -9 $$'`
10232 * should be silent.
10233 */
10234 IF_HUSH_JOB(G.run_list_level = 1;)
10208# if ENABLE_HUSH_FUNCTIONS 10235# if ENABLE_HUSH_FUNCTIONS
10209 /* nommu uses re-exec trick for "... | func | ...", 10236 /* nommu uses re-exec trick for "... | func | ...",
10210 * should allow "return". 10237 * should allow "return".
@@ -10229,19 +10256,14 @@ int hush_main(int argc, char **argv)
10229 } 10256 }
10230# endif 10257# endif
10231#endif 10258#endif
10232 case 'n': 10259 /*case '?': invalid option encountered (set_mode('?') will fail) */
10233 case 'x': 10260 /*case 'n':*/
10234 case 'e': 10261 /*case 'x':*/
10262 /*case 'e':*/
10263 default:
10235 if (set_mode(1, opt, NULL) == 0) /* no error */ 10264 if (set_mode(1, opt, NULL) == 0) /* no error */
10236 break; 10265 break;
10237 default:
10238#ifndef BB_VER
10239 fprintf(stderr, "Usage: sh [FILE]...\n"
10240 " or: sh -c command [args]...\n\n");
10241 exit(EXIT_FAILURE);
10242#else
10243 bb_show_usage(); 10266 bb_show_usage();
10244#endif
10245 } 10267 }
10246 } /* option parsing loop */ 10268 } /* option parsing loop */
10247 10269
@@ -10250,16 +10272,14 @@ int hush_main(int argc, char **argv)
10250 G.global_argv = argv + (optind - 1); 10272 G.global_argv = argv + (optind - 1);
10251 G.global_argv[0] = argv[0]; 10273 G.global_argv[0] = argv[0];
10252 10274
10253 if (!G.root_pid) {
10254 G.root_pid = getpid();
10255 G.root_ppid = getppid();
10256 }
10257
10258 /* If we are login shell... */ 10275 /* If we are login shell... */
10259 if (flags & OPT_login) { 10276 if (flags & OPT_login) {
10277 const char *hp = NULL;
10260 HFILE *input; 10278 HFILE *input;
10279
10261 debug_printf("sourcing /etc/profile\n"); 10280 debug_printf("sourcing /etc/profile\n");
10262 input = hfopen("/etc/profile"); 10281 input = hfopen("/etc/profile");
10282 run_profile:
10263 if (input != NULL) { 10283 if (input != NULL) {
10264 install_special_sighandlers(); 10284 install_special_sighandlers();
10265 parse_and_run_file(input); 10285 parse_and_run_file(input);
@@ -10272,6 +10292,64 @@ int hush_main(int argc, char **argv)
10272 * bash also sources ~/.bash_logout on exit. 10292 * bash also sources ~/.bash_logout on exit.
10273 * If called as sh, skips .bash_XXX files. 10293 * If called as sh, skips .bash_XXX files.
10274 */ 10294 */
10295 if (!hp) { /* unless we looped on the "goto" already */
10296 hp = get_local_var_value("HOME");
10297 if (hp && hp[0]) {
10298 debug_printf("sourcing ~/.profile\n");
10299 hp = concat_path_file(hp, ".profile");
10300 input = hfopen(hp);
10301 free((char*)hp);
10302 goto run_profile;
10303 }
10304 }
10305 }
10306
10307 /* -c takes effect *after* -l */
10308 if (G.opt_c) {
10309 /* Possibilities:
10310 * sh ... -c 'script'
10311 * sh ... -c 'script' ARG0 [ARG1...]
10312 * On NOMMU, if builtin_argc != 0,
10313 * sh ... -c 'builtin' BARGV... "" ARG0 [ARG1...]
10314 * "" needs to be replaced with NULL
10315 * and BARGV vector fed to builtin function.
10316 * Note: the form without ARG0 never happens:
10317 * sh ... -c 'builtin' BARGV... ""
10318 */
10319 char *script;
10320
10321 install_special_sighandlers();
10322
10323 G.global_argc--;
10324 G.global_argv++;
10325#if !BB_MMU
10326 if (builtin_argc) {
10327 /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */
10328 const struct built_in_command *x;
10329 x = find_builtin(G.global_argv[0]);
10330 if (x) { /* paranoia */
10331 argv = G.global_argv;
10332 G.global_argc -= builtin_argc + 1; /* skip [BARGV...] "" */
10333 G.global_argv += builtin_argc + 1;
10334 G.global_argv[-1] = NULL; /* replace "" */
10335 G.last_exitcode = x->b_function(argv);
10336 }
10337 goto final_return;
10338 }
10339#endif
10340
10341 script = G.global_argv[0];
10342 if (!script)
10343 bb_error_msg_and_die(bb_msg_requires_arg, "-c");
10344 if (!G.global_argv[1]) {
10345 /* -c 'script' (no params): prevent empty $0 */
10346 G.global_argv[0] = argv[0];
10347 } else { /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */
10348 G.global_argc--;
10349 G.global_argv++;
10350 }
10351 parse_and_run_string(script);
10352 goto final_return;
10275 } 10353 }
10276 10354
10277 /* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */ 10355 /* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */
@@ -10363,7 +10441,7 @@ int hush_main(int argc, char **argv)
10363 * (bash, too, does this only if ctty is available) */ 10441 * (bash, too, does this only if ctty is available) */
10364 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ 10442 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
10365 /* Grab control of the terminal */ 10443 /* Grab control of the terminal */
10366 tcsetpgrp(G_interactive_fd, getpid()); 10444 tcsetpgrp(G_interactive_fd, cached_getpid);
10367 } 10445 }
10368 enable_restore_tty_pgrp_on_exit(); 10446 enable_restore_tty_pgrp_on_exit();
10369 10447
@@ -10456,7 +10534,7 @@ static int FAST_FUNC builtin_true(char **argv UNUSED_PARAM)
10456} 10534}
10457 10535
10458#if ENABLE_HUSH_TEST || ENABLE_HUSH_ECHO || ENABLE_HUSH_PRINTF || ENABLE_HUSH_KILL 10536#if ENABLE_HUSH_TEST || ENABLE_HUSH_ECHO || ENABLE_HUSH_PRINTF || ENABLE_HUSH_KILL
10459static int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv)) 10537static NOINLINE int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv))
10460{ 10538{
10461 int argc = string_array_len(argv); 10539 int argc = string_array_len(argv);
10462 return applet_main_func(argc, argv); 10540 return applet_main_func(argc, argv);
@@ -11662,7 +11740,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid
11662 sig = check_and_run_traps(); 11740 sig = check_and_run_traps();
11663 if (sig /*&& sig != SIGCHLD - always true */) { 11741 if (sig /*&& sig != SIGCHLD - always true */) {
11664 /* Do this for any (non-ignored) signal, not only for ^C */ 11742 /* Do this for any (non-ignored) signal, not only for ^C */
11665 ret = 128 + sig; 11743 ret = 128 | sig;
11666 break; 11744 break;
11667 } 11745 }
11668 /* SIGCHLD, or no signal, or ignored one, such as SIGQUIT. Repeat */ 11746 /* SIGCHLD, or no signal, or ignored one, such as SIGQUIT. Repeat */
@@ -11762,7 +11840,7 @@ static int FAST_FUNC builtin_wait(char **argv)
11762 process_wait_result(NULL, pid, status); 11840 process_wait_result(NULL, pid, status);
11763 ret = WEXITSTATUS(status); 11841 ret = WEXITSTATUS(status);
11764 if (WIFSIGNALED(status)) 11842 if (WIFSIGNALED(status))
11765 ret = 128 + WTERMSIG(status); 11843 ret = 128 | WTERMSIG(status);
11766 } 11844 }
11767 } while (*++argv); 11845 } while (*++argv);
11768 11846
diff --git a/shell/hush_test/hush-misc/piped_input.right b/shell/hush_test/hush-misc/piped_input.right
new file mode 100644
index 000000000..7b8bf6758
--- /dev/null
+++ b/shell/hush_test/hush-misc/piped_input.right
@@ -0,0 +1,2 @@
1TEST
2One:1
diff --git a/shell/hush_test/hush-misc/piped_input.tests b/shell/hush_test/hush-misc/piped_input.tests
new file mode 100755
index 000000000..929fec0db
--- /dev/null
+++ b/shell/hush_test/hush-misc/piped_input.tests
@@ -0,0 +1,3 @@
1exec 2>&1
2echo 'echo TEST; false' | $THIS_SH
3echo One:$?
diff --git a/shell/hush_test/hush-vars/var_bash_repl_empty_var.right b/shell/hush_test/hush-vars/var_bash_repl_empty_var.right
index 892916783..a8d1a3bef 100644
--- a/shell/hush_test/hush-vars/var_bash_repl_empty_var.right
+++ b/shell/hush_test/hush-vars/var_bash_repl_empty_var.right
@@ -1,2 +1,3 @@
1 1
2w
2Ok:0 3Ok:0
diff --git a/shell/hush_test/hush-vars/var_bash_repl_empty_var.tests b/shell/hush_test/hush-vars/var_bash_repl_empty_var.tests
index 73a43d38e..22aaba560 100755
--- a/shell/hush_test/hush-vars/var_bash_repl_empty_var.tests
+++ b/shell/hush_test/hush-vars/var_bash_repl_empty_var.tests
@@ -1,3 +1,5 @@
1unset v
2echo ${v/*/w}
1v='' 3v=''
2echo ${v/*/w} 4echo ${v/*/w}
3echo Ok:$? 5echo Ok:$?
diff --git a/shell/shell_common.c b/shell/shell_common.c
index a6ee60851..1897fee3b 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -393,12 +393,18 @@ struct limits {
393 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ 393 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
394}; 394};
395 395
396static const struct limits limits_tbl[] = { 396/* Order of entries matches order in which bash prints "ulimit -a" */
397static const struct limits limits_tbl[] ALIGN2 = {
397 { RLIMIT_CORE, 9, }, // -c 398 { RLIMIT_CORE, 9, }, // -c
398 { RLIMIT_DATA, 10, }, // -d 399 { RLIMIT_DATA, 10, }, // -d
400#ifdef RLIMIT_NICE
399 { RLIMIT_NICE, 0, }, // -e 401 { RLIMIT_NICE, 0, }, // -e
400 { RLIMIT_FSIZE, 9, }, // -f
401#define LIMIT_F_IDX 3 402#define LIMIT_F_IDX 3
403#else
404/* for example, Hurd */
405#define LIMIT_F_IDX 2
406#endif
407 { RLIMIT_FSIZE, 9, }, // -f
402#ifdef RLIMIT_SIGPENDING 408#ifdef RLIMIT_SIGPENDING
403 { RLIMIT_SIGPENDING, 0, }, // -i 409 { RLIMIT_SIGPENDING, 0, }, // -i
404#endif 410#endif
@@ -433,13 +439,16 @@ static const struct limits limits_tbl[] = {
433 { RLIMIT_LOCKS, 0, }, // -x 439 { RLIMIT_LOCKS, 0, }, // -x
434#endif 440#endif
435}; 441};
436// bash also shows: 442// 1) bash also shows:
437//pipe size (512 bytes, -p) 8 443//pipe size (512 bytes, -p) 8
444// 2) RLIMIT_RTTIME ("timeout for RT tasks in us") is not in the table
438 445
439static const char limits_help[] ALIGN1 = 446static const char limits_help[] ALIGN1 =
440 "core file size (blocks)" // -c 447 "core file size (blocks)" // -c
441 "\0""data seg size (kb)" // -d 448 "\0""data seg size (kb)" // -d
449#ifdef RLIMIT_NICE
442 "\0""scheduling priority" // -e 450 "\0""scheduling priority" // -e
451#endif
443 "\0""file size (blocks)" // -f 452 "\0""file size (blocks)" // -f
444#ifdef RLIMIT_SIGPENDING 453#ifdef RLIMIT_SIGPENDING
445 "\0""pending signals" // -i 454 "\0""pending signals" // -i
@@ -479,7 +488,9 @@ static const char limits_help[] ALIGN1 =
479static const char limit_chars[] ALIGN1 = 488static const char limit_chars[] ALIGN1 =
480 "c" 489 "c"
481 "d" 490 "d"
491#ifdef RLIMIT_NICE
482 "e" 492 "e"
493#endif
483 "f" 494 "f"
484#ifdef RLIMIT_SIGPENDING 495#ifdef RLIMIT_SIGPENDING
485 "i" 496 "i"
@@ -520,7 +531,9 @@ static const char limit_chars[] ALIGN1 =
520static const char ulimit_opt_string[] ALIGN1 = "-HSa" 531static const char ulimit_opt_string[] ALIGN1 = "-HSa"
521 "c::" 532 "c::"
522 "d::" 533 "d::"
534#ifdef RLIMIT_NICE
523 "e::" 535 "e::"
536#endif
524 "f::" 537 "f::"
525#ifdef RLIMIT_SIGPENDING 538#ifdef RLIMIT_SIGPENDING
526 "i::" 539 "i::"
@@ -737,7 +750,7 @@ shell_builtin_ulimit(char **argv)
737 750
738 if (opt_cnt == 0) { 751 if (opt_cnt == 0) {
739 /* "bare ulimit": treat it as if it was -f */ 752 /* "bare ulimit": treat it as if it was -f */
740 getrlimit(limits_tbl[LIMIT_F_IDX].cmd, &limit); 753 getrlimit(RLIMIT_FSIZE, &limit);
741 printlim(opts, &limit, &limits_tbl[LIMIT_F_IDX]); 754 printlim(opts, &limit, &limits_tbl[LIMIT_F_IDX]);
742 } 755 }
743 756
diff --git a/sysklogd/klogd.c b/sysklogd/klogd.c
index c0ec1c0bf..82596bc0b 100644
--- a/sysklogd/klogd.c
+++ b/sysklogd/klogd.c
@@ -100,7 +100,7 @@ static void klogd_close(void)
100#else 100#else
101 101
102# ifndef _PATH_KLOG 102# ifndef _PATH_KLOG
103# ifdef __GNU__ 103# if defined(__GNU__) || defined (__FreeBSD__)
104# define _PATH_KLOG "/dev/klog" 104# define _PATH_KLOG "/dev/klog"
105# else 105# else
106# error "your system's _PATH_KLOG is unknown" 106# error "your system's _PATH_KLOG is unknown"
diff --git a/sysklogd/logger.c b/sysklogd/logger.c
index 4d692d6fc..9422b6ea7 100644
--- a/sysklogd/logger.c
+++ b/sysklogd/logger.c
@@ -21,7 +21,7 @@
21//kbuild:lib-$(CONFIG_LOGGER) += syslogd_and_logger.o 21//kbuild:lib-$(CONFIG_LOGGER) += syslogd_and_logger.o
22 22
23//usage:#define logger_trivial_usage 23//usage:#define logger_trivial_usage
24//usage: "[OPTIONS] [MESSAGE]" 24//usage: "[-s] [-t TAG] [-p PRIO] [MESSAGE]"
25//usage:#define logger_full_usage "\n\n" 25//usage:#define logger_full_usage "\n\n"
26//usage: "Write MESSAGE (or stdin) to syslog\n" 26//usage: "Write MESSAGE (or stdin) to syslog\n"
27//usage: "\n -s Log to stderr as well as the system log" 27//usage: "\n -s Log to stderr as well as the system log"
diff --git a/sysklogd/logread.c b/sysklogd/logread.c
index 1e1f1347f..b52dc9cac 100644
--- a/sysklogd/logread.c
+++ b/sysklogd/logread.c
@@ -180,7 +180,7 @@ int logread_main(int argc UNUSED_PARAM, char **argv)
180 if (cur == shbuf_tail) { 180 if (cur == shbuf_tail) {
181 sem_up(log_semid); 181 sem_up(log_semid);
182 fflush_all(); 182 fflush_all();
183 sleep(1); /* TODO: replace me with a sleep_on */ 183 sleep1(); /* TODO: replace me with a sleep_on */
184 continue; 184 continue;
185 } 185 }
186 } 186 }
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index f61da9de5..6ddfd771a 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -842,7 +842,7 @@ static void timestamp_and_log(int pri, char *msg, int len)
842#if ENABLE_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS 842#if ENABLE_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS
843 if (!timestamp) { 843 if (!timestamp) {
844 struct timeval tv; 844 struct timeval tv;
845 gettimeofday(&tv, NULL); 845 xgettimeofday(&tv);
846 now = tv.tv_sec; 846 now = tv.tv_sec;
847 timestamp = ctime(&now) + 4; /* skip day of week */ 847 timestamp = ctime(&now) + 4; /* skip day of week */
848 /* overwrite year by milliseconds, zero terminate */ 848 /* overwrite year by milliseconds, zero terminate */
@@ -1034,6 +1034,7 @@ static void do_syslogd(void)
1034 kmsg_init(); 1034 kmsg_init();
1035 1035
1036 timestamp_and_log_internal("syslogd started: BusyBox v" BB_VER); 1036 timestamp_and_log_internal("syslogd started: BusyBox v" BB_VER);
1037 write_pidfile_std_path_and_ext("syslogd");
1037 1038
1038 while (!bb_got_signal) { 1039 while (!bb_got_signal) {
1039 ssize_t sz; 1040 ssize_t sz;
@@ -1182,9 +1183,6 @@ int syslogd_main(int argc UNUSED_PARAM, char **argv)
1182 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); 1183 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
1183 } 1184 }
1184 1185
1185 //umask(0); - why??
1186 write_pidfile_std_path_and_ext("syslogd");
1187
1188 do_syslogd(); 1186 do_syslogd();
1189 /* return EXIT_SUCCESS; */ 1187 /* return EXIT_SUCCESS; */
1190} 1188}
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index 87f6b5007..92c83d719 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -398,5 +398,19 @@ testing 'awk do not allow "str"++' \
398 '' \ 398 '' \
399 'anything' 399 'anything'
400 400
401# gawk compat: FS regex matches only non-empty separators:
402# with -*, the splitting is NOT f o o b a r, but foo bar:
403testing 'awk FS regex which can match empty string' \
404 "awk -F '-*' '{print \$1 \"-\" \$2 \"=\" \$3 \"*\" \$4}'" \
405 "foo-bar=*\n" \
406 '' \
407 'foo--bar'
408
409# last+1 field should be empty (had a bug where it wasn't)
410testing 'awk $NF is empty' \
411 "awk -F '=+' '{print \$NF}'" \
412 "\n" \
413 '' \
414 'a=====123='
401 415
402exit $FAILCOUNT 416exit $FAILCOUNT
diff --git a/testsuite/dc_add_results.txt b/testsuite/dc_add_results.txt
index 542a62ea3..2d955935f 100644
--- a/testsuite/dc_add_results.txt
+++ b/testsuite/dc_add_results.txt
@@ -9,9 +9,9 @@
91998 91998
10324869359109479 10324869359109479
112378639108055453348401 112378639108055453348401
1278562139406792834691802347619083467219846713490861872324967138636055\ 12785621394067928346918023476190834672198467134908618723249671386360554\
1345508706362018540498696043776980521464405852627147161556994835657433\ 13550870636201854049869604377698052146440585262714716155699483565743300\
1400967298 14967298
151.1 151.1
161.1 161.1
1737842935130118.1187478621432354 1737842935130118.1187478621432354
@@ -20,21 +20,21 @@
20-2 20-2
21-19 21-19
22-1287904651762470260258 22-1287904651762470260258
23100000000000000000000000000000000000000000000000000000000000.0000000\ 23100000000000000000000000000000000000000000000000000000000000.00000000\
2400000000000000000000000000000000000000000000000000000000000000000000\ 24000000000000000000000000000000000000000000000000000000000000000000000\
25000000000000000000000000000000000000000000000 250000000000000000000000000000000000000000000
26100000000000000000000000000000000000000000000000000000000000.0000000\ 26100000000000000000000000000000000000000000000000000000000000.00000000\
2700000000000000000000000000000000000000000000000000000000000000000000\ 27000000000000000000000000000000000000000000000000000000000000000000000\
28000000000000000000000000000000000000000000000 280000000000000000000000000000000000000000000
29100000000000000000000000000000000000000000000000000000000000.0000000\ 29100000000000000000000000000000000000000000000000000000000000.00000000\
3000000000000000000000000000000000000000000000000000000000000000000000\ 30000000000000000000000000000000000000000000000000000000000000000000000\
31000000000000000000000000000000000000000009999 310000000000000000000000000000000000000009999
3299999999999999999999999999999999999999999999999999999999999.99999999\ 3299999999999999999999999999999999999999999999999999999999999.999999999\
3399999999999999999999999999999999999999999999999999000000000000000000\ 33999999999999999999999999999999999999999999999999900000000000000000000\
3400000000000000000000000000000000000000009999 34000000000000000000000000000000000000009999
3599999999999999999999999999999999999990000000000000000000000.00000000\ 3599999999999999999999999999999999999990000000000000000000000.000000000\
3600000000000000000000000000000000000000000000000000000000000000000000\ 36000000000000000000000000000000000000000000000000000000000000000000000\
3700000000000000000000000000000000000000009999 37000000000000000000000000000000000000009999
38122761518 38122761518
39-14338.391079082 39-14338.391079082
40-2422295.6865057444 40-2422295.6865057444
diff --git a/testsuite/dc_decimal_results.txt b/testsuite/dc_decimal_results.txt
index 275d431c6..66bb91ac3 100644
--- a/testsuite/dc_decimal_results.txt
+++ b/testsuite/dc_decimal_results.txt
@@ -9,19 +9,17 @@
9123 9123
107505 107505
111023468723275435238491972521917846 111023468723275435238491972521917846
1243434724324317058673920735170382703980273527090273892739207390379379\ 12434347243243170586739207351703827039802735270902738927392073903793796\
1360379637893607893607893670530278200795207952702873892786172916728961\ 13037963789360789360789367053027820079520795270287389278617291672896178\
1478390789360741897358785738607967926792673752073092537298378279365279\ 143907893607418973587857386079679267926737520730925372983782793652793
153
16-1 15-1
17-203 16-203
18-57 17-57
19-18586 18-18586
20-31378682943772818461924738352952347258 19-31378682943772818461924738352952347258
21-8239456287456735894950672387239865203756982376208346745096273452730\ 20-82394562874567358949506723872398652037569823762083467450962734527309\
2296287563846592384526349872634895763257893467523987578690283762897568\ 21628756384659238452634987263489576325789346752398757869028376289756845\
2345907234875807107108781350187590812735901871502384171023987230138727\ 229072348758071071087813501875908127359018715023841710239872301387278
248
25.123521346523546 23.123521346523546
26.1245923756273856 24.1245923756273856
27-.1024678456387 25-.1024678456387
@@ -31,21 +29,21 @@
31234237468293576.000000000000000000000000000000 29234237468293576.000000000000000000000000000000
3223987623568943567.00000000000000000005677834650000000000000 3023987623568943567.00000000000000000005677834650000000000000
3323856934568940675.000000000000000435676782300000000000000456784 3123856934568940675.000000000000000435676782300000000000000456784
3477567648698496.00000000000000000058767475000000000045856380000000000\ 3277567648698496.000000000000000000587674750000000000458563800000000000\
350000 33000
362348672354968723.237482354600000000000325698739450234689243562387000\ 342348672354968723.2374823546000000000003256987394502346892435623870000\
370000034578 35000034578
38-2354768.000000000000000000000000000000000000 36-2354768.000000000000000000000000000000000000
39-96739874567.000000000347683456 37-96739874567.000000000347683456
40-3764568345.000000000004573845000000347683460 38-3764568345.000000000004573845000000347683460
41-356784356.934568495770004586495678300000000 39-356784356.934568495770004586495678300000000
4274325437345273852773827101738273127312738521733017537073520735207307\ 40743254373452738527738271017382731273127385217330175370735207352073075\
43570358738257390761276072160719802671980267018728630178.7082681027680\ 4170358738257390761276072160719802671980267018728630178.708268102768052\
4452176021786784127612768127086782782176817317820783071097801773817867\ 42176021786784127612768127086782782176817317820783071097801773817867801\
458012767377058785378278207385237085237803278203782037237582795870 432767377058785378278207385237085237803278203782037237582795870
46-7567527327852738512737285378527382578372836789657385273852729836783\ 44-75675273278527385127372853785273825783728367896573852738527298367837\
4772867327835672967385278372637862738627836279863782673862783670.71738\ 452867327835672967385278372637862738627836279863782673862783670.7173817\
4817836173871836718637861073861783678160376017836701860376017810773527\ 46836173871836718637861073861783678160376017836701860376017810773527837\
498372832783728367826738627836278378260736270367362073867097307925 472832783728367826738627836278378260736270367362073867097307925
509812734012837410982345719208345712908357412903587192048571920458712.\ 489812734012837410982345719208345712908357412903587192048571920458712.2\
5123957182459817249058172945781 493957182459817249058172945781
diff --git a/testsuite/dc_divmod_results.txt b/testsuite/dc_divmod_results.txt
index c55e9303d..ee91ee88c 100644
--- a/testsuite/dc_divmod_results.txt
+++ b/testsuite/dc_divmod_results.txt
@@ -58,8 +58,8 @@
58100864416620775.31076855630746548983 58100864416620775.31076855630746548983
59-53336.193401942302558132911110799109649707477 59-53336.193401942302558132911110799109649707477
60.00000000052530099381 60.00000000052530099381
61.0000000000000000000000000000000000000000000000000000000000000001907\ 61.00000000000000000000000000000000000000000000000000000000000000019072\
62266929376630027064745963897 6266929376630027064745963897
6342612515855353136519261264261472677699404182.78776061098893912189 6342612515855353136519261264261472677699404182.78776061098893912189
640 640
650 650
@@ -121,6 +121,6 @@
121100864416620775 121100864416620775
122-3878923750692883.7238596702834756902 122-3878923750692883.7238596702834756902
1230 1230
124.0000000000000000000000000000000000000000000184866017689020776005643\ 124.00000000000000000000000000000000000000000001848660176890207760056433\
1253621086 125621086
12642612515855353136519261264261472677699404182 12642612515855353136519261264261472677699404182
diff --git a/testsuite/dc_multiply_results.txt b/testsuite/dc_multiply_results.txt
index 9666059a5..aaf3a20fc 100644
--- a/testsuite/dc_multiply_results.txt
+++ b/testsuite/dc_multiply_results.txt
@@ -15,8 +15,8 @@
153543531533584430580556128344529291738 153543531533584430580556128344529291738
16568600835566479683035874339053.4411638427543228060 16568600835566479683035874339053.4411638427543228060
177487566285885.8557453089005171423976251098 177487566285885.8557453089005171423976251098
18373846412427291014394738378015501363938345620046.7869650248829232267\ 18373846412427291014394738378015501363938345620046.78696502488292322672\
192297002026819 19297002026819
20-1 20-1
21-2 21-2
22-2751507058396910892 22-2751507058396910892
diff --git a/testsuite/dc_power_results.txt b/testsuite/dc_power_results.txt
index 997f44f59..dc5d56766 100644
--- a/testsuite/dc_power_results.txt
+++ b/testsuite/dc_power_results.txt
@@ -10,15 +10,15 @@
1018927361346 1018927361346
11.23523785962738592635777 11.23523785962738592635777
12328956734869213746.89782398457234 12328956734869213746.89782398457234
1316473742664221279051571200630760751138799221376964991600670000200609\ 13164737426642212790515712006307607511387992213769649916006700002006090\
1408006052596520320731708604393844468006290371918262741885989163144389\ 14800605259652032073170860439384446800629037191826274188598916314438939\
1539367835091560809036359941703341471396407660150658436796925310445979\ 15367835091560809036359941703341471396407660150658436796925310445979213\
1621333166245765946557344383284626113908419359990042883048537750217279\ 16331662457659465573443832846261139084193599900428830485377502172791748\
1717481980123593363177308481941550382845381799410533956718500484099889\ 17198012359336317730848194155038284538179941053395671850048409988961080\
18610805653325917409549921909941664118421333562129 185653325917409549921909941664118421333562129
190 190
2043287877285033571298394739716218787350087163435619825150259705419.98\ 2043287877285033571298394739716218787350087163435619825150259705419.980\
21016445740928054425 2116445740928054425
221.00000000000000000000 221.00000000000000000000
23.50000000000000000000 23.50000000000000000000
24.10000000000000000000 24.10000000000000000000
@@ -31,27 +31,27 @@
311 311
32-2 32-2
334 334
3414997322375665265051328725757939209353051902095893907150382724666290\ 34149973223756652650513287257579392093530519020958939071503827246662904\
3549749481660976421019742616298227588464420182758442163654172400528243\ 35974948166097642101974261629822758846442018275844216365417240052824300\
3600885441207762486233574213374503090372518590691583139696652847404883\ 36885441207762486233574213374503090372518590691583139696652847404883085\
3708573912261119588874308960204159666762789603037188471170006223907416\ 37739122611195888743089602041596667627896030371884711700062239074166049\
3860492840269152716750700089148882139254399347568222390231015487895905\ 38284026915271675070008914888213925439934756822239023101548789590573727\
3973727080561379177721440905866857248917982113340543176658480139248897\ 39080561379177721440905866857248917982113340543176658480139248897548025\
4054802503253413282808814063861470711399810899724515727713334909764746\ 40032534132828088140638614707113998108997245157277133349097647462791029\
4127910290211411231279325882505708287941671508154740003122373284699097\ 41021141123127932588250570828794167150815474000312237328469909778346501\
4278346501539634198926772266511968381368929692275950529960923432771985\ 42539634198926772266511968381368929692275950529960923432771985125971893\
4312597189390708050983487158873301681237787429436264801751664042999180\ 43907080509834871588733016812377874294362648017516640429991803448659818\
443448659818912436089 44912436089
4511478830555358864333472551120140548480416206583184496764727387456058\ 45114788305553588643334725511201405484804162065831844967647273874560587\
46792742209537931243951391229607936 4692742209537931243951391229607936
47-.00000000000000017759 47-.00000000000000017759
48-2067373624686414405470850679965010694114490999957199847684803894306\ 48-20673736246864144054708506799650106941144909999571998476848038943065\
4956243666149296582304582679590231948238805965642713928910384741502707\ 496243666149296582304582679590231948238805965642713928910384741502707.2\
50.23224479257866798694 503224479257866798694
5111606078892843496082360561256965139908586179418605021706789617179085\ 51116060788928434960823605612569651399085861794186050217067896171790858\
5285768049299693425729565480314913006780973928345684673490252494674985\ 52576804929969342572956548031491300678097392834568467349025249467498501\
530186164225375953066263609289359900615361965737717208159874390.293769\ 5386164225375953066263609289359900615361965737717208159874390.293769702\
5470206344604971 5406344604971
55-1.00000000000000000000 55-1.00000000000000000000
561.00000000000000000000 561.00000000000000000000
57-.50000000000000000000 57-.50000000000000000000
@@ -59,14 +59,14 @@
590 590
600 600
61-.00000000000002874159 61-.00000000000002874159
62-1945134149489344891879057554905782841936258356736314337975569799825\ 62-19451341494893448918790575549057828419362583567363143379755697998259\
6394091939572752348215929683891336730843553721422164737465108229034947\ 63409193957275234821592968389133673084355372142216473746510822903494787\
6487333189564755763444242676978610321731298729194092653999616928308494\ 64333189564755763444242676978610321731298729194092653999616928308494264\
6526419468484566422775668903315088810746121307679948574976162519479931\ 65194684845664227756689033150888107461213076799485749761625194799311893\
6618935243698160094347216562490000767121041786977792546155155934655909\ 66524369816009434721656249000076712104178697779254615515593465590914123\
6714123833869470494708767968978717730012864171105540029928688274136791\ 67833869470494708767968978717730012864171105540029928688274136791981750\
6898175053824022144065005509214813689232148489884560100200475909009813\ 68538240221440650055092148136892321484898845601002004759090098133400981\
69340098100705258138.98542904577525702068 6900705258138.98542904577525702068
700 700
710 710
720 720
diff --git a/testsuite/dc_subtract_results.txt b/testsuite/dc_subtract_results.txt
index 9f7726254..0a9762381 100644
--- a/testsuite/dc_subtract_results.txt
+++ b/testsuite/dc_subtract_results.txt
@@ -8,15 +8,15 @@
82874519803456326214611 82874519803456326214611
99000000000000000000000000000000000000001 99000000000000000000000000000000000000001
101 101
119000000000000000000000000000000000000000.000000000000000000000000000\ 119000000000000000000000000000000000000000.0000000000000000000000000000\
1200000001 120000001
13.0000000000000000000000000000000001 13.0000000000000000000000000000000001
149999999999999999999999999999999999999999.999999999999999999999999999\ 149999999999999999999999999999999999999999.9999999999999999999999999999\
159999999999999999999999999999999999999999999999999999999999
1610000000000000000000000000000000000000000.999999999999999999999999999\
1599999999999999999999999999999999999999999999999999999999999 1799999999999999999999999999999999999999999999999999999999999
1610000000000000000000000000000000000000000.99999999999999999999999999\ 1810000000000000000000000000000000000000000.000000000099999999999999999\
17999999999999999999999999999999999999999999999999999999999999 199999999999999999999999999999999999999999999999999
1810000000000000000000000000000000000000000.00000000009999999999999999\
1999999999999999999999999999999999999999999999999999
20-8 20-8
21-182934721309467230894628759280719690 21-182934721309467230894628759280719690
221245723576605103923392087218483 221245723576605103923392087218483
diff --git a/testsuite/factor.tests b/testsuite/factor.tests
index 2cf4a54ce..e404e29c1 100755
--- a/testsuite/factor.tests
+++ b/testsuite/factor.tests
@@ -45,4 +45,27 @@ testing "factor \$((2*3*5*7*11*13*17*19*23*29*31*37*41*43*47))" \
45 "614889782588491410: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47\n" \ 45 "614889782588491410: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47\n" \
46 "" "" 46 "" ""
47 47
48# Test that square-detection code is not buggy
49testing "factor 2 * 3037000493 * 3037000493" \
50 "factor 18446743988964486098" \
51 "18446743988964486098: 2 3037000493 3037000493\n" \
52 "" ""
53testing "factor 3 * 2479700513 * 2479700513" \
54 "factor 18446743902517389507" \
55 "18446743902517389507: 3 2479700513 2479700513\n" \
56 "" ""
57# including square-of-square cases:
58testing "factor 3 * 37831 * 37831 * 37831 * 37831" \
59 "factor 6144867742934288163" \
60 "6144867742934288163: 3 37831 37831 37831 37831\n" \
61 "" ""
62testing "factor 3 * 13^16" \
63 "factor 1996249827549539523" \
64 "1996249827549539523: 3 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13\n" \
65 "" ""
66testing "factor 13^16" \
67 "factor 665416609183179841" \
68 "665416609183179841: 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13 13\n" \
69 "" ""
70
48exit $FAILCOUNT 71exit $FAILCOUNT
diff --git a/testsuite/mount.tests b/testsuite/mount.tests
index 91c2e8b42..b6d5ebe08 100755
--- a/testsuite/mount.tests
+++ b/testsuite/mount.tests
@@ -34,6 +34,8 @@ umount -d "$testdir" 2>/dev/null
34# file input will be file called "input" 34# file input will be file called "input"
35# test can create a file "actual" instead of writing to stdout 35# test can create a file "actual" instead of writing to stdout
36 36
37# This will always fail on !CONFIG_MANDATORY_FILE_LOCKING kernels
38test "$SKIP_MOUNT_MAND_TESTS" = "1" || \
37testing "mount -o remount,mand" \ 39testing "mount -o remount,mand" \
38"mount -o loop mount.image1m $testdir "\ 40"mount -o loop mount.image1m $testdir "\
39"&& grep -Fc $testdir </proc/mounts "\ 41"&& grep -Fc $testdir </proc/mounts "\
diff --git a/testsuite/xargs.tests b/testsuite/xargs.tests
index e7c7c4b3d..c5e7b99e9 100755
--- a/testsuite/xargs.tests
+++ b/testsuite/xargs.tests
@@ -61,7 +61,7 @@ testing "xargs -n2" \
61 61
62SKIP= 62SKIP=
63 63
64optional FEATURE_XARGS_SUPPORT_QUOTES 64optional FEATURE_XARGS_SUPPORT_QUOTES FEATURE_XARGS_SUPPORT_REPL_STR
65testing "xargs -I skips empty lines and leading whitespace" \ 65testing "xargs -I skips empty lines and leading whitespace" \
66 "xargs -I% echo '[%]'" \ 66 "xargs -I% echo '[%]'" \
67 "[2]\n[4]\n[6 6 ]\n[7]\n" \ 67 "[2]\n[4]\n[6 6 ]\n[7]\n" \
diff --git a/util-linux/acpid.c b/util-linux/acpid.c
index d473e24fc..00613f8e3 100644
--- a/util-linux/acpid.c
+++ b/util-linux/acpid.c
@@ -99,7 +99,7 @@ struct acpi_event {
99 const char *desc; 99 const char *desc;
100}; 100};
101 101
102static const struct acpi_event f_evt_tab[] = { 102static const struct acpi_event f_evt_tab[] ALIGN_PTR = {
103 { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRF 00000080" }, 103 { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRF 00000080" },
104 { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRB 00000080" }, 104 { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRB 00000080" },
105 { "EV_SW", 0x05, "SW_LID", 0x00, 1, "button/lid LID0 00000080" }, 105 { "EV_SW", 0x05, "SW_LID", 0x00, 1, "button/lid LID0 00000080" },
@@ -110,7 +110,7 @@ struct acpi_action {
110 const char *action; 110 const char *action;
111}; 111};
112 112
113static const struct acpi_action f_act_tab[] = { 113static const struct acpi_action f_act_tab[] ALIGN_PTR = {
114 { "PWRF", "PWRF/00000080" }, 114 { "PWRF", "PWRF/00000080" },
115 { "LID0", "LID/00000080" }, 115 { "LID0", "LID/00000080" },
116}; 116};
diff --git a/util-linux/blockdev.c b/util-linux/blockdev.c
index e60bbe609..20a031377 100644
--- a/util-linux/blockdev.c
+++ b/util-linux/blockdev.c
@@ -60,7 +60,7 @@ static const char bdcmd_names[] ALIGN1 =
60 "flushbufs" "\0" 60 "flushbufs" "\0"
61 "rereadpt" "\0" 61 "rereadpt" "\0"
62; 62;
63static const uint32_t bdcmd_ioctl[] = { 63static const uint32_t bdcmd_ioctl[] ALIGN4 = {
64 BLKROSET, //setro 64 BLKROSET, //setro
65 BLKROSET, //setrw 65 BLKROSET, //setrw
66 BLKROGET, //getro 66 BLKROGET, //getro
diff --git a/util-linux/chrt.c b/util-linux/chrt.c
index 4dd78dabf..a8701b55f 100644
--- a/util-linux/chrt.c
+++ b/util-linux/chrt.c
@@ -17,7 +17,7 @@
17//kbuild:lib-$(CONFIG_CHRT) += chrt.o 17//kbuild:lib-$(CONFIG_CHRT) += chrt.o
18 18
19//usage:#define chrt_trivial_usage 19//usage:#define chrt_trivial_usage
20//usage: "-m | -p [PRIO] PID | [-rfobi] PRIO PROG [ARGS]" 20//usage: "-m | -p [PRIO] PID | [-rfobi] PRIO PROG ARGS"
21//usage:#define chrt_full_usage "\n\n" 21//usage:#define chrt_full_usage "\n\n"
22//usage: "Change scheduling priority and class for a process\n" 22//usage: "Change scheduling priority and class for a process\n"
23//usage: "\n -m Show min/max priorities" 23//usage: "\n -m Show min/max priorities"
@@ -39,6 +39,17 @@
39# define SCHED_IDLE 5 39# define SCHED_IDLE 5
40#endif 40#endif
41 41
42//musl has no __MUSL__ or similar define to check for,
43//but its <sys/types.h> has these lines:
44// #define __NEED_fsblkcnt_t
45// #define __NEED_fsfilcnt_t
46#if defined(__linux__) && defined(__NEED_fsblkcnt_t) && defined(__NEED_fsfilcnt_t)
47# define LIBC_IS_MUSL 1
48# include <sys/syscall.h>
49#else
50# define LIBC_IS_MUSL 0
51#endif
52
42static const char *policy_name(int pol) 53static const char *policy_name(int pol)
43{ 54{
44 if (pol > 6) 55 if (pol > 6)
@@ -85,6 +96,7 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
85 char *priority = priority; /* for compiler */ 96 char *priority = priority; /* for compiler */
86 const char *current_new; 97 const char *current_new;
87 int policy = SCHED_RR; 98 int policy = SCHED_RR;
99 int ret;
88 100
89 opt = getopt32(argv, "^" 101 opt = getopt32(argv, "^"
90 "+" "mprfobi" 102 "+" "mprfobi"
@@ -132,7 +144,15 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
132 if (opt & OPT_p) { 144 if (opt & OPT_p) {
133 int pol; 145 int pol;
134 print_rt_info: 146 print_rt_info:
147#if LIBC_IS_MUSL
148 /* musl libc returns ENOSYS for its sched_getscheduler library
149 * function, because the sched_getscheduler Linux kernel system call
150 * does not conform to Posix; so we use the system call directly
151 */
152 pol = syscall(SYS_sched_getscheduler, pid);
153#else
135 pol = sched_getscheduler(pid); 154 pol = sched_getscheduler(pid);
155#endif
136 if (pol < 0) 156 if (pol < 0)
137 bb_perror_msg_and_die("can't %cet pid %u's policy", 'g', (int)pid); 157 bb_perror_msg_and_die("can't %cet pid %u's policy", 'g', (int)pid);
138#ifdef SCHED_RESET_ON_FORK 158#ifdef SCHED_RESET_ON_FORK
@@ -149,7 +169,12 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
149 printf("pid %u's %s scheduling policy: SCHED_%s\n", 169 printf("pid %u's %s scheduling policy: SCHED_%s\n",
150 pid, current_new, policy_name(pol) 170 pid, current_new, policy_name(pol)
151 ); 171 );
152 if (sched_getparam(pid, &sp)) 172#if LIBC_IS_MUSL
173 ret = syscall(SYS_sched_getparam, pid, &sp);
174#else
175 ret = sched_getparam(pid, &sp);
176#endif
177 if (ret)
153 bb_perror_msg_and_die("can't get pid %u's attributes", (int)pid); 178 bb_perror_msg_and_die("can't get pid %u's attributes", (int)pid);
154 printf("pid %u's %s scheduling priority: %d\n", 179 printf("pid %u's %s scheduling priority: %d\n",
155 (int)pid, current_new, sp.sched_priority 180 (int)pid, current_new, sp.sched_priority
@@ -168,7 +193,12 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
168 sched_get_priority_min(policy), sched_get_priority_max(policy) 193 sched_get_priority_min(policy), sched_get_priority_max(policy)
169 ); 194 );
170 195
171 if (sched_setscheduler(pid, policy, &sp) < 0) 196#if LIBC_IS_MUSL
197 ret = syscall(SYS_sched_setscheduler, pid, policy, &sp);
198#else
199 ret = sched_setscheduler(pid, policy, &sp);
200#endif
201 if (ret)
172 bb_perror_msg_and_die("can't %cet pid %u's policy", 's', (int)pid); 202 bb_perror_msg_and_die("can't %cet pid %u's policy", 's', (int)pid);
173 203
174 if (!argv[0]) /* "-p PRIO PID [...]" */ 204 if (!argv[0]) /* "-p PRIO PID [...]" */
diff --git a/util-linux/fbset.c b/util-linux/fbset.c
index 0b9a9a6bc..cc5413b40 100644
--- a/util-linux/fbset.c
+++ b/util-linux/fbset.c
@@ -193,7 +193,7 @@ static const struct cmdoptions_t {
193 const char name[9]; 193 const char name[9];
194 const unsigned char param_count; 194 const unsigned char param_count;
195 const unsigned char code; 195 const unsigned char code;
196} g_cmdoptions[] = { 196} g_cmdoptions[] ALIGN1 = {
197 /*"12345678" + NUL */ 197 /*"12345678" + NUL */
198//TODO: convert to index_in_strings() 198//TODO: convert to index_in_strings()
199 { "fb" , 1, CMD_FB }, 199 { "fb" , 1, CMD_FB },
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c
index 0fb2e3e17..c50ceead1 100644
--- a/util-linux/fdisk.c
+++ b/util-linux/fdisk.c
@@ -185,8 +185,11 @@ struct hd_geometry {
185 185
186#define HDIO_GETGEO 0x0301 /* get device geometry */ 186#define HDIO_GETGEO 0x0301 /* get device geometry */
187 187
188/* TODO: #if ENABLE_FEATURE_FDISK_WRITABLE */ 188/* TODO: just #if ENABLE_FEATURE_FDISK_WRITABLE */
189/* (currently fdisk_sun/sgi.c do not have proper WRITABLE #ifs) */ 189/* (currently fdisk_sun/sgi.c do not have proper WRITABLE #ifs) */
190#if ENABLE_FEATURE_FDISK_WRITABLE \
191 || ENABLE_FEATURE_SGI_LABEL \
192 || ENABLE_FEATURE_SUN_LABEL
190static const char msg_building_new_label[] ALIGN1 = 193static const char msg_building_new_label[] ALIGN1 =
191"Building a new %s. Changes will remain in memory only,\n" 194"Building a new %s. Changes will remain in memory only,\n"
192"until you decide to write them. After that the previous content\n" 195"until you decide to write them. After that the previous content\n"
@@ -194,7 +197,7 @@ static const char msg_building_new_label[] ALIGN1 =
194 197
195static const char msg_part_already_defined[] ALIGN1 = 198static const char msg_part_already_defined[] ALIGN1 =
196"Partition %u is already defined, delete it before re-adding\n"; 199"Partition %u is already defined, delete it before re-adding\n";
197/* #endif */ 200#endif
198 201
199 202
200struct partition { 203struct partition {
@@ -303,7 +306,7 @@ static sector_t get_nr_sects(const struct partition *p);
303 306
304/* DOS partition types */ 307/* DOS partition types */
305 308
306static const char *const i386_sys_types[] = { 309static const char *const i386_sys_types[] ALIGN_PTR = {
307 "\x00" "Empty", 310 "\x00" "Empty",
308 "\x01" "FAT12", 311 "\x01" "FAT12",
309 "\x04" "FAT16 <32M", 312 "\x04" "FAT16 <32M",
@@ -2667,7 +2670,7 @@ reread_partition_table(int leave)
2667 /* Users with slow external USB disks on a 320MHz ARM system (year 2011) 2670 /* Users with slow external USB disks on a 320MHz ARM system (year 2011)
2668 * report that sleep is needed, otherwise BLKRRPART may fail with -EIO: 2671 * report that sleep is needed, otherwise BLKRRPART may fail with -EIO:
2669 */ 2672 */
2670 sleep(1); 2673 sleep1();
2671 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL, 2674 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2672 "WARNING: rereading partition table " 2675 "WARNING: rereading partition table "
2673 "failed, kernel still uses old table"); 2676 "failed, kernel still uses old table");
diff --git a/util-linux/fdisk_osf.c b/util-linux/fdisk_osf.c
index 92180b2bc..765740ff1 100644
--- a/util-linux/fdisk_osf.c
+++ b/util-linux/fdisk_osf.c
@@ -144,7 +144,7 @@ struct xbsd_disklabel {
144#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */ 144#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
145#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */ 145#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
146 146
147static const char *const xbsd_dktypenames[] = { 147static const char *const xbsd_dktypenames[] ALIGN_PTR = {
148 "unknown", 148 "unknown",
149 "SMD", 149 "SMD",
150 "MSCP", 150 "MSCP",
@@ -190,7 +190,7 @@ static const char *const xbsd_dktypenames[] = {
190#define BSD_FS_MSDOS 8 /* MS-DOS file system */ 190#define BSD_FS_MSDOS 8 /* MS-DOS file system */
191#endif 191#endif
192 192
193static const char *const xbsd_fstypes[] = { 193static const char *const xbsd_fstypes[] ALIGN_PTR = {
194 "\x00" "unused", /* BSD_FS_UNUSED */ 194 "\x00" "unused", /* BSD_FS_UNUSED */
195 "\x01" "swap", /* BSD_FS_SWAP */ 195 "\x01" "swap", /* BSD_FS_SWAP */
196 "\x02" "Version 6", /* BSD_FS_V6 */ 196 "\x02" "Version 6", /* BSD_FS_V6 */
diff --git a/util-linux/fdisk_sgi.c b/util-linux/fdisk_sgi.c
index c90c801e2..acb438ac0 100644
--- a/util-linux/fdisk_sgi.c
+++ b/util-linux/fdisk_sgi.c
@@ -174,7 +174,7 @@ isinfreelist(unsigned int b)
174 * end of free blocks section 174 * end of free blocks section
175 */ 175 */
176 176
177static const char *const sgi_sys_types[] = { 177static const char *const sgi_sys_types[] ALIGN_PTR = {
178/* SGI_VOLHDR */ "\x00" "SGI volhdr" , 178/* SGI_VOLHDR */ "\x00" "SGI volhdr" ,
179/* 0x01 */ "\x01" "SGI trkrepl" , 179/* 0x01 */ "\x01" "SGI trkrepl" ,
180/* 0x02 */ "\x02" "SGI secrepl" , 180/* 0x02 */ "\x02" "SGI secrepl" ,
diff --git a/util-linux/fdisk_sun.c b/util-linux/fdisk_sun.c
index 29d7c283a..427b9487b 100644
--- a/util-linux/fdisk_sun.c
+++ b/util-linux/fdisk_sun.c
@@ -61,7 +61,7 @@ guess_device_type(void)
61 } 61 }
62} 62}
63 63
64static const char *const sun_sys_types[] = { 64static const char *const sun_sys_types[] ALIGN_PTR = {
65 "\x00" "Empty" , /* 0 */ 65 "\x00" "Empty" , /* 0 */
66 "\x01" "Boot" , /* 1 */ 66 "\x01" "Boot" , /* 1 */
67 "\x02" "SunOS root" , /* 2 */ 67 "\x02" "SunOS root" , /* 2 */
@@ -133,7 +133,7 @@ static const struct sun_predefined_drives {
133 unsigned short ntrks; 133 unsigned short ntrks;
134 unsigned short nsect; 134 unsigned short nsect;
135 unsigned short rspeed; 135 unsigned short rspeed;
136} sun_drives[] = { 136} sun_drives[] ALIGN_PTR = {
137 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662}, 137 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
138 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662}, 138 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
139 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600}, 139 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
diff --git a/util-linux/fstrim.c b/util-linux/fstrim.c
index 8d29a6d54..6d673002f 100644
--- a/util-linux/fstrim.c
+++ b/util-linux/fstrim.c
@@ -20,18 +20,10 @@
20//usage:#define fstrim_trivial_usage 20//usage:#define fstrim_trivial_usage
21//usage: "[OPTIONS] MOUNTPOINT" 21//usage: "[OPTIONS] MOUNTPOINT"
22//usage:#define fstrim_full_usage "\n\n" 22//usage:#define fstrim_full_usage "\n\n"
23//usage: IF_LONG_OPTS(
24//usage: " -o,--offset OFFSET Offset in bytes to discard from"
25//usage: "\n -l,--length LEN Bytes to discard"
26//usage: "\n -m,--minimum MIN Minimum extent length"
27//usage: "\n -v,--verbose Print number of discarded bytes"
28//usage: )
29//usage: IF_NOT_LONG_OPTS(
30//usage: " -o OFFSET Offset in bytes to discard from" 23//usage: " -o OFFSET Offset in bytes to discard from"
31//usage: "\n -l LEN Bytes to discard" 24//usage: "\n -l LEN Bytes to discard"
32//usage: "\n -m MIN Minimum extent length" 25//usage: "\n -m MIN Minimum extent length"
33//usage: "\n -v Print number of discarded bytes" 26//usage: "\n -v Print number of discarded bytes"
34//usage: )
35 27
36#include "libbb.h" 28#include "libbb.h"
37#include <linux/fs.h> 29#include <linux/fs.h>
diff --git a/util-linux/hexdump.c b/util-linux/hexdump.c
index 2174c3008..57e7e8db7 100644
--- a/util-linux/hexdump.c
+++ b/util-linux/hexdump.c
@@ -28,7 +28,7 @@
28//kbuild:lib-$(CONFIG_HD) += hexdump.o 28//kbuild:lib-$(CONFIG_HD) += hexdump.o
29 29
30//usage:#define hexdump_trivial_usage 30//usage:#define hexdump_trivial_usage
31//usage: "[-bcCdefnosvx] [FILE]..." 31//usage: "[-bcdoxCv] [-e FMT] [-f FMT_FILE] [-n LEN] [-s OFS] [FILE]..."
32//usage:#define hexdump_full_usage "\n\n" 32//usage:#define hexdump_full_usage "\n\n"
33//usage: "Display FILEs (or stdin) in a user specified format\n" 33//usage: "Display FILEs (or stdin) in a user specified format\n"
34//usage: "\n -b 1-byte octal display" 34//usage: "\n -b 1-byte octal display"
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c
index d2f4b6ed8..29bbc6633 100644
--- a/util-linux/hexdump_xxd.c
+++ b/util-linux/hexdump_xxd.c
@@ -41,7 +41,7 @@
41// -u use upper case hex letters. 41// -u use upper case hex letters.
42 42
43//usage:#define xxd_trivial_usage 43//usage:#define xxd_trivial_usage
44//usage: "[OPTIONS] [FILE]" 44//usage: "[-pr] [-g N] [-c N] [-n LEN] [-s OFS] [FILE]"
45//usage:#define xxd_full_usage "\n\n" 45//usage:#define xxd_full_usage "\n\n"
46//usage: "Hex dump FILE (or stdin)\n" 46//usage: "Hex dump FILE (or stdin)\n"
47//usage: "\n -g N Bytes per group" 47//usage: "\n -g N Bytes per group"
@@ -51,7 +51,6 @@
51//usage: "\n -l LENGTH Show only first LENGTH bytes" 51//usage: "\n -l LENGTH Show only first LENGTH bytes"
52//usage: "\n -s OFFSET Skip OFFSET bytes" 52//usage: "\n -s OFFSET Skip OFFSET bytes"
53//usage: "\n -r Reverse (with -p, assumes no offsets in input)" 53//usage: "\n -r Reverse (with -p, assumes no offsets in input)"
54// TODO: implement -r (see hexdump -R)
55 54
56#include "libbb.h" 55#include "libbb.h"
57#include "dump.h" 56#include "dump.h"
diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c
index e85bca2b2..723b09589 100644
--- a/util-linux/hwclock.c
+++ b/util-linux/hwclock.c
@@ -36,6 +36,19 @@
36#include <sys/utsname.h> 36#include <sys/utsname.h>
37#include "rtc_.h" 37#include "rtc_.h"
38 38
39
40//musl has no __MUSL__ or similar define to check for,
41//but its <sys/types.h> has these lines:
42// #define __NEED_fsblkcnt_t
43// #define __NEED_fsfilcnt_t
44#if defined(__linux__) && defined(__NEED_fsblkcnt_t) && defined(__NEED_fsfilcnt_t)
45# define LIBC_IS_MUSL 1
46# include <sys/syscall.h>
47#else
48# define LIBC_IS_MUSL 0
49#endif
50
51
39/* diff code is disabled: it's not sys/hw clock diff, it's some useless 52/* diff code is disabled: it's not sys/hw clock diff, it's some useless
40 * "time between hwclock was started and we saw CMOS tick" quantity. 53 * "time between hwclock was started and we saw CMOS tick" quantity.
41 * It's useless since hwclock is started at a random moment, 54 * It's useless since hwclock is started at a random moment,
@@ -66,7 +79,7 @@ static time_t read_rtc(const char **pp_rtcname, struct timeval *sys_tv, int utc)
66 int before = tm_time.tm_sec; 79 int before = tm_time.tm_sec;
67 while (1) { 80 while (1) {
68 rtc_read_tm(&tm_time, fd); 81 rtc_read_tm(&tm_time, fd);
69 gettimeofday(sys_tv, NULL); 82 xgettimeofday(sys_tv);
70 if (before != (int)tm_time.tm_sec) 83 if (before != (int)tm_time.tm_sec)
71 break; 84 break;
72 } 85 }
@@ -116,26 +129,72 @@ static void show_clock(const char **pp_rtcname, int utc)
116#endif 129#endif
117} 130}
118 131
119static void to_sys_clock(const char **pp_rtcname, int utc) 132static void set_kernel_tz(const struct timezone *tz)
120{ 133{
121 struct timeval tv; 134#if LIBC_IS_MUSL
122 struct timezone tz; 135 /* musl libc does not pass tz argument to syscall
123 136 * because "it's deprecated by POSIX, therefore it's fine
124 tz.tz_minuteswest = timezone / 60; 137 * if we gratuitously break stuff" :(
125 /* ^^^ used to also subtract 60*daylight, but it's wrong:
126 * daylight!=0 means "this timezone has some DST
127 * during the year", not "DST is in effect now".
128 */ 138 */
129 tz.tz_dsttime = 0; 139#if !defined(SYS_settimeofday) && defined(SYS_settimeofday_time32)
130 140# define SYS_settimeofday SYS_settimeofday_time32
131 /* glibc v2.31+ returns an error if both args are non-NULL */ 141#endif
132 if (settimeofday(NULL, &tz)) 142 int ret = syscall(SYS_settimeofday, NULL, tz);
143#else
144 int ret = settimeofday(NULL, tz);
145#endif
146 if (ret)
133 bb_simple_perror_msg_and_die("settimeofday"); 147 bb_simple_perror_msg_and_die("settimeofday");
148}
149
150/*
151 * At system boot, kernel may set system time from RTC,
152 * but it knows nothing about timezones. If RTC is in local time,
153 * then system time is wrong - it is offset by timezone.
154 * --systz option corrects system time if RTC is in local time,
155 * and (always) sets in-kernel timezone.
156 * (Unlike --hctosys, it does not read the RTC).
157 *
158 * util-linux's code has this comment:
159 * RTC | settimeofday calls
160 * ------|-------------------------------------------------
161 * Local | 1st) warps system time*, sets PCIL* and kernel tz
162 * UTC | 1st) locks warp_clock 2nd) sets kernel tz
163 * * only on first call after boot
164 * (PCIL is "persistent_clock_is_local" kernel internal flag,
165 * it makes kernel save RTC in local time, not UTC.)
166 */
167static void set_kernel_timezone_and_clock(int utc, const struct timeval *hctosys)
168{
169 time_t cur;
170 struct tm *broken;
171 struct timezone tz = { 0 };
172
173 /* if --utc, prevent kernel's warp_clock() with a dummy call */
174 if (utc)
175 set_kernel_tz(&tz);
176
177 /* Set kernel's timezone offset based on userspace one */
178//It's tempting to call tzset() and use libc global "timezone" variable
179//...but it does NOT include DST shift (IOW: it's WRONG, usually by one hour,
180//if DST is in effect!) Thus this ridiculous dance:
181 cur = time(NULL);
182 broken = localtime(&cur);
183 tz.tz_minuteswest = -broken->tm_gmtoff / 60;
184 /*tz.tz_dsttime = 0; already is */
185 set_kernel_tz(&tz); /* MIGHT warp_clock() if 1st call since boot */
186
187 if (hctosys) /* it's --hctosys: set time too */
188 xsettimeofday(hctosys);
189}
190
191static void to_sys_clock(const char **pp_rtcname, int utc)
192{
193 struct timeval tv;
134 194
135 tv.tv_sec = read_rtc(pp_rtcname, NULL, utc); 195 tv.tv_sec = read_rtc(pp_rtcname, NULL, utc);
136 tv.tv_usec = 0; 196 tv.tv_usec = 0;
137 if (settimeofday(&tv, NULL)) 197 return set_kernel_timezone_and_clock(utc, &tv);
138 bb_simple_perror_msg_and_die("settimeofday");
139} 198}
140 199
141static void from_sys_clock(const char **pp_rtcname, int utc) 200static void from_sys_clock(const char **pp_rtcname, int utc)
@@ -146,7 +205,7 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
146 int rtc; 205 int rtc;
147 206
148 rtc = rtc_xopen(pp_rtcname, O_WRONLY); 207 rtc = rtc_xopen(pp_rtcname, O_WRONLY);
149 gettimeofday(&tv, NULL); 208 xgettimeofday(&tv);
150 /* Prepare tm_time */ 209 /* Prepare tm_time */
151 if (sizeof(time_t) == sizeof(tv.tv_sec)) { 210 if (sizeof(time_t) == sizeof(tv.tv_sec)) {
152 if (utc) 211 if (utc)
@@ -194,7 +253,7 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
194 unsigned rem_usec; 253 unsigned rem_usec;
195 time_t t; 254 time_t t;
196 255
197 gettimeofday(&tv, NULL); 256 xgettimeofday(&tv);
198 257
199 t = tv.tv_sec; 258 t = tv.tv_sec;
200 rem_usec = 1000000 - tv.tv_usec; 259 rem_usec = 1000000 - tv.tv_usec;
@@ -215,7 +274,7 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
215 } 274 }
216 275
217 /* gmtime/localtime took some time, re-get cur time */ 276 /* gmtime/localtime took some time, re-get cur time */
218 gettimeofday(&tv, NULL); 277 xgettimeofday(&tv);
219 278
220 if (tv.tv_sec < t /* we are still in old second */ 279 if (tv.tv_sec < t /* we are still in old second */
221 || (tv.tv_sec == t && tv.tv_usec < adj) /* not too far into next second */ 280 || (tv.tv_sec == t && tv.tv_usec < adj) /* not too far into next second */
@@ -261,64 +320,53 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
261 close(rtc); 320 close(rtc);
262} 321}
263 322
264/* 323// hwclock from util-linux 2.36.1
265 * At system boot, kernel may set system time from RTC, 324// hwclock [function] [option...]
266 * but it knows nothing about timezones. If RTC is in local time, 325//Functions:
267 * then system time is wrong - it is offset by timezone. 326// -r, --show display the RTC time
268 * This option corrects system time if RTC is in local time, 327// --get display drift corrected RTC time
269 * and (always) sets in-kernel timezone. 328// --set set the RTC according to --date
270 * 329// -s, --hctosys set the system time from the RTC
271 * This is an alternate option to --hctosys that does not read the 330// -w, --systohc set the RTC from the system time
272 * hardware clock. 331// --systz send timescale configurations to the kernel
273 */ 332// -a, --adjust adjust the RTC to account for systematic drift
274static void set_system_clock_timezone(int utc) 333// --predict predict the drifted RTC time according to --date
275{ 334//Options:
276 struct timeval tv; 335// -u, --utc the RTC timescale is UTC
277 struct tm *broken; 336// -l, --localtime the RTC timescale is Local
278 struct timezone tz; 337// -f, --rtc <file> use an alternate file to /dev/rtc0
279 338// --directisa use the ISA bus instead of /dev/rtc0 access
280 gettimeofday(&tv, NULL); 339// --date <time> date/time input for --set and --predict
281 broken = localtime(&tv.tv_sec); 340// --delay <sec> delay used when set new RTC time
282 tz.tz_minuteswest = timezone / 60; 341// --update-drift update the RTC drift factor
283 if (broken->tm_isdst > 0) 342// --noadjfile do not use /etc/adjtime
284 tz.tz_minuteswest -= 60; 343// --adjfile <file> use an alternate file to /etc/adjtime
285 tz.tz_dsttime = 0; 344// --test dry run; implies --verbose
286 gettimeofday(&tv, NULL); 345// -v, --verbose display more details
287 if (!utc)
288 tv.tv_sec += tz.tz_minuteswest * 60;
289
290 /* glibc v2.31+ returns an error if both args are non-NULL */
291 if (settimeofday(NULL, &tz))
292 bb_simple_perror_msg_and_die("settimeofday");
293 if (settimeofday(&tv, NULL))
294 bb_simple_perror_msg_and_die("settimeofday");
295}
296 346
297//usage:#define hwclock_trivial_usage 347//usage:#define hwclock_trivial_usage
298//usage: IF_LONG_OPTS( 348//usage: IF_LONG_OPTS(
299//usage: "[-r|--show] [-s|--hctosys] [-w|--systohc] [--systz]" 349//usage: "[-swul] [--systz] [-f DEV]"
300//usage: " [--localtime] [-u|--utc]"
301//usage: " [-f|--rtc FILE]"
302//usage: ) 350//usage: )
303//usage: IF_NOT_LONG_OPTS( 351//usage: IF_NOT_LONG_OPTS(
304//usage: "[-r] [-s] [-w] [-t] [-l] [-u] [-f FILE]" 352//usage: "[-swult] [-f DEV]"
305//usage: ) 353//usage: )
306//usage:#define hwclock_full_usage "\n\n" 354//usage:#define hwclock_full_usage "\n\n"
307//usage: "Query and set hardware clock (RTC)\n" 355//usage: "Show or set hardware clock (RTC)\n"
308//usage: "\n -r Show hardware clock time" 356///////: "\n -r Show RTC time"
309//usage: "\n -s Set system time from hardware clock" 357///////-r is default, don't bother showing it in help
310//usage: "\n -w Set hardware clock from system time" 358//usage: "\n -s Set system time from RTC"
359//usage: "\n -w Set RTC from system time"
311//usage: IF_LONG_OPTS( 360//usage: IF_LONG_OPTS(
312//usage: "\n --systz Set in-kernel timezone, correct system time" 361//usage: "\n --systz Set in-kernel timezone, correct system time"
362//usage: "\n if RTC is kept in local time"
313//usage: ) 363//usage: )
314//usage: "\n if hardware clock is in local time" 364//usage: "\n -f DEV Use specified device (e.g. /dev/rtc2)"
315//usage: "\n -u Assume hardware clock is kept in UTC" 365//usage: "\n -u Assume RTC is kept in UTC"
316//usage: IF_LONG_OPTS( 366//usage: "\n -l Assume RTC is kept in local time"
317//usage: "\n --localtime Assume hardware clock is kept in local time" 367//usage: "\n (if neither is given, read from "ADJTIME_PATH")"
318//usage: )
319//usage: "\n -f FILE Use specified device (e.g. /dev/rtc2)"
320 368
321//TODO: get rid of incompatible -t and -l aliases to --systz and --localtime 369//TODO: get rid of incompatible -t alias to --systz?
322 370
323#define HWCLOCK_OPT_LOCALTIME 0x01 371#define HWCLOCK_OPT_LOCALTIME 0x01
324#define HWCLOCK_OPT_UTC 0x02 372#define HWCLOCK_OPT_UTC 0x02
@@ -334,10 +382,9 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
334 const char *rtcname = NULL; 382 const char *rtcname = NULL;
335 unsigned opt; 383 unsigned opt;
336 int utc; 384 int utc;
337
338#if ENABLE_LONG_OPTS 385#if ENABLE_LONG_OPTS
339 static const char hwclock_longopts[] ALIGN1 = 386 static const char hwclock_longopts[] ALIGN1 =
340 "localtime\0" No_argument "l" /* short opt is non-standard */ 387 "localtime\0" No_argument "l"
341 "utc\0" No_argument "u" 388 "utc\0" No_argument "u"
342 "show\0" No_argument "r" 389 "show\0" No_argument "r"
343 "hctosys\0" No_argument "s" 390 "hctosys\0" No_argument "s"
@@ -346,17 +393,15 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
346 "rtc\0" Required_argument "f" 393 "rtc\0" Required_argument "f"
347 ; 394 ;
348#endif 395#endif
349
350 /* Initialize "timezone" (libc global variable) */
351 tzset();
352
353 opt = getopt32long(argv, 396 opt = getopt32long(argv,
354 "^lurswtf:" "\0" "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l", 397 "^""lurswtf:v" /* -v is accepted and ignored */
398 "\0"
399 "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l",
355 hwclock_longopts, 400 hwclock_longopts,
356 &rtcname 401 &rtcname
357 ); 402 );
358 403
359 /* If -u or -l wasn't given check if we are using utc */ 404 /* If -u or -l wasn't given, check if we are using utc */
360 if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME)) 405 if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME))
361 utc = (opt & HWCLOCK_OPT_UTC); 406 utc = (opt & HWCLOCK_OPT_UTC);
362 else 407 else
@@ -367,7 +412,7 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
367 else if (opt & HWCLOCK_OPT_SYSTOHC) 412 else if (opt & HWCLOCK_OPT_SYSTOHC)
368 from_sys_clock(&rtcname, utc); 413 from_sys_clock(&rtcname, utc);
369 else if (opt & HWCLOCK_OPT_SYSTZ) 414 else if (opt & HWCLOCK_OPT_SYSTZ)
370 set_system_clock_timezone(utc); 415 set_kernel_timezone_and_clock(utc, NULL);
371 else 416 else
372 /* default HWCLOCK_OPT_SHOW */ 417 /* default HWCLOCK_OPT_SHOW */
373 show_clock(&rtcname, utc); 418 show_clock(&rtcname, utc);
diff --git a/util-linux/ionice.c b/util-linux/ionice.c
index 40c04d5e0..c8fb1a777 100644
--- a/util-linux/ionice.c
+++ b/util-linux/ionice.c
@@ -18,11 +18,11 @@
18//kbuild:lib-$(CONFIG_IONICE) += ionice.o 18//kbuild:lib-$(CONFIG_IONICE) += ionice.o
19 19
20//usage:#define ionice_trivial_usage 20//usage:#define ionice_trivial_usage
21//usage: "[-c 1-3] [-n 0-7] [-p PID] [PROG]" 21//usage: "[-c 1-3] [-n 0-7] [-p PID] [PROG ARGS]"
22//usage:#define ionice_full_usage "\n\n" 22//usage:#define ionice_full_usage "\n\n"
23//usage: "Change I/O priority and class\n" 23//usage: "Change I/O priority and class\n"
24//usage: "\n -c Class. 1:realtime 2:best-effort 3:idle" 24//usage: "\n -c N Class. 1:realtime 2:best-effort 3:idle"
25//usage: "\n -n Priority" 25//usage: "\n -n N Priority"
26 26
27#include <sys/syscall.h> 27#include <sys/syscall.h>
28#include <asm/unistd.h> 28#include <asm/unistd.h>
@@ -61,7 +61,7 @@ int ionice_main(int argc UNUSED_PARAM, char **argv)
61 /* Defaults */ 61 /* Defaults */
62 int ioclass = 0; 62 int ioclass = 0;
63 int pri = 0; 63 int pri = 0;
64 int pid = 0; /* affect own porcess */ 64 int pid = 0; /* affect own process */
65 int opt; 65 int opt;
66 enum { 66 enum {
67 OPT_n = 1, 67 OPT_n = 1,
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index 59dbcf0cd..dbbcbc655 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -80,12 +80,14 @@
80//kbuild:lib-$(CONFIG_MDEV) += mdev.o 80//kbuild:lib-$(CONFIG_MDEV) += mdev.o
81 81
82//usage:#define mdev_trivial_usage 82//usage:#define mdev_trivial_usage
83//usage: "[-s]" IF_FEATURE_MDEV_DAEMON(" | [-df]") 83//usage: "[-vS] " IF_FEATURE_MDEV_DAEMON("{ ") "[-s]" IF_FEATURE_MDEV_DAEMON(" | [-df] }")
84//usage:#define mdev_full_usage "\n\n" 84//usage:#define mdev_full_usage "\n\n"
85//usage: "mdev -s is to be run during boot to scan /sys and populate /dev.\n" 85//usage: " -v verbose\n"
86//usage: " -S log to syslog too\n"
87//usage: " -s scan /sys and populate /dev\n"
86//usage: IF_FEATURE_MDEV_DAEMON( 88//usage: IF_FEATURE_MDEV_DAEMON(
87//usage: "mdev -d[f]: daemon, listen on netlink.\n" 89//usage: " -d daemon, listen on netlink\n"
88//usage: " -f: stay in foreground.\n" 90//usage: " -f stay in foreground\n"
89//usage: ) 91//usage: )
90//usage: "\n" 92//usage: "\n"
91//usage: "Bare mdev is a kernel hotplug helper. To activate it:\n" 93//usage: "Bare mdev is a kernel hotplug helper. To activate it:\n"
@@ -113,6 +115,7 @@
113#include "common_bufsiz.h" 115#include "common_bufsiz.h"
114#include "xregex.h" 116#include "xregex.h"
115#include <linux/netlink.h> 117#include <linux/netlink.h>
118#include <syslog.h>
116 119
117/* "mdev -s" scans /sys/class/xxx, looking for directories which have dev 120/* "mdev -s" scans /sys/class/xxx, looking for directories which have dev
118 * file (it is of the form "M:m\n"). Example: /sys/class/tty/tty0/dev 121 * file (it is of the form "M:m\n"). Example: /sys/class/tty/tty0/dev
@@ -269,10 +272,6 @@
269# define dbg3s(msg) ((void)0) 272# define dbg3s(msg) ((void)0)
270#endif 273#endif
271 274
272
273#ifndef SO_RCVBUFFORCE
274#define SO_RCVBUFFORCE 33
275#endif
276static const char keywords[] ALIGN1 = "add\0remove\0"; // "change\0" 275static const char keywords[] ALIGN1 = "add\0remove\0"; // "change\0"
277enum { OP_add, OP_remove }; 276enum { OP_add, OP_remove };
278 277
@@ -297,7 +296,7 @@ struct rule {
297 296
298struct globals { 297struct globals {
299 int root_major, root_minor; 298 int root_major, root_minor;
300 smallint verbose; 299 int verbose;
301 char *subsystem; 300 char *subsystem;
302 char *subsys_env; /* for putenv("SUBSYSTEM=subsystem") */ 301 char *subsys_env; /* for putenv("SUBSYSTEM=subsystem") */
303#if ENABLE_FEATURE_MDEV_CONF 302#if ENABLE_FEATURE_MDEV_CONF
@@ -921,7 +920,7 @@ static void load_firmware(const char *firmware, const char *sysfs_path)
921 loading_fd = open("loading", O_WRONLY); 920 loading_fd = open("loading", O_WRONLY);
922 if (loading_fd >= 0) 921 if (loading_fd >= 0)
923 goto loading; 922 goto loading;
924 sleep(1); 923 sleep1();
925 } 924 }
926 goto out; 925 goto out;
927 926
@@ -964,7 +963,7 @@ static void load_firmware(const char *firmware, const char *sysfs_path)
964static char *curtime(void) 963static char *curtime(void)
965{ 964{
966 struct timeval tv; 965 struct timeval tv;
967 gettimeofday(&tv, NULL); 966 xgettimeofday(&tv);
968 sprintf( 967 sprintf(
969 strftime_HHMMSS(G.timestr, sizeof(G.timestr), &tv.tv_sec), 968 strftime_HHMMSS(G.timestr, sizeof(G.timestr), &tv.tv_sec),
970 ".%06u", 969 ".%06u",
@@ -1152,15 +1151,50 @@ static void initial_scan(char *temp)
1152 1151
1153#if ENABLE_FEATURE_MDEV_DAEMON 1152#if ENABLE_FEATURE_MDEV_DAEMON
1154 1153
1155/* uevent applet uses 16k buffer, and mmaps it before every read */ 1154/*
1156# define BUFFER_SIZE (2 * 1024) 1155 * The kernel (as of v5.4) will pass up to 32 environment variables with a
1157# define RCVBUF (2 * 1024 * 1024) 1156 * total of 2kiB on each event. On top of that the action string and device
1157 * path are added. Using a 3kiB buffer for the event should suffice in any
1158 * case.
1159 *
1160 * As far as the socket receive buffer size is concerned 2MiB proved to be too
1161 * small (see [1]). Udevd seems to use a whooping 128MiB. The socket receive
1162 * buffer size is just a resource limit. The buffers are allocated lazily so
1163 * the memory is not wasted.
1164 *
1165 * [1] http://lists.busybox.net/pipermail/busybox/2019-December/087665.html
1166 */
1167# define USER_RCVBUF (3 * 1024)
1168# define KERN_RCVBUF (128 * 1024 * 1024)
1158# define MAX_ENV 32 1169# define MAX_ENV 32
1159 1170
1171static int daemon_init(char *temp)
1172{
1173 int fd;
1174
1175 /* Subscribe for UEVENT kernel messages */
1176 /* Without a sufficiently big RCVBUF, a ton of simultaneous events
1177 * can trigger ENOBUFS on read, which is unrecoverable.
1178 * Reproducer:
1179 * mdev -d
1180 * find /sys -name uevent -exec sh -c 'echo add >"{}"' ';'
1181 */
1182 fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT, 1 << 0, KERN_RCVBUF);
1183
1184 /*
1185 * Make inital scan after the uevent socket is alive and
1186 * _before_ we fork away. Already open mdev.log because we work
1187 * in daemon mode.
1188 */
1189 initial_scan(temp);
1190
1191 return fd;
1192}
1193
1160static void daemon_loop(char *temp, int fd) 1194static void daemon_loop(char *temp, int fd)
1161{ 1195{
1162 for (;;) { 1196 for (;;) {
1163 char netbuf[BUFFER_SIZE]; 1197 char netbuf[USER_RCVBUF];
1164 char *env[MAX_ENV]; 1198 char *env[MAX_ENV];
1165 char *s, *end; 1199 char *s, *end;
1166 ssize_t len; 1200 ssize_t len;
@@ -1168,6 +1202,16 @@ static void daemon_loop(char *temp, int fd)
1168 1202
1169 len = safe_read(fd, netbuf, sizeof(netbuf) - 1); 1203 len = safe_read(fd, netbuf, sizeof(netbuf) - 1);
1170 if (len < 0) { 1204 if (len < 0) {
1205 if (errno == ENOBUFS) {
1206 /*
1207 * We ran out of socket receive buffer space.
1208 * Start from scratch.
1209 */
1210 dbg1s("uevent overrun, rescanning");
1211 close(fd);
1212 fd = daemon_init(temp);
1213 continue;
1214 }
1171 bb_simple_perror_msg_and_die("read"); 1215 bb_simple_perror_msg_and_die("read");
1172 } 1216 }
1173 end = netbuf + len; 1217 end = netbuf + len;
@@ -1196,8 +1240,9 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
1196{ 1240{
1197 enum { 1241 enum {
1198 MDEV_OPT_SCAN = 1 << 0, 1242 MDEV_OPT_SCAN = 1 << 0,
1199 MDEV_OPT_DAEMON = 1 << 1, 1243 MDEV_OPT_SYSLOG = 1 << 1,
1200 MDEV_OPT_FOREGROUND = 1 << 2, 1244 MDEV_OPT_DAEMON = 1 << 2,
1245 MDEV_OPT_FOREGROUND = 1 << 3,
1201 }; 1246 };
1202 int opt; 1247 int opt;
1203 RESERVE_CONFIG_BUFFER(temp, PATH_MAX + SCRATCH_SIZE); 1248 RESERVE_CONFIG_BUFFER(temp, PATH_MAX + SCRATCH_SIZE);
@@ -1213,7 +1258,11 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
1213 1258
1214 xchdir("/dev"); 1259 xchdir("/dev");
1215 1260
1216 opt = getopt32(argv, "s" IF_FEATURE_MDEV_DAEMON("df")); 1261 opt = getopt32(argv, "^"
1262 "sS" IF_FEATURE_MDEV_DAEMON("df") "v"
1263 "\0"
1264 "vv",
1265 &G.verbose);
1217 1266
1218#if ENABLE_FEATURE_MDEV_CONF 1267#if ENABLE_FEATURE_MDEV_CONF
1219 G.filename = "/etc/mdev.conf"; 1268 G.filename = "/etc/mdev.conf";
@@ -1223,32 +1272,24 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
1223 } 1272 }
1224#endif 1273#endif
1225 1274
1275 if (opt & MDEV_OPT_SYSLOG) {
1276 openlog(applet_name, LOG_PID, LOG_DAEMON);
1277 logmode |= LOGMODE_SYSLOG;
1278 }
1279
1226#if ENABLE_FEATURE_MDEV_DAEMON 1280#if ENABLE_FEATURE_MDEV_DAEMON
1227 if (opt & MDEV_OPT_DAEMON) { 1281 if (opt & MDEV_OPT_DAEMON) {
1228 /* 1282 /* Daemon mode listening on uevent netlink socket. Fork away
1229 * Daemon mode listening on uevent netlink socket. 1283 * after initial scan so that caller can be sure everything
1230 */ 1284 * is up-to-date when mdev process returns.
1231 int fd;
1232
1233 /* Subscribe for UEVENT kernel messages */
1234 /* Without a sufficiently big RCVBUF, a ton of simultaneous events
1235 * can trigger ENOBUFS on read, which is unrecoverable.
1236 * Reproducer:
1237 * mdev -d
1238 * find /sys -name uevent -exec sh -c 'echo add >"{}"' ';'
1239 */ 1285 */
1240 fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT, 1 << 0, RCVBUF); 1286 int fd = daemon_init(temp);
1241 1287
1242 /* 1288 if (!(opt & MDEV_OPT_FOREGROUND)) {
1243 * Make inital scan after the uevent socket is alive and 1289 /* there is no point in logging to /dev/null */
1244 * _before_ we fork away. 1290 logmode &= ~LOGMODE_STDIO;
1245 */
1246 initial_scan(temp);
1247
1248 if (!(opt & MDEV_OPT_FOREGROUND))
1249 bb_daemonize_or_rexec(0, argv); 1291 bb_daemonize_or_rexec(0, argv);
1250 1292 }
1251 open_mdev_log(NULL, getpid());
1252 1293
1253 daemon_loop(temp, fd); 1294 daemon_loop(temp, fd);
1254 } 1295 }
diff --git a/util-linux/mkfs_ext2.c b/util-linux/mkfs_ext2.c
index 1f525d75b..fcf374b2d 100644
--- a/util-linux/mkfs_ext2.c
+++ b/util-linux/mkfs_ext2.c
@@ -131,7 +131,7 @@ static void allocate(uint8_t *bitmap, uint32_t blocksize, uint32_t start, uint32
131static uint32_t has_super(uint32_t x) 131static uint32_t has_super(uint32_t x)
132{ 132{
133 // 0, 1 and powers of 3, 5, 7 up to 2^32 limit 133 // 0, 1 and powers of 3, 5, 7 up to 2^32 limit
134 static const uint32_t supers[] = { 134 static const uint32_t supers[] ALIGN4 = {
135 0, 1, 3, 5, 7, 9, 25, 27, 49, 81, 125, 243, 343, 625, 729, 135 0, 1, 3, 5, 7, 9, 25, 27, 49, 81, 125, 243, 343, 625, 729,
136 2187, 2401, 3125, 6561, 15625, 16807, 19683, 59049, 78125, 136 2187, 2401, 3125, 6561, 15625, 16807, 19683, 59049, 78125,
137 117649, 177147, 390625, 531441, 823543, 1594323, 1953125, 137 117649, 177147, 390625, 531441, 823543, 1594323, 1953125,
diff --git a/util-linux/mkswap.c b/util-linux/mkswap.c
index 9e51a1dcc..8fe5d0293 100644
--- a/util-linux/mkswap.c
+++ b/util-linux/mkswap.c
@@ -128,7 +128,7 @@ int mkswap_main(int argc UNUSED_PARAM, char **argv)
128 128
129 /* Figure out how big the device is */ 129 /* Figure out how big the device is */
130 len = get_volume_size_in_bytes(fd, argv[1], 1024, /*extend:*/ 1); 130 len = get_volume_size_in_bytes(fd, argv[1], 1024, /*extend:*/ 1);
131 pagesize = getpagesize(); 131 pagesize = bb_getpagesize();
132 len -= pagesize; 132 len -= pagesize;
133 133
134 /* Announce our intentions */ 134 /* Announce our intentions */
diff --git a/util-linux/mount.c b/util-linux/mount.c
index fc5161d7f..831dab9e2 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -182,14 +182,16 @@
182//usage: "Returns 0 for success, number of failed mounts for -a, or errno for one mount." 182//usage: "Returns 0 for success, number of failed mounts for -a, or errno for one mount."
183 183
184#include <mntent.h> 184#include <mntent.h>
185#if ENABLE_FEATURE_SYSLOG
185#include <syslog.h> 186#include <syslog.h>
187#endif
186#include <sys/mount.h> 188#include <sys/mount.h>
187// Grab more as needed from util-linux's mount/mount_constants.h 189// Grab more as needed from util-linux's mount/mount_constants.h
188#ifndef MS_DIRSYNC 190#ifndef MS_DIRSYNC
189# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous 191# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous
190#endif 192#endif
191#ifndef MS_UNION 193#ifndef MS_NOSYMFOLLOW
192# define MS_UNION (1 << 8) 194# define MS_NOSYMFOLLOW (1 << 8)
193#endif 195#endif
194#ifndef MS_BIND 196#ifndef MS_BIND
195# define MS_BIND (1 << 12) 197# define MS_BIND (1 << 12)
@@ -216,12 +218,16 @@
216#ifndef MS_SHARED 218#ifndef MS_SHARED
217# define MS_SHARED (1 << 20) 219# define MS_SHARED (1 << 20)
218#endif 220#endif
221
219#ifndef MS_RELATIME 222#ifndef MS_RELATIME
220# define MS_RELATIME (1 << 21) 223# define MS_RELATIME (1 << 21)
221#endif 224#endif
222#ifndef MS_STRICTATIME 225#ifndef MS_STRICTATIME
223# define MS_STRICTATIME (1 << 24) 226# define MS_STRICTATIME (1 << 24)
224#endif 227#endif
228#ifndef MS_LAZYTIME
229# define MS_LAZYTIME (1 << 25)
230#endif
225 231
226/* Any ~MS_FOO value has this bit set: */ 232/* Any ~MS_FOO value has this bit set: */
227#define BB_MS_INVERTED_VALUE (1u << 31) 233#define BB_MS_INVERTED_VALUE (1u << 31)
@@ -323,7 +329,7 @@ enum {
323 329
324// Standard mount options (from -o options or --options), 330// Standard mount options (from -o options or --options),
325// with corresponding flags 331// with corresponding flags
326static const int32_t mount_options[] = { 332static const int32_t mount_options[] ALIGN4 = {
327 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs. 333 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
328 334
329 IF_FEATURE_MOUNT_LOOP( 335 IF_FEATURE_MOUNT_LOOP(
@@ -358,16 +364,19 @@ static const int32_t mount_options[] = {
358 /* "noatime" */ MS_NOATIME, 364 /* "noatime" */ MS_NOATIME,
359 /* "diratime" */ ~MS_NODIRATIME, 365 /* "diratime" */ ~MS_NODIRATIME,
360 /* "nodiratime" */ MS_NODIRATIME, 366 /* "nodiratime" */ MS_NODIRATIME,
361 /* "mand" */ MS_MANDLOCK,
362 /* "nomand" */ ~MS_MANDLOCK,
363 /* "relatime" */ MS_RELATIME, 367 /* "relatime" */ MS_RELATIME,
364 /* "norelatime" */ ~MS_RELATIME, 368 /* "norelatime" */ ~MS_RELATIME,
365 /* "strictatime" */ MS_STRICTATIME, 369 /* "strictatime" */ MS_STRICTATIME,
366 /* "loud" */ ~MS_SILENT, 370 /* "nostrictatime"*/ ~MS_STRICTATIME,
367 /* "rbind" */ MS_BIND|MS_RECURSIVE, 371 /* "lazytime" */ MS_LAZYTIME,
372 /* "nolazytime" */ ~MS_LAZYTIME,
373 /* "nosymfollow" */ MS_NOSYMFOLLOW,
374 /* "mand" */ MS_MANDLOCK,
375 /* "nomand" */ ~MS_MANDLOCK,
376 /* "loud" */ ~MS_SILENT,
368 377
369 // action flags 378 // action flags
370 /* "union" */ MS_UNION, 379 /* "rbind" */ MS_BIND|MS_RECURSIVE,
371 /* "bind" */ MS_BIND, 380 /* "bind" */ MS_BIND,
372 /* "move" */ MS_MOVE, 381 /* "move" */ MS_MOVE,
373 /* "shared" */ MS_SHARED, 382 /* "shared" */ MS_SHARED,
@@ -404,29 +413,32 @@ static const char mount_option_str[] ALIGN1 =
404 ) 413 )
405 IF_FEATURE_MOUNT_FLAGS( 414 IF_FEATURE_MOUNT_FLAGS(
406 // vfs flags 415 // vfs flags
407 "nosuid\0" 416 "nosuid" "\0"
408 "suid\0" 417 "suid" "\0"
409 "dev\0" 418 "dev" "\0"
410 "nodev\0" 419 "nodev" "\0"
411 "exec\0" 420 "exec" "\0"
412 "noexec\0" 421 "noexec" "\0"
413 "sync\0" 422 "sync" "\0"
414 "dirsync\0" 423 "dirsync" "\0"
415 "async\0" 424 "async" "\0"
416 "atime\0" 425 "atime" "\0"
417 "noatime\0" 426 "noatime" "\0"
418 "diratime\0" 427 "diratime" "\0"
419 "nodiratime\0" 428 "nodiratime" "\0"
420 "mand\0" 429 "relatime" "\0"
421 "nomand\0" 430 "norelatime" "\0"
422 "relatime\0" 431 "strictatime" "\0"
423 "norelatime\0" 432 "nostrictatime""\0"
424 "strictatime\0" 433 "lazytime" "\0"
425 "loud\0" 434 "nolazytime" "\0"
426 "rbind\0" 435 "nosymfollow" "\0"
436 "mand" "\0"
437 "nomand" "\0"
438 "loud" "\0"
427 439
428 // action flags 440 // action flags
429 "union\0" 441 "rbind\0"
430 "bind\0" 442 "bind\0"
431 "move\0" 443 "move\0"
432 "make-shared\0" 444 "make-shared\0"
@@ -641,7 +653,7 @@ static unsigned long parse_mount_options(char *options, char **unrecognized)
641// Return a list of all block device backed filesystems 653// Return a list of all block device backed filesystems
642static llist_t *get_block_backed_filesystems(void) 654static llist_t *get_block_backed_filesystems(void)
643{ 655{
644 static const char filesystems[2][sizeof("/proc/filesystems")] = { 656 static const char filesystems[2][sizeof("/proc/filesystems")] ALIGN1 = {
645 "/etc/filesystems", 657 "/etc/filesystems",
646 "/proc/filesystems", 658 "/proc/filesystems",
647 }; 659 };
@@ -2064,13 +2076,18 @@ static int singlemount(struct mntent *mp, int ignore_busy)
2064 } 2076 }
2065 2077
2066 // Might this be an NFS filesystem? 2078 // Might this be an NFS filesystem?
2067 if ((!mp->mnt_type || is_prefixed_with(mp->mnt_type, "nfs")) 2079 if (!(vfsflags & (MS_BIND | MS_MOVE))
2068 && strchr(mp->mnt_fsname, ':') != NULL 2080 && (!mp->mnt_type || is_prefixed_with(mp->mnt_type, "nfs"))
2069 ) { 2081 ) {
2070 if (!mp->mnt_type) 2082 char *colon = strchr(mp->mnt_fsname, ':');
2071 mp->mnt_type = (char*)"nfs"; 2083 if (colon // looks like "hostname:..."
2072 rc = nfsmount(mp, vfsflags, filteropts); 2084 && strchrnul(mp->mnt_fsname, '/') > colon // "hostname:" has no slashes
2073 goto report_error; 2085 ) {
2086 if (!mp->mnt_type)
2087 mp->mnt_type = (char*)"nfs";
2088 rc = nfsmount(mp, vfsflags, filteropts);
2089 goto report_error;
2090 }
2074 } 2091 }
2075 2092
2076 // Look at the file. (Not found isn't a failure for remount, or for 2093 // Look at the file. (Not found isn't a failure for remount, or for
@@ -2110,7 +2127,7 @@ static int singlemount(struct mntent *mp, int ignore_busy)
2110 bb_simple_error_msg(bb_msg_perm_denied_are_you_root); 2127 bb_simple_error_msg(bb_msg_perm_denied_are_you_root);
2111 else 2128 else
2112 bb_simple_perror_msg("can't setup loop device"); 2129 bb_simple_perror_msg("can't setup loop device");
2113 return errno; 2130 return loopfd; // was "return errno", but it can be 0 here
2114 } 2131 }
2115 2132
2116 // Autodetect bind mounts 2133 // Autodetect bind mounts
diff --git a/util-linux/nsenter.c b/util-linux/nsenter.c
index c48dcf885..e6339da2f 100644
--- a/util-linux/nsenter.c
+++ b/util-linux/nsenter.c
@@ -17,7 +17,7 @@
17//kbuild:lib-$(CONFIG_NSENTER) += nsenter.o 17//kbuild:lib-$(CONFIG_NSENTER) += nsenter.o
18 18
19//usage:#define nsenter_trivial_usage 19//usage:#define nsenter_trivial_usage
20//usage: "[OPTIONS] [PROG [ARGS]]" 20//usage: "[OPTIONS] [PROG ARGS]"
21//usage:#define nsenter_full_usage "\n" 21//usage:#define nsenter_full_usage "\n"
22//usage: "\n -t PID Target process to get namespaces from" 22//usage: "\n -t PID Target process to get namespaces from"
23//usage: "\n -m[FILE] Enter mount namespace" 23//usage: "\n -m[FILE] Enter mount namespace"
@@ -103,8 +103,9 @@ static const struct namespace_descr ns_list[] = {
103}; 103};
104/* 104/*
105 * Upstream nsenter doesn't support the short option for --preserve-credentials 105 * Upstream nsenter doesn't support the short option for --preserve-credentials
106 * "+": stop on first non-option
106 */ 107 */
107static const char opt_str[] ALIGN1 = "U::i::u::n::p::m::""t:+S:+G:+r::w::F"; 108static const char opt_str[] ALIGN1 = "+""U::i::u::n::p::m::""t:+S:+G:+r::w::F";
108 109
109#if ENABLE_LONG_OPTS 110#if ENABLE_LONG_OPTS
110static const char nsenter_longopts[] ALIGN1 = 111static const char nsenter_longopts[] ALIGN1 =
diff --git a/util-linux/rdate.c b/util-linux/rdate.c
index bb1dc519a..9b80141c9 100644
--- a/util-linux/rdate.c
+++ b/util-linux/rdate.c
@@ -96,11 +96,10 @@ int rdate_main(int argc UNUSED_PARAM, char **argv)
96 if (time(NULL) == remote_time) 96 if (time(NULL) == remote_time)
97 bb_simple_error_msg("current time matches remote time"); 97 bb_simple_error_msg("current time matches remote time");
98 else { 98 else {
99 struct timespec ts; 99 struct timeval ts;
100 ts.tv_sec = remote_time; 100 ts.tv_sec = remote_time;
101 ts.tv_nsec = 0; 101 ts.tv_usec = 0;
102 if (clock_settime(CLOCK_REALTIME, &ts) < 0) 102 xsettimeofday(&ts);
103 bb_simple_perror_msg_and_die("can't set time of day");
104 } 103 }
105 } 104 }
106 105
diff --git a/util-linux/rtcwake.c b/util-linux/rtcwake.c
index 823e55662..eac16077d 100644
--- a/util-linux/rtcwake.c
+++ b/util-linux/rtcwake.c
@@ -36,24 +36,13 @@
36//usage: "[-a | -l | -u] [-d DEV] [-m MODE] [-s SEC | -t TIME]" 36//usage: "[-a | -l | -u] [-d DEV] [-m MODE] [-s SEC | -t TIME]"
37//usage:#define rtcwake_full_usage "\n\n" 37//usage:#define rtcwake_full_usage "\n\n"
38//usage: "Enter a system sleep state until specified wakeup time\n" 38//usage: "Enter a system sleep state until specified wakeup time\n"
39//usage: IF_LONG_OPTS( 39//usage: "\n -a Read clock mode from "ADJTIME_PATH" (default)"
40//usage: "\n -a,--auto Read clock mode from adjtime"
41//usage: "\n -l,--local Clock is set to local time"
42//usage: "\n -u,--utc Clock is set to UTC time"
43//usage: "\n -d,--device DEV Specify the RTC device"
44//usage: "\n -m,--mode MODE Set sleep state (default: standby)"
45//usage: "\n -s,--seconds SEC Set timeout in SEC seconds from now"
46//usage: "\n -t,--time TIME Set timeout to TIME seconds from epoch"
47//usage: )
48//usage: IF_NOT_LONG_OPTS(
49//usage: "\n -a Read clock mode from adjtime"
50//usage: "\n -l Clock is set to local time" 40//usage: "\n -l Clock is set to local time"
51//usage: "\n -u Clock is set to UTC time" 41//usage: "\n -u Clock is set to UTC time"
52//usage: "\n -d DEV Specify the RTC device" 42//usage: "\n -d DEV Specify the RTC device"
53//usage: "\n -m MODE Set sleep state (default: standby)" 43//usage: "\n -m MODE Set sleep state (default: standby)"
54//usage: "\n -s SEC Set timeout in SEC seconds from now" 44//usage: "\n -s SEC Set timeout in SEC seconds from now"
55//usage: "\n -t TIME Set timeout to TIME seconds from epoch" 45//usage: "\n -t TIME Set timeout to TIME seconds from epoch"
56//usage: )
57 46
58#include "libbb.h" 47#include "libbb.h"
59#include "rtc_.h" 48#include "rtc_.h"
diff --git a/util-linux/script.c b/util-linux/script.c
index 4eac5e94f..963435335 100644
--- a/util-linux/script.c
+++ b/util-linux/script.c
@@ -172,7 +172,7 @@ int script_main(int argc UNUSED_PARAM, char **argv)
172 struct timeval tv; 172 struct timeval tv;
173 double newtime; 173 double newtime;
174 174
175 gettimeofday(&tv, NULL); 175 xgettimeofday(&tv);
176 newtime = tv.tv_sec + (double) tv.tv_usec / 1000000; 176 newtime = tv.tv_sec + (double) tv.tv_usec / 1000000;
177 fprintf(timing_fp, "%f %u\n", newtime - oldtime, count); 177 fprintf(timing_fp, "%f %u\n", newtime - oldtime, count);
178 oldtime = newtime; 178 oldtime = newtime;
diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c
index 1e4b201ed..6904cf019 100644
--- a/util-linux/setpriv.c
+++ b/util-linux/setpriv.c
@@ -47,7 +47,7 @@
47//kbuild:lib-$(CONFIG_SETPRIV) += setpriv.o 47//kbuild:lib-$(CONFIG_SETPRIV) += setpriv.o
48 48
49//usage:#define setpriv_trivial_usage 49//usage:#define setpriv_trivial_usage
50//usage: "[OPTIONS] PROG [ARGS]" 50//usage: "[OPTIONS] PROG ARGS"
51//usage:#define setpriv_full_usage "\n\n" 51//usage:#define setpriv_full_usage "\n\n"
52//usage: "Run PROG with different privilege settings\n" 52//usage: "Run PROG with different privilege settings\n"
53//usage: IF_FEATURE_SETPRIV_DUMP( 53//usage: IF_FEATURE_SETPRIV_DUMP(
diff --git a/util-linux/uevent.c b/util-linux/uevent.c
index 57d9328ef..db11746d0 100644
--- a/util-linux/uevent.c
+++ b/util-linux/uevent.c
@@ -15,7 +15,7 @@
15//kbuild:lib-$(CONFIG_UEVENT) += uevent.o 15//kbuild:lib-$(CONFIG_UEVENT) += uevent.o
16 16
17//usage:#define uevent_trivial_usage 17//usage:#define uevent_trivial_usage
18//usage: "[PROG [ARGS]]" 18//usage: "[PROG ARGS]"
19//usage:#define uevent_full_usage "\n\n" 19//usage:#define uevent_full_usage "\n\n"
20//usage: "uevent runs PROG for every netlink notification." 20//usage: "uevent runs PROG for every netlink notification."
21//usage: "\n""PROG's environment contains data passed from the kernel." 21//usage: "\n""PROG's environment contains data passed from the kernel."
@@ -26,22 +26,26 @@
26#include "common_bufsiz.h" 26#include "common_bufsiz.h"
27#include <linux/netlink.h> 27#include <linux/netlink.h>
28 28
29#define BUFFER_SIZE 16*1024
30
31#define env ((char **)bb_common_bufsiz1) 29#define env ((char **)bb_common_bufsiz1)
32#define INIT_G() do { setup_common_bufsiz(); } while (0) 30#define INIT_G() do { setup_common_bufsiz(); } while (0)
33enum { 31enum {
34 MAX_ENV = COMMON_BUFSIZE / sizeof(char*) - 1, 32 MAX_ENV = COMMON_BUFSIZE / sizeof(char*) - 1,
35 /* sizeof(env[0]) instead of sizeof(char*) 33 // ^^^sizeof(env[0]) instead of sizeof(char*)
36 * makes gcc-6.3.0 emit "strict-aliasing" warning. 34 // makes gcc-6.3.0 emit "strict-aliasing" warning.
37 */ 35
36 // socket receive buffer of 2MiB proved to be too small:
37 // http://lists.busybox.net/pipermail/busybox/2019-December/087665.html
38 // udevd seems to use a whooping 128MiB.
39 // The socket receive buffer size is just a resource limit.
40 // The buffers are allocated lazily so the memory is not wasted.
41 KERN_RCVBUF = 128 * 1024 * 1024,
42
43 // Might be made smaller: the kernel v5.4 passes up to 32 environment
44 // variables with a total of 2kb on each event.
45 // On top of that the action string and device path are added.
46 USER_RCVBUF = 16 * 1024,
38}; 47};
39 48
40#ifndef SO_RCVBUFFORCE
41#define SO_RCVBUFFORCE 33
42#endif
43enum { RCVBUF = 2 * 1024 * 1024 };
44
45int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 49int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
46int uevent_main(int argc UNUSED_PARAM, char **argv) 50int uevent_main(int argc UNUSED_PARAM, char **argv)
47{ 51{
@@ -57,7 +61,8 @@ int uevent_main(int argc UNUSED_PARAM, char **argv)
57 // Reproducer: 61 // Reproducer:
58 // uevent mdev & 62 // uevent mdev &
59 // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';' 63 // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';'
60 fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT, /*groups:*/ 1 << 0, RCVBUF); 64 reopen:
65 fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT, /*groups:*/ 1 << 0, KERN_RCVBUF);
61 66
62 for (;;) { 67 for (;;) {
63 char *netbuf; 68 char *netbuf;
@@ -69,17 +74,20 @@ int uevent_main(int argc UNUSED_PARAM, char **argv)
69 // for a new uevent notification to come in. 74 // for a new uevent notification to come in.
70 // We use a fresh mmap so that buffer is not allocated 75 // We use a fresh mmap so that buffer is not allocated
71 // until kernel actually starts filling it. 76 // until kernel actually starts filling it.
72 netbuf = mmap(NULL, BUFFER_SIZE, 77 netbuf = xmmap_anon(USER_RCVBUF);
73 PROT_READ | PROT_WRITE,
74 MAP_PRIVATE | MAP_ANON,
75 /* ignored: */ -1, 0);
76 if (netbuf == MAP_FAILED)
77 bb_simple_perror_msg_and_die("mmap");
78 78
79 // Here we block, possibly for a very long time 79 // Here we block, possibly for a very long time
80 len = safe_read(fd, netbuf, BUFFER_SIZE - 1); 80 len = safe_read(fd, netbuf, USER_RCVBUF - 1);
81 if (len < 0) 81 if (len < 0) {
82 if (errno == ENOBUFS) {
83 // Ran out of socket receive buffer
84 bb_simple_error_msg("uevent overrun");
85 close(fd);
86 munmap(netbuf, USER_RCVBUF);
87 goto reopen;
88 }
82 bb_simple_perror_msg_and_die("read"); 89 bb_simple_perror_msg_and_die("read");
90 }
83 end = netbuf + len; 91 end = netbuf + len;
84 *end = '\0'; 92 *end = '\0';
85 93
@@ -108,7 +116,7 @@ int uevent_main(int argc UNUSED_PARAM, char **argv)
108 while (env[idx]) 116 while (env[idx])
109 bb_unsetenv(env[idx++]); 117 bb_unsetenv(env[idx++]);
110 } 118 }
111 munmap(netbuf, BUFFER_SIZE); 119 munmap(netbuf, USER_RCVBUF);
112 } 120 }
113 121
114 return 0; // not reached 122 return 0; // not reached
diff --git a/util-linux/umount.c b/util-linux/umount.c
index 63a3bf504..23da32868 100644
--- a/util-linux/umount.c
+++ b/util-linux/umount.c
@@ -41,16 +41,16 @@
41//kbuild:lib-$(CONFIG_UMOUNT) += umount.o 41//kbuild:lib-$(CONFIG_UMOUNT) += umount.o
42 42
43//usage:#define umount_trivial_usage 43//usage:#define umount_trivial_usage
44//usage: "[OPTIONS] FILESYSTEM|DIRECTORY" 44//usage: "[-rlf"IF_FEATURE_MTAB_SUPPORT("m")IF_FEATURE_MOUNT_LOOP("d")IF_FEATURE_UMOUNT_ALL("a")"] [-t FSTYPE] FILESYSTEM|DIRECTORY"
45//usage:#define umount_full_usage "\n\n" 45//usage:#define umount_full_usage "\n\n"
46//usage: "Unmount file systems\n" 46//usage: "Unmount filesystems\n"
47//usage: IF_FEATURE_UMOUNT_ALL( 47//usage: IF_FEATURE_UMOUNT_ALL(
48//usage: "\n -a Unmount all file systems" IF_FEATURE_MTAB_SUPPORT(" in /etc/mtab") 48//usage: "\n -a Unmount all filesystems" IF_FEATURE_MTAB_SUPPORT(" in /etc/mtab")
49//usage: ) 49//usage: )
50//usage: IF_FEATURE_MTAB_SUPPORT( 50//usage: IF_FEATURE_MTAB_SUPPORT(
51//usage: "\n -n Don't erase /etc/mtab entries" 51//usage: "\n -n Don't erase /etc/mtab entries"
52//usage: ) 52//usage: )
53//usage: "\n -r Try to remount devices as read-only if mount is busy" 53//usage: "\n -r Remount devices read-only if mount is busy"
54//usage: "\n -l Lazy umount (detach filesystem)" 54//usage: "\n -l Lazy umount (detach filesystem)"
55//usage: "\n -f Force umount (i.e., unreachable NFS server)" 55//usage: "\n -f Force umount (i.e., unreachable NFS server)"
56//usage: IF_FEATURE_MOUNT_LOOP( 56//usage: IF_FEATURE_MOUNT_LOOP(
diff --git a/util-linux/unshare.c b/util-linux/unshare.c
index 2087413e8..68ccdd874 100644
--- a/util-linux/unshare.c
+++ b/util-linux/unshare.c
@@ -23,7 +23,7 @@
23//kbuild:lib-$(CONFIG_UNSHARE) += unshare.o 23//kbuild:lib-$(CONFIG_UNSHARE) += unshare.o
24 24
25//usage:#define unshare_trivial_usage 25//usage:#define unshare_trivial_usage
26//usage: "[OPTIONS] [PROG [ARGS]]" 26//usage: "[OPTIONS] [PROG ARGS]"
27//usage:#define unshare_full_usage "\n" 27//usage:#define unshare_full_usage "\n"
28//usage: "\n -m,--mount[=FILE] Unshare mount namespace" 28//usage: "\n -m,--mount[=FILE] Unshare mount namespace"
29//usage: "\n -u,--uts[=FILE] Unshare UTS namespace (hostname etc.)" 29//usage: "\n -u,--uts[=FILE] Unshare UTS namespace (hostname etc.)"
@@ -31,8 +31,8 @@
31//usage: "\n -n,--net[=FILE] Unshare network namespace" 31//usage: "\n -n,--net[=FILE] Unshare network namespace"
32//usage: "\n -p,--pid[=FILE] Unshare PID namespace" 32//usage: "\n -p,--pid[=FILE] Unshare PID namespace"
33//usage: "\n -U,--user[=FILE] Unshare user namespace" 33//usage: "\n -U,--user[=FILE] Unshare user namespace"
34//usage: "\n -f,--fork Fork before execing PROG" 34//usage: "\n -f Fork before execing PROG"
35//usage: "\n -r,--map-root-user Map current user to root (implies -U)" 35//usage: "\n -r Map current user to root (implies -U)"
36//usage: "\n --mount-proc[=DIR] Mount /proc filesystem first (implies -m)" 36//usage: "\n --mount-proc[=DIR] Mount /proc filesystem first (implies -m)"
37//usage: "\n --propagation slave|shared|private|unchanged" 37//usage: "\n --propagation slave|shared|private|unchanged"
38//usage: "\n Modify mount propagation in mount namespace" 38//usage: "\n Modify mount propagation in mount namespace"
diff --git a/util-linux/volume_id/erofs.c b/util-linux/volume_id/erofs.c
new file mode 100644
index 000000000..a163a353d
--- /dev/null
+++ b/util-linux/volume_id/erofs.c
@@ -0,0 +1,67 @@
1/*
2 * volume_id - reads filesystem label and uuid
3 *
4 * Copyright (C) 2020 Norbert Lange <nolange79@gmail.com>
5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */
8//config:config FEATURE_VOLUMEID_EROFS
9//config: bool "erofs filesystem"
10//config: default y
11//config: depends on VOLUMEID
12//config: help
13//config: Erofs is a compressed readonly filesystem for Linux.
14
15//kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_EROFS) += erofs.o
16
17#include "volume_id_internal.h"
18
19#define EROFS_SUPER_MAGIC_V1 0xE0F5E1E2
20#define EROFS_SUPER_OFFSET 1024
21#define EROFS_FEATURE_COMPAT_SB_CHKSUM 0x00000001
22
23/* 128-byte erofs on-disk super block */
24struct erofs_super_block {
25 uint32_t magic; /* file system magic number */
26 uint32_t checksum; /* crc32c(super_block) */
27 uint32_t feature_compat;
28 uint8_t blkszbits; /* support block_size == PAGE_SIZE only */
29 uint8_t reserved;
30
31 uint16_t root_nid; /* nid of root directory */
32 uint64_t inos; /* total valid ino # (== f_files - f_favail) */
33
34 uint64_t build_time; /* inode v1 time derivation */
35 uint32_t build_time_nsec; /* inode v1 time derivation in nano scale */
36 uint32_t blocks; /* used for statfs */
37 uint32_t meta_blkaddr; /* start block address of metadata area */
38 uint32_t xattr_blkaddr; /* start block address of shared xattr area */
39 uint8_t uuid[16]; /* 128-bit uuid for volume */
40 uint8_t volume_name[16]; /* volume name */
41 uint32_t feature_incompat;
42 uint8_t reserved2[44];
43} PACKED;
44
45int FAST_FUNC volume_id_probe_erofs(struct volume_id *id /*,uint64_t off*/)
46{
47 struct erofs_super_block *sb;
48
49 BUILD_BUG_ON(sizeof(struct erofs_super_block) != 128);
50
51 dbg("erofs: probing at offset 0x%llx", EROFS_SUPER_OFFSET);
52 sb = volume_id_get_buffer(id, EROFS_SUPER_OFFSET, sizeof(*sb));
53 if (!sb)
54 return -1;
55
56 if (sb->magic != cpu_to_le32(EROFS_SUPER_MAGIC_V1))
57 return -1;
58
59 IF_FEATURE_BLKID_TYPE(id->type = "erofs");
60
61 volume_id_set_label_string(id, sb->volume_name,
62 MIN(sizeof(sb->volume_name), VOLUME_ID_LABEL_SIZE));
63
64 volume_id_set_uuid(id, sb->uuid, UUID_DCE);
65
66 return 0;
67}
diff --git a/util-linux/volume_id/volume_id.c b/util-linux/volume_id/volume_id.c
index c3f07a741..8ceb61bde 100644
--- a/util-linux/volume_id/volume_id.c
+++ b/util-linux/volume_id/volume_id.c
@@ -49,7 +49,7 @@
49typedef int FAST_FUNC (*raid_probe_fptr)(struct volume_id *id, /*uint64_t off,*/ uint64_t size); 49typedef int FAST_FUNC (*raid_probe_fptr)(struct volume_id *id, /*uint64_t off,*/ uint64_t size);
50typedef int FAST_FUNC (*probe_fptr)(struct volume_id *id /*, uint64_t off*/); 50typedef int FAST_FUNC (*probe_fptr)(struct volume_id *id /*, uint64_t off*/);
51 51
52static const raid_probe_fptr raid1[] = { 52static const raid_probe_fptr raid1[] ALIGN_PTR = {
53#if ENABLE_FEATURE_VOLUMEID_LINUXRAID 53#if ENABLE_FEATURE_VOLUMEID_LINUXRAID
54 volume_id_probe_linux_raid, 54 volume_id_probe_linux_raid,
55#endif 55#endif
@@ -76,7 +76,7 @@ static const raid_probe_fptr raid1[] = {
76#endif 76#endif
77}; 77};
78 78
79static const probe_fptr raid2[] = { 79static const probe_fptr raid2[] ALIGN_PTR = {
80#if ENABLE_FEATURE_VOLUMEID_LVM 80#if ENABLE_FEATURE_VOLUMEID_LVM
81 volume_id_probe_lvm1, 81 volume_id_probe_lvm1,
82 volume_id_probe_lvm2, 82 volume_id_probe_lvm2,
@@ -90,7 +90,7 @@ static const probe_fptr raid2[] = {
90}; 90};
91 91
92/* signature in the first block, only small buffer needed */ 92/* signature in the first block, only small buffer needed */
93static const probe_fptr fs1[] = { 93static const probe_fptr fs1[] ALIGN_PTR = {
94#if ENABLE_FEATURE_VOLUMEID_FAT 94#if ENABLE_FEATURE_VOLUMEID_FAT
95 volume_id_probe_vfat, 95 volume_id_probe_vfat,
96#endif 96#endif
@@ -106,6 +106,9 @@ static const probe_fptr fs1[] = {
106#if ENABLE_FEATURE_VOLUMEID_SQUASHFS 106#if ENABLE_FEATURE_VOLUMEID_SQUASHFS
107 volume_id_probe_squashfs, 107 volume_id_probe_squashfs,
108#endif 108#endif
109#if ENABLE_FEATURE_VOLUMEID_EROFS
110 volume_id_probe_erofs,
111#endif
109#if ENABLE_FEATURE_VOLUMEID_XFS 112#if ENABLE_FEATURE_VOLUMEID_XFS
110 volume_id_probe_xfs, 113 volume_id_probe_xfs,
111#endif 114#endif
@@ -115,7 +118,7 @@ static const probe_fptr fs1[] = {
115}; 118};
116 119
117/* fill buffer with maximum */ 120/* fill buffer with maximum */
118static const probe_fptr fs2[] = { 121static const probe_fptr fs2[] ALIGN_PTR = {
119#if ENABLE_FEATURE_VOLUMEID_LINUXSWAP 122#if ENABLE_FEATURE_VOLUMEID_LINUXSWAP
120 volume_id_probe_linux_swap, 123 volume_id_probe_linux_swap,
121#endif 124#endif
diff --git a/util-linux/volume_id/volume_id_internal.h b/util-linux/volume_id/volume_id_internal.h
index ada18339d..b1e44481f 100644
--- a/util-linux/volume_id/volume_id_internal.h
+++ b/util-linux/volume_id/volume_id_internal.h
@@ -66,6 +66,9 @@ struct volume_id {
66 uint8_t *sbbuf; 66 uint8_t *sbbuf;
67 uint8_t *seekbuf; 67 uint8_t *seekbuf;
68 uint64_t seekbuf_off; 68 uint64_t seekbuf_off;
69#if ENABLE_FEATURE_BLKID_TYPE
70 const char *type;
71#endif
69#ifdef UNUSED_PARTITION_CODE 72#ifdef UNUSED_PARTITION_CODE
70 struct volume_id_partition *partitions; 73 struct volume_id_partition *partitions;
71 size_t partition_count; 74 size_t partition_count;
@@ -80,9 +83,6 @@ struct volume_id {
80// char type_version[VOLUME_ID_FORMAT_SIZE]; 83// char type_version[VOLUME_ID_FORMAT_SIZE];
81// smallint usage_id; 84// smallint usage_id;
82// const char *usage; 85// const char *usage;
83#if ENABLE_FEATURE_BLKID_TYPE
84 const char *type;
85#endif
86}; 86};
87 87
88struct volume_id* FAST_FUNC volume_id_open_node(int fd); 88struct volume_id* FAST_FUNC volume_id_open_node(int fd);
@@ -215,6 +215,8 @@ int FAST_FUNC volume_id_probe_romfs(struct volume_id *id /*,uint64_t off*/);
215 215
216int FAST_FUNC volume_id_probe_squashfs(struct volume_id *id /*,uint64_t off*/); 216int FAST_FUNC volume_id_probe_squashfs(struct volume_id *id /*,uint64_t off*/);
217 217
218int FAST_FUNC volume_id_probe_erofs(struct volume_id *id /*,uint64_t off*/);
219
218int FAST_FUNC volume_id_probe_sysv(struct volume_id *id /*,uint64_t off*/); 220int FAST_FUNC volume_id_probe_sysv(struct volume_id *id /*,uint64_t off*/);
219 221
220int FAST_FUNC volume_id_probe_udf(struct volume_id *id /*,uint64_t off*/); 222int FAST_FUNC volume_id_probe_udf(struct volume_id *id /*,uint64_t off*/);