aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2015-10-13 14:45:51 +0100
committerRon Yorston <rmy@pobox.com>2015-10-13 14:45:51 +0100
commit8e509f11bceeec419abc718300bef7422d1fee4c (patch)
treefdfbc752ad94102e3613a5d7254f14a93eaf7f56
parent420f5edfe7676fe6e7cddbbf15c04649d096e422 (diff)
parent4d0c1ea4784c9844f8468d97ca5c26d3c70f9921 (diff)
downloadbusybox-w32-8e509f11bceeec419abc718300bef7422d1fee4c.tar.gz
busybox-w32-8e509f11bceeec419abc718300bef7422d1fee4c.tar.bz2
busybox-w32-8e509f11bceeec419abc718300bef7422d1fee4c.zip
Merge branch 'busybox' into merge
-rw-r--r--Makefile2
-rw-r--r--Makefile.flags23
-rwxr-xr-xapplets/usage_compressed9
-rw-r--r--archival/dpkg.c8
-rw-r--r--archival/libarchive/data_extract_to_command.c2
-rw-r--r--configs/android_ndk_defconfig181
-rw-r--r--coreutils/chmod.c4
-rw-r--r--coreutils/install.c2
-rw-r--r--coreutils/libcoreutils/getopt_mk_fifo_nod.c4
-rw-r--r--coreutils/mkdir.c4
-rw-r--r--coreutils/sort.c12
-rw-r--r--coreutils/uniq.c2
-rw-r--r--coreutils/uudecode.c13
-rw-r--r--coreutils/who.c2
-rw-r--r--debianutils/run_parts.c2
-rw-r--r--editors/awk.c115
-rw-r--r--editors/diff.c4
-rw-r--r--editors/ed.c2
-rw-r--r--editors/vi.c8
-rw-r--r--findutils/find.c8
-rw-r--r--findutils/xargs.c2
-rw-r--r--include/applets.src.h1
-rw-r--r--include/libbb.h18
-rw-r--r--init/init.c9
-rw-r--r--libbb/auto_string.c23
-rw-r--r--libbb/bb_askpass.c6
-rw-r--r--libbb/bbunit.c31
-rw-r--r--libbb/compare_string_array.c59
-rw-r--r--libbb/fflush_stdout_and_exit.c13
-rw-r--r--libbb/hash_md5_sha.c16
-rw-r--r--libbb/human_readable.c9
-rw-r--r--libbb/messages.c2
-rw-r--r--libbb/parse_mode.c16
-rw-r--r--libbb/printable_string.c10
-rw-r--r--libbb/procps.c4
-rw-r--r--libbb/udp_io.c4
-rw-r--r--libbb/vfork_daemon_rexec.c39
-rw-r--r--libbb/xconnect.c25
-rw-r--r--libbb/xfunc_die.c26
-rw-r--r--libpwdgrp/pwd_grp.c17
-rw-r--r--loginutils/add-remove-shell.c4
-rw-r--r--loginutils/adduser.c11
-rw-r--r--loginutils/getty.c7
-rw-r--r--loginutils/login.c3
-rw-r--r--mailutils/mail.c2
-rw-r--r--mailutils/sendmail.c2
-rw-r--r--miscutils/devfsd.c19
-rw-r--r--miscutils/hdparm.c58
-rw-r--r--miscutils/i2c_tools.c210
-rw-r--r--miscutils/last.c3
-rw-r--r--modutils/modprobe.c34
-rw-r--r--networking/Config.src49
-rw-r--r--networking/Kbuild.src1
-rw-r--r--networking/arping.c29
-rw-r--r--networking/brctl.c56
-rw-r--r--networking/ftpd.c25
-rw-r--r--networking/ftpgetput.c7
-rw-r--r--networking/httpd.c10
-rw-r--r--networking/ifenslave.c8
-rw-r--r--networking/ifplugd.c16
-rw-r--r--networking/ifupdown.c4
-rw-r--r--networking/interface.c24
-rw-r--r--networking/isrv.c4
-rw-r--r--networking/libiproute/ipaddress.c14
-rw-r--r--networking/libiproute/iproute.c3
-rw-r--r--networking/libiproute/iprule.c11
-rw-r--r--networking/libiproute/iptunnel.c3
-rw-r--r--networking/libiproute/ll_map.c14
-rw-r--r--networking/libiproute/ll_map.h2
-rw-r--r--networking/libiproute/rt_names.c93
-rw-r--r--networking/libiproute/rt_names.h11
-rw-r--r--networking/libiproute/rtm_map.c6
-rw-r--r--networking/libiproute/rtm_map.h2
-rw-r--r--networking/nbd-client.c2
-rw-r--r--networking/nc_bloaty.c4
-rw-r--r--networking/ntpd.c6
-rw-r--r--networking/ping.c24
-rwxr-xr-xnetworking/ssl_helper-wolfssl/00cfg-wolfssl-3.6.822
-rw-r--r--networking/ssl_helper-wolfssl/README20
-rw-r--r--networking/ssl_helper-wolfssl/ssl_helper.c480
-rwxr-xr-xnetworking/ssl_helper-wolfssl/ssl_helper.sh12
-rw-r--r--networking/tc.c7
-rw-r--r--networking/telnet.c2
-rw-r--r--networking/telnetd.c2
-rw-r--r--networking/tftp.c7
-rw-r--r--networking/traceroute.c115
-rw-r--r--networking/udhcp/dhcpc.c18
-rw-r--r--networking/wget.c159
-rw-r--r--networking/zcip.c363
-rw-r--r--printutils/lpd.c8
-rw-r--r--procps/iostat.c2
-rw-r--r--procps/powertop.c6
-rw-r--r--qemu_multiarch_testing/README58
-rwxr-xr-xqemu_multiarch_testing/extract_od_binary.sh6
-rwxr-xr-xqemu_multiarch_testing/hdc.dir/build50
-rwxr-xr-xqemu_multiarch_testing/hdc.dir/init9
-rwxr-xr-xqemu_multiarch_testing/make-hdc-img.sh30
-rwxr-xr-xqemu_multiarch_testing/parallel-build-hdc-img.sh40
-rw-r--r--runit/runsv.c19
-rwxr-xr-xscripts/randomtest4
-rw-r--r--shell/ash.c255
-rw-r--r--shell/ash_test/ash-glob/glob1.right2
-rwxr-xr-xshell/ash_test/ash-glob/glob1.tests2
-rw-r--r--shell/ash_test/ash-glob/glob2.right18
-rwxr-xr-xshell/ash_test/ash-glob/glob2.tests27
-rw-r--r--shell/ash_test/ash-glob/glob3.right2
-rwxr-xr-xshell/ash_test/ash-glob/glob3.tests2
-rw-r--r--shell/ash_test/ash-glob/glob_and_assign.right6
-rwxr-xr-xshell/ash_test/ash-glob/glob_and_assign.tests10
-rw-r--r--shell/ash_test/ash-glob/glob_redir.right2
-rwxr-xr-xshell/ash_test/ash-glob/glob_redir.tests9
-rw-r--r--shell/hush.c82
-rw-r--r--shell/hush_test/hush-glob/glob3.right2
-rwxr-xr-xshell/hush_test/hush-glob/glob3.tests2
-rw-r--r--shell/hush_test/hush-misc/nommu3.right2
-rwxr-xr-xshell/hush_test/hush-misc/nommu3.tests15
-rw-r--r--shell/shell_common.c2
-rwxr-xr-xtestsuite/awk.tests5
-rwxr-xr-xtestsuite/bzcat.tests16
-rwxr-xr-xtestsuite/makedevs.tests2
-rw-r--r--testsuite/pwd/pwd-prints-working-directory5
-rwxr-xr-xtestsuite/readlink.tests11
-rwxr-xr-xtestsuite/sort.tests8
-rw-r--r--util-linux/dmesg.c8
-rw-r--r--util-linux/fdformat.c4
-rw-r--r--util-linux/fdisk.c94
-rw-r--r--util-linux/fdisk_gpt.c4
-rw-r--r--util-linux/fsck_minix.c16
-rw-r--r--util-linux/getopt.c2
-rw-r--r--util-linux/ipcrm.c2
-rw-r--r--util-linux/mdev.c2
-rw-r--r--util-linux/mkfs_minix.c10
-rw-r--r--util-linux/switch_root.c2
-rw-r--r--util-linux/uevent.c6
-rw-r--r--util-linux/umount.c16
135 files changed, 2335 insertions, 1275 deletions
diff --git a/Makefile b/Makefile
index b36e2c14d..966578a0f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
1VERSION = 1 1VERSION = 1
2PATCHLEVEL = 24 2PATCHLEVEL = 25
3SUBLEVEL = 0 3SUBLEVEL = 0
4EXTRAVERSION = .git 4EXTRAVERSION = .git
5NAME = Unnamed 5NAME = Unnamed
diff --git a/Makefile.flags b/Makefile.flags
index 58fcf33eb..c3ac5b458 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -57,6 +57,9 @@ CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1
57# Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary): 57# Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary):
58CFLAGS += $(call cc-option,-fno-unwind-tables,) 58CFLAGS += $(call cc-option,-fno-unwind-tables,)
59CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,) 59CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,)
60# No automatic printf->puts,putchar conversions
61# (try disabling this and comparing assembly, it's instructive)
62CFLAGS += $(call cc-option,-fno-builtin-printf,)
60 63
61# FIXME: These warnings are at least partially to be concerned about and should 64# FIXME: These warnings are at least partially to be concerned about and should
62# be fixed.. 65# be fixed..
@@ -134,15 +137,19 @@ else
134LDLIBS += m 137LDLIBS += m
135endif 138endif
136 139
140# libpam may use libpthread, libdl and/or libaudit.
141# On some platforms that requires an explicit -lpthread, -ldl, -laudit.
142# However, on *other platforms* it fails when some of those flags
143# given needlessly. On some systems, crypt needs pthread.
144#
145# I even had a system where a runtime test for pthread
146# (similar to CRYPT_AVAILABLE test above) was not reliable.
147#
148# Do not propagate this mess by adding libraries to CONFIG_PAM/CRYPT_AVAILABLE blocks.
149# Add libraries you need to CONFIG_EXTRA_LDLIBS instead.
150
137ifeq ($(CONFIG_PAM),y) 151ifeq ($(CONFIG_PAM),y)
138# libpam uses libpthread, so for static builds busybox must be linked to 152LDLIBS += pam pam_misc
139# libpthread. On some platforms that requires an explicit -lpthread, so
140# it should be in LDLIBS. For non-static builds, scripts/trylink will
141# take care of removing -lpthread if possible. (Not bothering to check
142# CONFIG_STATIC because even in a non-static build it could be that the
143# only libpam available is libpam.a, so -lpthread could still be
144# needed.)
145LDLIBS += pam pam_misc pthread
146endif 153endif
147 154
148ifeq ($(CONFIG_SELINUX),y) 155ifeq ($(CONFIG_SELINUX),y)
diff --git a/applets/usage_compressed b/applets/usage_compressed
index fb6e1c286..186fcde77 100755
--- a/applets/usage_compressed
+++ b/applets/usage_compressed
@@ -20,6 +20,7 @@ exec >"$target.$$"
20 20
21echo '#define UNPACKED_USAGE "" \' 21echo '#define UNPACKED_USAGE "" \'
22"$loc/usage" | od -v -b \ 22"$loc/usage" | od -v -b \
23| grep -v '^ ' \
23| $SED -e 's/^[^ ]*//' \ 24| $SED -e 's/^[^ ]*//' \
24 -e 's/ //g' \ 25 -e 's/ //g' \
25 -e '/^$/d' \ 26 -e '/^$/d' \
@@ -27,6 +28,13 @@ echo '#define UNPACKED_USAGE "" \'
27 -e 's/^/"/' \ 28 -e 's/^/"/' \
28 -e 's/$/" \\/' 29 -e 's/$/" \\/'
29echo '' 30echo ''
31# "grep -v '^ '" is for toybox's od bug: od -b prints some extra lines:
32#0000000 010 000 010 000 133 055 144 146 135 040 133 055 143 040 103 117
33# 000010 000010 026533 063144 020135 026533 020143 047503
34#0000020 116 106 104 111 122 135 040 133 055 154 040 114 117 107 106 111
35# 043116 044504 056522 055440 066055 046040 043517 044506
36#0000040 114 105 135 040 133 055 141 040 101 103 124 111 117 116 106 111
37# 042514 020135 026533 020141 041501 044524 047117 044506
30 38
31echo '#define PACKED_USAGE \' 39echo '#define PACKED_USAGE \'
32## Breaks on big-endian systems! 40## Breaks on big-endian systems!
@@ -40,6 +48,7 @@ echo '#define PACKED_USAGE \'
40## -e 's/\(..\)\(..\)/0x\2,0x\1,/g' 48## -e 's/\(..\)\(..\)/0x\2,0x\1,/g'
41## -e 's/$/ \\/' 49## -e 's/$/ \\/'
42"$loc/usage" | bzip2 -1 | $DD bs=2 skip=1 2>/dev/null | od -v -b \ 50"$loc/usage" | bzip2 -1 | $DD bs=2 skip=1 2>/dev/null | od -v -b \
51| grep -v '^ ' \
43| $SED -e 's/^[^ ]*//' \ 52| $SED -e 's/^[^ ]*//' \
44 -e 's/ //g' \ 53 -e 's/ //g' \
45 -e '/^$/d' \ 54 -e '/^$/d' \
diff --git a/archival/dpkg.c b/archival/dpkg.c
index 151f0ca43..df7a0db64 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -1151,13 +1151,13 @@ static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count
1151 if (result && number_of_alternatives == 0) { 1151 if (result && number_of_alternatives == 0) {
1152 if (root_of_alternatives) 1152 if (root_of_alternatives)
1153 bb_error_msg_and_die( 1153 bb_error_msg_and_die(
1154 "package %s %sdepends on %s, " 1154 "package %s %sdepends on %s, which %s",
1155 "which cannot be satisfied",
1156 name_hashtable[package_node->name], 1155 name_hashtable[package_node->name],
1157 package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", 1156 package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "",
1158 name_hashtable[root_of_alternatives->name]); 1157 name_hashtable[root_of_alternatives->name],
1158 "cannot be satisfied");
1159 bb_error_msg_and_die( 1159 bb_error_msg_and_die(
1160 "package %s %sdepends on %s, which %s\n", 1160 "package %s %sdepends on %s, which %s",
1161 name_hashtable[package_node->name], 1161 name_hashtable[package_node->name],
1162 package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", 1162 package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "",
1163 name_hashtable[package_edge->name], 1163 name_hashtable[package_edge->name],
diff --git a/archival/libarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c
index 5b32c2ec8..6f5317a0e 100644
--- a/archival/libarchive/data_extract_to_command.c
+++ b/archival/libarchive/data_extract_to_command.c
@@ -118,7 +118,7 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle)
118 bb_error_msg_and_die("'%s' returned status %d", 118 bb_error_msg_and_die("'%s' returned status %d",
119 archive_handle->tar__to_command, WEXITSTATUS(status)); 119 archive_handle->tar__to_command, WEXITSTATUS(status));
120 if (WIFSIGNALED(status)) 120 if (WIFSIGNALED(status))
121 bb_error_msg_and_die("'%s' terminated on signal %d", 121 bb_error_msg_and_die("'%s' terminated by signal %d",
122 archive_handle->tar__to_command, WTERMSIG(status)); 122 archive_handle->tar__to_command, WTERMSIG(status));
123 123
124 if (!BB_MMU) { 124 if (!BB_MMU) {
diff --git a/configs/android_ndk_defconfig b/configs/android_ndk_defconfig
index 01cc2dd15..66c85268f 100644
--- a/configs/android_ndk_defconfig
+++ b/configs/android_ndk_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.21.0.git 3# Busybox version: 1.24.0.git
4# Mon May 28 21:51:18 2012 4# Fri Sep 18 20:39:29 2015
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7 7
@@ -36,12 +36,15 @@ CONFIG_LAST_SUPPORTED_WCHAR=0
36# CONFIG_UNICODE_BIDI_SUPPORT is not set 36# CONFIG_UNICODE_BIDI_SUPPORT is not set
37# CONFIG_UNICODE_NEUTRAL_TABLE is not set 37# CONFIG_UNICODE_NEUTRAL_TABLE is not set
38# CONFIG_UNICODE_PRESERVE_BROKEN is not set 38# CONFIG_UNICODE_PRESERVE_BROKEN is not set
39# CONFIG_PAM is not set
40CONFIG_FEATURE_USE_SENDFILE=y
39CONFIG_LONG_OPTS=y 41CONFIG_LONG_OPTS=y
40# CONFIG_FEATURE_DEVPTS is not set 42# CONFIG_FEATURE_DEVPTS is not set
41# CONFIG_FEATURE_CLEAN_UP is not set 43# CONFIG_FEATURE_CLEAN_UP is not set
42# CONFIG_FEATURE_UTMP is not set 44# CONFIG_FEATURE_UTMP is not set
43# CONFIG_FEATURE_WTMP is not set 45# CONFIG_FEATURE_WTMP is not set
44# CONFIG_FEATURE_PIDFILE is not set 46# CONFIG_FEATURE_PIDFILE is not set
47CONFIG_PID_FILE_PATH=""
45# CONFIG_FEATURE_SUID is not set 48# CONFIG_FEATURE_SUID is not set
46# CONFIG_FEATURE_SUID_CONFIG is not set 49# CONFIG_FEATURE_SUID_CONFIG is not set
47# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set 50# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
@@ -63,7 +66,7 @@ CONFIG_FEATURE_SYSLOG=y
63# CONFIG_LFS is not set 66# CONFIG_LFS is not set
64CONFIG_CROSS_COMPILER_PREFIX="arm-linux-androideabi-" 67CONFIG_CROSS_COMPILER_PREFIX="arm-linux-androideabi-"
65CONFIG_SYSROOT="/opt/android-ndk/platforms/android-9/arch-arm" 68CONFIG_SYSROOT="/opt/android-ndk/platforms/android-9/arch-arm"
66CONFIG_EXTRA_CFLAGS="-DANDROID -D__ANDROID__ -DSK_RELEASE -nostdlib -march=armv7-a -msoft-float -mfloat-abi=softfp -mfpu=neon -mthumb -mthumb-interwork -fpic -fno-short-enums -fgcse-after-reload -frename-registers" 69CONFIG_EXTRA_CFLAGS="-DANDROID -D__ANDROID__ -DSK_RELEASE -nostdlib -march=armv7-a -msoft-float -mfloat-abi=softfp -mfpu=neon -mthumb -mthumb-interwork -fpic -fno-short-enums -fgcse-after-reload -frename-registers -fuse-ld=bfd"
67CONFIG_EXTRA_LDFLAGS="-Xlinker -z -Xlinker muldefs -nostdlib -Bdynamic -Xlinker -dynamic-linker -Xlinker /system/bin/linker -Xlinker -z -Xlinker nocopyreloc -Xlinker --no-undefined ${SYSROOT}/usr/lib/crtbegin_dynamic.o ${SYSROOT}/usr/lib/crtend_android.o" 70CONFIG_EXTRA_LDFLAGS="-Xlinker -z -Xlinker muldefs -nostdlib -Bdynamic -Xlinker -dynamic-linker -Xlinker /system/bin/linker -Xlinker -z -Xlinker nocopyreloc -Xlinker --no-undefined ${SYSROOT}/usr/lib/crtbegin_dynamic.o ${SYSROOT}/usr/lib/crtend_android.o"
68CONFIG_EXTRA_LDLIBS="dl m c gcc" 71CONFIG_EXTRA_LDLIBS="dl m c gcc"
69 72
@@ -72,6 +75,7 @@ CONFIG_EXTRA_LDLIBS="dl m c gcc"
72# 75#
73# CONFIG_DEBUG is not set 76# CONFIG_DEBUG is not set
74# CONFIG_DEBUG_PESSIMIZE is not set 77# CONFIG_DEBUG_PESSIMIZE is not set
78# CONFIG_UNIT_TEST is not set
75# CONFIG_WERROR is not set 79# CONFIG_WERROR is not set
76CONFIG_NO_DEBUG_LIB=y 80CONFIG_NO_DEBUG_LIB=y
77# CONFIG_DMALLOC is not set 81# CONFIG_DMALLOC is not set
@@ -96,6 +100,7 @@ CONFIG_PREFIX="./_install"
96# CONFIG_FEATURE_RTMINMAX is not set 100# CONFIG_FEATURE_RTMINMAX is not set
97CONFIG_PASSWORD_MINLEN=6 101CONFIG_PASSWORD_MINLEN=6
98CONFIG_MD5_SMALL=1 102CONFIG_MD5_SMALL=1
103CONFIG_SHA3_SMALL=1
99# CONFIG_FEATURE_FAST_TOP is not set 104# CONFIG_FEATURE_FAST_TOP is not set
100# CONFIG_FEATURE_ETC_NETWORKS is not set 105# CONFIG_FEATURE_ETC_NETWORKS is not set
101CONFIG_FEATURE_USE_TERMIOS=y 106CONFIG_FEATURE_USE_TERMIOS=y
@@ -133,7 +138,14 @@ CONFIG_FEATURE_SEAMLESS_Z=y
133CONFIG_AR=y 138CONFIG_AR=y
134CONFIG_FEATURE_AR_LONG_FILENAMES=y 139CONFIG_FEATURE_AR_LONG_FILENAMES=y
135CONFIG_FEATURE_AR_CREATE=y 140CONFIG_FEATURE_AR_CREATE=y
141CONFIG_UNCOMPRESS=y
142CONFIG_GUNZIP=y
136CONFIG_BUNZIP2=y 143CONFIG_BUNZIP2=y
144CONFIG_UNLZMA=y
145CONFIG_FEATURE_LZMA_FAST=y
146CONFIG_LZMA=y
147CONFIG_UNXZ=y
148CONFIG_XZ=y
137CONFIG_BZIP2=y 149CONFIG_BZIP2=y
138CONFIG_CPIO=y 150CONFIG_CPIO=y
139CONFIG_FEATURE_CPIO_O=y 151CONFIG_FEATURE_CPIO_O=y
@@ -141,14 +153,14 @@ CONFIG_FEATURE_CPIO_P=y
141CONFIG_DPKG=y 153CONFIG_DPKG=y
142CONFIG_DPKG_DEB=y 154CONFIG_DPKG_DEB=y
143# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set 155# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set
144CONFIG_GUNZIP=y
145CONFIG_GZIP=y 156CONFIG_GZIP=y
146# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set 157# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set
147CONFIG_GZIP_FAST=0 158CONFIG_GZIP_FAST=0
159# CONFIG_FEATURE_GZIP_LEVELS is not set
148CONFIG_LZOP=y 160CONFIG_LZOP=y
149CONFIG_LZOP_COMPR_HIGH=y 161CONFIG_LZOP_COMPR_HIGH=y
150CONFIG_RPM2CPIO=y
151CONFIG_RPM=y 162CONFIG_RPM=y
163CONFIG_RPM2CPIO=y
152CONFIG_TAR=y 164CONFIG_TAR=y
153CONFIG_FEATURE_TAR_CREATE=y 165CONFIG_FEATURE_TAR_CREATE=y
154CONFIG_FEATURE_TAR_AUTODETECT=y 166CONFIG_FEATURE_TAR_AUTODETECT=y
@@ -161,12 +173,6 @@ CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
161CONFIG_FEATURE_TAR_UNAME_GNAME=y 173CONFIG_FEATURE_TAR_UNAME_GNAME=y
162CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y 174CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
163# CONFIG_FEATURE_TAR_SELINUX is not set 175# CONFIG_FEATURE_TAR_SELINUX is not set
164CONFIG_UNCOMPRESS=y
165CONFIG_UNLZMA=y
166CONFIG_FEATURE_LZMA_FAST=y
167CONFIG_LZMA=y
168CONFIG_UNXZ=y
169CONFIG_XZ=y
170CONFIG_UNZIP=y 176CONFIG_UNZIP=y
171 177
172# 178#
@@ -178,16 +184,27 @@ CONFIG_CAT=y
178# CONFIG_FEATURE_DATE_ISOFMT is not set 184# CONFIG_FEATURE_DATE_ISOFMT is not set
179# CONFIG_FEATURE_DATE_NANO is not set 185# CONFIG_FEATURE_DATE_NANO is not set
180# CONFIG_FEATURE_DATE_COMPAT is not set 186# CONFIG_FEATURE_DATE_COMPAT is not set
187CONFIG_DD=y
188CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
189CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y
190CONFIG_FEATURE_DD_IBS_OBS=y
191CONFIG_FEATURE_DD_STATUS=y
181# CONFIG_HOSTID is not set 192# CONFIG_HOSTID is not set
182# CONFIG_ID is not set 193# CONFIG_ID is not set
183# CONFIG_GROUPS is not set 194# CONFIG_GROUPS is not set
195CONFIG_SHUF=y
196CONFIG_SYNC=y
197# CONFIG_FEATURE_SYNC_FANCY is not set
184CONFIG_TEST=y 198CONFIG_TEST=y
185CONFIG_FEATURE_TEST_64=y 199CONFIG_FEATURE_TEST_64=y
186CONFIG_TOUCH=y 200CONFIG_TOUCH=y
201# CONFIG_FEATURE_TOUCH_NODEREF is not set
187CONFIG_FEATURE_TOUCH_SUSV3=y 202CONFIG_FEATURE_TOUCH_SUSV3=y
188CONFIG_TR=y 203CONFIG_TR=y
189CONFIG_FEATURE_TR_CLASSES=y 204CONFIG_FEATURE_TR_CLASSES=y
190CONFIG_FEATURE_TR_EQUIV=y 205CONFIG_FEATURE_TR_EQUIV=y
206CONFIG_TRUNCATE=y
207CONFIG_UNLINK=y
191CONFIG_BASE64=y 208CONFIG_BASE64=y
192# CONFIG_WHO is not set 209# CONFIG_WHO is not set
193# CONFIG_USERS is not set 210# CONFIG_USERS is not set
@@ -203,10 +220,6 @@ CONFIG_COMM=y
203CONFIG_CP=y 220CONFIG_CP=y
204# CONFIG_FEATURE_CP_LONG_OPTIONS is not set 221# CONFIG_FEATURE_CP_LONG_OPTIONS is not set
205CONFIG_CUT=y 222CONFIG_CUT=y
206CONFIG_DD=y
207CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
208CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y
209CONFIG_FEATURE_DD_IBS_OBS=y
210# CONFIG_DF is not set 223# CONFIG_DF is not set
211# CONFIG_FEATURE_DF_FANCY is not set 224# CONFIG_FEATURE_DF_FANCY is not set
212CONFIG_DIRNAME=y 225CONFIG_DIRNAME=y
@@ -263,6 +276,7 @@ CONFIG_SEQ=y
263CONFIG_SHA1SUM=y 276CONFIG_SHA1SUM=y
264CONFIG_SHA256SUM=y 277CONFIG_SHA256SUM=y
265CONFIG_SHA512SUM=y 278CONFIG_SHA512SUM=y
279CONFIG_SHA3SUM=y
266CONFIG_SLEEP=y 280CONFIG_SLEEP=y
267CONFIG_FEATURE_FANCY_SLEEP=y 281CONFIG_FEATURE_FANCY_SLEEP=y
268CONFIG_FEATURE_FLOAT_SLEEP=y 282CONFIG_FEATURE_FLOAT_SLEEP=y
@@ -274,7 +288,6 @@ CONFIG_FEATURE_SPLIT_FANCY=y
274# CONFIG_FEATURE_STAT_FORMAT is not set 288# CONFIG_FEATURE_STAT_FORMAT is not set
275CONFIG_STTY=y 289CONFIG_STTY=y
276CONFIG_SUM=y 290CONFIG_SUM=y
277CONFIG_SYNC=y
278CONFIG_TAC=y 291CONFIG_TAC=y
279CONFIG_TAIL=y 292CONFIG_TAIL=y
280CONFIG_FEATURE_FANCY_TAIL=y 293CONFIG_FEATURE_FANCY_TAIL=y
@@ -283,6 +296,7 @@ CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
283CONFIG_TRUE=y 296CONFIG_TRUE=y
284# CONFIG_TTY is not set 297# CONFIG_TTY is not set
285CONFIG_UNAME=y 298CONFIG_UNAME=y
299CONFIG_UNAME_OSNAME="GNU/Linux"
286CONFIG_UNEXPAND=y 300CONFIG_UNEXPAND=y
287# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set 301# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set
288CONFIG_UNIQ=y 302CONFIG_UNIQ=y
@@ -295,6 +309,11 @@ CONFIG_WHOAMI=y
295CONFIG_YES=y 309CONFIG_YES=y
296 310
297# 311#
312# Common options
313#
314CONFIG_FEATURE_VERBOSE=y
315
316#
298# Common options for cp and mv 317# Common options for cp and mv
299# 318#
300CONFIG_FEATURE_PRESERVE_HARDLINKS=y 319CONFIG_FEATURE_PRESERVE_HARDLINKS=y
@@ -310,7 +329,7 @@ CONFIG_FEATURE_AUTOWIDTH=y
310CONFIG_FEATURE_HUMAN_READABLE=y 329CONFIG_FEATURE_HUMAN_READABLE=y
311 330
312# 331#
313# Common options for md5sum, sha1sum, sha256sum, sha512sum 332# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
314# 333#
315CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y 334CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
316 335
@@ -356,7 +375,16 @@ CONFIG_WHICH=y
356# 375#
357# Editors 376# Editors
358# 377#
378CONFIG_AWK=y
379CONFIG_FEATURE_AWK_LIBM=y
380CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
381CONFIG_CMP=y
382CONFIG_DIFF=y
383# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set
384CONFIG_FEATURE_DIFF_DIR=y
385CONFIG_ED=y
359CONFIG_PATCH=y 386CONFIG_PATCH=y
387CONFIG_SED=y
360CONFIG_VI=y 388CONFIG_VI=y
361CONFIG_FEATURE_VI_MAX_LEN=4096 389CONFIG_FEATURE_VI_MAX_LEN=4096
362CONFIG_FEATURE_VI_8BIT=y 390CONFIG_FEATURE_VI_8BIT=y
@@ -371,14 +399,9 @@ CONFIG_FEATURE_VI_SETOPTS=y
371CONFIG_FEATURE_VI_SET=y 399CONFIG_FEATURE_VI_SET=y
372CONFIG_FEATURE_VI_WIN_RESIZE=y 400CONFIG_FEATURE_VI_WIN_RESIZE=y
373CONFIG_FEATURE_VI_ASK_TERMINAL=y 401CONFIG_FEATURE_VI_ASK_TERMINAL=y
374CONFIG_AWK=y 402CONFIG_FEATURE_VI_UNDO=y
375CONFIG_FEATURE_AWK_LIBM=y 403CONFIG_FEATURE_VI_UNDO_QUEUE=y
376CONFIG_CMP=y 404CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
377CONFIG_DIFF=y
378# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set
379CONFIG_FEATURE_DIFF_DIR=y
380CONFIG_ED=y
381CONFIG_SED=y
382CONFIG_FEATURE_ALLOW_EXEC=y 405CONFIG_FEATURE_ALLOW_EXEC=y
383 406
384# 407#
@@ -395,6 +418,7 @@ CONFIG_FEATURE_FIND_MAXDEPTH=y
395CONFIG_FEATURE_FIND_NEWER=y 418CONFIG_FEATURE_FIND_NEWER=y
396CONFIG_FEATURE_FIND_INUM=y 419CONFIG_FEATURE_FIND_INUM=y
397CONFIG_FEATURE_FIND_EXEC=y 420CONFIG_FEATURE_FIND_EXEC=y
421CONFIG_FEATURE_FIND_EXEC_PLUS=y
398CONFIG_FEATURE_FIND_USER=y 422CONFIG_FEATURE_FIND_USER=y
399CONFIG_FEATURE_FIND_GROUP=y 423CONFIG_FEATURE_FIND_GROUP=y
400CONFIG_FEATURE_FIND_NOT=y 424CONFIG_FEATURE_FIND_NOT=y
@@ -416,6 +440,7 @@ CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
416CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y 440CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
417CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y 441CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
418CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y 442CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
443CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
419 444
420# 445#
421# Init Utilities 446# Init Utilities
@@ -447,11 +472,12 @@ CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y
447# CONFIG_FEATURE_SHADOWPASSWDS is not set 472# CONFIG_FEATURE_SHADOWPASSWDS is not set
448# CONFIG_USE_BB_PWD_GRP is not set 473# CONFIG_USE_BB_PWD_GRP is not set
449# CONFIG_USE_BB_SHADOW is not set 474# CONFIG_USE_BB_SHADOW is not set
450# CONFIG_USE_BB_CRYPT is not set 475CONFIG_USE_BB_CRYPT=y
451# CONFIG_USE_BB_CRYPT_SHA is not set 476CONFIG_USE_BB_CRYPT_SHA=y
452# CONFIG_ADDUSER is not set 477# CONFIG_ADDUSER is not set
453# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set 478# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
454# CONFIG_FEATURE_CHECK_NAMES is not set 479# CONFIG_FEATURE_CHECK_NAMES is not set
480CONFIG_LAST_ID=0
455CONFIG_FIRST_SYSTEM_ID=0 481CONFIG_FIRST_SYSTEM_ID=0
456CONFIG_LAST_SYSTEM_ID=0 482CONFIG_LAST_SYSTEM_ID=0
457# CONFIG_ADDGROUP is not set 483# CONFIG_ADDGROUP is not set
@@ -463,7 +489,6 @@ CONFIG_LAST_SYSTEM_ID=0
463# CONFIG_GETTY is not set 489# CONFIG_GETTY is not set
464# CONFIG_LOGIN is not set 490# CONFIG_LOGIN is not set
465# CONFIG_LOGIN_SESSION_AS_CHILD is not set 491# CONFIG_LOGIN_SESSION_AS_CHILD is not set
466# CONFIG_PAM is not set
467# CONFIG_LOGIN_SCRIPTS is not set 492# CONFIG_LOGIN_SCRIPTS is not set
468# CONFIG_FEATURE_NOLOGIN is not set 493# CONFIG_FEATURE_NOLOGIN is not set
469# CONFIG_FEATURE_SECURETTY is not set 494# CONFIG_FEATURE_SECURETTY is not set
@@ -521,13 +546,26 @@ CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
521# Linux System Utilities 546# Linux System Utilities
522# 547#
523CONFIG_BLOCKDEV=y 548CONFIG_BLOCKDEV=y
524CONFIG_MDEV=y 549CONFIG_FATATTR=y
525CONFIG_FEATURE_MDEV_CONF=y 550CONFIG_FSTRIM=y
526CONFIG_FEATURE_MDEV_RENAME=y 551# CONFIG_MDEV is not set
527CONFIG_FEATURE_MDEV_RENAME_REGEXP=y 552# CONFIG_FEATURE_MDEV_CONF is not set
528CONFIG_FEATURE_MDEV_EXEC=y 553# CONFIG_FEATURE_MDEV_RENAME is not set
529CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y 554# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
555# CONFIG_FEATURE_MDEV_EXEC is not set
556# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
557# CONFIG_MOUNT is not set
558# CONFIG_FEATURE_MOUNT_FAKE is not set
559# CONFIG_FEATURE_MOUNT_VERBOSE is not set
560# CONFIG_FEATURE_MOUNT_HELPERS is not set
561# CONFIG_FEATURE_MOUNT_LABEL is not set
562# CONFIG_FEATURE_MOUNT_NFS is not set
563# CONFIG_FEATURE_MOUNT_CIFS is not set
564# CONFIG_FEATURE_MOUNT_FLAGS is not set
565# CONFIG_FEATURE_MOUNT_FSTAB is not set
566# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
530CONFIG_REV=y 567CONFIG_REV=y
568CONFIG_UEVENT=y
531# CONFIG_ACPID is not set 569# CONFIG_ACPID is not set
532# CONFIG_FEATURE_ACPID_COMPAT is not set 570# CONFIG_FEATURE_ACPID_COMPAT is not set
533CONFIG_BLKID=y 571CONFIG_BLKID=y
@@ -573,15 +611,6 @@ CONFIG_LSUSB=y
573CONFIG_MKSWAP=y 611CONFIG_MKSWAP=y
574CONFIG_FEATURE_MKSWAP_UUID=y 612CONFIG_FEATURE_MKSWAP_UUID=y
575CONFIG_MORE=y 613CONFIG_MORE=y
576# CONFIG_MOUNT is not set
577# CONFIG_FEATURE_MOUNT_FAKE is not set
578# CONFIG_FEATURE_MOUNT_VERBOSE is not set
579# CONFIG_FEATURE_MOUNT_HELPERS is not set
580# CONFIG_FEATURE_MOUNT_LABEL is not set
581# CONFIG_FEATURE_MOUNT_NFS is not set
582# CONFIG_FEATURE_MOUNT_CIFS is not set
583# CONFIG_FEATURE_MOUNT_FLAGS is not set
584# CONFIG_FEATURE_MOUNT_FSTAB is not set
585# CONFIG_PIVOT_ROOT is not set 614# CONFIG_PIVOT_ROOT is not set
586# CONFIG_RDATE is not set 615# CONFIG_RDATE is not set
587CONFIG_RDEV=y 616CONFIG_RDEV=y
@@ -591,6 +620,7 @@ CONFIG_SCRIPT=y
591CONFIG_SCRIPTREPLAY=y 620CONFIG_SCRIPTREPLAY=y
592# CONFIG_SETARCH is not set 621# CONFIG_SETARCH is not set
593# CONFIG_SWAPONOFF is not set 622# CONFIG_SWAPONOFF is not set
623# CONFIG_FEATURE_SWAPON_DISCARD is not set
594# CONFIG_FEATURE_SWAPON_PRI is not set 624# CONFIG_FEATURE_SWAPON_PRI is not set
595CONFIG_SWITCH_ROOT=y 625CONFIG_SWITCH_ROOT=y
596# CONFIG_UMOUNT is not set 626# CONFIG_UMOUNT is not set
@@ -603,32 +633,45 @@ CONFIG_VOLUMEID=y
603# 633#
604# Filesystem/Volume identification 634# Filesystem/Volume identification
605# 635#
606CONFIG_FEATURE_VOLUMEID_EXT=y
607CONFIG_FEATURE_VOLUMEID_BTRFS=y 636CONFIG_FEATURE_VOLUMEID_BTRFS=y
608CONFIG_FEATURE_VOLUMEID_REISERFS=y 637CONFIG_FEATURE_VOLUMEID_CRAMFS=y
638CONFIG_FEATURE_VOLUMEID_EXFAT=y
639CONFIG_FEATURE_VOLUMEID_EXT=y
640CONFIG_FEATURE_VOLUMEID_F2FS=y
609CONFIG_FEATURE_VOLUMEID_FAT=y 641CONFIG_FEATURE_VOLUMEID_FAT=y
610CONFIG_FEATURE_VOLUMEID_HFS=y 642CONFIG_FEATURE_VOLUMEID_HFS=y
611CONFIG_FEATURE_VOLUMEID_JFS=y
612CONFIG_FEATURE_VOLUMEID_XFS=y
613CONFIG_FEATURE_VOLUMEID_NTFS=y
614CONFIG_FEATURE_VOLUMEID_ISO9660=y 643CONFIG_FEATURE_VOLUMEID_ISO9660=y
615CONFIG_FEATURE_VOLUMEID_UDF=y 644CONFIG_FEATURE_VOLUMEID_JFS=y
616CONFIG_FEATURE_VOLUMEID_LUKS=y 645CONFIG_FEATURE_VOLUMEID_LINUXRAID=y
617CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y 646CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y
618CONFIG_FEATURE_VOLUMEID_CRAMFS=y 647CONFIG_FEATURE_VOLUMEID_LUKS=y
648CONFIG_FEATURE_VOLUMEID_NILFS=y
649CONFIG_FEATURE_VOLUMEID_NTFS=y
650CONFIG_FEATURE_VOLUMEID_OCFS2=y
651CONFIG_FEATURE_VOLUMEID_REISERFS=y
619CONFIG_FEATURE_VOLUMEID_ROMFS=y 652CONFIG_FEATURE_VOLUMEID_ROMFS=y
653CONFIG_FEATURE_VOLUMEID_SQUASHFS=y
620CONFIG_FEATURE_VOLUMEID_SYSV=y 654CONFIG_FEATURE_VOLUMEID_SYSV=y
621CONFIG_FEATURE_VOLUMEID_OCFS2=y 655CONFIG_FEATURE_VOLUMEID_UDF=y
622CONFIG_FEATURE_VOLUMEID_LINUXRAID=y 656CONFIG_FEATURE_VOLUMEID_XFS=y
623 657
624# 658#
625# Miscellaneous Utilities 659# Miscellaneous Utilities
626# 660#
627# CONFIG_CONSPY is not set 661# CONFIG_CONSPY is not set
662CONFIG_CROND=y
663CONFIG_FEATURE_CROND_D=y
664CONFIG_FEATURE_CROND_CALL_SENDMAIL=y
665CONFIG_FEATURE_CROND_DIR="/var/spool/cron"
666CONFIG_I2CGET=y
667CONFIG_I2CSET=y
668CONFIG_I2CDUMP=y
669CONFIG_I2CDETECT=y
628CONFIG_LESS=y 670CONFIG_LESS=y
629CONFIG_FEATURE_LESS_MAXLINES=9999999 671CONFIG_FEATURE_LESS_MAXLINES=9999999
630CONFIG_FEATURE_LESS_BRACKETS=y 672CONFIG_FEATURE_LESS_BRACKETS=y
631CONFIG_FEATURE_LESS_FLAGS=y 673CONFIG_FEATURE_LESS_FLAGS=y
674CONFIG_FEATURE_LESS_TRUNCATE=y
632CONFIG_FEATURE_LESS_MARKS=y 675CONFIG_FEATURE_LESS_MARKS=y
633CONFIG_FEATURE_LESS_REGEXP=y 676CONFIG_FEATURE_LESS_REGEXP=y
634CONFIG_FEATURE_LESS_WINCH=y 677CONFIG_FEATURE_LESS_WINCH=y
@@ -637,13 +680,17 @@ CONFIG_FEATURE_LESS_DASHCMD=y
637CONFIG_FEATURE_LESS_LINENUMS=y 680CONFIG_FEATURE_LESS_LINENUMS=y
638# CONFIG_NANDWRITE is not set 681# CONFIG_NANDWRITE is not set
639CONFIG_NANDDUMP=y 682CONFIG_NANDDUMP=y
683# CONFIG_RFKILL is not set
640CONFIG_SETSERIAL=y 684CONFIG_SETSERIAL=y
685# CONFIG_TASKSET is not set
686# CONFIG_FEATURE_TASKSET_FANCY is not set
641# CONFIG_UBIATTACH is not set 687# CONFIG_UBIATTACH is not set
642# CONFIG_UBIDETACH is not set 688# CONFIG_UBIDETACH is not set
643# CONFIG_UBIMKVOL is not set 689# CONFIG_UBIMKVOL is not set
644# CONFIG_UBIRMVOL is not set 690# CONFIG_UBIRMVOL is not set
645# CONFIG_UBIRSVOL is not set 691# CONFIG_UBIRSVOL is not set
646# CONFIG_UBIUPDATEVOL is not set 692# CONFIG_UBIUPDATEVOL is not set
693# CONFIG_WALL is not set
647# CONFIG_ADJTIMEX is not set 694# CONFIG_ADJTIMEX is not set
648CONFIG_BBCONFIG=y 695CONFIG_BBCONFIG=y
649CONFIG_FEATURE_COMPRESS_BBCONFIG=y 696CONFIG_FEATURE_COMPRESS_BBCONFIG=y
@@ -659,10 +706,6 @@ CONFIG_FEATURE_CHAT_SEND_ESCAPES=y
659CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y 706CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y
660CONFIG_FEATURE_CHAT_CLR_ABORT=y 707CONFIG_FEATURE_CHAT_CLR_ABORT=y
661CONFIG_CHRT=y 708CONFIG_CHRT=y
662CONFIG_CROND=y
663CONFIG_FEATURE_CROND_D=y
664CONFIG_FEATURE_CROND_CALL_SENDMAIL=y
665CONFIG_FEATURE_CROND_DIR="/var/spool/cron"
666CONFIG_CRONTAB=y 709CONFIG_CRONTAB=y
667CONFIG_DC=y 710CONFIG_DC=y
668CONFIG_FEATURE_DC_LIBM=y 711CONFIG_FEATURE_DC_LIBM=y
@@ -700,18 +743,14 @@ CONFIG_MAN=y
700# CONFIG_MT is not set 743# CONFIG_MT is not set
701CONFIG_RAIDAUTORUN=y 744CONFIG_RAIDAUTORUN=y
702# CONFIG_READAHEAD is not set 745# CONFIG_READAHEAD is not set
703# CONFIG_RFKILL is not set
704# CONFIG_RUNLEVEL is not set 746# CONFIG_RUNLEVEL is not set
705CONFIG_RX=y 747CONFIG_RX=y
706CONFIG_SETSID=y 748CONFIG_SETSID=y
707CONFIG_STRINGS=y 749CONFIG_STRINGS=y
708# CONFIG_TASKSET is not set
709# CONFIG_FEATURE_TASKSET_FANCY is not set
710CONFIG_TIME=y 750CONFIG_TIME=y
711CONFIG_TIMEOUT=y 751CONFIG_TIMEOUT=y
712CONFIG_TTYSIZE=y 752CONFIG_TTYSIZE=y
713CONFIG_VOLNAME=y 753CONFIG_VOLNAME=y
714# CONFIG_WALL is not set
715# CONFIG_WATCHDOG is not set 754# CONFIG_WATCHDOG is not set
716 755
717# 756#
@@ -743,13 +782,13 @@ CONFIG_FAKEIDENTD=y
743CONFIG_FTPD=y 782CONFIG_FTPD=y
744CONFIG_FEATURE_FTP_WRITE=y 783CONFIG_FEATURE_FTP_WRITE=y
745CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y 784CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y
785CONFIG_FEATURE_FTP_AUTHENTICATION=y
746CONFIG_FTPGET=y 786CONFIG_FTPGET=y
747CONFIG_FTPPUT=y 787CONFIG_FTPPUT=y
748# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set 788# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set
749# CONFIG_HOSTNAME is not set 789# CONFIG_HOSTNAME is not set
750CONFIG_HTTPD=y 790CONFIG_HTTPD=y
751CONFIG_FEATURE_HTTPD_RANGES=y 791CONFIG_FEATURE_HTTPD_RANGES=y
752CONFIG_FEATURE_HTTPD_USE_SENDFILE=y
753CONFIG_FEATURE_HTTPD_SETUID=y 792CONFIG_FEATURE_HTTPD_SETUID=y
754CONFIG_FEATURE_HTTPD_BASIC_AUTH=y 793CONFIG_FEATURE_HTTPD_BASIC_AUTH=y
755# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set 794# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
@@ -806,6 +845,7 @@ CONFIG_FEATURE_NETSTAT_PRG=y
806# CONFIG_NSLOOKUP is not set 845# CONFIG_NSLOOKUP is not set
807# CONFIG_NTPD is not set 846# CONFIG_NTPD is not set
808# CONFIG_FEATURE_NTPD_SERVER is not set 847# CONFIG_FEATURE_NTPD_SERVER is not set
848# CONFIG_FEATURE_NTPD_CONF is not set
809CONFIG_PSCAN=y 849CONFIG_PSCAN=y
810CONFIG_ROUTE=y 850CONFIG_ROUTE=y
811# CONFIG_SLATTACH is not set 851# CONFIG_SLATTACH is not set
@@ -843,6 +883,7 @@ CONFIG_FEATURE_TUNCTL_UG=y
843CONFIG_DHCPD_LEASES_FILE="" 883CONFIG_DHCPD_LEASES_FILE=""
844CONFIG_UDHCPC=y 884CONFIG_UDHCPC=y
845CONFIG_FEATURE_UDHCPC_ARPING=y 885CONFIG_FEATURE_UDHCPC_ARPING=y
886CONFIG_FEATURE_UDHCPC_SANITIZEOPT=y
846CONFIG_FEATURE_UDHCP_PORT=y 887CONFIG_FEATURE_UDHCP_PORT=y
847CONFIG_UDHCP_DEBUG=9 888CONFIG_UDHCP_DEBUG=9
848CONFIG_FEATURE_UDHCP_RFC3397=y 889CONFIG_FEATURE_UDHCP_RFC3397=y
@@ -889,6 +930,13 @@ CONFIG_POWERTOP=y
889CONFIG_PSTREE=y 930CONFIG_PSTREE=y
890CONFIG_PWDX=y 931CONFIG_PWDX=y
891CONFIG_SMEMCAP=y 932CONFIG_SMEMCAP=y
933CONFIG_TOP=y
934CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
935CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
936CONFIG_FEATURE_TOP_SMP_CPU=y
937CONFIG_FEATURE_TOP_DECIMALS=y
938CONFIG_FEATURE_TOP_SMP_PROCESS=y
939CONFIG_FEATURE_TOPMEM=y
892CONFIG_UPTIME=y 940CONFIG_UPTIME=y
893# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set 941# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
894CONFIG_FREE=y 942CONFIG_FREE=y
@@ -909,13 +957,6 @@ CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y
909# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set 957# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
910CONFIG_RENICE=y 958CONFIG_RENICE=y
911CONFIG_BB_SYSCTL=y 959CONFIG_BB_SYSCTL=y
912CONFIG_TOP=y
913CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
914CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
915CONFIG_FEATURE_TOP_SMP_CPU=y
916CONFIG_FEATURE_TOP_DECIMALS=y
917CONFIG_FEATURE_TOP_SMP_PROCESS=y
918CONFIG_FEATURE_TOPMEM=y
919CONFIG_FEATURE_SHOW_THREADS=y 960CONFIG_FEATURE_SHOW_THREADS=y
920CONFIG_WATCH=y 961CONFIG_WATCH=y
921 962
@@ -961,6 +1002,7 @@ CONFIG_SOFTLIMIT=y
961# CONFIG_ASH_BUILTIN_ECHO is not set 1002# CONFIG_ASH_BUILTIN_ECHO is not set
962# CONFIG_ASH_BUILTIN_PRINTF is not set 1003# CONFIG_ASH_BUILTIN_PRINTF is not set
963# CONFIG_ASH_BUILTIN_TEST is not set 1004# CONFIG_ASH_BUILTIN_TEST is not set
1005# CONFIG_ASH_HELP is not set
964# CONFIG_ASH_CMDCMD is not set 1006# CONFIG_ASH_CMDCMD is not set
965# CONFIG_ASH_MAIL is not set 1007# CONFIG_ASH_MAIL is not set
966# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set 1008# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set
@@ -1010,6 +1052,7 @@ CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1010CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 1052CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1011# CONFIG_LOGREAD is not set 1053# CONFIG_LOGREAD is not set
1012# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set 1054# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1055# CONFIG_FEATURE_KMSG_SYSLOG is not set
1013CONFIG_KLOGD=y 1056CONFIG_KLOGD=y
1014CONFIG_FEATURE_KLOGD_KLOGCTL=y 1057CONFIG_FEATURE_KLOGD_KLOGCTL=y
1015# CONFIG_LOGGER is not set 1058# CONFIG_LOGGER is not set
diff --git a/coreutils/chmod.c b/coreutils/chmod.c
index 5ee45b942..a21c6d501 100644
--- a/coreutils/chmod.c
+++ b/coreutils/chmod.c
@@ -69,9 +69,9 @@ static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, void
69 if (S_ISLNK(statbuf->st_mode)) 69 if (S_ISLNK(statbuf->st_mode))
70 return TRUE; 70 return TRUE;
71 } 71 }
72 newmode = statbuf->st_mode;
73 72
74 if (!bb_parse_mode((char *)param, &newmode)) 73 newmode = bb_parse_mode((char *)param, statbuf->st_mode);
74 if (newmode == (mode_t)-1)
75 bb_error_msg_and_die("invalid mode '%s'", (char *)param); 75 bb_error_msg_and_die("invalid mode '%s'", (char *)param);
76 76
77 if (chmod(fileName, newmode) == 0) { 77 if (chmod(fileName, newmode) == 0) {
diff --git a/coreutils/install.c b/coreutils/install.c
index 73f9c70d5..8aa51cc34 100644
--- a/coreutils/install.c
+++ b/coreutils/install.c
@@ -159,7 +159,7 @@ int install_main(int argc, char **argv)
159 } 159 }
160 mode = 0755; /* GNU coreutils 6.10 compat */ 160 mode = 0755; /* GNU coreutils 6.10 compat */
161 if (opts & OPT_MODE) 161 if (opts & OPT_MODE)
162 bb_parse_mode(mode_str, &mode); 162 mode = bb_parse_mode(mode_str, mode);
163 uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid(); 163 uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid();
164 gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid(); 164 gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid();
165 165
diff --git a/coreutils/libcoreutils/getopt_mk_fifo_nod.c b/coreutils/libcoreutils/getopt_mk_fifo_nod.c
index 222717149..47375ff91 100644
--- a/coreutils/libcoreutils/getopt_mk_fifo_nod.c
+++ b/coreutils/libcoreutils/getopt_mk_fifo_nod.c
@@ -33,7 +33,9 @@ mode_t FAST_FUNC getopt_mk_fifo_nod(char **argv)
33 int opt; 33 int opt;
34 opt = getopt32(argv, "m:" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); 34 opt = getopt32(argv, "m:" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext));
35 if (opt & 1) { 35 if (opt & 1) {
36 if (bb_parse_mode(smode, &mode)) 36 mode = bb_parse_mode(smode, mode);
37 if (mode != (mode_t)-1) /* if mode is valid */
38 /* make future mknod/mkfifo set mode bits exactly */
37 umask(0); 39 umask(0);
38 } 40 }
39 41
diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c
index 864edfb0a..6f7b004dd 100644
--- a/coreutils/mkdir.c
+++ b/coreutils/mkdir.c
@@ -71,8 +71,8 @@ int mkdir_main(int argc UNUSED_PARAM, char **argv)
71#endif 71#endif
72 opt = getopt32(argv, "m:pv" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); 72 opt = getopt32(argv, "m:pv" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext));
73 if (opt & 1) { 73 if (opt & 1) {
74 mode_t mmode = 0777; 74 mode_t mmode = bb_parse_mode(smode, 0777);
75 if (!bb_parse_mode(smode, &mmode)) { 75 if (mmode == (mode_t)-1) {
76 bb_error_msg_and_die("invalid mode '%s'", smode); 76 bb_error_msg_and_die("invalid mode '%s'", smode);
77 } 77 }
78 mode = mmode; 78 mode = mmode;
diff --git a/coreutils/sort.c b/coreutils/sort.c
index 1cb4c3e3f..36f02543b 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -25,14 +25,14 @@
25//usage: "\n -f Ignore case" 25//usage: "\n -f Ignore case"
26//usage: "\n -g General numerical sort" 26//usage: "\n -g General numerical sort"
27//usage: "\n -i Ignore unprintable characters" 27//usage: "\n -i Ignore unprintable characters"
28//usage: "\n -k Sort key"
29//usage: "\n -M Sort month" 28//usage: "\n -M Sort month"
30//usage: ) 29//usage: )
30//-h, --human-numeric-sort: compare human readable numbers (e.g., 2K 1G)
31//usage: "\n -n Sort numbers" 31//usage: "\n -n Sort numbers"
32//usage: IF_FEATURE_SORT_BIG( 32//usage: IF_FEATURE_SORT_BIG(
33//usage: "\n -o Output to file" 33//usage: "\n -o Output to file"
34//usage: "\n -k Sort by key" 34//usage: "\n -t CHAR Field separator"
35//usage: "\n -t CHAR Key separator" 35//usage: "\n -k N[,M] Sort by Nth field"
36//usage: ) 36//usage: )
37//usage: "\n -r Reverse sort order" 37//usage: "\n -r Reverse sort order"
38//usage: IF_FEATURE_SORT_BIG( 38//usage: IF_FEATURE_SORT_BIG(
@@ -143,6 +143,9 @@ static char *get_key(char *str, struct sort_key *key, int flags)
143 } 143 }
144 } 144 }
145 } 145 }
146 /* Remove last delim: "abc:def:" => "abc:def" */
147 if (key_separator && j && end != 0)
148 end--;
146 } 149 }
147 if (!j) start = end; 150 if (!j) start = end;
148 } 151 }
@@ -163,7 +166,8 @@ static char *get_key(char *str, struct sort_key *key, int flags)
163 if (start > len) start = len; 166 if (start > len) start = len;
164 } 167 }
165 /* Make the copy */ 168 /* Make the copy */
166 if (end < start) end = start; 169 if (end < start)
170 end = start;
167 str = xstrndup(str+start, end-start); 171 str = xstrndup(str+start, end-start);
168 /* Handle -d */ 172 /* Handle -d */
169 if (flags & FLAG_d) { 173 if (flags & FLAG_d) {
diff --git a/coreutils/uniq.c b/coreutils/uniq.c
index 9208d34ec..e0133998a 100644
--- a/coreutils/uniq.c
+++ b/coreutils/uniq.c
@@ -112,7 +112,7 @@ int uniq_main(int argc UNUSED_PARAM, char **argv)
112 /* %7lu matches GNU coreutils 6.9 */ 112 /* %7lu matches GNU coreutils 6.9 */
113 printf("%7lu ", dups + 1); 113 printf("%7lu ", dups + 1);
114 } 114 }
115 printf("%s\n", old_line); 115 puts(old_line);
116 } 116 }
117 free(old_line); 117 free(old_line);
118 } 118 }
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c
index 7aa5c67f2..37b254d30 100644
--- a/coreutils/uudecode.c
+++ b/coreutils/uudecode.c
@@ -29,9 +29,19 @@ static void FAST_FUNC read_stduu(FILE *src_stream, FILE *dst_stream, int flags U
29{ 29{
30 char *line; 30 char *line;
31 31
32 while ((line = xmalloc_fgetline(src_stream)) != NULL) { 32 for (;;) {
33 int encoded_len, str_len; 33 int encoded_len, str_len;
34 char *line_ptr, *dst; 34 char *line_ptr, *dst;
35 size_t line_len;
36
37 line_len = 64 * 1024;
38 line = xmalloc_fgets_str_len(src_stream, "\n", &line_len);
39 if (!line)
40 break;
41 /* Handle both Unix and MSDOS text, and stray trailing spaces */
42 str_len = line_len;
43 while (--str_len >= 0 && isspace(line[str_len]))
44 line[str_len] = '\0';
35 45
36 if (strcmp(line, "end") == 0) { 46 if (strcmp(line, "end") == 0) {
37 return; /* the only non-error exit */ 47 return; /* the only non-error exit */
@@ -128,6 +138,7 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv)
128 if (!outname) 138 if (!outname)
129 break; 139 break;
130 outname++; 140 outname++;
141 trim(outname); /* remove trailing space (and '\r' for DOS text) */
131 if (!outname[0]) 142 if (!outname[0])
132 break; 143 break;
133 } 144 }
diff --git a/coreutils/who.c b/coreutils/who.c
index 8337212c9..f694d0c60 100644
--- a/coreutils/who.c
+++ b/coreutils/who.c
@@ -81,7 +81,7 @@ int who_main(int argc UNUSED_PARAM, char **argv)
81 opt_complementary = "=0"; 81 opt_complementary = "=0";
82 opt = getopt32(argv, do_users ? "" : "aH"); 82 opt = getopt32(argv, do_users ? "" : "aH");
83 if (opt & 2) // -H 83 if (opt & 2) // -H
84 printf("USER\t\tTTY\t\tIDLE\tTIME\t\t HOST\n"); 84 puts("USER\t\tTTY\t\tIDLE\tTIME\t\t HOST");
85 85
86 setutxent(); 86 setutxent();
87 while ((ut = getutxent()) != NULL) { 87 while ((ut = getutxent()) != NULL) {
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c
index 527fae227..dd6fe7d49 100644
--- a/debianutils/run_parts.c
+++ b/debianutils/run_parts.c
@@ -189,7 +189,7 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv)
189 if (ret < 0) 189 if (ret < 0)
190 bb_perror_msg("can't execute '%s'", name); 190 bb_perror_msg("can't execute '%s'", name);
191 else /* ret > 0 */ 191 else /* ret > 0 */
192 bb_error_msg("%s exited with code %d", name, ret & 0xff); 192 bb_error_msg("%s: exit status %u", name, ret & 0xff);
193 193
194 if (option_mask32 & OPT_e) 194 if (option_mask32 & OPT_e)
195 xfunc_die(); 195 xfunc_die();
diff --git a/editors/awk.c b/editors/awk.c
index b4b6c5f78..142ab670f 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -207,7 +207,7 @@ typedef struct tsplitter_s {
207 207
208/* simple token classes */ 208/* simple token classes */
209/* Order and hex values are very important!!! See next_token() */ 209/* Order and hex values are very important!!! See next_token() */
210#define TC_SEQSTART 1 /* ( */ 210#define TC_SEQSTART (1 << 0) /* ( */
211#define TC_SEQTERM (1 << 1) /* ) */ 211#define TC_SEQTERM (1 << 1) /* ) */
212#define TC_REGEXP (1 << 2) /* /.../ */ 212#define TC_REGEXP (1 << 2) /* /.../ */
213#define TC_OUTRDR (1 << 3) /* | > >> */ 213#define TC_OUTRDR (1 << 3) /* | > >> */
@@ -227,16 +227,22 @@ typedef struct tsplitter_s {
227#define TC_WHILE (1 << 17) 227#define TC_WHILE (1 << 17)
228#define TC_ELSE (1 << 18) 228#define TC_ELSE (1 << 18)
229#define TC_BUILTIN (1 << 19) 229#define TC_BUILTIN (1 << 19)
230#define TC_GETLINE (1 << 20) 230/* This costs ~50 bytes of code.
231#define TC_FUNCDECL (1 << 21) /* `function' `func' */ 231 * A separate class to support deprecated "length" form. If we don't need that
232#define TC_BEGIN (1 << 22) 232 * (i.e. if we demand that only "length()" with () is valid), then TC_LENGTH
233#define TC_END (1 << 23) 233 * can be merged with TC_BUILTIN:
234#define TC_EOF (1 << 24) 234 */
235#define TC_VARIABLE (1 << 25) 235#define TC_LENGTH (1 << 20)
236#define TC_ARRAY (1 << 26) 236#define TC_GETLINE (1 << 21)
237#define TC_FUNCTION (1 << 27) 237#define TC_FUNCDECL (1 << 22) /* `function' `func' */
238#define TC_STRING (1 << 28) 238#define TC_BEGIN (1 << 23)
239#define TC_NUMBER (1 << 29) 239#define TC_END (1 << 24)
240#define TC_EOF (1 << 25)
241#define TC_VARIABLE (1 << 26)
242#define TC_ARRAY (1 << 27)
243#define TC_FUNCTION (1 << 28)
244#define TC_STRING (1 << 29)
245#define TC_NUMBER (1 << 30)
240 246
241#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2) 247#define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2)
242 248
@@ -244,14 +250,16 @@ typedef struct tsplitter_s {
244#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN) 250#define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
245//#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST) 251//#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
246#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \ 252#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
247 | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER) 253 | TC_BUILTIN | TC_LENGTH | TC_GETLINE \
254 | TC_SEQSTART | TC_STRING | TC_NUMBER)
248 255
249#define TC_STATEMNT (TC_STATX | TC_WHILE) 256#define TC_STATEMNT (TC_STATX | TC_WHILE)
250#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE) 257#define TC_OPTERM (TC_SEMICOL | TC_NEWLINE)
251 258
252/* word tokens, cannot mean something else if not expected */ 259/* word tokens, cannot mean something else if not expected */
253#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \ 260#define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE \
254 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END) 261 | TC_BUILTIN | TC_LENGTH | TC_GETLINE \
262 | TC_FUNCDECL | TC_BEGIN | TC_END)
255 263
256/* discard newlines after these */ 264/* discard newlines after these */
257#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \ 265#define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
@@ -346,54 +354,54 @@ enum {
346#define NTC "\377" /* switch to next token class (tc<<1) */ 354#define NTC "\377" /* switch to next token class (tc<<1) */
347#define NTCC '\377' 355#define NTCC '\377'
348 356
349#define OC_B OC_BUILTIN
350
351static const char tokenlist[] ALIGN1 = 357static const char tokenlist[] ALIGN1 =
352 "\1(" NTC 358 "\1(" NTC /* TC_SEQSTART */
353 "\1)" NTC 359 "\1)" NTC /* TC_SEQTERM */
354 "\1/" NTC /* REGEXP */ 360 "\1/" NTC /* TC_REGEXP */
355 "\2>>" "\1>" "\1|" NTC /* OUTRDR */ 361 "\2>>" "\1>" "\1|" NTC /* TC_OUTRDR */
356 "\2++" "\2--" NTC /* UOPPOST */ 362 "\2++" "\2--" NTC /* TC_UOPPOST */
357 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ 363 "\2++" "\2--" "\1$" NTC /* TC_UOPPRE1 */
358 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ 364 "\2==" "\1=" "\2+=" "\2-=" /* TC_BINOPX */
359 "\2*=" "\2/=" "\2%=" "\2^=" 365 "\2*=" "\2/=" "\2%=" "\2^="
360 "\1+" "\1-" "\3**=" "\2**" 366 "\1+" "\1-" "\3**=" "\2**"
361 "\1/" "\1%" "\1^" "\1*" 367 "\1/" "\1%" "\1^" "\1*"
362 "\2!=" "\2>=" "\2<=" "\1>" 368 "\2!=" "\2>=" "\2<=" "\1>"
363 "\1<" "\2!~" "\1~" "\2&&" 369 "\1<" "\2!~" "\1~" "\2&&"
364 "\2||" "\1?" "\1:" NTC 370 "\2||" "\1?" "\1:" NTC
365 "\2in" NTC 371 "\2in" NTC /* TC_IN */
366 "\1," NTC 372 "\1," NTC /* TC_COMMA */
367 "\1|" NTC 373 "\1|" NTC /* TC_PIPE */
368 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ 374 "\1+" "\1-" "\1!" NTC /* TC_UOPPRE2 */
369 "\1]" NTC 375 "\1]" NTC /* TC_ARRTERM */
370 "\1{" NTC 376 "\1{" NTC /* TC_GRPSTART */
371 "\1}" NTC 377 "\1}" NTC /* TC_GRPTERM */
372 "\1;" NTC 378 "\1;" NTC /* TC_SEMICOL */
373 "\1\n" NTC 379 "\1\n" NTC /* TC_NEWLINE */
374 "\2if" "\2do" "\3for" "\5break" /* STATX */ 380 "\2if" "\2do" "\3for" "\5break" /* TC_STATX */
375 "\10continue" "\6delete" "\5print" 381 "\10continue" "\6delete" "\5print"
376 "\6printf" "\4next" "\10nextfile" 382 "\6printf" "\4next" "\10nextfile"
377 "\6return" "\4exit" NTC 383 "\6return" "\4exit" NTC
378 "\5while" NTC 384 "\5while" NTC /* TC_WHILE */
379 "\4else" NTC 385 "\4else" NTC /* TC_ELSE */
380 386 "\3and" "\5compl" "\6lshift" "\2or" /* TC_BUILTIN */
381 "\3and" "\5compl" "\6lshift" "\2or"
382 "\6rshift" "\3xor" 387 "\6rshift" "\3xor"
383 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ 388 "\5close" "\6system" "\6fflush" "\5atan2"
384 "\3cos" "\3exp" "\3int" "\3log" 389 "\3cos" "\3exp" "\3int" "\3log"
385 "\4rand" "\3sin" "\4sqrt" "\5srand" 390 "\4rand" "\3sin" "\4sqrt" "\5srand"
386 "\6gensub" "\4gsub" "\5index" "\6length" 391 "\6gensub" "\4gsub" "\5index" /* "\6length" was here */
387 "\5match" "\5split" "\7sprintf" "\3sub" 392 "\5match" "\5split" "\7sprintf" "\3sub"
388 "\6substr" "\7systime" "\10strftime" "\6mktime" 393 "\6substr" "\7systime" "\10strftime" "\6mktime"
389 "\7tolower" "\7toupper" NTC 394 "\7tolower" "\7toupper" NTC
390 "\7getline" NTC 395 "\6length" NTC /* TC_LENGTH */
391 "\4func" "\10function" NTC 396 "\7getline" NTC /* TC_GETLINE */
392 "\5BEGIN" NTC 397 "\4func" "\10function" NTC /* TC_FUNCDECL */
393 "\3END" 398 "\5BEGIN" NTC /* TC_BEGIN */
399 "\3END" /* TC_END */
394 /* compiler adds trailing "\0" */ 400 /* compiler adds trailing "\0" */
395 ; 401 ;
396 402
403#define OC_B OC_BUILTIN
404
397static const uint32_t tokeninfo[] = { 405static const uint32_t tokeninfo[] = {
398 0, 406 0,
399 0, 407 0,
@@ -408,7 +416,7 @@ static const uint32_t tokeninfo[] = {
408 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, 416 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
409 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), 417 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
410 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':', 418 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':',
411 OC_IN|SV|P(49), /* in */ 419 OC_IN|SV|P(49), /* TC_IN */
412 OC_COMMA|SS|P(80), 420 OC_COMMA|SS|P(80),
413 OC_PGETLINE|SV|P(37), 421 OC_PGETLINE|SV|P(37),
414 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!', 422 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!',
@@ -423,20 +431,20 @@ static const uint32_t tokeninfo[] = {
423 OC_RETURN|Vx, OC_EXIT|Nx, 431 OC_RETURN|Vx, OC_EXIT|Nx,
424 ST_WHILE, 432 ST_WHILE,
425 0, /* else */ 433 0, /* else */
426
427 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83), 434 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
428 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83), 435 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
429 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83), 436 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
430 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg, 437 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
431 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr, 438 OC_FBLTIN|F_rn, OC_FBLTIN|Nx|F_si, OC_FBLTIN|Nx|F_sq, OC_FBLTIN|Nx|F_sr,
432 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), OC_FBLTIN|Sx|F_le, 439 OC_B|B_ge|P(0xd6), OC_B|B_gs|P(0xb6), OC_B|B_ix|P(0x9b), /* OC_FBLTIN|Sx|F_le, was here */
433 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6), 440 OC_B|B_ma|P(0x89), OC_B|B_sp|P(0x8b), OC_SPRINTF, OC_B|B_su|P(0xb6),
434 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), 441 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b),
435 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), 442 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
443 OC_FBLTIN|Sx|F_le, /* TC_LENGTH */
436 OC_GETLINE|SV|P(0), 444 OC_GETLINE|SV|P(0),
437 0, 0, 445 0, 0,
438 0, 446 0,
439 0 /* END */ 447 0 /* TC_END */
440}; 448};
441 449
442/* internal variable names and their initial values */ 450/* internal variable names and their initial values */
@@ -1206,9 +1214,10 @@ static uint32_t next_token(uint32_t expected)
1206 ltclass = t_tclass; 1214 ltclass = t_tclass;
1207 1215
1208 /* Are we ready for this? */ 1216 /* Are we ready for this? */
1209 if (!(ltclass & expected)) 1217 if (!(ltclass & expected)) {
1210 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ? 1218 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
1211 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); 1219 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
1220 }
1212 1221
1213 return ltclass; 1222 return ltclass;
1214#undef concat_inserted 1223#undef concat_inserted
@@ -1375,6 +1384,16 @@ static node *parse_expr(uint32_t iexp)
1375 debug_printf_parse("%s: TC_BUILTIN\n", __func__); 1384 debug_printf_parse("%s: TC_BUILTIN\n", __func__);
1376 cn->l.n = condition(); 1385 cn->l.n = condition();
1377 break; 1386 break;
1387
1388 case TC_LENGTH:
1389 debug_printf_parse("%s: TC_LENGTH\n", __func__);
1390 next_token(TC_SEQSTART | TC_OPTERM | TC_GRPTERM);
1391 rollback_token();
1392 if (t_tclass & TC_SEQSTART) {
1393 /* It was a "(" token. Handle just like TC_BUILTIN */
1394 cn->l.n = condition();
1395 }
1396 break;
1378 } 1397 }
1379 } 1398 }
1380 } 1399 }
diff --git a/editors/diff.c b/editors/diff.c
index e0adcee59..a892cfdf2 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -433,7 +433,7 @@ static void fetch(FILE_and_pos_t *ft, const off_t *ix, int a, int b, int ch)
433 for (j = 0, col = 0; j < ix[i] - ix[i - 1]; j++) { 433 for (j = 0, col = 0; j < ix[i] - ix[i - 1]; j++) {
434 int c = fgetc(ft->ft_fp); 434 int c = fgetc(ft->ft_fp);
435 if (c == EOF) { 435 if (c == EOF) {
436 printf("\n\\ No newline at end of file\n"); 436 puts("\n\\ No newline at end of file");
437 return; 437 return;
438 } 438 }
439 ft->ft_pos++; 439 ft->ft_pos++;
@@ -692,7 +692,7 @@ static bool diff(FILE* fp[2], char *file[2])
692 continue; 692 continue;
693 printf(",%d", (a < b) ? b - a + 1 : 0); 693 printf(",%d", (a < b) ? b - a + 1 : 0);
694 } 694 }
695 printf(" @@\n"); 695 puts(" @@");
696 /* 696 /*
697 * Output changes in "unified" diff format--the old and new lines 697 * Output changes in "unified" diff format--the old and new lines
698 * are printed together. 698 * are printed together.
diff --git a/editors/ed.c b/editors/ed.c
index f0e5e4d5d..a4c419099 100644
--- a/editors/ed.c
+++ b/editors/ed.c
@@ -206,7 +206,7 @@ static void doCommands(void)
206 if (fileName) 206 if (fileName)
207 printf("\"%s\"\n", fileName); 207 printf("\"%s\"\n", fileName);
208 else 208 else
209 printf("No file name\n"); 209 puts("No file name");
210 break; 210 break;
211 } 211 }
212 free(fileName); 212 free(fileName);
diff --git a/editors/vi.c b/editors/vi.c
index 075f714cf..b2d185193 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -2919,10 +2919,10 @@ static int file_insert(const char *fn, char *p, int initial)
2919 int fd, size; 2919 int fd, size;
2920 struct stat statbuf; 2920 struct stat statbuf;
2921 2921
2922 if (p < text || p > end) { 2922 if (p < text)
2923 status_line_bold("Trying to insert file outside of memory"); 2923 p = text;
2924 return cnt; 2924 if (p > end)
2925 } 2925 p = end;
2926 2926
2927 fd = open(fn, O_RDONLY); 2927 fd = open(fn, O_RDONLY);
2928 if (fd < 0) { 2928 if (fd < 0) {
diff --git a/findutils/find.c b/findutils/find.c
index ced8922e7..bd7ccc323 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -768,7 +768,10 @@ ACTF(delete)
768{ 768{
769 int rc; 769 int rc;
770 if (S_ISDIR(statbuf->st_mode)) { 770 if (S_ISDIR(statbuf->st_mode)) {
771 rc = rmdir(fileName); 771 /* "find . -delete" skips rmdir(".") */
772 rc = 0;
773 if (NOT_LONE_CHAR(fileName, '.'))
774 rc = rmdir(fileName);
772 } else { 775 } else {
773 rc = unlink(fileName); 776 rc = unlink(fileName);
774 } 777 }
@@ -1261,7 +1264,8 @@ static action*** parse_params(char **argv)
1261 ap->perm_char = arg1[0]; 1264 ap->perm_char = arg1[0];
1262 arg1 = (arg1[0] == '/' ? arg1+1 : plus_minus_num(arg1)); 1265 arg1 = (arg1[0] == '/' ? arg1+1 : plus_minus_num(arg1));
1263 /*ap->perm_mask = 0; - ALLOC_ACTION did it */ 1266 /*ap->perm_mask = 0; - ALLOC_ACTION did it */
1264 if (!bb_parse_mode(arg1, &ap->perm_mask)) 1267 ap->perm_mask = bb_parse_mode(arg1, ap->perm_mask);
1268 if (ap->perm_mask == (mode_t)-1)
1265 bb_error_msg_and_die("invalid mode '%s'", arg1); 1269 bb_error_msg_and_die("invalid mode '%s'", arg1);
1266 } 1270 }
1267#endif 1271#endif
diff --git a/findutils/xargs.c b/findutils/xargs.c
index 1ca136128..dba74ea61 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -125,7 +125,7 @@ static int xargs_exec(void)
125 return 124; 125 return 124;
126 } 126 }
127 if (status >= 0x180) { 127 if (status >= 0x180) {
128 bb_error_msg("%s: terminated by signal %d", 128 bb_error_msg("'%s' terminated by signal %d",
129 G.args[0], status - 0x180); 129 G.args[0], status - 0x180);
130 return 125; 130 return 125;
131 } 131 }
diff --git a/include/applets.src.h b/include/applets.src.h
index 9f3ac78cb..dac83e7fb 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -382,7 +382,6 @@ IF_VOLNAME(APPLET(volname, BB_DIR_USR_BIN, BB_SUID_DROP))
382IF_WATCH(APPLET(watch, BB_DIR_BIN, BB_SUID_DROP)) 382IF_WATCH(APPLET(watch, BB_DIR_BIN, BB_SUID_DROP))
383IF_WATCHDOG(APPLET(watchdog, BB_DIR_SBIN, BB_SUID_DROP)) 383IF_WATCHDOG(APPLET(watchdog, BB_DIR_SBIN, BB_SUID_DROP))
384IF_WC(APPLET(wc, BB_DIR_USR_BIN, BB_SUID_DROP)) 384IF_WC(APPLET(wc, BB_DIR_USR_BIN, BB_SUID_DROP))
385IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP))
386IF_WHICH(APPLET(which, BB_DIR_USR_BIN, BB_SUID_DROP)) 385IF_WHICH(APPLET(which, BB_DIR_USR_BIN, BB_SUID_DROP))
387IF_WHOAMI(APPLET_NOFORK(whoami, whoami, BB_DIR_USR_BIN, BB_SUID_DROP, whoami)) 386IF_WHOAMI(APPLET_NOFORK(whoami, whoami, BB_DIR_USR_BIN, BB_SUID_DROP, whoami))
388IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) 387IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes))
diff --git a/include/libbb.h b/include/libbb.h
index 729704974..2f90b35f7 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -424,6 +424,7 @@ const char *bb_basename(const char *name) FAST_FUNC;
424char *last_char_is(const char *s, int c) FAST_FUNC; 424char *last_char_is(const char *s, int c) FAST_FUNC;
425const char* endofname(const char *name) FAST_FUNC; 425const char* endofname(const char *name) FAST_FUNC;
426char *is_prefixed_with(const char *string, const char *key) FAST_FUNC; 426char *is_prefixed_with(const char *string, const char *key) FAST_FUNC;
427char *is_suffixed_with(const char *string, const char *key) FAST_FUNC;
427 428
428int ndelay_on(int fd) FAST_FUNC; 429int ndelay_on(int fd) FAST_FUNC;
429int ndelay_off(int fd) FAST_FUNC; 430int ndelay_off(int fd) FAST_FUNC;
@@ -572,6 +573,11 @@ void xlisten(int s, int backlog) FAST_FUNC;
572void xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen) FAST_FUNC; 573void xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen) FAST_FUNC;
573ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, 574ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
574 socklen_t tolen) FAST_FUNC; 575 socklen_t tolen) FAST_FUNC;
576
577int setsockopt_int(int fd, int level, int optname, int optval) FAST_FUNC;
578int setsockopt_1(int fd, int level, int optname) FAST_FUNC;
579int setsockopt_SOL_SOCKET_int(int fd, int optname, int optval) FAST_FUNC;
580int setsockopt_SOL_SOCKET_1(int fd, int optname) FAST_FUNC;
575/* SO_REUSEADDR allows a server to rebind to an address that is already 581/* SO_REUSEADDR allows a server to rebind to an address that is already
576 * "in use" by old connections to e.g. previous server instance which is 582 * "in use" by old connections to e.g. previous server instance which is
577 * killed or crashed. Without it bind will fail until all such connections 583 * killed or crashed. Without it bind will fail until all such connections
@@ -579,6 +585,7 @@ ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
579 * regardless of SO_REUSEADDR (unlike some other flavors of Unix). 585 * regardless of SO_REUSEADDR (unlike some other flavors of Unix).
580 * Turn it on before you call bind(). */ 586 * Turn it on before you call bind(). */
581void setsockopt_reuseaddr(int fd) FAST_FUNC; /* On Linux this never fails. */ 587void setsockopt_reuseaddr(int fd) FAST_FUNC; /* On Linux this never fails. */
588int setsockopt_keepalive(int fd) FAST_FUNC;
582int setsockopt_broadcast(int fd) FAST_FUNC; 589int setsockopt_broadcast(int fd) FAST_FUNC;
583int setsockopt_bindtodevice(int fd, const char *iface) FAST_FUNC; 590int setsockopt_bindtodevice(int fd, const char *iface) FAST_FUNC;
584/* NB: returns port in host byte order */ 591/* NB: returns port in host byte order */
@@ -696,6 +703,7 @@ int bb_putchar(int ch) FAST_FUNC;
696/* Note: does not use stdio, writes to fd 2 directly */ 703/* Note: does not use stdio, writes to fd 2 directly */
697int bb_putchar_stderr(char ch) FAST_FUNC; 704int bb_putchar_stderr(char ch) FAST_FUNC;
698char *xasprintf(const char *format, ...) __attribute__ ((format(printf, 1, 2))) FAST_FUNC RETURNS_MALLOC; 705char *xasprintf(const char *format, ...) __attribute__ ((format(printf, 1, 2))) FAST_FUNC RETURNS_MALLOC;
706char *auto_string(char *str) FAST_FUNC;
699// gcc-4.1.1 still isn't good enough at optimizing it 707// gcc-4.1.1 still isn't good enough at optimizing it
700// (+200 bytes compared to macro) 708// (+200 bytes compared to macro)
701//static ALWAYS_INLINE 709//static ALWAYS_INLINE
@@ -1134,9 +1142,8 @@ enum {
1134extern const char *msg_eol; 1142extern const char *msg_eol;
1135extern smallint syslog_level; 1143extern smallint syslog_level;
1136extern smallint logmode; 1144extern smallint logmode;
1137extern int die_sleep;
1138extern uint8_t xfunc_error_retval; 1145extern uint8_t xfunc_error_retval;
1139extern jmp_buf die_jmp; 1146extern void (*die_func)(void);
1140extern void xfunc_die(void) NORETURN FAST_FUNC; 1147extern void xfunc_die(void) NORETURN FAST_FUNC;
1141extern void bb_show_usage(void) NORETURN FAST_FUNC; 1148extern void bb_show_usage(void) NORETURN FAST_FUNC;
1142extern void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; 1149extern void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC;
@@ -1258,7 +1265,8 @@ char *bb_ask_stdin(const char * prompt) FAST_FUNC;
1258char *bb_ask(const int fd, int timeout, const char * prompt) FAST_FUNC; 1265char *bb_ask(const int fd, int timeout, const char * prompt) FAST_FUNC;
1259int bb_ask_confirmation(void) FAST_FUNC; 1266int bb_ask_confirmation(void) FAST_FUNC;
1260 1267
1261int bb_parse_mode(const char* s, mode_t* theMode) FAST_FUNC; 1268/* Returns -1 if input is invalid. current_mode is a base for e.g. "u+rw" */
1269int bb_parse_mode(const char* s, unsigned cur_mode) FAST_FUNC;
1262 1270
1263/* 1271/*
1264 * Config file parser 1272 * Config file parser
@@ -1832,7 +1840,7 @@ extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr
1832#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin")) 1840#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin"))
1833 1841
1834extern const int const_int_0; 1842extern const int const_int_0;
1835extern const int const_int_1; 1843//extern const int const_int_1;
1836 1844
1837 1845
1838/* Providing hard guarantee on minimum size (think of BUFSIZ == 128) */ 1846/* Providing hard guarantee on minimum size (think of BUFSIZ == 128) */
@@ -1918,6 +1926,7 @@ extern const char bb_default_login_shell[] ALIGN1;
1918 1926
1919 1927
1920#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) 1928#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0])))
1929#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
1921 1930
1922 1931
1923/* We redefine ctype macros. Unicode-correct handling of char types 1932/* We redefine ctype macros. Unicode-correct handling of char types
@@ -2008,7 +2017,6 @@ static ALWAYS_INLINE unsigned char bb_ascii_tolower(unsigned char a)
2008typedef void (*bbunit_testfunc)(void); 2017typedef void (*bbunit_testfunc)(void);
2009 2018
2010struct bbunit_listelem { 2019struct bbunit_listelem {
2011 struct bbunit_listelem* next;
2012 const char* name; 2020 const char* name;
2013 bbunit_testfunc testfunc; 2021 bbunit_testfunc testfunc;
2014}; 2022};
diff --git a/init/init.c b/init/init.c
index b2fe85635..80c5d0f74 100644
--- a/init/init.c
+++ b/init/init.c
@@ -1015,6 +1015,11 @@ void handle_sigsegv(int sig, siginfo_t *info, void *ucontext)
1015} 1015}
1016#endif 1016#endif
1017 1017
1018static void sleep_much(void)
1019{
1020 sleep(30 * 24*60*60);
1021}
1022
1018int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1023int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1019int init_main(int argc UNUSED_PARAM, char **argv) 1024int init_main(int argc UNUSED_PARAM, char **argv)
1020{ 1025{
@@ -1051,12 +1056,12 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1051 1056
1052 /* If, say, xmalloc would ever die, we don't want to oops kernel 1057 /* If, say, xmalloc would ever die, we don't want to oops kernel
1053 * by exiting. 1058 * by exiting.
1054 * NB: we set die_sleep *after* PID 1 check and bb_show_usage. 1059 * NB: we set die_func *after* PID 1 check and bb_show_usage.
1055 * Otherwise, for example, "init u" ("please rexec yourself" 1060 * Otherwise, for example, "init u" ("please rexec yourself"
1056 * command for sysvinit) will show help text (which isn't too bad), 1061 * command for sysvinit) will show help text (which isn't too bad),
1057 * *and sleep forever* (which is bad!) 1062 * *and sleep forever* (which is bad!)
1058 */ 1063 */
1059 die_sleep = 30 * 24*60*60; 1064 die_func = sleep_much;
1060 1065
1061 /* Figure out where the default console should be */ 1066 /* Figure out where the default console should be */
1062 console_init(); 1067 console_init();
diff --git a/libbb/auto_string.c b/libbb/auto_string.c
new file mode 100644
index 000000000..ae940069a
--- /dev/null
+++ b/libbb/auto_string.c
@@ -0,0 +1,23 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2015 Denys Vlasenko
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9//kbuild:lib-y += auto_string.o
10
11#include "libbb.h"
12
13char* FAST_FUNC auto_string(char *str)
14{
15 static char *saved[4];
16 static uint8_t cur_saved; /* = 0 */
17
18 free(saved[cur_saved]);
19 saved[cur_saved] = str;
20 cur_saved = (cur_saved + 1) & (ARRAY_SIZE(saved)-1);
21
22 return str;
23}
diff --git a/libbb/bb_askpass.c b/libbb/bb_askpass.c
index 1927ba9e9..c2580b9eb 100644
--- a/libbb/bb_askpass.c
+++ b/libbb/bb_askpass.c
@@ -1,7 +1,6 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * Ask for a password 3 * Ask for a password
4 * I use a static buffer in this function. Plan accordingly.
5 * 4 *
6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7 * 6 *
@@ -23,8 +22,8 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt)
23{ 22{
24 /* Was static char[BIGNUM] */ 23 /* Was static char[BIGNUM] */
25 enum { sizeof_passwd = 128 }; 24 enum { sizeof_passwd = 128 };
26 static char *passwd;
27 25
26 char *passwd;
28 char *ret; 27 char *ret;
29 int i; 28 int i;
30 struct sigaction sa, oldsa; 29 struct sigaction sa, oldsa;
@@ -62,8 +61,7 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt)
62 alarm(timeout); 61 alarm(timeout);
63 } 62 }
64 63
65 if (!passwd) 64 passwd = auto_string(xmalloc(sizeof_passwd));
66 passwd = xmalloc(sizeof_passwd);
67 ret = passwd; 65 ret = passwd;
68 i = 0; 66 i = 0;
69 while (1) { 67 while (1) {
diff --git a/libbb/bbunit.c b/libbb/bbunit.c
index 4c692d59f..db67b1081 100644
--- a/libbb/bbunit.c
+++ b/libbb/bbunit.c
@@ -17,8 +17,6 @@
17 17
18#include "libbb.h" 18#include "libbb.h"
19 19
20#define WANT_TIMING 0
21
22static llist_t *tests = NULL; 20static llist_t *tests = NULL;
23static unsigned tests_registered = 0; 21static unsigned tests_registered = 0;
24static int test_retval; 22static int test_retval;
@@ -34,57 +32,34 @@ void bbunit_settestfailed(void)
34 test_retval = -1; 32 test_retval = -1;
35} 33}
36 34
37#if WANT_TIMING
38static void timeval_diff(struct timeval* res,
39 const struct timeval* x,
40 const struct timeval* y)
41{
42 long udiff = x->tv_usec - y->tv_usec;
43
44 res->tv_sec = x->tv_sec - y->tv_sec - (udiff < 0);
45 res->tv_usec = (udiff >= 0 ? udiff : udiff + 1000000);
46}
47#endif
48
49int unit_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) MAIN_EXTERNALLY_VISIBLE; 35int unit_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) MAIN_EXTERNALLY_VISIBLE;
50int unit_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 36int unit_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
51{ 37{
52 unsigned tests_run = 0; 38 unsigned tests_run = 0;
53 unsigned tests_failed = 0; 39 unsigned tests_failed = 0;
54#if WANT_TIMING
55 struct timeval begin;
56 struct timeval end;
57 struct timeval time_spent;
58 gettimeofday(&begin, NULL);
59#endif
60 40
61 bb_error_msg("Running %d test(s)...", tests_registered); 41 bb_error_msg("Running %d test(s)...", tests_registered);
62 for (;;) { 42 for (;;) {
63 struct bbunit_listelem* el = llist_pop(&tests); 43 struct bbunit_listelem* el = llist_pop(&tests);
64 if (!el) 44 if (!el)
65 break; 45 break;
46
66 bb_error_msg("Case: [%s]", el->name); 47 bb_error_msg("Case: [%s]", el->name);
67 test_retval = 0; 48 test_retval = 0;
68 el->testfunc(); 49 el->testfunc();
50
69 if (test_retval < 0) { 51 if (test_retval < 0) {
70 bb_error_msg("[ERROR] [%s]: TEST FAILED", el->name); 52 bb_error_msg("[ERROR] [%s]: TEST FAILED", el->name);
71 tests_failed++; 53 tests_failed++;
72 } 54 }
73 tests_run++; 55 tests_run++;
74 el = el->next;
75 } 56 }
76 57
77#if WANT_TIMING
78 gettimeofday(&end, NULL);
79 timeval_diff(&time_spent, &end, &begin);
80 bb_error_msg("Elapsed time %u.%06u seconds",
81 (int)time_spent.tv_sec,
82 (int)time_spent.tv_usec);
83#endif
84 if (tests_failed > 0) { 58 if (tests_failed > 0) {
85 bb_error_msg("[ERROR] %u test(s) FAILED", tests_failed); 59 bb_error_msg("[ERROR] %u test(s) FAILED", tests_failed);
86 return EXIT_FAILURE; 60 return EXIT_FAILURE;
87 } 61 }
62
88 bb_error_msg("All tests passed"); 63 bb_error_msg("All tests passed");
89 return EXIT_SUCCESS; 64 return EXIT_SUCCESS;
90} 65}
diff --git a/libbb/compare_string_array.c b/libbb/compare_string_array.c
index e24815a03..2f51237a3 100644
--- a/libbb/compare_string_array.c
+++ b/libbb/compare_string_array.c
@@ -5,6 +5,11 @@
5 5
6#include "libbb.h" 6#include "libbb.h"
7 7
8/*
9 * Return NULL if string is not prefixed with key. Return pointer to the
10 * first character in string after the prefix key. If key is an empty string,
11 * return pointer to the beginning of string.
12 */
8char* FAST_FUNC is_prefixed_with(const char *string, const char *key) 13char* FAST_FUNC is_prefixed_with(const char *string, const char *key)
9{ 14{
10#if 0 /* Two passes over key - probably slower */ 15#if 0 /* Two passes over key - probably slower */
@@ -23,6 +28,26 @@ char* FAST_FUNC is_prefixed_with(const char *string, const char *key)
23#endif 28#endif
24} 29}
25 30
31/*
32 * Return NULL if string is not suffixed with key. Return pointer to the
33 * beginning of prefix key in string. If key is an empty string return pointer
34 * to the end of string.
35 */
36char* FAST_FUNC is_suffixed_with(const char *string, const char *key)
37{
38 size_t key_len = strlen(key);
39 ssize_t len_diff = strlen(string) - key_len;
40
41 if (len_diff >= 0) {
42 string += len_diff;
43 if (strcmp(string, key) == 0) {
44 return (char*)string;
45 }
46 }
47
48 return NULL;
49}
50
26/* returns the array index of the string */ 51/* returns the array index of the string */
27/* (index of first match is returned, or -1) */ 52/* (index of first match is returned, or -1) */
28int FAST_FUNC index_in_str_array(const char *const string_array[], const char *key) 53int FAST_FUNC index_in_str_array(const char *const string_array[], const char *key)
@@ -110,3 +135,37 @@ smallint FAST_FUNC yesno(const char *str)
110 return ret / 3; 135 return ret / 3;
111} 136}
112#endif 137#endif
138
139#if ENABLE_UNIT_TEST
140
141BBUNIT_DEFINE_TEST(is_prefixed_with)
142{
143 BBUNIT_ASSERT_STREQ(" bar", is_prefixed_with("foo bar", "foo"));
144 BBUNIT_ASSERT_STREQ("bar", is_prefixed_with("foo bar", "foo "));
145 BBUNIT_ASSERT_STREQ("", is_prefixed_with("foo", "foo"));
146 BBUNIT_ASSERT_STREQ("foo", is_prefixed_with("foo", ""));
147 BBUNIT_ASSERT_STREQ("", is_prefixed_with("", ""));
148
149 BBUNIT_ASSERT_NULL(is_prefixed_with("foo", "bar foo"));
150 BBUNIT_ASSERT_NULL(is_prefixed_with("foo foo", "bar"));
151 BBUNIT_ASSERT_NULL(is_prefixed_with("", "foo"));
152
153 BBUNIT_ENDTEST;
154}
155
156BBUNIT_DEFINE_TEST(is_suffixed_with)
157{
158 BBUNIT_ASSERT_STREQ("bar", is_suffixed_with("foo bar", "bar"));
159 BBUNIT_ASSERT_STREQ("foo", is_suffixed_with("foo", "foo"));
160 BBUNIT_ASSERT_STREQ("", is_suffixed_with("foo", ""));
161 BBUNIT_ASSERT_STREQ("", is_suffixed_with("", ""));
162 BBUNIT_ASSERT_STREQ("foo", is_suffixed_with("barfoofoo", "foo"));
163
164 BBUNIT_ASSERT_NULL(is_suffixed_with("foo", "bar foo"));
165 BBUNIT_ASSERT_NULL(is_suffixed_with("foo foo", "bar"));
166 BBUNIT_ASSERT_NULL(is_suffixed_with("", "foo"));
167
168 BBUNIT_ENDTEST;
169}
170
171#endif /* ENABLE_UNIT_TEST */
diff --git a/libbb/fflush_stdout_and_exit.c b/libbb/fflush_stdout_and_exit.c
index 9ad5dbf96..b4bed865f 100644
--- a/libbb/fflush_stdout_and_exit.c
+++ b/libbb/fflush_stdout_and_exit.c
@@ -15,15 +15,10 @@
15 15
16void FAST_FUNC fflush_stdout_and_exit(int retval) 16void FAST_FUNC fflush_stdout_and_exit(int retval)
17{ 17{
18 xfunc_error_retval = retval;
18 if (fflush(stdout)) 19 if (fflush(stdout))
19 bb_perror_msg_and_die(bb_msg_standard_output); 20 bb_perror_msg_and_die(bb_msg_standard_output);
20 21 /* In case we are in NOFORK applet. Do not exit() directly,
21 if (ENABLE_FEATURE_PREFER_APPLETS && die_sleep < 0) { 22 * but use xfunc_die() */
22 /* We are in NOFORK applet. Do not exit() directly, 23 xfunc_die();
23 * but use xfunc_die() */
24 xfunc_error_retval = retval;
25 xfunc_die();
26 }
27
28 exit(retval);
29} 24}
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index 1f63ccdee..d08c6b2f7 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -137,7 +137,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
137#if MD5_SMALL > 0 137#if MD5_SMALL > 0
138 /* Before we start, one word to the strange constants. 138 /* Before we start, one word to the strange constants.
139 They are defined in RFC 1321 as 139 They are defined in RFC 1321 as
140 T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64 140 T[i] = (int)(2^32 * fabs(sin(i))), i=1..64
141 */ 141 */
142 static const uint32_t C_array[] = { 142 static const uint32_t C_array[] = {
143 /* round 1 */ 143 /* round 1 */
@@ -213,7 +213,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
213 case 2: 213 case 2:
214 temp += FH(B, C, D); 214 temp += FH(B, C, D);
215 break; 215 break;
216 case 3: 216 default: /* case 3 */
217 temp += FI(B, C, D); 217 temp += FI(B, C, D);
218 } 218 }
219 temp += words[(int) (*pp++)] + *pc++; 219 temp += words[(int) (*pp++)] + *pc++;
@@ -277,10 +277,6 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
277 277
278#else /* MD5_SMALL == 0 or 1 */ 278#else /* MD5_SMALL == 0 or 1 */
279 279
280 uint32_t A_save = A;
281 uint32_t B_save = B;
282 uint32_t C_save = C;
283 uint32_t D_save = D;
284# if MD5_SMALL == 1 280# if MD5_SMALL == 1
285 const uint32_t *pc; 281 const uint32_t *pc;
286 const char *pp; 282 const char *pp;
@@ -425,10 +421,10 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
425# undef OP 421# undef OP
426# endif 422# endif
427 /* Add checksum to the starting values */ 423 /* Add checksum to the starting values */
428 ctx->hash[0] = A_save + A; 424 ctx->hash[0] += A;
429 ctx->hash[1] = B_save + B; 425 ctx->hash[1] += B;
430 ctx->hash[2] = C_save + C; 426 ctx->hash[2] += C;
431 ctx->hash[3] = D_save + D; 427 ctx->hash[3] += D;
432#endif 428#endif
433} 429}
434#undef FF 430#undef FF
diff --git a/libbb/human_readable.c b/libbb/human_readable.c
index 0b2eb777e..5c7fc076f 100644
--- a/libbb/human_readable.c
+++ b/libbb/human_readable.c
@@ -37,8 +37,6 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val,
37 '\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' 37 '\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'
38 }; 38 };
39 39
40 static char *str;
41
42 unsigned frac; /* 0..9 - the fractional digit */ 40 unsigned frac; /* 0..9 - the fractional digit */
43 const char *u; 41 const char *u;
44 const char *fmt; 42 const char *fmt;
@@ -81,12 +79,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val,
81#endif 79#endif
82 } 80 }
83 81
84 if (!str) { 82 return auto_string(xasprintf(fmt, val, frac, *u));
85 /* sufficient for any width of val */
86 str = xmalloc(sizeof(val)*3 + 2 + 3);
87 }
88 sprintf(str, fmt, val, frac, *u);
89 return str;
90} 83}
91 84
92 85
diff --git a/libbb/messages.c b/libbb/messages.c
index ef42b30d7..108cb0285 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -45,7 +45,7 @@ const char bb_PATH_root_path[] ALIGN1 =
45 "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH; 45 "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH;
46 46
47 47
48const int const_int_1 = 1; 48//const int const_int_1 = 1;
49/* explicitly = 0, otherwise gcc may make it a common variable 49/* explicitly = 0, otherwise gcc may make it a common variable
50 * and it will end up in bss */ 50 * and it will end up in bss */
51const int const_int_0 = 0; 51const int const_int_0 = 0;
diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c
index 5a4e1c579..bddd39bca 100644
--- a/libbb/parse_mode.c
+++ b/libbb/parse_mode.c
@@ -15,7 +15,7 @@
15 15
16#define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) 16#define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
17 17
18int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) 18int FAST_FUNC bb_parse_mode(const char *s, unsigned current_mode)
19{ 19{
20 static const mode_t who_mask[] = { 20 static const mode_t who_mask[] = {
21 S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */ 21 S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
@@ -46,13 +46,12 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode)
46 46
47 tmp = strtoul(s, &e, 8); 47 tmp = strtoul(s, &e, 8);
48 if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */ 48 if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
49 return 0; 49 return -1;
50 } 50 }
51 *current_mode = tmp; 51 return tmp;
52 return 1;
53 } 52 }
54 53
55 new_mode = *current_mode; 54 new_mode = current_mode;
56 55
57 /* Note: we allow empty clauses, and hence empty modes. 56 /* Note: we allow empty clauses, and hence empty modes.
58 * We treat an empty mode as no change to perms. */ 57 * We treat an empty mode as no change to perms. */
@@ -71,7 +70,7 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode)
71 if (*p == *s) { 70 if (*p == *s) {
72 wholist |= who_mask[(int)(p-who_chars)]; 71 wholist |= who_mask[(int)(p-who_chars)];
73 if (!*++s) { 72 if (!*++s) {
74 return 0; 73 return -1;
75 } 74 }
76 goto WHO_LIST; 75 goto WHO_LIST;
77 } 76 }
@@ -80,7 +79,7 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode)
80 do { /* Process action list. */ 79 do { /* Process action list. */
81 if ((*s != '+') && (*s != '-')) { 80 if ((*s != '+') && (*s != '-')) {
82 if (*s != '=') { 81 if (*s != '=') {
83 return 0; 82 return -1;
84 } 83 }
85 /* Since op is '=', clear all bits corresponding to the 84 /* Since op is '=', clear all bits corresponding to the
86 * wholist, or all file bits if wholist is empty. */ 85 * wholist, or all file bits if wholist is empty. */
@@ -145,6 +144,5 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode)
145 } while (*s && (*s != ',')); 144 } while (*s && (*s != ','));
146 } 145 }
147 146
148 *current_mode = new_mode; 147 return new_mode;
149 return 1;
150} 148}
diff --git a/libbb/printable_string.c b/libbb/printable_string.c
index 3e768d0b9..e638a178e 100644
--- a/libbb/printable_string.c
+++ b/libbb/printable_string.c
@@ -11,9 +11,6 @@
11 11
12const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str) 12const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
13{ 13{
14 static char *saved[4];
15 static unsigned cur_saved; /* = 0 */
16
17 char *dst; 14 char *dst;
18 const char *s; 15 const char *s;
19 16
@@ -56,10 +53,5 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
56 } 53 }
57 } 54 }
58#endif 55#endif
59 56 return auto_string(dst);
60 free(saved[cur_saved]);
61 saved[cur_saved] = dst;
62 cur_saved = (cur_saved + 1) & (ARRAY_SIZE(saved)-1);
63
64 return dst;
65} 57}
diff --git a/libbb/procps.c b/libbb/procps.c
index 32dae43e3..5a4ea59d0 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -284,7 +284,6 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
284} 284}
285#endif 285#endif
286 286
287void BUG_comm_size(void);
288procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) 287procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
289{ 288{
290 if (!sp) 289 if (!sp)
@@ -386,8 +385,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
386 /*if (!cp || cp[1] != ' ') 385 /*if (!cp || cp[1] != ' ')
387 continue;*/ 386 continue;*/
388 cp[0] = '\0'; 387 cp[0] = '\0';
389 if (sizeof(sp->comm) < 16) 388 BUILD_BUG_ON(sizeof(sp->comm) < 16);
390 BUG_comm_size();
391 comm1 = strchr(buf, '('); 389 comm1 = strchr(buf, '(');
392 /*if (comm1)*/ 390 /*if (comm1)*/
393 safe_strncpy(sp->comm, comm1 + 1, sizeof(sp->comm)); 391 safe_strncpy(sp->comm, comm1 + 1, sizeof(sp->comm));
diff --git a/libbb/udp_io.c b/libbb/udp_io.c
index 7985a9723..a32af9bd2 100644
--- a/libbb/udp_io.c
+++ b/libbb/udp_io.c
@@ -16,10 +16,10 @@ void FAST_FUNC
16socket_want_pktinfo(int fd UNUSED_PARAM) 16socket_want_pktinfo(int fd UNUSED_PARAM)
17{ 17{
18#ifdef IP_PKTINFO 18#ifdef IP_PKTINFO
19 setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &const_int_1, sizeof(int)); 19 setsockopt_1(fd, IPPROTO_IP, IP_PKTINFO);
20#endif 20#endif
21#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) 21#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
22 setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &const_int_1, sizeof(int)); 22 setsockopt_1(fd, IPPROTO_IPV6, IPV6_PKTINFO);
23#endif 23#endif
24} 24}
25 25
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index de4d14fce..2d3204507 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -71,28 +71,44 @@ pid_t FAST_FUNC xspawn(char **argv)
71} 71}
72 72
73#if ENABLE_FEATURE_PREFER_APPLETS 73#if ENABLE_FEATURE_PREFER_APPLETS
74static jmp_buf die_jmp;
75static void jump(void)
76{
77 /* Special case. We arrive here if NOFORK applet
78 * calls xfunc, which then decides to die.
79 * We don't die, but jump instead back to caller.
80 * NOFORK applets still cannot carelessly call xfuncs:
81 * p = xmalloc(10);
82 * q = xmalloc(10); // BUG! if this dies, we leak p!
83 */
84 /* | 0x100 allows to pass zero exitcode (longjmp can't pass 0).
85 * This works because exitcodes are bytes,
86 * run_nofork_applet() ensures that by "& 0xff" */
87 longjmp(die_jmp, xfunc_error_retval | 0x100);
88}
89
74struct nofork_save_area { 90struct nofork_save_area {
75 jmp_buf die_jmp; 91 jmp_buf die_jmp;
92 void (*die_func)(void);
76 const char *applet_name; 93 const char *applet_name;
77 uint32_t option_mask32; 94 uint32_t option_mask32;
78 int die_sleep;
79 uint8_t xfunc_error_retval; 95 uint8_t xfunc_error_retval;
80}; 96};
81static void save_nofork_data(struct nofork_save_area *save) 97static void save_nofork_data(struct nofork_save_area *save)
82{ 98{
83 memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp)); 99 memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp));
100 save->die_func = die_func;
84 save->applet_name = applet_name; 101 save->applet_name = applet_name;
85 save->xfunc_error_retval = xfunc_error_retval;
86 save->option_mask32 = option_mask32; 102 save->option_mask32 = option_mask32;
87 save->die_sleep = die_sleep; 103 save->xfunc_error_retval = xfunc_error_retval;
88} 104}
89static void restore_nofork_data(struct nofork_save_area *save) 105static void restore_nofork_data(struct nofork_save_area *save)
90{ 106{
91 memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp)); 107 memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp));
108 die_func = save->die_func;
92 applet_name = save->applet_name; 109 applet_name = save->applet_name;
93 xfunc_error_retval = save->xfunc_error_retval;
94 option_mask32 = save->option_mask32; 110 option_mask32 = save->option_mask32;
95 die_sleep = save->die_sleep; 111 xfunc_error_retval = save->xfunc_error_retval;
96} 112}
97 113
98int FAST_FUNC run_nofork_applet(int applet_no, char **argv) 114int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
@@ -135,11 +151,8 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
135 while (argv[argc]) 151 while (argv[argc])
136 argc++; 152 argc++;
137 153
138 /* Special flag for xfunc_die(). If xfunc will "die" 154 /* If xfunc "dies" in NOFORK applet, die_func longjmp's here instead */
139 * in NOFORK applet, xfunc_die() sees negative 155 die_func = jump;
140 * die_sleep and longjmp here instead. */
141 die_sleep = -1;
142
143 rc = setjmp(die_jmp); 156 rc = setjmp(die_jmp);
144 if (!rc) { 157 if (!rc) {
145 /* Some callers (xargs) 158 /* Some callers (xargs)
@@ -148,10 +161,8 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
148 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0])); 161 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
149 /* Finally we can call NOFORK applet's main() */ 162 /* Finally we can call NOFORK applet's main() */
150 rc = applet_main[applet_no](argc, tmp_argv); 163 rc = applet_main[applet_no](argc, tmp_argv);
151 } else { /* xfunc died in NOFORK applet */ 164 } else {
152 /* in case they meant to return 0... */ 165 /* xfunc died in NOFORK applet */
153 if (rc == -2222)
154 rc = 0;
155 } 166 }
156 167
157 /* Restoring some globals */ 168 /* Restoring some globals */
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 442482a8b..0a4d8f128 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -14,13 +14,34 @@
14#include <sys/un.h> 14#include <sys/un.h>
15#include "libbb.h" 15#include "libbb.h"
16 16
17int FAST_FUNC setsockopt_int(int fd, int level, int optname, int optval)
18{
19 return setsockopt(fd, level, optname, &optval, sizeof(int));
20}
21int FAST_FUNC setsockopt_1(int fd, int level, int optname)
22{
23 return setsockopt_int(fd, level, optname, 1);
24}
25int FAST_FUNC setsockopt_SOL_SOCKET_int(int fd, int optname, int optval)
26{
27 return setsockopt_int(fd, SOL_SOCKET, optname, optval);
28}
29int FAST_FUNC setsockopt_SOL_SOCKET_1(int fd, int optname)
30{
31 return setsockopt_SOL_SOCKET_int(fd, optname, 1);
32}
33
17void FAST_FUNC setsockopt_reuseaddr(int fd) 34void FAST_FUNC setsockopt_reuseaddr(int fd)
18{ 35{
19 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1)); 36 setsockopt_SOL_SOCKET_1(fd, SO_REUSEADDR);
20} 37}
21int FAST_FUNC setsockopt_broadcast(int fd) 38int FAST_FUNC setsockopt_broadcast(int fd)
22{ 39{
23 return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1)); 40 return setsockopt_SOL_SOCKET_1(fd, SO_BROADCAST);
41}
42int FAST_FUNC setsockopt_keepalive(int fd)
43{
44 return setsockopt_SOL_SOCKET_1(fd, SO_KEEPALIVE);
24} 45}
25 46
26#ifdef SO_BINDTODEVICE 47#ifdef SO_BINDTODEVICE
diff --git a/libbb/xfunc_die.c b/libbb/xfunc_die.c
index 204e5e49d..73f7998e5 100644
--- a/libbb/xfunc_die.c
+++ b/libbb/xfunc_die.c
@@ -7,34 +7,16 @@
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 9
10/* Keeping it separate allows to NOT suck in stdio for VERY small applets. 10/* Keeping it separate allows to NOT pull in stdio for VERY small applets.
11 * Try building busybox with only "true" enabled... */ 11 * Try building busybox with only "true" enabled... */
12 12
13#include "libbb.h" 13#include "libbb.h"
14 14
15int die_sleep; 15void (*die_func)(void);
16#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH
17jmp_buf die_jmp;
18#endif
19 16
20void FAST_FUNC xfunc_die(void) 17void FAST_FUNC xfunc_die(void)
21{ 18{
22 if (die_sleep) { 19 if (die_func)
23 if ((ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH) 20 die_func();
24 && die_sleep < 0
25 ) {
26 /* Special case. We arrive here if NOFORK applet
27 * calls xfunc, which then decides to die.
28 * We don't die, but jump instead back to caller.
29 * NOFORK applets still cannot carelessly call xfuncs:
30 * p = xmalloc(10);
31 * q = xmalloc(10); // BUG! if this dies, we leak p!
32 */
33 /* -2222 means "zero" (longjmp can't pass 0)
34 * run_nofork_applet() catches -2222. */
35 longjmp(die_jmp, xfunc_error_retval ? xfunc_error_retval : -2222);
36 }
37 sleep(die_sleep);
38 }
39 exit(xfunc_error_retval); 21 exit(xfunc_error_retval);
40} 22}
diff --git a/libpwdgrp/pwd_grp.c b/libpwdgrp/pwd_grp.c
index 3886facf0..cefbc8a7e 100644
--- a/libpwdgrp/pwd_grp.c
+++ b/libpwdgrp/pwd_grp.c
@@ -16,11 +16,10 @@
16 * a) must contain the expected number of fields (as per count of field 16 * a) must contain the expected number of fields (as per count of field
17 * delimeters ":") or we will complain with a error message. 17 * delimeters ":") or we will complain with a error message.
18 * b) leading and trailing whitespace in fields is stripped. 18 * b) leading and trailing whitespace in fields is stripped.
19 * c) some fields are not allowed to be empty (e.g. username, uid/gid, 19 * c) some fields are not allowed to be empty (e.g. username, uid/gid),
20 * homedir, shell) and in this case NULL is returned and errno is 20 * and in this case NULL is returned and errno is set to EINVAL.
21 * set to EINVAL. This behaviour could be easily changed by 21 * This behaviour could be easily changed by modifying PW_DEF, GR_DEF,
22 * modifying PW_DEF, GR_DEF, SP_DEF strings (uppercase 22 * SP_DEF strings (uppercase makes a field mandatory).
23 * makes a field mandatory).
24 * d) the string representing uid/gid must be convertible by strtoXX 23 * d) the string representing uid/gid must be convertible by strtoXX
25 * functions, or errno is set to EINVAL. 24 * functions, or errno is set to EINVAL.
26 * e) leading and trailing whitespace in group member names is stripped. 25 * e) leading and trailing whitespace in group member names is stripped.
@@ -58,7 +57,7 @@ struct passdb {
58 * I = uid,gid, l = long maybe empty, m = members, 57 * I = uid,gid, l = long maybe empty, m = members,
59 * r = reserved 58 * r = reserved
60 */ 59 */
61#define PW_DEF "SsIIsSS" 60#define PW_DEF "SsIIsss"
62#define GR_DEF "SsIm" 61#define GR_DEF "SsIm"
63#define SP_DEF "Ssllllllr" 62#define SP_DEF "Ssllllllr"
64 63
@@ -70,8 +69,8 @@ static const struct const_passdb const_pw_db = {
70 offsetof(struct passwd, pw_uid), /* 2 I */ 69 offsetof(struct passwd, pw_uid), /* 2 I */
71 offsetof(struct passwd, pw_gid), /* 3 I */ 70 offsetof(struct passwd, pw_gid), /* 3 I */
72 offsetof(struct passwd, pw_gecos), /* 4 s */ 71 offsetof(struct passwd, pw_gecos), /* 4 s */
73 offsetof(struct passwd, pw_dir), /* 5 S */ 72 offsetof(struct passwd, pw_dir), /* 5 s */
74 offsetof(struct passwd, pw_shell) /* 6 S */ 73 offsetof(struct passwd, pw_shell) /* 6 s */
75 }, 74 },
76 sizeof(PW_DEF)-1, sizeof(struct passwd) 75 sizeof(PW_DEF)-1, sizeof(struct passwd)
77}; 76};
@@ -122,7 +121,7 @@ static struct statics *ptr_to_statics;
122#if ENABLE_FEATURE_CLEAN_UP 121#if ENABLE_FEATURE_CLEAN_UP
123static void free_static(void) 122static void free_static(void)
124{ 123{
125 free(S.db[0].malloced); 124 free(S.db[0].malloced);
126 free(S.db[1].malloced); 125 free(S.db[1].malloced);
127# if ENABLE_USE_BB_SHADOW 126# if ENABLE_USE_BB_SHADOW
128 free(S.db[2].malloced); 127 free(S.db[2].malloced);
diff --git a/loginutils/add-remove-shell.c b/loginutils/add-remove-shell.c
index e492b6e5a..9419ff5e7 100644
--- a/loginutils/add-remove-shell.c
+++ b/loginutils/add-remove-shell.c
@@ -100,7 +100,7 @@ int add_remove_shell_main(int argc UNUSED_PARAM, char **argv)
100 cpp++; 100 cpp++;
101 } 101 }
102 /* copy shell name from old to new file */ 102 /* copy shell name from old to new file */
103 printf("%s\n", line); 103 puts(line);
104 next_line: 104 next_line:
105 free(line); 105 free(line);
106 } 106 }
@@ -112,7 +112,7 @@ int add_remove_shell_main(int argc UNUSED_PARAM, char **argv)
112 char **cpp = argv; 112 char **cpp = argv;
113 while (*cpp) { 113 while (*cpp) {
114 if (*cpp != dont_add) 114 if (*cpp != dont_add)
115 printf("%s\n", *cpp); 115 puts(*cpp);
116 cpp++; 116 cpp++;
117 } 117 }
118 } 118 }
diff --git a/loginutils/adduser.c b/loginutils/adduser.c
index 568a3018e..605e3363f 100644
--- a/loginutils/adduser.c
+++ b/loginutils/adduser.c
@@ -20,6 +20,7 @@
20//usage: "\n -D Don't assign a password" 20//usage: "\n -D Don't assign a password"
21//usage: "\n -H Don't create home directory" 21//usage: "\n -H Don't create home directory"
22//usage: "\n -u UID User id" 22//usage: "\n -u UID User id"
23//usage: "\n -k SKEL Skeleton directory (/etc/skel)"
23 24
24#include "libbb.h" 25#include "libbb.h"
25 26
@@ -39,6 +40,7 @@
39#define OPT_SYSTEM_ACCOUNT (1 << 5) 40#define OPT_SYSTEM_ACCOUNT (1 << 5)
40#define OPT_DONT_MAKE_HOME (1 << 6) 41#define OPT_DONT_MAKE_HOME (1 << 6)
41#define OPT_UID (1 << 7) 42#define OPT_UID (1 << 7)
43#define OPT_SKEL (1 << 8)
42 44
43/* remix */ 45/* remix */
44/* recoded such that the uid may be passed in *p */ 46/* recoded such that the uid may be passed in *p */
@@ -134,6 +136,7 @@ static const char adduser_longopts[] ALIGN1 =
134 "system\0" No_argument "S" 136 "system\0" No_argument "S"
135 "no-create-home\0" No_argument "H" 137 "no-create-home\0" No_argument "H"
136 "uid\0" Required_argument "u" 138 "uid\0" Required_argument "u"
139 "skel\0" Required_argument "k"
137 ; 140 ;
138#endif 141#endif
139 142
@@ -150,6 +153,7 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
150 char *p; 153 char *p;
151 unsigned opts; 154 unsigned opts;
152 char *uid; 155 char *uid;
156 const char *skel = "/etc/skel";
153 157
154#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS 158#if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
155 applet_long_options = adduser_longopts; 159 applet_long_options = adduser_longopts;
@@ -168,7 +172,7 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
168 /* at least one and at most two non-option args */ 172 /* at least one and at most two non-option args */
169 /* disable interactive passwd for system accounts */ 173 /* disable interactive passwd for system accounts */
170 opt_complementary = "-1:?2:SD"; 174 opt_complementary = "-1:?2:SD";
171 opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid); 175 opts = getopt32(argv, "h:g:s:G:DSHu:k:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid, &skel);
172 if (opts & OPT_UID) 176 if (opts & OPT_UID)
173 pw.pw_uid = xatou_range(uid, 0, CONFIG_LAST_ID); 177 pw.pw_uid = xatou_range(uid, 0, CONFIG_LAST_ID);
174 178
@@ -250,8 +254,9 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
250 NULL 254 NULL
251 }; 255 };
252 /* Be silent on any errors (like: no /etc/skel) */ 256 /* Be silent on any errors (like: no /etc/skel) */
253 logmode = LOGMODE_NONE; 257 if (!(opts & OPT_SKEL))
254 copy_file("/etc/skel", pw.pw_dir, FILEUTILS_RECUR); 258 logmode = LOGMODE_NONE;
259 copy_file(skel, pw.pw_dir, FILEUTILS_RECUR);
255 logmode = LOGMODE_STDIO; 260 logmode = LOGMODE_STDIO;
256 chown_main(4, (char**)args); 261 chown_main(4, (char**)args);
257 } 262 }
diff --git a/loginutils/getty.c b/loginutils/getty.c
index 174542841..762d5c773 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -520,6 +520,11 @@ static void alarm_handler(int sig UNUSED_PARAM)
520 _exit(EXIT_SUCCESS); 520 _exit(EXIT_SUCCESS);
521} 521}
522 522
523static void sleep10(void)
524{
525 sleep(10);
526}
527
523int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 528int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
524int getty_main(int argc UNUSED_PARAM, char **argv) 529int getty_main(int argc UNUSED_PARAM, char **argv)
525{ 530{
@@ -599,7 +604,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
599 close(n--); 604 close(n--);
600 605
601 /* Logging. We want special flavor of error_msg_and_die */ 606 /* Logging. We want special flavor of error_msg_and_die */
602 die_sleep = 10; 607 die_func = sleep10;
603 msg_eol = "\r\n"; 608 msg_eol = "\r\n";
604 /* most likely will internally use fd #3 in CLOEXEC mode: */ 609 /* most likely will internally use fd #3 in CLOEXEC mode: */
605 openlog(applet_name, LOG_PID, LOG_AUTH); 610 openlog(applet_name, LOG_PID, LOG_AUTH);
diff --git a/loginutils/login.c b/loginutils/login.c
index b9d910331..1700cfcb5 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -489,7 +489,8 @@ int login_main(int argc UNUSED_PARAM, char **argv)
489 } 489 }
490#endif 490#endif
491 491
492 motd(); 492 if (access(".hushlogin", F_OK) != 0)
493 motd();
493 494
494 if (pw->pw_uid == 0) 495 if (pw->pw_uid == 0)
495 syslog(LOG_INFO, "root login%s", fromhost); 496 syslog(LOG_INFO, "root login%s", fromhost);
diff --git a/mailutils/mail.c b/mailutils/mail.c
index 199f64407..a7e43c0d1 100644
--- a/mailutils/mail.c
+++ b/mailutils/mail.c
@@ -154,7 +154,7 @@ void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol)
154 // encode the buffer we just read in 154 // encode the buffer we just read in
155 bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64); 155 bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64);
156 if (fname) { 156 if (fname) {
157 printf("%s\n", eol); 157 puts(eol);
158 } else { 158 } else {
159 src_buf += size; 159 src_buf += size;
160 len -= size; 160 len -= size;
diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c
index 9455b4e7a..4355e4dc5 100644
--- a/mailutils/sendmail.c
+++ b/mailutils/sendmail.c
@@ -375,7 +375,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
375 // N.B. we need to escape the leading dot regardless of 375 // N.B. we need to escape the leading dot regardless of
376 // whether it is single or not character on the line 376 // whether it is single or not character on the line
377 if ('.' == s[0] /*&& '\0' == s[1] */) 377 if ('.' == s[0] /*&& '\0' == s[1] */)
378 printf("."); 378 bb_putchar('.');
379 // dump read line 379 // dump read line
380 send_r_n(s); 380 send_r_n(s);
381 free(s); 381 free(s);
diff --git a/miscutils/devfsd.c b/miscutils/devfsd.c
index 5a6aec6bd..9256567cc 100644
--- a/miscutils/devfsd.c
+++ b/miscutils/devfsd.c
@@ -1142,19 +1142,19 @@ static void signal_handler(int sig)
1142 1142
1143static const char *get_variable(const char *variable, void *info) 1143static const char *get_variable(const char *variable, void *info)
1144{ 1144{
1145 static char sbuf[sizeof(int)*3 + 2]; /* sign and NUL */
1146 static char *hostname; 1145 static char *hostname;
1147 1146
1148 struct get_variable_info *gv_info = info; 1147 struct get_variable_info *gv_info = info;
1149 const char *field_names[] = { 1148 const char *field_names[] = {
1150 "hostname", "mntpt", "devpath", "devname", 1149 "hostname", "mntpt", "devpath", "devname", "uid", "gid", "mode",
1151 "uid", "gid", "mode", hostname, mount_point, 1150 NULL, mount_point, gv_info->devpath, gv_info->devname, NULL
1152 gv_info->devpath, gv_info->devname, NULL
1153 }; 1151 };
1154 int i; 1152 int i;
1155 1153
1156 if (!hostname) 1154 if (!hostname)
1157 hostname = safe_gethostname(); 1155 hostname = safe_gethostname();
1156 field_names[7] = hostname;
1157
1158 /* index_in_str_array returns i>=0 */ 1158 /* index_in_str_array returns i>=0 */
1159 i = index_in_str_array(field_names, variable); 1159 i = index_in_str_array(field_names, variable);
1160 1160
@@ -1164,12 +1164,11 @@ static const char *get_variable(const char *variable, void *info)
1164 return field_names[i + 7]; 1164 return field_names[i + 7];
1165 1165
1166 if (i == 4) 1166 if (i == 4)
1167 sprintf(sbuf, "%u", gv_info->info->uid); 1167 return auto_string(xasprintf("%u", gv_info->info->uid));
1168 else if (i == 5) 1168 if (i == 5)
1169 sprintf(sbuf, "%u", gv_info->info->gid); 1169 return auto_string(xasprintf("%u", gv_info->info->gid));
1170 else if (i == 6) 1170 /* i == 6 */
1171 sprintf(sbuf, "%o", gv_info->info->mode); 1171 return auto_string(xasprintf("%o", gv_info->info->mode));
1172 return sbuf;
1173} /* End Function get_variable */ 1172} /* End Function get_variable */
1174 1173
1175static void service(struct stat statbuf, char *path) 1174static void service(struct stat statbuf, char *path)
diff --git a/miscutils/hdparm.c b/miscutils/hdparm.c
index f0e9c9d75..9c486e7aa 100644
--- a/miscutils/hdparm.c
+++ b/miscutils/hdparm.c
@@ -763,9 +763,9 @@ static void identify(uint16_t *val)
763 ) { 763 ) {
764 like_std = 5; 764 like_std = 5;
765 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL)) 765 if ((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==STBY_ID_VAL))
766 printf("powers-up in standby; SET FEATURES subcmd spins-up.\n"); 766 puts("powers-up in standby; SET FEATURES subcmd spins-up.");
767 if (((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE)) 767 if (((val[CONFIG]==STBY_NID_VAL) || (val[CONFIG]==PWRD_NID_VAL)) && (val[GEN_CONFIG] & INCOMPLETE))
768 printf("\n\tWARNING: ID response incomplete.\n\tFollowing data may be incorrect.\n\n"); 768 puts("\n\tWARNING: ID response incomplete.\n\tFollowing data may be incorrect.\n");
769 } 769 }
770 770
771 /* output the model and serial numbers and the fw revision */ 771 /* output the model and serial numbers and the fw revision */
@@ -875,7 +875,7 @@ static void identify(uint16_t *val)
875 if (min_std == 0xffff) 875 if (min_std == 0xffff)
876 min_std = like_std > 4 ? like_std - 3 : 1; 876 min_std = like_std > 4 ? like_std - 3 : 1;
877 877
878 printf("Configuration:\n"); 878 puts("Configuration:");
879 /* more info from the general configuration word */ 879 /* more info from the general configuration word */
880 if ((eqpt != CDROM) && (like_std == 1)) { 880 if ((eqpt != CDROM) && (like_std == 1)) {
881 jj = val[GEN_CONFIG] >> 1; 881 jj = val[GEN_CONFIG] >> 1;
@@ -909,7 +909,7 @@ static void identify(uint16_t *val)
909 mm = 0; 909 mm = 0;
910 bbbig = 0; 910 bbbig = 0;
911 if ((ll > 0x00FBFC10) && (!val[LCYLS])) 911 if ((ll > 0x00FBFC10) && (!val[LCYLS]))
912 printf("\tCHS addressing not supported\n"); 912 puts("\tCHS addressing not supported");
913 else { 913 else {
914 jj = val[WHATS_VALID] & OK_W54_58; 914 jj = val[WHATS_VALID] & OK_W54_58;
915 printf("\tLogical\t\tmax\tcurrent\n" 915 printf("\tLogical\t\tmax\tcurrent\n"
@@ -980,7 +980,7 @@ static void identify(uint16_t *val)
980 !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "", 980 !(val[CAPAB_0] & IORDY_SUP) ? "(may be)" : "",
981 (val[CAPAB_0] & IORDY_OFF) ? "" :"not"); 981 (val[CAPAB_0] & IORDY_OFF) ? "" :"not");
982 } else 982 } else
983 printf("no IORDY\n"); 983 puts("no IORDY");
984 984
985 if ((like_std == 1) && val[BUF_TYPE]) { 985 if ((like_std == 1) && val[BUF_TYPE]) {
986 printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE], 986 printf("\tBuffer type: %04x: %s%s\n", val[BUF_TYPE],
@@ -1012,13 +1012,13 @@ static void identify(uint16_t *val)
1012 } 1012 }
1013 printf("\tR/W multiple sector transfer: "); 1013 printf("\tR/W multiple sector transfer: ");
1014 if ((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER)) 1014 if ((like_std < 3) && !(val[SECTOR_XFER_MAX] & SECTOR_XFER))
1015 printf("not supported\n"); 1015 puts("not supported");
1016 else { 1016 else {
1017 printf("Max = %u\tCurrent = ", val[SECTOR_XFER_MAX] & SECTOR_XFER); 1017 printf("Max = %u\tCurrent = ", val[SECTOR_XFER_MAX] & SECTOR_XFER);
1018 if (val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID) 1018 if (val[SECTOR_XFER_CUR] & MULTIPLE_SETTING_VALID)
1019 printf("%u\n", val[SECTOR_XFER_CUR] & SECTOR_XFER); 1019 printf("%u\n", val[SECTOR_XFER_CUR] & SECTOR_XFER);
1020 else 1020 else
1021 printf("?\n"); 1021 puts("?");
1022 } 1022 }
1023 if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) { 1023 if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) {
1024 /* We print out elsewhere whether the APM feature is enabled or 1024 /* We print out elsewhere whether the APM feature is enabled or
@@ -1040,7 +1040,7 @@ static void identify(uint16_t *val)
1040 } else { 1040 } else {
1041 /* ATAPI */ 1041 /* ATAPI */
1042 if (eqpt != CDROM && (val[CAPAB_0] & SWRST_REQ)) 1042 if (eqpt != CDROM && (val[CAPAB_0] & SWRST_REQ))
1043 printf("\tATA sw reset required\n"); 1043 puts("\tATA sw reset required");
1044 1044
1045 if (val[PKT_REL] || val[SVC_NBSY]) { 1045 if (val[PKT_REL] || val[SVC_NBSY]) {
1046 printf("\tOverlap support:"); 1046 printf("\tOverlap support:");
@@ -1056,7 +1056,7 @@ static void identify(uint16_t *val)
1056 /* DMA stuff. Check that only one DMA mode is selected. */ 1056 /* DMA stuff. Check that only one DMA mode is selected. */
1057 printf("\tDMA: "); 1057 printf("\tDMA: ");
1058 if (!(val[CAPAB_0] & DMA_SUP)) 1058 if (!(val[CAPAB_0] & DMA_SUP))
1059 printf("not supported\n"); 1059 puts("not supported");
1060 else { 1060 else {
1061 if (val[DMA_MODE] && !val[SINGLE_DMA] && !val[MULTI_DMA]) 1061 if (val[DMA_MODE] && !val[SINGLE_DMA] && !val[MULTI_DMA])
1062 printf(" sdma%u\n", (val[DMA_MODE] & MODE) >> 8); 1062 printf(" sdma%u\n", (val[DMA_MODE] & MODE) >> 8);
@@ -1079,7 +1079,7 @@ static void identify(uint16_t *val)
1079 bb_putchar('\n'); 1079 bb_putchar('\n');
1080 1080
1081 if ((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP)) 1081 if ((dev == ATAPI_DEV) && (eqpt != CDROM) && (val[CAPAB_0] & DMA_IL_SUP))
1082 printf("\t\tInterleaved DMA support\n"); 1082 puts("\t\tInterleaved DMA support");
1083 1083
1084 if ((val[WHATS_VALID] & OK_W64_70) 1084 if ((val[WHATS_VALID] & OK_W64_70)
1085 && (val[DMA_TIME_MIN] || val[DMA_TIME_NORM]) 1085 && (val[DMA_TIME_MIN] || val[DMA_TIME_NORM])
@@ -1121,8 +1121,8 @@ static void identify(uint16_t *val)
1121 } 1121 }
1122 1122
1123 if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) { 1123 if ((val[CMDS_SUPP_1] & VALID) == VALID_VAL) {
1124 printf("Commands/features:\n" 1124 puts("Commands/features:\n"
1125 "\tEnabled\tSupported:\n"); 1125 "\tEnabled\tSupported:");
1126 jj = val[CMDS_SUPP_0]; 1126 jj = val[CMDS_SUPP_0];
1127 kk = val[CMDS_EN_0]; 1127 kk = val[CMDS_EN_0];
1128 for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) { 1128 for (ii = 0; ii < NUM_CMD_FEAT_STR; ii++) {
@@ -1150,7 +1150,7 @@ static void identify(uint16_t *val)
1150 if ((eqpt != CDROM) && (like_std > 3) 1150 if ((eqpt != CDROM) && (like_std > 3)
1151 && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME]) 1151 && (val[SECU_STATUS] || val[ERASE_TIME] || val[ENH_ERASE_TIME])
1152 ) { 1152 ) {
1153 printf("Security:\n"); 1153 puts("Security:");
1154 if (val[PSWD_CODE] && (val[PSWD_CODE] != NOVAL_1)) 1154 if (val[PSWD_CODE] && (val[PSWD_CODE] != NOVAL_1))
1155 printf("\tMaster password revision code = %u\n", val[PSWD_CODE]); 1155 printf("\tMaster password revision code = %u\n", val[PSWD_CODE]);
1156 jj = val[SECU_STATUS]; 1156 jj = val[SECU_STATUS];
@@ -1366,7 +1366,7 @@ static NOINLINE void dump_identity(const struct hd_driveid *id)
1366 } 1366 }
1367 } 1367 }
1368#endif /* __NEW_HD_DRIVE_ID */ 1368#endif /* __NEW_HD_DRIVE_ID */
1369 printf("\n\n * current active mode\n\n"); 1369 puts("\n\n * current active mode\n");
1370} 1370}
1371#endif 1371#endif
1372 1372
@@ -1507,7 +1507,7 @@ static void bus_state_value(unsigned value)
1507 else if (value == BUSSTATE_OFF) 1507 else if (value == BUSSTATE_OFF)
1508 on_off(0); 1508 on_off(0);
1509 else if (value == BUSSTATE_TRISTATE) 1509 else if (value == BUSSTATE_TRISTATE)
1510 printf(" (tristate)\n"); 1510 puts(" (tristate)");
1511 else 1511 else
1512 printf(" (unknown: %u)\n", value); 1512 printf(" (unknown: %u)\n", value);
1513} 1513}
@@ -1531,7 +1531,7 @@ static void interpret_standby(uint8_t standby)
1531 printf("vendor-specific"); 1531 printf("vendor-specific");
1532 if (standby == 254) 1532 if (standby == 254)
1533 printf("reserved"); 1533 printf("reserved");
1534 printf(")\n"); 1534 puts(")");
1535} 1535}
1536 1536
1537static const uint8_t xfermode_val[] ALIGN1 = { 1537static const uint8_t xfermode_val[] ALIGN1 = {
@@ -1582,7 +1582,7 @@ static void interpret_xfermode(unsigned xfermode)
1582 printf("UltraDMA mode%u", xfermode - 64); 1582 printf("UltraDMA mode%u", xfermode - 64);
1583 else 1583 else
1584 printf("unknown"); 1584 printf("unknown");
1585 printf(")\n"); 1585 puts(")");
1586} 1586}
1587#endif /* HDIO_DRIVE_CMD */ 1587#endif /* HDIO_DRIVE_CMD */
1588 1588
@@ -1633,7 +1633,7 @@ static void process_dev(char *devname)
1633 if (noisy_piomode) { 1633 if (noisy_piomode) {
1634 printf(" attempting to "); 1634 printf(" attempting to ");
1635 if (piomode == 255) 1635 if (piomode == 255)
1636 printf("auto-tune PIO mode\n"); 1636 puts("auto-tune PIO mode");
1637 else if (piomode < 100) 1637 else if (piomode < 100)
1638 printf("set PIO mode to %d\n", piomode); 1638 printf("set PIO mode to %d\n", piomode);
1639 else if (piomode < 200) 1639 else if (piomode < 200)
@@ -1762,7 +1762,7 @@ static void process_dev(char *devname)
1762#ifndef WIN_STANDBYNOW2 1762#ifndef WIN_STANDBYNOW2
1763#define WIN_STANDBYNOW2 0x94 1763#define WIN_STANDBYNOW2 0x94
1764#endif 1764#endif
1765 printf(" issuing standby command\n"); 1765 puts(" issuing standby command");
1766 args[0] = WIN_STANDBYNOW1; 1766 args[0] = WIN_STANDBYNOW1;
1767 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2); 1767 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_STANDBYNOW2);
1768 } 1768 }
@@ -1773,13 +1773,13 @@ static void process_dev(char *devname)
1773#ifndef WIN_SLEEPNOW2 1773#ifndef WIN_SLEEPNOW2
1774#define WIN_SLEEPNOW2 0x99 1774#define WIN_SLEEPNOW2 0x99
1775#endif 1775#endif
1776 printf(" issuing sleep command\n"); 1776 puts(" issuing sleep command");
1777 args[0] = WIN_SLEEPNOW1; 1777 args[0] = WIN_SLEEPNOW1;
1778 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2); 1778 ioctl_alt_or_warn(HDIO_DRIVE_CMD, args, WIN_SLEEPNOW2);
1779 } 1779 }
1780 if (set_seagate) { 1780 if (set_seagate) {
1781 args[0] = 0xfb; 1781 args[0] = 0xfb;
1782 printf(" disabling Seagate auto powersaving mode\n"); 1782 puts(" disabling Seagate auto powersaving mode");
1783 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args); 1783 ioctl_or_warn(fd, HDIO_DRIVE_CMD, &args);
1784 } 1784 }
1785 if (getset_standby == IS_SET) { 1785 if (getset_standby == IS_SET) {
@@ -1815,17 +1815,17 @@ static void process_dev(char *devname)
1815 if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) { 1815 if (!ioctl_or_warn(fd, HDIO_GET_32BIT, &parm)) {
1816 printf(" IO_support\t=%3ld (", parm); 1816 printf(" IO_support\t=%3ld (", parm);
1817 if (parm == 0) 1817 if (parm == 0)
1818 printf("default 16-bit)\n"); 1818 puts("default 16-bit)");
1819 else if (parm == 2) 1819 else if (parm == 2)
1820 printf("16-bit)\n"); 1820 puts("16-bit)");
1821 else if (parm == 1) 1821 else if (parm == 1)
1822 printf("32-bit)\n"); 1822 puts("32-bit)");
1823 else if (parm == 3) 1823 else if (parm == 3)
1824 printf("32-bit w/sync)\n"); 1824 puts("32-bit w/sync)");
1825 else if (parm == 8) 1825 else if (parm == 8)
1826 printf("Request-Queue-Bypass)\n"); 1826 puts("Request-Queue-Bypass)");
1827 else 1827 else
1828 printf("\?\?\?)\n"); 1828 puts("\?\?\?)");
1829 } 1829 }
1830 } 1830 }
1831 if (getset_unmask) { 1831 if (getset_unmask) {
@@ -1837,7 +1837,7 @@ static void process_dev(char *devname)
1837 if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) { 1837 if (!ioctl_or_warn(fd, HDIO_GET_DMA, &parm)) {
1838 printf(fmt, "using_dma", parm); 1838 printf(fmt, "using_dma", parm);
1839 if (parm == 8) 1839 if (parm == 8)
1840 printf(" (DMA-Assisted-PIO)\n"); 1840 puts(" (DMA-Assisted-PIO)");
1841 else 1841 else
1842 on_off(parm != 0); 1842 on_off(parm != 0);
1843 } 1843 }
@@ -1921,7 +1921,7 @@ static void process_dev(char *devname)
1921 id.multsect_valid &= ~1; 1921 id.multsect_valid &= ~1;
1922 dump_identity(&id); 1922 dump_identity(&id);
1923 } else if (errno == -ENOMSG) 1923 } else if (errno == -ENOMSG)
1924 printf(" no identification info available\n"); 1924 puts(" no identification info available");
1925 else if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */ 1925 else if (ENABLE_IOCTL_HEX2STR_ERROR) /* To be coherent with ioctl_or_warn */
1926 bb_perror_msg("HDIO_GET_IDENTITY"); 1926 bb_perror_msg("HDIO_GET_IDENTITY");
1927 else 1927 else
diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c
index 38d90ff10..d77e6bacf 100644
--- a/miscutils/i2c_tools.c
+++ b/miscutils/i2c_tools.c
@@ -61,112 +61,14 @@
61 61
62#include "libbb.h" 62#include "libbb.h"
63 63
64/* 64#include <linux/i2c.h>
65 * /dev/i2c-X ioctl commands. The ioctl's parameter is always an unsigned long, 65#include <linux/i2c-dev.h>
66 * except for:
67 * - I2C_FUNCS, takes pointer to an unsigned long
68 * - I2C_RDWR, takes pointer to struct i2c_rdwr_ioctl_data
69 * - I2C_SMBUS, takes pointer to struct i2c_smbus_ioctl_data
70 */
71
72/*
73 * NOTE: Slave address is 7 or 10 bits, but 10-bit addresses
74 * are not supported due to code brokenness.
75 */
76 66
77/* Use this slave address. */ 67#define I2CDUMP_NUM_REGS 256
78#define I2C_SLAVE 0x0703
79/* Use this slave address, even if it is already in use by a driver. */
80#define I2C_SLAVE_FORCE 0x0706
81/* 0 for 7 bit addrs, != 0 for 10 bit. */
82#define I2C_TENBIT 0x0704
83/* Get the adapter functionality mask. */
84#define I2C_FUNCS 0x0705
85/* Combined R/W transfer (one STOP only). */
86#define I2C_RDWR 0x0707
87/* != 0 to use PEC with SMBus. */
88#define I2C_PEC 0x0708
89/* SMBus transfer. */
90#define I2C_SMBUS 0x0720
91
92/* Structure used in the I2C_SMBUS ioctl call. */
93struct i2c_smbus_ioctl_data {
94 uint8_t read_write;
95 uint8_t command;
96 uint32_t size;
97 union i2c_smbus_data *data;
98};
99
100/* Structure used in the I2C_RDWR ioctl call. */
101struct i2c_rdwr_ioctl_data {
102 struct i2c_msg *msgs; /* Pointers to i2c_msgs. */
103 uint32_t nmsgs; /* Number of i2c_msgs. */
104};
105
106/* As specified in SMBus standard. */
107#define I2C_SMBUS_BLOCK_MAX 32
108/* Not specified but we use same structure. */
109#define I2C_SMBUS_I2C_BLOCK_MAX 32
110
111/* Data for SMBus Messages. */
112union i2c_smbus_data {
113 uint8_t byte;
114 uint16_t word;
115 /* block[0] is used for length and one more for PEC */
116 uint8_t block[I2C_SMBUS_BLOCK_MAX + 2];
117};
118 68
119#define I2C_RDRW_IOCTL_MAX_MSGS 42 69#define I2CDETECT_MODE_AUTO 0
120#define I2C_MAX_REGS 256 70#define I2CDETECT_MODE_QUICK 1
121 71#define I2CDETECT_MODE_READ 2
122/* Smbus_access read or write markers. */
123#define I2C_SMBUS_READ 1
124#define I2C_SMBUS_WRITE 0
125
126/* SMBus transaction types (size parameter in the below functions). */
127#define I2C_SMBUS_QUICK 0
128#define I2C_SMBUS_BYTE 1
129#define I2C_SMBUS_BYTE_DATA 2
130#define I2C_SMBUS_WORD_DATA 3
131#define I2C_SMBUS_PROC_CALL 4
132#define I2C_SMBUS_BLOCK_DATA 5
133#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
134#define I2C_SMBUS_BLOCK_PROC_CALL 7
135#define I2C_SMBUS_I2C_BLOCK_DATA 8
136
137#define DETECT_MODE_AUTO 0
138#define DETECT_MODE_QUICK 1
139#define DETECT_MODE_READ 2
140
141/* Defines to determine what functionality is present. */
142#define I2C_FUNC_I2C 0x00000001
143#define I2C_FUNC_10BIT_ADDR 0x00000002
144#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004
145#define I2C_FUNC_SMBUS_PEC 0x00000008
146#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000
147#define I2C_FUNC_SMBUS_QUICK 0x00010000
148#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
149#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
150#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
151#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
152#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
153#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
154#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
155#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
156#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
157#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000
158#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000
159
160#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
161 I2C_FUNC_SMBUS_WRITE_BYTE)
162#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \
163 I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
164#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \
165 I2C_FUNC_SMBUS_WRITE_WORD_DATA)
166#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
167 I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
168#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
169 I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
170 72
171/* 73/*
172 * This is needed for ioctl_or_perror_and_die() since it only accepts pointers. 74 * This is needed for ioctl_or_perror_and_die() since it only accepts pointers.
@@ -456,7 +358,7 @@ static void check_read_funcs(int fd, int mode, int data_addr, int pec)
456 break; 358 break;
457#endif /* ENABLE_I2CDUMP */ 359#endif /* ENABLE_I2CDUMP */
458 default: 360 default:
459 bb_error_msg_and_die("Programmer goofed!"); 361 bb_error_msg_and_die("internal error");
460 } 362 }
461 check_funcs_test_end(funcs, pec, err); 363 check_funcs_test_end(funcs, pec, err);
462} 364}
@@ -799,7 +701,7 @@ int i2cset_main(int argc, char **argv)
799 } 701 }
800 702
801 if (status < 0) { 703 if (status < 0) {
802 printf("Warning - readback failed\n"); 704 puts("Warning - readback failed");
803 } else 705 } else
804 if (status != val) { 706 if (status != val) {
805 printf("Warning - data mismatch - wrote " 707 printf("Warning - data mismatch - wrote "
@@ -818,14 +720,14 @@ int i2cset_main(int argc, char **argv)
818#if ENABLE_I2CDUMP 720#if ENABLE_I2CDUMP
819static int read_block_data(int buf_fd, int mode, int *block) 721static int read_block_data(int buf_fd, int mode, int *block)
820{ 722{
821 uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2C_MAX_REGS]; 723 uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2CDUMP_NUM_REGS];
822 int res, blen = 0, tmp, i; 724 int res, blen = 0, tmp, i;
823 725
824 if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA) { 726 if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA) {
825 res = i2c_smbus_read_block_data(buf_fd, 0, cblock); 727 res = i2c_smbus_read_block_data(buf_fd, 0, cblock);
826 blen = res; 728 blen = res;
827 } else { 729 } else {
828 for (res = 0; res < I2C_MAX_REGS; res += tmp) { 730 for (res = 0; res < I2CDUMP_NUM_REGS; res += tmp) {
829 tmp = i2c_smbus_read_i2c_block_data( 731 tmp = i2c_smbus_read_i2c_block_data(
830 buf_fd, res, I2C_SMBUS_BLOCK_MAX, 732 buf_fd, res, I2C_SMBUS_BLOCK_MAX,
831 cblock + res); 733 cblock + res);
@@ -834,14 +736,14 @@ static int read_block_data(int buf_fd, int mode, int *block)
834 } 736 }
835 } 737 }
836 738
837 if (res >= I2C_MAX_REGS) 739 if (res >= I2CDUMP_NUM_REGS)
838 res = I2C_MAX_REGS; 740 res = I2CDUMP_NUM_REGS;
839 741
840 for (i = 0; i < res; i++) 742 for (i = 0; i < res; i++)
841 block[i] = cblock[i]; 743 block[i] = cblock[i];
842 744
843 if (mode != I2C_SMBUS_BLOCK_DATA) 745 if (mode != I2C_SMBUS_BLOCK_DATA)
844 for (i = res; i < I2C_MAX_REGS; i++) 746 for (i = res; i < I2CDUMP_NUM_REGS; i++)
845 block[i] = -1; 747 block[i] = -1;
846 } 748 }
847 749
@@ -854,10 +756,10 @@ static void dump_data(int bus_fd, int mode, unsigned first,
854{ 756{
855 int i, j, res; 757 int i, j, res;
856 758
857 printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f" 759 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"
858 " 0123456789abcdef\n"); 760 " 0123456789abcdef");
859 761
860 for (i = 0; i < I2C_MAX_REGS; i += 0x10) { 762 for (i = 0; i < I2CDUMP_NUM_REGS; i += 0x10) {
861 if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen) 763 if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen)
862 break; 764 break;
863 if (i/16 < first/16) 765 if (i/16 < first/16)
@@ -924,22 +826,22 @@ static void dump_data(int bus_fd, int mode, unsigned first,
924 break; 826 break;
925 /* Skip unwanted registers */ 827 /* Skip unwanted registers */
926 if (i+j < first || i+j > last) { 828 if (i+j < first || i+j > last) {
927 printf(" "); 829 bb_putchar(' ');
928 continue; 830 continue;
929 } 831 }
930 832
931 res = block[i+j]; 833 res = block[i+j];
932 if (res < 0) { 834 if (res < 0) {
933 printf("X"); 835 bb_putchar('X');
934 } else if (res == 0x00 || res == 0xff) { 836 } else if (res == 0x00 || res == 0xff) {
935 printf("."); 837 bb_putchar('.');
936 } else if (res < 32 || res >= 127) { 838 } else if (res < 32 || res >= 127) {
937 printf("?"); 839 bb_putchar('?');
938 } else { 840 } else {
939 printf("%c", res); 841 bb_putchar(res);
940 } 842 }
941 } 843 }
942 printf("\n"); 844 bb_putchar('\n');
943 } 845 }
944} 846}
945 847
@@ -948,7 +850,7 @@ static void dump_word_data(int bus_fd, unsigned first, unsigned last)
948 int i, j, rv; 850 int i, j, rv;
949 851
950 /* Word data. */ 852 /* Word data. */
951 printf(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f\n"); 853 puts(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f");
952 for (i = 0; i < 256; i += 8) { 854 for (i = 0; i < 256; i += 8) {
953 if (i/8 < first/8) 855 if (i/8 < first/8)
954 continue; 856 continue;
@@ -969,7 +871,7 @@ static void dump_word_data(int bus_fd, unsigned first, unsigned last)
969 else 871 else
970 printf("%04x ", rv & 0xffff); 872 printf("%04x ", rv & 0xffff);
971 } 873 }
972 printf("\n"); 874 bb_putchar('\n');
973 } 875 }
974} 876}
975 877
@@ -1120,33 +1022,33 @@ static const struct i2c_func i2c_funcs_tab[] = {
1120 { .value = I2C_FUNC_I2C, 1022 { .value = I2C_FUNC_I2C,
1121 .name = "I2C" }, 1023 .name = "I2C" },
1122 { .value = I2C_FUNC_SMBUS_QUICK, 1024 { .value = I2C_FUNC_SMBUS_QUICK,
1123 .name = "SMBus Quick Command" }, 1025 .name = "SMBus quick command" },
1124 { .value = I2C_FUNC_SMBUS_WRITE_BYTE, 1026 { .value = I2C_FUNC_SMBUS_WRITE_BYTE,
1125 .name = "SMBus Send Byte" }, 1027 .name = "SMBus send byte" },
1126 { .value = I2C_FUNC_SMBUS_READ_BYTE, 1028 { .value = I2C_FUNC_SMBUS_READ_BYTE,
1127 .name = "SMBus Receive Byte" }, 1029 .name = "SMBus receive byte" },
1128 { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA, 1030 { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
1129 .name = "SMBus Write Byte" }, 1031 .name = "SMBus write byte" },
1130 { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA, 1032 { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
1131 .name = "SMBus Read Byte" }, 1033 .name = "SMBus read byte" },
1132 { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA, 1034 { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
1133 .name = "SMBus Write Word" }, 1035 .name = "SMBus write word" },
1134 { .value = I2C_FUNC_SMBUS_READ_WORD_DATA, 1036 { .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
1135 .name = "SMBus Read Word" }, 1037 .name = "SMBus read word" },
1136 { .value = I2C_FUNC_SMBUS_PROC_CALL, 1038 { .value = I2C_FUNC_SMBUS_PROC_CALL,
1137 .name = "SMBus Process Call" }, 1039 .name = "SMBus process call" },
1138 { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA, 1040 { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
1139 .name = "SMBus Block Write" }, 1041 .name = "SMBus block write" },
1140 { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA, 1042 { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
1141 .name = "SMBus Block Read" }, 1043 .name = "SMBus block read" },
1142 { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL, 1044 { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
1143 .name = "SMBus Block Process Call" }, 1045 .name = "SMBus block process call" },
1144 { .value = I2C_FUNC_SMBUS_PEC, 1046 { .value = I2C_FUNC_SMBUS_PEC,
1145 .name = "SMBus PEC" }, 1047 .name = "SMBus PEC" },
1146 { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK, 1048 { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
1147 .name = "I2C Block Write" }, 1049 .name = "I2C block write" },
1148 { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK, 1050 { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
1149 .name = "I2C Block Read" }, 1051 .name = "I2C block read" },
1150 { .value = 0, .name = NULL } 1052 { .value = 0, .name = NULL }
1151}; 1053};
1152 1054
@@ -1298,7 +1200,7 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1298 opt_F = (1 << 4), opt_l = (1 << 5); 1200 opt_F = (1 << 4), opt_l = (1 << 5);
1299 const char *const optstr = "yaqrFl"; 1201 const char *const optstr = "yaqrFl";
1300 1202
1301 int fd, bus_num, i, j, mode = DETECT_MODE_AUTO, status; 1203 int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status;
1302 unsigned first = 0x03, last = 0x77, opts; 1204 unsigned first = 0x03, last = 0x77, opts;
1303 unsigned long funcs; 1205 unsigned long funcs;
1304 1206
@@ -1329,9 +1231,9 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1329 } 1231 }
1330 1232
1331 if (opts & opt_r) 1233 if (opts & opt_r)
1332 mode = DETECT_MODE_READ; 1234 mode = I2CDETECT_MODE_READ;
1333 else if (opts & opt_q) 1235 else if (opts & opt_q)
1334 mode = DETECT_MODE_QUICK; 1236 mode = I2CDETECT_MODE_QUICK;
1335 1237
1336 if (opts & opt_a) { 1238 if (opts & opt_a) {
1337 first = 0x00; 1239 first = 0x00;
@@ -1348,42 +1250,42 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1348 if (!(funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) { 1250 if (!(funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) {
1349 no_support("detection commands"); 1251 no_support("detection commands");
1350 } else 1252 } else
1351 if (mode == DETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) { 1253 if (mode == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
1352 no_support("SMBus Quick Write command"); 1254 no_support("SMBus quick write");
1353 } else 1255 } else
1354 if (mode == DETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) { 1256 if (mode == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
1355 no_support("SMBus Receive Byte command"); 1257 no_support("SMBus receive byte");
1356 } 1258 }
1357 1259
1358 if (mode == DETECT_MODE_AUTO) { 1260 if (mode == I2CDETECT_MODE_AUTO) {
1359 if (!(funcs & I2C_FUNC_SMBUS_QUICK)) 1261 if (!(funcs & I2C_FUNC_SMBUS_QUICK))
1360 will_skip("SMBus Quick Write"); 1262 will_skip("SMBus quick write");
1361 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) 1263 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
1362 will_skip("SMBus Receive Byte"); 1264 will_skip("SMBus receive byte");
1363 } 1265 }
1364 1266
1365 if (!(opts & opt_y)) 1267 if (!(opts & opt_y))
1366 confirm_action(-1, -1, -1, 0); 1268 confirm_action(-1, -1, -1, 0);
1367 1269
1368 printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 1270 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f");
1369 for (i = 0; i < 128; i += 16) { 1271 for (i = 0; i < 128; i += 16) {
1370 printf("%02x: ", i); 1272 printf("%02x: ", i);
1371 for(j = 0; j < 16; j++) { 1273 for(j = 0; j < 16; j++) {
1372 fflush_all(); 1274 fflush_all();
1373 1275
1374 if (mode == DETECT_MODE_AUTO) { 1276 if (mode == I2CDETECT_MODE_AUTO) {
1375 if ((i+j >= 0x30 && i+j <= 0x37) || 1277 if ((i+j >= 0x30 && i+j <= 0x37) ||
1376 (i+j >= 0x50 && i+j <= 0x5F)) 1278 (i+j >= 0x50 && i+j <= 0x5F))
1377 mode = DETECT_MODE_READ; 1279 mode = I2CDETECT_MODE_READ;
1378 else 1280 else
1379 mode = DETECT_MODE_QUICK; 1281 mode = I2CDETECT_MODE_QUICK;
1380 } 1282 }
1381 1283
1382 /* Skip unwanted addresses. */ 1284 /* Skip unwanted addresses. */
1383 if (i+j < first 1285 if (i+j < first
1384 || i+j > last 1286 || i+j > last
1385 || (mode == DETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) 1287 || (mode == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE))
1386 || (mode == DETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK))) 1288 || (mode == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)))
1387 { 1289 {
1388 printf(" "); 1290 printf(" ");
1389 continue; 1291 continue;
@@ -1401,14 +1303,14 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1401 } 1303 }
1402 1304
1403 switch (mode) { 1305 switch (mode) {
1404 case DETECT_MODE_READ: 1306 case I2CDETECT_MODE_READ:
1405 /* 1307 /*
1406 * This is known to lock SMBus on various 1308 * This is known to lock SMBus on various
1407 * write-only chips (mainly clock chips). 1309 * write-only chips (mainly clock chips).
1408 */ 1310 */
1409 status = i2c_smbus_read_byte(fd); 1311 status = i2c_smbus_read_byte(fd);
1410 break; 1312 break;
1411 default: /* DETECT_MODE_QUICK: */ 1313 default: /* I2CDETECT_MODE_QUICK: */
1412 /* 1314 /*
1413 * This is known to corrupt the Atmel 1315 * This is known to corrupt the Atmel
1414 * AT24RF08 EEPROM. 1316 * AT24RF08 EEPROM.
@@ -1423,7 +1325,7 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1423 else 1325 else
1424 printf("%02x ", i+j); 1326 printf("%02x ", i+j);
1425 } 1327 }
1426 printf("\n"); 1328 bb_putchar('\n');
1427 } 1329 }
1428 1330
1429 return 0; 1331 return 0;
diff --git a/miscutils/last.c b/miscutils/last.c
index 6d8b58463..f8f34371a 100644
--- a/miscutils/last.c
+++ b/miscutils/last.c
@@ -34,7 +34,8 @@
34 && ((UT_LINESIZE != 32) || (UT_NAMESIZE != 32) || (UT_HOSTSIZE != 256)) 34 && ((UT_LINESIZE != 32) || (UT_NAMESIZE != 32) || (UT_HOSTSIZE != 256))
35#error struct utmpx member char[] size(s) have changed! 35#error struct utmpx member char[] size(s) have changed!
36#elif defined __UT_LINESIZE \ 36#elif defined __UT_LINESIZE \
37 && ((__UT_LINESIZE != 32) || (__UT_NAMESIZE != 64) || (__UT_HOSTSIZE != 256)) 37 && ((__UT_LINESIZE != 32) || (__UT_NAMESIZE != 32) || (__UT_HOSTSIZE != 256))
38/* __UT_NAMESIZE was checked with 64 above, but glibc-2.11 definitely uses 32! */
38#error struct utmpx member char[] size(s) have changed! 39#error struct utmpx member char[] size(s) have changed!
39#endif 40#endif
40 41
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index 996de4074..314a7a1cb 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -348,6 +348,38 @@ static const char *humanly_readable_name(struct module_entry *m)
348 return m->probed_name ? m->probed_name : m->modname; 348 return m->probed_name ? m->probed_name : m->modname;
349} 349}
350 350
351/* Like strsep(&stringp, "\n\t ") but quoted text goes to single token
352 * even if it contains whitespace.
353 */
354static char *strsep_quotes(char **stringp)
355{
356 char *s, *start = *stringp;
357
358 if (!start)
359 return NULL;
360
361 for (s = start; ; s++) {
362 switch (*s) {
363 case '"':
364 s = strchrnul(s + 1, '"'); /* find trailing quote */
365 if (*s != '\0')
366 s++; /* skip trailing quote */
367 /* fall through */
368 case '\0':
369 case '\n':
370 case '\t':
371 case ' ':
372 if (*s != '\0') {
373 *s = '\0';
374 *stringp = s + 1;
375 } else {
376 *stringp = NULL;
377 }
378 return start;
379 }
380 }
381}
382
351static char *parse_and_add_kcmdline_module_options(char *options, const char *modulename) 383static char *parse_and_add_kcmdline_module_options(char *options, const char *modulename)
352{ 384{
353 char *kcmdline_buf; 385 char *kcmdline_buf;
@@ -359,7 +391,7 @@ static char *parse_and_add_kcmdline_module_options(char *options, const char *mo
359 return options; 391 return options;
360 392
361 kcmdline = kcmdline_buf; 393 kcmdline = kcmdline_buf;
362 while ((kptr = strsep(&kcmdline, "\n\t ")) != NULL) { 394 while ((kptr = strsep_quotes(&kcmdline)) != NULL) {
363 char *after_modulename = is_prefixed_with(kptr, modulename); 395 char *after_modulename = is_prefixed_with(kptr, modulename);
364 if (!after_modulename || *after_modulename != '.') 396 if (!after_modulename || *after_modulename != '.')
365 continue; 397 continue;
diff --git a/networking/Config.src b/networking/Config.src
index da36e8627..43ccbf385 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -533,6 +533,13 @@ config FEATURE_IP_ROUTE
533 help 533 help
534 Add support for routing table management to "ip". 534 Add support for routing table management to "ip".
535 535
536config FEATURE_IP_ROUTE_DIR
537 string "ip route configuration directory"
538 default "/etc/iproute2"
539 depends on FEATURE_IP_ROUTE
540 help
541 Location of the "ip" applet routing configuration.
542
536config FEATURE_IP_TUNNEL 543config FEATURE_IP_TUNNEL
537 bool "ip tunnel" 544 bool "ip tunnel"
538 default y 545 default y
@@ -947,48 +954,6 @@ config VCONFIG
947 help 954 help
948 Creates, removes, and configures VLAN interfaces 955 Creates, removes, and configures VLAN interfaces
949 956
950config WGET
951 bool "wget"
952 default y
953 help
954 wget is a utility for non-interactive download of files from HTTP
955 and FTP servers.
956
957config FEATURE_WGET_STATUSBAR
958 bool "Enable a nifty process meter (+2k)"
959 default y
960 depends on WGET
961 help
962 Enable the transfer progress bar for wget transfers.
963
964config FEATURE_WGET_AUTHENTICATION
965 bool "Enable HTTP authentication"
966 default y
967 depends on WGET
968 help
969 Support authenticated HTTP transfers.
970
971config FEATURE_WGET_LONG_OPTIONS
972 bool "Enable long options"
973 default y
974 depends on WGET && LONG_OPTS
975 help
976 Support long options for the wget applet.
977
978config FEATURE_WGET_TIMEOUT
979 bool "Enable timeout option -T SEC"
980 default y
981 depends on WGET
982 help
983 Supports network read and connect timeouts for wget,
984 so that wget will give up and timeout, through the -T
985 command line option.
986
987 Currently only connect and network data read timeout are
988 supported (i.e., timeout is not applied to the DNS query). When
989 FEATURE_WGET_LONG_OPTIONS is also enabled, the --timeout option
990 will work in addition to -T.
991
992config ZCIP 957config ZCIP
993 bool "zcip" 958 bool "zcip"
994 default y 959 default y
diff --git a/networking/Kbuild.src b/networking/Kbuild.src
index 944f27be1..79f54824b 100644
--- a/networking/Kbuild.src
+++ b/networking/Kbuild.src
@@ -41,7 +41,6 @@ lib-$(CONFIG_TFTPD) += tftp.o
41lib-$(CONFIG_TRACEROUTE) += traceroute.o 41lib-$(CONFIG_TRACEROUTE) += traceroute.o
42lib-$(CONFIG_TUNCTL) += tunctl.o 42lib-$(CONFIG_TUNCTL) += tunctl.o
43lib-$(CONFIG_VCONFIG) += vconfig.o 43lib-$(CONFIG_VCONFIG) += vconfig.o
44lib-$(CONFIG_WGET) += wget.o
45lib-$(CONFIG_ZCIP) += zcip.o 44lib-$(CONFIG_ZCIP) += zcip.o
46 45
47lib-$(CONFIG_TCPSVD) += tcpudp.o tcpudp_perhost.o 46lib-$(CONFIG_TCPSVD) += tcpudp.o tcpudp_perhost.o
diff --git a/networking/arping.c b/networking/arping.c
index dbfd75ef5..ef205e5e6 100644
--- a/networking/arping.c
+++ b/networking/arping.c
@@ -13,11 +13,11 @@
13//usage: "\n -f Quit on first ARP reply" 13//usage: "\n -f Quit on first ARP reply"
14//usage: "\n -q Quiet" 14//usage: "\n -q Quiet"
15//usage: "\n -b Keep broadcasting, don't go unicast" 15//usage: "\n -b Keep broadcasting, don't go unicast"
16//usage: "\n -D Duplicated address detection mode" 16//usage: "\n -D Exit with 1 if DST_IP replies"
17//usage: "\n -U Unsolicited ARP mode, update your neighbors" 17//usage: "\n -U Unsolicited ARP mode, update your neighbors"
18//usage: "\n -A ARP answer mode, update your neighbors" 18//usage: "\n -A ARP answer mode, update your neighbors"
19//usage: "\n -c N Stop after sending N ARP requests" 19//usage: "\n -c N Stop after sending N ARP requests"
20//usage: "\n -w TIMEOUT Time to wait for ARP reply, seconds" 20//usage: "\n -w TIMEOUT Seconds to wait for ARP reply"
21//usage: "\n -I IFACE Interface to use (default eth0)" 21//usage: "\n -I IFACE Interface to use (default eth0)"
22//usage: "\n -s SRC_IP Sender IP address" 22//usage: "\n -s SRC_IP Sender IP address"
23//usage: "\n DST_IP Target IP address" 23//usage: "\n DST_IP Target IP address"
@@ -162,7 +162,7 @@ static void catcher(void)
162 alarm(1); 162 alarm(1);
163} 163}
164 164
165static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) 165static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
166{ 166{
167 struct arphdr *ah = (struct arphdr *) buf; 167 struct arphdr *ah = (struct arphdr *) buf;
168 unsigned char *p = (unsigned char *) (ah + 1); 168 unsigned char *p = (unsigned char *) (ah + 1);
@@ -181,33 +181,33 @@ static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
181 if (FROM->sll_pkttype != PACKET_HOST 181 if (FROM->sll_pkttype != PACKET_HOST
182 && FROM->sll_pkttype != PACKET_BROADCAST 182 && FROM->sll_pkttype != PACKET_BROADCAST
183 && FROM->sll_pkttype != PACKET_MULTICAST) 183 && FROM->sll_pkttype != PACKET_MULTICAST)
184 return false; 184 return;
185 185
186 /* Only these types are recognized */ 186 /* Only these types are recognized */
187 if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY)) 187 if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY))
188 return false; 188 return;
189 189
190 /* ARPHRD check and this darned FDDI hack here :-( */ 190 /* ARPHRD check and this darned FDDI hack here :-( */
191 if (ah->ar_hrd != htons(FROM->sll_hatype) 191 if (ah->ar_hrd != htons(FROM->sll_hatype)
192 && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER))) 192 && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
193 return false; 193 return;
194 194
195 /* Protocol must be IP. */ 195 /* Protocol must be IP. */
196 if (ah->ar_pro != htons(ETH_P_IP) 196 if (ah->ar_pro != htons(ETH_P_IP)
197 || (ah->ar_pln != 4) 197 || (ah->ar_pln != 4)
198 || (ah->ar_hln != me.sll_halen) 198 || (ah->ar_hln != me.sll_halen)
199 || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))) 199 || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln))))
200 return false; 200 return;
201 201
202 move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln); 202 move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln);
203 move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln); 203 move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln);
204 204
205 if (dst.s_addr != src_ip.s_addr) 205 if (dst.s_addr != src_ip.s_addr)
206 return false; 206 return;
207 if (!(option_mask32 & DAD)) { 207 if (!(option_mask32 & DAD)) {
208 if ((src.s_addr != dst_ip.s_addr) 208 if ((src.s_addr != dst_ip.s_addr)
209 || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln))) 209 || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)))
210 return false; 210 return;
211 } else { 211 } else {
212 /* DAD packet was: 212 /* DAD packet was:
213 src_ip = 0 (or some src) 213 src_ip = 0 (or some src)
@@ -224,7 +224,7 @@ static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
224 */ 224 */
225 if ((memcmp(p, &me.sll_addr, me.sll_halen) == 0) 225 if ((memcmp(p, &me.sll_addr, me.sll_halen) == 0)
226 || (src.s_addr && src.s_addr != dst_ip.s_addr)) 226 || (src.s_addr && src.s_addr != dst_ip.s_addr))
227 return false; 227 return;
228 } 228 }
229 if (!(option_mask32 & QUIET)) { 229 if (!(option_mask32 & QUIET)) {
230 int s_printed = 0; 230 int s_printed = 0;
@@ -249,7 +249,7 @@ static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
249 unsigned diff = MONOTONIC_US() - last; 249 unsigned diff = MONOTONIC_US() - last;
250 printf(" %u.%03ums\n", diff / 1000, diff % 1000); 250 printf(" %u.%03ums\n", diff / 1000, diff % 1000);
251 } else { 251 } else {
252 printf(" UNSOLICITED?\n"); 252 puts(" UNSOLICITED?");
253 } 253 }
254 fflush_all(); 254 fflush_all();
255 } 255 }
@@ -264,7 +264,6 @@ static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
264 memcpy(he.sll_addr, p, me.sll_halen); 264 memcpy(he.sll_addr, p, me.sll_halen);
265 option_mask32 |= UNICASTING; 265 option_mask32 |= UNICASTING;
266 } 266 }
267 return true;
268} 267}
269 268
270int arping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 269int arping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -358,8 +357,8 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
358 saddr.sin_port = htons(1025); 357 saddr.sin_port = htons(1025);
359 saddr.sin_addr = dst; 358 saddr.sin_addr = dst;
360 359
361 if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)) == -1) 360 if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0)
362 bb_perror_msg("setsockopt(SO_DONTROUTE)"); 361 bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE");
363 xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 362 xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
364 getsockname(probe_fd, (struct sockaddr *) &saddr, &alen); 363 getsockname(probe_fd, (struct sockaddr *) &saddr, &alen);
365 //never happens: 364 //never happens:
diff --git a/networking/brctl.c b/networking/brctl.c
index 207b069aa..c01a86998 100644
--- a/networking/brctl.c
+++ b/networking/brctl.c
@@ -64,7 +64,57 @@
64#define BRCTL_USE_INTERNAL 1 64#define BRCTL_USE_INTERNAL 1
65 65
66#if ENABLE_FEATURE_BRCTL_FANCY 66#if ENABLE_FEATURE_BRCTL_FANCY
67# include <linux/if_bridge.h> 67/* #include <linux/if_bridge.h>
68 * breaks on musl: we already included netinet/in.h in libbb.h,
69 * if we include <linux/if_bridge.h> here, we get this:
70 * In file included from /usr/include/linux/if_bridge.h:18,
71 * from networking/brctl.c:67:
72 * /usr/include/linux/in6.h:32: error: redefinition of 'struct in6_addr'
73 * /usr/include/linux/in6.h:49: error: redefinition of 'struct sockaddr_in6'
74 * /usr/include/linux/in6.h:59: error: redefinition of 'struct ipv6_mreq'
75 */
76/* From <linux/if_bridge.h> */
77#define BRCTL_GET_VERSION 0
78#define BRCTL_GET_BRIDGES 1
79#define BRCTL_ADD_BRIDGE 2
80#define BRCTL_DEL_BRIDGE 3
81#define BRCTL_ADD_IF 4
82#define BRCTL_DEL_IF 5
83#define BRCTL_GET_BRIDGE_INFO 6
84#define BRCTL_GET_PORT_LIST 7
85#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8
86#define BRCTL_SET_BRIDGE_HELLO_TIME 9
87#define BRCTL_SET_BRIDGE_MAX_AGE 10
88#define BRCTL_SET_AGEING_TIME 11
89#define BRCTL_SET_GC_INTERVAL 12
90#define BRCTL_GET_PORT_INFO 13
91#define BRCTL_SET_BRIDGE_STP_STATE 14
92#define BRCTL_SET_BRIDGE_PRIORITY 15
93#define BRCTL_SET_PORT_PRIORITY 16
94#define BRCTL_SET_PATH_COST 17
95#define BRCTL_GET_FDB_ENTRIES 18
96struct __bridge_info {
97 uint64_t designated_root;
98 uint64_t bridge_id;
99 uint32_t root_path_cost;
100 uint32_t max_age;
101 uint32_t hello_time;
102 uint32_t forward_delay;
103 uint32_t bridge_max_age;
104 uint32_t bridge_hello_time;
105 uint32_t bridge_forward_delay;
106 uint8_t topology_change;
107 uint8_t topology_change_detected;
108 uint8_t root_port;
109 uint8_t stp_enabled;
110 uint32_t ageing_time;
111 uint32_t gc_interval;
112 uint32_t hello_timer_value;
113 uint32_t tcn_timer_value;
114 uint32_t topology_change_timer_value;
115 uint32_t gc_timer_value;
116};
117/* end <linux/if_bridge.h> */
68 118
69/* FIXME: These 4 funcs are not really clean and could be improved */ 119/* FIXME: These 4 funcs are not really clean and could be improved */
70static ALWAYS_INLINE void bb_strtotimeval(struct timeval *tv, 120static ALWAYS_INLINE void bb_strtotimeval(struct timeval *tv,
@@ -167,7 +217,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
167 arm_ioctl(args, BRCTL_GET_BRIDGES, 217 arm_ioctl(args, BRCTL_GET_BRIDGES,
168 (unsigned long) bridx, MAX_PORTS); 218 (unsigned long) bridx, MAX_PORTS);
169 num = xioctl(fd, SIOCGIFBR, args); 219 num = xioctl(fd, SIOCGIFBR, args);
170 printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n"); 220 puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces");
171 for (i = 0; i < num; i++) { 221 for (i = 0; i < num; i++) {
172 char ifname[IFNAMSIZ]; 222 char ifname[IFNAMSIZ];
173 int j, tabs; 223 int j, tabs;
@@ -186,7 +236,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv)
186 /* print bridge id */ 236 /* print bridge id */
187 x = (unsigned char *) &bi.bridge_id; 237 x = (unsigned char *) &bi.bridge_id;
188 for (j = 0; j < 8; j++) { 238 for (j = 0; j < 8; j++) {
189 printf("%.2x", x[j]); 239 printf("%02x", x[j]);
190 if (j == 1) 240 if (j == 1)
191 bb_putchar('.'); 241 bb_putchar('.');
192 } 242 }
diff --git a/networking/ftpd.c b/networking/ftpd.c
index 2351d6dd3..8345ae67c 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -377,7 +377,7 @@ ftpdataio_get_pasv_fd(void)
377 return remote_fd; 377 return remote_fd;
378 } 378 }
379 379
380 setsockopt(remote_fd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 380 setsockopt_keepalive(remote_fd);
381 return remote_fd; 381 return remote_fd;
382} 382}
383 383
@@ -1186,11 +1186,11 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
1186 , SIG_IGN); 1186 , SIG_IGN);
1187 1187
1188 /* Set up options on the command socket (do we need these all? why?) */ 1188 /* Set up options on the command socket (do we need these all? why?) */
1189 setsockopt(STDIN_FILENO, IPPROTO_TCP, TCP_NODELAY, &const_int_1, sizeof(const_int_1)); 1189 setsockopt_1(STDIN_FILENO, IPPROTO_TCP, TCP_NODELAY);
1190 setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 1190 setsockopt_keepalive(STDIN_FILENO);
1191 /* Telnet protocol over command link may send "urgent" data, 1191 /* Telnet protocol over command link may send "urgent" data,
1192 * we prefer it to be received in the "normal" data stream: */ 1192 * we prefer it to be received in the "normal" data stream: */
1193 setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &const_int_1, sizeof(const_int_1)); 1193 setsockopt_1(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE);
1194 1194
1195 WRITE_OK(FTP_GREET); 1195 WRITE_OK(FTP_GREET);
1196 signal(SIGALRM, timeout_handler); 1196 signal(SIGALRM, timeout_handler);
@@ -1223,11 +1223,26 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
1223#endif 1223#endif
1224 argv += optind; 1224 argv += optind;
1225 if (argv[0]) { 1225 if (argv[0]) {
1226 const char *basedir = argv[0];
1226#if !BB_MMU 1227#if !BB_MMU
1227 G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY); 1228 G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY);
1228 close_on_exec_on(G.root_fd); 1229 close_on_exec_on(G.root_fd);
1229#endif 1230#endif
1230 xchroot(argv[0]); 1231 if (chroot(basedir) == 0)
1232 basedir = "/";
1233#if !BB_MMU
1234 else {
1235 close(G.root_fd);
1236 G.root_fd = -1;
1237 }
1238#endif
1239 /*
1240 * If chroot failed, assume that we aren't root,
1241 * and at least chdir to the specified DIR
1242 * (older versions were dying with error message).
1243 * If chroot worked, move current dir to new "/":
1244 */
1245 xchdir(basedir);
1231 } 1246 }
1232 1247
1233#if ENABLE_FEATURE_FTP_AUTHENTICATION 1248#if ENABLE_FEATURE_FTP_AUTHENTICATION
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index 0670b2141..607e82713 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -62,9 +62,6 @@ struct globals {
62} FIX_ALIASING; 62} FIX_ALIASING;
63#define G (*(struct globals*)&bb_common_bufsiz1) 63#define G (*(struct globals*)&bb_common_bufsiz1)
64enum { BUFSZ = COMMON_BUFSIZE - offsetof(struct globals, buf) }; 64enum { BUFSZ = COMMON_BUFSIZE - offsetof(struct globals, buf) };
65struct BUG_G_too_big {
66 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
67};
68#define user (G.user ) 65#define user (G.user )
69#define password (G.password ) 66#define password (G.password )
70#define lsa (G.lsa ) 67#define lsa (G.lsa )
@@ -72,7 +69,9 @@ struct BUG_G_too_big {
72#define verbose_flag (G.verbose_flag ) 69#define verbose_flag (G.verbose_flag )
73#define do_continue (G.do_continue ) 70#define do_continue (G.do_continue )
74#define buf (G.buf ) 71#define buf (G.buf )
75#define INIT_G() do { } while (0) 72#define INIT_G() do { \
73 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
74} while (0)
76 75
77 76
78static void ftp_die(const char *msg) NORETURN; 77static void ftp_die(const char *msg) NORETURN;
diff --git a/networking/httpd.c b/networking/httpd.c
index 7a9065fcc..00169c36d 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -1222,12 +1222,12 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1222 out_cnt += count; 1222 out_cnt += count;
1223 count = 0; 1223 count = 0;
1224 /* "Status" header format is: "Status: 302 Redirected\r\n" */ 1224 /* "Status" header format is: "Status: 302 Redirected\r\n" */
1225 if (out_cnt >= 8 && memcmp(rbuf, "Status: ", 8) == 0) { 1225 if (out_cnt >= 7 && memcmp(rbuf, "Status:", 7) == 0) {
1226 /* send "HTTP/1.0 " */ 1226 /* send "HTTP/1.0 " */
1227 if (full_write(STDOUT_FILENO, HTTP_200, 9) != 9) 1227 if (full_write(STDOUT_FILENO, HTTP_200, 9) != 9)
1228 break; 1228 break;
1229 rbuf += 8; /* skip "Status: " */ 1229 rbuf += 7; /* skip "Status:" */
1230 count = out_cnt - 8; 1230 count = out_cnt - 7;
1231 out_cnt = -1; /* buffering off */ 1231 out_cnt = -1; /* buffering off */
1232 } else if (out_cnt >= 4) { 1232 } else if (out_cnt >= 4) {
1233 /* Did CGI add "HTTP"? */ 1233 /* Did CGI add "HTTP"? */
@@ -2352,7 +2352,7 @@ static void mini_httpd(int server_socket)
2352 continue; 2352 continue;
2353 2353
2354 /* set the KEEPALIVE option to cull dead connections */ 2354 /* set the KEEPALIVE option to cull dead connections */
2355 setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 2355 setsockopt_keepalive(n);
2356 2356
2357 if (fork() == 0) { 2357 if (fork() == 0) {
2358 /* child */ 2358 /* child */
@@ -2395,7 +2395,7 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv)
2395 continue; 2395 continue;
2396 2396
2397 /* set the KEEPALIVE option to cull dead connections */ 2397 /* set the KEEPALIVE option to cull dead connections */
2398 setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 2398 setsockopt_keepalive(n);
2399 2399
2400 if (vfork() == 0) { 2400 if (vfork() == 0) {
2401 /* child */ 2401 /* child */
diff --git a/networking/ifenslave.c b/networking/ifenslave.c
index c3be8180b..6b234adee 100644
--- a/networking/ifenslave.c
+++ b/networking/ifenslave.c
@@ -577,8 +577,8 @@ int ifenslave_main(int argc UNUSED_PARAM, char **argv)
577 /* Can't work with this slave, */ 577 /* Can't work with this slave, */
578 /* remember the error and skip it */ 578 /* remember the error and skip it */
579 bb_perror_msg( 579 bb_perror_msg(
580 "skipping %s: can't get flags", 580 "skipping %s: can't get %s",
581 slave_ifname); 581 slave_ifname, "flags");
582 res = rv; 582 res = rv;
583 continue; 583 continue;
584 } 584 }
@@ -595,8 +595,8 @@ int ifenslave_main(int argc UNUSED_PARAM, char **argv)
595 /* Can't work with this slave, */ 595 /* Can't work with this slave, */
596 /* remember the error and skip it */ 596 /* remember the error and skip it */
597 bb_perror_msg( 597 bb_perror_msg(
598 "skipping %s: can't get settings", 598 "skipping %s: can't get %s",
599 slave_ifname); 599 slave_ifname, "settings");
600 res = rv; 600 res = rv;
601 continue; 601 continue;
602 } 602 }
diff --git a/networking/ifplugd.c b/networking/ifplugd.c
index fef7a5ac9..f0defb5c8 100644
--- a/networking/ifplugd.c
+++ b/networking/ifplugd.c
@@ -38,7 +38,17 @@
38#include <linux/mii.h> 38#include <linux/mii.h>
39#include <linux/ethtool.h> 39#include <linux/ethtool.h>
40#ifdef HAVE_NET_ETHERNET_H 40#ifdef HAVE_NET_ETHERNET_H
41# include <net/ethernet.h> 41/* musl breakage:
42 * In file included from /usr/include/net/ethernet.h:10,
43 * from networking/ifplugd.c:41:
44 * /usr/include/netinet/if_ether.h:96: error: redefinition of 'struct ethhdr'
45 *
46 * Build succeeds without it on musl. Commented it out.
47 * If on your system you need it, consider removing <linux/ethtool.h>
48 * and copy-pasting its definitions here (<linux/ethtool.h> is what pulls in
49 * conflicting definition of struct ethhdr on musl).
50 */
51/* # include <net/ethernet.h> */
42#endif 52#endif
43#include <linux/netlink.h> 53#include <linux/netlink.h>
44#include <linux/rtnetlink.h> 54#include <linux/rtnetlink.h>
@@ -48,6 +58,10 @@
48#define __user 58#define __user
49#include <linux/wireless.h> 59#include <linux/wireless.h>
50 60
61#ifndef ETH_ALEN
62# define ETH_ALEN 6
63#endif
64
51/* 65/*
52From initial port to busybox, removed most of the redundancy by 66From initial port to busybox, removed most of the redundancy by
53converting implementation of a polymorphic interface to the strict 67converting implementation of a polymorphic interface to the strict
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 606fc049f..7c45e8927 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -395,7 +395,7 @@ static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec)
395 result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec); 395 result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec);
396 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); 396 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
397 /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */ 397 /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */
398 result += execute("[[ip route add ::/0 via %gateway%]][[ prio %metric%]]", ifd, exec); 398 result += execute("[[ip route add ::/0 via %gateway%]][[ metric %metric%]]", ifd, exec);
399# else 399# else
400 result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec); 400 result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec);
401 result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec); 401 result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec);
@@ -482,7 +482,7 @@ static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec)
482 result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] " 482 result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
483 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec); 483 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
484 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); 484 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
485 result += execute("[[ip route add default via %gateway% dev %iface%[[ prio %metric%]]]]", ifd, exec); 485 result += execute("[[ip route add default via %gateway% dev %iface%[[ metric %metric%]]]]", ifd, exec);
486 return ((result == 3) ? 3 : 0); 486 return ((result == 3) ? 3 : 0);
487# else 487# else
488 /* ifconfig said to set iface up before it processes hw %hwaddress%, 488 /* ifconfig said to set iface up before it processes hw %hwaddress%,
diff --git a/networking/interface.c b/networking/interface.c
index b0572d04e..24bd13c57 100644
--- a/networking/interface.c
+++ b/networking/interface.c
@@ -89,13 +89,9 @@ struct in6_ifreq {
89/* Display an Internet socket address. */ 89/* Display an Internet socket address. */
90static const char* FAST_FUNC INET_sprint(struct sockaddr *sap, int numeric) 90static const char* FAST_FUNC INET_sprint(struct sockaddr *sap, int numeric)
91{ 91{
92 static char *buff; /* defaults to NULL */
93
94 if (sap->sa_family == 0xFFFF || sap->sa_family == 0) 92 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
95 return "[NONE SET]"; 93 return "[NONE SET]";
96 free(buff); 94 return auto_string(INET_rresolve((struct sockaddr_in *) sap, numeric, 0xffffff00));
97 buff = INET_rresolve((struct sockaddr_in *) sap, numeric, 0xffffff00);
98 return buff;
99} 95}
100 96
101#ifdef UNUSED_AND_BUGGY 97#ifdef UNUSED_AND_BUGGY
@@ -171,13 +167,9 @@ static const struct aftype inet_aftype = {
171/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */ 167/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
172static const char* FAST_FUNC INET6_sprint(struct sockaddr *sap, int numeric) 168static const char* FAST_FUNC INET6_sprint(struct sockaddr *sap, int numeric)
173{ 169{
174 static char *buff;
175
176 if (sap->sa_family == 0xFFFF || sap->sa_family == 0) 170 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
177 return "[NONE SET]"; 171 return "[NONE SET]";
178 free(buff); 172 return auto_string(INET6_rresolve((struct sockaddr_in6 *) sap, numeric));
179 buff = INET6_rresolve((struct sockaddr_in6 *) sap, numeric);
180 return buff;
181} 173}
182 174
183#ifdef UNUSED 175#ifdef UNUSED
@@ -223,13 +215,11 @@ static const struct aftype inet6_aftype = {
223/* Display an UNSPEC address. */ 215/* Display an UNSPEC address. */
224static char* FAST_FUNC UNSPEC_print(unsigned char *ptr) 216static char* FAST_FUNC UNSPEC_print(unsigned char *ptr)
225{ 217{
226 static char *buff; 218 char *buff;
227
228 char *pos; 219 char *pos;
229 unsigned int i; 220 unsigned int i;
230 221
231 if (!buff) 222 buff = auto_string(xmalloc(sizeof(struct sockaddr) * 3 + 1));
232 buff = xmalloc(sizeof(struct sockaddr) * 3 + 1);
233 pos = buff; 223 pos = buff;
234 for (i = 0; i < sizeof(struct sockaddr); i++) { 224 for (i = 0; i < sizeof(struct sockaddr); i++) {
235 /* careful -- not every libc's sprintf returns # bytes written */ 225 /* careful -- not every libc's sprintf returns # bytes written */
@@ -712,14 +702,12 @@ static const struct hwtype loop_hwtype = {
712/* Display an Ethernet address in readable format. */ 702/* Display an Ethernet address in readable format. */
713static char* FAST_FUNC ether_print(unsigned char *ptr) 703static char* FAST_FUNC ether_print(unsigned char *ptr)
714{ 704{
715 static char *buff; 705 char *buff;
716
717 free(buff);
718 buff = xasprintf("%02X:%02X:%02X:%02X:%02X:%02X", 706 buff = xasprintf("%02X:%02X:%02X:%02X:%02X:%02X",
719 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377), 707 (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377),
720 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377) 708 (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377)
721 ); 709 );
722 return buff; 710 return auto_string(buff);
723} 711}
724 712
725static const struct hwtype ether_hwtype = { 713static const struct hwtype ether_hwtype = {
diff --git a/networking/isrv.c b/networking/isrv.c
index 1c6491edd..3673db715 100644
--- a/networking/isrv.c
+++ b/networking/isrv.c
@@ -194,7 +194,6 @@ static void handle_accept(isrv_state_t *state, int fd)
194 remove_peer(state, n); /* unsuccesful peer start */ 194 remove_peer(state, n); /* unsuccesful peer start */
195} 195}
196 196
197void BUG_sizeof_fd_set_is_strange(void);
198static void handle_fd_set(isrv_state_t *state, fd_set *fds, int (*h)(int, void **)) 197static void handle_fd_set(isrv_state_t *state, fd_set *fds, int (*h)(int, void **))
199{ 198{
200 enum { LONG_CNT = sizeof(fd_set) / sizeof(long) }; 199 enum { LONG_CNT = sizeof(fd_set) / sizeof(long) };
@@ -203,8 +202,7 @@ static void handle_fd_set(isrv_state_t *state, fd_set *fds, int (*h)(int, void *
203 /* need to know value at _the beginning_ of this routine */ 202 /* need to know value at _the beginning_ of this routine */
204 int fd_cnt = FD_COUNT; 203 int fd_cnt = FD_COUNT;
205 204
206 if (LONG_CNT * sizeof(long) != sizeof(fd_set)) 205 BUILD_BUG_ON(LONG_CNT * sizeof(long) != sizeof(fd_set));
207 BUG_sizeof_fd_set_is_strange();
208 206
209 fds_pos = 0; 207 fds_pos = 0;
210 while (1) { 208 while (1) {
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index a6d5129e7..8845cab91 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -137,12 +137,11 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n)
137 { 137 {
138 unsigned m_flag = 0; 138 unsigned m_flag = 0;
139 if (tb[IFLA_LINK]) { 139 if (tb[IFLA_LINK]) {
140 SPRINT_BUF(b1);
141 int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]); 140 int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]);
142 if (iflink == 0) 141 if (iflink == 0)
143 printf("@NONE: "); 142 printf("@NONE: ");
144 else { 143 else {
145 printf("@%s: ", ll_idx_n2a(iflink, b1)); 144 printf("@%s: ", ll_index_to_name(iflink));
146 m_flag = ll_index_to_flags(iflink); 145 m_flag = ll_index_to_flags(iflink);
147 m_flag = !(m_flag & IFF_UP); 146 m_flag = !(m_flag & IFF_UP);
148 } 147 }
@@ -158,8 +157,7 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n)
158 printf("qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC])); 157 printf("qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC]));
159#ifdef IFLA_MASTER 158#ifdef IFLA_MASTER
160 if (tb[IFLA_MASTER]) { 159 if (tb[IFLA_MASTER]) {
161 SPRINT_BUF(b1); 160 printf("master %s ", ll_index_to_name(*(int*)RTA_DATA(tb[IFLA_MASTER])));
162 printf("master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
163 } 161 }
164#endif 162#endif
165/* IFLA_OPERSTATE was added to kernel with the same commit as IFF_DORMANT */ 163/* IFLA_OPERSTATE was added to kernel with the same commit as IFF_DORMANT */
@@ -218,7 +216,6 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
218 int len = n->nlmsg_len; 216 int len = n->nlmsg_len;
219 struct rtattr * rta_tb[IFA_MAX+1]; 217 struct rtattr * rta_tb[IFA_MAX+1];
220 char abuf[256]; 218 char abuf[256];
221 SPRINT_BUF(b1);
222 219
223 if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR) 220 if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR)
224 return 0; 221 return 0;
@@ -250,7 +247,7 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
250 if (rta_tb[IFA_LABEL]) 247 if (rta_tb[IFA_LABEL])
251 label = RTA_DATA(rta_tb[IFA_LABEL]); 248 label = RTA_DATA(rta_tb[IFA_LABEL]);
252 else 249 else
253 label = ll_idx_n2a(ifa->ifa_index, b1); 250 label = ll_index_to_name(ifa->ifa_index);
254 if (fnmatch(G_filter.label, label, 0) != 0) 251 if (fnmatch(G_filter.label, label, 0) != 0)
255 return 0; 252 return 0;
256 } 253 }
@@ -325,7 +322,7 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
325 abuf, sizeof(abuf)) 322 abuf, sizeof(abuf))
326 ); 323 );
327 } 324 }
328 printf("scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1)); 325 printf("scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope));
329 if (ifa->ifa_flags & IFA_F_SECONDARY) { 326 if (ifa->ifa_flags & IFA_F_SECONDARY) {
330 ifa->ifa_flags &= ~IFA_F_SECONDARY; 327 ifa->ifa_flags &= ~IFA_F_SECONDARY;
331 printf("secondary "); 328 printf("secondary ");
@@ -556,12 +553,11 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
556 continue; 553 continue;
557 } 554 }
558 if (G_filter.label) { 555 if (G_filter.label) {
559 SPRINT_BUF(b1);
560 const char *label; 556 const char *label;
561 if (tb[IFA_LABEL]) 557 if (tb[IFA_LABEL])
562 label = RTA_DATA(tb[IFA_LABEL]); 558 label = RTA_DATA(tb[IFA_LABEL]);
563 else 559 else
564 label = ll_idx_n2a(ifa->ifa_index, b1); 560 label = ll_index_to_name(ifa->ifa_index);
565 if (fnmatch(G_filter.label, label, 0) != 0) 561 if (fnmatch(G_filter.label, label, 0) != 0)
566 continue; 562 continue;
567 } 563 }
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c
index 170c67b30..6ecd5f719 100644
--- a/networking/libiproute/iproute.c
+++ b/networking/libiproute/iproute.c
@@ -87,7 +87,6 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
87 inet_prefix dst; 87 inet_prefix dst;
88 inet_prefix src; 88 inet_prefix src;
89 int host_len = -1; 89 int host_len = -1;
90 SPRINT_BUF(b1);
91 90
92 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { 91 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
93 fprintf(stderr, "Not a route: %08x %08x %08x\n", 92 fprintf(stderr, "Not a route: %08x %08x %08x\n",
@@ -236,7 +235,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
236 printf("Deleted "); 235 printf("Deleted ");
237 } 236 }
238 if (r->rtm_type != RTN_UNICAST /* && !G_filter.type - always 0 */) { 237 if (r->rtm_type != RTN_UNICAST /* && !G_filter.type - always 0 */) {
239 printf("%s ", rtnl_rtntype_n2a(r->rtm_type, b1)); 238 printf("%s ", rtnl_rtntype_n2a(r->rtm_type));
240 } 239 }
241 240
242 if (tb[RTA_DST]) { 241 if (tb[RTA_DST]) {
diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c
index 8dbe6bd92..774a3e220 100644
--- a/networking/libiproute/iprule.c
+++ b/networking/libiproute/iprule.c
@@ -45,7 +45,6 @@ static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM,
45 int host_len = -1; 45 int host_len = -1;
46 struct rtattr * tb[RTA_MAX+1]; 46 struct rtattr * tb[RTA_MAX+1];
47 char abuf[256]; 47 char abuf[256];
48 SPRINT_BUF(b1);
49 48
50 if (n->nlmsg_type != RTM_NEWRULE) 49 if (n->nlmsg_type != RTM_NEWRULE)
51 return 0; 50 return 0;
@@ -110,7 +109,7 @@ static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM,
110 } 109 }
111 110
112 if (r->rtm_tos) { 111 if (r->rtm_tos) {
113 printf("tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1)); 112 printf("tos %s ", rtnl_dsfield_n2a(r->rtm_tos));
114 } 113 }
115 if (tb[RTA_PROTOINFO]) { 114 if (tb[RTA_PROTOINFO]) {
116 printf("fwmark %#x ", *(uint32_t*)RTA_DATA(tb[RTA_PROTOINFO])); 115 printf("fwmark %#x ", *(uint32_t*)RTA_DATA(tb[RTA_PROTOINFO]));
@@ -121,7 +120,7 @@ static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM,
121 } 120 }
122 121
123 if (r->rtm_table) 122 if (r->rtm_table)
124 printf("lookup %s ", rtnl_rttable_n2a(r->rtm_table, b1)); 123 printf("lookup %s ", rtnl_rttable_n2a(r->rtm_table));
125 124
126 if (tb[RTA_FLOW]) { 125 if (tb[RTA_FLOW]) {
127 uint32_t to = *(uint32_t*)RTA_DATA(tb[RTA_FLOW]); 126 uint32_t to = *(uint32_t*)RTA_DATA(tb[RTA_FLOW]);
@@ -129,10 +128,10 @@ static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM,
129 to &= 0xFFFF; 128 to &= 0xFFFF;
130 if (from) { 129 if (from) {
131 printf("realms %s/", 130 printf("realms %s/",
132 rtnl_rtrealm_n2a(from, b1)); 131 rtnl_rtrealm_n2a(from));
133 } 132 }
134 printf("%s ", 133 printf("%s ",
135 rtnl_rtrealm_n2a(to, b1)); 134 rtnl_rtrealm_n2a(to));
136 } 135 }
137 136
138 if (r->rtm_type == RTN_NAT) { 137 if (r->rtm_type == RTN_NAT) {
@@ -145,7 +144,7 @@ static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM,
145 } else 144 } else
146 printf("masquerade"); 145 printf("masquerade");
147 } else if (r->rtm_type != RTN_UNICAST) 146 } else if (r->rtm_type != RTN_UNICAST)
148 fputs(rtnl_rtntype_n2a(r->rtm_type, b1), stdout); 147 fputs(rtnl_rtntype_n2a(r->rtm_type), stdout);
149 148
150 bb_putchar('\n'); 149 bb_putchar('\n');
151 /*fflush_all();*/ 150 /*fflush_all();*/
diff --git a/networking/libiproute/iptunnel.c b/networking/libiproute/iptunnel.c
index b54c3c53f..a65d5e579 100644
--- a/networking/libiproute/iptunnel.c
+++ b/networking/libiproute/iptunnel.c
@@ -432,13 +432,12 @@ static void print_tunnel(struct ip_tunnel_parm *p)
432 else 432 else
433 printf(" ttl inherit "); 433 printf(" ttl inherit ");
434 if (p->iph.tos) { 434 if (p->iph.tos) {
435 SPRINT_BUF(b1);
436 printf(" tos"); 435 printf(" tos");
437 if (p->iph.tos & 1) 436 if (p->iph.tos & 1)
438 printf(" inherit"); 437 printf(" inherit");
439 if (p->iph.tos & ~1) 438 if (p->iph.tos & ~1)
440 printf("%c%s ", p->iph.tos & 1 ? '/' : ' ', 439 printf("%c%s ", p->iph.tos & 1 ? '/' : ' ',
441 rtnl_dsfield_n2a(p->iph.tos & ~1, b1)); 440 rtnl_dsfield_n2a(p->iph.tos & ~1));
442 } 441 }
443 if (!(p->iph.frag_off & htons(IP_DF))) 442 if (!(p->iph.frag_off & htons(IP_DF)))
444 printf(" nopmtudisc"); 443 printf(" nopmtudisc");
diff --git a/networking/libiproute/ll_map.c b/networking/libiproute/ll_map.c
index 27cd90f34..e2b85fc7b 100644
--- a/networking/libiproute/ll_map.c
+++ b/networking/libiproute/ll_map.c
@@ -86,7 +86,8 @@ int FAST_FUNC ll_remember_index(const struct sockaddr_nl *who UNUSED_PARAM,
86 return 0; 86 return 0;
87} 87}
88 88
89const char FAST_FUNC *ll_idx_n2a(int idx, char *buf) 89static
90const char FAST_FUNC *ll_idx_n2a(int idx/*, char *buf*/)
90{ 91{
91 struct idxmap *im; 92 struct idxmap *im;
92 93
@@ -95,16 +96,15 @@ const char FAST_FUNC *ll_idx_n2a(int idx, char *buf)
95 im = find_by_index(idx); 96 im = find_by_index(idx);
96 if (im) 97 if (im)
97 return im->name; 98 return im->name;
98 snprintf(buf, 16, "if%d", idx); 99 //snprintf(buf, 16, "if%d", idx);
99 return buf; 100 //return buf;
101 return auto_string(xasprintf("if%d", idx));
100} 102}
101 103
102
103const char FAST_FUNC *ll_index_to_name(int idx) 104const char FAST_FUNC *ll_index_to_name(int idx)
104{ 105{
105 static char nbuf[16]; 106 //static char nbuf[16];
106 107 return ll_idx_n2a(idx/*, nbuf*/);
107 return ll_idx_n2a(idx, nbuf);
108} 108}
109 109
110#ifdef UNUSED 110#ifdef UNUSED
diff --git a/networking/libiproute/ll_map.h b/networking/libiproute/ll_map.h
index c5d383422..7ea383c81 100644
--- a/networking/libiproute/ll_map.h
+++ b/networking/libiproute/ll_map.h
@@ -7,8 +7,8 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
7int ll_remember_index(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) FAST_FUNC; 7int ll_remember_index(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) FAST_FUNC;
8int ll_init_map(struct rtnl_handle *rth) FAST_FUNC; 8int ll_init_map(struct rtnl_handle *rth) FAST_FUNC;
9int xll_name_to_index(const char *name) FAST_FUNC; 9int xll_name_to_index(const char *name) FAST_FUNC;
10//static: const char *ll_idx_n2a(int idx, char *buf) FAST_FUNC;
10const char *ll_index_to_name(int idx) FAST_FUNC; 11const char *ll_index_to_name(int idx) FAST_FUNC;
11const char *ll_idx_n2a(int idx, char *buf) FAST_FUNC;
12/* int ll_index_to_type(int idx); */ 12/* int ll_index_to_type(int idx); */
13unsigned ll_index_to_flags(int idx) FAST_FUNC; 13unsigned ll_index_to_flags(int idx) FAST_FUNC;
14 14
diff --git a/networking/libiproute/rt_names.c b/networking/libiproute/rt_names.c
index c474ab903..51f2e9bdb 100644
--- a/networking/libiproute/rt_names.c
+++ b/networking/libiproute/rt_names.c
@@ -10,20 +10,32 @@
10#include "libbb.h" 10#include "libbb.h"
11#include "rt_names.h" 11#include "rt_names.h"
12 12
13#define CONFDIR CONFIG_FEATURE_IP_ROUTE_DIR
14
13typedef struct rtnl_tab_t { 15typedef struct rtnl_tab_t {
14 const char *cached_str; 16 const char *cached_str;
15 unsigned cached_result; 17 unsigned cached_result;
16 const char *tab[256]; 18 /* upstream version switched to a hash table and removed
19 * id < 256 limit. For now bbox bumps this array size from 256
20 * to 1024. If you plan to change this to a hash table,
21 * consider merging several hash tables we have (for example,
22 * awk has resizable one!
23 */
24#define RT_TABLE_MAX 1023
25 const char *tab[RT_TABLE_MAX+1];
17} rtnl_tab_t; 26} rtnl_tab_t;
18 27
19static void rtnl_tab_initialize(const char *file, const char **tab) 28static void rtnl_tab_initialize(const char *file, const char **tab)
20{ 29{
21 char *token[2]; 30 char *token[2];
22 parser_t *parser = config_open2(file, fopen_for_read); 31 char fullname[sizeof(CONFDIR"/rt_dsfield") + 8];
32 parser_t *parser;
23 33
34 sprintf(fullname, CONFDIR"/rt_%s", file);
35 parser = config_open2(fullname, fopen_for_read);
24 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) { 36 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
25 unsigned id = bb_strtou(token[0], NULL, 0); 37 unsigned id = bb_strtou(token[0], NULL, 0);
26 if (id > 256) { 38 if (id > RT_TABLE_MAX) {
27 bb_error_msg("database %s is corrupted at line %d", 39 bb_error_msg("database %s is corrupted at line %d",
28 file, parser->lineno); 40 file, parser->lineno);
29 break; 41 break;
@@ -42,7 +54,7 @@ static int rtnl_a2n(rtnl_tab_t *tab, uint32_t *id, const char *arg, int base)
42 return 0; 54 return 0;
43 } 55 }
44 56
45 for (i = 0; i < 256; i++) { 57 for (i = 0; i <= RT_TABLE_MAX; i++) {
46 if (tab->tab[i] 58 if (tab->tab[i]
47 && strcmp(tab->tab[i], arg) == 0 59 && strcmp(tab->tab[i], arg) == 0
48 ) { 60 ) {
@@ -54,7 +66,7 @@ static int rtnl_a2n(rtnl_tab_t *tab, uint32_t *id, const char *arg, int base)
54 } 66 }
55 67
56 i = bb_strtou(arg, NULL, base); 68 i = bb_strtou(arg, NULL, base);
57 if (i > 255) 69 if (i > RT_TABLE_MAX)
58 return -1; 70 return -1;
59 *id = i; 71 *id = i;
60 return 0; 72 return 0;
@@ -85,24 +97,23 @@ static void rtnl_rtprot_initialize(void)
85 return; 97 return;
86 rtnl_rtprot_tab = xzalloc(sizeof(*rtnl_rtprot_tab)); 98 rtnl_rtprot_tab = xzalloc(sizeof(*rtnl_rtprot_tab));
87 memcpy(rtnl_rtprot_tab->tab, init_tab, sizeof(init_tab)); 99 memcpy(rtnl_rtprot_tab->tab, init_tab, sizeof(init_tab));
88 rtnl_tab_initialize("/etc/iproute2/rt_protos", rtnl_rtprot_tab->tab); 100 rtnl_tab_initialize("protos", rtnl_rtprot_tab->tab);
89} 101}
90 102
91const char* FAST_FUNC rtnl_rtprot_n2a(int id, char *buf) 103#if 0 /* UNUSED */
104const char* FAST_FUNC rtnl_rtprot_n2a(int id)
92{ 105{
93 if (id < 0 || id >= 256) { 106 if (id < 0 || id > RT_TABLE_MAX) {
94 sprintf(buf, "%d", id); 107 return itoa(id);
95 return buf;
96 } 108 }
97 109
98 rtnl_rtprot_initialize(); 110 rtnl_rtprot_initialize();
99 111
100 if (rtnl_rtprot_tab->tab[id]) 112 if (rtnl_rtprot_tab->tab[id])
101 return rtnl_rtprot_tab->tab[id]; 113 return rtnl_rtprot_tab->tab[id];
102 /* buf is SPRINT_BSIZE big */ 114 return itoa(id);
103 sprintf(buf, "%d", id);
104 return buf;
105} 115}
116#endif
106 117
107int FAST_FUNC rtnl_rtprot_a2n(uint32_t *id, char *arg) 118int FAST_FUNC rtnl_rtprot_a2n(uint32_t *id, char *arg)
108{ 119{
@@ -123,23 +134,20 @@ static void rtnl_rtscope_initialize(void)
123 rtnl_rtscope_tab->tab[254] = "host"; 134 rtnl_rtscope_tab->tab[254] = "host";
124 rtnl_rtscope_tab->tab[253] = "link"; 135 rtnl_rtscope_tab->tab[253] = "link";
125 rtnl_rtscope_tab->tab[200] = "site"; 136 rtnl_rtscope_tab->tab[200] = "site";
126 rtnl_tab_initialize("/etc/iproute2/rt_scopes", rtnl_rtscope_tab->tab); 137 rtnl_tab_initialize("scopes", rtnl_rtscope_tab->tab);
127} 138}
128 139
129const char* FAST_FUNC rtnl_rtscope_n2a(int id, char *buf) 140const char* FAST_FUNC rtnl_rtscope_n2a(int id)
130{ 141{
131 if (id < 0 || id >= 256) { 142 if (id < 0 || id > RT_TABLE_MAX) {
132 sprintf(buf, "%d", id); 143 return itoa(id);
133 return buf;
134 } 144 }
135 145
136 rtnl_rtscope_initialize(); 146 rtnl_rtscope_initialize();
137 147
138 if (rtnl_rtscope_tab->tab[id]) 148 if (rtnl_rtscope_tab->tab[id])
139 return rtnl_rtscope_tab->tab[id]; 149 return rtnl_rtscope_tab->tab[id];
140 /* buf is SPRINT_BSIZE big */ 150 return itoa(id);
141 sprintf(buf, "%d", id);
142 return buf;
143} 151}
144 152
145int FAST_FUNC rtnl_rtscope_a2n(uint32_t *id, char *arg) 153int FAST_FUNC rtnl_rtscope_a2n(uint32_t *id, char *arg)
@@ -156,7 +164,7 @@ static void rtnl_rtrealm_initialize(void)
156 if (rtnl_rtrealm_tab) return; 164 if (rtnl_rtrealm_tab) return;
157 rtnl_rtrealm_tab = xzalloc(sizeof(*rtnl_rtrealm_tab)); 165 rtnl_rtrealm_tab = xzalloc(sizeof(*rtnl_rtrealm_tab));
158 rtnl_rtrealm_tab->tab[0] = "unknown"; 166 rtnl_rtrealm_tab->tab[0] = "unknown";
159 rtnl_tab_initialize("/etc/iproute2/rt_realms", rtnl_rtrealm_tab->tab); 167 rtnl_tab_initialize("realms", rtnl_rtrealm_tab->tab);
160} 168}
161 169
162int FAST_FUNC rtnl_rtrealm_a2n(uint32_t *id, char *arg) 170int FAST_FUNC rtnl_rtrealm_a2n(uint32_t *id, char *arg)
@@ -166,20 +174,17 @@ int FAST_FUNC rtnl_rtrealm_a2n(uint32_t *id, char *arg)
166} 174}
167 175
168#if ENABLE_FEATURE_IP_RULE 176#if ENABLE_FEATURE_IP_RULE
169const char* FAST_FUNC rtnl_rtrealm_n2a(int id, char *buf) 177const char* FAST_FUNC rtnl_rtrealm_n2a(int id)
170{ 178{
171 if (id < 0 || id >= 256) { 179 if (id < 0 || id > RT_TABLE_MAX) {
172 sprintf(buf, "%d", id); 180 return itoa(id);
173 return buf;
174 } 181 }
175 182
176 rtnl_rtrealm_initialize(); 183 rtnl_rtrealm_initialize();
177 184
178 if (rtnl_rtrealm_tab->tab[id]) 185 if (rtnl_rtrealm_tab->tab[id])
179 return rtnl_rtrealm_tab->tab[id]; 186 return rtnl_rtrealm_tab->tab[id];
180 /* buf is SPRINT_BSIZE big */ 187 return itoa(id);
181 sprintf(buf, "%d", id);
182 return buf;
183} 188}
184#endif 189#endif
185 190
@@ -191,23 +196,20 @@ static void rtnl_rtdsfield_initialize(void)
191 if (rtnl_rtdsfield_tab) return; 196 if (rtnl_rtdsfield_tab) return;
192 rtnl_rtdsfield_tab = xzalloc(sizeof(*rtnl_rtdsfield_tab)); 197 rtnl_rtdsfield_tab = xzalloc(sizeof(*rtnl_rtdsfield_tab));
193 rtnl_rtdsfield_tab->tab[0] = "0"; 198 rtnl_rtdsfield_tab->tab[0] = "0";
194 rtnl_tab_initialize("/etc/iproute2/rt_dsfield", rtnl_rtdsfield_tab->tab); 199 rtnl_tab_initialize("dsfield", rtnl_rtdsfield_tab->tab);
195} 200}
196 201
197const char* FAST_FUNC rtnl_dsfield_n2a(int id, char *buf) 202const char* FAST_FUNC rtnl_dsfield_n2a(int id)
198{ 203{
199 if (id < 0 || id >= 256) { 204 if (id < 0 || id > RT_TABLE_MAX) {
200 sprintf(buf, "%d", id); 205 return itoa(id);
201 return buf;
202 } 206 }
203 207
204 rtnl_rtdsfield_initialize(); 208 rtnl_rtdsfield_initialize();
205 209
206 if (rtnl_rtdsfield_tab->tab[id]) 210 if (rtnl_rtdsfield_tab->tab[id])
207 return rtnl_rtdsfield_tab->tab[id]; 211 return rtnl_rtdsfield_tab->tab[id];
208 /* buf is SPRINT_BSIZE big */ 212 return itoa(id);
209 sprintf(buf, "0x%02x", id);
210 return buf;
211} 213}
212 214
213int FAST_FUNC rtnl_dsfield_a2n(uint32_t *id, char *arg) 215int FAST_FUNC rtnl_dsfield_a2n(uint32_t *id, char *arg)
@@ -222,29 +224,28 @@ static rtnl_tab_t *rtnl_rttable_tab;
222 224
223static void rtnl_rttable_initialize(void) 225static void rtnl_rttable_initialize(void)
224{ 226{
225 if (rtnl_rtdsfield_tab) return; 227 if (rtnl_rttable_tab)
228 return;
229
226 rtnl_rttable_tab = xzalloc(sizeof(*rtnl_rttable_tab)); 230 rtnl_rttable_tab = xzalloc(sizeof(*rtnl_rttable_tab));
227 rtnl_rttable_tab->tab[0] = "unspec"; 231 rtnl_rttable_tab->tab[0] = "unspec";
228 rtnl_rttable_tab->tab[255] = "local"; 232 rtnl_rttable_tab->tab[255] = "local";
229 rtnl_rttable_tab->tab[254] = "main"; 233 rtnl_rttable_tab->tab[254] = "main";
230 rtnl_rttable_tab->tab[253] = "default"; 234 rtnl_rttable_tab->tab[253] = "default";
231 rtnl_tab_initialize("/etc/iproute2/rt_tables", rtnl_rttable_tab->tab); 235 rtnl_tab_initialize("tables", rtnl_rttable_tab->tab);
232} 236}
233 237
234const char* FAST_FUNC rtnl_rttable_n2a(int id, char *buf) 238const char* FAST_FUNC rtnl_rttable_n2a(int id)
235{ 239{
236 if (id < 0 || id >= 256) { 240 if (id < 0 || id > RT_TABLE_MAX) {
237 sprintf(buf, "%d", id); 241 return itoa(id);
238 return buf;
239 } 242 }
240 243
241 rtnl_rttable_initialize(); 244 rtnl_rttable_initialize();
242 245
243 if (rtnl_rttable_tab->tab[id]) 246 if (rtnl_rttable_tab->tab[id])
244 return rtnl_rttable_tab->tab[id]; 247 return rtnl_rttable_tab->tab[id];
245 /* buf is SPRINT_BSIZE big */ 248 return itoa(id);
246 sprintf(buf, "%d", id);
247 return buf;
248} 249}
249 250
250int FAST_FUNC rtnl_rttable_a2n(uint32_t *id, char *arg) 251int FAST_FUNC rtnl_rttable_a2n(uint32_t *id, char *arg)
diff --git a/networking/libiproute/rt_names.h b/networking/libiproute/rt_names.h
index e73aa851c..29932d6a4 100644
--- a/networking/libiproute/rt_names.h
+++ b/networking/libiproute/rt_names.h
@@ -4,12 +4,11 @@
4 4
5PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 5PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
6 6
7/* buf is SPRINT_BSIZE big */ 7extern const char* rtnl_rtprot_n2a(int id) FAST_FUNC;
8extern const char* rtnl_rtprot_n2a(int id, char *buf) FAST_FUNC; 8extern const char* rtnl_rtscope_n2a(int id) FAST_FUNC;
9extern const char* rtnl_rtscope_n2a(int id, char *buf) FAST_FUNC; 9extern const char* rtnl_rtrealm_n2a(int id) FAST_FUNC;
10extern const char* rtnl_rtrealm_n2a(int id, char *buf) FAST_FUNC; 10extern const char* rtnl_dsfield_n2a(int id) FAST_FUNC;
11extern const char* rtnl_dsfield_n2a(int id, char *buf) FAST_FUNC; 11extern const char* rtnl_rttable_n2a(int id) FAST_FUNC;
12extern const char* rtnl_rttable_n2a(int id, char *buf) FAST_FUNC;
13extern int rtnl_rtprot_a2n(uint32_t *id, char *arg) FAST_FUNC; 12extern int rtnl_rtprot_a2n(uint32_t *id, char *arg) FAST_FUNC;
14extern int rtnl_rtscope_a2n(uint32_t *id, char *arg) FAST_FUNC; 13extern int rtnl_rtscope_a2n(uint32_t *id, char *arg) FAST_FUNC;
15extern int rtnl_rtrealm_a2n(uint32_t *id, char *arg) FAST_FUNC; 14extern int rtnl_rtrealm_a2n(uint32_t *id, char *arg) FAST_FUNC;
diff --git a/networking/libiproute/rtm_map.c b/networking/libiproute/rtm_map.c
index 3bab53baf..c763da049 100644
--- a/networking/libiproute/rtm_map.c
+++ b/networking/libiproute/rtm_map.c
@@ -12,7 +12,7 @@
12#include "rt_names.h" 12#include "rt_names.h"
13#include "utils.h" 13#include "utils.h"
14 14
15const char* FAST_FUNC rtnl_rtntype_n2a(int id, char *buf) 15const char* FAST_FUNC rtnl_rtntype_n2a(int id)
16{ 16{
17 switch (id) { 17 switch (id) {
18 case RTN_UNSPEC: 18 case RTN_UNSPEC:
@@ -40,9 +40,7 @@ const char* FAST_FUNC rtnl_rtntype_n2a(int id, char *buf)
40 case RTN_XRESOLVE: 40 case RTN_XRESOLVE:
41 return "xresolve"; 41 return "xresolve";
42 default: 42 default:
43 /* buf is SPRINT_BSIZE big */ 43 return itoa(id);
44 sprintf(buf, "%d", id);
45 return buf;
46 } 44 }
47} 45}
48 46
diff --git a/networking/libiproute/rtm_map.h b/networking/libiproute/rtm_map.h
index 4377bd590..63b665169 100644
--- a/networking/libiproute/rtm_map.h
+++ b/networking/libiproute/rtm_map.h
@@ -4,7 +4,7 @@
4 4
5PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 5PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
6 6
7const char *rtnl_rtntype_n2a(int id, char *buf) FAST_FUNC; 7const char *rtnl_rtntype_n2a(int id) FAST_FUNC;
8int rtnl_rtntype_a2n(int *id, char *arg) FAST_FUNC; 8int rtnl_rtntype_a2n(int *id, char *arg) FAST_FUNC;
9 9
10int get_rt_realms(uint32_t *realms, char *arg) FAST_FUNC; 10int get_rt_realms(uint32_t *realms, char *arg) FAST_FUNC;
diff --git a/networking/nbd-client.c b/networking/nbd-client.c
index cadda5261..a601430b6 100644
--- a/networking/nbd-client.c
+++ b/networking/nbd-client.c
@@ -83,7 +83,7 @@ int nbdclient_main(int argc, char **argv)
83 83
84 // Find and connect to server 84 // Find and connect to server
85 sock = create_and_connect_stream_or_die(host, xatou16(port)); 85 sock = create_and_connect_stream_or_die(host, xatou16(port));
86 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &const_int_1, sizeof(const_int_1)); 86 setsockopt_1(sock, IPPROTO_TCP, TCP_NODELAY);
87 87
88 // Log on to the server 88 // Log on to the server
89 xread(sock, &nbd_header, 8+8+8+4 + 124); 89 xread(sock, &nbd_header, 8+8+8+4 + 124);
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index b28d05f51..471ae1a12 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -863,8 +863,8 @@ int nc_main(int argc UNUSED_PARAM, char **argv)
863 xbind(netfd, &ouraddr->u.sa, ouraddr->len); 863 xbind(netfd, &ouraddr->u.sa, ouraddr->len);
864 } 864 }
865#if 0 865#if 0
866 setsockopt(netfd, SOL_SOCKET, SO_RCVBUF, &o_rcvbuf, sizeof o_rcvbuf); 866 setsockopt_SOL_SOCKET_int(netfd, SO_RCVBUF, o_rcvbuf);
867 setsockopt(netfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf); 867 setsockopt_SOL_SOCKET_int(netfd, SO_SNDBUF, o_sndbuf);
868#endif 868#endif
869 869
870#ifdef BLOAT 870#ifdef BLOAT
diff --git a/networking/ntpd.c b/networking/ntpd.c
index b5120a70d..9732c9b1a 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -405,8 +405,6 @@ struct globals {
405}; 405};
406#define G (*ptr_to_globals) 406#define G (*ptr_to_globals)
407 407
408static const int const_IPTOS_LOWDELAY = IPTOS_LOWDELAY;
409
410 408
411#define VERB1 if (MAX_VERBOSE && G.verbose) 409#define VERB1 if (MAX_VERBOSE && G.verbose)
412#define VERB2 if (MAX_VERBOSE >= 2 && G.verbose >= 2) 410#define VERB2 if (MAX_VERBOSE >= 2 && G.verbose >= 2)
@@ -837,7 +835,7 @@ send_query_to_peer(peer_t *p)
837#if ENABLE_FEATURE_IPV6 835#if ENABLE_FEATURE_IPV6
838 if (family == AF_INET) 836 if (family == AF_INET)
839#endif 837#endif
840 setsockopt(fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY)); 838 setsockopt_int(fd, IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY);
841 free(local_lsa); 839 free(local_lsa);
842 } 840 }
843 841
@@ -2186,7 +2184,7 @@ static NOINLINE void ntp_init(char **argv)
2186 xfunc_die(); 2184 xfunc_die();
2187 } 2185 }
2188 socket_want_pktinfo(G_listen_fd); 2186 socket_want_pktinfo(G_listen_fd);
2189 setsockopt(G_listen_fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY)); 2187 setsockopt_int(G_listen_fd, IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY);
2190 } 2188 }
2191#endif 2189#endif
2192 if (!(opts & OPT_n)) { 2190 if (!(opts & OPT_n)) {
diff --git a/networking/ping.c b/networking/ping.c
index c475395e7..0eb1ae799 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -247,7 +247,7 @@ static void ping6(len_and_sockaddr *lsa)
247 pkt->icmp6_type = ICMP6_ECHO_REQUEST; 247 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
248 248
249 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); 249 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
250 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt)); 250 setsockopt_int(pingsock, SOL_RAW, IPV6_CHECKSUM, sockopt);
251 251
252 xsendto(pingsock, G.packet, DEFDATALEN + sizeof(struct icmp6_hdr), &lsa->u.sa, lsa->len); 252 xsendto(pingsock, G.packet, DEFDATALEN + sizeof(struct icmp6_hdr), &lsa->u.sa, lsa->len);
253 253
@@ -396,10 +396,8 @@ struct globals {
396#define dotted (G.dotted ) 396#define dotted (G.dotted )
397#define pingaddr (G.pingaddr ) 397#define pingaddr (G.pingaddr )
398#define rcvd_tbl (G.rcvd_tbl ) 398#define rcvd_tbl (G.rcvd_tbl )
399void BUG_ping_globals_too_big(void);
400#define INIT_G() do { \ 399#define INIT_G() do { \
401 if (sizeof(G) > COMMON_BUFSIZE) \ 400 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
402 BUG_ping_globals_too_big(); \
403 datalen = DEFDATALEN; \ 401 datalen = DEFDATALEN; \
404 timeout = MAXWAIT; \ 402 timeout = MAXWAIT; \
405 tmin = UINT_MAX; \ 403 tmin = UINT_MAX; \
@@ -700,12 +698,12 @@ static void ping4(len_and_sockaddr *lsa)
700 /* set recv buf (needed if we can get lots of responses: flood ping, 698 /* set recv buf (needed if we can get lots of responses: flood ping,
701 * broadcast ping etc) */ 699 * broadcast ping etc) */
702 sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */ 700 sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */
703 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); 701 setsockopt_SOL_SOCKET_int(pingsock, SO_RCVBUF, sockopt);
704 702
705 if (opt_ttl != 0) { 703 if (opt_ttl != 0) {
706 setsockopt(pingsock, IPPROTO_IP, IP_TTL, &opt_ttl, sizeof(opt_ttl)); 704 setsockopt_int(pingsock, IPPROTO_IP, IP_TTL, opt_ttl);
707 /* above doesnt affect packets sent to bcast IP, so... */ 705 /* above doesnt affect packets sent to bcast IP, so... */
708 setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, &opt_ttl, sizeof(opt_ttl)); 706 setsockopt_int(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, opt_ttl);
709 } 707 }
710 708
711 signal(SIGINT, print_stats_and_exit); 709 signal(SIGINT, print_stats_and_exit);
@@ -732,7 +730,6 @@ static void ping4(len_and_sockaddr *lsa)
732 } 730 }
733} 731}
734#if ENABLE_PING6 732#if ENABLE_PING6
735extern int BUG_bad_offsetof_icmp6_cksum(void);
736static void ping6(len_and_sockaddr *lsa) 733static void ping6(len_and_sockaddr *lsa)
737{ 734{
738 int sockopt; 735 int sockopt;
@@ -756,7 +753,7 @@ static void ping6(len_and_sockaddr *lsa)
756 } 753 }
757 if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 754 if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
758 sizeof(filt)) < 0) 755 sizeof(filt)) < 0)
759 bb_error_msg_and_die("setsockopt(ICMP6_FILTER)"); 756 bb_error_msg_and_die("setsockopt(%s)", "ICMP6_FILTER");
760 } 757 }
761#endif /*ICMP6_FILTER*/ 758#endif /*ICMP6_FILTER*/
762 759
@@ -766,15 +763,14 @@ static void ping6(len_and_sockaddr *lsa)
766 /* set recv buf (needed if we can get lots of responses: flood ping, 763 /* set recv buf (needed if we can get lots of responses: flood ping,
767 * broadcast ping etc) */ 764 * broadcast ping etc) */
768 sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */ 765 sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */
769 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); 766 setsockopt_SOL_SOCKET_int(pingsock, SO_RCVBUF, sockopt);
770 767
771 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); 768 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
772 if (offsetof(struct icmp6_hdr, icmp6_cksum) != 2) 769 BUILD_BUG_ON(offsetof(struct icmp6_hdr, icmp6_cksum) != 2);
773 BUG_bad_offsetof_icmp6_cksum(); 770 setsockopt_int(pingsock, SOL_RAW, IPV6_CHECKSUM, sockopt);
774 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt));
775 771
776 /* request ttl info to be returned in ancillary data */ 772 /* request ttl info to be returned in ancillary data */
777 setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, &const_int_1, sizeof(const_int_1)); 773 setsockopt_1(pingsock, SOL_IPV6, IPV6_HOPLIMIT);
778 774
779 if (if_index) 775 if (if_index)
780 pingaddr.sin6.sin6_scope_id = if_index; 776 pingaddr.sin6.sin6_scope_id = if_index;
diff --git a/networking/ssl_helper-wolfssl/00cfg-wolfssl-3.6.8 b/networking/ssl_helper-wolfssl/00cfg-wolfssl-3.6.8
new file mode 100755
index 000000000..50b6102d9
--- /dev/null
+++ b/networking/ssl_helper-wolfssl/00cfg-wolfssl-3.6.8
@@ -0,0 +1,22 @@
1#!/bin/sh
2
3# How to configure & build a static wolfssl-3.6.8 library
4# suitable for static build of ssl_helper.
5
6export CC="i686-gcc"
7export CFLAGS="\
8-Os \
9-static \
10-fomit-frame-pointer \
11-falign-functions=1 -falign-labels=1 -falign-loops=1 -falign-jumps=1 \
12-ffunction-sections -fdata-sections \
13"
14
15./configure \
16 --host=i686 \
17 --enable-static \
18 --enable-singlethreaded \
19 --disable-shared \
20|| exit $?
21
22make
diff --git a/networking/ssl_helper-wolfssl/README b/networking/ssl_helper-wolfssl/README
new file mode 100644
index 000000000..58a381c20
--- /dev/null
+++ b/networking/ssl_helper-wolfssl/README
@@ -0,0 +1,20 @@
1A small SSL helper for busybox wget.
2
3Precompiled static binary may be found in
4http://busybox.net/downloads/binaries/
5
6Build instructions:
7
8* Unpack wolfssl-3.6.8.zip
9* Build it:
10 ./configure --enable-static --disable-shared && make
11* Drop this directory into wolfssl-3.6.8/ssl_helper
12* Run ssl_helper.sh to compile and link the helper
13
14Usage: "ssl_helper -d FILE_DESCRIPTOR" where FILE_DESCRIPTOR is open to the peer.
15
16In bash, you can do it this way:
17$ ssl_helper -d3 3<>/dev/tcp/HOST/PORT
18
19Stdin will be SSL-encrypted and sent to FILE_DESCRIPTOR.
20Data from FILE_DESCRIPTOR will be decrypted and sent to stdout.
diff --git a/networking/ssl_helper-wolfssl/ssl_helper.c b/networking/ssl_helper-wolfssl/ssl_helper.c
new file mode 100644
index 000000000..38b7b56c6
--- /dev/null
+++ b/networking/ssl_helper-wolfssl/ssl_helper.c
@@ -0,0 +1,480 @@
1/*
2 * Adapted from:
3 *
4 * client.c
5 *
6 * Copyright (C) 2006-2015 wolfSSL Inc.
7 *
8 * This file is part of wolfSSL. (formerly known as CyaSSL)
9 *
10 * wolfSSL is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * wolfSSL is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24#include <stdlib.h>
25#include <unistd.h>
26#include <stdarg.h>
27#include <string.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <stdio.h>
31#include <time.h>
32#include <poll.h>
33#include <sys/socket.h>
34
35#include <wolfssl/wolfcrypt/types.h>
36#include <wolfssl/ssl.h>
37
38#if 0
39# define dbg(...) say(__VA_ARGS__)
40#else
41# define dbg(...) ((void)0)
42#endif
43
44static ssize_t safe_write(int fd, const void *buf, size_t count)
45{
46 ssize_t n;
47
48 do {
49 n = write(fd, buf, count);
50 } while (n < 0 && errno == EINTR);
51
52 return n;
53}
54
55static ssize_t full_write(int fd, const void *buf, size_t len)
56{
57 ssize_t cc;
58 ssize_t total;
59
60 total = 0;
61
62 while (len) {
63 cc = safe_write(fd, buf, len);
64
65 if (cc < 0) {
66 if (total) {
67 /* we already wrote some! */
68 /* user can do another write to know the error code */
69 return total;
70 }
71 return cc; /* write() returns -1 on failure. */
72 }
73
74 total += cc;
75 buf = ((const char *)buf) + cc;
76 len -= cc;
77 }
78
79 return total;
80}
81
82static void say(const char *s, ...)
83{
84 char buf[256];
85 va_list p;
86 int sz;
87
88 va_start(p, s);
89 sz = vsnprintf(buf, sizeof(buf), s, p);
90 full_write(STDERR_FILENO, buf, sz >= 0 && sz < sizeof(buf) ? sz : strlen(buf));
91 va_end(p);
92}
93
94static void die(const char *s, ...)
95{
96 char buf[256];
97 va_list p;
98 int sz;
99
100 va_start(p, s);
101 sz = vsnprintf(buf, sizeof(buf), s, p);
102 full_write(STDERR_FILENO, buf, sz >= 0 && sz < sizeof(buf) ? sz : strlen(buf));
103 exit(1);
104 va_end(p);
105}
106
107static void err_sys(const char *msg)
108{
109 die("%s\n", msg);
110}
111
112/* ==== */
113
114#if 0
115static void showPeer(WOLFSSL* ssl)
116{
117 WOLFSSL_CIPHER* cipher;
118 WOLFSSL_X509* peer = wolfSSL_get_peer_certificate(ssl);
119 if (peer)
120 ShowX509(peer, "peer's cert info:");
121 else
122 say("peer has no cert!\n");
123 say("SSL version is %s\n", wolfSSL_get_version(ssl));
124
125 cipher = wolfSSL_get_current_cipher(ssl);
126 say("SSL cipher suite is %s\n", wolfSSL_CIPHER_get_name(cipher));
127
128 {
129 WOLFSSL_X509_CHAIN* chain = wolfSSL_get_peer_chain(ssl);
130 int count = wolfSSL_get_chain_count(chain);
131 int i;
132
133 for (i = 0; i < count; i++) {
134 int length;
135 unsigned char buffer[3072];
136 WOLFSSL_X509* chainX509;
137
138 wolfSSL_get_chain_cert_pem(chain, i, buffer, sizeof(buffer), &length);
139 buffer[length] = 0;
140 say("cert %d has length %d data = \n%s\n", i, length, buffer);
141
142 chainX509 = wolfSSL_get_chain_X509(chain, i);
143 if (chainX509)
144 ShowX509(chainX509, "session cert info:");
145 else
146 say("get_chain_X509 failed\n");
147 wolfSSL_FreeX509(chainX509);
148 }
149 }
150}
151#endif
152
153WOLFSSL *prepare(int sockfd)
154{
155 WOLFSSL_METHOD* method;
156 WOLFSSL_CTX* ctx;
157 WOLFSSL* ssl;
158
159 wolfSSL_Init();
160
161 method = wolfTLSv1_1_client_method();
162 if (method == NULL)
163 err_sys("out of memory");
164 ctx = wolfSSL_CTX_new(method);
165 if (ctx == NULL)
166 err_sys("out of memory");
167// if (cipherList)
168// if (wolfSSL_CTX_set_cipher_list(ctx, cipherList) != SSL_SUCCESS)
169// err_sys("client can't set cipher list 1");
170
171// if (fewerPackets)
172// wolfSSL_CTX_set_group_messages(ctx);
173
174//#ifndef NO_DH
175// wolfSSL_CTX_SetMinDhKey_Sz(ctx, (word16)minDhKeyBits);
176//#endif
177
178// if (usePsk) {
179// wolfSSL_CTX_set_psk_client_callback(ctx, my_psk_client_cb);
180// if (cipherList == NULL) {
181// const char *defaultCipherList;
182//#if defined(HAVE_AESGCM) && !defined(NO_DH)
183// defaultCipherList = "DHE-PSK-AES128-GCM-SHA256";
184//#elif defined(HAVE_NULL_CIPHER)
185// defaultCipherList = "PSK-NULL-SHA256";
186//#else
187// defaultCipherList = "PSK-AES128-CBC-SHA256";
188//#endif
189// if (wolfSSL_CTX_set_cipher_list(ctx,defaultCipherList) != SSL_SUCCESS)
190// err_sys("client can't set cipher list 2");
191// }
192// useClientCert = 0;
193// }
194
195// if (useAnon) {
196// if (cipherList == NULL) {
197// wolfSSL_CTX_allow_anon_cipher(ctx);
198// if (wolfSSL_CTX_set_cipher_list(ctx,"ADH-AES128-SHA") != SSL_SUCCESS)
199// err_sys("client can't set cipher list 4");
200// }
201// useClientCert = 0;
202// }
203
204//#if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
205// wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
206//#endif
207
208// if (useOcsp) {
209// if (ocspUrl != NULL) {
210// wolfSSL_CTX_SetOCSP_OverrideURL(ctx, ocspUrl);
211// wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_NO_NONCE
212// | WOLFSSL_OCSP_URL_OVERRIDE);
213// }
214// else
215// wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_NO_NONCE);
216// }
217//
218//#ifdef USER_CA_CB
219// wolfSSL_CTX_SetCACb(ctx, CaCb);
220//#endif
221//
222//#ifdef VERIFY_CALLBACK
223// wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, myVerify);
224//#endif
225//#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
226// if (useClientCert) {
227// if (wolfSSL_CTX_use_certificate_chain_file(ctx, ourCert) != SSL_SUCCESS)
228// err_sys("can't load client cert file, check file and run from"
229// " wolfSSL home dir");
230// if (wolfSSL_CTX_use_PrivateKey_file(ctx, ourKey, SSL_FILETYPE_PEM) != SSL_SUCCESS)
231// err_sys("can't load client private key file, check file and run "
232// "from wolfSSL home dir");
233// }
234//
235// if (!usePsk && !useAnon) {
236// if (wolfSSL_CTX_load_verify_locations(ctx, verifyCert,0) != SSL_SUCCESS)
237// err_sys("can't load ca file, Please run from wolfSSL home dir");
238//#ifdef HAVE_ECC
239// /* load ecc verify too, echoserver uses it by default w/ ecc */
240// if (wolfSSL_CTX_load_verify_locations(ctx, eccCert, 0) != SSL_SUCCESS)
241// err_sys("can't load ecc ca file, Please run from wolfSSL home dir");
242//#endif
243// }
244//#endif /* !NO_FILESYSTEM && !NO_CERTS */
245
246//#if !defined(NO_CERTS)
247// if (!usePsk && !useAnon && doPeerCheck == 0)
248// wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
249// if (!usePsk && !useAnon && overrideDateErrors == 1)
250// wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, myDateCb);
251//#endif
252
253 wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
254
255//#ifdef HAVE_SNI
256// if (sniHostName)
257// if (wolfSSL_CTX_UseSNI(ctx, 0, sniHostName, XSTRLEN(sniHostName)) != SSL_SUCCESS)
258// err_sys("UseSNI failed");
259//#endif
260
261//#ifdef HAVE_MAX_FRAGMENT
262// if (maxFragment)
263// if (wolfSSL_CTX_UseMaxFragment(ctx, maxFragment) != SSL_SUCCESS)
264// err_sys("UseMaxFragment failed");
265//#endif
266//#ifdef HAVE_TRUNCATED_HMAC
267// if (truncatedHMAC)
268// if (wolfSSL_CTX_UseTruncatedHMAC(ctx) != SSL_SUCCESS)
269// err_sys("UseTruncatedHMAC failed");
270//#endif
271//#ifdef HAVE_SESSION_TICKET
272// if (wolfSSL_CTX_UseSessionTicket(ctx) != SSL_SUCCESS)
273// err_sys("UseSessionTicket failed");
274//#endif
275
276//#if defined(WOLFSSL_MDK_ARM)
277// wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
278//#endif
279
280 ssl = wolfSSL_new(ctx);
281 if (ssl == NULL)
282 err_sys("out of memory");
283
284//#ifdef HAVE_SESSION_TICKET
285// wolfSSL_set_SessionTicket_cb(ssl, sessionTicketCB, (void*)"initial session");
286//#endif
287
288// if (doDTLS) {
289// SOCKADDR_IN_T addr;
290// build_addr(&addr, host, port, 1);
291// wolfSSL_dtls_set_peer(ssl, &addr, sizeof(addr));
292// tcp_socket(&sockfd, 1);
293// } wlse {
294// tcp_connect(&sockfd, host, port, 0);
295// }
296
297//#ifdef HAVE_POLY1305
298// /* use old poly to connect with google server */
299// if (!XSTRNCMP(domain, "www.google.com", 14)) {
300// if (wolfSSL_use_old_poly(ssl, 1) != 0)
301// err_sys("unable to set to old poly");
302// }
303//#endif
304
305 wolfSSL_set_fd(ssl, sockfd);
306
307//#ifdef HAVE_CRL
308// if (disableCRL == 0) {
309// if (wolfSSL_EnableCRL(ssl, WOLFSSL_CRL_CHECKALL) != SSL_SUCCESS)
310// err_sys("can't enable crl check");
311// if (wolfSSL_LoadCRL(ssl, crlPemDir, SSL_FILETYPE_PEM, 0) != SSL_SUCCESS)
312// err_sys("can't load crl, check crlfile and date validity");
313// if (wolfSSL_SetCRL_Cb(ssl, CRL_CallBack) != SSL_SUCCESS)
314// err_sys("can't set crl callback");
315// }
316//#endif
317//#ifdef HAVE_SECURE_RENEGOTIATION
318// if (scr) {
319// if (wolfSSL_UseSecureRenegotiation(ssl) != SSL_SUCCESS)
320// err_sys("can't enable secure renegotiation");
321// }
322//#endif
323//#ifdef ATOMIC_USER
324// if (atomicUser)
325// SetupAtomicUser(ctx, ssl);
326//#endif
327//#ifdef HAVE_PK_CALLBACKS
328// if (pkCallbacks)
329// SetupPkCallbacks(ctx, ssl);
330//#endif
331// if (matchName && doPeerCheck)
332// wolfSSL_check_domain_name(ssl, domain);
333
334 if (wolfSSL_connect(ssl) != SSL_SUCCESS) {
335// /* see note at top of README */
336// int err = wolfSSL_get_error(ssl, 0);
337// char buffer[WOLFSSL_MAX_ERROR_SZ];
338// say("err = %d, %s\n", err,
339// wolfSSL_ERR_error_string(err, buffer));
340 err_sys("SSL_connect failed");
341 }
342// showPeer(ssl);
343
344//#ifdef HAVE_SECURE_RENEGOTIATION
345// if (scr && forceScr) {
346// if (wolfSSL_Rehandshake(ssl) != SSL_SUCCESS) {
347// int err = wolfSSL_get_error(ssl, 0);
348// char buffer[WOLFSSL_MAX_ERROR_SZ];
349// say("err = %d, %s\n", err,
350// wolfSSL_ERR_error_string(err, buffer));
351// err_sys("wolfSSL_Rehandshake failed");
352// }
353// }
354//#endif
355
356 return ssl;
357}
358
359static struct pollfd pfd[2] = {
360 { -1, POLLIN|POLLERR|POLLHUP, 0 },
361 { -1, POLLIN|POLLERR|POLLHUP, 0 },
362};
363#define STDIN pfd[0]
364#define NETWORK pfd[1]
365#define STDIN_READY() (pfd[0].revents & (POLLIN|POLLERR|POLLHUP))
366#define NETWORK_READY() (pfd[1].revents & (POLLIN|POLLERR|POLLHUP))
367
368static void wait_for_input(void)
369{
370 if (STDIN.fd == NETWORK.fd) /* means both are -1 */
371 exit(0);
372 dbg("polling\n");
373 STDIN.revents = NETWORK.revents = 0;
374 while (poll(pfd, 2, -1) < 0 && errno == EINTR)
375 continue;
376}
377
378static void do_io_until_eof_and_exit(WOLFSSL *ssl, int fd)
379{
380 int len;
381 char ibuf[4 * 1024];
382
383 NETWORK.fd = fd;
384 STDIN.fd = 0;
385
386 len = 0; /* only to suppress compiler warning */
387 for (;;) {
388 wait_for_input();
389
390 if (STDIN_READY()) {
391 dbg("reading stdin\n");
392 len = read(STDIN_FILENO, ibuf, sizeof(ibuf));
393 if (len < 0)
394 die("read error on stdin\n");
395 if (len == 0) {
396 dbg("read len = 0, stdin not polled anymore\n");
397 STDIN.fd = -1;
398 } else {
399 int n = wolfSSL_write(ssl, ibuf, len);
400 if (n != len)
401 die("SSL_write(%d) failed (returned %d)\n", len, n);
402 }
403 }
404
405 if (NETWORK_READY()) {
406 dbg("%s%s%s\n",
407 (pfd[1].revents & POLLIN) ? "POLLIN" : "",
408 (pfd[1].revents & POLLERR) ? "|POLLERR" : "",
409 (pfd[1].revents & POLLHUP) ? "|POLLHUP" : ""
410 );
411/* We are using blocking socket here.
412 * (Nonblocking socket would complicate writing to it).
413 * Therefore, SSL_read _can block_ here.
414 * This is not what wget expects (it wants to see short reads).
415 * Therefore, we use smallish buffer here, to approximate that.
416 */
417 len = wolfSSL_read(ssl, ibuf,
418 sizeof(ibuf) < 1024 ? sizeof(ibuf) : 1024
419 );
420 if (len < 0)
421 die("SSL_read error on network (%d)\n", len);
422 if (len > 0) {
423 int n;
424 n = full_write(STDOUT_FILENO, ibuf, len);
425 if (n != len)
426 die("write(%d) to stdout returned %d\n", len, n);
427 continue;
428 }
429/* Blocking reads are easier wtr EOF detection (no EAGAIN error to check for) */
430 dbg("read len = 0, network not polled anymore\n");
431 NETWORK.fd = -1;
432 /* saw EOF on network, and we processed
433 * and wrote out all ssl data. Signal it:
434 */
435 close(STDOUT_FILENO);
436 }
437 }
438}
439
440int main(int argc, char **argv)
441{
442 WOLFSSL *ssl;
443 int fd;
444 char *fd_str;
445
446 if (!argv[1])
447 die("Syntax error\n");
448 if (argv[1][0] != '-')
449 die("Syntax error\n");
450 if (argv[1][1] != 'd')
451 die("Syntax error\n");
452 fd_str = argv[1] + 2;
453 if (!fd_str[0])
454 fd_str = argv[2];
455 if (!fd_str || fd_str[0] < '0' || fd_str[0] > '9')
456 die("Syntax error\n");
457
458 fd = atoi(fd_str);
459 if (fd < 3)
460 die("Syntax error\n");
461
462 ssl = prepare(fd);
463 do_io_until_eof_and_exit(ssl, fd);
464 /* does not return */
465
466// if (doDTLS == 0) { /* don't send alert after "break" command */
467// ret = wolfSSL_shutdown(ssl);
468// if (wc_shutdown && ret == SSL_SHUTDOWN_NOT_DONE)
469// wolfSSL_shutdown(ssl); /* bidirectional shutdown */
470// }
471//#ifdef ATOMIC_USER
472// if (atomicUser)
473// FreeAtomicUser(ssl);
474//#endif
475// wolfSSL_free(ssl);
476// CloseSocket(sockfd);
477// wolfSSL_CTX_free(ctx);
478
479 return 0;
480}
diff --git a/networking/ssl_helper-wolfssl/ssl_helper.sh b/networking/ssl_helper-wolfssl/ssl_helper.sh
new file mode 100755
index 000000000..184ffe67e
--- /dev/null
+++ b/networking/ssl_helper-wolfssl/ssl_helper.sh
@@ -0,0 +1,12 @@
1#!/bin/sh
2
3# I use this to build static uclibc based binary using Aboriginal Linux toolchain:
4PREFIX="i686-"
5STATIC="-static"
6# Standard build:
7#PREFIX=""
8#STATIC=""
9
10${PREFIX}gcc -Os -Wall -I.. -c ssl_helper.c -o ssl_helper.o
11${PREFIX}gcc $STATIC --start-group ssl_helper.o -lm ../src/.libs/libwolfssl.a --end-group -o ssl_helper
12${PREFIX}-strip ssl_helper
diff --git a/networking/tc.c b/networking/tc.c
index 76e2e8359..6d1fef993 100644
--- a/networking/tc.c
+++ b/networking/tc.c
@@ -64,15 +64,14 @@ struct globals {
64 uint32_t filter_proto; 64 uint32_t filter_proto;
65} FIX_ALIASING; 65} FIX_ALIASING;
66#define G (*(struct globals*)&bb_common_bufsiz1) 66#define G (*(struct globals*)&bb_common_bufsiz1)
67struct BUG_G_too_big {
68 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
69};
70#define filter_ifindex (G.filter_ifindex) 67#define filter_ifindex (G.filter_ifindex)
71#define filter_qdisc (G.filter_qdisc) 68#define filter_qdisc (G.filter_qdisc)
72#define filter_parent (G.filter_parent) 69#define filter_parent (G.filter_parent)
73#define filter_prio (G.filter_prio) 70#define filter_prio (G.filter_prio)
74#define filter_proto (G.filter_proto) 71#define filter_proto (G.filter_proto)
75#define INIT_G() do { } while (0) 72#define INIT_G() do { \
73 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
74} while (0)
76 75
77/* Allocates a buffer containing the name of a class id. 76/* Allocates a buffer containing the name of a class id.
78 * The caller must free the returned memory. */ 77 * The caller must free the returned memory. */
diff --git a/networking/telnet.c b/networking/telnet.c
index a25579773..3bb6fb1ba 100644
--- a/networking/telnet.c
+++ b/networking/telnet.c
@@ -623,7 +623,7 @@ int telnet_main(int argc UNUSED_PARAM, char **argv)
623 623
624 xmove_fd(create_and_connect_stream_or_die(host, port), netfd); 624 xmove_fd(create_and_connect_stream_or_die(host, port), netfd);
625 625
626 setsockopt(netfd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 626 setsockopt_keepalive(netfd);
627 627
628 signal(SIGINT, record_signo); 628 signal(SIGINT, record_signo);
629 629
diff --git a/networking/telnetd.c b/networking/telnetd.c
index 6aee95871..25d05fe7a 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -265,7 +265,7 @@ make_new_session(
265 close_on_exec_on(fd); 265 close_on_exec_on(fd);
266 266
267 /* SO_KEEPALIVE by popular demand */ 267 /* SO_KEEPALIVE by popular demand */
268 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 268 setsockopt_keepalive(sock);
269#if ENABLE_FEATURE_TELNETD_STANDALONE 269#if ENABLE_FEATURE_TELNETD_STANDALONE
270 ts->sockfd_read = sock; 270 ts->sockfd_read = sock;
271 ndelay_on(sock); 271 ndelay_on(sock);
diff --git a/networking/tftp.c b/networking/tftp.c
index 8ecd7bb6f..ad9308e52 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -129,10 +129,9 @@ struct globals {
129#endif 129#endif
130} FIX_ALIASING; 130} FIX_ALIASING;
131#define G (*(struct globals*)&bb_common_bufsiz1) 131#define G (*(struct globals*)&bb_common_bufsiz1)
132struct BUG_G_too_big { 132#define INIT_G() do { \
133 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; 133 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
134}; 134} while (0)
135#define INIT_G() do { } while (0)
136 135
137#define G_error_pkt_reason (G.error_pkt[3]) 136#define G_error_pkt_reason (G.error_pkt[3])
138#define G_error_pkt_str ((char*)(G.error_pkt + 4)) 137#define G_error_pkt_str ((char*)(G.error_pkt + 4))
diff --git a/networking/traceroute.c b/networking/traceroute.c
index 12ba614e8..642110c54 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -211,60 +211,62 @@
211 */ 211 */
212 212
213//usage:#define traceroute_trivial_usage 213//usage:#define traceroute_trivial_usage
214//usage: "[-"IF_TRACEROUTE6("46")"FIldnrv] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]\n" 214//usage: "[-"IF_TRACEROUTE6("46")"FIlnrv] [-f 1ST_TTL] [-m MAXTTL] [-q PROBES] [-p PORT]\n"
215//usage: " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE]\n" 215//usage: " [-t TOS] [-w WAIT_SEC]"
216//usage: IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(" [-g GATEWAY]")" [-s SRC_IP] [-i IFACE]\n"
216//usage: " [-z PAUSE_MSEC] HOST [BYTES]" 217//usage: " [-z PAUSE_MSEC] HOST [BYTES]"
217//usage:#define traceroute_full_usage "\n\n" 218//usage:#define traceroute_full_usage "\n\n"
218//usage: "Trace the route to HOST\n" 219//usage: "Trace the route to HOST\n"
219//usage: IF_TRACEROUTE6( 220//usage: IF_TRACEROUTE6(
220//usage: "\n -4,-6 Force IP or IPv6 name resolution" 221//usage: "\n -4,-6 Force IP or IPv6 name resolution"
221//usage: ) 222//usage: )
222//usage: "\n -F Set the don't fragment bit" 223//usage: "\n -F Set don't fragment bit"
224//usage: IF_FEATURE_TRACEROUTE_USE_ICMP(
223//usage: "\n -I Use ICMP ECHO instead of UDP datagrams" 225//usage: "\n -I Use ICMP ECHO instead of UDP datagrams"
224//usage: "\n -l Display the TTL value of the returned packet" 226//usage: )
225//usage: "\n -d Set SO_DEBUG options to socket" 227//usage: "\n -l Display TTL value of the returned packet"
228//Currently disabled (TRACEROUTE_SO_DEBUG==0)
229////usage: "\n -d Set SO_DEBUG options to socket"
226//usage: "\n -n Print numeric addresses" 230//usage: "\n -n Print numeric addresses"
227//usage: "\n -r Bypass routing tables, send directly to HOST" 231//usage: "\n -r Bypass routing tables, send directly to HOST"
232//usage: IF_FEATURE_TRACEROUTE_VERBOSE(
228//usage: "\n -v Verbose" 233//usage: "\n -v Verbose"
229//usage: "\n -m Max time-to-live (max number of hops)" 234//usage: )
230//usage: "\n -p Base UDP port number used in probes" 235//usage: "\n -f N First number of hops (default 1)"
236//usage: "\n -m N Max number of hops"
237//usage: "\n -q N Number of probes per hop (default 3)"
238//usage: "\n -p N Base UDP port number used in probes"
231//usage: "\n (default 33434)" 239//usage: "\n (default 33434)"
232//usage: "\n -q Number of probes per TTL (default 3)" 240//usage: "\n -s IP Source address"
233//usage: "\n -s IP address to use as the source address" 241//usage: "\n -i IFACE Source interface"
234//usage: "\n -t Type-of-service in probe packets (default 0)" 242//usage: "\n -t N Type-of-service in probe packets (default 0)"
235//usage: "\n -w Time in seconds to wait for a response (default 3)" 243//usage: "\n -w SEC Time to wait for a response (default 3)"
236//usage: "\n -g Loose source route gateway (8 max)" 244//usage: "\n -g IP Loose source route gateway (8 max)"
237//usage: 245//usage:
238//usage:#define traceroute6_trivial_usage 246//usage:#define traceroute6_trivial_usage
239//usage: "[-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES]\n" 247//usage: "[-nrv] [-m MAXTTL] [-q PROBES] [-p PORT]\n"
240//usage: " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-i IFACE]\n" 248//usage: " [-t TOS] [-w WAIT_SEC] [-s SRC_IP] [-i IFACE]\n"
241//usage: " HOST [BYTES]" 249//usage: " HOST [BYTES]"
242//usage:#define traceroute6_full_usage "\n\n" 250//usage:#define traceroute6_full_usage "\n\n"
243//usage: "Trace the route to HOST\n" 251//usage: "Trace the route to HOST\n"
244//usage: "\n -d Set SO_DEBUG options to socket" 252//Currently disabled (TRACEROUTE_SO_DEBUG==0)
253////usage: "\n -d Set SO_DEBUG options to socket"
245//usage: "\n -n Print numeric addresses" 254//usage: "\n -n Print numeric addresses"
246//usage: "\n -r Bypass routing tables, send directly to HOST" 255//usage: "\n -r Bypass routing tables, send directly to HOST"
256//usage: IF_FEATURE_TRACEROUTE_VERBOSE(
247//usage: "\n -v Verbose" 257//usage: "\n -v Verbose"
248//usage: "\n -m Max time-to-live (max number of hops)" 258//usage: )
249//usage: "\n -p Base UDP port number used in probes" 259//usage: "\n -m N Max number of hops"
250//usage: "\n (default is 33434)" 260//usage: "\n -q N Number of probes per hop (default 3)"
251//usage: "\n -q Number of probes per TTL (default 3)" 261//usage: "\n -p N Base UDP port number used in probes"
252//usage: "\n -s IP address to use as the source address" 262//usage: "\n (default 33434)"
253//usage: "\n -t Type-of-service in probe packets (default 0)" 263//usage: "\n -s IP Source address"
254//usage: "\n -w Time in seconds to wait for a response (default 3)" 264//usage: "\n -i IFACE Source interface"
265//usage: "\n -t N Type-of-service in probe packets (default 0)"
266//usage: "\n -w SEC Time wait for a response (default 3)"
255 267
256#define TRACEROUTE_SO_DEBUG 0 268#define TRACEROUTE_SO_DEBUG 0
257 269
258/* TODO: undefs were uncommented - ??! we have config system for that! */
259/* probably ok to remove altogether */
260//#undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
261//#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
262//#undef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
263//#define CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
264//#undef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
265//#define CONFIG_FEATURE_TRACEROUTE_USE_ICMP
266
267
268#include <net/if.h> 270#include <net/if.h>
269#include <arpa/inet.h> 271#include <arpa/inet.h>
270#include <netinet/in.h> 272#include <netinet/in.h>
@@ -471,18 +473,18 @@ send_probe(int seq, int ttl)
471 473
472#if ENABLE_TRACEROUTE6 474#if ENABLE_TRACEROUTE6
473 if (dest_lsa->u.sa.sa_family == AF_INET6) { 475 if (dest_lsa->u.sa.sa_family == AF_INET6) {
474 res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); 476 res = setsockopt_int(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, ttl);
475 if (res < 0) 477 if (res != 0)
476 bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl); 478 bb_perror_msg_and_die("setsockopt(%s) %d", "UNICAST_HOPS", ttl);
477 out = outip; 479 out = outip;
478 len = packlen; 480 len = packlen;
479 } else 481 } else
480#endif 482#endif
481 { 483 {
482#if defined IP_TTL 484#if defined IP_TTL
483 res = setsockopt(sndsock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 485 res = setsockopt_int(sndsock, IPPROTO_IP, IP_TTL, ttl);
484 if (res < 0) 486 if (res != 0)
485 bb_perror_msg_and_die("setsockopt ttl %d", ttl); 487 bb_perror_msg_and_die("setsockopt(%s) %d", "TTL", ttl);
486#endif 488#endif
487 out = outicmp; 489 out = outicmp;
488 len = packlen - sizeof(*outip); 490 len = packlen - sizeof(*outip);
@@ -900,13 +902,10 @@ common_traceroute_main(int op, char **argv)
900 if (af == AF_INET6) { 902 if (af == AF_INET6) {
901 xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock); 903 xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock);
902# ifdef IPV6_RECVPKTINFO 904# ifdef IPV6_RECVPKTINFO
903 setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO, 905 setsockopt_1(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO);
904 &const_int_1, sizeof(const_int_1)); 906 setsockopt_1(rcvsock, SOL_IPV6, IPV6_2292PKTINFO);
905 setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO,
906 &const_int_1, sizeof(const_int_1));
907# else 907# else
908 setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO, 908 setsockopt_1(rcvsock, SOL_IPV6, IPV6_PKTINFO);
909 &const_int_1, sizeof(const_int_1));
910# endif 909# endif
911 } else 910 } else
912#endif 911#endif
@@ -916,18 +915,15 @@ common_traceroute_main(int op, char **argv)
916 915
917#if TRACEROUTE_SO_DEBUG 916#if TRACEROUTE_SO_DEBUG
918 if (op & OPT_DEBUG) 917 if (op & OPT_DEBUG)
919 setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 918 setsockopt_SOL_SOCKET_1(rcvsock, SO_DEBUG);
920 &const_int_1, sizeof(const_int_1));
921#endif 919#endif
922 if (op & OPT_BYPASS_ROUTE) 920 if (op & OPT_BYPASS_ROUTE)
923 setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, 921 setsockopt_SOL_SOCKET_1(rcvsock, SO_DONTROUTE);
924 &const_int_1, sizeof(const_int_1));
925 922
926#if ENABLE_TRACEROUTE6 923#if ENABLE_TRACEROUTE6
927 if (af == AF_INET6) { 924 if (af == AF_INET6) {
928 static const int two = 2; 925 if (setsockopt_int(rcvsock, SOL_RAW, IPV6_CHECKSUM, 2) != 0)
929 if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0) 926 bb_perror_msg_and_die("setsockopt(%s)", "IPV6_CHECKSUM");
930 bb_perror_msg_and_die("setsockopt RAW_CHECKSUM");
931 xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock); 927 xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock);
932 } else 928 } else
933#endif 929#endif
@@ -964,28 +960,25 @@ common_traceroute_main(int op, char **argv)
964 } 960 }
965 961
966#ifdef SO_SNDBUF 962#ifdef SO_SNDBUF
967 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) { 963 if (setsockopt_SOL_SOCKET_int(sndsock, SO_SNDBUF, packlen) != 0) {
968 bb_perror_msg_and_die("SO_SNDBUF"); 964 bb_perror_msg_and_die("setsockopt(%s)", "SO_SNDBUF");
969 } 965 }
970#endif 966#endif
971#ifdef IP_TOS 967#ifdef IP_TOS
972 if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) { 968 if ((op & OPT_TOS) && setsockopt_int(sndsock, IPPROTO_IP, IP_TOS, tos) != 0) {
973 bb_perror_msg_and_die("setsockopt tos %d", tos); 969 bb_perror_msg_and_die("setsockopt(%s) %d", "TOS", tos);
974 } 970 }
975#endif 971#endif
976#ifdef IP_DONTFRAG 972#ifdef IP_DONTFRAG
977 if (op & OPT_DONT_FRAGMNT) 973 if (op & OPT_DONT_FRAGMNT)
978 setsockopt(sndsock, IPPROTO_IP, IP_DONTFRAG, 974 setsockopt_1(sndsock, IPPROTO_IP, IP_DONTFRAG);
979 &const_int_1, sizeof(const_int_1));
980#endif 975#endif
981#if TRACEROUTE_SO_DEBUG 976#if TRACEROUTE_SO_DEBUG
982 if (op & OPT_DEBUG) 977 if (op & OPT_DEBUG)
983 setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 978 setsockopt_SOL_SOCKET_1(sndsock, SO_DEBUG);
984 &const_int_1, sizeof(const_int_1));
985#endif 979#endif
986 if (op & OPT_BYPASS_ROUTE) 980 if (op & OPT_BYPASS_ROUTE)
987 setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 981 setsockopt_SOL_SOCKET_1(sndsock, SO_DONTROUTE);
988 &const_int_1, sizeof(const_int_1));
989 982
990 outip = xzalloc(packlen); 983 outip = xzalloc(packlen);
991 984
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 811a1a1ee..915f65935 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -29,6 +29,20 @@
29#include <linux/filter.h> 29#include <linux/filter.h>
30#include <linux/if_packet.h> 30#include <linux/if_packet.h>
31 31
32#ifndef PACKET_AUXDATA
33# define PACKET_AUXDATA 8
34struct tpacket_auxdata {
35 uint32_t tp_status;
36 uint32_t tp_len;
37 uint32_t tp_snaplen;
38 uint16_t tp_mac;
39 uint16_t tp_net;
40 uint16_t tp_vlan_tci;
41 uint16_t tp_padding;
42};
43#endif
44
45
32/* "struct client_config_t client_config" is in bb_common_bufsiz1 */ 46/* "struct client_config_t client_config" is in bb_common_bufsiz1 */
33 47
34 48
@@ -1043,9 +1057,7 @@ static int udhcp_raw_socket(int ifindex)
1043 } 1057 }
1044#endif 1058#endif
1045 1059
1046 if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA, 1060 if (setsockopt_1(fd, SOL_PACKET, PACKET_AUXDATA) != 0) {
1047 &const_int_1, sizeof(int)) < 0
1048 ) {
1049 if (errno != ENOPROTOOPT) 1061 if (errno != ENOPROTOOPT)
1050 log1("Can't set PACKET_AUXDATA on raw socket"); 1062 log1("Can't set PACKET_AUXDATA on raw socket");
1051 } 1063 }
diff --git a/networking/wget.c b/networking/wget.c
index e09bd2368..0082ced39 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -9,6 +9,94 @@
9 * Kuhn's copyrights are licensed GPLv2-or-later. File as a whole remains GPLv2. 9 * Kuhn's copyrights are licensed GPLv2-or-later. File as a whole remains GPLv2.
10 */ 10 */
11 11
12//config:config WGET
13//config: bool "wget"
14//config: default y
15//config: help
16//config: wget is a utility for non-interactive download of files from HTTP
17//config: and FTP servers.
18//config:
19//config:config FEATURE_WGET_STATUSBAR
20//config: bool "Enable a nifty process meter (+2k)"
21//config: default y
22//config: depends on WGET
23//config: help
24//config: Enable the transfer progress bar for wget transfers.
25//config:
26//config:config FEATURE_WGET_AUTHENTICATION
27//config: bool "Enable HTTP authentication"
28//config: default y
29//config: depends on WGET
30//config: help
31//config: Support authenticated HTTP transfers.
32//config:
33//config:config FEATURE_WGET_LONG_OPTIONS
34//config: bool "Enable long options"
35//config: default y
36//config: depends on WGET && LONG_OPTS
37//config: help
38//config: Support long options for the wget applet.
39//config:
40//config:config FEATURE_WGET_TIMEOUT
41//config: bool "Enable timeout option -T SEC"
42//config: default y
43//config: depends on WGET
44//config: help
45//config: Supports network read and connect timeouts for wget,
46//config: so that wget will give up and timeout, through the -T
47//config: command line option.
48//config:
49//config: Currently only connect and network data read timeout are
50//config: supported (i.e., timeout is not applied to the DNS query). When
51//config: FEATURE_WGET_LONG_OPTIONS is also enabled, the --timeout option
52//config: will work in addition to -T.
53//config:
54//config:config FEATURE_WGET_OPENSSL
55//config: bool "Try to connect to HTTPS using openssl"
56//config: default y
57//config: depends on WGET
58//config: help
59//config: Choose how wget establishes SSL connection for https:// URLs.
60//config:
61//config: Busybox itself contains no SSL code. wget will spawn
62//config: a helper program to talk over HTTPS.
63//config:
64//config: OpenSSL has a simple SSL client for debug purposes.
65//config: If you select "openssl" helper, wget will effectively call
66//config: "openssl s_client -quiet -connect IP:443 2>/dev/null"
67//config: and pipe its data through it.
68//config: Note inconvenient API: host resolution is done twice,
69//config: and there is no guarantee openssl's idea of IPv6 address
70//config: format is the same as ours.
71//config: Another problem is that s_client prints debug information
72//config: to stderr, and it needs to be suppressed. This means
73//config: all error messages get suppressed too.
74//config: openssl is also a big binary, often dynamically linked
75//config: against ~15 libraries.
76//config:
77//config:config FEATURE_WGET_SSL_HELPER
78//config: bool "Try to connect to HTTPS using ssl_helper"
79//config: default y
80//config: depends on WGET
81//config: help
82//config: Choose how wget establishes SSL connection for https:// URLs.
83//config:
84//config: Busybox itself contains no SSL code. wget will spawn
85//config: a helper program to talk over HTTPS.
86//config:
87//config: ssl_helper is a tool which can be built statically
88//config: from busybox sources against a small embedded SSL library.
89//config: Please see networking/ssl_helper/README.
90//config: It does not require double host resolution and emits
91//config: error messages to stderr.
92//config:
93//config: Precompiled static binary may be available at
94//config: http://busybox.net/downloads/binaries/
95
96//applet:IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP))
97
98//kbuild:lib-$(CONFIG_WGET) += wget.o
99
12//usage:#define wget_trivial_usage 100//usage:#define wget_trivial_usage
13//usage: IF_FEATURE_WGET_LONG_OPTIONS( 101//usage: IF_FEATURE_WGET_LONG_OPTIONS(
14//usage: "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document FILE]\n" 102//usage: "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document FILE]\n"
@@ -59,7 +147,9 @@ struct host_info {
59}; 147};
60static const char P_FTP[] = "ftp"; 148static const char P_FTP[] = "ftp";
61static const char P_HTTP[] = "http"; 149static const char P_HTTP[] = "http";
150#if ENABLE_FEATURE_WGET_OPENSSL || ENABLE_FEATURE_WGET_SSL_HELPER
62static const char P_HTTPS[] = "https"; 151static const char P_HTTPS[] = "https";
152#endif
63 153
64#if ENABLE_FEATURE_WGET_LONG_OPTIONS 154#if ENABLE_FEATURE_WGET_LONG_OPTIONS
65/* User-specified headers prevent using our corresponding built-in headers. */ 155/* User-specified headers prevent using our corresponding built-in headers. */
@@ -328,7 +418,7 @@ static void parse_url(const char *src_url, struct host_info *h)
328 if (strcmp(url, P_FTP) == 0) { 418 if (strcmp(url, P_FTP) == 0) {
329 h->port = bb_lookup_port(P_FTP, "tcp", 21); 419 h->port = bb_lookup_port(P_FTP, "tcp", 21);
330 } else 420 } else
331#if !ENABLE_PLATFORM_MINGW32 421#if ENABLE_FEATURE_WGET_OPENSSL || ENABLE_FEATURE_WGET_SSL_HELPER
332 if (strcmp(url, P_HTTPS) == 0) { 422 if (strcmp(url, P_HTTPS) == 0) {
333 h->port = bb_lookup_port(P_HTTPS, "tcp", 443); 423 h->port = bb_lookup_port(P_HTTPS, "tcp", 443);
334 h->protocol = P_HTTPS; 424 h->protocol = P_HTTPS;
@@ -528,12 +618,13 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
528 return sfp; 618 return sfp;
529} 619}
530 620
531#if !ENABLE_PLATFORM_MINGW32 621#if ENABLE_FEATURE_WGET_OPENSSL
532static int spawn_https_helper(const char *host, unsigned port) 622static int spawn_https_helper_openssl(const char *host, unsigned port)
533{ 623{
534 char *allocated = NULL; 624 char *allocated = NULL;
535 int sp[2]; 625 int sp[2];
536 int pid; 626 int pid;
627 IF_FEATURE_WGET_SSL_HELPER(volatile int child_failed = 0;)
537 628
538 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0) 629 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0)
539 /* Kernel can have AF_UNIX support disabled */ 630 /* Kernel can have AF_UNIX support disabled */
@@ -542,7 +633,8 @@ static int spawn_https_helper(const char *host, unsigned port)
542 if (!strchr(host, ':')) 633 if (!strchr(host, ':'))
543 host = allocated = xasprintf("%s:%u", host, port); 634 host = allocated = xasprintf("%s:%u", host, port);
544 635
545 pid = BB_MMU ? xfork() : xvfork(); 636 fflush_all();
637 pid = xvfork();
546 if (pid == 0) { 638 if (pid == 0) {
547 /* Child */ 639 /* Child */
548 char *argv[6]; 640 char *argv[6];
@@ -551,10 +643,6 @@ static int spawn_https_helper(const char *host, unsigned port)
551 xmove_fd(sp[1], 0); 643 xmove_fd(sp[1], 0);
552 xdup2(0, 1); 644 xdup2(0, 1);
553 /* 645 /*
554 * TODO: develop a tiny ssl/tls helper (using matrixssl?),
555 * try to exec it here before falling back to big fat openssl.
556 */
557 /*
558 * openssl s_client -quiet -connect www.kernel.org:443 2>/dev/null 646 * openssl s_client -quiet -connect www.kernel.org:443 2>/dev/null
559 * It prints some debug stuff on stderr, don't know how to suppress it. 647 * It prints some debug stuff on stderr, don't know how to suppress it.
560 * Work around by dev-nulling stderr. We lose all error messages :( 648 * Work around by dev-nulling stderr. We lose all error messages :(
@@ -569,22 +657,31 @@ static int spawn_https_helper(const char *host, unsigned port)
569 argv[5] = NULL; 657 argv[5] = NULL;
570 BB_EXECVP(argv[0], argv); 658 BB_EXECVP(argv[0], argv);
571 xmove_fd(3, 2); 659 xmove_fd(3, 2);
660# if ENABLE_FEATURE_WGET_SSL_HELPER
661 child_failed = 1;
662 xfunc_die();
663# else
572 bb_perror_msg_and_die("can't execute '%s'", argv[0]); 664 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
665# endif
573 /* notreached */ 666 /* notreached */
574 } 667 }
575 668
576 /* Parent */ 669 /* Parent */
577 free(allocated); 670 free(allocated);
578 close(sp[1]); 671 close(sp[1]);
672# if ENABLE_FEATURE_WGET_SSL_HELPER
673 if (child_failed) {
674 close(sp[0]);
675 return -1;
676 }
677# endif
579 return sp[0]; 678 return sp[0];
580} 679}
581#endif 680#endif
582 681
583/* See networking/ssl_helper/README */ 682/* See networking/ssl_helper/README how to build one */
584#define SSL_HELPER 0 683#if ENABLE_FEATURE_WGET_SSL_HELPER
585 684static void spawn_https_helper_small(int network_fd)
586#if SSL_HELPER
587static void spawn_https_helper1(int network_fd)
588{ 685{
589 int sp[2]; 686 int sp[2];
590 int pid; 687 int pid;
@@ -861,21 +958,37 @@ static void download_one_url(const char *url)
861 int status; 958 int status;
862 959
863 /* Open socket to http(s) server */ 960 /* Open socket to http(s) server */
864#if !ENABLE_PLATFORM_MINGW32 961#if ENABLE_FEATURE_WGET_OPENSSL
962 /* openssl (and maybe ssl_helper) support is configured */
865 if (target.protocol == P_HTTPS) { 963 if (target.protocol == P_HTTPS) {
866/* openssl-based helper 964 /* openssl-based helper
867 * Inconvenient API since we can't give it an open fd 965 * Inconvenient API since we can't give it an open fd
868 */ 966 */
869 int fd = spawn_https_helper(server.host, server.port); 967 int fd = spawn_https_helper_openssl(server.host, server.port);
968# if ENABLE_FEATURE_WGET_SSL_HELPER
969 if (fd < 0) { /* no openssl? try ssl_helper */
970 sfp = open_socket(lsa);
971 spawn_https_helper_small(fileno(sfp));
972 goto socket_opened;
973 }
974# else
975 /* We don't check for exec("openssl") failure in this case */
976# endif
870 sfp = fdopen(fd, "r+"); 977 sfp = fdopen(fd, "r+");
871 if (!sfp) 978 if (!sfp)
872 bb_perror_msg_and_die(bb_msg_memory_exhausted); 979 bb_perror_msg_and_die(bb_msg_memory_exhausted);
873 } else 980 goto socket_opened;
874#endif 981 }
875 sfp = open_socket(lsa); 982 sfp = open_socket(lsa);
876#if SSL_HELPER 983 socket_opened:
984#elif ENABLE_FEATURE_WGET_SSL_HELPER
985 /* Only ssl_helper support is configured */
986 sfp = open_socket(lsa);
877 if (target.protocol == P_HTTPS) 987 if (target.protocol == P_HTTPS)
878 spawn_https_helper1(fileno(sfp)); 988 spawn_https_helper_small(fileno(sfp));
989#else
990 /* ssl (https) support is not configured */
991 sfp = open_socket(lsa);
879#endif 992#endif
880 /* Send HTTP request */ 993 /* Send HTTP request */
881 if (use_proxy) { 994 if (use_proxy) {
diff --git a/networking/zcip.c b/networking/zcip.c
index 69644b230..d15c67d55 100644
--- a/networking/zcip.c
+++ b/networking/zcip.c
@@ -56,9 +56,6 @@ struct arp_packet {
56} PACKED; 56} PACKED;
57 57
58enum { 58enum {
59 /* 169.254.0.0 */
60 LINKLOCAL_ADDR = 0xa9fe0000,
61
62 /* 0-1 seconds before sending 1st probe */ 59 /* 0-1 seconds before sending 1st probe */
63 PROBE_WAIT = 1, 60 PROBE_WAIT = 1,
64 /* 1-2 seconds between probes */ 61 /* 1-2 seconds between probes */
@@ -70,7 +67,7 @@ enum {
70 /* if probe/announce sees a conflict, multiply RANDOM(NUM_CONFLICT) by... */ 67 /* if probe/announce sees a conflict, multiply RANDOM(NUM_CONFLICT) by... */
71 CONFLICT_MULTIPLIER = 2, 68 CONFLICT_MULTIPLIER = 2,
72 /* if we monitor and see a conflict, how long is defend state? */ 69 /* if we monitor and see a conflict, how long is defend state? */
73 DEFEND_INTERVAL = 10 70 DEFEND_INTERVAL = 10,
74}; 71};
75 72
76/* States during the configuration process. */ 73/* States during the configuration process. */
@@ -90,7 +87,7 @@ enum {
90 87
91struct globals { 88struct globals {
92 struct sockaddr iface_sockaddr; 89 struct sockaddr iface_sockaddr;
93 struct ether_addr eth_addr; 90 struct ether_addr our_ethaddr;
94 uint32_t localnet_ip; 91 uint32_t localnet_ip;
95} FIX_ALIASING; 92} FIX_ALIASING;
96#define G (*(struct globals*)&bb_common_bufsiz1) 93#define G (*(struct globals*)&bb_common_bufsiz1)
@@ -121,14 +118,14 @@ static const char *nip_to_a(uint32_t nip)
121/** 118/**
122 * Broadcast an ARP packet. 119 * Broadcast an ARP packet.
123 */ 120 */
124static void arp( 121static void send_arp_request(
125 /* int op, - always ARPOP_REQUEST */ 122 /* int op, - always ARPOP_REQUEST */
126 /* const struct ether_addr *source_eth, - always &G.eth_addr */ 123 /* const struct ether_addr *source_eth, - always &G.our_ethaddr */
127 uint32_t source_nip, 124 uint32_t source_nip,
128 const struct ether_addr *target_eth, uint32_t target_nip) 125 const struct ether_addr *target_eth, uint32_t target_nip)
129{ 126{
130 enum { op = ARPOP_REQUEST }; 127 enum { op = ARPOP_REQUEST };
131#define source_eth (&G.eth_addr) 128#define source_eth (&G.our_ethaddr)
132 129
133 struct arp_packet p; 130 struct arp_packet p;
134 memset(&p, 0, sizeof(p)); 131 memset(&p, 0, sizeof(p));
@@ -196,7 +193,7 @@ static int run(char *argv[3], const char *param, uint32_t nip)
196 */ 193 */
197static ALWAYS_INLINE unsigned random_delay_ms(unsigned secs) 194static ALWAYS_INLINE unsigned random_delay_ms(unsigned secs)
198{ 195{
199 return rand() % (secs * 1000); 196 return (unsigned)rand() % (secs * 1000);
200} 197}
201 198
202/** 199/**
@@ -205,37 +202,34 @@ static ALWAYS_INLINE unsigned random_delay_ms(unsigned secs)
205int zcip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 202int zcip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
206int zcip_main(int argc UNUSED_PARAM, char **argv) 203int zcip_main(int argc UNUSED_PARAM, char **argv)
207{ 204{
208 int state;
209 char *r_opt; 205 char *r_opt;
210 const char *l_opt = "169.254.0.0"; 206 const char *l_opt = "169.254.0.0";
207 int state;
208 int nsent;
211 unsigned opts; 209 unsigned opts;
212 210
213 // ugly trick, but I want these zeroed in one go 211 // Ugly trick, but I want these zeroed in one go
214 struct { 212 struct {
215 const struct ether_addr null_addr; 213 const struct ether_addr null_ethaddr;
216 struct ifreq ifr; 214 struct ifreq ifr;
217 uint32_t chosen_nip; 215 uint32_t chosen_nip;
218 int timeout_ms; /* must be signed */ 216 int conflicts;
219 unsigned conflicts; 217 int timeout_ms; // must be signed
220 unsigned nprobes;
221 unsigned nclaims;
222 int verbose; 218 int verbose;
223 } L; 219 } L;
224#define null_addr (L.null_addr ) 220#define null_ethaddr (L.null_ethaddr)
225#define chosen_nip (L.chosen_nip) 221#define ifr (L.ifr )
226#define ifr (L.ifr ) 222#define chosen_nip (L.chosen_nip )
227#define timeout_ms (L.timeout_ms) 223#define conflicts (L.conflicts )
228#define conflicts (L.conflicts ) 224#define timeout_ms (L.timeout_ms )
229#define nprobes (L.nprobes ) 225#define verbose (L.verbose )
230#define nclaims (L.nclaims )
231#define verbose (L.verbose )
232 226
233 memset(&L, 0, sizeof(L)); 227 memset(&L, 0, sizeof(L));
234 INIT_G(); 228 INIT_G();
235 229
236#define FOREGROUND (opts & 1) 230#define FOREGROUND (opts & 1)
237#define QUIT (opts & 2) 231#define QUIT (opts & 2)
238 // parse commandline: prog [options] ifname script 232 // Parse commandline: prog [options] ifname script
239 // exactly 2 args; -v accumulates and implies -f 233 // exactly 2 args; -v accumulates and implies -f
240 opt_complementary = "=2:vv:vf"; 234 opt_complementary = "=2:vv:vf";
241 opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose); 235 opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose);
@@ -244,7 +238,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
244 if (!FOREGROUND) 238 if (!FOREGROUND)
245 bb_daemonize_or_rexec(0 /*was: DAEMON_CHDIR_ROOT*/, argv); 239 bb_daemonize_or_rexec(0 /*was: DAEMON_CHDIR_ROOT*/, argv);
246#endif 240#endif
247 // open an ARP socket 241 // Open an ARP socket
248 // (need to do it before openlog to prevent openlog from taking 242 // (need to do it before openlog to prevent openlog from taking
249 // fd 3 (sock_fd==3)) 243 // fd 3 (sock_fd==3))
250 xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd); 244 xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd);
@@ -284,26 +278,26 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
284 278
285 xsetenv("interface", argv_intf); 279 xsetenv("interface", argv_intf);
286 280
287 // initialize the interface (modprobe, ifup, etc) 281 // Initialize the interface (modprobe, ifup, etc)
288 if (run(argv, "init", 0)) 282 if (run(argv, "init", 0))
289 return EXIT_FAILURE; 283 return EXIT_FAILURE;
290 284
291 // initialize G.iface_sockaddr 285 // Initialize G.iface_sockaddr
292 // G.iface_sockaddr is: { u16 sa_family; u8 sa_data[14]; } 286 // G.iface_sockaddr is: { u16 sa_family; u8 sa_data[14]; }
293 //memset(&G.iface_sockaddr, 0, sizeof(G.iface_sockaddr)); 287 //memset(&G.iface_sockaddr, 0, sizeof(G.iface_sockaddr));
294 //TODO: are we leaving sa_family == 0 (AF_UNSPEC)?! 288 //TODO: are we leaving sa_family == 0 (AF_UNSPEC)?!
295 safe_strncpy(G.iface_sockaddr.sa_data, argv_intf, sizeof(G.iface_sockaddr.sa_data)); 289 safe_strncpy(G.iface_sockaddr.sa_data, argv_intf, sizeof(G.iface_sockaddr.sa_data));
296 290
297 // bind to the interface's ARP socket 291 // Bind to the interface's ARP socket
298 xbind(sock_fd, &G.iface_sockaddr, sizeof(G.iface_sockaddr)); 292 xbind(sock_fd, &G.iface_sockaddr, sizeof(G.iface_sockaddr));
299 293
300 // get the interface's ethernet address 294 // Get the interface's ethernet address
301 //memset(&ifr, 0, sizeof(ifr)); 295 //memset(&ifr, 0, sizeof(ifr));
302 strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf); 296 strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf);
303 xioctl(sock_fd, SIOCGIFHWADDR, &ifr); 297 xioctl(sock_fd, SIOCGIFHWADDR, &ifr);
304 memcpy(&G.eth_addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); 298 memcpy(&G.our_ethaddr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
305 299
306 // start with some stable ip address, either a function of 300 // Start with some stable ip address, either a function of
307 // the hardware address or else the last address we used. 301 // the hardware address or else the last address we used.
308 // we are taking low-order four bytes, as top-order ones 302 // we are taking low-order four bytes, as top-order ones
309 // aren't random enough. 303 // aren't random enough.
@@ -311,17 +305,14 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
311 // depending on when we detect conflicts. 305 // depending on when we detect conflicts.
312 { 306 {
313 uint32_t t; 307 uint32_t t;
314 move_from_unaligned32(t, ((char *)&G.eth_addr + 2)); 308 move_from_unaligned32(t, ((char *)&G.our_ethaddr + 2));
315 srand(t); 309 srand(t);
316 } 310 }
317 if (chosen_nip == 0)
318 chosen_nip = pick_nip();
319
320 // FIXME cases to handle: 311 // FIXME cases to handle:
321 // - zcip already running! 312 // - zcip already running!
322 // - link already has local address... just defend/update 313 // - link already has local address... just defend/update
323 314
324 // daemonize now; don't delay system startup 315 // Daemonize now; don't delay system startup
325 if (!FOREGROUND) { 316 if (!FOREGROUND) {
326#if BB_MMU 317#if BB_MMU
327 bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/); 318 bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/);
@@ -329,14 +320,14 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
329 bb_info_msg("start, interface %s", argv_intf); 320 bb_info_msg("start, interface %s", argv_intf);
330 } 321 }
331 322
332 // run the dynamic address negotiation protocol, 323 // Run the dynamic address negotiation protocol,
333 // restarting after address conflicts: 324 // restarting after address conflicts:
334 // - start with some address we want to try 325 // - start with some address we want to try
335 // - short random delay 326 // - short random delay
336 // - arp probes to see if another host uses it 327 // - arp probes to see if another host uses it
337 // 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff, ARP (0x0806): arp who-has 169.254.194.171 tell 0.0.0.0 328 // 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff arp who-has 169.254.194.171 tell 0.0.0.0
338 // - arp announcements that we're claiming it 329 // - arp announcements that we're claiming it
339 // 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff, ARP (0x0806): arp who-has 169.254.194.171 (00:04:e2:64:23:c2) tell 169.254.194.171 330 // 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff arp who-has 169.254.194.171 (00:04:e2:64:23:c2) tell 169.254.194.171
340 // - use it 331 // - use it
341 // - defend it, within limits 332 // - defend it, within limits
342 // exit if: 333 // exit if:
@@ -344,215 +335,191 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
344 // run "<script> config", then exit with exitcode 0 335 // run "<script> config", then exit with exitcode 0
345 // - poll error (when does this happen?) 336 // - poll error (when does this happen?)
346 // - read error (when does this happen?) 337 // - read error (when does this happen?)
347 // - sendto error (in arp()) (when does this happen?) 338 // - sendto error (in send_arp_request()) (when does this happen?)
348 // - revents & POLLERR (link down). run "<script> deconfig" first 339 // - revents & POLLERR (link down). run "<script> deconfig" first
340 if (chosen_nip == 0) {
341 new_nip_and_PROBE:
342 chosen_nip = pick_nip();
343 }
344 nsent = 0;
349 state = PROBE; 345 state = PROBE;
350 while (1) { 346 while (1) {
351 struct pollfd fds[1]; 347 struct pollfd fds[1];
352 unsigned deadline_us; 348 unsigned deadline_us;
353 struct arp_packet p; 349 struct arp_packet p;
354 int source_ip_conflict; 350 int ip_conflict;
355 int target_ip_conflict; 351 int n;
356 352
357 fds[0].fd = sock_fd; 353 fds[0].fd = sock_fd;
358 fds[0].events = POLLIN; 354 fds[0].events = POLLIN;
359 fds[0].revents = 0; 355 fds[0].revents = 0;
360 356
361 // poll, being ready to adjust current timeout 357 // Poll, being ready to adjust current timeout
362 if (!timeout_ms) { 358 if (!timeout_ms) {
363 timeout_ms = random_delay_ms(PROBE_WAIT); 359 timeout_ms = random_delay_ms(PROBE_WAIT);
364 // FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to 360 // FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to
365 // make the kernel filter out all packets except 361 // make the kernel filter out all packets except
366 // ones we'd care about. 362 // ones we'd care about.
367 } 363 }
368 // set deadline_us to the point in time when we timeout 364 // Set deadline_us to the point in time when we timeout
369 deadline_us = MONOTONIC_US() + timeout_ms * 1000; 365 deadline_us = MONOTONIC_US() + timeout_ms * 1000;
370 366
371 VDBG("...wait %d %s nprobes=%u, nclaims=%u\n", 367 VDBG("...wait %d %s nsent=%u\n",
372 timeout_ms, argv_intf, nprobes, nclaims); 368 timeout_ms, argv_intf, nsent);
373
374 switch (safe_poll(fds, 1, timeout_ms)) {
375 369
376 default: 370 n = safe_poll(fds, 1, timeout_ms);
371 if (n < 0) {
377 //bb_perror_msg("poll"); - done in safe_poll 372 //bb_perror_msg("poll"); - done in safe_poll
378 return EXIT_FAILURE; 373 return EXIT_FAILURE;
379 374 }
380 // timeout 375 if (n == 0) { // timed out?
381 case 0: 376 VDBG("state:%d\n", state);
382 VDBG("state = %d\n", state);
383 switch (state) { 377 switch (state) {
384 case PROBE: 378 case PROBE:
385 // timeouts in the PROBE state mean no conflicting ARP packets 379 // No conflicting ARP packets were seen:
386 // have been received, so we can progress through the states 380 // we can progress through the states
387 if (nprobes < PROBE_NUM) { 381 if (nsent < PROBE_NUM) {
388 nprobes++; 382 nsent++;
389 VDBG("probe/%u %s@%s\n", 383 VDBG("probe/%u %s@%s\n",
390 nprobes, argv_intf, nip_to_a(chosen_nip)); 384 nsent, argv_intf, nip_to_a(chosen_nip));
391 timeout_ms = PROBE_MIN * 1000; 385 timeout_ms = PROBE_MIN * 1000;
392 timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN); 386 timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN);
393 arp(/* ARPOP_REQUEST, */ 387 send_arp_request(0, &null_ethaddr, chosen_nip);
394 /* &G.eth_addr, */ 0, 388 continue;
395 &null_addr, chosen_nip);
396 break;
397 } 389 }
398 // Switch to announce state. 390 // Switch to announce state
399 nclaims = 0; 391 nsent = 0;
400 state = ANNOUNCE; 392 state = ANNOUNCE;
401 goto send_announce; 393 goto send_announce;
402 case ANNOUNCE: 394 case ANNOUNCE:
403 // timeouts in the ANNOUNCE state mean no conflicting ARP packets 395 // No conflicting ARP packets were seen:
404 // have been received, so we can progress through the states 396 // we can progress through the states
405 if (nclaims < ANNOUNCE_NUM) { 397 if (nsent < ANNOUNCE_NUM) {
406 send_announce: 398 send_announce:
407 nclaims++; 399 nsent++;
408 VDBG("announce/%u %s@%s\n", 400 VDBG("announce/%u %s@%s\n",
409 nclaims, argv_intf, nip_to_a(chosen_nip)); 401 nsent, argv_intf, nip_to_a(chosen_nip));
410 timeout_ms = ANNOUNCE_INTERVAL * 1000; 402 timeout_ms = ANNOUNCE_INTERVAL * 1000;
411 arp(/* ARPOP_REQUEST, */ 403 send_arp_request(chosen_nip, &G.our_ethaddr, chosen_nip);
412 /* &G.eth_addr, */ chosen_nip, 404 continue;
413 &G.eth_addr, chosen_nip);
414 break;
415 } 405 }
416 // Switch to monitor state. 406 // Switch to monitor state
417 // FIXME update filters 407 // FIXME update filters
418 run(argv, "config", chosen_nip); 408 run(argv, "config", chosen_nip);
419 // NOTE: all other exit paths should deconfig... 409 // NOTE: all other exit paths should deconfig...
420 if (QUIT) 410 if (QUIT)
421 return EXIT_SUCCESS; 411 return EXIT_SUCCESS;
422 conflicts = 0; 412 // fall through: switch to MONITOR
423 timeout_ms = -1; // Never timeout in the monitor state. 413 default:
424 state = MONITOR; 414 // case DEFEND:
425 break; 415 // case MONITOR: (shouldn't happen, MONITOR timeout is infinite)
426 case DEFEND: 416 // Defend period ended with no ARP replies - we won
427 // Defend period ended with no ARP replies - we won. 417 timeout_ms = -1; // never timeout in monitor state
428 conflicts = 0;
429 timeout_ms = -1;
430 state = MONITOR; 418 state = MONITOR;
431 break;
432 } // switch (state)
433 break; // case 0 (timeout)
434
435 // packets arriving, or link went down
436 case 1:
437 // We need to adjust the timeout in case we didn't receive
438 // a conflicting packet.
439 if (timeout_ms > 0) {
440 unsigned diff = deadline_us - MONOTONIC_US();
441 if ((int)(diff) < 0) {
442 // Current time is greater than the expected timeout time.
443 diff = 0;
444 }
445 VDBG("adjusting timeout\n");
446 timeout_ms = (diff / 1000) | 1; /* never 0 */
447 }
448
449 if ((fds[0].revents & POLLIN) == 0) {
450 if (fds[0].revents & POLLERR) {
451 // FIXME: links routinely go down;
452 // this shouldn't necessarily exit.
453 bb_error_msg("iface %s is down", argv_intf);
454 if (state >= MONITOR) {
455 /* only if we are in MONITOR or DEFEND */
456 run(argv, "deconfig", chosen_nip);
457 }
458 return EXIT_FAILURE;
459 }
460 continue; 419 continue;
461 } 420 }
421 }
462 422
463 // read ARP packet 423 // Packet arrived, or link went down.
464 if (safe_read(sock_fd, &p, sizeof(p)) < 0) { 424 // We need to adjust the timeout in case we didn't receive
465 bb_perror_msg_and_die(bb_msg_read_error); 425 // a conflicting packet.
426 if (timeout_ms > 0) {
427 unsigned diff = deadline_us - MONOTONIC_US();
428 if ((int)(diff) < 0) {
429 // Current time is greater than the expected timeout time.
430 diff = 0;
466 } 431 }
432 VDBG("adjusting timeout\n");
433 timeout_ms = (diff / 1000) | 1; // never 0
434 }
467 435
468 if (p.eth.ether_type != htons(ETHERTYPE_ARP)) 436 if ((fds[0].revents & POLLIN) == 0) {
469 continue; 437 if (fds[0].revents & POLLERR) {
470 if (p.arp.arp_op != htons(ARPOP_REQUEST) 438 // FIXME: links routinely go down;
471 && p.arp.arp_op != htons(ARPOP_REPLY) 439 // this shouldn't necessarily exit.
472 ) { 440 bb_error_msg("iface %s is down", argv_intf);
473 continue; 441 if (state >= MONITOR) {
442 // Only if we are in MONITOR or DEFEND
443 run(argv, "deconfig", chosen_nip);
444 }
445 return EXIT_FAILURE;
474 } 446 }
447 continue;
448 }
449
450 // Read ARP packet
451 if (safe_read(sock_fd, &p, sizeof(p)) < 0) {
452 bb_perror_msg_and_die(bb_msg_read_error);
453 }
454
455 if (p.eth.ether_type != htons(ETHERTYPE_ARP))
456 continue;
457 if (p.arp.arp_op != htons(ARPOP_REQUEST)
458 && p.arp.arp_op != htons(ARPOP_REPLY)
459 ) {
460 continue;
461 }
475#ifdef DEBUG 462#ifdef DEBUG
476 { 463 {
477 struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha; 464 struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha;
478 struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha; 465 struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha;
479 struct in_addr *spa = (struct in_addr *) p.arp.arp_spa; 466 struct in_addr *spa = (struct in_addr *) p.arp.arp_spa;
480 struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa; 467 struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa;
481 VDBG("%s recv arp type=%d, op=%d,\n", 468 VDBG("source=%s %s\n", ether_ntoa(sha), inet_ntoa(*spa));
482 argv_intf, ntohs(p.eth.ether_type), 469 VDBG("target=%s %s\n", ether_ntoa(tha), inet_ntoa(*tpa));
483 ntohs(p.arp.arp_op)); 470 }
484 VDBG("\tsource=%s %s\n",
485 ether_ntoa(sha),
486 inet_ntoa(*spa));
487 VDBG("\ttarget=%s %s\n",
488 ether_ntoa(tha),
489 inet_ntoa(*tpa));
490 }
491#endif 471#endif
492 source_ip_conflict = 0; 472 ip_conflict = 0;
493 target_ip_conflict = 0; 473 if (memcmp(&p.arp.arp_sha, &G.our_ethaddr, ETH_ALEN) != 0) {
494 474 if (memcmp(p.arp.arp_spa, &chosen_nip, 4) == 0) {
495 if (memcmp(&p.arp.arp_sha, &G.eth_addr, ETH_ALEN) != 0) { 475 // A probe or reply with source_ip == chosen ip
496 if (memcmp(p.arp.arp_spa, &chosen_nip, 4) == 0) { 476 ip_conflict = 1;
497 /* A probe or reply with source_ip == chosen ip */
498 source_ip_conflict = 1;
499 }
500 if (p.arp.arp_op == htons(ARPOP_REQUEST)
501 && memcmp(p.arp.arp_spa, &const_int_0, 4) == 0
502 && memcmp(p.arp.arp_tpa, &chosen_nip, 4) == 0
503 ) {
504 /* A probe with source_ip == 0.0.0.0, target_ip == chosen ip:
505 * another host trying to claim this ip!
506 */
507 target_ip_conflict = 1;
508 }
509 } 477 }
478 if (p.arp.arp_op == htons(ARPOP_REQUEST)
479 && memcmp(p.arp.arp_spa, &const_int_0, 4) == 0
480 && memcmp(p.arp.arp_tpa, &chosen_nip, 4) == 0
481 ) {
482 // A probe with source_ip == 0.0.0.0, target_ip == chosen ip:
483 // another host trying to claim this ip!
484 ip_conflict |= 2;
485 }
486 }
487 VDBG("state:%d ip_conflict:%d\n", state, ip_conflict);
488 if (!ip_conflict)
489 continue;
490
491 // Either src or target IP conflict exists
492 if (state <= ANNOUNCE) {
493 // PROBE or ANNOUNCE
494 conflicts++;
495 timeout_ms = PROBE_MIN * 1000
496 + CONFLICT_MULTIPLIER * random_delay_ms(conflicts);
497 goto new_nip_and_PROBE;
498 }
510 499
511 VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n", 500 // MONITOR or DEFEND: only src IP conflict is a problem
512 state, source_ip_conflict, target_ip_conflict); 501 if (ip_conflict & 1) {
513 switch (state) { 502 if (state == MONITOR) {
514 case PROBE: 503 // Src IP conflict, defend with a single ARP probe
515 case ANNOUNCE: 504 VDBG("monitor conflict - defending\n");
516 // When probing or announcing, check for source IP conflicts 505 timeout_ms = DEFEND_INTERVAL * 1000;
517 // and other hosts doing ARP probes (target IP conflicts). 506 state = DEFEND;
518 if (source_ip_conflict || target_ip_conflict) { 507 send_arp_request(chosen_nip, &G.our_ethaddr, chosen_nip);
519 conflicts++; 508 continue;
520 timeout_ms = PROBE_MIN * 1000 509 }
521 + CONFLICT_MULTIPLIER * random_delay_ms(conflicts); 510 // state == DEFEND
522 chosen_nip = pick_nip(); 511 // Another src IP conflict, start over
523 nprobes = 0; 512 VDBG("defend conflict - starting over\n");
524 nclaims = 0; 513 run(argv, "deconfig", chosen_nip);
525 state = PROBE; 514 conflicts = 0;
526 } 515 timeout_ms = 0;
527 break; 516 goto new_nip_and_PROBE;
528 case MONITOR: 517 }
529 // If a conflict, we try to defend with a single ARP probe. 518 // Note: if we only have a target IP conflict here (ip_conflict & 2),
530 if (source_ip_conflict) { 519 // IOW: if we just saw this sort of ARP packet:
531 VDBG("monitor conflict -- defending\n"); 520 // aa:bb:cc:dd:ee:ff > xx:xx:xx:xx:xx:xx arp who-has <chosen_nip> tell 0.0.0.0
532 timeout_ms = DEFEND_INTERVAL * 1000; 521 // we expect _kernel_ to respond to that, because <chosen_nip>
533 state = DEFEND; 522 // is (expected to be) configured on this iface.
534 arp(/* ARPOP_REQUEST, */
535 /* &G.eth_addr, */ chosen_nip,
536 &G.eth_addr, chosen_nip);
537 }
538 break;
539 case DEFEND:
540 // Well, we tried. Start over (on conflict).
541 if (source_ip_conflict) {
542 VDBG("defend conflict -- starting over\n");
543 run(argv, "deconfig", chosen_nip);
544
545 // restart the whole protocol
546 timeout_ms = 0;
547 chosen_nip = pick_nip();
548 nprobes = 0;
549 nclaims = 0;
550 state = PROBE;
551 }
552 break;
553 } // switch state
554 break; // case 1 (packets arriving)
555 } // switch poll
556 } // while (1) 523 } // while (1)
557#undef argv_intf 524#undef argv_intf
558} 525}
diff --git a/printutils/lpd.c b/printutils/lpd.c
index eaf42c08b..c98bbb347 100644
--- a/printutils/lpd.c
+++ b/printutils/lpd.c
@@ -200,7 +200,7 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[])
200 if (2 != s[0] && 3 != s[0]) 200 if (2 != s[0] && 3 != s[0])
201 goto unsupported_cmd; 201 goto unsupported_cmd;
202 if (spooling & (1 << (s[0]-1))) { 202 if (spooling & (1 << (s[0]-1))) {
203 printf("Duplicated subcommand\n"); 203 puts("Duplicated subcommand");
204 goto err_exit; 204 goto err_exit;
205 } 205 }
206 // get filename 206 // get filename
@@ -208,7 +208,7 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[])
208 fname = strchr(s, ' '); 208 fname = strchr(s, ' ');
209 if (!fname) { 209 if (!fname) {
210// bad_fname: 210// bad_fname:
211 printf("No or bad filename\n"); 211 puts("No or bad filename");
212 goto err_exit; 212 goto err_exit;
213 } 213 }
214 *fname++ = '\0'; 214 *fname++ = '\0';
@@ -219,13 +219,13 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[])
219 // get length 219 // get length
220 expected_len = bb_strtou(s + 1, NULL, 10); 220 expected_len = bb_strtou(s + 1, NULL, 10);
221 if (errno || expected_len < 0) { 221 if (errno || expected_len < 0) {
222 printf("Bad length\n"); 222 puts("Bad length");
223 goto err_exit; 223 goto err_exit;
224 } 224 }
225 if (2 == s[0] && expected_len > 16 * 1024) { 225 if (2 == s[0] && expected_len > 16 * 1024) {
226 // SECURITY: 226 // SECURITY:
227 // ctrlfile can't be big (we want to read it back later!) 227 // ctrlfile can't be big (we want to read it back later!)
228 printf("File is too big\n"); 228 puts("File is too big");
229 goto err_exit; 229 goto err_exit;
230 } 230 }
231 231
diff --git a/procps/iostat.c b/procps/iostat.c
index 8d272c87c..c290c594b 100644
--- a/procps/iostat.c
+++ b/procps/iostat.c
@@ -142,7 +142,7 @@ static void print_timestamp(void)
142 /* %x: date representation for the current locale */ 142 /* %x: date representation for the current locale */
143 /* %X: time representation for the current locale */ 143 /* %X: time representation for the current locale */
144 strftime(buf, sizeof(buf), "%x %X", &G.tmtime); 144 strftime(buf, sizeof(buf), "%x %X", &G.tmtime);
145 printf("%s\n", buf); 145 puts(buf);
146} 146}
147 147
148static cputime_t get_smp_uptime(void) 148static cputime_t get_smp_uptime(void)
diff --git a/procps/powertop.c b/procps/powertop.c
index 1de5d329e..ce85f4191 100644
--- a/procps/powertop.c
+++ b/procps/powertop.c
@@ -591,7 +591,7 @@ static NOINLINE void print_intel_cstates(void)
591 if (!edx || !(ecx & 1)) 591 if (!edx || !(ecx & 1))
592 return; 592 return;
593 593
594 printf("Your CPU supports the following C-states: "); 594 printf("Your %s the following C-states: ", "CPU supports");
595 i = 0; 595 i = 0;
596 while (edx) { 596 while (edx) {
597 if (edx & 7) 597 if (edx & 7)
@@ -602,7 +602,7 @@ static NOINLINE void print_intel_cstates(void)
602 bb_putchar('\n'); 602 bb_putchar('\n');
603 603
604 /* Print BIOS C-States */ 604 /* Print BIOS C-States */
605 printf("Your BIOS reports the following C-states: "); 605 printf("Your %s the following C-states: ", "BIOS reports");
606 for (i = 0; i < ARRAY_SIZE(bios_table); i++) 606 for (i = 0; i < ARRAY_SIZE(bios_table); i++)
607 if (bios_table[i]) 607 if (bios_table[i])
608 printf("C%u ", i); 608 printf("C%u ", i);
@@ -704,7 +704,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
704 /* Get number of CPUs */ 704 /* Get number of CPUs */
705 G.total_cpus = get_cpu_count(); 705 G.total_cpus = get_cpu_count();
706 706
707 printf("Collecting data for "DEFAULT_SLEEP_STR" seconds\n"); 707 puts("Collecting data for "DEFAULT_SLEEP_STR" seconds");
708 708
709#if ENABLE_FEATURE_USE_TERMIOS 709#if ENABLE_FEATURE_USE_TERMIOS
710 tcgetattr(0, (void *)&G.init_settings); 710 tcgetattr(0, (void *)&G.init_settings);
diff --git a/qemu_multiarch_testing/README b/qemu_multiarch_testing/README
new file mode 100644
index 000000000..9757ff0e4
--- /dev/null
+++ b/qemu_multiarch_testing/README
@@ -0,0 +1,58 @@
1How to test build using Aboriginal Linux system images.
2
3* Put a source tree into hdc.dir/.
4For example, this should work:
5git clone git://busybox.net/var/lib/git/busybox.git
6
7* Run ./make-hdc-img.sh: it will generate ext2 image file,
8hdc.img, from hdc.dir/* data. This requires root for loop mount.
9
10* Download and unpack, or build from source and unpack
11one or more system-image-ARCH directories into this directory
12(the one which contains this README).
13
14* Run: ./parallel-build-hdc-img.sh system-image-DIR1 system-image-DIR2...
15(background it if you don't want to see "Waiting to finish" thing).
16This runs build in several qemu virtual machines in parallel.
17
18* Observe system-image-*.log file(s) with growing log of the build.
19
20There is no automated detection of errors for now: you need to examine
21logs yourself.
22
23Log files will also contain uuencoded (or if all else fails, od -tx1'ed)
24binary, if build was successful.
25
26To debug a build problem in one of the sandboxes, change keep_hdb
27to "keep_hdb=true" in parallel-build-hdc-img.sh
28- this preserves system-image-ARCH/hdb.img after the build,
29so you can go into system-image-ARCH and run
30"HDB=hdb.img ./dev-environment.sh" to debug the problem.
31
32You can also run "./parallel-build-hdc-img.sh -s system-image-ARCH"
33- single mode, output is to screen and serial input is from keyboard.
34
35If hdc.dir/bin/busybox-$ARCH exists, it will be used during build
36to supply additional tools (dir with all applets appended to $PATH).
37
38For me, the following system images worked:
39system-image-armv4l
40system-image-armv4tl
41system-image-armv5l
42 od is buggy on arm*:
43 # echo Hello-hello-hello-hello | od -b
44 0000000 110 145 154 154 157 055 150 145 154 154 157 055 150 145 154 154
45 0000000 157 055 150 145 154 154 157 012 <= WRONG OFFSET
46 0000000 (can also be even more bogus like 17767153361)
47system-image-i686
48system-image-mips - od is buggy
49system-image-mipsel - od is buggy
50system-image-x86_64
51system-image-powerpc - qemu 1.2.2 didn't work, 2.4.0 worked; od is buggy
52system-image-sparc - qemu 1.2.2 didn't work, 2.4.0 worked; od is buggy
53
54And these did not:
55system-image-armv6l - hang on "Uncompressing Linux... done, booting the kernel"
56system-image-m68k - my qemu doesn't like "-M q800"
57system-image-mips64 - init dies "Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000a"
58system-image-sh4 - qemu segfaults early in kernel boot
diff --git a/qemu_multiarch_testing/extract_od_binary.sh b/qemu_multiarch_testing/extract_od_binary.sh
new file mode 100755
index 000000000..1006e5153
--- /dev/null
+++ b/qemu_multiarch_testing/extract_od_binary.sh
@@ -0,0 +1,6 @@
1#!/bin/sh
2
3# Converts textual result of "od -tx1 <FILE"
4# back into a binary FILE
5
6grep -a '^[0-7][0-7][0-7][0-7][0-7][0-7][0-7][0-7]* [0-9a-f][0-9a-f] [0-9a-f][0-9a-f] [0-9a-f][0-9a-f] [0-9a-f][0-9a-f]' | busybox hexdump -R
diff --git a/qemu_multiarch_testing/hdc.dir/build b/qemu_multiarch_testing/hdc.dir/build
new file mode 100755
index 000000000..a9981864a
--- /dev/null
+++ b/qemu_multiarch_testing/hdc.dir/build
@@ -0,0 +1,50 @@
1#!/bin/sh
2
3umount /mnt # optional
4
5test -x "bin/busybox-$HOST" && {
6 echo "Found bin/busybox-$HOST, using it"
7 cp -a "bin/busybox-$HOST" bin/busybox
8 bin/busybox --install -s bin/
9 # Supply missing stuff (e.g. bzip2):
10 PATH="$PATH:$PWD/bin"
11 # Override known-buggy host binaries:
12 cp -af bin/od `which od`
13}
14
15(
16 #set -e -x
17 cd busybox
18
19 make defconfig
20 # Want static build
21 sed 's/^.*CONFIG_STATIC.*$/CONFIG_STATIC=y/' -i .config
22 bzip2 </dev/null >/dev/null || {
23 # Drats, newer Aboriginal Linux has no bzip2
24 sed 's/^.*CONFIG_FEATURE_COMPRESS_USAGE.*$/# CONFIG_FEATURE_COMPRESS_USAGE is not set/' -i .config
25 }
26 test x"`uname -m`" = x"mips" && {
27 # Without this, I get MIPS-I binary instead of MIPS32.
28 # No idea what's the difference, but my router wants MIPS32.
29 sed 's/^.*CONFIG_EXTRA_CFLAGS.*$/CONFIG_EXTRA_CFLAGS="-mips32"/' -i .config
30 }
31 # These won't build because of toolchain/libc breakage:
32 sed 's/^.*CONFIG_FEATURE_SYNC_FANCY.*$/# CONFIG_FEATURE_SYNC_FANCY is not set/' -i .config # no syncfs()
33 sed 's/^.*CONFIG_FEATURE_WTMP.*$/# CONFIG_FEATURE_WTMP is not set/' -i .config
34 sed 's/^.*CONFIG_FEATURE_UTMP.*$/# CONFIG_FEATURE_UTMP is not set/' -i .config
35 sed 's/^.*CONFIG_FEATURE_INETD_RPC.*$/# CONFIG_FEATURE_INETD_RPC is not set/' -i .config
36
37 make #V=1 || sh
38 size busybox
39 ./busybox || echo "Exit code: $?"
40 if uuencode TEST </dev/null >/dev/null && bzip2 </dev/null >/dev/null; then
41 bzip2 <busybox | uuencode busybox.bz2
42 else
43 od -v -tx1 <busybox
44 fi
45 #test "x$FTP_PORT" = x ||
46 # ftpput -P "$FTP_PORT" "$FTP_SERVER" strace
47) 2>&1 | tee build.log
48mount -o remount,ro /home
49sync
50sleep 1
diff --git a/qemu_multiarch_testing/hdc.dir/init b/qemu_multiarch_testing/hdc.dir/init
new file mode 100755
index 000000000..692371db6
--- /dev/null
+++ b/qemu_multiarch_testing/hdc.dir/init
@@ -0,0 +1,9 @@
1#!/bin/sh
2
3# Emit a msg to let user know this place was reached
4echo "Copying to /home"
5# Had a case where cp SEGVs, let's have diagnostics for it
6cp -a /mnt /home || { echo "cp: $?"; exit 1; }
7cd /home/mnt || { echo "cd: $?"; exit 1; }
8exec ./build
9echo "Failed to exec ./build"
diff --git a/qemu_multiarch_testing/make-hdc-img.sh b/qemu_multiarch_testing/make-hdc-img.sh
new file mode 100755
index 000000000..3c35f4ead
--- /dev/null
+++ b/qemu_multiarch_testing/make-hdc-img.sh
@@ -0,0 +1,30 @@
1#!/bin/sh -ex
2
3mountpoint -q /
4[ ! -e hdc.img.dir ]
5
6cleanup()
7{
8 trap - EXIT
9 if mountpoint -q hdc.img.dir; then
10 umount -d hdc.img.dir
11 fi
12 mountpoint -q hdc.img.dir ||
13 rm -rf hdc.img.dir
14 exit $@
15}
16
17trap 'cleanup $?' EXIT
18trap 'cleanup 1' HUP PIPE INT QUIT TERM
19
20size=$(du -ks hdc.dir | sed -rn 's/^([0-9]+).*/\1/p')
21[ "$size" -gt 0 ]
22
23rm -f hdc.img
24dd if=/dev/zero of=hdc.img count=1 bs=1024 seek=$(($size*2))
25mkfs.ext3 -q -F -b 1024 -i 4096 hdc.img
26tune2fs -c 0 -i 0 hdc.img
27mkdir hdc.img.dir
28mount -o loop hdc.img hdc.img.dir
29cp -a hdc.dir/* hdc.img.dir/
30umount -d hdc.img.dir
diff --git a/qemu_multiarch_testing/parallel-build-hdc-img.sh b/qemu_multiarch_testing/parallel-build-hdc-img.sh
new file mode 100755
index 000000000..9ee54ebb8
--- /dev/null
+++ b/qemu_multiarch_testing/parallel-build-hdc-img.sh
@@ -0,0 +1,40 @@
1#!/bin/sh
2
3export HDBMEGS=100
4keep_hdb=false
5
6build_in_dir()
7{
8 cd "$1" || exit 1
9 rm -f hdb.img
10 nice -n10 time ./native-build.sh ../hdc.img
11 $keep_hdb || rm -f hdb.img
12 echo >&3 "Finished: $1"
13}
14
15test "$1" = "-s" && {
16 dir="$2"
17 # single mode: build one directory, show output
18 test -d "$dir" || exit 1
19 test -e "$dir/native-build.sh" || exit 1
20 build_in_dir "$dir"
21 exit $?
22}
23
24started=false
25for dir; do
26 test -d "$dir" || continue
27 test -e "$dir/native-build.sh" || continue
28 echo "Starting: $dir"
29 build_in_dir "$dir" 3>&1 </dev/null >"$dir.log" 2>&1 &
30 started=true
31done
32
33$started || {
34 echo "Give me system-image-ARCH directories on command line"
35 exit 1
36}
37
38echo "Waiting to finish"
39wait
40echo "Done, check the logs"
diff --git a/runit/runsv.c b/runit/runsv.c
index d941e897d..6cf5bcc29 100644
--- a/runit/runsv.c
+++ b/runit/runsv.c
@@ -49,16 +49,11 @@ static void gettimeofday_ns(struct timespec *ts)
49#else 49#else
50static void gettimeofday_ns(struct timespec *ts) 50static void gettimeofday_ns(struct timespec *ts)
51{ 51{
52 if (sizeof(struct timeval) == sizeof(struct timespec) 52 BUILD_BUG_ON(sizeof(struct timeval) != sizeof(struct timespec));
53 && sizeof(((struct timeval*)ts)->tv_usec) == sizeof(ts->tv_nsec) 53 BUILD_BUG_ON(sizeof(((struct timeval*)ts)->tv_usec) != sizeof(ts->tv_nsec));
54 ) { 54 /* Cheat */
55 /* Cheat */ 55 gettimeofday((void*)ts, NULL);
56 gettimeofday((void*)ts, NULL); 56 ts->tv_nsec *= 1000;
57 ts->tv_nsec *= 1000;
58 } else {
59 extern void BUG_need_to_implement_gettimeofday_ns(void);
60 BUG_need_to_implement_gettimeofday_ns();
61 }
62} 57}
63#endif 58#endif
64 59
@@ -114,7 +109,7 @@ struct globals {
114 109
115static void fatal2_cannot(const char *m1, const char *m2) 110static void fatal2_cannot(const char *m1, const char *m2)
116{ 111{
117 bb_perror_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2); 112 bb_perror_msg_and_die("%s: fatal: can't %s%s", dir, m1, m2);
118 /* was exiting 111 */ 113 /* was exiting 111 */
119} 114}
120static void fatal_cannot(const char *m) 115static void fatal_cannot(const char *m)
@@ -124,7 +119,7 @@ static void fatal_cannot(const char *m)
124} 119}
125static void fatal2x_cannot(const char *m1, const char *m2) 120static void fatal2x_cannot(const char *m1, const char *m2)
126{ 121{
127 bb_error_msg_and_die("%s: fatal: cannot %s%s", dir, m1, m2); 122 bb_error_msg_and_die("%s: fatal: can't %s%s", dir, m1, m2);
128 /* was exiting 111 */ 123 /* was exiting 111 */
129} 124}
130static void warn_cannot(const char *m) 125static void warn_cannot(const char *m)
diff --git a/scripts/randomtest b/scripts/randomtest
index d2b26bc76..e2513d058 100755
--- a/scripts/randomtest
+++ b/scripts/randomtest
@@ -65,14 +65,16 @@ if test x"$LIBC" = x"uclibc"; then
65 | grep -v CONFIG_BUILD_LIBBUSYBOX \ 65 | grep -v CONFIG_BUILD_LIBBUSYBOX \
66 | grep -v CONFIG_PIE \ 66 | grep -v CONFIG_PIE \
67 \ 67 \
68 | grep -v CONFIG_FEATURE_TOUCH_NODEREF \
69 | grep -v CONFIG_FEATURE_2_4_MODULES \ 68 | grep -v CONFIG_FEATURE_2_4_MODULES \
69 | grep -v CONFIG_FEATURE_SYNC_FANCY \
70 | grep -v CONFIG_FEATURE_TOUCH_NODEREF \
70 >.config.new 71 >.config.new
71 mv .config.new .config 72 mv .config.new .config
72 echo 'CONFIG_STATIC=y' >>.config 73 echo 'CONFIG_STATIC=y' >>.config
73 echo '# CONFIG_BUILD_LIBBUSYBOX is not set' >>.config 74 echo '# CONFIG_BUILD_LIBBUSYBOX is not set' >>.config
74 echo '# CONFIG_PIE is not set' >>.config 75 echo '# CONFIG_PIE is not set' >>.config
75 echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config 76 echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config
77 echo '# CONFIG_FEATURE_SYNC_FANCY is not set' >>.config
76 echo '# CONFIG_FEATURE_TOUCH_NODEREF is not set' >>.config 78 echo '# CONFIG_FEATURE_TOUCH_NODEREF is not set' >>.config
77fi 79fi
78 80
diff --git a/shell/ash.c b/shell/ash.c
index e9850f493..21fc05f01 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -607,11 +607,12 @@ flush_stdout_stderr(void)
607 INT_ON; 607 INT_ON;
608} 608}
609 609
610/* Was called outcslow(c,FILE*), but c was always '\n' */
610static void 611static void
611outcslow(int c, FILE *dest) 612newline_and_flush(FILE *dest)
612{ 613{
613 INT_OFF; 614 INT_OFF;
614 putc(c, dest); 615 putc('\n', dest);
615 fflush(dest); 616 fflush(dest);
616 INT_ON; 617 INT_ON;
617} 618}
@@ -1272,7 +1273,7 @@ ash_vmsg(const char *msg, va_list ap)
1272 fprintf(stderr, "line %d: ", startlinno); 1273 fprintf(stderr, "line %d: ", startlinno);
1273 } 1274 }
1274 vfprintf(stderr, msg, ap); 1275 vfprintf(stderr, msg, ap);
1275 outcslow('\n', stderr); 1276 newline_and_flush(stderr);
1276} 1277}
1277 1278
1278/* 1279/*
@@ -3528,6 +3529,7 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3528#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */ 3529#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3529#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */ 3530#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3530#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */ 3531#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
3532#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
3531 3533
3532/* 3534/*
3533 * A job structure contains information about a job. A job is either a 3535 * A job structure contains information about a job. A job is either a
@@ -4046,7 +4048,7 @@ showpipe(struct job *jp /*, FILE *out*/)
4046 psend = jp->ps + jp->nprocs; 4048 psend = jp->ps + jp->nprocs;
4047 for (ps = jp->ps + 1; ps < psend; ps++) 4049 for (ps = jp->ps + 1; ps < psend; ps++)
4048 printf(" | %s", ps->ps_cmd); 4050 printf(" | %s", ps->ps_cmd);
4049 outcslow('\n', stdout); 4051 newline_and_flush(stdout);
4050 flush_stdout_stderr(); 4052 flush_stdout_stderr();
4051} 4053}
4052 4054
@@ -4106,39 +4108,33 @@ fg_bgcmd(int argc UNUSED_PARAM, char **argv)
4106#endif 4108#endif
4107 4109
4108static int 4110static int
4109sprint_status(char *s, int status, int sigonly) 4111sprint_status48(char *s, int status, int sigonly)
4110{ 4112{
4111 int col; 4113 int col;
4112 int st; 4114 int st;
4113 4115
4114 col = 0; 4116 col = 0;
4115 if (!WIFEXITED(status)) { 4117 if (!WIFEXITED(status)) {
4116#if JOBS 4118 if (JOBS && WIFSTOPPED(status))
4117 if (WIFSTOPPED(status))
4118 st = WSTOPSIG(status); 4119 st = WSTOPSIG(status);
4119 else 4120 else
4120#endif
4121 st = WTERMSIG(status); 4121 st = WTERMSIG(status);
4122 if (sigonly) { 4122 if (sigonly) {
4123 if (st == SIGINT || st == SIGPIPE) 4123 if (st == SIGINT || st == SIGPIPE)
4124 goto out; 4124 goto out;
4125#if JOBS 4125 if (JOBS && WIFSTOPPED(status))
4126 if (WIFSTOPPED(status))
4127 goto out; 4126 goto out;
4128#endif
4129 } 4127 }
4130 st &= 0x7f; 4128 st &= 0x7f;
4131//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata 4129//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
4132 col = fmtstr(s, 32, strsignal(st)); 4130 col = fmtstr(s, 32, strsignal(st));
4133 if (WCOREDUMP(status)) { 4131 if (WCOREDUMP(status)) {
4134 col += fmtstr(s + col, 16, " (core dumped)"); 4132 strcpy(s + col, " (core dumped)");
4133 col += sizeof(" (core dumped)")-1;
4135 } 4134 }
4136 } else if (!sigonly) { 4135 } else if (!sigonly) {
4137 st = WEXITSTATUS(status); 4136 st = WEXITSTATUS(status);
4138 if (st) 4137 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
4139 col = fmtstr(s, 16, "Done(%d)", st);
4140 else
4141 col = fmtstr(s, 16, "Done");
4142 } 4138 }
4143 out: 4139 out:
4144 return col; 4140 return col;
@@ -4224,7 +4220,6 @@ dowait(int wait_flags, struct job *job)
4224 int status; 4220 int status;
4225 struct job *jp; 4221 struct job *jp;
4226 struct job *thisjob; 4222 struct job *thisjob;
4227 int state;
4228 4223
4229 TRACE(("dowait(0x%x) called\n", wait_flags)); 4224 TRACE(("dowait(0x%x) called\n", wait_flags));
4230 4225
@@ -4246,11 +4241,12 @@ dowait(int wait_flags, struct job *job)
4246 INT_OFF; 4241 INT_OFF;
4247 thisjob = NULL; 4242 thisjob = NULL;
4248 for (jp = curjob; jp; jp = jp->prev_job) { 4243 for (jp = curjob; jp; jp = jp->prev_job) {
4244 int jobstate;
4249 struct procstat *ps; 4245 struct procstat *ps;
4250 struct procstat *psend; 4246 struct procstat *psend;
4251 if (jp->state == JOBDONE) 4247 if (jp->state == JOBDONE)
4252 continue; 4248 continue;
4253 state = JOBDONE; 4249 jobstate = JOBDONE;
4254 ps = jp->ps; 4250 ps = jp->ps;
4255 psend = ps + jp->nprocs; 4251 psend = ps + jp->nprocs;
4256 do { 4252 do {
@@ -4264,41 +4260,41 @@ dowait(int wait_flags, struct job *job)
4264 ps->ps_pid = -1; 4260 ps->ps_pid = -1;
4265 } 4261 }
4266 if (ps->ps_status == -1) 4262 if (ps->ps_status == -1)
4267 state = JOBRUNNING; 4263 jobstate = JOBRUNNING;
4268#if JOBS 4264#if JOBS
4269 if (state == JOBRUNNING) 4265 if (jobstate == JOBRUNNING)
4270 continue; 4266 continue;
4271 if (WIFSTOPPED(ps->ps_status)) { 4267 if (WIFSTOPPED(ps->ps_status)) {
4272 jp->stopstatus = ps->ps_status; 4268 jp->stopstatus = ps->ps_status;
4273 state = JOBSTOPPED; 4269 jobstate = JOBSTOPPED;
4274 } 4270 }
4275#endif 4271#endif
4276 } while (++ps < psend); 4272 } while (++ps < psend);
4277 if (thisjob) 4273 if (!thisjob)
4278 goto gotjob; 4274 continue;
4279 }
4280#if JOBS
4281 if (!WIFSTOPPED(status))
4282#endif
4283 jobless--;
4284 goto out;
4285
4286 gotjob:
4287 if (state != JOBRUNNING) {
4288 thisjob->changed = 1;
4289 4275
4290 if (thisjob->state != state) { 4276 /* Found the job where one of its processes changed its state.
4291 TRACE(("Job %d: changing state from %d to %d\n", 4277 * Is there at least one live and running process in this job? */
4292 jobno(thisjob), thisjob->state, state)); 4278 if (jobstate != JOBRUNNING) {
4293 thisjob->state = state; 4279 /* No. All live processes in the job are stopped
4280 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4281 */
4282 thisjob->changed = 1;
4283 if (thisjob->state != jobstate) {
4284 TRACE(("Job %d: changing state from %d to %d\n",
4285 jobno(thisjob), thisjob->state, jobstate));
4286 thisjob->state = jobstate;
4294#if JOBS 4287#if JOBS
4295 if (state == JOBSTOPPED) { 4288 if (jobstate == JOBSTOPPED)
4296 set_curjob(thisjob, CUR_STOPPED); 4289 set_curjob(thisjob, CUR_STOPPED);
4297 }
4298#endif 4290#endif
4291 }
4299 } 4292 }
4293 goto out;
4300 } 4294 }
4301 4295 /* The process wasn't found in job list */
4296 if (JOBS && !WIFSTOPPED(status))
4297 jobless--;
4302 out: 4298 out:
4303 INT_ON; 4299 INT_ON;
4304 4300
@@ -4306,7 +4302,7 @@ dowait(int wait_flags, struct job *job)
4306 char s[48 + 1]; 4302 char s[48 + 1];
4307 int len; 4303 int len;
4308 4304
4309 len = sprint_status(s, status, 1); 4305 len = sprint_status48(s, status, 1);
4310 if (len) { 4306 if (len) {
4311 s[len] = '\n'; 4307 s[len] = '\n';
4312 s[len + 1] = '\0'; 4308 s[len + 1] = '\0';
@@ -4327,13 +4323,14 @@ blocking_wait_with_raise_on_sig(void)
4327 4323
4328#if JOBS 4324#if JOBS
4329static void 4325static void
4330showjob(FILE *out, struct job *jp, int mode) 4326showjob(struct job *jp, int mode)
4331{ 4327{
4332 struct procstat *ps; 4328 struct procstat *ps;
4333 struct procstat *psend; 4329 struct procstat *psend;
4334 int col; 4330 int col;
4335 int indent_col; 4331 int indent_col;
4336 char s[80]; 4332 char s[16 + 16 + 48];
4333 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
4337 4334
4338 ps = jp->ps; 4335 ps = jp->ps;
4339 4336
@@ -4363,7 +4360,7 @@ showjob(FILE *out, struct job *jp, int mode)
4363 int status = psend[-1].ps_status; 4360 int status = psend[-1].ps_status;
4364 if (jp->state == JOBSTOPPED) 4361 if (jp->state == JOBSTOPPED)
4365 status = jp->stopstatus; 4362 status = jp->stopstatus;
4366 col += sprint_status(s + col, status, 0); 4363 col += sprint_status48(s + col, status, 0);
4367 } 4364 }
4368 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */ 4365 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
4369 4366
@@ -4390,7 +4387,7 @@ showjob(FILE *out, struct job *jp, int mode)
4390 ps->ps_cmd 4387 ps->ps_cmd
4391 ); 4388 );
4392 } while (++ps != psend); 4389 } while (++ps != psend);
4393 outcslow('\n', out); 4390 newline_and_flush(out);
4394 4391
4395 jp->changed = 0; 4392 jp->changed = 0;
4396 4393
@@ -4405,7 +4402,7 @@ showjob(FILE *out, struct job *jp, int mode)
4405 * statuses have changed since the last call to showjobs. 4402 * statuses have changed since the last call to showjobs.
4406 */ 4403 */
4407static void 4404static void
4408showjobs(FILE *out, int mode) 4405showjobs(int mode)
4409{ 4406{
4410 struct job *jp; 4407 struct job *jp;
4411 4408
@@ -4417,7 +4414,7 @@ showjobs(FILE *out, int mode)
4417 4414
4418 for (jp = curjob; jp; jp = jp->prev_job) { 4415 for (jp = curjob; jp; jp = jp->prev_job) {
4419 if (!(mode & SHOW_CHANGED) || jp->changed) { 4416 if (!(mode & SHOW_CHANGED) || jp->changed) {
4420 showjob(out, jp, mode); 4417 showjob(jp, mode);
4421 } 4418 }
4422 } 4419 }
4423} 4420}
@@ -4438,10 +4435,10 @@ jobscmd(int argc UNUSED_PARAM, char **argv)
4438 argv = argptr; 4435 argv = argptr;
4439 if (*argv) { 4436 if (*argv) {
4440 do 4437 do
4441 showjob(stdout, getjob(*argv, 0), mode); 4438 showjob(getjob(*argv, 0), mode);
4442 while (*++argv); 4439 while (*++argv);
4443 } else { 4440 } else {
4444 showjobs(stdout, mode); 4441 showjobs(mode);
4445 } 4442 }
4446 4443
4447 return 0; 4444 return 0;
@@ -5894,8 +5891,8 @@ cvtnum(arith_t num)
5894{ 5891{
5895 int len; 5892 int len;
5896 5893
5897 expdest = makestrspace(32, expdest); 5894 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5898 len = fmtstr(expdest, 32, ARITH_FMT, num); 5895 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
5899 STADJUST(len, expdest); 5896 STADJUST(len, expdest);
5900 return len; 5897 return len;
5901} 5898}
@@ -7326,10 +7323,11 @@ expmeta(char *expdir, char *enddir, char *name)
7326 struct dirent *dp; 7323 struct dirent *dp;
7327 int atend; 7324 int atend;
7328 int matchdot; 7325 int matchdot;
7326 int esc;
7329 7327
7330 metaflag = 0; 7328 metaflag = 0;
7331 start = name; 7329 start = name;
7332 for (p = name; *p; p++) { 7330 for (p = name; esc = 0, *p; p += esc + 1) {
7333 if (*p == '*' || *p == '?') 7331 if (*p == '*' || *p == '?')
7334 metaflag = 1; 7332 metaflag = 1;
7335 else if (*p == '[') { 7333 else if (*p == '[') {
@@ -7346,15 +7344,16 @@ expmeta(char *expdir, char *enddir, char *name)
7346 break; 7344 break;
7347 } 7345 }
7348 } 7346 }
7349 } else if (*p == '\\') 7347 } else {
7350 p++; 7348 if (*p == '\\')
7351 else if (*p == '/') { 7349 esc++;
7352 if (metaflag) 7350 if (p[esc] == '/') {
7353 goto out; 7351 if (metaflag)
7354 start = p + 1; 7352 break;
7353 start = p + esc + 1;
7354 }
7355 } 7355 }
7356 } 7356 }
7357 out:
7358 if (metaflag == 0) { /* we've reached the end of the file name */ 7357 if (metaflag == 0) { /* we've reached the end of the file name */
7359 if (enddir != expdir) 7358 if (enddir != expdir)
7360 metaflag++; 7359 metaflag++;
@@ -7394,7 +7393,8 @@ expmeta(char *expdir, char *enddir, char *name)
7394 atend = 1; 7393 atend = 1;
7395 } else { 7394 } else {
7396 atend = 0; 7395 atend = 0;
7397 *endname++ = '\0'; 7396 *endname = '\0';
7397 endname += esc + 1;
7398 } 7398 }
7399 matchdot = 0; 7399 matchdot = 0;
7400 p = start; 7400 p = start;
@@ -7419,7 +7419,7 @@ expmeta(char *expdir, char *enddir, char *name)
7419 } 7419 }
7420 closedir(dirp); 7420 closedir(dirp);
7421 if (!atend) 7421 if (!atend)
7422 endname[-1] = '/'; 7422 endname[-esc - 1] = esc ? '\\' : '/';
7423} 7423}
7424 7424
7425static struct strlist * 7425static struct strlist *
@@ -10118,7 +10118,7 @@ preadfd(void)
10118 } 10118 }
10119# if ENABLE_ASH_IDLE_TIMEOUT 10119# if ENABLE_ASH_IDLE_TIMEOUT
10120 else if (errno == EAGAIN && timeout > 0) { 10120 else if (errno == EAGAIN && timeout > 0) {
10121 printf("\007timed out waiting for input: auto-logout\n"); 10121 puts("\007timed out waiting for input: auto-logout");
10122 exitshell(); 10122 exitshell();
10123 } 10123 }
10124# endif 10124# endif
@@ -10472,10 +10472,8 @@ setinputstring(char *string)
10472 10472
10473#if ENABLE_ASH_MAIL 10473#if ENABLE_ASH_MAIL
10474 10474
10475#define MAXMBOXES 10 10475/* Hash of mtimes of mailboxes */
10476 10476static unsigned mailtime_hash;
10477/* times of mailboxes */
10478static time_t mailtime[MAXMBOXES];
10479/* Set if MAIL or MAILPATH is changed. */ 10477/* Set if MAIL or MAILPATH is changed. */
10480static smallint mail_var_path_changed; 10478static smallint mail_var_path_changed;
10481 10479
@@ -10491,13 +10489,14 @@ chkmail(void)
10491 const char *mpath; 10489 const char *mpath;
10492 char *p; 10490 char *p;
10493 char *q; 10491 char *q;
10494 time_t *mtp; 10492 unsigned new_hash;
10495 struct stackmark smark; 10493 struct stackmark smark;
10496 struct stat statb; 10494 struct stat statb;
10497 10495
10498 setstackmark(&smark); 10496 setstackmark(&smark);
10499 mpath = mpathset() ? mpathval() : mailval(); 10497 mpath = mpathset() ? mpathval() : mailval();
10500 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) { 10498 new_hash = 0;
10499 for (;;) {
10501 p = path_advance(&mpath, nullstr); 10500 p = path_advance(&mpath, nullstr);
10502 if (p == NULL) 10501 if (p == NULL)
10503 break; 10502 break;
@@ -10511,16 +10510,15 @@ chkmail(void)
10511#endif 10510#endif
10512 q[-1] = '\0'; /* delete trailing '/' */ 10511 q[-1] = '\0'; /* delete trailing '/' */
10513 if (stat(p, &statb) < 0) { 10512 if (stat(p, &statb) < 0) {
10514 *mtp = 0;
10515 continue; 10513 continue;
10516 } 10514 }
10517 if (!mail_var_path_changed && statb.st_mtime != *mtp) { 10515 /* Very simplistic "hash": just a sum of all mtimes */
10518 fprintf( 10516 new_hash += (unsigned)statb.st_mtime;
10519 stderr, "%s\n", 10517 }
10520 pathopt ? pathopt : "you have mail" 10518 if (!mail_var_path_changed && mailtime_hash != new_hash) {
10521 ); 10519 if (mailtime_hash != 0)
10522 } 10520 out2str("you have mail\n");
10523 *mtp = statb.st_mtime; 10521 mailtime_hash = new_hash;
10524 } 10522 }
10525 mail_var_path_changed = 0; 10523 mail_var_path_changed = 0;
10526 popstackmark(&smark); 10524 popstackmark(&smark);
@@ -10792,9 +10790,11 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt
10792 char c = '?'; 10790 char c = '?';
10793 int done = 0; 10791 int done = 0;
10794 int err = 0; 10792 int err = 0;
10795 char s[12]; 10793 char sbuf[2];
10796 char **optnext; 10794 char **optnext;
10797 10795
10796 sbuf[1] = '\0';
10797
10798 if (*param_optind < 1) 10798 if (*param_optind < 1)
10799 return 1; 10799 return 1;
10800 optnext = optfirst + *param_optind - 1; 10800 optnext = optfirst + *param_optind - 1;
@@ -10821,9 +10821,9 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt
10821 for (q = optstr; *q != c;) { 10821 for (q = optstr; *q != c;) {
10822 if (*q == '\0') { 10822 if (*q == '\0') {
10823 if (optstr[0] == ':') { 10823 if (optstr[0] == ':') {
10824 s[0] = c; 10824 sbuf[0] = c;
10825 s[1] = '\0'; 10825 /*sbuf[1] = '\0'; - already is */
10826 err |= setvarsafe("OPTARG", s, 0); 10826 err |= setvarsafe("OPTARG", sbuf, 0);
10827 } else { 10827 } else {
10828 fprintf(stderr, "Illegal option -%c\n", c); 10828 fprintf(stderr, "Illegal option -%c\n", c);
10829 unsetvar("OPTARG"); 10829 unsetvar("OPTARG");
@@ -10838,9 +10838,9 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt
10838 if (*++q == ':') { 10838 if (*++q == ':') {
10839 if (*p == '\0' && (p = *optnext) == NULL) { 10839 if (*p == '\0' && (p = *optnext) == NULL) {
10840 if (optstr[0] == ':') { 10840 if (optstr[0] == ':') {
10841 s[0] = c; 10841 sbuf[0] = c;
10842 s[1] = '\0'; 10842 /*sbuf[1] = '\0'; - already is */
10843 err |= setvarsafe("OPTARG", s, 0); 10843 err |= setvarsafe("OPTARG", sbuf, 0);
10844 c = ':'; 10844 c = ':';
10845 } else { 10845 } else {
10846 fprintf(stderr, "No arg for -%c option\n", c); 10846 fprintf(stderr, "No arg for -%c option\n", c);
@@ -10859,11 +10859,10 @@ getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *opt
10859 out: 10859 out:
10860 *optoff = p ? p - *(optnext - 1) : -1; 10860 *optoff = p ? p - *(optnext - 1) : -1;
10861 *param_optind = optnext - optfirst + 1; 10861 *param_optind = optnext - optfirst + 1;
10862 fmtstr(s, sizeof(s), "%d", *param_optind); 10862 err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC);
10863 err |= setvarsafe("OPTIND", s, VNOFUNC); 10863 sbuf[0] = c;
10864 s[0] = c; 10864 /*sbuf[1] = '\0'; - already is */
10865 s[1] = '\0'; 10865 err |= setvarsafe(optvar, sbuf, 0);
10866 err |= setvarsafe(optvar, s, 0);
10867 if (err) { 10866 if (err) {
10868 *param_optind = 1; 10867 *param_optind = 1;
10869 *optoff = -1; 10868 *optoff = -1;
@@ -12559,7 +12558,7 @@ cmdloop(int top)
12559 setstackmark(&smark); 12558 setstackmark(&smark);
12560#if JOBS 12559#if JOBS
12561 if (doing_jobctl) 12560 if (doing_jobctl)
12562 showjobs(stderr, SHOW_CHANGED); 12561 showjobs(SHOW_CHANGED|SHOW_STDERR);
12563#endif 12562#endif
12564 inter = 0; 12563 inter = 0;
12565 if (iflag && top) { 12564 if (iflag && top) {
@@ -13298,21 +13297,11 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13298} 13297}
13299 13298
13300static int FAST_FUNC 13299static int FAST_FUNC
13301umaskcmd(int argc UNUSED_PARAM, char **argv) 13300umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
13302{ 13301{
13303 static const char permuser[3] ALIGN1 = "ugo"; 13302 static const char permuser[3] ALIGN1 = "ogu";
13304 static const char permmode[3] ALIGN1 = "rwx";
13305 static const short permmask[] ALIGN2 = {
13306 S_IRUSR, S_IWUSR, S_IXUSR,
13307 S_IRGRP, S_IWGRP, S_IXGRP,
13308 S_IROTH, S_IWOTH, S_IXOTH
13309 };
13310
13311 /* TODO: use bb_parse_mode() instead */
13312 13303
13313 char *ap;
13314 mode_t mask; 13304 mode_t mask;
13315 int i;
13316 int symbolic_mode = 0; 13305 int symbolic_mode = 0;
13317 13306
13318 while (nextopt("S") != '\0') { 13307 while (nextopt("S") != '\0') {
@@ -13324,45 +13313,43 @@ umaskcmd(int argc UNUSED_PARAM, char **argv)
13324 umask(mask); 13313 umask(mask);
13325 INT_ON; 13314 INT_ON;
13326 13315
13327 ap = *argptr; 13316 if (*argptr == NULL) {
13328 if (ap == NULL) {
13329 if (symbolic_mode) { 13317 if (symbolic_mode) {
13330 char buf[18]; 13318 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
13331 char *p = buf; 13319 char *p = buf;
13320 int i;
13332 13321
13333 for (i = 0; i < 3; i++) { 13322 i = 2;
13334 int j; 13323 for (;;) {
13335 13324 *p++ = ',';
13336 *p++ = permuser[i]; 13325 *p++ = permuser[i];
13337 *p++ = '='; 13326 *p++ = '=';
13338 for (j = 0; j < 3; j++) { 13327 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
13339 if ((mask & permmask[3 * i + j]) == 0) { 13328 if (!(mask & 0400)) *p++ = 'r';
13340 *p++ = permmode[j]; 13329 if (!(mask & 0200)) *p++ = 'w';
13341 } 13330 if (!(mask & 0100)) *p++ = 'x';
13342 } 13331 mask <<= 3;
13343 *p++ = ','; 13332 if (--i < 0)
13333 break;
13344 } 13334 }
13345 *--p = 0; 13335 *p = '\0';
13346 puts(buf); 13336 puts(buf + 1);
13347 } else { 13337 } else {
13348 out1fmt("%.4o\n", mask); 13338 out1fmt("%04o\n", mask);
13349 } 13339 }
13350 } else { 13340 } else {
13351 if (isdigit((unsigned char) *ap)) { 13341 char *modestr = *argptr;
13352 mask = 0; 13342 /* numeric umasks are taken as-is */
13353 do { 13343 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13354 if (*ap >= '8' || *ap < '0') 13344 if (!isdigit(modestr[0]))
13355 ash_msg_and_raise_error(msg_illnum, argv[1]); 13345 mask ^= 0777;
13356 mask = (mask << 3) + (*ap - '0'); 13346 mask = bb_parse_mode(modestr, mask);
13357 } while (*++ap != '\0'); 13347 if ((unsigned)mask > 0777) {
13358 umask(mask); 13348 ash_msg_and_raise_error("illegal mode: %s", modestr);
13359 } else { 13349 }
13360 mask = ~mask & 0777; 13350 if (!isdigit(modestr[0]))
13361 if (!bb_parse_mode(ap, &mask)) { 13351 mask ^= 0777;
13362 ash_msg_and_raise_error("illegal mode: %s", ap); 13352 umask(mask);
13363 }
13364 umask(~mask & 0777);
13365 }
13366 } 13353 }
13367 return 0; 13354 return 0;
13368} 13355}
@@ -13713,7 +13700,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13713 exitshell(); 13700 exitshell();
13714 } 13701 }
13715 if (e == EXINT) { 13702 if (e == EXINT) {
13716 outcslow('\n', stderr); 13703 newline_and_flush(stderr);
13717 } 13704 }
13718 13705
13719 popstackmark(&smark); 13706 popstackmark(&smark);
diff --git a/shell/ash_test/ash-glob/glob1.right b/shell/ash_test/ash-glob/glob1.right
new file mode 100644
index 000000000..f29ab4e65
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob1.right
@@ -0,0 +1,2 @@
1glob1.tests
2glob1.tests
diff --git a/shell/ash_test/ash-glob/glob1.tests b/shell/ash_test/ash-glob/glob1.tests
new file mode 100755
index 000000000..f980ce064
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob1.tests
@@ -0,0 +1,2 @@
1echo *glob1?t[e]sts*
2echo "glob1"?'t'[e]s*
diff --git a/shell/ash_test/ash-glob/glob2.right b/shell/ash_test/ash-glob/glob2.right
new file mode 100644
index 000000000..7a70c2263
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob2.right
@@ -0,0 +1,18 @@
1Expected Actual
2Z\* : Z\*
3Z* : Z*
4Z\f : Z\f
5Z\* : Z\*
6
7Z\z : Z\z
8Zz : Zz
9Z\z : Z\z
10Z\z : Z\z
11
12Z\ : Z\
13Z\ : Z\
14
15Z\f Zf : Z\f Zf
16Z\f Zf : Z\f Zf
17
18Done: 0
diff --git a/shell/ash_test/ash-glob/glob2.tests b/shell/ash_test/ash-glob/glob2.tests
new file mode 100755
index 000000000..00618b9db
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob2.tests
@@ -0,0 +1,27 @@
1# This test demonstrates that in unquoted $v, backslashes expand by this rule:
2# \z -> \\\z; \<eol> -> \\<eol> (for any z, special or not),
3# and subsequently globbing converts \\ to \ and treats \z as literal z
4# even if it is a special char.
5
6>'Zf'
7>'Z\f'
8 echo 'Expected' 'Actual'
9v='\*'; echo 'Z\* :' Z$v # ash is buggy here: prints 'Z\f'
10 echo 'Z* :' Z\*
11 echo 'Z\f :' Z\\*
12 echo 'Z\* :' Z\\\* # NB! only this matches Z$v output
13echo
14v='\z'; echo 'Z\z :' Z$v
15 echo 'Zz :' Z\z
16 echo 'Z\z :' Z\\z
17 echo 'Z\z :' Z\\\z
18echo
19v='\'; echo 'Z\ :' Z$v
20 echo 'Z\ :' Z\\
21echo
22v='*'; echo 'Z\f Zf :' Z$v
23 echo 'Z\f Zf :' Z*
24echo
25
26rm 'Z\f' 'Zf'
27echo Done: $?
diff --git a/shell/ash_test/ash-glob/glob3.right b/shell/ash_test/ash-glob/glob3.right
new file mode 100644
index 000000000..161b589e0
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob3.right
@@ -0,0 +1,2 @@
1glob3.tests
2./glob3.tests
diff --git a/shell/ash_test/ash-glob/glob3.tests b/shell/ash_test/ash-glob/glob3.tests
new file mode 100755
index 000000000..bdf54001e
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob3.tests
@@ -0,0 +1,2 @@
1echo "glob3.test"*
2echo "./glob3.test"*
diff --git a/shell/ash_test/ash-glob/glob_and_assign.right b/shell/ash_test/ash-glob/glob_and_assign.right
new file mode 100644
index 000000000..d46e44363
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob_and_assign.right
@@ -0,0 +1,6 @@
1ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp
2ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp
3*.tmp
4ZVAR=z.tmp z.tmp
5ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp
6ZVAR=z.tmp ZVAR=*.tmp ZVAR=[z].tmp
diff --git a/shell/ash_test/ash-glob/glob_and_assign.tests b/shell/ash_test/ash-glob/glob_and_assign.tests
new file mode 100755
index 000000000..0b158f20f
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob_and_assign.tests
@@ -0,0 +1,10 @@
1>ZVAR=z.tmp
2>z.tmp
3ZVAR=*.tmp echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp"
4ZVAR=*.tmp /bin/echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp"
5ZVAR=*.tmp
6echo "$ZVAR"
7echo $ZVAR
8echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp"
9/bin/echo ZVAR=*.tmp "ZVAR=*.tmp" "ZVAR=[z].tmp"
10rm ZVAR=z.tmp z.tmp
diff --git a/shell/ash_test/ash-glob/glob_redir.right b/shell/ash_test/ash-glob/glob_redir.right
new file mode 100644
index 000000000..fbd0309b0
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob_redir.right
@@ -0,0 +1,2 @@
1z.tmp:
2?.tmp: TEST
diff --git a/shell/ash_test/ash-glob/glob_redir.tests b/shell/ash_test/ash-glob/glob_redir.tests
new file mode 100755
index 000000000..621d12017
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob_redir.tests
@@ -0,0 +1,9 @@
1# Redirections are not globbed.
2# bash:
3# if run as "sh", they are not globbed, but
4# if run as "bash", they are!
5>z.tmp
6echo TEST >?.tmp
7echo 'z.tmp:' `cat 'z.tmp'`
8echo '?.tmp:' `cat '?.tmp'`
9rm 'z.tmp' '?.tmp'
diff --git a/shell/hush.c b/shell/hush.c
index 3ca04494c..eabe83ac6 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1479,10 +1479,11 @@ static sighandler_t install_sighandler(int sig, sighandler_t handler)
1479 1479
1480#if ENABLE_HUSH_JOB 1480#if ENABLE_HUSH_JOB
1481 1481
1482static void xfunc_has_died(void);
1482/* After [v]fork, in child: do not restore tty pgrp on xfunc death */ 1483/* After [v]fork, in child: do not restore tty pgrp on xfunc death */
1483# define disable_restore_tty_pgrp_on_exit() (die_sleep = 0) 1484# define disable_restore_tty_pgrp_on_exit() (die_func = NULL)
1484/* After [v]fork, in parent: restore tty pgrp on xfunc death */ 1485/* After [v]fork, in parent: restore tty pgrp on xfunc death */
1485# define enable_restore_tty_pgrp_on_exit() (die_sleep = -1) 1486# define enable_restore_tty_pgrp_on_exit() (die_func = xfunc_has_died)
1486 1487
1487/* Restores tty foreground process group, and exits. 1488/* Restores tty foreground process group, and exits.
1488 * May be called as signal handler for fatal signal 1489 * May be called as signal handler for fatal signal
@@ -1587,6 +1588,15 @@ static void hush_exit(int exitcode)
1587#endif 1588#endif
1588} 1589}
1589 1590
1591static void xfunc_has_died(void) NORETURN;
1592static void xfunc_has_died(void)
1593{
1594 /* xfunc has failed! die die die */
1595 /* no EXIT traps, this is an escape hatch! */
1596 G.exiting = 1;
1597 hush_exit(xfunc_error_retval);
1598}
1599
1590 1600
1591//TODO: return a mask of ALL handled sigs? 1601//TODO: return a mask of ALL handled sigs?
1592static int check_and_run_traps(void) 1602static int check_and_run_traps(void)
@@ -3161,11 +3171,29 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3161 old->command->group = ctx->list_head; 3171 old->command->group = ctx->list_head;
3162 old->command->cmd_type = CMD_NORMAL; 3172 old->command->cmd_type = CMD_NORMAL;
3163# if !BB_MMU 3173# if !BB_MMU
3164 o_addstr(&old->as_string, ctx->as_string.data); 3174 /* At this point, the compound command's string is in
3165 o_free_unsafe(&ctx->as_string); 3175 * ctx->as_string... except for the leading keyword!
3166 old->command->group_as_string = xstrdup(old->as_string.data); 3176 * Consider this example: "echo a | if true; then echo a; fi"
3167 debug_printf_parse("pop, remembering as:'%s'\n", 3177 * ctx->as_string will contain "true; then echo a; fi",
3168 old->command->group_as_string); 3178 * with "if " remaining in old->as_string!
3179 */
3180 {
3181 char *str;
3182 int len = old->as_string.length;
3183 /* Concatenate halves */
3184 o_addstr(&old->as_string, ctx->as_string.data);
3185 o_free_unsafe(&ctx->as_string);
3186 /* Find where leading keyword starts in first half */
3187 str = old->as_string.data + len;
3188 if (str > old->as_string.data)
3189 str--; /* skip whitespace after keyword */
3190 while (str > old->as_string.data && isalpha(str[-1]))
3191 str--;
3192 /* Ugh, we're done with this horrid hack */
3193 old->command->group_as_string = xstrdup(str);
3194 debug_printf_parse("pop, remembering as:'%s'\n",
3195 old->command->group_as_string);
3196 }
3169# endif 3197# endif
3170 *ctx = *old; /* physical copy */ 3198 *ctx = *old; /* physical copy */
3171 free(old); 3199 free(old);
@@ -4248,7 +4276,7 @@ static struct pipe *parse_stream(char **pstring,
4248 pi = NULL; 4276 pi = NULL;
4249 } 4277 }
4250#if !BB_MMU 4278#if !BB_MMU
4251 debug_printf_parse("as_string '%s'\n", ctx.as_string.data); 4279 debug_printf_parse("as_string1 '%s'\n", ctx.as_string.data);
4252 if (pstring) 4280 if (pstring)
4253 *pstring = ctx.as_string.data; 4281 *pstring = ctx.as_string.data;
4254 else 4282 else
@@ -4399,7 +4427,7 @@ static struct pipe *parse_stream(char **pstring,
4399 ) { 4427 ) {
4400 o_free(&dest); 4428 o_free(&dest);
4401#if !BB_MMU 4429#if !BB_MMU
4402 debug_printf_parse("as_string '%s'\n", ctx.as_string.data); 4430 debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data);
4403 if (pstring) 4431 if (pstring)
4404 *pstring = ctx.as_string.data; 4432 *pstring = ctx.as_string.data;
4405 else 4433 else
@@ -4639,9 +4667,6 @@ static struct pipe *parse_stream(char **pstring,
4639 * with redirect_opt_num(), but bash doesn't do it. 4667 * with redirect_opt_num(), but bash doesn't do it.
4640 * "echo foo 2| cat" yields "foo 2". */ 4668 * "echo foo 2| cat" yields "foo 2". */
4641 done_command(&ctx); 4669 done_command(&ctx);
4642#if !BB_MMU
4643 o_reset_to_empty_unquoted(&ctx.as_string);
4644#endif
4645 } 4670 }
4646 goto new_cmd; 4671 goto new_cmd;
4647 case '(': 4672 case '(':
@@ -6779,7 +6804,7 @@ static int checkjobs(struct pipe *fg_pipe)
6779 int sig = WTERMSIG(status); 6804 int sig = WTERMSIG(status);
6780 if (i == fg_pipe->num_cmds-1) 6805 if (i == fg_pipe->num_cmds-1)
6781 /* TODO: use strsignal() instead for bash compat? but that's bloat... */ 6806 /* TODO: use strsignal() instead for bash compat? but that's bloat... */
6782 printf("%s\n", sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); 6807 puts(sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig));
6783 /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ 6808 /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */
6784 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? 6809 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here?
6785 * Maybe we need to use sig | 128? */ 6810 * Maybe we need to use sig | 128? */
@@ -7851,12 +7876,7 @@ int hush_main(int argc, char **argv)
7851 /* Initialize some more globals to non-zero values */ 7876 /* Initialize some more globals to non-zero values */
7852 cmdedit_update_prompt(); 7877 cmdedit_update_prompt();
7853 7878
7854 if (setjmp(die_jmp)) { 7879 die_func = xfunc_has_died;
7855 /* xfunc has failed! die die die */
7856 /* no EXIT traps, this is an escape hatch! */
7857 G.exiting = 1;
7858 hush_exit(xfunc_error_retval);
7859 }
7860 7880
7861 /* Shell is non-interactive at first. We need to call 7881 /* Shell is non-interactive at first. We need to call
7862 * install_special_sighandlers() if we are going to execute "sh <script>", 7882 * install_special_sighandlers() if we are going to execute "sh <script>",
@@ -8114,9 +8134,7 @@ int hush_main(int argc, char **argv)
8114 /* Grab control of the terminal */ 8134 /* Grab control of the terminal */
8115 tcsetpgrp(G_interactive_fd, getpid()); 8135 tcsetpgrp(G_interactive_fd, getpid());
8116 } 8136 }
8117 /* -1 is special - makes xfuncs longjmp, not exit 8137 enable_restore_tty_pgrp_on_exit();
8118 * (we reset die_sleep = 0 whereever we [v]fork) */
8119 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
8120 8138
8121# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 8139# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0
8122 { 8140 {
@@ -8950,24 +8968,29 @@ static int FAST_FUNC builtin_umask(char **argv)
8950 int rc; 8968 int rc;
8951 mode_t mask; 8969 mode_t mask;
8952 8970
8971 rc = 1;
8953 mask = umask(0); 8972 mask = umask(0);
8954 argv = skip_dash_dash(argv); 8973 argv = skip_dash_dash(argv);
8955 if (argv[0]) { 8974 if (argv[0]) {
8956 mode_t old_mask = mask; 8975 mode_t old_mask = mask;
8957 8976
8958 mask ^= 0777; 8977 /* numeric umasks are taken as-is */
8959 rc = bb_parse_mode(argv[0], &mask); 8978 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
8960 mask ^= 0777; 8979 if (!isdigit(argv[0][0]))
8961 if (rc == 0) { 8980 mask ^= 0777;
8981 mask = bb_parse_mode(argv[0], mask);
8982 if (!isdigit(argv[0][0]))
8983 mask ^= 0777;
8984 if ((unsigned)mask > 0777) {
8962 mask = old_mask; 8985 mask = old_mask;
8963 /* bash messages: 8986 /* bash messages:
8964 * bash: umask: 'q': invalid symbolic mode operator 8987 * bash: umask: 'q': invalid symbolic mode operator
8965 * bash: umask: 999: octal number out of range 8988 * bash: umask: 999: octal number out of range
8966 */ 8989 */
8967 bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]); 8990 bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]);
8991 rc = 0;
8968 } 8992 }
8969 } else { 8993 } else {
8970 rc = 1;
8971 /* Mimic bash */ 8994 /* Mimic bash */
8972 printf("%04o\n", (unsigned) mask); 8995 printf("%04o\n", (unsigned) mask);
8973 /* fall through and restore mask which we set to 0 */ 8996 /* fall through and restore mask which we set to 0 */
@@ -9097,12 +9120,9 @@ static int FAST_FUNC builtin_wait(char **argv)
9097 return EXIT_FAILURE; 9120 return EXIT_FAILURE;
9098 } 9121 }
9099 if (waitpid(pid, &status, 0) == pid) { 9122 if (waitpid(pid, &status, 0) == pid) {
9123 ret = WEXITSTATUS(status);
9100 if (WIFSIGNALED(status)) 9124 if (WIFSIGNALED(status))
9101 ret = 128 + WTERMSIG(status); 9125 ret = 128 + WTERMSIG(status);
9102 else if (WIFEXITED(status))
9103 ret = WEXITSTATUS(status);
9104 else /* wtf? */
9105 ret = EXIT_FAILURE;
9106 } else { 9126 } else {
9107 bb_perror_msg("wait %s", *argv); 9127 bb_perror_msg("wait %s", *argv);
9108 ret = 127; 9128 ret = 127;
diff --git a/shell/hush_test/hush-glob/glob3.right b/shell/hush_test/hush-glob/glob3.right
new file mode 100644
index 000000000..161b589e0
--- /dev/null
+++ b/shell/hush_test/hush-glob/glob3.right
@@ -0,0 +1,2 @@
1glob3.tests
2./glob3.tests
diff --git a/shell/hush_test/hush-glob/glob3.tests b/shell/hush_test/hush-glob/glob3.tests
new file mode 100755
index 000000000..bdf54001e
--- /dev/null
+++ b/shell/hush_test/hush-glob/glob3.tests
@@ -0,0 +1,2 @@
1echo "glob3.test"*
2echo "./glob3.test"*
diff --git a/shell/hush_test/hush-misc/nommu3.right b/shell/hush_test/hush-misc/nommu3.right
new file mode 100644
index 000000000..da1534bef
--- /dev/null
+++ b/shell/hush_test/hush-misc/nommu3.right
@@ -0,0 +1,2 @@
1Ok
20
diff --git a/shell/hush_test/hush-misc/nommu3.tests b/shell/hush_test/hush-misc/nommu3.tests
new file mode 100755
index 000000000..ac82a6a11
--- /dev/null
+++ b/shell/hush_test/hush-misc/nommu3.tests
@@ -0,0 +1,15 @@
1#!/bin/sh
2
3func()
4{
5 while read p; do echo "$p"; done
6}
7
8pipe_to_func()
9{
10 # We had a NOMMU bug which caused "echo Ok |" part to be lost
11 echo Ok | func
12}
13
14pipe_to_func | cat
15echo $?
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 1567d1de4..dbd4286bf 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -387,7 +387,7 @@ static void printlim(unsigned opts, const struct rlimit *limit,
387 val = limit->rlim_cur; 387 val = limit->rlim_cur;
388 388
389 if (val == RLIM_INFINITY) 389 if (val == RLIM_INFINITY)
390 printf("unlimited\n"); 390 puts("unlimited");
391 else { 391 else {
392 val >>= l->factor_shift; 392 val >>= l->factor_shift;
393 printf("%llu\n", (long long) val); 393 printf("%llu\n", (long long) val);
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index 9e6952ffd..adab4ae1e 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -281,6 +281,11 @@ testing "awk length(array)" \
281 "2\n" \ 281 "2\n" \
282 "" "" 282 "" ""
283 283
284testing "awk length()" \
285 "awk '{print length; print length(); print length(\"qwe\"); print length(99+9)}'" \
286 "3\n3\n3\n3\n" \
287 "" "qwe"
288
284testing "awk -f and ARGC" \ 289testing "awk -f and ARGC" \
285 "awk -f - input" \ 290 "awk -f - input" \
286 "re\n2\n" \ 291 "re\n2\n" \
diff --git a/testsuite/bzcat.tests b/testsuite/bzcat.tests
index 9a1c28425..0ae530dc7 100755
--- a/testsuite/bzcat.tests
+++ b/testsuite/bzcat.tests
@@ -28,7 +28,10 @@ hello_bz2() {
28 $ECHO -ne "\x17\x72\x45\x38\x50\x90\x5b\xb8\xe8\xa3" 28 $ECHO -ne "\x17\x72\x45\x38\x50\x90\x5b\xb8\xe8\xa3"
29} 29}
30 30
31for ext in gz bz2 Z 31for ext in \
32 `test x"$CONFIG_GUNZIP" = x"y" && echo gz` \
33 `test x"$CONFIG_BUNZIP2" = x"y" && echo bz2` \
34 `test x"$CONFIG_UNCOMPRESS" = x"y" && echo Z`
32do 35do
33 prep() { 36 prep() {
34 rm -f t1.$ext t2.$ext t_actual 37 rm -f t1.$ext t2.$ext t_actual
@@ -49,11 +52,12 @@ do
49 mkdir testdir 2>/dev/null 52 mkdir testdir 2>/dev/null
50 ( 53 (
51 cd testdir || { echo "cannot cd testdir!"; exit 1; } 54 cd testdir || { echo "cannot cd testdir!"; exit 1; }
52
53 expected="HELLO\nok\n" 55 expected="HELLO\nok\n"
54 prep; check "zcat: dont delete $ext src" "${bb}zcat t2.$ext; test -f t2.$ext && echo ok" 56 prep
55 57 check "zcat: dont delete $ext src" "${bb}zcat t2.$ext; test -f t2.$ext && echo ok"
58 exit $FAILCOUNT
56 ) 59 )
60 FAILCOUNT=$?
57 rm -rf testdir 61 rm -rf testdir
58done 62done
59 63
@@ -89,6 +93,7 @@ testing "bzcat can handle compressed zero-length bzip2 files" \
89## compress algorithm 93## compress algorithm
90 94
91# "input" file is compressed (.Z) file with "a\n" data 95# "input" file is compressed (.Z) file with "a\n" data
96test x"$CONFIG_UNCOMPRESS" = x"y" && \
92testing "zcat can print many files" \ 97testing "zcat can print many files" \
93"$ECHO -ne '$hexdump' | zcat input input; echo \$?" \ 98"$ECHO -ne '$hexdump' | zcat input input; echo \$?" \
94"\ 99"\
@@ -100,7 +105,8 @@ a
100" "" 105" ""
101 106
102# "input" file is compressed (.Z) zero byte file 107# "input" file is compressed (.Z) zero byte file
103testing "zcat can handle compressed zero-length compressed (.Z) files" \ 108test x"$CONFIG_UNCOMPRESS" = x"y" && \
109testing "zcat can handle compressed zero-length (.Z) files" \
104"$ECHO -ne '$hexdump' | zcat input input; echo \$?" \ 110"$ECHO -ne '$hexdump' | zcat input input; echo \$?" \
105"0\n" \ 111"0\n" \
106"\x1f\x9d\x90\x00" "" 112"\x1f\x9d\x90\x00" ""
diff --git a/testsuite/makedevs.tests b/testsuite/makedevs.tests
index fd12460ec..b51fe0798 100755
--- a/testsuite/makedevs.tests
+++ b/testsuite/makedevs.tests
@@ -25,7 +25,7 @@ FILTER_LS2="sed -e 's/, */,/g' -e 's/ */ /g' | cut -d' ' -f 1-4,9-"
25rm -rf makedevs.testdir 25rm -rf makedevs.testdir
26mkdir makedevs.testdir 26mkdir makedevs.testdir
27 27
28optional FEATURE_MAKEDEVS_TABLE FEATURE_FIND_NOT FEATURE_FIND_TYPE FEATURE_LS_RECURSIVE FEATURE_LS_SORTFILES 28optional FEATURE_MAKEDEVS_TABLE FEATURE_FIND_NOT FEATURE_FIND_TYPE FEATURE_LS_RECURSIVE FEATURE_LS_SORTFILES FEATURE_LS_TIMESTAMPS
29testing "makedevs -d ../makedevs.device_table.txt ." \ 29testing "makedevs -d ../makedevs.device_table.txt ." \
30 "(cd makedevs.testdir && makedevs -d ../makedevs.device_table.txt . 2>&1); 30 "(cd makedevs.testdir && makedevs -d ../makedevs.device_table.txt . 2>&1);
31 find makedevs.testdir ! -type d | sort | xargs ls -lnR | $FILTER_LS" \ 31 find makedevs.testdir ! -type d | sort | xargs ls -lnR | $FILTER_LS" \
diff --git a/testsuite/pwd/pwd-prints-working-directory b/testsuite/pwd/pwd-prints-working-directory
index 8575347d6..971adb5a6 100644
--- a/testsuite/pwd/pwd-prints-working-directory
+++ b/testsuite/pwd/pwd-prints-working-directory
@@ -1 +1,4 @@
1test $(pwd) = $(busybox pwd) 1# shell's $PWD may leave symlinks unresolved.
2# "pwd" may be a built-in and have the same problem.
3# External pwd _can't_ have that problem (current dir on Unix is physical).
4test $(`which pwd`) = $(busybox pwd)
diff --git a/testsuite/readlink.tests b/testsuite/readlink.tests
index c7fc8adf0..e9d8da0fc 100755
--- a/testsuite/readlink.tests
+++ b/testsuite/readlink.tests
@@ -21,10 +21,15 @@ testing "readlink on a link" "readlink ./$TESTLINK" "./$TESTFILE\n" "" ""
21 21
22optional FEATURE_READLINK_FOLLOW 22optional FEATURE_READLINK_FOLLOW
23 23
24testing "readlink -f on a file" "readlink -f ./$TESTFILE" "$PWD/$TESTFILE\n" "" "" 24# shell's $PWD may leave symlinks unresolved.
25testing "readlink -f on a link" "readlink -f ./$TESTLINK" "$PWD/$TESTFILE\n" "" "" 25# "pwd" may be a built-in and have the same problem.
26# External pwd _can't_ have that problem (current dir on Unix is physical).
27pwd=`which pwd`
28pwd=`$pwd`
29testing "readlink -f on a file" "readlink -f ./$TESTFILE" "$pwd/$TESTFILE\n" "" ""
30testing "readlink -f on a link" "readlink -f ./$TESTLINK" "$pwd/$TESTFILE\n" "" ""
26testing "readlink -f on an invalid link" "readlink -f ./$FAILLINK" "" "" "" 31testing "readlink -f on an invalid link" "readlink -f ./$FAILLINK" "" "" ""
27testing "readlink -f on a wierd dir" "readlink -f $TESTDIR/../$TESTFILE" "$PWD/$TESTFILE\n" "" "" 32testing "readlink -f on a wierd dir" "readlink -f $TESTDIR/../$TESTFILE" "$pwd/$TESTFILE\n" "" ""
28 33
29 34
30# clean up 35# clean up
diff --git a/testsuite/sort.tests b/testsuite/sort.tests
index 68fa3e405..c4b223464 100755
--- a/testsuite/sort.tests
+++ b/testsuite/sort.tests
@@ -98,6 +98,14 @@ testing "sort with non-default leading delim 3" "sort -n -k3 -t/ input" "\
98//b/1 98//b/1
99" "" 99" ""
100 100
101testing "sort with non-default leading delim 4" "sort -t: -k1,1 input" "\
102a:b
103a/a:a
104" "\
105a/a:a
106a:b
107" ""
108
101testing "sort -u should consider field only when discarding" "sort -u -k2 input" "\ 109testing "sort -u should consider field only when discarding" "sort -u -k2 input" "\
102a c 110a c
103" "\ 111" "\
diff --git a/util-linux/dmesg.c b/util-linux/dmesg.c
index 81ba1c9d1..e543446c1 100644
--- a/util-linux/dmesg.c
+++ b/util-linux/dmesg.c
@@ -16,6 +16,7 @@
16//usage: "\n -c Clear ring buffer after printing" 16//usage: "\n -c Clear ring buffer after printing"
17//usage: "\n -n LEVEL Set console logging level" 17//usage: "\n -n LEVEL Set console logging level"
18//usage: "\n -s SIZE Buffer size" 18//usage: "\n -s SIZE Buffer size"
19//usage: "\n -r Print raw message buffer"
19 20
20#include <sys/klog.h> 21#include <sys/klog.h>
21#include "libbb.h" 22#include "libbb.h"
@@ -29,11 +30,12 @@ int dmesg_main(int argc UNUSED_PARAM, char **argv)
29 enum { 30 enum {
30 OPT_c = 1 << 0, 31 OPT_c = 1 << 0,
31 OPT_s = 1 << 1, 32 OPT_s = 1 << 1,
32 OPT_n = 1 << 2 33 OPT_n = 1 << 2,
34 OPT_r = 1 << 3
33 }; 35 };
34 36
35 opt_complementary = "s+:n+"; /* numeric */ 37 opt_complementary = "s+:n+"; /* numeric */
36 opts = getopt32(argv, "cs:n:", &len, &level); 38 opts = getopt32(argv, "cs:n:r", &len, &level);
37 if (opts & OPT_n) { 39 if (opts & OPT_n) {
38 if (klogctl(8, NULL, (long) level)) 40 if (klogctl(8, NULL, (long) level))
39 bb_perror_msg_and_die("klogctl"); 41 bb_perror_msg_and_die("klogctl");
@@ -55,7 +57,7 @@ int dmesg_main(int argc UNUSED_PARAM, char **argv)
55 return EXIT_SUCCESS; 57 return EXIT_SUCCESS;
56 58
57 59
58 if (ENABLE_FEATURE_DMESG_PRETTY) { 60 if (ENABLE_FEATURE_DMESG_PRETTY && !(opts & OPT_r)) {
59 int last = '\n'; 61 int last = '\n';
60 int in = 0; 62 int in = 0;
61 63
diff --git a/util-linux/fdformat.c b/util-linux/fdformat.c
index 6f49cec8f..6ef6445e6 100644
--- a/util-linux/fdformat.c
+++ b/util-linux/fdformat.c
@@ -93,7 +93,7 @@ int fdformat_main(int argc UNUSED_PARAM, char **argv)
93 } 93 }
94 94
95 xioctl(fd, FDFMTEND, NULL); 95 xioctl(fd, FDFMTEND, NULL);
96 printf("done\n"); 96 puts("Done");
97 97
98 /* VERIFY */ 98 /* VERIFY */
99 if (verify) { 99 if (verify) {
@@ -126,7 +126,7 @@ int fdformat_main(int argc UNUSED_PARAM, char **argv)
126 126
127 if (ENABLE_FEATURE_CLEAN_UP) free(data); 127 if (ENABLE_FEATURE_CLEAN_UP) free(data);
128 128
129 printf("done\n"); 129 puts("Done");
130 } 130 }
131 131
132 if (ENABLE_FEATURE_CLEAN_UP) close(fd); 132 if (ENABLE_FEATURE_CLEAN_UP) close(fd);
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c
index 7fe70fb72..f49ce95a4 100644
--- a/util-linux/fdisk.c
+++ b/util-linux/fdisk.c
@@ -1102,11 +1102,11 @@ warn_geometry(void)
1102 printf(" sectors"); 1102 printf(" sectors");
1103 if (!g_cylinders) 1103 if (!g_cylinders)
1104 printf(" cylinders"); 1104 printf(" cylinders");
1105 printf(
1106#if ENABLE_FEATURE_FDISK_WRITABLE 1105#if ENABLE_FEATURE_FDISK_WRITABLE
1107 " (settable in the extra functions menu)" 1106 puts(" (settable in the extra functions menu)");
1107#else
1108 bb_putchar('\n');
1108#endif 1109#endif
1109 "\n");
1110 return 1; 1110 return 1;
1111} 1111}
1112 1112
@@ -1150,7 +1150,7 @@ read_extended(int ext)
1150 1150
1151 p = pex->part_table; 1151 p = pex->part_table;
1152 if (!get_start_sect(p)) { 1152 if (!get_start_sect(p)) {
1153 printf("Bad offset in primary extended partition\n"); 1153 puts("Bad offset in primary extended partition");
1154 return; 1154 return;
1155 } 1155 }
1156 1156
@@ -1450,8 +1450,8 @@ static int get_boot(void)
1450 current_label_type = LABEL_OSF; 1450 current_label_type = LABEL_OSF;
1451 return 0; 1451 return 0;
1452 } 1452 }
1453 printf("This disk has both DOS and BSD magic.\n" 1453 puts("This disk has both DOS and BSD magic.\n"
1454 "Give the 'b' command to go to BSD mode.\n"); 1454 "Give the 'b' command to go to BSD mode.");
1455 } 1455 }
1456#endif 1456#endif
1457 1457
@@ -1461,9 +1461,9 @@ static int get_boot(void)
1461#else 1461#else
1462 if (!valid_part_table_flag(MBRbuffer)) { 1462 if (!valid_part_table_flag(MBRbuffer)) {
1463 if (what == OPEN_MAIN) { 1463 if (what == OPEN_MAIN) {
1464 printf("Device contains neither a valid DOS " 1464 puts("Device contains neither a valid DOS "
1465 "partition table, nor Sun, SGI, OSF or GPT " 1465 "partition table, nor Sun, SGI, OSF or GPT "
1466 "disklabel\n"); 1466 "disklabel");
1467#ifdef __sparc__ 1467#ifdef __sparc__
1468 IF_FEATURE_SUN_LABEL(create_sunlabel();) 1468 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1469#else 1469#else
@@ -1596,7 +1596,7 @@ read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *
1596 } 1596 }
1597 if (value >= low && value <= high) 1597 if (value >= low && value <= high)
1598 break; 1598 break;
1599 printf("Value is out of range\n"); 1599 puts("Value is out of range");
1600 } 1600 }
1601 return value; 1601 return value;
1602} 1602}
@@ -1641,7 +1641,7 @@ get_existing_partition(int warn, unsigned max)
1641 printf("Selected partition %u\n", pno+1); 1641 printf("Selected partition %u\n", pno+1);
1642 return pno; 1642 return pno;
1643 } 1643 }
1644 printf("No partition is defined yet!\n"); 1644 puts("No partition is defined yet!");
1645 return -1; 1645 return -1;
1646 1646
1647 not_unique: 1647 not_unique:
@@ -1668,7 +1668,7 @@ get_nonexisting_partition(int warn, unsigned max)
1668 printf("Selected partition %u\n", pno+1); 1668 printf("Selected partition %u\n", pno+1);
1669 return pno; 1669 return pno;
1670 } 1670 }
1671 printf("All primary partitions have been defined already!\n"); 1671 puts("All primary partitions have been defined already!");
1672 return -1; 1672 return -1;
1673 1673
1674 not_unique: 1674 not_unique:
@@ -1703,10 +1703,10 @@ toggle_dos_compatibility_flag(void)
1703 dos_compatible_flag = 1 - dos_compatible_flag; 1703 dos_compatible_flag = 1 - dos_compatible_flag;
1704 if (dos_compatible_flag) { 1704 if (dos_compatible_flag) {
1705 sector_offset = g_sectors; 1705 sector_offset = g_sectors;
1706 printf("DOS Compatibility flag is set\n"); 1706 printf("DOS Compatibility flag is %sset\n", "");
1707 } else { 1707 } else {
1708 sector_offset = 1; 1708 sector_offset = 1;
1709 printf("DOS Compatibility flag is not set\n"); 1709 printf("DOS Compatibility flag is %sset\n", "not ");
1710 } 1710 }
1711} 1711}
1712 1712
@@ -1813,16 +1813,16 @@ change_sysid(void)
1813 sys = read_hex(get_sys_types()); 1813 sys = read_hex(get_sys_types());
1814 1814
1815 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) { 1815 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1816 printf("Type 0 means free space to many systems\n" 1816 puts("Type 0 means free space to many systems\n"
1817 "(but not to Linux). Having partitions of\n" 1817 "(but not to Linux). Having partitions of\n"
1818 "type 0 is probably unwise.\n"); 1818 "type 0 is probably unwise.");
1819 /* break; */ 1819 /* break; */
1820 } 1820 }
1821 1821
1822 if (!LABEL_IS_SUN && !LABEL_IS_SGI) { 1822 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1823 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) { 1823 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1824 printf("You cannot change a partition into" 1824 puts("You cannot change a partition into"
1825 " an extended one or vice versa\n"); 1825 " an extended one or vice versa");
1826 break; 1826 break;
1827 } 1827 }
1828 } 1828 }
@@ -1830,10 +1830,10 @@ change_sysid(void)
1830 if (sys < 256) { 1830 if (sys < 256) {
1831#if ENABLE_FEATURE_SUN_LABEL 1831#if ENABLE_FEATURE_SUN_LABEL
1832 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK) 1832 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1833 printf("Consider leaving partition 3 " 1833 puts("Consider leaving partition 3 "
1834 "as Whole disk (5),\n" 1834 "as Whole disk (5),\n"
1835 "as SunOS/Solaris expects it and " 1835 "as SunOS/Solaris expects it and "
1836 "even Linux likes it\n\n"); 1836 "even Linux likes it\n");
1837#endif 1837#endif
1838#if ENABLE_FEATURE_SGI_LABEL 1838#if ENABLE_FEATURE_SGI_LABEL
1839 if (LABEL_IS_SGI && 1839 if (LABEL_IS_SGI &&
@@ -1842,10 +1842,10 @@ change_sysid(void)
1842 (i == 8 && sys != 0) 1842 (i == 8 && sys != 0)
1843 ) 1843 )
1844 ) { 1844 ) {
1845 printf("Consider leaving partition 9 " 1845 puts("Consider leaving partition 9 "
1846 "as volume header (0),\nand " 1846 "as volume header (0),\nand "
1847 "partition 11 as entire volume (6)" 1847 "partition 11 as entire volume (6)"
1848 "as IRIX expects it\n\n"); 1848 "as IRIX expects it\n");
1849 } 1849 }
1850#endif 1850#endif
1851 if (sys == origsys) 1851 if (sys == origsys)
@@ -2067,7 +2067,7 @@ fix_partition_table_order(void)
2067 int i,k; 2067 int i,k;
2068 2068
2069 if (!wrong_p_order(NULL)) { 2069 if (!wrong_p_order(NULL)) {
2070 printf("Ordering is already correct\n\n"); 2070 puts("Ordering is already correct\n");
2071 return; 2071 return;
2072 } 2072 }
2073 2073
@@ -2095,7 +2095,7 @@ fix_partition_table_order(void)
2095 if (i) 2095 if (i)
2096 fix_chain_of_logicals(); 2096 fix_chain_of_logicals();
2097 2097
2098 printf("Done.\n"); 2098 puts("Done");
2099} 2099}
2100#endif 2100#endif
2101 2101
@@ -2178,7 +2178,7 @@ list_table(int xtra)
2178 * if this is a sgi, sun or aix labeled disk... */ 2178 * if this is a sgi, sun or aix labeled disk... */
2179 if (LABEL_IS_DOS && wrong_p_order(NULL)) { 2179 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2180 /* FIXME */ 2180 /* FIXME */
2181 printf("\nPartition table entries are not in disk order\n"); 2181 puts("\nPartition table entries are not in disk order");
2182 } 2182 }
2183} 2183}
2184 2184
@@ -2192,7 +2192,7 @@ x_list_table(int extend)
2192 2192
2193 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n", 2193 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n",
2194 disk_device, g_heads, g_sectors, g_cylinders); 2194 disk_device, g_heads, g_sectors, g_cylinders);
2195 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"); 2195 puts("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID");
2196 for (i = 0; i < g_partitions; i++) { 2196 for (i = 0; i < g_partitions; i++) {
2197 pe = &ptes[i]; 2197 pe = &ptes[i];
2198 p = (extend ? pe->ext_pointer : pe->part_table); 2198 p = (extend ? pe->ext_pointer : pe->part_table);
@@ -2419,7 +2419,7 @@ add_partition(int n, int sys)
2419 limit = first[i] - 1; 2419 limit = first[i] - 1;
2420 } 2420 }
2421 if (start > limit) { 2421 if (start > limit) {
2422 printf("No free sectors available\n"); 2422 puts("No free sectors available");
2423 if (n > 4) 2423 if (n > 4)
2424 g_partitions--; 2424 g_partitions--;
2425 return; 2425 return;
@@ -2490,9 +2490,9 @@ new_partition(void)
2490 return; 2490 return;
2491 } 2491 }
2492 if (LABEL_IS_AIX) { 2492 if (LABEL_IS_AIX) {
2493 printf("Sorry - this fdisk cannot handle AIX disk labels.\n" 2493 puts("Sorry - this fdisk cannot handle AIX disk labels.\n"
2494"If you want to add DOS-type partitions, create a new empty DOS partition\n" 2494"If you want to add DOS-type partitions, create a new empty DOS partition\n"
2495"table first (use 'o'). This will destroy the present disk contents.\n"); 2495"table first (use 'o'). This will destroy the present disk contents.");
2496 return; 2496 return;
2497 } 2497 }
2498 2498
@@ -2500,7 +2500,7 @@ new_partition(void)
2500 free_primary += !ptes[i].part_table->sys_ind; 2500 free_primary += !ptes[i].part_table->sys_ind;
2501 2501
2502 if (!free_primary && g_partitions >= MAXIMUM_PARTS) { 2502 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2503 printf("The maximum number of partitions has been created\n"); 2503 puts("The maximum number of partitions has been created");
2504 return; 2504 return;
2505 } 2505 }
2506 2506
@@ -2508,8 +2508,8 @@ new_partition(void)
2508 if (extended_offset) 2508 if (extended_offset)
2509 add_logical(); 2509 add_logical();
2510 else 2510 else
2511 printf("You must delete some partition and add " 2511 puts("You must delete some partition and add "
2512 "an extended partition first\n"); 2512 "an extended partition first");
2513 } else { 2513 } else {
2514 char c, line[80]; 2514 char c, line[80];
2515 snprintf(line, sizeof(line), 2515 snprintf(line, sizeof(line),
@@ -2547,7 +2547,7 @@ reread_partition_table(int leave)
2547{ 2547{
2548 int i; 2548 int i;
2549 2549
2550 printf("Calling ioctl() to re-read partition table\n"); 2550 puts("Calling ioctl() to re-read partition table");
2551 sync(); 2551 sync();
2552 /* Users with slow external USB disks on a 320MHz ARM system (year 2011) 2552 /* Users with slow external USB disks on a 320MHz ARM system (year 2011)
2553 * report that sleep is needed, otherwise BLKRRPART may fail with -EIO: 2553 * report that sleep is needed, otherwise BLKRRPART may fail with -EIO:
@@ -2558,10 +2558,10 @@ reread_partition_table(int leave)
2558 "failed, kernel still uses old table"); 2558 "failed, kernel still uses old table");
2559#if 0 2559#if 0
2560 if (dos_changed) 2560 if (dos_changed)
2561 printf( 2561 puts(
2562 "\nWARNING: If you have created or modified any DOS 6.x\n" 2562 "\nWARNING: If you have created or modified any DOS 6.x\n"
2563 "partitions, please see the fdisk manual page for additional\n" 2563 "partitions, please see the fdisk manual page for additional\n"
2564 "information\n"); 2564 "information");
2565#endif 2565#endif
2566 2566
2567 if (leave) { 2567 if (leave) {
@@ -2589,7 +2589,7 @@ write_table(void)
2589 } 2589 }
2590 } 2590 }
2591 else if (LABEL_IS_SGI) { 2591 else if (LABEL_IS_SGI) {
2592 /* no test on change? the printf below might be mistaken */ 2592 /* no test on change? the "altered" msg below might be mistaken */
2593 sgi_write_table(); 2593 sgi_write_table();
2594 } 2594 }
2595 else if (LABEL_IS_SUN) { 2595 else if (LABEL_IS_SUN) {
@@ -2601,7 +2601,7 @@ write_table(void)
2601 } 2601 }
2602 } 2602 }
2603 2603
2604 printf("The partition table has been altered.\n"); 2604 puts("The partition table has been altered.");
2605 reread_partition_table(1); 2605 reread_partition_table(1);
2606} 2606}
2607#endif /* FEATURE_FDISK_WRITABLE */ 2607#endif /* FEATURE_FDISK_WRITABLE */
@@ -2744,8 +2744,8 @@ xselect(void)
2744 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0, "Number of sectors"); 2744 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0, "Number of sectors");
2745 if (dos_compatible_flag) { 2745 if (dos_compatible_flag) {
2746 sector_offset = g_sectors; 2746 sector_offset = g_sectors;
2747 printf("Warning: setting sector offset for DOS " 2747 puts("Warning: setting sector offset for DOS "
2748 "compatiblity\n"); 2748 "compatiblity");
2749 } 2749 }
2750 update_units(); 2750 update_units();
2751 break; 2751 break;
@@ -3024,7 +3024,7 @@ int fdisk_main(int argc UNUSED_PARAM, char **argv)
3024 sgi_get_bootfile()); 3024 sgi_get_bootfile());
3025 if (read_maybe_empty("Please enter the name of the " 3025 if (read_maybe_empty("Please enter the name of the "
3026 "new boot file: ") == '\n') 3026 "new boot file: ") == '\n')
3027 printf("Boot file unchanged\n"); 3027 puts("Boot file unchanged");
3028 else 3028 else
3029 sgi_set_bootfile(line_ptr); 3029 sgi_set_bootfile(line_ptr);
3030 } 3030 }
@@ -3106,8 +3106,8 @@ int fdisk_main(int argc UNUSED_PARAM, char **argv)
3106#if ENABLE_FEATURE_FDISK_ADVANCED 3106#if ENABLE_FEATURE_FDISK_ADVANCED
3107 case 'x': 3107 case 'x':
3108 if (LABEL_IS_SGI) { 3108 if (LABEL_IS_SGI) {
3109 printf("\n\tSorry, no experts menu for SGI " 3109 puts("\n\tSorry, no experts menu for SGI "
3110 "partition tables available\n\n"); 3110 "partition tables available\n");
3111 } else 3111 } else
3112 xselect(); 3112 xselect();
3113 break; 3113 break;
diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c
index 5786d5f7d..715e227ca 100644
--- a/util-linux/fdisk_gpt.c
+++ b/util-linux/fdisk_gpt.c
@@ -106,7 +106,7 @@ gpt_list_table(int xtra UNUSED_PARAM)
106 (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba), 106 (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba),
107 (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba)); 107 (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba));
108 108
109 printf("Number Start (sector) End (sector) Size Code Name\n"); 109 puts("Number Start (sector) End (sector) Size Code Name");
110 for (i = 0; i < n_parts; i++) { 110 for (i = 0; i < n_parts; i++) {
111 gpt_partition *p = gpt_part(i); 111 gpt_partition *p = gpt_part(i);
112 if (p->lba_start) { 112 if (p->lba_start) {
@@ -119,7 +119,7 @@ gpt_list_table(int xtra UNUSED_PARAM)
119 numstr6, 119 numstr6,
120 0x0700 /* FIXME */); 120 0x0700 /* FIXME */);
121 gpt_print_wide(p->name, 18); 121 gpt_print_wide(p->name, 18);
122 printf("\n"); 122 bb_putchar('\n');
123 } 123 }
124 } 124 }
125} 125}
diff --git a/util-linux/fsck_minix.c b/util-linux/fsck_minix.c
index 33767a1af..d2f3524b4 100644
--- a/util-linux/fsck_minix.c
+++ b/util-linux/fsck_minix.c
@@ -371,9 +371,9 @@ static int ask(const char *string, int def)
371 } 371 }
372 } 372 }
373 if (def) 373 if (def)
374 printf("y\n"); 374 puts("y");
375 else { 375 else {
376 printf("n\n"); 376 puts("n");
377 errors_uncorrected = 1; 377 errors_uncorrected = 1;
378 } 378 }
379 return def; 379 return def;
@@ -405,7 +405,7 @@ static void check_mount(void)
405 if (isatty(0) && isatty(1)) 405 if (isatty(0) && isatty(1))
406 cont = ask("Do you really want to continue", 0); 406 cont = ask("Do you really want to continue", 0);
407 if (!cont) { 407 if (!cont) {
408 printf("Check aborted\n"); 408 puts("Check aborted");
409 exit(EXIT_SUCCESS); 409 exit(EXIT_SUCCESS);
410 } 410 }
411 } 411 }
@@ -470,8 +470,8 @@ static void write_block(unsigned nr, void *addr)
470 if (!nr) 470 if (!nr)
471 return; 471 return;
472 if (nr < FIRSTZONE || nr >= ZONES) { 472 if (nr < FIRSTZONE || nr >= ZONES) {
473 printf("Internal error: trying to write bad block\n" 473 puts("Internal error: trying to write bad block\n"
474 "Write request ignored\n"); 474 "Write request ignored");
475 errors_uncorrected = 1; 475 errors_uncorrected = 1;
476 return; 476 return;
477 } 477 }
@@ -659,7 +659,7 @@ static void read_tables(void)
659 if (INODE_BUFFER_SIZE != read(dev_fd, inode_buffer, INODE_BUFFER_SIZE)) 659 if (INODE_BUFFER_SIZE != read(dev_fd, inode_buffer, INODE_BUFFER_SIZE))
660 die("can't read inodes"); 660 die("can't read inodes");
661 if (NORM_FIRSTZONE != FIRSTZONE) { 661 if (NORM_FIRSTZONE != FIRSTZONE) {
662 printf("warning: firstzone!=norm_firstzone\n"); 662 puts("warning: firstzone!=norm_firstzone");
663 errors_uncorrected = 1; 663 errors_uncorrected = 1;
664 } 664 }
665 get_dirsize(); 665 get_dirsize();
@@ -713,7 +713,7 @@ static void get_inode_common(unsigned nr, uint16_t i_mode)
713 } else 713 } else
714 links++; 714 links++;
715 if (!++inode_count[nr]) { 715 if (!++inode_count[nr]) {
716 printf("Warning: inode count too big\n"); 716 puts("Warning: inode count too big");
717 inode_count[nr]--; 717 inode_count[nr]--;
718 errors_uncorrected = 1; 718 errors_uncorrected = 1;
719 } 719 }
@@ -1299,7 +1299,7 @@ int fsck_minix_main(int argc UNUSED_PARAM, char **argv)
1299 } 1299 }
1300 if (changed) { 1300 if (changed) {
1301 write_tables(); 1301 write_tables();
1302 printf("FILE SYSTEM HAS BEEN CHANGED\n"); 1302 puts("FILE SYSTEM HAS BEEN CHANGED");
1303 sync(); 1303 sync();
1304 } else if (OPT_repair) 1304 } else if (OPT_repair)
1305 write_superblock(); 1305 write_superblock();
diff --git a/util-linux/getopt.c b/util-linux/getopt.c
index 58df1c823..b9dadf13c 100644
--- a/util-linux/getopt.c
+++ b/util-linux/getopt.c
@@ -378,7 +378,7 @@ int getopt_main(int argc, char **argv)
378 if (compatible) { 378 if (compatible) {
379 /* For some reason, the original getopt gave no error 379 /* For some reason, the original getopt gave no error
380 * when there were no arguments. */ 380 * when there were no arguments. */
381 printf(" --\n"); 381 puts(" --");
382 return 0; 382 return 0;
383 } 383 }
384 bb_error_msg_and_die("missing optstring argument"); 384 bb_error_msg_and_die("missing optstring argument");
diff --git a/util-linux/ipcrm.c b/util-linux/ipcrm.c
index 888f70ef8..38d81af50 100644
--- a/util-linux/ipcrm.c
+++ b/util-linux/ipcrm.c
@@ -119,7 +119,7 @@ int ipcrm_main(int argc, char **argv)
119 119
120 if (remove_ids(what, &argv[2])) 120 if (remove_ids(what, &argv[2]))
121 fflush_stdout_and_exit(EXIT_FAILURE); 121 fflush_stdout_and_exit(EXIT_FAILURE);
122 printf("resource(s) deleted\n"); 122 puts("resource(s) deleted");
123 return 0; 123 return 0;
124 } 124 }
125 } 125 }
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index 662e8ab38..51781d597 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -406,7 +406,7 @@ static void parse_next_rule(void)
406 } 406 }
407 407
408 /* 3rd field: mode - device permissions */ 408 /* 3rd field: mode - device permissions */
409 bb_parse_mode(tokens[2], &G.cur_rule.mode); 409 G.cur_rule.mode = bb_parse_mode(tokens[2], G.cur_rule.mode);
410 410
411 /* 4th field (opt): ">|=alias" or "!" to not create the node */ 411 /* 4th field (opt): ">|=alias" or "!" to not create the node */
412 val = tokens[3]; 412 val = tokens[3];
diff --git a/util-linux/mkfs_minix.c b/util-linux/mkfs_minix.c
index d65a5161c..88d797584 100644
--- a/util-linux/mkfs_minix.c
+++ b/util-linux/mkfs_minix.c
@@ -576,11 +576,11 @@ static void setup_tables(void)
576 for (i = MINIX_ROOT_INO; i <= SB_INODES; i++) 576 for (i = MINIX_ROOT_INO; i <= SB_INODES; i++)
577 unmark_inode(i); 577 unmark_inode(i);
578 G.inode_buffer = xzalloc(INODE_BUFFER_SIZE); 578 G.inode_buffer = xzalloc(INODE_BUFFER_SIZE);
579 printf("%ld inodes\n", (long)SB_INODES); 579 printf("%lu inodes\n", (unsigned long)SB_INODES);
580 printf("%ld blocks\n", (long)SB_ZONES); 580 printf("%lu blocks\n", (unsigned long)SB_ZONES);
581 printf("Firstdatazone=%ld (%ld)\n", (long)SB_FIRSTZONE, (long)norm_firstzone); 581 printf("Firstdatazone=%lu (%lu)\n", (unsigned long)SB_FIRSTZONE, (unsigned long)norm_firstzone);
582 printf("Zonesize=%d\n", BLOCK_SIZE << SB_ZONE_SIZE); 582 printf("Zonesize=%u\n", BLOCK_SIZE << SB_ZONE_SIZE);
583 printf("Maxsize=%ld\n", (long)SB_MAXSIZE); 583 printf("Maxsize=%lu\n", (unsigned long)SB_MAXSIZE);
584} 584}
585 585
586int mkfs_minix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 586int mkfs_minix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c
index a301b365b..7960b672c 100644
--- a/util-linux/switch_root.c
+++ b/util-linux/switch_root.c
@@ -206,7 +206,7 @@ because they're what all paths your process uses would be relative to.
206 206
207That's why the careful sequencing above: we cd into the new mount point before 207That's why the careful sequencing above: we cd into the new mount point before
208we do the mount --move. Moving the mount point would otherwise make it 208we do the mount --move. Moving the mount point would otherwise make it
209totally inaccessible to is because cd-ing to the old path wouldn't give it to 209totally inaccessible to us because cd-ing to the old path wouldn't give it to
210us anymore, and cd "/" just gives us the cached dentry from when the process 210us anymore, and cd "/" just gives us the cached dentry from when the process
211was created (in this case the old initramfs one). But the "." symlink gives 211was created (in this case the old initramfs one). But the "." symlink gives
212us the dentry of the filesystem we just moved, so we can then "chroot ." to 212us the dentry of the filesystem we just moved, so we can then "chroot ." to
diff --git a/util-linux/uevent.c b/util-linux/uevent.c
index fb98b4845..514a9e934 100644
--- a/util-linux/uevent.c
+++ b/util-linux/uevent.c
@@ -37,7 +37,7 @@ enum {
37#ifndef SO_RCVBUFFORCE 37#ifndef SO_RCVBUFFORCE
38#define SO_RCVBUFFORCE 33 38#define SO_RCVBUFFORCE 33
39#endif 39#endif
40static const int RCVBUF = 2 * 1024 * 1024; 40enum { RCVBUF = 2 * 1024 * 1024 };
41 41
42int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 42int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
43int uevent_main(int argc UNUSED_PARAM, char **argv) 43int uevent_main(int argc UNUSED_PARAM, char **argv)
@@ -63,8 +63,8 @@ int uevent_main(int argc UNUSED_PARAM, char **argv)
63 // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';' 63 // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';'
64 // 64 //
65 // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl 65 // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl
66 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &RCVBUF, sizeof(RCVBUF)); 66 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, RCVBUF);
67 setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &RCVBUF, sizeof(RCVBUF)); 67 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, RCVBUF);
68 if (0) { 68 if (0) {
69 int z; 69 int z;
70 socklen_t zl = sizeof(z); 70 socklen_t zl = sizeof(z);
diff --git a/util-linux/umount.c b/util-linux/umount.c
index 4c2e8821e..00910977d 100644
--- a/util-linux/umount.c
+++ b/util-linux/umount.c
@@ -81,8 +81,9 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
81 argv += optind; 81 argv += optind;
82 82
83 // MNT_FORCE and MNT_DETACH (from linux/fs.h) must match 83 // MNT_FORCE and MNT_DETACH (from linux/fs.h) must match
84 // OPT_FORCE and OPT_LAZY, otherwise this trick won't work: 84 // OPT_FORCE and OPT_LAZY.
85 doForce = MAX((opt & OPT_FORCE), (opt & OPT_LAZY)); 85 BUILD_BUG_ON(OPT_FORCE != MNT_FORCE || OPT_LAZY != MNT_DETACH);
86 doForce = opt & (OPT_FORCE|OPT_LAZY);
86 87
87 /* Get a list of mount points from mtab. We read them all in now mostly 88 /* Get a list of mount points from mtab. We read them all in now mostly
88 * for umount -a (so we don't have to worry about the list changing while 89 * for umount -a (so we don't have to worry about the list changing while
@@ -147,11 +148,18 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
147 // umount the directory even if we were given the block device. 148 // umount the directory even if we were given the block device.
148 if (m) zapit = m->dir; 149 if (m) zapit = m->dir;
149 150
151// umount from util-linux 2.22.2 does not do this:
152// umount -f uses umount2(MNT_FORCE) immediately,
153// not trying umount() first.
154// (Strangely, umount -fl ignores -f: it is equivalent to umount -l.
155// We do pass both flags in this case)
156#if 0
150 // Let's ask the thing nicely to unmount. 157 // Let's ask the thing nicely to unmount.
151 curstat = umount(zapit); 158 curstat = umount(zapit);
152 159
153 // Force the unmount, if necessary. 160 // Unmount with force and/or lazy flags, if necessary.
154 if (curstat && doForce) 161 if (curstat && doForce)
162#endif
155 curstat = umount2(zapit, doForce); 163 curstat = umount2(zapit, doForce);
156 164
157 // If still can't umount, maybe remount read-only? 165 // If still can't umount, maybe remount read-only?
@@ -168,7 +176,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
168 bb_error_msg(msg, m->device); 176 bb_error_msg(msg, m->device);
169 } else { 177 } else {
170 status = EXIT_FAILURE; 178 status = EXIT_FAILURE;
171 bb_perror_msg("can't %sumount %s", (doForce ? "forcibly " : ""), zapit); 179 bb_perror_msg("can't unmount %s", zapit);
172 } 180 }
173 } else { 181 } else {
174 // De-allocate the loop device. This ioctl should be ignored on 182 // De-allocate the loop device. This ioctl should be ignored on