aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2012-03-23 11:13:23 +0000
committerRon Yorston <rmy@pobox.com>2012-03-23 11:13:23 +0000
commit40514a0309939f2446f0d4ed9600cad5de396e7f (patch)
tree0f5f4a57d4bb7893418b5bb11d482858eb17ba8b
parent9db164d6e39050d09f38288c6045cd2a2cbf6d63 (diff)
parentc0cae52662ccced9df19f19ec94238d1b1e3bd71 (diff)
downloadbusybox-w32-40514a0309939f2446f0d4ed9600cad5de396e7f.tar.gz
busybox-w32-40514a0309939f2446f0d4ed9600cad5de396e7f.tar.bz2
busybox-w32-40514a0309939f2446f0d4ed9600cad5de396e7f.zip
Merge commit 'c0cae52662ccced9df19f19ec94238d1b1e3bd71' into merge
Conflicts: Makefile.flags scripts/basic/fixdep.c
-rw-r--r--Makefile4
-rw-r--r--Makefile.flags7
-rw-r--r--TODO2
-rw-r--r--applets/applet_tables.c9
-rw-r--r--archival/Config.src19
-rw-r--r--archival/ar.c2
-rw-r--r--archival/bbunzip.c9
-rw-r--r--archival/bzip2.c6
-rw-r--r--archival/cpio.c2
-rw-r--r--archival/dpkg.c2
-rw-r--r--archival/dpkg_deb.c2
-rw-r--r--archival/gzip.c12
-rw-r--r--archival/libarchive/bz/blocksort.c8
-rw-r--r--archival/libarchive/bz/bzlib_private.h2
-rw-r--r--archival/libarchive/bz/compress.c8
-rw-r--r--archival/libarchive/bz/huffman.c2
-rw-r--r--archival/libarchive/data_align.c2
-rw-r--r--archival/libarchive/data_extract_all.c2
-rw-r--r--archival/libarchive/data_extract_to_command.c2
-rw-r--r--archival/libarchive/data_extract_to_stdout.c2
-rw-r--r--archival/libarchive/data_skip.c2
-rw-r--r--archival/libarchive/decompress_bunzip2.c11
-rw-r--r--archival/libarchive/decompress_uncompress.c15
-rw-r--r--archival/libarchive/decompress_unlzma.c2
-rw-r--r--archival/libarchive/decompress_unxz.c2
-rw-r--r--archival/libarchive/decompress_unzip.c2
-rw-r--r--archival/libarchive/filter_accept_all.c2
-rw-r--r--archival/libarchive/filter_accept_list.c2
-rw-r--r--archival/libarchive/filter_accept_list_reassign.c2
-rw-r--r--archival/libarchive/filter_accept_reject_list.c2
-rw-r--r--archival/libarchive/find_list_entry.c2
-rw-r--r--archival/libarchive/get_header_ar.c2
-rw-r--r--archival/libarchive/get_header_cpio.c2
-rw-r--r--archival/libarchive/get_header_tar.c10
-rw-r--r--archival/libarchive/get_header_tar_bz2.c2
-rw-r--r--archival/libarchive/get_header_tar_gz.c2
-rw-r--r--archival/libarchive/get_header_tar_lzma.c2
-rw-r--r--archival/libarchive/header_list.c2
-rw-r--r--archival/libarchive/header_skip.c2
-rw-r--r--archival/libarchive/header_verbose_list.c2
-rw-r--r--archival/libarchive/init_handle.c2
-rw-r--r--archival/libarchive/open_transformer.c2
-rw-r--r--archival/libarchive/seek_by_jump.c2
-rw-r--r--archival/libarchive/seek_by_read.c2
-rw-r--r--archival/libarchive/unpack_ar_archive.c2
-rw-r--r--archival/lzop.c2
-rw-r--r--archival/rpm.c2
-rw-r--r--archival/rpm2cpio.c2
-rw-r--r--archival/tar.c2
-rw-r--r--archival/unzip.c7
-rw-r--r--configs/TEST_nommu_defconfig2
-rw-r--r--configs/TEST_noprintf_defconfig2
-rw-r--r--configs/TEST_rh9_defconfig2
-rw-r--r--configs/android2_defconfig997
-rw-r--r--configs/android_defconfig227
-rw-r--r--configs/cygwin_defconfig2
-rw-r--r--configs/freebsd_defconfig2
-rw-r--r--coreutils/Config.src7
-rw-r--r--coreutils/Kbuild.src1
-rw-r--r--coreutils/du.c3
-rw-r--r--coreutils/expr.c3
-rw-r--r--coreutils/hostid.c13
-rw-r--r--coreutils/pwd.c52
-rw-r--r--coreutils/stty.c12
-rw-r--r--coreutils/tail.c9
-rw-r--r--coreutils/uudecode.c5
-rw-r--r--debianutils/run_parts.c3
-rw-r--r--debianutils/start_stop_daemon.c12
-rw-r--r--docs/ctty.htm3
-rw-r--r--docs/mdev.txt12
-rw-r--r--e2fsprogs/tune2fs.c15
-rw-r--r--editors/awk.c94
-rw-r--r--editors/patch.c26
-rw-r--r--editors/sed.c84
-rw-r--r--editors/vi.c294
-rwxr-xr-xexamples/android-build5
-rwxr-xr-xexamples/depmod.pl2
-rw-r--r--findutils/find.c5
-rw-r--r--findutils/grep.c22
-rw-r--r--include/applets.src.h2
-rw-r--r--include/bb_archive.h (renamed from include/archive.h)0
-rw-r--r--include/libbb.h114
-rw-r--r--include/platform.h6
-rw-r--r--libbb/Config.src15
-rw-r--r--libbb/Kbuild.src6
-rw-r--r--libbb/appletlib.c2
-rw-r--r--libbb/bb_askpass.c22
-rw-r--r--libbb/getpty.c18
-rw-r--r--libbb/hash_md5_sha.c32
-rw-r--r--libbb/hash_md5prime.c26
-rw-r--r--libbb/inet_cksum.c36
-rw-r--r--libbb/lineedit.c110
-rw-r--r--libbb/loop.c10
-rw-r--r--libbb/match_fstype.c4
-rw-r--r--libbb/percent_decode.c69
-rw-r--r--libbb/procps.c34
-rw-r--r--libbb/read_key.c11
-rw-r--r--libbb/read_printf.c2
-rw-r--r--libbb/udp_io.c2
-rw-r--r--libbb/uuencode.c155
-rw-r--r--libbb/vdprintf.c4
-rw-r--r--loginutils/Config.src11
-rw-r--r--loginutils/README70
-rw-r--r--loginutils/chpasswd.c17
-rw-r--r--loginutils/getty.c262
-rw-r--r--loginutils/login.c95
-rw-r--r--mailutils/mail.c11
-rw-r--r--mailutils/makemime.c2
-rw-r--r--mailutils/sendmail.c90
-rw-r--r--miscutils/bbconfig.c2
-rw-r--r--miscutils/conspy.c116
-rw-r--r--miscutils/crond.c3
-rw-r--r--miscutils/fbsplash.c99
-rw-r--r--miscutils/hdparm.c3
-rw-r--r--miscutils/inotifyd.c21
-rw-r--r--miscutils/less.c7
-rw-r--r--miscutils/nandwrite.c16
-rw-r--r--miscutils/runlevel.c2
-rw-r--r--miscutils/rx.c21
-rw-r--r--modutils/modinfo.c1
-rw-r--r--modutils/modutils-24.c1
-rw-r--r--networking/httpd.c76
-rw-r--r--networking/ifupdown.c40
-rw-r--r--networking/inetd.c68
-rw-r--r--networking/nc_bloaty.c3
-rw-r--r--networking/ping.c37
-rw-r--r--networking/tftp.c3
-rw-r--r--networking/traceroute.c35
-rw-r--r--networking/udhcp/common.c6
-rw-r--r--networking/udhcp/common.h7
-rw-r--r--networking/udhcp/dhcpc.c220
-rw-r--r--networking/udhcp/dhcpd.c4
-rw-r--r--networking/udhcp/packet.c34
-rw-r--r--networking/wget.c13
-rw-r--r--networking/zcip.c2
-rw-r--r--procps/Config.src10
-rw-r--r--procps/nmeter.c50
-rw-r--r--procps/ps.c108
-rw-r--r--procps/smemcap.c2
-rw-r--r--procps/top.c2
-rw-r--r--runit/chpst.c14
-rw-r--r--runit/runsvdir.c3
-rw-r--r--scripts/basic/docproc.c1
-rw-r--r--scripts/basic/fixdep.c1
-rw-r--r--scripts/defconfig.tig24
-rwxr-xr-xscripts/gen_build_files.sh56
-rw-r--r--shell/ash.c6
-rw-r--r--shell/cttyhack.c71
-rw-r--r--shell/hush.c41
-rw-r--r--sysklogd/syslogd.c12
-rwxr-xr-xtestsuite/awk.tests3
-rwxr-xr-xtestsuite/bzcat.tests30
-rwxr-xr-xtestsuite/grep.tests18
-rwxr-xr-xtestsuite/patch.tests30
-rwxr-xr-xtestsuite/sed.tests10
-rwxr-xr-xtestsuite/tail.tests8
-rwxr-xr-xtestsuite/uncompress.tests20
-rwxr-xr-xtestsuite/uuencode.tests101
-rw-r--r--util-linux/Config.src58
-rw-r--r--util-linux/Kbuild.src1
-rw-r--r--util-linux/losetup.c16
-rw-r--r--util-linux/mdev.c676
-rw-r--r--util-linux/mount.c25
-rw-r--r--util-linux/swaponoff.c7
164 files changed, 3969 insertions, 1628 deletions
diff --git a/Makefile b/Makefile
index 7d2db1871..bc05f3a27 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
1VERSION = 1 1VERSION = 1
2PATCHLEVEL = 19 2PATCHLEVEL = 20
3SUBLEVEL = 0 3SUBLEVEL = 0
4EXTRAVERSION = 4EXTRAVERSION = .git
5NAME = Unnamed 5NAME = Unnamed
6 6
7# *DOCUMENTATION* 7# *DOCUMENTATION*
diff --git a/Makefile.flags b/Makefile.flags
index 513b6ebb2..b653d55c1 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -99,13 +99,18 @@ endif
99 99
100ifeq ($(CONFIG_PLATFORM_MINGW32),y) 100ifeq ($(CONFIG_PLATFORM_MINGW32),y)
101# These defintions are not strictly needed, but they help shut up fnmatch.c warnings 101# These defintions are not strictly needed, but they help shut up fnmatch.c warnings
102CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 102CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy
103EXEEXT = .exe 103EXEEXT = .exe
104ifeq ($(CONFIG_WIN32_NET),y) 104ifeq ($(CONFIG_WIN32_NET),y)
105LDLIBS += ws2_32 105LDLIBS += ws2_32
106endif 106endif
107else 107else
108ifneq ($(CONFIG_CROSS_COMPILER_PREFIX),"arm-linux-androideabi-")
108LDLIBS += m crypt 109LDLIBS += m crypt
110else
111# Android libc has no crypt. TODO: make a generic CONFIG_LINK_WITH_CRYPT option?
112LDLIBS += m
113endif
109endif 114endif
110 115
111ifeq ($(CONFIG_PAM),y) 116ifeq ($(CONFIG_PAM),y)
diff --git a/TODO b/TODO
index 8b9f87f79..44364690f 100644
--- a/TODO
+++ b/TODO
@@ -2,6 +2,8 @@ Busybox TODO
2 2
3Harvest patches from 3Harvest patches from
4http://git.openembedded.org/cgit.cgi/openembedded/tree/recipes/busybox/ 4http://git.openembedded.org/cgit.cgi/openembedded/tree/recipes/busybox/
5https://dev.openwrt.org/browser/trunk/package/busybox/patches/
6
5 7
6Stuff that needs to be done. This is organized by who plans to get around to 8Stuff that needs to be done. This is organized by who plans to get around to
7doing it eventually, but that doesn't mean they "own" the item. If you want to 9doing it eventually, but that doesn't mean they "own" the item. If you want to
diff --git a/applets/applet_tables.c b/applets/applet_tables.c
index 3859d7326..a47574737 100644
--- a/applets/applet_tables.c
+++ b/applets/applet_tables.c
@@ -80,8 +80,15 @@ int main(int argc, char **argv)
80 80
81 printf("#define NUM_APPLETS %u\n", NUM_APPLETS); 81 printf("#define NUM_APPLETS %u\n", NUM_APPLETS);
82 if (NUM_APPLETS == 1) { 82 if (NUM_APPLETS == 1) {
83 char *dash_to_underscore, *p;
83 printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name); 84 printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name);
84 printf("#define SINGLE_APPLET_MAIN %s_main\n", applets[0].name); 85 /* Example: "ether-wake" -> "ether_wake" */
86 p = dash_to_underscore = strdup(applets[0].name);
87 p--;
88 while (*++p)
89 if (*p == '-')
90 *p = '_';
91 printf("#define SINGLE_APPLET_MAIN %s_main\n", dash_to_underscore);
85 } 92 }
86 printf("\n"); 93 printf("\n");
87 94
diff --git a/archival/Config.src b/archival/Config.src
index 7e493f56f..f1d6d3511 100644
--- a/archival/Config.src
+++ b/archival/Config.src
@@ -187,6 +187,18 @@ config FEATURE_GZIP_LONG_OPTIONS
187 help 187 help
188 Enable use of long options, increases size by about 106 Bytes 188 Enable use of long options, increases size by about 106 Bytes
189 189
190config GZIP_FAST
191 int "Trade memory for gzip speed (0:small,slow - 2:fast,big)"
192 default 0
193 range 0 2
194 depends on GZIP
195 help
196 Enable big memory options for gzip.
197 0: small buffers, small hash-tables
198 1: larger buffers, larger hash-tables
199 2: larger buffers, largest hash-tables
200 Larger models may give slightly better compression
201
190config LZOP 202config LZOP
191 bool "lzop" 203 bool "lzop"
192 default y 204 default y
@@ -331,15 +343,12 @@ config UNLZMA
331 is generally considerably better than that achieved by the bzip2 343 is generally considerably better than that achieved by the bzip2
332 compressors. 344 compressors.
333 345
334 The BusyBox unlzma applet is limited to de-compression only. 346 The BusyBox unlzma applet is limited to decompression only.
335 On an x86 system, this applet adds about 4K. 347 On an x86 system, this applet adds about 4K.
336 348
337 Unless you have a specific application which requires unlzma, you
338 should probably say N here.
339
340config FEATURE_LZMA_FAST 349config FEATURE_LZMA_FAST
341 bool "Optimize unlzma for speed" 350 bool "Optimize unlzma for speed"
342 default y 351 default n
343 depends on UNLZMA 352 depends on UNLZMA
344 help 353 help
345 This option reduces decompression time by about 25% at the cost of 354 This option reduces decompression time by about 25% at the cost of
diff --git a/archival/ar.c b/archival/ar.c
index acad20ff2..88236e878 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -28,7 +28,7 @@
28//usage: "\n -v Verbose" 28//usage: "\n -v Verbose"
29 29
30#include "libbb.h" 30#include "libbb.h"
31#include "archive.h" 31#include "bb_archive.h"
32#include "ar.h" 32#include "ar.h"
33 33
34#if ENABLE_FEATURE_AR_CREATE 34#if ENABLE_FEATURE_AR_CREATE
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index 0b0d84994..c96e5396a 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -5,7 +5,7 @@
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 */ 6 */
7#include "libbb.h" 7#include "libbb.h"
8#include "archive.h" 8#include "bb_archive.h"
9 9
10enum { 10enum {
11 OPT_STDOUT = 1 << 0, 11 OPT_STDOUT = 1 << 0,
@@ -103,7 +103,9 @@ int FAST_FUNC bbunpack(char **argv,
103 status = unpacker(&info); 103 status = unpacker(&info);
104 if (status < 0) 104 if (status < 0)
105 exitcode = 1; 105 exitcode = 1;
106 xclose(STDOUT_FILENO); /* with error check! */ 106
107 if (!(option_mask32 & OPT_STDOUT))
108 xclose(STDOUT_FILENO); /* with error check! */
107 109
108 if (filename) { 110 if (filename) {
109 char *del = new_name; 111 char *del = new_name;
@@ -145,6 +147,9 @@ int FAST_FUNC bbunpack(char **argv,
145 } 147 }
146 } while (*argv && *++argv); 148 } while (*argv && *++argv);
147 149
150 if (option_mask32 & OPT_STDOUT)
151 xclose(STDOUT_FILENO); /* with error check! */
152
148 return exitcode; 153 return exitcode;
149} 154}
150 155
diff --git a/archival/bzip2.c b/archival/bzip2.c
index e39d7f704..0716fa89b 100644
--- a/archival/bzip2.c
+++ b/archival/bzip2.c
@@ -17,9 +17,9 @@
17//usage: "\n -f Force" 17//usage: "\n -f Force"
18 18
19#include "libbb.h" 19#include "libbb.h"
20#include "archive.h" 20#include "bb_archive.h"
21 21
22#define CONFIG_BZIP2_FEATURE_SPEED 1 22#define CONFIG_BZIP2_FAST 1
23 23
24/* Speed test: 24/* Speed test:
25 * Compiled with gcc 4.2.1, run on Athlon 64 1800 MHz (512K L2 cache). 25 * Compiled with gcc 4.2.1, run on Athlon 64 1800 MHz (512K L2 cache).
@@ -27,7 +27,7 @@
27 * (time to compress gcc-4.2.1.tar is 126.4% compared to bbox). 27 * (time to compress gcc-4.2.1.tar is 126.4% compared to bbox).
28 * At SPEED 5 difference is 32.7%. 28 * At SPEED 5 difference is 32.7%.
29 * 29 *
30 * Test run of all CONFIG_BZIP2_FEATURE_SPEED values on a 11Mb text file: 30 * Test run of all CONFIG_BZIP2_FAST values on a 11Mb text file:
31 * Size Time (3 runs) 31 * Size Time (3 runs)
32 * 0: 10828 4.145 4.146 4.148 32 * 0: 10828 4.145 4.146 4.148
33 * 1: 11097 3.845 3.860 3.861 33 * 1: 11097 3.845 3.860 3.861
diff --git a/archival/cpio.c b/archival/cpio.c
index 9674a046b..c2a5b8ab9 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -12,7 +12,7 @@
12 * 12 *
13 */ 13 */
14#include "libbb.h" 14#include "libbb.h"
15#include "archive.h" 15#include "bb_archive.h"
16 16
17//usage:#define cpio_trivial_usage 17//usage:#define cpio_trivial_usage
18//usage: "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]") 18//usage: "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]")
diff --git a/archival/dpkg.c b/archival/dpkg.c
index 2a6a7b3bf..bf9e9992c 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -57,7 +57,7 @@
57 57
58#include "libbb.h" 58#include "libbb.h"
59#include <fnmatch.h> 59#include <fnmatch.h>
60#include "archive.h" 60#include "bb_archive.h"
61 61
62/* note: if you vary hash_prime sizes be aware, 62/* note: if you vary hash_prime sizes be aware,
63 * 1) tweaking these will have a big effect on how much memory this program uses. 63 * 1) tweaking these will have a big effect on how much memory this program uses.
diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c
index 5d814d7ef..a04ec9407 100644
--- a/archival/dpkg_deb.c
+++ b/archival/dpkg_deb.c
@@ -19,7 +19,7 @@
19//usage: "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n" 19//usage: "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n"
20 20
21#include "libbb.h" 21#include "libbb.h"
22#include "archive.h" 22#include "bb_archive.h"
23 23
24#define DPKG_DEB_OPT_CONTENTS 1 24#define DPKG_DEB_OPT_CONTENTS 1
25#define DPKG_DEB_OPT_CONTROL 2 25#define DPKG_DEB_OPT_CONTROL 2
diff --git a/archival/gzip.c b/archival/gzip.c
index 507f5b151..f590fffa5 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -55,7 +55,7 @@ aa: 85.1% -- replaced with aa.gz
55//usage: "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n" 55//usage: "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
56 56
57#include "libbb.h" 57#include "libbb.h"
58#include "archive.h" 58#include "bb_archive.h"
59 59
60 60
61/* =========================================================================== 61/* ===========================================================================
@@ -81,7 +81,15 @@ aa: 85.1% -- replaced with aa.gz
81 81
82/* =========================================================================== 82/* ===========================================================================
83 */ 83 */
84#define SMALL_MEM 84#if CONFIG_GZIP_FAST == 0
85# define SMALL_MEM
86#elif CONFIG_GZIP_FAST == 1
87# define MEDIUM_MEM
88#elif CONFIG_GZIP_FAST == 2
89# define BIG_MEM
90#else
91# error "Invalid CONFIG_GZIP_FAST value"
92#endif
85 93
86#ifndef INBUFSIZ 94#ifndef INBUFSIZ
87# ifdef SMALL_MEM 95# ifdef SMALL_MEM
diff --git a/archival/libarchive/bz/blocksort.c b/archival/libarchive/bz/blocksort.c
index f70c3701d..e600cb7a7 100644
--- a/archival/libarchive/bz/blocksort.c
+++ b/archival/libarchive/bz/blocksort.c
@@ -385,7 +385,7 @@ int mainGtU(
385 * but speeds up compression 10% overall 385 * but speeds up compression 10% overall
386 */ 386 */
387 387
388#if CONFIG_BZIP2_FEATURE_SPEED >= 1 388#if CONFIG_BZIP2_FAST >= 1
389 389
390#define TIMES_8(code) \ 390#define TIMES_8(code) \
391 code; code; code; code; \ 391 code; code; code; code; \
@@ -496,7 +496,7 @@ void mainSimpleSort(uint32_t* ptr,
496 i++; 496 i++;
497 497
498/* 1.5% overall speedup, +290 bytes */ 498/* 1.5% overall speedup, +290 bytes */
499#if CONFIG_BZIP2_FEATURE_SPEED >= 3 499#if CONFIG_BZIP2_FAST >= 3
500 /*-- copy 2 --*/ 500 /*-- copy 2 --*/
501 if (i > hi) break; 501 if (i > hi) break;
502 v = ptr[i]; 502 v = ptr[i];
@@ -750,7 +750,7 @@ void mainSort(EState* state,
750 j = block[0] << 8; 750 j = block[0] << 8;
751 i = nblock - 1; 751 i = nblock - 1;
752/* 3%, +300 bytes */ 752/* 3%, +300 bytes */
753#if CONFIG_BZIP2_FEATURE_SPEED >= 2 753#if CONFIG_BZIP2_FAST >= 2
754 for (; i >= 3; i -= 4) { 754 for (; i >= 3; i -= 4) {
755 quadrant[i] = 0; 755 quadrant[i] = 0;
756 j = (j >> 8) | (((uint16_t)block[i]) << 8); 756 j = (j >> 8) | (((uint16_t)block[i]) << 8);
@@ -787,7 +787,7 @@ void mainSort(EState* state,
787 787
788 s = block[0] << 8; 788 s = block[0] << 8;
789 i = nblock - 1; 789 i = nblock - 1;
790#if CONFIG_BZIP2_FEATURE_SPEED >= 2 790#if CONFIG_BZIP2_FAST >= 2
791 for (; i >= 3; i -= 4) { 791 for (; i >= 3; i -= 4) {
792 s = (s >> 8) | (block[i] << 8); 792 s = (s >> 8) | (block[i] << 8);
793 j = ftab[s] - 1; 793 j = ftab[s] - 1;
diff --git a/archival/libarchive/bz/bzlib_private.h b/archival/libarchive/bz/bzlib_private.h
index 6430ce407..43e674bec 100644
--- a/archival/libarchive/bz/bzlib_private.h
+++ b/archival/libarchive/bz/bzlib_private.h
@@ -183,7 +183,7 @@ typedef struct EState {
183 /* stack-saving measures: these can be local, but they are too big */ 183 /* stack-saving measures: these can be local, but they are too big */
184 int32_t sendMTFValues__code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; 184 int32_t sendMTFValues__code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
185 int32_t sendMTFValues__rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; 185 int32_t sendMTFValues__rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
186#if CONFIG_BZIP2_FEATURE_SPEED >= 5 186#if CONFIG_BZIP2_FAST >= 5
187 /* second dimension: only 3 needed; 4 makes index calculations faster */ 187 /* second dimension: only 3 needed; 4 makes index calculations faster */
188 uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4]; 188 uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4];
189#endif 189#endif
diff --git a/archival/libarchive/bz/compress.c b/archival/libarchive/bz/compress.c
index f93671742..e9f1afdaf 100644
--- a/archival/libarchive/bz/compress.c
+++ b/archival/libarchive/bz/compress.c
@@ -61,7 +61,7 @@ void bsFinishWrite(EState* s)
61/*---------------------------------------------------*/ 61/*---------------------------------------------------*/
62static 62static
63/* Helps only on level 5, on other levels hurts. ? */ 63/* Helps only on level 5, on other levels hurts. ? */
64#if CONFIG_BZIP2_FEATURE_SPEED >= 5 64#if CONFIG_BZIP2_FAST >= 5
65ALWAYS_INLINE 65ALWAYS_INLINE
66#endif 66#endif
67void bsW(EState* s, int32_t n, uint32_t v) 67void bsW(EState* s, int32_t n, uint32_t v)
@@ -331,7 +331,7 @@ void sendMTFValues(EState* s)
331 for (v = 0; v < alphaSize; v++) 331 for (v = 0; v < alphaSize; v++)
332 s->rfreq[t][v] = 0; 332 s->rfreq[t][v] = 0;
333 333
334#if CONFIG_BZIP2_FEATURE_SPEED >= 5 334#if CONFIG_BZIP2_FAST >= 5
335 /* 335 /*
336 * Set up an auxiliary length table which is used to fast-track 336 * Set up an auxiliary length table which is used to fast-track
337 * the common case (nGroups == 6). 337 * the common case (nGroups == 6).
@@ -361,7 +361,7 @@ void sendMTFValues(EState* s)
361 */ 361 */
362 for (t = 0; t < nGroups; t++) 362 for (t = 0; t < nGroups; t++)
363 cost[t] = 0; 363 cost[t] = 0;
364#if CONFIG_BZIP2_FEATURE_SPEED >= 5 364#if CONFIG_BZIP2_FAST >= 5
365 if (nGroups == 6 && 50 == ge-gs+1) { 365 if (nGroups == 6 && 50 == ge-gs+1) {
366 /*--- fast track the common case ---*/ 366 /*--- fast track the common case ---*/
367 register uint32_t cost01, cost23, cost45; 367 register uint32_t cost01, cost23, cost45;
@@ -420,7 +420,7 @@ void sendMTFValues(EState* s)
420 * Increment the symbol frequencies for the selected table. 420 * Increment the symbol frequencies for the selected table.
421 */ 421 */
422/* 1% faster compress. +800 bytes */ 422/* 1% faster compress. +800 bytes */
423#if CONFIG_BZIP2_FEATURE_SPEED >= 4 423#if CONFIG_BZIP2_FAST >= 4
424 if (nGroups == 6 && 50 == ge-gs+1) { 424 if (nGroups == 6 && 50 == ge-gs+1) {
425 /*--- fast track the common case ---*/ 425 /*--- fast track the common case ---*/
426#define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++ 426#define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++
diff --git a/archival/libarchive/bz/huffman.c b/archival/libarchive/bz/huffman.c
index 676b1af66..bbec11adb 100644
--- a/archival/libarchive/bz/huffman.c
+++ b/archival/libarchive/bz/huffman.c
@@ -48,7 +48,7 @@ in the file LICENSE.
48 48
49 49
50/* 90 bytes, 0.3% of overall compress speed */ 50/* 90 bytes, 0.3% of overall compress speed */
51#if CONFIG_BZIP2_FEATURE_SPEED >= 1 51#if CONFIG_BZIP2_FAST >= 1
52 52
53/* macro works better than inline (gcc 4.2.1) */ 53/* macro works better than inline (gcc 4.2.1) */
54#define DOWNHEAP1(heap, weight, Heap) \ 54#define DOWNHEAP1(heap, weight, Heap) \
diff --git a/archival/libarchive/data_align.c b/archival/libarchive/data_align.c
index 2e56fa8ff..a6b84a440 100644
--- a/archival/libarchive/data_align.c
+++ b/archival/libarchive/data_align.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary) 9void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary)
10{ 10{
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index 1b25c8bd6..f565e5471 100644
--- a/archival/libarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) 9void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
10{ 10{
diff --git a/archival/libarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c
index 0e977049d..cc2ff7798 100644
--- a/archival/libarchive/data_extract_to_command.c
+++ b/archival/libarchive/data_extract_to_command.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9enum { 9enum {
10 //TAR_FILETYPE, 10 //TAR_FILETYPE,
diff --git a/archival/libarchive/data_extract_to_stdout.c b/archival/libarchive/data_extract_to_stdout.c
index 91f3f3539..f849f3b42 100644
--- a/archival/libarchive/data_extract_to_stdout.c
+++ b/archival/libarchive/data_extract_to_stdout.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle) 9void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle)
10{ 10{
diff --git a/archival/libarchive/data_skip.c b/archival/libarchive/data_skip.c
index a055424e2..588167f01 100644
--- a/archival/libarchive/data_skip.c
+++ b/archival/libarchive/data_skip.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9void FAST_FUNC data_skip(archive_handle_t *archive_handle) 9void FAST_FUNC data_skip(archive_handle_t *archive_handle)
10{ 10{
diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c
index 4e46e6849..c4640d489 100644
--- a/archival/libarchive/decompress_bunzip2.c
+++ b/archival/libarchive/decompress_bunzip2.c
@@ -40,7 +40,7 @@
40 */ 40 */
41 41
42#include "libbb.h" 42#include "libbb.h"
43#include "archive.h" 43#include "bb_archive.h"
44 44
45/* Constants for Huffman coding */ 45/* Constants for Huffman coding */
46#define MAX_GROUPS 6 46#define MAX_GROUPS 6
@@ -752,7 +752,14 @@ unpack_bz2_stream(int src_fd, int dst_fd)
752 } 752 }
753 } 753 }
754 754
755 if (i != RETVAL_LAST_BLOCK) { 755 if (i != RETVAL_LAST_BLOCK
756 /* Observed case when i == RETVAL_OK:
757 * "bzcat z.bz2", where "z.bz2" is a bzipped zero-length file
758 * (to be exact, z.bz2 is exactly these 14 bytes:
759 * 42 5a 68 39 17 72 45 38 50 90 00 00 00 00).
760 */
761 && i != RETVAL_OK
762 ) {
756 bb_error_msg("bunzip error %d", i); 763 bb_error_msg("bunzip error %d", i);
757 break; 764 break;
758 } 765 }
diff --git a/archival/libarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c
index 44d894244..c6040d04b 100644
--- a/archival/libarchive/decompress_uncompress.c
+++ b/archival/libarchive/decompress_uncompress.c
@@ -25,7 +25,7 @@
25 */ 25 */
26 26
27#include "libbb.h" 27#include "libbb.h"
28#include "archive.h" 28#include "bb_archive.h"
29 29
30 30
31/* Default input buffer size */ 31/* Default input buffer size */
@@ -163,7 +163,8 @@ unpack_Z_stream(int fd_in, int fd_out)
163 163
164 if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { 164 if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) {
165 rsize = safe_read(fd_in, inbuf + insize, IBUFSIZ); 165 rsize = safe_read(fd_in, inbuf + insize, IBUFSIZ);
166//error check?? 166 if (rsize < 0)
167 bb_error_msg_and_die(bb_msg_read_error);
167 insize += rsize; 168 insize += rsize;
168 } 169 }
169 170
@@ -195,6 +196,8 @@ unpack_Z_stream(int fd_in, int fd_out)
195 196
196 197
197 if (oldcode == -1) { 198 if (oldcode == -1) {
199 if (code >= 256)
200 bb_error_msg_and_die("corrupted data"); /* %ld", code); */
198 oldcode = code; 201 oldcode = code;
199 finchar = (int) oldcode; 202 finchar = (int) oldcode;
200 outbuf[outpos++] = (unsigned char) finchar; 203 outbuf[outpos++] = (unsigned char) finchar;
@@ -239,6 +242,8 @@ unpack_Z_stream(int fd_in, int fd_out)
239 242
240 /* Generate output characters in reverse order */ 243 /* Generate output characters in reverse order */
241 while ((long) code >= (long) 256) { 244 while ((long) code >= (long) 256) {
245 if (stackp <= &htabof(0))
246 bb_error_msg_and_die("corrupted data");
242 *--stackp = tab_suffixof(code); 247 *--stackp = tab_suffixof(code);
243 code = tab_prefixof(code); 248 code = tab_prefixof(code);
244 } 249 }
@@ -263,8 +268,7 @@ unpack_Z_stream(int fd_in, int fd_out)
263 } 268 }
264 269
265 if (outpos >= OBUFSIZ) { 270 if (outpos >= OBUFSIZ) {
266 full_write(fd_out, outbuf, outpos); 271 xwrite(fd_out, outbuf, outpos);
267//error check??
268 IF_DESKTOP(total_written += outpos;) 272 IF_DESKTOP(total_written += outpos;)
269 outpos = 0; 273 outpos = 0;
270 } 274 }
@@ -292,8 +296,7 @@ unpack_Z_stream(int fd_in, int fd_out)
292 } while (rsize > 0); 296 } while (rsize > 0);
293 297
294 if (outpos > 0) { 298 if (outpos > 0) {
295 full_write(fd_out, outbuf, outpos); 299 xwrite(fd_out, outbuf, outpos);
296//error check??
297 IF_DESKTOP(total_written += outpos;) 300 IF_DESKTOP(total_written += outpos;)
298 } 301 }
299 302
diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c
index a04714341..3631b50cc 100644
--- a/archival/libarchive/decompress_unlzma.c
+++ b/archival/libarchive/decompress_unlzma.c
@@ -9,7 +9,7 @@
9 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
10 */ 10 */
11#include "libbb.h" 11#include "libbb.h"
12#include "archive.h" 12#include "bb_archive.h"
13 13
14#if ENABLE_FEATURE_LZMA_FAST 14#if ENABLE_FEATURE_LZMA_FAST
15# define speed_inline ALWAYS_INLINE 15# define speed_inline ALWAYS_INLINE
diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
index e90dfb06f..3e5d4edca 100644
--- a/archival/libarchive/decompress_unxz.c
+++ b/archival/libarchive/decompress_unxz.c
@@ -10,7 +10,7 @@
10 * Licensed under GPLv2, see file LICENSE in this source tree. 10 * Licensed under GPLv2, see file LICENSE in this source tree.
11 */ 11 */
12#include "libbb.h" 12#include "libbb.h"
13#include "archive.h" 13#include "bb_archive.h"
14 14
15#define XZ_FUNC FAST_FUNC 15#define XZ_FUNC FAST_FUNC
16#define XZ_EXTERN static 16#define XZ_EXTERN static
diff --git a/archival/libarchive/decompress_unzip.c b/archival/libarchive/decompress_unzip.c
index a29eef837..aa5d22d0a 100644
--- a/archival/libarchive/decompress_unzip.c
+++ b/archival/libarchive/decompress_unzip.c
@@ -35,7 +35,7 @@
35 35
36#include <setjmp.h> 36#include <setjmp.h>
37#include "libbb.h" 37#include "libbb.h"
38#include "archive.h" 38#include "bb_archive.h"
39 39
40typedef struct huft_t { 40typedef struct huft_t {
41 unsigned char e; /* number of extra bits or operation */ 41 unsigned char e; /* number of extra bits or operation */
diff --git a/archival/libarchive/filter_accept_all.c b/archival/libarchive/filter_accept_all.c
index e69deb679..c33f7d3e3 100644
--- a/archival/libarchive/filter_accept_all.c
+++ b/archival/libarchive/filter_accept_all.c
@@ -6,7 +6,7 @@
6 */ 6 */
7 7
8#include "libbb.h" 8#include "libbb.h"
9#include "archive.h" 9#include "bb_archive.h"
10 10
11/* Accept any non-null name, its not really a filter at all */ 11/* Accept any non-null name, its not really a filter at all */
12char FAST_FUNC filter_accept_all(archive_handle_t *archive_handle) 12char FAST_FUNC filter_accept_all(archive_handle_t *archive_handle)
diff --git a/archival/libarchive/filter_accept_list.c b/archival/libarchive/filter_accept_list.c
index a7640af79..a2d4b23e9 100644
--- a/archival/libarchive/filter_accept_list.c
+++ b/archival/libarchive/filter_accept_list.c
@@ -6,7 +6,7 @@
6 */ 6 */
7 7
8#include "libbb.h" 8#include "libbb.h"
9#include "archive.h" 9#include "bb_archive.h"
10 10
11/* 11/*
12 * Accept names that are in the accept list, ignoring reject list. 12 * Accept names that are in the accept list, ignoring reject list.
diff --git a/archival/libarchive/filter_accept_list_reassign.c b/archival/libarchive/filter_accept_list_reassign.c
index d80f71668..3d19abe44 100644
--- a/archival/libarchive/filter_accept_list_reassign.c
+++ b/archival/libarchive/filter_accept_list_reassign.c
@@ -6,7 +6,7 @@
6 */ 6 */
7 7
8#include "libbb.h" 8#include "libbb.h"
9#include "archive.h" 9#include "bb_archive.h"
10 10
11/* Built and used only if ENABLE_DPKG || ENABLE_DPKG_DEB */ 11/* Built and used only if ENABLE_DPKG || ENABLE_DPKG_DEB */
12 12
diff --git a/archival/libarchive/filter_accept_reject_list.c b/archival/libarchive/filter_accept_reject_list.c
index 3e86cca65..39c811337 100644
--- a/archival/libarchive/filter_accept_reject_list.c
+++ b/archival/libarchive/filter_accept_reject_list.c
@@ -6,7 +6,7 @@
6 */ 6 */
7 7
8#include "libbb.h" 8#include "libbb.h"
9#include "archive.h" 9#include "bb_archive.h"
10 10
11/* 11/*
12 * Accept names that are in the accept list and not in the reject list 12 * Accept names that are in the accept list and not in the reject list
diff --git a/archival/libarchive/find_list_entry.c b/archival/libarchive/find_list_entry.c
index 5efd1af2e..56032c65a 100644
--- a/archival/libarchive/find_list_entry.c
+++ b/archival/libarchive/find_list_entry.c
@@ -7,7 +7,7 @@
7 7
8#include <fnmatch.h> 8#include <fnmatch.h>
9#include "libbb.h" 9#include "libbb.h"
10#include "archive.h" 10#include "bb_archive.h"
11 11
12/* Find a string in a shell pattern list */ 12/* Find a string in a shell pattern list */
13const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename) 13const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename)
diff --git a/archival/libarchive/get_header_ar.c b/archival/libarchive/get_header_ar.c
index df603b111..23c412496 100644
--- a/archival/libarchive/get_header_ar.c
+++ b/archival/libarchive/get_header_ar.c
@@ -5,7 +5,7 @@
5 */ 5 */
6 6
7#include "libbb.h" 7#include "libbb.h"
8#include "archive.h" 8#include "bb_archive.h"
9#include "ar.h" 9#include "ar.h"
10 10
11static unsigned read_num(const char *str, int base) 11static unsigned read_num(const char *str, int base)
diff --git a/archival/libarchive/get_header_cpio.c b/archival/libarchive/get_header_cpio.c
index 3d99b492a..1a0058b63 100644
--- a/archival/libarchive/get_header_cpio.c
+++ b/archival/libarchive/get_header_cpio.c
@@ -5,7 +5,7 @@
5 */ 5 */
6 6
7#include "libbb.h" 7#include "libbb.h"
8#include "archive.h" 8#include "bb_archive.h"
9 9
10typedef struct hardlinks_t { 10typedef struct hardlinks_t {
11 struct hardlinks_t *next; 11 struct hardlinks_t *next;
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index 79caff55a..a63c0fb01 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -12,7 +12,7 @@
12 */ 12 */
13 13
14#include "libbb.h" 14#include "libbb.h"
15#include "archive.h" 15#include "bb_archive.h"
16 16
17typedef uint32_t aliased_uint32_t FIX_ALIASING; 17typedef uint32_t aliased_uint32_t FIX_ALIASING;
18typedef off_t aliased_off_t FIX_ALIASING; 18typedef off_t aliased_off_t FIX_ALIASING;
@@ -79,10 +79,10 @@ static unsigned long long getOctal(char *str, int len)
79 * 79 *
80 * NB: tarballs with NEGATIVE unix times encoded that way were seen! 80 * NB: tarballs with NEGATIVE unix times encoded that way were seen!
81 */ 81 */
82 v = first; 82 /* Sign-extend 7bit 'first' to 64bit 'v' (that is, using 6th bit as sign): */
83 /* Sign-extend using 6th bit: */ 83 first <<= 1;
84 v <<= sizeof(unsigned long long)*8 - 7; 84 first >>= 1; /* now 7th bit = 6th bit */
85 v = (long long)v >> (sizeof(unsigned long long)*8 - 7); 85 v = first; /* sign-extend 8 bits to 64 */
86 while (--len != 0) 86 while (--len != 0)
87 v = (v << 8) + (unsigned char) *str++; 87 v = (v << 8) + (unsigned char) *str++;
88 } 88 }
diff --git a/archival/libarchive/get_header_tar_bz2.c b/archival/libarchive/get_header_tar_bz2.c
index 60d32069f..e012dec3b 100644
--- a/archival/libarchive/get_header_tar_bz2.c
+++ b/archival/libarchive/get_header_tar_bz2.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle) 9char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle)
10{ 10{
diff --git a/archival/libarchive/get_header_tar_gz.c b/archival/libarchive/get_header_tar_gz.c
index 889fed0d9..b9679b0bd 100644
--- a/archival/libarchive/get_header_tar_gz.c
+++ b/archival/libarchive/get_header_tar_gz.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) 9char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle)
10{ 10{
diff --git a/archival/libarchive/get_header_tar_lzma.c b/archival/libarchive/get_header_tar_lzma.c
index da08e0c72..666700729 100644
--- a/archival/libarchive/get_header_tar_lzma.c
+++ b/archival/libarchive/get_header_tar_lzma.c
@@ -7,7 +7,7 @@
7 */ 7 */
8 8
9#include "libbb.h" 9#include "libbb.h"
10#include "archive.h" 10#include "bb_archive.h"
11 11
12char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle) 12char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle)
13{ 13{
diff --git a/archival/libarchive/header_list.c b/archival/libarchive/header_list.c
index c4fc75f38..0621aa406 100644
--- a/archival/libarchive/header_list.c
+++ b/archival/libarchive/header_list.c
@@ -3,7 +3,7 @@
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */ 4 */
5#include "libbb.h" 5#include "libbb.h"
6#include "archive.h" 6#include "bb_archive.h"
7 7
8void FAST_FUNC header_list(const file_header_t *file_header) 8void FAST_FUNC header_list(const file_header_t *file_header)
9{ 9{
diff --git a/archival/libarchive/header_skip.c b/archival/libarchive/header_skip.c
index 2bfc5253c..f5987bfe2 100644
--- a/archival/libarchive/header_skip.c
+++ b/archival/libarchive/header_skip.c
@@ -3,7 +3,7 @@
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */ 4 */
5#include "libbb.h" 5#include "libbb.h"
6#include "archive.h" 6#include "bb_archive.h"
7 7
8void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM) 8void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM)
9{ 9{
diff --git a/archival/libarchive/header_verbose_list.c b/archival/libarchive/header_verbose_list.c
index bc4e4154b..87dd82136 100644
--- a/archival/libarchive/header_verbose_list.c
+++ b/archival/libarchive/header_verbose_list.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9void FAST_FUNC header_verbose_list(const file_header_t *file_header) 9void FAST_FUNC header_verbose_list(const file_header_t *file_header)
10{ 10{
diff --git a/archival/libarchive/init_handle.c b/archival/libarchive/init_handle.c
index 6644ea13b..cbae06ac3 100644
--- a/archival/libarchive/init_handle.c
+++ b/archival/libarchive/init_handle.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9archive_handle_t* FAST_FUNC init_handle(void) 9archive_handle_t* FAST_FUNC init_handle(void)
10{ 10{
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index 26ae565f5..aa8c1021c 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9/* transformer(), more than meets the eye */ 9/* transformer(), more than meets the eye */
10/* 10/*
diff --git a/archival/libarchive/seek_by_jump.c b/archival/libarchive/seek_by_jump.c
index 7c2c52ae1..4fcd99ac8 100644
--- a/archival/libarchive/seek_by_jump.c
+++ b/archival/libarchive/seek_by_jump.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9void FAST_FUNC seek_by_jump(int fd, off_t amount) 9void FAST_FUNC seek_by_jump(int fd, off_t amount)
10{ 10{
diff --git a/archival/libarchive/seek_by_read.c b/archival/libarchive/seek_by_read.c
index ad931a8de..c0fde9660 100644
--- a/archival/libarchive/seek_by_read.c
+++ b/archival/libarchive/seek_by_read.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8 8
9/* If we are reading through a pipe, or from stdin then we can't lseek, 9/* If we are reading through a pipe, or from stdin then we can't lseek,
10 * we must read and discard the data to skip over it. 10 * we must read and discard the data to skip over it.
diff --git a/archival/libarchive/unpack_ar_archive.c b/archival/libarchive/unpack_ar_archive.c
index 18dbfd54d..214d17e23 100644
--- a/archival/libarchive/unpack_ar_archive.c
+++ b/archival/libarchive/unpack_ar_archive.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "archive.h" 7#include "bb_archive.h"
8#include "ar.h" 8#include "ar.h"
9 9
10void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive) 10void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive)
diff --git a/archival/lzop.c b/archival/lzop.c
index 1326bd790..7e30091d9 100644
--- a/archival/lzop.c
+++ b/archival/lzop.c
@@ -51,7 +51,7 @@
51//usage: "\n -F Don't store or verify checksum" 51//usage: "\n -F Don't store or verify checksum"
52 52
53#include "libbb.h" 53#include "libbb.h"
54#include "archive.h" 54#include "bb_archive.h"
55#include "liblzo_interface.h" 55#include "liblzo_interface.h"
56 56
57/* lzo-2.03/src/lzo_ptr.h */ 57/* lzo-2.03/src/lzo_ptr.h */
diff --git a/archival/rpm.c b/archival/rpm.c
index 8174f4869..089b68983 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -20,7 +20,7 @@
20//usage: "\n -c List config files" 20//usage: "\n -c List config files"
21 21
22#include "libbb.h" 22#include "libbb.h"
23#include "archive.h" 23#include "bb_archive.h"
24#include "rpm.h" 24#include "rpm.h"
25 25
26#define RPM_CHAR_TYPE 1 26#define RPM_CHAR_TYPE 1
diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c
index ff4a0d1b0..28b43a181 100644
--- a/archival/rpm2cpio.c
+++ b/archival/rpm2cpio.c
@@ -13,7 +13,7 @@
13//usage: "Output a cpio archive of the rpm file" 13//usage: "Output a cpio archive of the rpm file"
14 14
15#include "libbb.h" 15#include "libbb.h"
16#include "archive.h" 16#include "bb_archive.h"
17#include "rpm.h" 17#include "rpm.h"
18 18
19enum { rpm_fd = STDIN_FILENO }; 19enum { rpm_fd = STDIN_FILENO };
diff --git a/archival/tar.c b/archival/tar.c
index e7963b0b4..2b752f640 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -44,7 +44,7 @@
44 44
45#include <fnmatch.h> 45#include <fnmatch.h>
46#include "libbb.h" 46#include "libbb.h"
47#include "archive.h" 47#include "bb_archive.h"
48/* FIXME: Stop using this non-standard feature */ 48/* FIXME: Stop using this non-standard feature */
49#ifndef FNM_LEADING_DIR 49#ifndef FNM_LEADING_DIR
50# define FNM_LEADING_DIR 0 50# define FNM_LEADING_DIR 0
diff --git a/archival/unzip.c b/archival/unzip.c
index 4fa729326..3a11f78a5 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -32,7 +32,7 @@
32//usage: "\n -d DIR Extract files into DIR" 32//usage: "\n -d DIR Extract files into DIR"
33 33
34#include "libbb.h" 34#include "libbb.h"
35#include "archive.h" 35#include "bb_archive.h"
36 36
37enum { 37enum {
38#if BB_BIG_ENDIAN 38#if BB_BIG_ENDIAN
@@ -235,7 +235,7 @@ static void unzip_create_leading_dirs(const char *fn)
235 /* Create all leading directories */ 235 /* Create all leading directories */
236 char *name = xstrdup(fn); 236 char *name = xstrdup(fn);
237 if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) { 237 if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) {
238 bb_error_msg_and_die("exiting"); /* bb_make_directory is noisy */ 238 xfunc_die(); /* bb_make_directory is noisy */
239 } 239 }
240 free(name); 240 free(name);
241} 241}
@@ -595,7 +595,7 @@ int unzip_main(int argc, char **argv)
595 } 595 }
596 unzip_create_leading_dirs(dst_fn); 596 unzip_create_leading_dirs(dst_fn);
597 if (bb_make_directory(dst_fn, dir_mode, 0)) { 597 if (bb_make_directory(dst_fn, dir_mode, 0)) {
598 bb_error_msg_and_die("exiting"); 598 xfunc_die();
599 } 599 }
600 } else { 600 } else {
601 if (!S_ISDIR(stat_buf.st_mode)) { 601 if (!S_ISDIR(stat_buf.st_mode)) {
@@ -619,6 +619,7 @@ int unzip_main(int argc, char **argv)
619 i = 'y'; 619 i = 'y';
620 } else { 620 } else {
621 printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn); 621 printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
622 fflush_all();
622 if (!fgets(key_buf, sizeof(key_buf), stdin)) { 623 if (!fgets(key_buf, sizeof(key_buf), stdin)) {
623 bb_perror_msg_and_die("can't read input"); 624 bb_perror_msg_and_die("can't read input");
624 } 625 }
diff --git a/configs/TEST_nommu_defconfig b/configs/TEST_nommu_defconfig
index 905f65296..15e12b1d2 100644
--- a/configs/TEST_nommu_defconfig
+++ b/configs/TEST_nommu_defconfig
@@ -79,7 +79,7 @@ CONFIG_PREFIX="./_install"
79# Busybox Library Tuning 79# Busybox Library Tuning
80# 80#
81CONFIG_PASSWORD_MINLEN=6 81CONFIG_PASSWORD_MINLEN=6
82CONFIG_MD5_SIZE_VS_SPEED=2 82CONFIG_MD5_SMALL=1
83CONFIG_FEATURE_FAST_TOP=y 83CONFIG_FEATURE_FAST_TOP=y
84CONFIG_FEATURE_ETC_NETWORKS=y 84CONFIG_FEATURE_ETC_NETWORKS=y
85CONFIG_FEATURE_EDITING=y 85CONFIG_FEATURE_EDITING=y
diff --git a/configs/TEST_noprintf_defconfig b/configs/TEST_noprintf_defconfig
index b72e12856..f4338df71 100644
--- a/configs/TEST_noprintf_defconfig
+++ b/configs/TEST_noprintf_defconfig
@@ -89,7 +89,7 @@ CONFIG_PREFIX="./_install"
89# Busybox Library Tuning 89# Busybox Library Tuning
90# 90#
91CONFIG_PASSWORD_MINLEN=6 91CONFIG_PASSWORD_MINLEN=6
92CONFIG_MD5_SIZE_VS_SPEED=2 92CONFIG_MD5_SMALL=1
93CONFIG_FEATURE_FAST_TOP=y 93CONFIG_FEATURE_FAST_TOP=y
94# CONFIG_FEATURE_ETC_NETWORKS is not set 94# CONFIG_FEATURE_ETC_NETWORKS is not set
95CONFIG_FEATURE_EDITING=y 95CONFIG_FEATURE_EDITING=y
diff --git a/configs/TEST_rh9_defconfig b/configs/TEST_rh9_defconfig
index 23094e391..193d8f615 100644
--- a/configs/TEST_rh9_defconfig
+++ b/configs/TEST_rh9_defconfig
@@ -88,7 +88,7 @@ CONFIG_PREFIX="./_install"
88# Busybox Library Tuning 88# Busybox Library Tuning
89# 89#
90CONFIG_PASSWORD_MINLEN=6 90CONFIG_PASSWORD_MINLEN=6
91CONFIG_MD5_SIZE_VS_SPEED=2 91CONFIG_MD5_SMALL=1
92CONFIG_FEATURE_FAST_TOP=y 92CONFIG_FEATURE_FAST_TOP=y
93# CONFIG_FEATURE_ETC_NETWORKS is not set 93# CONFIG_FEATURE_ETC_NETWORKS is not set
94CONFIG_FEATURE_EDITING=y 94CONFIG_FEATURE_EDITING=y
diff --git a/configs/android2_defconfig b/configs/android2_defconfig
new file mode 100644
index 000000000..b5166e0fc
--- /dev/null
+++ b/configs/android2_defconfig
@@ -0,0 +1,997 @@
1# Run "make android2_defconfig", then "make".
2#
3# Tested with the standalone toolchain from ndk r6:
4# android-ndk-r6/build/tools/make-standalone-toolchain.sh --platform=android-8
5#
6CONFIG_HAVE_DOT_CONFIG=y
7
8#
9# Busybox Settings
10#
11
12#
13# General Configuration
14#
15# CONFIG_DESKTOP is not set
16# CONFIG_EXTRA_COMPAT is not set
17# CONFIG_INCLUDE_SUSv2 is not set
18# CONFIG_USE_PORTABLE_CODE is not set
19CONFIG_PLATFORM_LINUX=y
20CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
21# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
22# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
23# CONFIG_SHOW_USAGE is not set
24# CONFIG_FEATURE_VERBOSE_USAGE is not set
25# CONFIG_FEATURE_COMPRESS_USAGE is not set
26# CONFIG_FEATURE_INSTALLER is not set
27# CONFIG_INSTALL_NO_USR is not set
28# CONFIG_LOCALE_SUPPORT is not set
29# CONFIG_UNICODE_SUPPORT is not set
30# CONFIG_UNICODE_USING_LOCALE is not set
31# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
32CONFIG_SUBST_WCHAR=0
33CONFIG_LAST_SUPPORTED_WCHAR=0
34# CONFIG_UNICODE_COMBINING_WCHARS is not set
35# CONFIG_UNICODE_WIDE_WCHARS is not set
36# CONFIG_UNICODE_BIDI_SUPPORT is not set
37# CONFIG_UNICODE_NEUTRAL_TABLE is not set
38# CONFIG_UNICODE_PRESERVE_BROKEN is not set
39# CONFIG_LONG_OPTS is not set
40# CONFIG_FEATURE_DEVPTS is not set
41# CONFIG_FEATURE_CLEAN_UP is not set
42# CONFIG_FEATURE_UTMP is not set
43# CONFIG_FEATURE_WTMP is not set
44# CONFIG_FEATURE_PIDFILE is not set
45# CONFIG_FEATURE_SUID is not set
46# CONFIG_FEATURE_SUID_CONFIG is not set
47# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
48# CONFIG_SELINUX is not set
49# CONFIG_FEATURE_PREFER_APPLETS is not set
50CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe"
51CONFIG_FEATURE_SYSLOG=y
52# CONFIG_FEATURE_HAVE_RPC is not set
53
54#
55# Build Options
56#
57# CONFIG_STATIC is not set
58# CONFIG_PIE is not set
59# CONFIG_NOMMU is not set
60# CONFIG_BUILD_LIBBUSYBOX is not set
61# CONFIG_FEATURE_INDIVIDUAL is not set
62# CONFIG_FEATURE_SHARED_BUSYBOX is not set
63# CONFIG_LFS is not set
64CONFIG_CROSS_COMPILER_PREFIX="arm-linux-androideabi-"
65CONFIG_EXTRA_CFLAGS=""
66
67#
68# Debugging Options
69#
70# CONFIG_DEBUG is not set
71# CONFIG_DEBUG_PESSIMIZE is not set
72# CONFIG_WERROR is not set
73CONFIG_NO_DEBUG_LIB=y
74# CONFIG_DMALLOC is not set
75# CONFIG_EFENCE is not set
76
77#
78# Installation Options ("make install" behavior)
79#
80CONFIG_INSTALL_APPLET_SYMLINKS=y
81# CONFIG_INSTALL_APPLET_HARDLINKS is not set
82# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
83# CONFIG_INSTALL_APPLET_DONT is not set
84# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
85# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
86# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
87CONFIG_PREFIX="./_install"
88
89#
90# Busybox Library Tuning
91#
92# CONFIG_FEATURE_SYSTEMD is not set
93# CONFIG_FEATURE_RTMINMAX is not set
94CONFIG_PASSWORD_MINLEN=6
95CONFIG_MD5_SMALL=1
96# CONFIG_FEATURE_FAST_TOP is not set
97# CONFIG_FEATURE_ETC_NETWORKS is not set
98CONFIG_FEATURE_USE_TERMIOS=y
99# CONFIG_FEATURE_EDITING is not set
100CONFIG_FEATURE_EDITING_MAX_LEN=0
101# CONFIG_FEATURE_EDITING_VI is not set
102CONFIG_FEATURE_EDITING_HISTORY=0
103# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
104# CONFIG_FEATURE_TAB_COMPLETION is not set
105# CONFIG_FEATURE_USERNAME_COMPLETION is not set
106# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set
107# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
108# CONFIG_FEATURE_NON_POSIX_CP is not set
109# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
110CONFIG_FEATURE_COPYBUF_KB=4
111# CONFIG_FEATURE_SKIP_ROOTFS is not set
112# CONFIG_MONOTONIC_SYSCALL is not set
113# CONFIG_IOCTL_HEX2STR_ERROR is not set
114# CONFIG_FEATURE_HWIB is not set
115
116#
117# Applets
118#
119
120#
121# Archival Utilities
122#
123CONFIG_FEATURE_SEAMLESS_XZ=y
124CONFIG_FEATURE_SEAMLESS_LZMA=y
125CONFIG_FEATURE_SEAMLESS_BZ2=y
126CONFIG_FEATURE_SEAMLESS_GZ=y
127CONFIG_FEATURE_SEAMLESS_Z=y
128CONFIG_AR=y
129CONFIG_FEATURE_AR_LONG_FILENAMES=y
130CONFIG_FEATURE_AR_CREATE=y
131CONFIG_BUNZIP2=y
132CONFIG_BZIP2=y
133CONFIG_CPIO=y
134CONFIG_FEATURE_CPIO_O=y
135CONFIG_FEATURE_CPIO_P=y
136CONFIG_DPKG=y
137CONFIG_DPKG_DEB=y
138# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set
139CONFIG_GUNZIP=y
140CONFIG_GZIP=y
141# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set
142CONFIG_LZOP=y
143CONFIG_LZOP_COMPR_HIGH=y
144CONFIG_RPM2CPIO=y
145CONFIG_RPM=y
146CONFIG_TAR=y
147CONFIG_FEATURE_TAR_CREATE=y
148CONFIG_FEATURE_TAR_AUTODETECT=y
149CONFIG_FEATURE_TAR_FROM=y
150CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
151CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y
152CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
153# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set
154# CONFIG_FEATURE_TAR_TO_COMMAND is not set
155CONFIG_FEATURE_TAR_UNAME_GNAME=y
156CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
157# CONFIG_FEATURE_TAR_SELINUX is not set
158CONFIG_UNCOMPRESS=y
159CONFIG_UNLZMA=y
160CONFIG_FEATURE_LZMA_FAST=y
161CONFIG_LZMA=y
162CONFIG_UNXZ=y
163CONFIG_XZ=y
164CONFIG_UNZIP=y
165
166#
167# Coreutils
168#
169CONFIG_BASENAME=y
170CONFIG_CAT=y
171# CONFIG_DATE is not set
172# CONFIG_FEATURE_DATE_ISOFMT is not set
173# CONFIG_FEATURE_DATE_NANO is not set
174# CONFIG_FEATURE_DATE_COMPAT is not set
175# CONFIG_ID is not set
176# CONFIG_GROUPS is not set
177CONFIG_TEST=y
178CONFIG_FEATURE_TEST_64=y
179CONFIG_TOUCH=y
180CONFIG_TR=y
181CONFIG_FEATURE_TR_CLASSES=y
182CONFIG_FEATURE_TR_EQUIV=y
183CONFIG_BASE64=y
184CONFIG_CAL=y
185CONFIG_CATV=y
186CONFIG_CHGRP=y
187CONFIG_CHMOD=y
188CONFIG_CHOWN=y
189# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
190CONFIG_CHROOT=y
191CONFIG_CKSUM=y
192CONFIG_COMM=y
193CONFIG_CP=y
194# CONFIG_FEATURE_CP_LONG_OPTIONS is not set
195CONFIG_CUT=y
196CONFIG_DD=y
197CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
198CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y
199CONFIG_FEATURE_DD_IBS_OBS=y
200# CONFIG_DF is not set
201# CONFIG_FEATURE_DF_FANCY is not set
202CONFIG_DIRNAME=y
203CONFIG_DOS2UNIX=y
204CONFIG_UNIX2DOS=y
205CONFIG_DU=y
206CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
207CONFIG_ECHO=y
208CONFIG_FEATURE_FANCY_ECHO=y
209# CONFIG_ENV is not set
210# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set
211CONFIG_EXPAND=y
212# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set
213# CONFIG_EXPR is not set
214# CONFIG_EXPR_MATH_SUPPORT_64 is not set
215CONFIG_FALSE=y
216CONFIG_FOLD=y
217# CONFIG_FSYNC is not set
218CONFIG_HEAD=y
219CONFIG_FEATURE_FANCY_HEAD=y
220# CONFIG_HOSTID is not set
221CONFIG_INSTALL=y
222# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
223CONFIG_LN=y
224# CONFIG_LOGNAME is not set
225CONFIG_LS=y
226CONFIG_FEATURE_LS_FILETYPES=y
227CONFIG_FEATURE_LS_FOLLOWLINKS=y
228CONFIG_FEATURE_LS_RECURSIVE=y
229CONFIG_FEATURE_LS_SORTFILES=y
230CONFIG_FEATURE_LS_TIMESTAMPS=y
231CONFIG_FEATURE_LS_USERNAME=y
232# CONFIG_FEATURE_LS_COLOR is not set
233# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set
234CONFIG_MD5SUM=y
235CONFIG_MKDIR=y
236# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set
237CONFIG_MKFIFO=y
238CONFIG_MKNOD=y
239CONFIG_MV=y
240# CONFIG_FEATURE_MV_LONG_OPTIONS is not set
241CONFIG_NICE=y
242CONFIG_NOHUP=y
243CONFIG_OD=y
244CONFIG_PRINTENV=y
245CONFIG_PRINTF=y
246CONFIG_PWD=y
247CONFIG_READLINK=y
248CONFIG_FEATURE_READLINK_FOLLOW=y
249CONFIG_REALPATH=y
250CONFIG_RM=y
251CONFIG_RMDIR=y
252# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set
253CONFIG_SEQ=y
254CONFIG_SHA1SUM=y
255CONFIG_SHA256SUM=y
256CONFIG_SHA512SUM=y
257CONFIG_SLEEP=y
258CONFIG_FEATURE_FANCY_SLEEP=y
259CONFIG_FEATURE_FLOAT_SLEEP=y
260CONFIG_SORT=y
261CONFIG_FEATURE_SORT_BIG=y
262CONFIG_SPLIT=y
263CONFIG_FEATURE_SPLIT_FANCY=y
264# CONFIG_STAT is not set
265# CONFIG_FEATURE_STAT_FORMAT is not set
266CONFIG_STTY=y
267CONFIG_SUM=y
268CONFIG_SYNC=y
269CONFIG_TAC=y
270CONFIG_TAIL=y
271CONFIG_FEATURE_FANCY_TAIL=y
272CONFIG_TEE=y
273CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
274CONFIG_TRUE=y
275# CONFIG_TTY is not set
276CONFIG_UNAME=y
277CONFIG_UNEXPAND=y
278# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set
279CONFIG_UNIQ=y
280# CONFIG_USLEEP is not set
281CONFIG_UUDECODE=y
282CONFIG_UUENCODE=y
283CONFIG_WC=y
284CONFIG_FEATURE_WC_LARGE=y
285# CONFIG_WHO is not set
286CONFIG_WHOAMI=y
287CONFIG_YES=y
288
289#
290# Common options for cp and mv
291#
292CONFIG_FEATURE_PRESERVE_HARDLINKS=y
293
294#
295# Common options for ls, more and telnet
296#
297CONFIG_FEATURE_AUTOWIDTH=y
298
299#
300# Common options for df, du, ls
301#
302CONFIG_FEATURE_HUMAN_READABLE=y
303
304#
305# Common options for md5sum, sha1sum, sha256sum, sha512sum
306#
307CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
308
309#
310# Console Utilities
311#
312CONFIG_CHVT=y
313CONFIG_FGCONSOLE=y
314CONFIG_CLEAR=y
315CONFIG_DEALLOCVT=y
316CONFIG_DUMPKMAP=y
317# CONFIG_KBD_MODE is not set
318# CONFIG_LOADFONT is not set
319CONFIG_LOADKMAP=y
320CONFIG_OPENVT=y
321CONFIG_RESET=y
322CONFIG_RESIZE=y
323CONFIG_FEATURE_RESIZE_PRINT=y
324CONFIG_SETCONSOLE=y
325# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
326# CONFIG_SETFONT is not set
327# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
328CONFIG_DEFAULT_SETFONT_DIR=""
329CONFIG_SETKEYCODES=y
330CONFIG_SETLOGCONS=y
331CONFIG_SHOWKEY=y
332# CONFIG_FEATURE_LOADFONT_PSF2 is not set
333# CONFIG_FEATURE_LOADFONT_RAW is not set
334
335#
336# Debian Utilities
337#
338CONFIG_MKTEMP=y
339CONFIG_PIPE_PROGRESS=y
340CONFIG_RUN_PARTS=y
341# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
342CONFIG_FEATURE_RUN_PARTS_FANCY=y
343CONFIG_START_STOP_DAEMON=y
344CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y
345# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
346CONFIG_WHICH=y
347
348#
349# Editors
350#
351CONFIG_PATCH=y
352# CONFIG_VI is not set
353CONFIG_FEATURE_VI_MAX_LEN=0
354# CONFIG_FEATURE_VI_8BIT is not set
355# CONFIG_FEATURE_VI_COLON is not set
356# CONFIG_FEATURE_VI_YANKMARK is not set
357# CONFIG_FEATURE_VI_SEARCH is not set
358# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
359# CONFIG_FEATURE_VI_USE_SIGNALS is not set
360# CONFIG_FEATURE_VI_DOT_CMD is not set
361# CONFIG_FEATURE_VI_READONLY is not set
362# CONFIG_FEATURE_VI_SETOPTS is not set
363# CONFIG_FEATURE_VI_SET is not set
364# CONFIG_FEATURE_VI_WIN_RESIZE is not set
365# CONFIG_FEATURE_VI_ASK_TERMINAL is not set
366# CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set
367# CONFIG_AWK is not set
368# CONFIG_FEATURE_AWK_LIBM is not set
369CONFIG_CMP=y
370CONFIG_DIFF=y
371# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set
372CONFIG_FEATURE_DIFF_DIR=y
373# CONFIG_ED is not set
374# CONFIG_SED is not set
375# CONFIG_FEATURE_ALLOW_EXEC is not set
376
377#
378# Finding Utilities
379#
380# CONFIG_FIND is not set
381# CONFIG_FEATURE_FIND_PRINT0 is not set
382# CONFIG_FEATURE_FIND_MTIME is not set
383# CONFIG_FEATURE_FIND_MMIN is not set
384# CONFIG_FEATURE_FIND_PERM is not set
385# CONFIG_FEATURE_FIND_TYPE is not set
386# CONFIG_FEATURE_FIND_XDEV is not set
387# CONFIG_FEATURE_FIND_MAXDEPTH is not set
388# CONFIG_FEATURE_FIND_NEWER is not set
389# CONFIG_FEATURE_FIND_INUM is not set
390# CONFIG_FEATURE_FIND_EXEC is not set
391# CONFIG_FEATURE_FIND_USER is not set
392# CONFIG_FEATURE_FIND_GROUP is not set
393# CONFIG_FEATURE_FIND_NOT is not set
394# CONFIG_FEATURE_FIND_DEPTH is not set
395# CONFIG_FEATURE_FIND_PAREN is not set
396# CONFIG_FEATURE_FIND_SIZE is not set
397# CONFIG_FEATURE_FIND_PRUNE is not set
398# CONFIG_FEATURE_FIND_DELETE is not set
399# CONFIG_FEATURE_FIND_PATH is not set
400# CONFIG_FEATURE_FIND_REGEX is not set
401# CONFIG_FEATURE_FIND_CONTEXT is not set
402# CONFIG_FEATURE_FIND_LINKS is not set
403# CONFIG_GREP is not set
404# CONFIG_FEATURE_GREP_EGREP_ALIAS is not set
405# CONFIG_FEATURE_GREP_FGREP_ALIAS is not set
406# CONFIG_FEATURE_GREP_CONTEXT is not set
407CONFIG_XARGS=y
408CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
409CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
410CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
411CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
412
413#
414# Init Utilities
415#
416# CONFIG_BOOTCHARTD is not set
417# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
418# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
419CONFIG_HALT=y
420# CONFIG_FEATURE_CALL_TELINIT is not set
421CONFIG_TELINIT_PATH=""
422CONFIG_INIT=y
423CONFIG_FEATURE_USE_INITTAB=y
424# CONFIG_FEATURE_KILL_REMOVED is not set
425CONFIG_FEATURE_KILL_DELAY=0
426CONFIG_FEATURE_INIT_SCTTY=y
427CONFIG_FEATURE_INIT_SYSLOG=y
428CONFIG_FEATURE_EXTRA_QUIET=y
429CONFIG_FEATURE_INIT_COREDUMPS=y
430CONFIG_FEATURE_INITRD=y
431CONFIG_INIT_TERMINAL_TYPE="linux"
432CONFIG_MESG=y
433CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y
434
435#
436# Login/Password Management Utilities
437#
438# CONFIG_ADD_SHELL is not set
439# CONFIG_REMOVE_SHELL is not set
440# CONFIG_FEATURE_SHADOWPASSWDS is not set
441# CONFIG_USE_BB_PWD_GRP is not set
442# CONFIG_USE_BB_SHADOW is not set
443# CONFIG_USE_BB_CRYPT is not set
444# CONFIG_USE_BB_CRYPT_SHA is not set
445# CONFIG_ADDUSER is not set
446# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
447# CONFIG_FEATURE_CHECK_NAMES is not set
448CONFIG_FIRST_SYSTEM_ID=0
449CONFIG_LAST_SYSTEM_ID=0
450# CONFIG_ADDGROUP is not set
451# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set
452# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
453# CONFIG_DELUSER is not set
454# CONFIG_DELGROUP is not set
455# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
456# CONFIG_GETTY is not set
457# CONFIG_LOGIN is not set
458# CONFIG_PAM is not set
459# CONFIG_LOGIN_SCRIPTS is not set
460# CONFIG_FEATURE_NOLOGIN is not set
461# CONFIG_FEATURE_SECURETTY is not set
462# CONFIG_PASSWD is not set
463# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
464# CONFIG_CRYPTPW is not set
465# CONFIG_CHPASSWD is not set
466# CONFIG_SU is not set
467# CONFIG_FEATURE_SU_SYSLOG is not set
468# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
469# CONFIG_SULOGIN is not set
470# CONFIG_VLOCK is not set
471
472#
473# Linux Ext2 FS Progs
474#
475CONFIG_CHATTR=y
476# CONFIG_FSCK is not set
477CONFIG_LSATTR=y
478CONFIG_TUNE2FS=y
479
480#
481# Linux Module Utilities
482#
483CONFIG_MODINFO=y
484CONFIG_MODPROBE_SMALL=y
485CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y
486CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y
487# CONFIG_INSMOD is not set
488# CONFIG_RMMOD is not set
489# CONFIG_LSMOD is not set
490# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
491# CONFIG_MODPROBE is not set
492# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
493# CONFIG_DEPMOD is not set
494
495#
496# Options common to multiple modutils
497#
498# CONFIG_FEATURE_2_4_MODULES is not set
499# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
500# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
501# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
502# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
503# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
504# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
505# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
506# CONFIG_FEATURE_MODUTILS_ALIAS is not set
507# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
508CONFIG_DEFAULT_MODULES_DIR="/lib/modules"
509CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
510
511#
512# Linux System Utilities
513#
514CONFIG_BLOCKDEV=y
515CONFIG_REV=y
516# CONFIG_ACPID is not set
517# CONFIG_FEATURE_ACPID_COMPAT is not set
518CONFIG_BLKID=y
519# CONFIG_FEATURE_BLKID_TYPE is not set
520CONFIG_DMESG=y
521CONFIG_FEATURE_DMESG_PRETTY=y
522CONFIG_FBSET=y
523CONFIG_FEATURE_FBSET_FANCY=y
524CONFIG_FEATURE_FBSET_READMODE=y
525CONFIG_FDFLUSH=y
526CONFIG_FDFORMAT=y
527CONFIG_FDISK=y
528CONFIG_FDISK_SUPPORT_LARGE_DISKS=y
529CONFIG_FEATURE_FDISK_WRITABLE=y
530# CONFIG_FEATURE_AIX_LABEL is not set
531# CONFIG_FEATURE_SGI_LABEL is not set
532# CONFIG_FEATURE_SUN_LABEL is not set
533# CONFIG_FEATURE_OSF_LABEL is not set
534# CONFIG_FEATURE_GPT_LABEL is not set
535CONFIG_FEATURE_FDISK_ADVANCED=y
536CONFIG_FINDFS=y
537CONFIG_FLOCK=y
538CONFIG_FREERAMDISK=y
539# CONFIG_FSCK_MINIX is not set
540# CONFIG_MKFS_EXT2 is not set
541# CONFIG_MKFS_MINIX is not set
542# CONFIG_FEATURE_MINIX2 is not set
543# CONFIG_MKFS_REISER is not set
544# CONFIG_MKFS_VFAT is not set
545CONFIG_GETOPT=y
546CONFIG_FEATURE_GETOPT_LONG=y
547CONFIG_HEXDUMP=y
548CONFIG_FEATURE_HEXDUMP_REVERSE=y
549CONFIG_HD=y
550# CONFIG_HWCLOCK is not set
551# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
552# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
553# CONFIG_IPCRM is not set
554# CONFIG_IPCS is not set
555CONFIG_LOSETUP=y
556CONFIG_LSPCI=y
557CONFIG_LSUSB=y
558# CONFIG_MDEV is not set
559# CONFIG_FEATURE_MDEV_CONF is not set
560# CONFIG_FEATURE_MDEV_RENAME is not set
561# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
562# CONFIG_FEATURE_MDEV_EXEC is not set
563# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
564CONFIG_MKSWAP=y
565CONFIG_FEATURE_MKSWAP_UUID=y
566CONFIG_MORE=y
567# CONFIG_MOUNT is not set
568# CONFIG_FEATURE_MOUNT_FAKE is not set
569# CONFIG_FEATURE_MOUNT_VERBOSE is not set
570# CONFIG_FEATURE_MOUNT_HELPERS is not set
571# CONFIG_FEATURE_MOUNT_LABEL is not set
572# CONFIG_FEATURE_MOUNT_NFS is not set
573# CONFIG_FEATURE_MOUNT_CIFS is not set
574# CONFIG_FEATURE_MOUNT_FLAGS is not set
575# CONFIG_FEATURE_MOUNT_FSTAB is not set
576# CONFIG_PIVOT_ROOT is not set
577# CONFIG_RDATE is not set
578CONFIG_RDEV=y
579CONFIG_READPROFILE=y
580CONFIG_RTCWAKE=y
581CONFIG_SCRIPT=y
582CONFIG_SCRIPTREPLAY=y
583# CONFIG_SETARCH is not set
584# CONFIG_SWAPONOFF is not set
585# CONFIG_FEATURE_SWAPON_PRI is not set
586# CONFIG_SWITCH_ROOT is not set
587# CONFIG_UMOUNT is not set
588# CONFIG_FEATURE_UMOUNT_ALL is not set
589# CONFIG_FEATURE_MOUNT_LOOP is not set
590# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
591# CONFIG_FEATURE_MTAB_SUPPORT is not set
592CONFIG_VOLUMEID=y
593
594#
595# Filesystem/Volume identification
596#
597CONFIG_FEATURE_VOLUMEID_EXT=y
598CONFIG_FEATURE_VOLUMEID_BTRFS=y
599CONFIG_FEATURE_VOLUMEID_REISERFS=y
600CONFIG_FEATURE_VOLUMEID_FAT=y
601CONFIG_FEATURE_VOLUMEID_HFS=y
602CONFIG_FEATURE_VOLUMEID_JFS=y
603CONFIG_FEATURE_VOLUMEID_XFS=y
604CONFIG_FEATURE_VOLUMEID_NTFS=y
605CONFIG_FEATURE_VOLUMEID_ISO9660=y
606CONFIG_FEATURE_VOLUMEID_UDF=y
607CONFIG_FEATURE_VOLUMEID_LUKS=y
608CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y
609CONFIG_FEATURE_VOLUMEID_CRAMFS=y
610CONFIG_FEATURE_VOLUMEID_ROMFS=y
611CONFIG_FEATURE_VOLUMEID_SYSV=y
612CONFIG_FEATURE_VOLUMEID_OCFS2=y
613CONFIG_FEATURE_VOLUMEID_LINUXRAID=y
614
615#
616# Miscellaneous Utilities
617#
618# CONFIG_CONSPY is not set
619# CONFIG_NANDWRITE is not set
620CONFIG_NANDDUMP=y
621CONFIG_SETSERIAL=y
622# CONFIG_UBIATTACH is not set
623# CONFIG_UBIDETACH is not set
624# CONFIG_UBIMKVOL is not set
625# CONFIG_UBIRMVOL is not set
626# CONFIG_UBIRSVOL is not set
627# CONFIG_UBIUPDATEVOL is not set
628# CONFIG_ADJTIMEX is not set
629# CONFIG_BBCONFIG is not set
630# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
631CONFIG_BEEP=y
632CONFIG_FEATURE_BEEP_FREQ=4000
633CONFIG_FEATURE_BEEP_LENGTH_MS=30
634CONFIG_CHAT=y
635CONFIG_FEATURE_CHAT_NOFAIL=y
636# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
637CONFIG_FEATURE_CHAT_IMPLICIT_CR=y
638CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y
639CONFIG_FEATURE_CHAT_SEND_ESCAPES=y
640CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y
641CONFIG_FEATURE_CHAT_CLR_ABORT=y
642CONFIG_CHRT=y
643# CONFIG_CROND is not set
644# CONFIG_FEATURE_CROND_D is not set
645# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
646CONFIG_FEATURE_CROND_DIR=""
647# CONFIG_CRONTAB is not set
648CONFIG_DC=y
649CONFIG_FEATURE_DC_LIBM=y
650# CONFIG_DEVFSD is not set
651# CONFIG_DEVFSD_MODLOAD is not set
652# CONFIG_DEVFSD_FG_NP is not set
653# CONFIG_DEVFSD_VERBOSE is not set
654# CONFIG_FEATURE_DEVFS is not set
655CONFIG_DEVMEM=y
656# CONFIG_EJECT is not set
657# CONFIG_FEATURE_EJECT_SCSI is not set
658CONFIG_FBSPLASH=y
659CONFIG_FLASHCP=y
660CONFIG_FLASH_LOCK=y
661CONFIG_FLASH_UNLOCK=y
662# CONFIG_FLASH_ERASEALL is not set
663# CONFIG_IONICE is not set
664CONFIG_INOTIFYD=y
665# CONFIG_LAST is not set
666# CONFIG_FEATURE_LAST_SMALL is not set
667# CONFIG_FEATURE_LAST_FANCY is not set
668# CONFIG_LESS is not set
669CONFIG_FEATURE_LESS_MAXLINES=0
670# CONFIG_FEATURE_LESS_BRACKETS is not set
671# CONFIG_FEATURE_LESS_FLAGS is not set
672# CONFIG_FEATURE_LESS_MARKS is not set
673# CONFIG_FEATURE_LESS_REGEXP is not set
674# CONFIG_FEATURE_LESS_WINCH is not set
675# CONFIG_FEATURE_LESS_DASHCMD is not set
676# CONFIG_FEATURE_LESS_LINENUMS is not set
677CONFIG_HDPARM=y
678CONFIG_FEATURE_HDPARM_GET_IDENTITY=y
679CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y
680CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y
681CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y
682CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y
683CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y
684CONFIG_MAKEDEVS=y
685# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
686CONFIG_FEATURE_MAKEDEVS_TABLE=y
687CONFIG_MAN=y
688# CONFIG_MICROCOM is not set
689# CONFIG_MOUNTPOINT is not set
690# CONFIG_MT is not set
691CONFIG_RAIDAUTORUN=y
692# CONFIG_READAHEAD is not set
693# CONFIG_RFKILL is not set
694# CONFIG_RUNLEVEL is not set
695CONFIG_RX=y
696CONFIG_SETSID=y
697CONFIG_STRINGS=y
698# CONFIG_TASKSET is not set
699# CONFIG_FEATURE_TASKSET_FANCY is not set
700CONFIG_TIME=y
701CONFIG_TIMEOUT=y
702CONFIG_TTYSIZE=y
703CONFIG_VOLNAME=y
704# CONFIG_WALL is not set
705# CONFIG_WATCHDOG is not set
706
707#
708# Networking Utilities
709#
710# CONFIG_NAMEIF is not set
711# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
712CONFIG_NBDCLIENT=y
713CONFIG_NC=y
714CONFIG_NC_SERVER=y
715CONFIG_NC_EXTRA=y
716# CONFIG_NC_110_COMPAT is not set
717# CONFIG_PING is not set
718# CONFIG_PING6 is not set
719# CONFIG_FEATURE_FANCY_PING is not set
720CONFIG_WHOIS=y
721# CONFIG_FEATURE_IPV6 is not set
722# CONFIG_FEATURE_UNIX_LOCAL is not set
723# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set
724# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
725CONFIG_ARP=y
726# CONFIG_ARPING is not set
727# CONFIG_BRCTL is not set
728# CONFIG_FEATURE_BRCTL_FANCY is not set
729# CONFIG_FEATURE_BRCTL_SHOW is not set
730CONFIG_DNSD=y
731# CONFIG_ETHER_WAKE is not set
732CONFIG_FAKEIDENTD=y
733CONFIG_FTPD=y
734CONFIG_FEATURE_FTP_WRITE=y
735CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y
736CONFIG_FTPGET=y
737CONFIG_FTPPUT=y
738# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set
739# CONFIG_HOSTNAME is not set
740CONFIG_HTTPD=y
741CONFIG_FEATURE_HTTPD_RANGES=y
742CONFIG_FEATURE_HTTPD_USE_SENDFILE=y
743CONFIG_FEATURE_HTTPD_SETUID=y
744CONFIG_FEATURE_HTTPD_BASIC_AUTH=y
745# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
746CONFIG_FEATURE_HTTPD_CGI=y
747CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y
748CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y
749CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y
750CONFIG_FEATURE_HTTPD_ERROR_PAGES=y
751CONFIG_FEATURE_HTTPD_PROXY=y
752CONFIG_FEATURE_HTTPD_GZIP=y
753CONFIG_IFCONFIG=y
754CONFIG_FEATURE_IFCONFIG_STATUS=y
755# CONFIG_FEATURE_IFCONFIG_SLIP is not set
756CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y
757CONFIG_FEATURE_IFCONFIG_HW=y
758CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y
759# CONFIG_IFENSLAVE is not set
760# CONFIG_IFPLUGD is not set
761CONFIG_IFUPDOWN=y
762CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate"
763CONFIG_FEATURE_IFUPDOWN_IP=y
764CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y
765# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set
766CONFIG_FEATURE_IFUPDOWN_IPV4=y
767# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
768CONFIG_FEATURE_IFUPDOWN_MAPPING=y
769# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
770# CONFIG_INETD is not set
771# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
772# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
773# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
774# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
775# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
776# CONFIG_FEATURE_INETD_RPC is not set
777CONFIG_IP=y
778CONFIG_FEATURE_IP_ADDRESS=y
779CONFIG_FEATURE_IP_LINK=y
780CONFIG_FEATURE_IP_ROUTE=y
781CONFIG_FEATURE_IP_TUNNEL=y
782CONFIG_FEATURE_IP_RULE=y
783CONFIG_FEATURE_IP_SHORT_FORMS=y
784# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
785CONFIG_IPADDR=y
786CONFIG_IPLINK=y
787CONFIG_IPROUTE=y
788CONFIG_IPTUNNEL=y
789CONFIG_IPRULE=y
790CONFIG_IPCALC=y
791CONFIG_FEATURE_IPCALC_FANCY=y
792# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set
793CONFIG_NETSTAT=y
794CONFIG_FEATURE_NETSTAT_WIDE=y
795CONFIG_FEATURE_NETSTAT_PRG=y
796# CONFIG_NSLOOKUP is not set
797# CONFIG_NTPD is not set
798# CONFIG_FEATURE_NTPD_SERVER is not set
799CONFIG_PSCAN=y
800CONFIG_ROUTE=y
801# CONFIG_SLATTACH is not set
802CONFIG_TCPSVD=y
803# CONFIG_TELNET is not set
804# CONFIG_FEATURE_TELNET_TTYPE is not set
805# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
806# CONFIG_TELNETD is not set
807# CONFIG_FEATURE_TELNETD_STANDALONE is not set
808# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
809# CONFIG_TFTP is not set
810# CONFIG_TFTPD is not set
811# CONFIG_FEATURE_TFTP_GET is not set
812# CONFIG_FEATURE_TFTP_PUT is not set
813# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
814# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
815# CONFIG_TFTP_DEBUG is not set
816# CONFIG_TRACEROUTE is not set
817# CONFIG_TRACEROUTE6 is not set
818# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
819# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set
820# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
821CONFIG_TUNCTL=y
822CONFIG_FEATURE_TUNCTL_UG=y
823# CONFIG_UDHCPD is not set
824# CONFIG_DHCPRELAY is not set
825# CONFIG_DUMPLEASES is not set
826# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
827# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
828CONFIG_DHCPD_LEASES_FILE=""
829CONFIG_UDHCPC=y
830CONFIG_FEATURE_UDHCPC_ARPING=y
831# CONFIG_FEATURE_UDHCP_PORT is not set
832CONFIG_UDHCP_DEBUG=9
833CONFIG_FEATURE_UDHCP_RFC3397=y
834CONFIG_FEATURE_UDHCP_8021Q=y
835CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script"
836CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80
837CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n"
838# CONFIG_UDPSVD is not set
839# CONFIG_VCONFIG is not set
840CONFIG_WGET=y
841CONFIG_FEATURE_WGET_STATUSBAR=y
842CONFIG_FEATURE_WGET_AUTHENTICATION=y
843# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set
844CONFIG_FEATURE_WGET_TIMEOUT=y
845# CONFIG_ZCIP is not set
846
847#
848# Print Utilities
849#
850CONFIG_LPD=y
851CONFIG_LPR=y
852CONFIG_LPQ=y
853
854#
855# Mail Utilities
856#
857CONFIG_MAKEMIME=y
858CONFIG_FEATURE_MIME_CHARSET="us-ascii"
859CONFIG_POPMAILDIR=y
860CONFIG_FEATURE_POPMAILDIR_DELIVERY=y
861CONFIG_REFORMIME=y
862CONFIG_FEATURE_REFORMIME_COMPAT=y
863CONFIG_SENDMAIL=y
864
865#
866# Process Utilities
867#
868CONFIG_IOSTAT=y
869CONFIG_MPSTAT=y
870CONFIG_NMETER=y
871CONFIG_PMAP=y
872CONFIG_POWERTOP=y
873CONFIG_PSTREE=y
874CONFIG_PWDX=y
875CONFIG_SMEMCAP=y
876# CONFIG_FREE is not set
877CONFIG_FUSER=y
878# CONFIG_KILL is not set
879# CONFIG_KILLALL is not set
880# CONFIG_KILLALL5 is not set
881# CONFIG_PGREP is not set
882CONFIG_PIDOF=y
883CONFIG_FEATURE_PIDOF_SINGLE=y
884CONFIG_FEATURE_PIDOF_OMIT=y
885# CONFIG_PKILL is not set
886# CONFIG_PS is not set
887# CONFIG_FEATURE_PS_WIDE is not set
888# CONFIG_FEATURE_PS_TIME is not set
889# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
890# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
891CONFIG_RENICE=y
892CONFIG_BB_SYSCTL=y
893CONFIG_TOP=y
894CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
895CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
896CONFIG_FEATURE_TOP_SMP_CPU=y
897CONFIG_FEATURE_TOP_DECIMALS=y
898CONFIG_FEATURE_TOP_SMP_PROCESS=y
899CONFIG_FEATURE_TOPMEM=y
900CONFIG_FEATURE_SHOW_THREADS=y
901# CONFIG_UPTIME is not set
902CONFIG_WATCH=y
903
904#
905# Runit Utilities
906#
907CONFIG_RUNSV=y
908CONFIG_RUNSVDIR=y
909# CONFIG_FEATURE_RUNSVDIR_LOG is not set
910CONFIG_SV=y
911CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service"
912CONFIG_SVLOGD=y
913CONFIG_CHPST=y
914CONFIG_SETUIDGID=y
915CONFIG_ENVUIDGID=y
916CONFIG_ENVDIR=y
917CONFIG_SOFTLIMIT=y
918# CONFIG_CHCON is not set
919# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
920# CONFIG_GETENFORCE is not set
921# CONFIG_GETSEBOOL is not set
922# CONFIG_LOAD_POLICY is not set
923# CONFIG_MATCHPATHCON is not set
924# CONFIG_RESTORECON is not set
925# CONFIG_RUNCON is not set
926# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
927# CONFIG_SELINUXENABLED is not set
928# CONFIG_SETENFORCE is not set
929# CONFIG_SETFILES is not set
930# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
931# CONFIG_SETSEBOOL is not set
932# CONFIG_SESTATUS is not set
933
934#
935# Shells
936#
937# CONFIG_ASH is not set
938# CONFIG_ASH_BASH_COMPAT is not set
939# CONFIG_ASH_IDLE_TIMEOUT is not set
940# CONFIG_ASH_JOB_CONTROL is not set
941# CONFIG_ASH_ALIAS is not set
942# CONFIG_ASH_GETOPTS is not set
943# CONFIG_ASH_BUILTIN_ECHO is not set
944# CONFIG_ASH_BUILTIN_PRINTF is not set
945# CONFIG_ASH_BUILTIN_TEST is not set
946# CONFIG_ASH_CMDCMD is not set
947# CONFIG_ASH_MAIL is not set
948# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set
949# CONFIG_ASH_RANDOM_SUPPORT is not set
950# CONFIG_ASH_EXPAND_PRMT is not set
951CONFIG_CTTYHACK=y
952# CONFIG_HUSH is not set
953# CONFIG_HUSH_BASH_COMPAT is not set
954# CONFIG_HUSH_BRACE_EXPANSION is not set
955# CONFIG_HUSH_HELP is not set
956# CONFIG_HUSH_INTERACTIVE is not set
957# CONFIG_HUSH_SAVEHISTORY is not set
958# CONFIG_HUSH_JOB is not set
959# CONFIG_HUSH_TICK is not set
960# CONFIG_HUSH_IF is not set
961# CONFIG_HUSH_LOOPS is not set
962# CONFIG_HUSH_CASE is not set
963# CONFIG_HUSH_FUNCTIONS is not set
964# CONFIG_HUSH_LOCAL is not set
965# CONFIG_HUSH_RANDOM_SUPPORT is not set
966# CONFIG_HUSH_EXPORT_N is not set
967# CONFIG_HUSH_MODE_X is not set
968# CONFIG_MSH is not set
969# CONFIG_FEATURE_SH_IS_ASH is not set
970# CONFIG_FEATURE_SH_IS_HUSH is not set
971CONFIG_FEATURE_SH_IS_NONE=y
972# CONFIG_FEATURE_BASH_IS_ASH is not set
973# CONFIG_FEATURE_BASH_IS_HUSH is not set
974CONFIG_FEATURE_BASH_IS_NONE=y
975# CONFIG_SH_MATH_SUPPORT is not set
976# CONFIG_SH_MATH_SUPPORT_64 is not set
977# CONFIG_FEATURE_SH_EXTRA_QUIET is not set
978# CONFIG_FEATURE_SH_STANDALONE is not set
979# CONFIG_FEATURE_SH_NOFORK is not set
980# CONFIG_FEATURE_SH_HISTFILESIZE is not set
981
982#
983# System Logging Utilities
984#
985# CONFIG_SYSLOGD is not set
986# CONFIG_FEATURE_ROTATE_LOGFILE is not set
987# CONFIG_FEATURE_REMOTE_LOG is not set
988# CONFIG_FEATURE_SYSLOGD_DUP is not set
989# CONFIG_FEATURE_SYSLOGD_CFG is not set
990CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
991# CONFIG_FEATURE_IPC_SYSLOG is not set
992CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
993# CONFIG_LOGREAD is not set
994# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
995CONFIG_KLOGD=y
996CONFIG_FEATURE_KLOGD_KLOGCTL=y
997# CONFIG_LOGGER is not set
diff --git a/configs/android_defconfig b/configs/android_defconfig
index 7e5232a84..b9df0ea02 100644
--- a/configs/android_defconfig
+++ b/configs/android_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.19.0.git 3# Busybox version: 1.20.0.git
4# Wed Jun 29 12:01:57 2011 4# Wed Nov 2 17:54:00 2011
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7 7
@@ -12,7 +12,7 @@ CONFIG_HAVE_DOT_CONFIG=y
12# 12#
13# General Configuration 13# General Configuration
14# 14#
15# CONFIG_DESKTOP is not set 15CONFIG_DESKTOP=y
16# CONFIG_EXTRA_COMPAT is not set 16# CONFIG_EXTRA_COMPAT is not set
17# CONFIG_INCLUDE_SUSv2 is not set 17# CONFIG_INCLUDE_SUSv2 is not set
18# CONFIG_USE_PORTABLE_CODE is not set 18# CONFIG_USE_PORTABLE_CODE is not set
@@ -60,7 +60,7 @@ CONFIG_FEATURE_SYSLOG=y
60# CONFIG_BUILD_LIBBUSYBOX is not set 60# CONFIG_BUILD_LIBBUSYBOX is not set
61# CONFIG_FEATURE_INDIVIDUAL is not set 61# CONFIG_FEATURE_INDIVIDUAL is not set
62# CONFIG_FEATURE_SHARED_BUSYBOX is not set 62# CONFIG_FEATURE_SHARED_BUSYBOX is not set
63# CONFIG_LFS is not set 63CONFIG_LFS=y
64CONFIG_CROSS_COMPILER_PREFIX="arm-eabi-" 64CONFIG_CROSS_COMPILER_PREFIX="arm-eabi-"
65# 65#
66# Removed: 66# Removed:
@@ -70,6 +70,8 @@ CONFIG_CROSS_COMPILER_PREFIX="arm-eabi-"
70# -Werror=sequence-point -Wstrict-aliasing=2 -Wno-undef -Wno-shadow 70# -Werror=sequence-point -Wstrict-aliasing=2 -Wno-undef -Wno-shadow
71# bbox already adds these: 71# bbox already adds these:
72# -ffunction-sections -fomit-frame-pointer 72# -ffunction-sections -fomit-frame-pointer
73# enabled implicitly by -Os:
74# -frerun-cse-after-loop
73# should be not needed, or even increases code size: 75# should be not needed, or even increases code size:
74# -finline-functions -fno-inline-functions-called-once -finline-limit=64 76# -finline-functions -fno-inline-functions-called-once -finline-limit=64
75# -fstack-protector -fno-strict-aliasing -fno-exceptions -funwind-tables 77# -fstack-protector -fno-strict-aliasing -fno-exceptions -funwind-tables
@@ -77,9 +79,8 @@ CONFIG_CROSS_COMPILER_PREFIX="arm-eabi-"
77# todo: do we need these? - 79# todo: do we need these? -
78# -fno-short-enums 80# -fno-short-enums
79# -fgcse-after-reload 81# -fgcse-after-reload
80# -frerun-cse-after-loop
81# -frename-registers 82# -frename-registers
82CONFIG_EXTRA_CFLAGS="-I$A/system/core/include -I$A/bionic/libc/arch-arm/include -I$A/bionic/libc/include -I$A/bionic/libc/kernel/common -I$A/bionic/libc/kernel/arch-arm -I$A/bionic/libm/include -I$A/bionic/libm/include/arch/arm -include $A/system/core/include/arch/linux-arm/AndroidConfig.h -I$A/system/core/include/arch/linux-arm/ -DANDROID -DSK_RELEASE -nostdlib -march=armv7-a -msoft-float -mfloat-abi=softfp -mfpu=neon -mthumb -mthumb-interwork -fpic -fno-short-enums -fgcse-after-reload -frerun-cse-after-loop -frename-registers" 83CONFIG_EXTRA_CFLAGS="-I$A/system/core/include -I$A/bionic/libc/arch-arm/include -I$A/bionic/libc/include -I$A/bionic/libc/kernel/common -I$A/bionic/libc/kernel/arch-arm -I$A/bionic/libm/include -I$A/bionic/libm/include/arch/arm -include $A/system/core/include/arch/linux-arm/AndroidConfig.h -I$A/system/core/include/arch/linux-arm/ -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"
83 84
84# 85#
85# Debugging Options 86# Debugging Options
@@ -109,7 +110,7 @@ CONFIG_PREFIX="./_install"
109# CONFIG_FEATURE_SYSTEMD is not set 110# CONFIG_FEATURE_SYSTEMD is not set
110# CONFIG_FEATURE_RTMINMAX is not set 111# CONFIG_FEATURE_RTMINMAX is not set
111CONFIG_PASSWORD_MINLEN=6 112CONFIG_PASSWORD_MINLEN=6
112CONFIG_MD5_SIZE_VS_SPEED=2 113CONFIG_MD5_SMALL=1
113# CONFIG_FEATURE_FAST_TOP is not set 114# CONFIG_FEATURE_FAST_TOP is not set
114# CONFIG_FEATURE_ETC_NETWORKS is not set 115# CONFIG_FEATURE_ETC_NETWORKS is not set
115CONFIG_FEATURE_USE_TERMIOS=y 116CONFIG_FEATURE_USE_TERMIOS=y
@@ -118,6 +119,8 @@ CONFIG_FEATURE_EDITING_MAX_LEN=0
118# CONFIG_FEATURE_EDITING_VI is not set 119# CONFIG_FEATURE_EDITING_VI is not set
119CONFIG_FEATURE_EDITING_HISTORY=0 120CONFIG_FEATURE_EDITING_HISTORY=0
120# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set 121# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
122# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
123# CONFIG_FEATURE_REVERSE_SEARCH is not set
121# CONFIG_FEATURE_TAB_COMPLETION is not set 124# CONFIG_FEATURE_TAB_COMPLETION is not set
122# CONFIG_FEATURE_USERNAME_COMPLETION is not set 125# CONFIG_FEATURE_USERNAME_COMPLETION is not set
123# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set 126# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set
@@ -156,6 +159,7 @@ CONFIG_DPKG_DEB=y
156CONFIG_GUNZIP=y 159CONFIG_GUNZIP=y
157CONFIG_GZIP=y 160CONFIG_GZIP=y
158# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set 161# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set
162CONFIG_GZIP_FAST=0
159CONFIG_LZOP=y 163CONFIG_LZOP=y
160CONFIG_LZOP_COMPR_HIGH=y 164CONFIG_LZOP_COMPR_HIGH=y
161CONFIG_RPM2CPIO=y 165CONFIG_RPM2CPIO=y
@@ -189,6 +193,7 @@ CONFIG_CAT=y
189# CONFIG_FEATURE_DATE_ISOFMT is not set 193# CONFIG_FEATURE_DATE_ISOFMT is not set
190# CONFIG_FEATURE_DATE_NANO is not set 194# CONFIG_FEATURE_DATE_NANO is not set
191# CONFIG_FEATURE_DATE_COMPAT is not set 195# CONFIG_FEATURE_DATE_COMPAT is not set
196# CONFIG_HOSTID is not set
192# CONFIG_ID is not set 197# CONFIG_ID is not set
193# CONFIG_GROUPS is not set 198# CONFIG_GROUPS is not set
194CONFIG_TEST=y 199CONFIG_TEST=y
@@ -198,6 +203,8 @@ CONFIG_TR=y
198CONFIG_FEATURE_TR_CLASSES=y 203CONFIG_FEATURE_TR_CLASSES=y
199CONFIG_FEATURE_TR_EQUIV=y 204CONFIG_FEATURE_TR_EQUIV=y
200CONFIG_BASE64=y 205CONFIG_BASE64=y
206# CONFIG_WHO is not set
207# CONFIG_USERS is not set
201CONFIG_CAL=y 208CONFIG_CAL=y
202CONFIG_CATV=y 209CONFIG_CATV=y
203CONFIG_CHGRP=y 210CONFIG_CHGRP=y
@@ -223,18 +230,17 @@ CONFIG_DU=y
223CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y 230CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
224CONFIG_ECHO=y 231CONFIG_ECHO=y
225CONFIG_FEATURE_FANCY_ECHO=y 232CONFIG_FEATURE_FANCY_ECHO=y
226# CONFIG_ENV is not set 233CONFIG_ENV=y
227# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set 234# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set
228CONFIG_EXPAND=y 235CONFIG_EXPAND=y
229# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set 236# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set
230# CONFIG_EXPR is not set 237CONFIG_EXPR=y
231# CONFIG_EXPR_MATH_SUPPORT_64 is not set 238CONFIG_EXPR_MATH_SUPPORT_64=y
232CONFIG_FALSE=y 239CONFIG_FALSE=y
233CONFIG_FOLD=y 240CONFIG_FOLD=y
234# CONFIG_FSYNC is not set 241CONFIG_FSYNC=y
235CONFIG_HEAD=y 242CONFIG_HEAD=y
236CONFIG_FEATURE_FANCY_HEAD=y 243CONFIG_FEATURE_FANCY_HEAD=y
237# CONFIG_HOSTID is not set
238CONFIG_INSTALL=y 244CONFIG_INSTALL=y
239# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set 245# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
240CONFIG_LN=y 246CONFIG_LN=y
@@ -294,12 +300,11 @@ CONFIG_UNAME=y
294CONFIG_UNEXPAND=y 300CONFIG_UNEXPAND=y
295# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set 301# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set
296CONFIG_UNIQ=y 302CONFIG_UNIQ=y
297# CONFIG_USLEEP is not set 303CONFIG_USLEEP=y
298CONFIG_UUDECODE=y 304CONFIG_UUDECODE=y
299CONFIG_UUENCODE=y 305CONFIG_UUENCODE=y
300CONFIG_WC=y 306CONFIG_WC=y
301CONFIG_FEATURE_WC_LARGE=y 307CONFIG_FEATURE_WC_LARGE=y
302# CONFIG_WHO is not set
303CONFIG_WHOAMI=y 308CONFIG_WHOAMI=y
304CONFIG_YES=y 309CONFIG_YES=y
305 310
@@ -366,61 +371,61 @@ CONFIG_WHICH=y
366# Editors 371# Editors
367# 372#
368CONFIG_PATCH=y 373CONFIG_PATCH=y
369# CONFIG_VI is not set 374CONFIG_VI=y
370CONFIG_FEATURE_VI_MAX_LEN=0 375CONFIG_FEATURE_VI_MAX_LEN=4096
371# CONFIG_FEATURE_VI_8BIT is not set 376CONFIG_FEATURE_VI_8BIT=y
372# CONFIG_FEATURE_VI_COLON is not set 377CONFIG_FEATURE_VI_COLON=y
373# CONFIG_FEATURE_VI_YANKMARK is not set 378CONFIG_FEATURE_VI_YANKMARK=y
374# CONFIG_FEATURE_VI_SEARCH is not set 379CONFIG_FEATURE_VI_SEARCH=y
375# CONFIG_FEATURE_VI_REGEX_SEARCH is not set 380# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
376# CONFIG_FEATURE_VI_USE_SIGNALS is not set 381CONFIG_FEATURE_VI_USE_SIGNALS=y
377# CONFIG_FEATURE_VI_DOT_CMD is not set 382CONFIG_FEATURE_VI_DOT_CMD=y
378# CONFIG_FEATURE_VI_READONLY is not set 383CONFIG_FEATURE_VI_READONLY=y
379# CONFIG_FEATURE_VI_SETOPTS is not set 384CONFIG_FEATURE_VI_SETOPTS=y
380# CONFIG_FEATURE_VI_SET is not set 385CONFIG_FEATURE_VI_SET=y
381# CONFIG_FEATURE_VI_WIN_RESIZE is not set 386CONFIG_FEATURE_VI_WIN_RESIZE=y
382# CONFIG_FEATURE_VI_ASK_TERMINAL is not set 387CONFIG_FEATURE_VI_ASK_TERMINAL=y
383# CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set 388CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
384# CONFIG_AWK is not set 389CONFIG_AWK=y
385# CONFIG_FEATURE_AWK_LIBM is not set 390CONFIG_FEATURE_AWK_LIBM=y
386CONFIG_CMP=y 391CONFIG_CMP=y
387CONFIG_DIFF=y 392CONFIG_DIFF=y
388# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set 393# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set
389CONFIG_FEATURE_DIFF_DIR=y 394CONFIG_FEATURE_DIFF_DIR=y
390# CONFIG_ED is not set 395CONFIG_ED=y
391# CONFIG_SED is not set 396CONFIG_SED=y
392# CONFIG_FEATURE_ALLOW_EXEC is not set 397CONFIG_FEATURE_ALLOW_EXEC=y
393 398
394# 399#
395# Finding Utilities 400# Finding Utilities
396# 401#
397# CONFIG_FIND is not set 402CONFIG_FIND=y
398# CONFIG_FEATURE_FIND_PRINT0 is not set 403CONFIG_FEATURE_FIND_PRINT0=y
399# CONFIG_FEATURE_FIND_MTIME is not set 404CONFIG_FEATURE_FIND_MTIME=y
400# CONFIG_FEATURE_FIND_MMIN is not set 405CONFIG_FEATURE_FIND_MMIN=y
401# CONFIG_FEATURE_FIND_PERM is not set 406CONFIG_FEATURE_FIND_PERM=y
402# CONFIG_FEATURE_FIND_TYPE is not set 407CONFIG_FEATURE_FIND_TYPE=y
403# CONFIG_FEATURE_FIND_XDEV is not set 408CONFIG_FEATURE_FIND_XDEV=y
404# CONFIG_FEATURE_FIND_MAXDEPTH is not set 409CONFIG_FEATURE_FIND_MAXDEPTH=y
405# CONFIG_FEATURE_FIND_NEWER is not set 410CONFIG_FEATURE_FIND_NEWER=y
406# CONFIG_FEATURE_FIND_INUM is not set 411CONFIG_FEATURE_FIND_INUM=y
407# CONFIG_FEATURE_FIND_EXEC is not set 412CONFIG_FEATURE_FIND_EXEC=y
408# CONFIG_FEATURE_FIND_USER is not set 413CONFIG_FEATURE_FIND_USER=y
409# CONFIG_FEATURE_FIND_GROUP is not set 414CONFIG_FEATURE_FIND_GROUP=y
410# CONFIG_FEATURE_FIND_NOT is not set 415CONFIG_FEATURE_FIND_NOT=y
411# CONFIG_FEATURE_FIND_DEPTH is not set 416CONFIG_FEATURE_FIND_DEPTH=y
412# CONFIG_FEATURE_FIND_PAREN is not set 417CONFIG_FEATURE_FIND_PAREN=y
413# CONFIG_FEATURE_FIND_SIZE is not set 418CONFIG_FEATURE_FIND_SIZE=y
414# CONFIG_FEATURE_FIND_PRUNE is not set 419CONFIG_FEATURE_FIND_PRUNE=y
415# CONFIG_FEATURE_FIND_DELETE is not set 420CONFIG_FEATURE_FIND_DELETE=y
416# CONFIG_FEATURE_FIND_PATH is not set 421CONFIG_FEATURE_FIND_PATH=y
417# CONFIG_FEATURE_FIND_REGEX is not set 422CONFIG_FEATURE_FIND_REGEX=y
418# CONFIG_FEATURE_FIND_CONTEXT is not set 423# CONFIG_FEATURE_FIND_CONTEXT is not set
419# CONFIG_FEATURE_FIND_LINKS is not set 424CONFIG_FEATURE_FIND_LINKS=y
420# CONFIG_GREP is not set 425CONFIG_GREP=y
421# CONFIG_FEATURE_GREP_EGREP_ALIAS is not set 426CONFIG_FEATURE_GREP_EGREP_ALIAS=y
422# CONFIG_FEATURE_GREP_FGREP_ALIAS is not set 427CONFIG_FEATURE_GREP_FGREP_ALIAS=y
423# CONFIG_FEATURE_GREP_CONTEXT is not set 428CONFIG_FEATURE_GREP_CONTEXT=y
424CONFIG_XARGS=y 429CONFIG_XARGS=y
425CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y 430CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
426CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y 431CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
@@ -430,9 +435,9 @@ CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
430# 435#
431# Init Utilities 436# Init Utilities
432# 437#
433# CONFIG_BOOTCHARTD is not set 438CONFIG_BOOTCHARTD=y
434# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set 439CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y
435# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set 440CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y
436CONFIG_HALT=y 441CONFIG_HALT=y
437# CONFIG_FEATURE_CALL_TELINIT is not set 442# CONFIG_FEATURE_CALL_TELINIT is not set
438CONFIG_TELINIT_PATH="" 443CONFIG_TELINIT_PATH=""
@@ -472,6 +477,7 @@ CONFIG_LAST_SYSTEM_ID=0
472# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set 477# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
473# CONFIG_GETTY is not set 478# CONFIG_GETTY is not set
474# CONFIG_LOGIN is not set 479# CONFIG_LOGIN is not set
480# CONFIG_LOGIN_SESSION_AS_CHILD is not set
475# CONFIG_PAM is not set 481# CONFIG_PAM is not set
476# CONFIG_LOGIN_SCRIPTS is not set 482# CONFIG_LOGIN_SCRIPTS is not set
477# CONFIG_FEATURE_NOLOGIN is not set 483# CONFIG_FEATURE_NOLOGIN is not set
@@ -529,11 +535,17 @@ CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
529# Linux System Utilities 535# Linux System Utilities
530# 536#
531CONFIG_BLOCKDEV=y 537CONFIG_BLOCKDEV=y
538CONFIG_MDEV=y
539CONFIG_FEATURE_MDEV_CONF=y
540CONFIG_FEATURE_MDEV_RENAME=y
541CONFIG_FEATURE_MDEV_RENAME_REGEXP=y
542CONFIG_FEATURE_MDEV_EXEC=y
543CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y
532CONFIG_REV=y 544CONFIG_REV=y
533# CONFIG_ACPID is not set 545# CONFIG_ACPID is not set
534# CONFIG_FEATURE_ACPID_COMPAT is not set 546# CONFIG_FEATURE_ACPID_COMPAT is not set
535CONFIG_BLKID=y 547CONFIG_BLKID=y
536# CONFIG_FEATURE_BLKID_TYPE is not set 548CONFIG_FEATURE_BLKID_TYPE=y
537CONFIG_DMESG=y 549CONFIG_DMESG=y
538CONFIG_FEATURE_DMESG_PRETTY=y 550CONFIG_FEATURE_DMESG_PRETTY=y
539CONFIG_FBSET=y 551CONFIG_FBSET=y
@@ -542,7 +554,7 @@ CONFIG_FEATURE_FBSET_READMODE=y
542CONFIG_FDFLUSH=y 554CONFIG_FDFLUSH=y
543CONFIG_FDFORMAT=y 555CONFIG_FDFORMAT=y
544CONFIG_FDISK=y 556CONFIG_FDISK=y
545CONFIG_FDISK_SUPPORT_LARGE_DISKS=y 557# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
546CONFIG_FEATURE_FDISK_WRITABLE=y 558CONFIG_FEATURE_FDISK_WRITABLE=y
547# CONFIG_FEATURE_AIX_LABEL is not set 559# CONFIG_FEATURE_AIX_LABEL is not set
548# CONFIG_FEATURE_SGI_LABEL is not set 560# CONFIG_FEATURE_SGI_LABEL is not set
@@ -564,7 +576,7 @@ CONFIG_FEATURE_GETOPT_LONG=y
564CONFIG_HEXDUMP=y 576CONFIG_HEXDUMP=y
565CONFIG_FEATURE_HEXDUMP_REVERSE=y 577CONFIG_FEATURE_HEXDUMP_REVERSE=y
566CONFIG_HD=y 578CONFIG_HD=y
567# CONFIG_HWCLOCK is not set 579CONFIG_HWCLOCK=y
568# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set 580# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
569# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set 581# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
570# CONFIG_IPCRM is not set 582# CONFIG_IPCRM is not set
@@ -572,12 +584,6 @@ CONFIG_HD=y
572CONFIG_LOSETUP=y 584CONFIG_LOSETUP=y
573CONFIG_LSPCI=y 585CONFIG_LSPCI=y
574CONFIG_LSUSB=y 586CONFIG_LSUSB=y
575# CONFIG_MDEV is not set
576# CONFIG_FEATURE_MDEV_CONF is not set
577# CONFIG_FEATURE_MDEV_RENAME is not set
578# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
579# CONFIG_FEATURE_MDEV_EXEC is not set
580# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
581CONFIG_MKSWAP=y 587CONFIG_MKSWAP=y
582CONFIG_FEATURE_MKSWAP_UUID=y 588CONFIG_FEATURE_MKSWAP_UUID=y
583CONFIG_MORE=y 589CONFIG_MORE=y
@@ -600,7 +606,7 @@ CONFIG_SCRIPTREPLAY=y
600# CONFIG_SETARCH is not set 606# CONFIG_SETARCH is not set
601# CONFIG_SWAPONOFF is not set 607# CONFIG_SWAPONOFF is not set
602# CONFIG_FEATURE_SWAPON_PRI is not set 608# CONFIG_FEATURE_SWAPON_PRI is not set
603# CONFIG_SWITCH_ROOT is not set 609CONFIG_SWITCH_ROOT=y
604# CONFIG_UMOUNT is not set 610# CONFIG_UMOUNT is not set
605# CONFIG_FEATURE_UMOUNT_ALL is not set 611# CONFIG_FEATURE_UMOUNT_ALL is not set
606# CONFIG_FEATURE_MOUNT_LOOP is not set 612# CONFIG_FEATURE_MOUNT_LOOP is not set
@@ -633,6 +639,16 @@ CONFIG_FEATURE_VOLUMEID_LINUXRAID=y
633# Miscellaneous Utilities 639# Miscellaneous Utilities
634# 640#
635# CONFIG_CONSPY is not set 641# CONFIG_CONSPY is not set
642CONFIG_LESS=y
643CONFIG_FEATURE_LESS_MAXLINES=9999999
644CONFIG_FEATURE_LESS_BRACKETS=y
645CONFIG_FEATURE_LESS_FLAGS=y
646CONFIG_FEATURE_LESS_MARKS=y
647CONFIG_FEATURE_LESS_REGEXP=y
648CONFIG_FEATURE_LESS_WINCH=y
649CONFIG_FEATURE_LESS_ASK_TERMINAL=y
650CONFIG_FEATURE_LESS_DASHCMD=y
651CONFIG_FEATURE_LESS_LINENUMS=y
636# CONFIG_NANDWRITE is not set 652# CONFIG_NANDWRITE is not set
637CONFIG_NANDDUMP=y 653CONFIG_NANDDUMP=y
638CONFIG_SETSERIAL=y 654CONFIG_SETSERIAL=y
@@ -657,11 +673,11 @@ CONFIG_FEATURE_CHAT_SEND_ESCAPES=y
657CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y 673CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y
658CONFIG_FEATURE_CHAT_CLR_ABORT=y 674CONFIG_FEATURE_CHAT_CLR_ABORT=y
659CONFIG_CHRT=y 675CONFIG_CHRT=y
660# CONFIG_CROND is not set 676CONFIG_CROND=y
661# CONFIG_FEATURE_CROND_D is not set 677CONFIG_FEATURE_CROND_D=y
662# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set 678CONFIG_FEATURE_CROND_CALL_SENDMAIL=y
663CONFIG_FEATURE_CROND_DIR="" 679CONFIG_FEATURE_CROND_DIR="/var/spool/cron"
664# CONFIG_CRONTAB is not set 680CONFIG_CRONTAB=y
665CONFIG_DC=y 681CONFIG_DC=y
666CONFIG_FEATURE_DC_LIBM=y 682CONFIG_FEATURE_DC_LIBM=y
667# CONFIG_DEVFSD is not set 683# CONFIG_DEVFSD is not set
@@ -682,15 +698,6 @@ CONFIG_INOTIFYD=y
682# CONFIG_LAST is not set 698# CONFIG_LAST is not set
683# CONFIG_FEATURE_LAST_SMALL is not set 699# CONFIG_FEATURE_LAST_SMALL is not set
684# CONFIG_FEATURE_LAST_FANCY is not set 700# CONFIG_FEATURE_LAST_FANCY is not set
685# CONFIG_LESS is not set
686CONFIG_FEATURE_LESS_MAXLINES=0
687# CONFIG_FEATURE_LESS_BRACKETS is not set
688# CONFIG_FEATURE_LESS_FLAGS is not set
689# CONFIG_FEATURE_LESS_MARKS is not set
690# CONFIG_FEATURE_LESS_REGEXP is not set
691# CONFIG_FEATURE_LESS_WINCH is not set
692# CONFIG_FEATURE_LESS_DASHCMD is not set
693# CONFIG_FEATURE_LESS_LINENUMS is not set
694CONFIG_HDPARM=y 701CONFIG_HDPARM=y
695CONFIG_FEATURE_HDPARM_GET_IDENTITY=y 702CONFIG_FEATURE_HDPARM_GET_IDENTITY=y
696CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y 703CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y
@@ -731,9 +738,9 @@ CONFIG_NC=y
731CONFIG_NC_SERVER=y 738CONFIG_NC_SERVER=y
732CONFIG_NC_EXTRA=y 739CONFIG_NC_EXTRA=y
733# CONFIG_NC_110_COMPAT is not set 740# CONFIG_NC_110_COMPAT is not set
734# CONFIG_PING is not set 741CONFIG_PING=y
735# CONFIG_PING6 is not set 742# CONFIG_PING6 is not set
736# CONFIG_FEATURE_FANCY_PING is not set 743CONFIG_FEATURE_FANCY_PING=y
737CONFIG_WHOIS=y 744CONFIG_WHOIS=y
738# CONFIG_FEATURE_IPV6 is not set 745# CONFIG_FEATURE_IPV6 is not set
739# CONFIG_FEATURE_UNIX_LOCAL is not set 746# CONFIG_FEATURE_UNIX_LOCAL is not set
@@ -817,18 +824,22 @@ CONFIG_PSCAN=y
817CONFIG_ROUTE=y 824CONFIG_ROUTE=y
818# CONFIG_SLATTACH is not set 825# CONFIG_SLATTACH is not set
819CONFIG_TCPSVD=y 826CONFIG_TCPSVD=y
820# CONFIG_TELNET is not set 827CONFIG_TELNET=y
821# CONFIG_FEATURE_TELNET_TTYPE is not set 828CONFIG_FEATURE_TELNET_TTYPE=y
822# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set 829CONFIG_FEATURE_TELNET_AUTOLOGIN=y
823# CONFIG_TELNETD is not set 830CONFIG_TELNETD=y
824# CONFIG_FEATURE_TELNETD_STANDALONE is not set 831CONFIG_FEATURE_TELNETD_STANDALONE=y
825# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set 832CONFIG_FEATURE_TELNETD_INETD_WAIT=y
826# CONFIG_TFTP is not set 833CONFIG_TFTP=y
827# CONFIG_TFTPD is not set 834CONFIG_TFTPD=y
828# CONFIG_FEATURE_TFTP_GET is not set 835
829# CONFIG_FEATURE_TFTP_PUT is not set 836#
830# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set 837# Common options for tftp/tftpd
831# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set 838#
839CONFIG_FEATURE_TFTP_GET=y
840CONFIG_FEATURE_TFTP_PUT=y
841CONFIG_FEATURE_TFTP_BLOCKSIZE=y
842CONFIG_FEATURE_TFTP_PROGRESS_BAR=y
832# CONFIG_TFTP_DEBUG is not set 843# CONFIG_TFTP_DEBUG is not set
833# CONFIG_TRACEROUTE is not set 844# CONFIG_TRACEROUTE is not set
834# CONFIG_TRACEROUTE6 is not set 845# CONFIG_TRACEROUTE6 is not set
@@ -852,8 +863,8 @@ CONFIG_FEATURE_UDHCP_8021Q=y
852CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" 863CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script"
853CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 864CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80
854CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" 865CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n"
855# CONFIG_UDPSVD is not set 866CONFIG_UDPSVD=y
856# CONFIG_VCONFIG is not set 867CONFIG_VCONFIG=y
857CONFIG_WGET=y 868CONFIG_WGET=y
858CONFIG_FEATURE_WGET_STATUSBAR=y 869CONFIG_FEATURE_WGET_STATUSBAR=y
859CONFIG_FEATURE_WGET_AUTHENTICATION=y 870CONFIG_FEATURE_WGET_AUTHENTICATION=y
@@ -890,7 +901,9 @@ CONFIG_POWERTOP=y
890CONFIG_PSTREE=y 901CONFIG_PSTREE=y
891CONFIG_PWDX=y 902CONFIG_PWDX=y
892CONFIG_SMEMCAP=y 903CONFIG_SMEMCAP=y
893# CONFIG_FREE is not set 904CONFIG_UPTIME=y
905# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
906CONFIG_FREE=y
894CONFIG_FUSER=y 907CONFIG_FUSER=y
895# CONFIG_KILL is not set 908# CONFIG_KILL is not set
896# CONFIG_KILLALL is not set 909# CONFIG_KILLALL is not set
@@ -900,10 +913,11 @@ CONFIG_PIDOF=y
900CONFIG_FEATURE_PIDOF_SINGLE=y 913CONFIG_FEATURE_PIDOF_SINGLE=y
901CONFIG_FEATURE_PIDOF_OMIT=y 914CONFIG_FEATURE_PIDOF_OMIT=y
902# CONFIG_PKILL is not set 915# CONFIG_PKILL is not set
903# CONFIG_PS is not set 916CONFIG_PS=y
904# CONFIG_FEATURE_PS_WIDE is not set 917# CONFIG_FEATURE_PS_WIDE is not set
905# CONFIG_FEATURE_PS_TIME is not set 918# CONFIG_FEATURE_PS_LONG is not set
906# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set 919CONFIG_FEATURE_PS_TIME=y
920CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y
907# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set 921# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
908CONFIG_RENICE=y 922CONFIG_RENICE=y
909CONFIG_BB_SYSCTL=y 923CONFIG_BB_SYSCTL=y
@@ -915,7 +929,6 @@ CONFIG_FEATURE_TOP_DECIMALS=y
915CONFIG_FEATURE_TOP_SMP_PROCESS=y 929CONFIG_FEATURE_TOP_SMP_PROCESS=y
916CONFIG_FEATURE_TOPMEM=y 930CONFIG_FEATURE_TOPMEM=y
917CONFIG_FEATURE_SHOW_THREADS=y 931CONFIG_FEATURE_SHOW_THREADS=y
918# CONFIG_UPTIME is not set
919CONFIG_WATCH=y 932CONFIG_WATCH=y
920 933
921# 934#
diff --git a/configs/cygwin_defconfig b/configs/cygwin_defconfig
index cc2d643e1..bdd0d66d0 100644
--- a/configs/cygwin_defconfig
+++ b/configs/cygwin_defconfig
@@ -92,7 +92,7 @@ CONFIG_PREFIX="./_install"
92# CONFIG_FEATURE_SYSTEMD is not set 92# CONFIG_FEATURE_SYSTEMD is not set
93CONFIG_FEATURE_RTMINMAX=y 93CONFIG_FEATURE_RTMINMAX=y
94CONFIG_PASSWORD_MINLEN=6 94CONFIG_PASSWORD_MINLEN=6
95CONFIG_MD5_SIZE_VS_SPEED=2 95CONFIG_MD5_SMALL=1
96CONFIG_FEATURE_FAST_TOP=y 96CONFIG_FEATURE_FAST_TOP=y
97# CONFIG_FEATURE_ETC_NETWORKS is not set 97# CONFIG_FEATURE_ETC_NETWORKS is not set
98CONFIG_FEATURE_USE_TERMIOS=y 98CONFIG_FEATURE_USE_TERMIOS=y
diff --git a/configs/freebsd_defconfig b/configs/freebsd_defconfig
index 5f2985be1..dcb5d953c 100644
--- a/configs/freebsd_defconfig
+++ b/configs/freebsd_defconfig
@@ -90,7 +90,7 @@ CONFIG_PREFIX="./_install"
90# Busybox Library Tuning 90# Busybox Library Tuning
91# 91#
92CONFIG_PASSWORD_MINLEN=6 92CONFIG_PASSWORD_MINLEN=6
93CONFIG_MD5_SIZE_VS_SPEED=2 93CONFIG_MD5_SMALL=1
94CONFIG_FEATURE_FAST_TOP=y 94CONFIG_FEATURE_FAST_TOP=y
95# CONFIG_FEATURE_ETC_NETWORKS is not set 95# CONFIG_FEATURE_ETC_NETWORKS is not set
96CONFIG_FEATURE_USE_TERMIOS=y 96CONFIG_FEATURE_USE_TERMIOS=y
diff --git a/coreutils/Config.src b/coreutils/Config.src
index cff2ce216..81be71993 100644
--- a/coreutils/Config.src
+++ b/coreutils/Config.src
@@ -269,13 +269,6 @@ config FEATURE_FANCY_HEAD
269 help 269 help
270 This enables the head options (-c, -q, and -v). 270 This enables the head options (-c, -q, and -v).
271 271
272config HOSTID
273 bool "hostid"
274 default y
275 help
276 hostid prints the numeric identifier (in hexadecimal) for
277 the current host.
278
279config INSTALL 272config INSTALL
280 bool "install" 273 bool "install"
281 default y 274 default y
diff --git a/coreutils/Kbuild.src b/coreutils/Kbuild.src
index 53d88b391..d6453f014 100644
--- a/coreutils/Kbuild.src
+++ b/coreutils/Kbuild.src
@@ -36,7 +36,6 @@ lib-$(CONFIG_FALSE) += false.o
36lib-$(CONFIG_FOLD) += fold.o 36lib-$(CONFIG_FOLD) += fold.o
37lib-$(CONFIG_FSYNC) += fsync.o 37lib-$(CONFIG_FSYNC) += fsync.o
38lib-$(CONFIG_HEAD) += head.o 38lib-$(CONFIG_HEAD) += head.o
39lib-$(CONFIG_HOSTID) += hostid.o
40lib-$(CONFIG_INSTALL) += install.o 39lib-$(CONFIG_INSTALL) += install.o
41#lib-$(CONFIG_LENGTH) += length.o 40#lib-$(CONFIG_LENGTH) += length.o
42lib-$(CONFIG_LN) += ln.o 41lib-$(CONFIG_LN) += ln.o
diff --git a/coreutils/du.c b/coreutils/du.c
index b8bbe3d9e..34a549f02 100644
--- a/coreutils/du.c
+++ b/coreutils/du.c
@@ -88,6 +88,7 @@ struct globals {
88 dev_t dir_dev; 88 dev_t dir_dev;
89} FIX_ALIASING; 89} FIX_ALIASING;
90#define G (*(struct globals*)&bb_common_bufsiz1) 90#define G (*(struct globals*)&bb_common_bufsiz1)
91#define INIT_G() do { } while (0)
91 92
92 93
93static void print(unsigned long size, const char *filename) 94static void print(unsigned long size, const char *filename)
@@ -193,6 +194,8 @@ int du_main(int argc UNUSED_PARAM, char **argv)
193 int slink_depth_save; 194 int slink_depth_save;
194 unsigned opt; 195 unsigned opt;
195 196
197 INIT_G();
198
196#if ENABLE_FEATURE_HUMAN_READABLE 199#if ENABLE_FEATURE_HUMAN_READABLE
197 IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 1024;) 200 IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 1024;)
198 IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 512;) 201 IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 512;)
diff --git a/coreutils/expr.c b/coreutils/expr.c
index 24e75b556..c986f9327 100644
--- a/coreutils/expr.c
+++ b/coreutils/expr.c
@@ -100,6 +100,7 @@ struct globals {
100 char **args; 100 char **args;
101} FIX_ALIASING; 101} FIX_ALIASING;
102#define G (*(struct globals*)&bb_common_bufsiz1) 102#define G (*(struct globals*)&bb_common_bufsiz1)
103#define INIT_G() do { } while (0)
103 104
104/* forward declarations */ 105/* forward declarations */
105static VALUE *eval(void); 106static VALUE *eval(void);
@@ -519,6 +520,8 @@ int expr_main(int argc UNUSED_PARAM, char **argv)
519{ 520{
520 VALUE *v; 521 VALUE *v;
521 522
523 INIT_G();
524
522 xfunc_error_retval = 2; /* coreutils compat */ 525 xfunc_error_retval = 2; /* coreutils compat */
523 G.args = argv + 1; 526 G.args = argv + 1;
524 if (*G.args == NULL) { 527 if (*G.args == NULL) {
diff --git a/coreutils/hostid.c b/coreutils/hostid.c
index 49409b9de..5c1a4e086 100644
--- a/coreutils/hostid.c
+++ b/coreutils/hostid.c
@@ -9,6 +9,17 @@
9 9
10/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ 10/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
11 11
12//config:config HOSTID
13//config: bool "hostid"
14//config: default y
15//config: help
16//config: hostid prints the numeric identifier (in hexadecimal) for
17//config: the current host.
18
19//applet:IF_HOSTID(APPLET_NOFORK(hostid, hostid, BB_DIR_USR_BIN, BB_SUID_DROP, hostid))
20
21//kbuild:lib-$(CONFIG_HOSTID) += hostid.o
22
12//usage:#define hostid_trivial_usage 23//usage:#define hostid_trivial_usage
13//usage: "" 24//usage: ""
14//usage:#define hostid_full_usage "\n\n" 25//usage:#define hostid_full_usage "\n\n"
@@ -25,7 +36,7 @@ int hostid_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
25 bb_show_usage(); 36 bb_show_usage();
26 } 37 }
27 38
28 printf("%lx\n", gethostid()); 39 printf("%08lx\n", gethostid());
29 40
30 return fflush_all(); 41 return fflush_all();
31} 42}
diff --git a/coreutils/pwd.c b/coreutils/pwd.c
index 739b835b5..bb3ad04fc 100644
--- a/coreutils/pwd.c
+++ b/coreutils/pwd.c
@@ -20,13 +20,63 @@
20 20
21/* This is a NOFORK applet. Be very careful! */ 21/* This is a NOFORK applet. Be very careful! */
22 22
23static int logical_getcwd(void)
24{
25 struct stat st1;
26 struct stat st2;
27 char *wd;
28 char *p;
29
30 wd = getenv("PWD");
31 if (!wd || wd[0] != '/')
32 return 0;
33
34 p = wd;
35 while (*p) {
36 /* doing strstr(p, "/.") by hand is smaller and faster... */
37 if (*p++ != '/')
38 continue;
39 if (*p != '.')
40 continue;
41 /* we found "/.", skip to next char */
42 p++;
43 if (*p == '.')
44 p++; /* we found "/.." */
45 if (*p == '\0' || *p == '/')
46 return 0; /* "/./" or "/../" component: bad */
47 }
48
49 if (stat(wd, &st1) != 0)
50 return 0;
51 if (stat(".", &st2) != 0)
52 return 0;
53 if (st1.st_ino != st2.st_ino)
54 return 0;
55 if (st1.st_dev != st2.st_dev)
56 return 0;
57
58 puts(wd);
59 return 1;
60}
61
23int pwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 62int pwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
24int pwd_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 63int pwd_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
25{ 64{
26 char *buf; 65 char *buf;
27 66
67 if (ENABLE_DESKTOP) {
68 /* TODO: assume -L if $POSIXLY_CORRECT? (coreutils does that)
69 * Rationale:
70 * POSIX requires a default of -L, but most scripts expect -P
71 */
72 unsigned opt = getopt32(argv, "LP");
73 if ((opt & 1) && logical_getcwd())
74 return fflush_all();
75 }
76
28 buf = xrealloc_getcwd_or_warn(NULL); 77 buf = xrealloc_getcwd_or_warn(NULL);
29 if (buf != NULL) { 78
79 if (buf) {
30 puts(buf); 80 puts(buf);
31 free(buf); 81 free(buf);
32 return fflush_all(); 82 return fflush_all();
diff --git a/coreutils/stty.c b/coreutils/stty.c
index 7f057ead2..0668cf7be 100644
--- a/coreutils/stty.c
+++ b/coreutils/stty.c
@@ -1404,13 +1404,15 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1404 1404
1405 /* Specifying both -a and -g is an error */ 1405 /* Specifying both -a and -g is an error */
1406 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) == 1406 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
1407 (STTY_verbose_output | STTY_recoverable_output)) 1407 (STTY_verbose_output | STTY_recoverable_output)
1408 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive"); 1408 ) {
1409 bb_error_msg_and_die("-a and -g are mutually exclusive");
1410 }
1409 /* Specifying -a or -g with non-options is an error */ 1411 /* Specifying -a or -g with non-options is an error */
1410 if (!(stty_state & STTY_noargs) 1412 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output))
1411 && (stty_state & (STTY_verbose_output | STTY_recoverable_output)) 1413 && !(stty_state & STTY_noargs)
1412 ) { 1414 ) {
1413 bb_error_msg_and_die("modes may not be set when specifying an output style"); 1415 bb_error_msg_and_die("modes may not be set when -a or -g is used");
1414 } 1416 }
1415 1417
1416 /* Now it is safe to start doing things */ 1418 /* Now it is safe to start doing things */
diff --git a/coreutils/tail.c b/coreutils/tail.c
index 454c25936..b376ec863 100644
--- a/coreutils/tail.c
+++ b/coreutils/tail.c
@@ -62,6 +62,7 @@ struct globals {
62 bool exitcode; 62 bool exitcode;
63} FIX_ALIASING; 63} FIX_ALIASING;
64#define G (*(struct globals*)&bb_common_bufsiz1) 64#define G (*(struct globals*)&bb_common_bufsiz1)
65#define INIT_G() do { } while (0)
65 66
66static void tail_xprint_header(const char *fmt, const char *filename) 67static void tail_xprint_header(const char *fmt, const char *filename)
67{ 68{
@@ -120,6 +121,8 @@ int tail_main(int argc, char **argv)
120 int *fds; 121 int *fds;
121 const char *fmt; 122 const char *fmt;
122 123
124 INIT_G();
125
123#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_TAIL 126#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_TAIL
124 /* Allow legacy syntax of an initial numeric option without -n. */ 127 /* Allow legacy syntax of an initial numeric option without -n. */
125 if (argv[1] && (argv[1][0] == '+' || argv[1][0] == '-') 128 if (argv[1] && (argv[1][0] == '+' || argv[1][0] == '-')
@@ -203,7 +206,7 @@ int tail_main(int argc, char **argv)
203 int fd = fds[i]; 206 int fd = fds[i];
204 207
205 if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) 208 if (ENABLE_FEATURE_FANCY_TAIL && fd < 0)
206 continue; /* may happen with -E */ 209 continue; /* may happen with -F */
207 210
208 if (nfiles > header_threshhold) { 211 if (nfiles > header_threshhold) {
209 tail_xprint_header(fmt, argv[i]); 212 tail_xprint_header(fmt, argv[i]);
@@ -252,14 +255,14 @@ int tail_main(int argc, char **argv)
252 * Used only by +N code ("start from Nth", 1-based): */ 255 * Used only by +N code ("start from Nth", 1-based): */
253 seen = 1; 256 seen = 1;
254 newlines_seen = 0; 257 newlines_seen = 0;
255 while ((nread = tail_read(fd, buf, tailbufsize-taillen)) > 0) { 258 while ((nread = tail_read(fd, buf, tailbufsize - taillen)) > 0) {
256 if (G.from_top) { 259 if (G.from_top) {
257 int nwrite = nread; 260 int nwrite = nread;
258 if (seen < count) { 261 if (seen < count) {
259 /* We need to skip a few more bytes/lines */ 262 /* We need to skip a few more bytes/lines */
260 if (COUNT_BYTES) { 263 if (COUNT_BYTES) {
261 nwrite -= (count - seen); 264 nwrite -= (count - seen);
262 seen = count; 265 seen += nread;
263 } else { 266 } else {
264 char *s = buf; 267 char *s = buf;
265 do { 268 do {
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c
index 6ecfe6cef..23ff711fa 100644
--- a/coreutils/uudecode.c
+++ b/coreutils/uudecode.c
@@ -125,10 +125,11 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv)
125 mode = bb_strtou(line_ptr, NULL, 8); 125 mode = bb_strtou(line_ptr, NULL, 8);
126 if (outname == NULL) { 126 if (outname == NULL) {
127 outname = strchr(line_ptr, ' '); 127 outname = strchr(line_ptr, ' ');
128 if ((outname == NULL) || (*outname == '\0')) { 128 if (!outname)
129 break; 129 break;
130 }
131 outname++; 130 outname++;
131 if (!outname[0])
132 break;
132 } 133 }
133 dst_stream = stdout; 134 dst_stream = stdout;
134 if (NOT_LONE_DASH(outname)) { 135 if (NOT_LONE_DASH(outname)) {
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c
index 65cbfc338..8f08f6dc6 100644
--- a/debianutils/run_parts.c
+++ b/debianutils/run_parts.c
@@ -66,6 +66,7 @@ struct globals {
66#define names (G.names) 66#define names (G.names)
67#define cur (G.cur ) 67#define cur (G.cur )
68#define cmd (G.cmd ) 68#define cmd (G.cmd )
69#define INIT_G() do { } while (0)
69 70
70enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 }; 71enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 };
71 72
@@ -143,6 +144,8 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv)
143 unsigned n; 144 unsigned n;
144 int ret; 145 int ret;
145 146
147 INIT_G();
148
146#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS 149#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
147 applet_long_options = runparts_longopts; 150 applet_long_options = runparts_longopts;
148#endif 151#endif
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c
index bc61959d2..02609c04f 100644
--- a/debianutils/start_stop_daemon.c
+++ b/debianutils/start_stop_daemon.c
@@ -502,8 +502,16 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
502 if (opt & OPT_c) { 502 if (opt & OPT_c) {
503 struct bb_uidgid_t ugid = { -1, -1 }; 503 struct bb_uidgid_t ugid = { -1, -1 };
504 parse_chown_usergroup_or_die(&ugid, chuid); 504 parse_chown_usergroup_or_die(&ugid, chuid);
505 if (ugid.gid != (gid_t) -1) xsetgid(ugid.gid); 505 if (ugid.uid != (uid_t) -1) {
506 if (ugid.uid != (uid_t) -1) xsetuid(ugid.uid); 506 struct passwd *pw = xgetpwuid(ugid.uid);
507 if (ugid.gid != (gid_t) -1)
508 pw->pw_gid = ugid.gid;
509 /* initgroups, setgid, setuid: */
510 change_identity(pw);
511 } else if (ugid.gid != (gid_t) -1) {
512 xsetgid(ugid.gid);
513 setgroups(1, &ugid.gid);
514 }
507 } 515 }
508#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY 516#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
509 if (opt & OPT_NICELEVEL) { 517 if (opt & OPT_NICELEVEL) {
diff --git a/docs/ctty.htm b/docs/ctty.htm
index 8f466cdde..3cb2dd2bd 100644
--- a/docs/ctty.htm
+++ b/docs/ctty.htm
@@ -9,6 +9,8 @@
9 9
10<p>Before looking at the Linux implementation, first a general Unix 10<p>Before looking at the Linux implementation, first a general Unix
11description of threads, processes, process groups and sessions. 11description of threads, processes, process groups and sessions.
12</p><p>
13(See also <a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html">General Terminal Interface</a>)
12</p><p>A session contains a number of process groups, and a process group 14</p><p>A session contains a number of process groups, and a process group
13contains a number of processes, and a process contains a number 15contains a number of processes, and a process contains a number
14of threads. 16of threads.
@@ -277,6 +279,7 @@ and inspect it by
277Again, if TOSTOP is set but the background process ignores or blocks 279Again, if TOSTOP is set but the background process ignores or blocks
278the SIGTTOU signal, or if its process group is orphaned (see below), 280the SIGTTOU signal, or if its process group is orphaned (see below),
279then the write() returns an EIO error, and no signal is sent. 281then the write() returns an EIO error, and no signal is sent.
282[vda: correction. SUS says that if SIGTTOU is blocked/ignored, write succeeds. ]
280<p> 283<p>
281</p><h3>Orphaned process groups</h3> 284</p><h3>Orphaned process groups</h3>
282 285
diff --git a/docs/mdev.txt b/docs/mdev.txt
index 2d03bd8b2..61f93c9df 100644
--- a/docs/mdev.txt
+++ b/docs/mdev.txt
@@ -51,19 +51,25 @@ device nodes if your system needs something more than the default root/root
51660 permissions. 51660 permissions.
52 52
53The file has the format: 53The file has the format:
54 <device regex> <uid>:<gid> <permissions> 54 [-]<device regex> <uid>:<gid> <permissions>
55 or @<maj[,min1[-min2]]> <uid>:<gid> <permissions> 55or
56 @<maj[,min1[-min2]]> <uid>:<gid> <permissions>
57or
58 $envvar=<regex> <uid>:<gid> <permissions>
56 59
57For example: 60For example:
58 hd[a-z][0-9]* 0:3 660 61 hd[a-z][0-9]* 0:3 660
59 62
60The config file parsing stops at the first matching line. If no line is 63The config file parsing stops at the first matching line. If no line is
61matched, then the default of 0:0 660 is used. To set your own default, simply 64matched, then the default of 0:0 660 is used. To set your own default, simply
62create your own total match like so: 65create your own total match like so:
66
63 .* 1:1 777 67 .* 1:1 777
64 68
65You can rename/move device nodes by using the next optional field. 69You can rename/move device nodes by using the next optional field.
70
66 <device regex> <uid>:<gid> <permissions> [=path] 71 <device regex> <uid>:<gid> <permissions> [=path]
72
67So if you want to place the device node into a subdirectory, make sure the path 73So if you want to place the device node into a subdirectory, make sure the path
68has a trailing /. If you want to rename the device node, just place the name. 74has a trailing /. If you want to rename the device node, just place the name.
69 hda 0:3 660 =drives/ 75 hda 0:3 660 =drives/
diff --git a/e2fsprogs/tune2fs.c b/e2fsprogs/tune2fs.c
index 9daec542a..020bdaa33 100644
--- a/e2fsprogs/tune2fs.c
+++ b/e2fsprogs/tune2fs.c
@@ -28,12 +28,13 @@ do { \
28 (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size()) 28 (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size())
29 29
30//usage:#define tune2fs_trivial_usage 30//usage:#define tune2fs_trivial_usage
31//usage: "[-c MOUNT_CNT] " 31//usage: "[-c MAX_MOUNT_COUNT] "
32////usage: "[-e errors-behavior] [-g group] " 32////usage: "[-e errors-behavior] [-g group] "
33//usage: "[-i DAYS] " 33//usage: "[-i DAYS] "
34////usage: "[-j] [-J journal-options] [-l] [-s sparse-flag] " 34////usage: "[-j] [-J journal-options] [-l] [-s sparse-flag] "
35////usage: "[-m reserved-blocks-percent] [-o [^]mount-options[,...]] " 35////usage: "[-m reserved-blocks-percent] [-o [^]mount-options[,...]] "
36////usage: "[-r reserved-blocks-count] [-u user] [-C mount-count] " 36////usage: "[-r reserved-blocks-count] [-u user] "
37//usage: "[-C MOUNT_COUNT] "
37//usage: "[-L LABEL] " 38//usage: "[-L LABEL] "
38////usage: "[-M last-mounted-dir] [-O [^]feature[,...]] " 39////usage: "[-M last-mounted-dir] [-O [^]feature[,...]] "
39////usage: "[-T last-check-time] [-U UUID] " 40////usage: "[-T last-check-time] [-U UUID] "
@@ -46,18 +47,19 @@ enum {
46 OPT_L = 1 << 0, // label 47 OPT_L = 1 << 0, // label
47 OPT_c = 1 << 1, // max mount count 48 OPT_c = 1 << 1, // max mount count
48 OPT_i = 1 << 2, // check interval 49 OPT_i = 1 << 2, // check interval
50 OPT_C = 1 << 3, // current mount count
49}; 51};
50 52
51int tune2fs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 53int tune2fs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
52int tune2fs_main(int argc UNUSED_PARAM, char **argv) 54int tune2fs_main(int argc UNUSED_PARAM, char **argv)
53{ 55{
54 unsigned opts; 56 unsigned opts;
55 const char *label, *str_c, *str_i; 57 const char *label, *str_c, *str_i, *str_C;
56 struct ext2_super_block *sb; 58 struct ext2_super_block *sb;
57 int fd; 59 int fd;
58 60
59 opt_complementary = "=1"; 61 opt_complementary = "=1";
60 opts = getopt32(argv, "L:c:i:", &label, &str_c, &str_i); 62 opts = getopt32(argv, "L:c:i:C:", &label, &str_c, &str_i, &str_C);
61 if (!opts) 63 if (!opts)
62 bb_show_usage(); 64 bb_show_usage();
63 argv += optind; // argv[0] -- device 65 argv += optind; // argv[0] -- device
@@ -71,6 +73,11 @@ int tune2fs_main(int argc UNUSED_PARAM, char **argv)
71 // mangle superblock 73 // mangle superblock
72 //STORE_LE(sb->s_wtime, time(NULL)); - why bother? 74 //STORE_LE(sb->s_wtime, time(NULL)); - why bother?
73 75
76 if (opts & OPT_C) {
77 int n = xatoi_range(str_C, 1, 0xfffe);
78 STORE_LE(sb->s_mnt_count, (unsigned)n);
79 }
80
74 // set the label 81 // set the label
75 if (opts & OPT_L) 82 if (opts & OPT_L)
76 safe_strncpy((char *)sb->s_volume_name, label, sizeof(sb->s_volume_name)); 83 safe_strncpy((char *)sb->s_volume_name, label, sizeof(sb->s_volume_name));
diff --git a/editors/awk.c b/editors/awk.c
index 7685546e5..71abca215 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -25,6 +25,7 @@
25 * to perform debug printfs to stderr: */ 25 * to perform debug printfs to stderr: */
26#define debug_printf_walker(...) do {} while (0) 26#define debug_printf_walker(...) do {} while (0)
27#define debug_printf_eval(...) do {} while (0) 27#define debug_printf_eval(...) do {} while (0)
28#define debug_printf_parse(...) do {} while (0)
28 29
29#ifndef debug_printf_walker 30#ifndef debug_printf_walker
30# define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__)) 31# define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__))
@@ -32,6 +33,9 @@
32#ifndef debug_printf_eval 33#ifndef debug_printf_eval
33# define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__)) 34# define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__))
34#endif 35#endif
36#ifndef debug_printf_parse
37# define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__))
38#endif
35 39
36 40
37 41
@@ -238,6 +242,9 @@ typedef struct tsplitter_s {
238 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1, 242 * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1,
239 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string 243 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
240 */ 244 */
245#undef P
246#undef PRIMASK
247#undef PRIMASK2
241#define P(x) (x << 24) 248#define P(x) (x << 24)
242#define PRIMASK 0x7F000000 249#define PRIMASK 0x7F000000
243#define PRIMASK2 0x7E000000 250#define PRIMASK2 0x7E000000
@@ -432,13 +439,13 @@ struct globals {
432 smallint nextrec; 439 smallint nextrec;
433 smallint nextfile; 440 smallint nextfile;
434 smallint is_f0_split; 441 smallint is_f0_split;
442 smallint t_rollback;
435}; 443};
436struct globals2 { 444struct globals2 {
437 uint32_t t_info; /* often used */ 445 uint32_t t_info; /* often used */
438 uint32_t t_tclass; 446 uint32_t t_tclass;
439 char *t_string; 447 char *t_string;
440 int t_lineno; 448 int t_lineno;
441 int t_rollback;
442 449
443 var *intvar[NUM_INTERNAL_VARS]; /* often used */ 450 var *intvar[NUM_INTERNAL_VARS]; /* often used */
444 451
@@ -496,11 +503,11 @@ struct globals2 {
496#define nextrec (G1.nextrec ) 503#define nextrec (G1.nextrec )
497#define nextfile (G1.nextfile ) 504#define nextfile (G1.nextfile )
498#define is_f0_split (G1.is_f0_split ) 505#define is_f0_split (G1.is_f0_split )
506#define t_rollback (G1.t_rollback )
499#define t_info (G.t_info ) 507#define t_info (G.t_info )
500#define t_tclass (G.t_tclass ) 508#define t_tclass (G.t_tclass )
501#define t_string (G.t_string ) 509#define t_string (G.t_string )
502#define t_lineno (G.t_lineno ) 510#define t_lineno (G.t_lineno )
503#define t_rollback (G.t_rollback )
504#define intvar (G.intvar ) 511#define intvar (G.intvar )
505#define fsplitter (G.fsplitter ) 512#define fsplitter (G.fsplitter )
506#define rsplitter (G.rsplitter ) 513#define rsplitter (G.rsplitter )
@@ -1008,6 +1015,7 @@ static uint32_t next_token(uint32_t expected)
1008 1015
1009 if (*p == '\0') { 1016 if (*p == '\0') {
1010 tc = TC_EOF; 1017 tc = TC_EOF;
1018 debug_printf_parse("%s: token found: TC_EOF\n", __func__);
1011 1019
1012 } else if (*p == '\"') { 1020 } else if (*p == '\"') {
1013 /* it's a string */ 1021 /* it's a string */
@@ -1023,6 +1031,7 @@ static uint32_t next_token(uint32_t expected)
1023 p++; 1031 p++;
1024 *s = '\0'; 1032 *s = '\0';
1025 tc = TC_STRING; 1033 tc = TC_STRING;
1034 debug_printf_parse("%s: token found:'%s' TC_STRING\n", __func__, t_string);
1026 1035
1027 } else if ((expected & TC_REGEXP) && *p == '/') { 1036 } else if ((expected & TC_REGEXP) && *p == '/') {
1028 /* it's regexp */ 1037 /* it's regexp */
@@ -1045,6 +1054,7 @@ static uint32_t next_token(uint32_t expected)
1045 p++; 1054 p++;
1046 *s = '\0'; 1055 *s = '\0';
1047 tc = TC_REGEXP; 1056 tc = TC_REGEXP;
1057 debug_printf_parse("%s: token found:'%s' TC_REGEXP\n", __func__, t_string);
1048 1058
1049 } else if (*p == '.' || isdigit(*p)) { 1059 } else if (*p == '.' || isdigit(*p)) {
1050 /* it's a number */ 1060 /* it's a number */
@@ -1054,6 +1064,7 @@ static uint32_t next_token(uint32_t expected)
1054 if (*p == '.') 1064 if (*p == '.')
1055 syntax_error(EMSG_UNEXP_TOKEN); 1065 syntax_error(EMSG_UNEXP_TOKEN);
1056 tc = TC_NUMBER; 1066 tc = TC_NUMBER;
1067 debug_printf_parse("%s: token found:%f TC_NUMBER\n", __func__, t_double);
1057 1068
1058 } else { 1069 } else {
1059 /* search for something known */ 1070 /* search for something known */
@@ -1076,6 +1087,7 @@ static uint32_t next_token(uint32_t expected)
1076 ) { 1087 ) {
1077 /* then this is what we are looking for */ 1088 /* then this is what we are looking for */
1078 t_info = *ti; 1089 t_info = *ti;
1090 debug_printf_parse("%s: token found:'%.*s' t_info:%x\n", __func__, l, p, t_info);
1079 p += l; 1091 p += l;
1080 goto token_found; 1092 goto token_found;
1081 } 1093 }
@@ -1099,14 +1111,17 @@ static uint32_t next_token(uint32_t expected)
1099 p = skip_spaces(p); 1111 p = skip_spaces(p);
1100 if (*p == '(') { 1112 if (*p == '(') {
1101 tc = TC_FUNCTION; 1113 tc = TC_FUNCTION;
1114 debug_printf_parse("%s: token found:'%s' TC_FUNCTION\n", __func__, t_string);
1102 } else { 1115 } else {
1103 if (*p == '[') { 1116 if (*p == '[') {
1104 p++; 1117 p++;
1105 tc = TC_ARRAY; 1118 tc = TC_ARRAY;
1106 } 1119 debug_printf_parse("%s: token found:'%s' TC_ARRAY\n", __func__, t_string);
1120 } else
1121 debug_printf_parse("%s: token found:'%s' TC_VARIABLE\n", __func__, t_string);
1107 } 1122 }
1108 token_found: ;
1109 } 1123 }
1124 token_found:
1110 g_pos = p; 1125 g_pos = p;
1111 1126
1112 /* skipping newlines in some cases */ 1127 /* skipping newlines in some cases */
@@ -1178,6 +1193,8 @@ static node *parse_expr(uint32_t iexp)
1178 uint32_t tc, xtc; 1193 uint32_t tc, xtc;
1179 var *v; 1194 var *v;
1180 1195
1196 debug_printf_parse("%s(%x)\n", __func__, iexp);
1197
1181 sn.info = PRIMASK; 1198 sn.info = PRIMASK;
1182 sn.r.n = glptr = NULL; 1199 sn.r.n = glptr = NULL;
1183 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; 1200 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
@@ -1186,12 +1203,14 @@ static node *parse_expr(uint32_t iexp)
1186 1203
1187 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { 1204 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
1188 /* input redirection (<) attached to glptr node */ 1205 /* input redirection (<) attached to glptr node */
1206 debug_printf_parse("%s: input redir\n", __func__);
1189 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); 1207 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
1190 cn->a.n = glptr; 1208 cn->a.n = glptr;
1191 xtc = TC_OPERAND | TC_UOPPRE; 1209 xtc = TC_OPERAND | TC_UOPPRE;
1192 glptr = NULL; 1210 glptr = NULL;
1193 1211
1194 } else if (tc & (TC_BINOP | TC_UOPPOST)) { 1212 } else if (tc & (TC_BINOP | TC_UOPPOST)) {
1213 debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__);
1195 /* for binary and postfix-unary operators, jump back over 1214 /* for binary and postfix-unary operators, jump back over
1196 * previous operators with higher priority */ 1215 * previous operators with higher priority */
1197 vn = cn; 1216 vn = cn;
@@ -1221,6 +1240,7 @@ static node *parse_expr(uint32_t iexp)
1221 vn->a.n = cn; 1240 vn->a.n = cn;
1222 1241
1223 } else { 1242 } else {
1243 debug_printf_parse("%s: other\n", __func__);
1224 /* for operands and prefix-unary operators, attach them 1244 /* for operands and prefix-unary operators, attach them
1225 * to last node */ 1245 * to last node */
1226 vn = cn; 1246 vn = cn;
@@ -1228,12 +1248,14 @@ static node *parse_expr(uint32_t iexp)
1228 cn->a.n = vn; 1248 cn->a.n = vn;
1229 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; 1249 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
1230 if (tc & (TC_OPERAND | TC_REGEXP)) { 1250 if (tc & (TC_OPERAND | TC_REGEXP)) {
1251 debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__);
1231 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp; 1252 xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
1232 /* one should be very careful with switch on tclass - 1253 /* one should be very careful with switch on tclass -
1233 * only simple tclasses should be used! */ 1254 * only simple tclasses should be used! */
1234 switch (tc) { 1255 switch (tc) {
1235 case TC_VARIABLE: 1256 case TC_VARIABLE:
1236 case TC_ARRAY: 1257 case TC_ARRAY:
1258 debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__);
1237 cn->info = OC_VAR; 1259 cn->info = OC_VAR;
1238 v = hash_search(ahash, t_string); 1260 v = hash_search(ahash, t_string);
1239 if (v != NULL) { 1261 if (v != NULL) {
@@ -1250,6 +1272,7 @@ static node *parse_expr(uint32_t iexp)
1250 1272
1251 case TC_NUMBER: 1273 case TC_NUMBER:
1252 case TC_STRING: 1274 case TC_STRING:
1275 debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__);
1253 cn->info = OC_VAR; 1276 cn->info = OC_VAR;
1254 v = cn->l.v = xzalloc(sizeof(var)); 1277 v = cn->l.v = xzalloc(sizeof(var));
1255 if (tc & TC_NUMBER) 1278 if (tc & TC_NUMBER)
@@ -1259,32 +1282,41 @@ static node *parse_expr(uint32_t iexp)
1259 break; 1282 break;
1260 1283
1261 case TC_REGEXP: 1284 case TC_REGEXP:
1285 debug_printf_parse("%s: TC_REGEXP\n", __func__);
1262 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2)); 1286 mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
1263 break; 1287 break;
1264 1288
1265 case TC_FUNCTION: 1289 case TC_FUNCTION:
1290 debug_printf_parse("%s: TC_FUNCTION\n", __func__);
1266 cn->info = OC_FUNC; 1291 cn->info = OC_FUNC;
1267 cn->r.f = newfunc(t_string); 1292 cn->r.f = newfunc(t_string);
1268 cn->l.n = condition(); 1293 cn->l.n = condition();
1269 break; 1294 break;
1270 1295
1271 case TC_SEQSTART: 1296 case TC_SEQSTART:
1297 debug_printf_parse("%s: TC_SEQSTART\n", __func__);
1272 cn = vn->r.n = parse_expr(TC_SEQTERM); 1298 cn = vn->r.n = parse_expr(TC_SEQTERM);
1299 if (!cn)
1300 syntax_error("Empty sequence");
1273 cn->a.n = vn; 1301 cn->a.n = vn;
1274 break; 1302 break;
1275 1303
1276 case TC_GETLINE: 1304 case TC_GETLINE:
1305 debug_printf_parse("%s: TC_GETLINE\n", __func__);
1277 glptr = cn; 1306 glptr = cn;
1278 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; 1307 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
1279 break; 1308 break;
1280 1309
1281 case TC_BUILTIN: 1310 case TC_BUILTIN:
1311 debug_printf_parse("%s: TC_BUILTIN\n", __func__);
1282 cn->l.n = condition(); 1312 cn->l.n = condition();
1283 break; 1313 break;
1284 } 1314 }
1285 } 1315 }
1286 } 1316 }
1287 } 1317 }
1318
1319 debug_printf_parse("%s() returns %p\n", __func__, sn.r.n);
1288 return sn.r.n; 1320 return sn.r.n;
1289} 1321}
1290 1322
@@ -1353,18 +1385,25 @@ static void chain_group(void)
1353 } while (c & TC_NEWLINE); 1385 } while (c & TC_NEWLINE);
1354 1386
1355 if (c & TC_GRPSTART) { 1387 if (c & TC_GRPSTART) {
1388 debug_printf_parse("%s: TC_GRPSTART\n", __func__);
1356 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { 1389 while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
1390 debug_printf_parse("%s: !TC_GRPTERM\n", __func__);
1357 if (t_tclass & TC_NEWLINE) 1391 if (t_tclass & TC_NEWLINE)
1358 continue; 1392 continue;
1359 rollback_token(); 1393 rollback_token();
1360 chain_group(); 1394 chain_group();
1361 } 1395 }
1396 debug_printf_parse("%s: TC_GRPTERM\n", __func__);
1362 } else if (c & (TC_OPSEQ | TC_OPTERM)) { 1397 } else if (c & (TC_OPSEQ | TC_OPTERM)) {
1398 debug_printf_parse("%s: TC_OPSEQ | TC_OPTERM\n", __func__);
1363 rollback_token(); 1399 rollback_token();
1364 chain_expr(OC_EXEC | Vx); 1400 chain_expr(OC_EXEC | Vx);
1365 } else { /* TC_STATEMNT */ 1401 } else {
1402 /* TC_STATEMNT */
1403 debug_printf_parse("%s: TC_STATEMNT(?)\n", __func__);
1366 switch (t_info & OPCLSMASK) { 1404 switch (t_info & OPCLSMASK) {
1367 case ST_IF: 1405 case ST_IF:
1406 debug_printf_parse("%s: ST_IF\n", __func__);
1368 n = chain_node(OC_BR | Vx); 1407 n = chain_node(OC_BR | Vx);
1369 n->l.n = condition(); 1408 n->l.n = condition();
1370 chain_group(); 1409 chain_group();
@@ -1379,12 +1418,14 @@ static void chain_group(void)
1379 break; 1418 break;
1380 1419
1381 case ST_WHILE: 1420 case ST_WHILE:
1421 debug_printf_parse("%s: ST_WHILE\n", __func__);
1382 n2 = condition(); 1422 n2 = condition();
1383 n = chain_loop(NULL); 1423 n = chain_loop(NULL);
1384 n->l.n = n2; 1424 n->l.n = n2;
1385 break; 1425 break;
1386 1426
1387 case ST_DO: 1427 case ST_DO:
1428 debug_printf_parse("%s: ST_DO\n", __func__);
1388 n2 = chain_node(OC_EXEC); 1429 n2 = chain_node(OC_EXEC);
1389 n = chain_loop(NULL); 1430 n = chain_loop(NULL);
1390 n2->a.n = n->a.n; 1431 n2->a.n = n->a.n;
@@ -1393,6 +1434,7 @@ static void chain_group(void)
1393 break; 1434 break;
1394 1435
1395 case ST_FOR: 1436 case ST_FOR:
1437 debug_printf_parse("%s: ST_FOR\n", __func__);
1396 next_token(TC_SEQSTART); 1438 next_token(TC_SEQSTART);
1397 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); 1439 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
1398 if (t_tclass & TC_SEQTERM) { /* for-in */ 1440 if (t_tclass & TC_SEQTERM) { /* for-in */
@@ -1418,6 +1460,7 @@ static void chain_group(void)
1418 1460
1419 case OC_PRINT: 1461 case OC_PRINT:
1420 case OC_PRINTF: 1462 case OC_PRINTF:
1463 debug_printf_parse("%s: OC_PRINT[F]\n", __func__);
1421 n = chain_node(t_info); 1464 n = chain_node(t_info);
1422 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM); 1465 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
1423 if (t_tclass & TC_OUTRDR) { 1466 if (t_tclass & TC_OUTRDR) {
@@ -1429,17 +1472,20 @@ static void chain_group(void)
1429 break; 1472 break;
1430 1473
1431 case OC_BREAK: 1474 case OC_BREAK:
1475 debug_printf_parse("%s: OC_BREAK\n", __func__);
1432 n = chain_node(OC_EXEC); 1476 n = chain_node(OC_EXEC);
1433 n->a.n = break_ptr; 1477 n->a.n = break_ptr;
1434 break; 1478 break;
1435 1479
1436 case OC_CONTINUE: 1480 case OC_CONTINUE:
1481 debug_printf_parse("%s: OC_CONTINUE\n", __func__);
1437 n = chain_node(OC_EXEC); 1482 n = chain_node(OC_EXEC);
1438 n->a.n = continue_ptr; 1483 n->a.n = continue_ptr;
1439 break; 1484 break;
1440 1485
1441 /* delete, next, nextfile, return, exit */ 1486 /* delete, next, nextfile, return, exit */
1442 default: 1487 default:
1488 debug_printf_parse("%s: default\n", __func__);
1443 chain_expr(t_info); 1489 chain_expr(t_info);
1444 } 1490 }
1445 } 1491 }
@@ -1457,19 +1503,24 @@ static void parse_program(char *p)
1457 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | 1503 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
1458 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) { 1504 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
1459 1505
1460 if (tclass & TC_OPTERM) 1506 if (tclass & TC_OPTERM) {
1507 debug_printf_parse("%s: TC_OPTERM\n", __func__);
1461 continue; 1508 continue;
1509 }
1462 1510
1463 seq = &mainseq; 1511 seq = &mainseq;
1464 if (tclass & TC_BEGIN) { 1512 if (tclass & TC_BEGIN) {
1513 debug_printf_parse("%s: TC_BEGIN\n", __func__);
1465 seq = &beginseq; 1514 seq = &beginseq;
1466 chain_group(); 1515 chain_group();
1467 1516
1468 } else if (tclass & TC_END) { 1517 } else if (tclass & TC_END) {
1518 debug_printf_parse("%s: TC_END\n", __func__);
1469 seq = &endseq; 1519 seq = &endseq;
1470 chain_group(); 1520 chain_group();
1471 1521
1472 } else if (tclass & TC_FUNCDECL) { 1522 } else if (tclass & TC_FUNCDECL) {
1523 debug_printf_parse("%s: TC_FUNCDECL\n", __func__);
1473 next_token(TC_FUNCTION); 1524 next_token(TC_FUNCTION);
1474 g_pos++; 1525 g_pos++;
1475 f = newfunc(t_string); 1526 f = newfunc(t_string);
@@ -1487,22 +1538,27 @@ static void parse_program(char *p)
1487 clear_array(ahash); 1538 clear_array(ahash);
1488 1539
1489 } else if (tclass & TC_OPSEQ) { 1540 } else if (tclass & TC_OPSEQ) {
1541 debug_printf_parse("%s: TC_OPSEQ\n", __func__);
1490 rollback_token(); 1542 rollback_token();
1491 cn = chain_node(OC_TEST); 1543 cn = chain_node(OC_TEST);
1492 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); 1544 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
1493 if (t_tclass & TC_GRPSTART) { 1545 if (t_tclass & TC_GRPSTART) {
1546 debug_printf_parse("%s: TC_GRPSTART\n", __func__);
1494 rollback_token(); 1547 rollback_token();
1495 chain_group(); 1548 chain_group();
1496 } else { 1549 } else {
1550 debug_printf_parse("%s: !TC_GRPSTART\n", __func__);
1497 chain_node(OC_PRINT); 1551 chain_node(OC_PRINT);
1498 } 1552 }
1499 cn->r.n = mainseq.last; 1553 cn->r.n = mainseq.last;
1500 1554
1501 } else /* if (tclass & TC_GRPSTART) */ { 1555 } else /* if (tclass & TC_GRPSTART) */ {
1556 debug_printf_parse("%s: TC_GRPSTART(?)\n", __func__);
1502 rollback_token(); 1557 rollback_token();
1503 chain_group(); 1558 chain_group();
1504 } 1559 }
1505 } 1560 }
1561 debug_printf_parse("%s: TC_EOF\n", __func__);
1506} 1562}
1507 1563
1508 1564
@@ -2627,7 +2683,7 @@ static var *evaluate(node *op, var *res)
2627 rsm = iF; 2683 rsm = iF;
2628 } 2684 }
2629 2685
2630 if (!rsm->F) { 2686 if (!rsm || !rsm->F) {
2631 setvar_i(intvar[ERRNO], errno); 2687 setvar_i(intvar[ERRNO], errno);
2632 setvar_i(res, -1); 2688 setvar_i(res, -1);
2633 break; 2689 break;
@@ -2961,7 +3017,7 @@ static rstream *next_input_file(void)
2961#define rsm (G.next_input_file__rsm) 3017#define rsm (G.next_input_file__rsm)
2962#define files_happen (G.next_input_file__files_happen) 3018#define files_happen (G.next_input_file__files_happen)
2963 3019
2964 FILE *F = NULL; 3020 FILE *F;
2965 const char *fname, *ind; 3021 const char *fname, *ind;
2966 3022
2967 if (rsm.F) 3023 if (rsm.F)
@@ -2969,19 +3025,21 @@ static rstream *next_input_file(void)
2969 rsm.F = NULL; 3025 rsm.F = NULL;
2970 rsm.pos = rsm.adv = 0; 3026 rsm.pos = rsm.adv = 0;
2971 3027
2972 do { 3028 for (;;) {
2973 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) { 3029 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
2974 if (files_happen) 3030 if (files_happen)
2975 return NULL; 3031 return NULL;
2976 fname = "-"; 3032 fname = "-";
2977 F = stdin; 3033 F = stdin;
2978 } else { 3034 break;
2979 ind = getvar_s(incvar(intvar[ARGIND]));
2980 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
2981 if (fname && *fname && !is_assignment(fname))
2982 F = xfopen_stdin(fname);
2983 } 3035 }
2984 } while (!F); 3036 ind = getvar_s(incvar(intvar[ARGIND]));
3037 fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
3038 if (fname && *fname && !is_assignment(fname)) {
3039 F = xfopen_stdin(fname);
3040 break;
3041 }
3042 }
2985 3043
2986 files_happen = TRUE; 3044 files_happen = TRUE;
2987 setvar_s(intvar[FILENAME], fname); 3045 setvar_s(intvar[FILENAME], fname);
@@ -2995,7 +3053,7 @@ int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2995int awk_main(int argc, char **argv) 3053int awk_main(int argc, char **argv)
2996{ 3054{
2997 unsigned opt; 3055 unsigned opt;
2998 char *opt_F, *opt_W; 3056 char *opt_F;
2999 llist_t *list_v = NULL; 3057 llist_t *list_v = NULL;
3000 llist_t *list_f = NULL; 3058 llist_t *list_f = NULL;
3001 int i, j; 3059 int i, j;
@@ -3057,7 +3115,7 @@ int awk_main(int argc, char **argv)
3057 } 3115 }
3058 } 3116 }
3059 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */ 3117 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
3060 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W); 3118 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL);
3061 argv += optind; 3119 argv += optind;
3062 argc -= optind; 3120 argc -= optind;
3063 if (opt & 0x1) 3121 if (opt & 0x1)
@@ -3091,7 +3149,7 @@ int awk_main(int argc, char **argv)
3091 parse_program(*argv++); 3149 parse_program(*argv++);
3092 } 3150 }
3093 if (opt & 0x8) // -W 3151 if (opt & 0x8) // -W
3094 bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W); 3152 bb_error_msg("warning: option -W is ignored");
3095 3153
3096 /* fill in ARGV array */ 3154 /* fill in ARGV array */
3097 setvar_i(intvar[ARGC], argc); 3155 setvar_i(intvar[ARGC], argc);
diff --git a/editors/patch.c b/editors/patch.c
index ec5b8e7ad..13785ef46 100644
--- a/editors/patch.c
+++ b/editors/patch.c
@@ -70,8 +70,7 @@ struct double_list {
70 70
71// Free all the elements of a linked list 71// Free all the elements of a linked list
72// Call freeit() on each element before freeing it. 72// Call freeit() on each element before freeing it.
73static 73static void dlist_free(struct double_list *list, void (*freeit)(void *data))
74void dlist_free(struct double_list *list, void (*freeit)(void *data))
75{ 74{
76 while (list) { 75 while (list) {
77 void *pop = list; 76 void *pop = list;
@@ -83,8 +82,7 @@ void dlist_free(struct double_list *list, void (*freeit)(void *data))
83} 82}
84 83
85// Add an entry before "list" element in (circular) doubly linked list 84// Add an entry before "list" element in (circular) doubly linked list
86static 85static struct double_list *dlist_add(struct double_list **list, char *data)
87struct double_list *dlist_add(struct double_list **list, char *data)
88{ 86{
89 struct double_list *llist; 87 struct double_list *llist;
90 struct double_list *line = xmalloc(sizeof(*line)); 88 struct double_list *line = xmalloc(sizeof(*line));
@@ -232,7 +230,7 @@ static int apply_one_hunk(void)
232 else matcheof = 0; 230 else matcheof = 0;
233 if (PATCH_DEBUG) fdprintf(2, "HUNK:%s\n", plist->data); 231 if (PATCH_DEBUG) fdprintf(2, "HUNK:%s\n", plist->data);
234 } 232 }
235 matcheof = matcheof < TT.context; 233 matcheof = !matcheof || matcheof < TT.context;
236 234
237 if (PATCH_DEBUG) fdprintf(2,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); 235 if (PATCH_DEBUG) fdprintf(2,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N');
238 236
@@ -476,19 +474,21 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
476 474
477 // We're deleting oldname if new file is /dev/null (before -p) 475 // We're deleting oldname if new file is /dev/null (before -p)
478 // or if new hunk is empty (zero context) after patching 476 // or if new hunk is empty (zero context) after patching
479 if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) 477 if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) {
480 {
481 name = reverse ? newname : oldname; 478 name = reverse ? newname : oldname;
482 empty++; 479 empty++;
483 } 480 }
484 481
485 // handle -p path truncation. 482 // handle -p path truncation.
486 for (i=0, s = name; *s;) { 483 for (i = 0, s = name; *s;) {
487 if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) break; 484 if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i)
488 if (*(s++)=='/') { 485 break;
489 name = s; 486 if (*s++ != '/')
490 i++; 487 continue;
491 } 488 while (*s == '/')
489 s++;
490 i++;
491 name = s;
492 } 492 }
493 493
494 if (empty) { 494 if (empty) {
diff --git a/editors/sed.c b/editors/sed.c
index 5c4e9cc3b..c8bb503ea 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -26,7 +26,7 @@
26 * add_input_file() adds a FILE* to the list of input files. We need to 26 * add_input_file() adds a FILE* to the list of input files. We need to
27 * know all input sources ahead of time to find the last line for the $ match. 27 * know all input sources ahead of time to find the last line for the $ match.
28 * 28 *
29 * process_files() does actual sedding, reading data lines from each input FILE * 29 * process_files() does actual sedding, reading data lines from each input FILE*
30 * (which could be stdin) and applying the sed command list (sed_cmd_head) to 30 * (which could be stdin) and applying the sed command list (sed_cmd_head) to
31 * each of the resulting lines. 31 * each of the resulting lines.
32 * 32 *
@@ -57,7 +57,8 @@
57 */ 57 */
58 58
59//usage:#define sed_trivial_usage 59//usage:#define sed_trivial_usage
60//usage: "[-efinr] SED_CMD [FILE]..." 60//usage: "[-inr] [-f FILE]... [-e CMD]... [FILE]...\n"
61//usage: "or: sed [-inr] CMD [FILE]..."
61//usage:#define sed_full_usage "\n\n" 62//usage:#define sed_full_usage "\n\n"
62//usage: " -e CMD Add CMD to sed commands to be executed" 63//usage: " -e CMD Add CMD to sed commands to be executed"
63//usage: "\n -f FILE Add FILE contents to sed commands to be executed" 64//usage: "\n -f FILE Add FILE contents to sed commands to be executed"
@@ -75,6 +76,13 @@
75#include "libbb.h" 76#include "libbb.h"
76#include "xregex.h" 77#include "xregex.h"
77 78
79#if 0
80# define dbg(...) bb_error_msg(__VA_ARGS__)
81#else
82# define dbg(...) ((void)0)
83#endif
84
85
78enum { 86enum {
79 OPT_in_place = 1 << 0, 87 OPT_in_place = 1 << 0,
80}; 88};
@@ -89,6 +97,7 @@ typedef struct sed_cmd_s {
89 regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */ 97 regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */
90 regex_t *sub_match; /* For 's/sub_match/string/' */ 98 regex_t *sub_match; /* For 's/sub_match/string/' */
91 int beg_line; /* 'sed 1p' 0 == apply commands to all lines */ 99 int beg_line; /* 'sed 1p' 0 == apply commands to all lines */
100 int beg_line_orig; /* copy of the above, needed for -i */
92 int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */ 101 int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */
93 102
94 FILE *sw_file; /* File (sw) command writes to, -1 for none. */ 103 FILE *sw_file; /* File (sw) command writes to, -1 for none. */
@@ -123,7 +132,7 @@ struct globals {
123 regex_t *previous_regex_ptr; 132 regex_t *previous_regex_ptr;
124 133
125 /* linked list of sed commands */ 134 /* linked list of sed commands */
126 sed_cmd_t sed_cmd_head, *sed_cmd_tail; 135 sed_cmd_t *sed_cmd_head, **sed_cmd_tail;
127 136
128 /* Linked list of append lines */ 137 /* Linked list of append lines */
129 llist_t *append_head; 138 llist_t *append_head;
@@ -148,7 +157,7 @@ struct BUG_G_too_big {
148#if ENABLE_FEATURE_CLEAN_UP 157#if ENABLE_FEATURE_CLEAN_UP
149static void sed_free_and_close_stuff(void) 158static void sed_free_and_close_stuff(void)
150{ 159{
151 sed_cmd_t *sed_cmd = G.sed_cmd_head.next; 160 sed_cmd_t *sed_cmd = G.sed_cmd_head;
152 161
153 llist_free(G.append_head, free); 162 llist_free(G.append_head, free);
154 163
@@ -599,6 +608,7 @@ static void add_cmd(const char *cmdstr)
599 608
600 /* first part (if present) is an address: either a '$', a number or a /regex/ */ 609 /* first part (if present) is an address: either a '$', a number or a /regex/ */
601 cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); 610 cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
611 sed_cmd->beg_line_orig = sed_cmd->beg_line;
602 612
603 /* second part (if present) will begin with a comma */ 613 /* second part (if present) will begin with a comma */
604 if (*cmdstr == ',') { 614 if (*cmdstr == ',') {
@@ -630,8 +640,8 @@ static void add_cmd(const char *cmdstr)
630 cmdstr = parse_cmd_args(sed_cmd, cmdstr); 640 cmdstr = parse_cmd_args(sed_cmd, cmdstr);
631 641
632 /* Add the command to the command array */ 642 /* Add the command to the command array */
633 G.sed_cmd_tail->next = sed_cmd; 643 *G.sed_cmd_tail = sed_cmd;
634 G.sed_cmd_tail = G.sed_cmd_tail->next; 644 G.sed_cmd_tail = &sed_cmd->next;
635 } 645 }
636 646
637 /* If we glued multiple lines together, free the memory. */ 647 /* If we glued multiple lines together, free the memory. */
@@ -777,7 +787,7 @@ static sed_cmd_t *branch_to(char *label)
777{ 787{
778 sed_cmd_t *sed_cmd; 788 sed_cmd_t *sed_cmd;
779 789
780 for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { 790 for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
781 if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) { 791 if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) {
782 return sed_cmd; 792 return sed_cmd;
783 } 793 }
@@ -953,24 +963,24 @@ static void process_files(void)
953 963
954 /* For every line, go through all the commands */ 964 /* For every line, go through all the commands */
955 restart: 965 restart:
956 for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { 966 for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
957 int old_matched, matched; 967 int old_matched, matched;
958 968
959 old_matched = sed_cmd->in_match; 969 old_matched = sed_cmd->in_match;
960 970
961 /* Determine if this command matches this line: */ 971 /* Determine if this command matches this line: */
962 972
963 //bb_error_msg("match1:%d", sed_cmd->in_match); 973 dbg("match1:%d", sed_cmd->in_match);
964 //bb_error_msg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line 974 dbg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line
965 // && !sed_cmd->beg_match && !sed_cmd->end_match)); 975 && !sed_cmd->beg_match && !sed_cmd->end_match));
966 //bb_error_msg("match3:%d", (sed_cmd->beg_line > 0 976 dbg("match3:%d", (sed_cmd->beg_line > 0
967 // && (sed_cmd->end_line || sed_cmd->end_match 977 && (sed_cmd->end_line || sed_cmd->end_match
968 // ? (sed_cmd->beg_line <= linenum) 978 ? (sed_cmd->beg_line <= linenum)
969 // : (sed_cmd->beg_line == linenum) 979 : (sed_cmd->beg_line == linenum)
970 // ) 980 )
971 // ) 981 ));
972 //bb_error_msg("match4:%d", (beg_match(sed_cmd, pattern_space))); 982 dbg("match4:%d", (beg_match(sed_cmd, pattern_space)));
973 //bb_error_msg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL)); 983 dbg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL));
974 984
975 /* Are we continuing a previous multi-line match? */ 985 /* Are we continuing a previous multi-line match? */
976 sed_cmd->in_match = sed_cmd->in_match 986 sed_cmd->in_match = sed_cmd->in_match
@@ -981,7 +991,14 @@ static void process_files(void)
981 || (sed_cmd->beg_line > 0 991 || (sed_cmd->beg_line > 0
982 && (sed_cmd->end_line || sed_cmd->end_match 992 && (sed_cmd->end_line || sed_cmd->end_match
983 /* note: even if end is numeric and is < linenum too, 993 /* note: even if end is numeric and is < linenum too,
984 * GNU sed matches! We match too */ 994 * GNU sed matches! We match too, therefore we don't
995 * check here that linenum <= end.
996 * Example:
997 * printf '1\n2\n3\n4\n' | sed -n '1{N;N;d};1p;2,3p;3p;4p'
998 * first three input lines are deleted;
999 * 4th line is matched and printed
1000 * by "2,3" (!) and by "4" ranges
1001 */
985 ? (sed_cmd->beg_line <= linenum) /* N,end */ 1002 ? (sed_cmd->beg_line <= linenum) /* N,end */
986 : (sed_cmd->beg_line == linenum) /* N */ 1003 : (sed_cmd->beg_line == linenum) /* N */
987 ) 1004 )
@@ -994,16 +1011,14 @@ static void process_files(void)
994 /* Snapshot the value */ 1011 /* Snapshot the value */
995 matched = sed_cmd->in_match; 1012 matched = sed_cmd->in_match;
996 1013
997 //bb_error_msg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d", 1014 dbg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d",
998 //sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum); 1015 sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum);
999 1016
1000 /* Is this line the end of the current match? */ 1017 /* Is this line the end of the current match? */
1001 1018
1002 if (matched) { 1019 if (matched) {
1003 /* once matched, "n,xxx" range is dead, disabling it */ 1020 /* once matched, "n,xxx" range is dead, disabling it */
1004 if (sed_cmd->beg_line > 0 1021 if (sed_cmd->beg_line > 0) {
1005 && !(option_mask32 & OPT_in_place) /* but not for -i */
1006 ) {
1007 sed_cmd->beg_line = -2; 1022 sed_cmd->beg_line = -2;
1008 } 1023 }
1009 sed_cmd->in_match = !( 1024 sed_cmd->in_match = !(
@@ -1017,7 +1032,8 @@ static void process_files(void)
1017 /* or does this line matches our last address regex */ 1032 /* or does this line matches our last address regex */
1018 || (sed_cmd->end_match && old_matched 1033 || (sed_cmd->end_match && old_matched
1019 && (regexec(sed_cmd->end_match, 1034 && (regexec(sed_cmd->end_match,
1020 pattern_space, 0, NULL, 0) == 0)) 1035 pattern_space, 0, NULL, 0) == 0)
1036 )
1021 ); 1037 );
1022 } 1038 }
1023 1039
@@ -1407,11 +1423,12 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1407 add_input_file(stdin); 1423 add_input_file(stdin);
1408 } else { 1424 } else {
1409 int i; 1425 int i;
1410 FILE *file;
1411 1426
1412 for (i = 0; argv[i]; i++) { 1427 for (i = 0; argv[i]; i++) {
1413 struct stat statbuf; 1428 struct stat statbuf;
1414 int nonstdoutfd; 1429 int nonstdoutfd;
1430 FILE *file;
1431 sed_cmd_t *sed_cmd;
1415 1432
1416 if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) { 1433 if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) {
1417 add_input_file(stdin); 1434 add_input_file(stdin);
@@ -1423,11 +1440,13 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1423 status = EXIT_FAILURE; 1440 status = EXIT_FAILURE;
1424 continue; 1441 continue;
1425 } 1442 }
1443 add_input_file(file);
1426 if (!(opt & OPT_in_place)) { 1444 if (!(opt & OPT_in_place)) {
1427 add_input_file(file);
1428 continue; 1445 continue;
1429 } 1446 }
1430 1447
1448 /* -i: process each FILE separately: */
1449
1431 G.outname = xasprintf("%sXXXXXX", argv[i]); 1450 G.outname = xasprintf("%sXXXXXX", argv[i]);
1432 nonstdoutfd = xmkstemp(G.outname); 1451 nonstdoutfd = xmkstemp(G.outname);
1433 G.nonstdout = xfdopen_for_write(nonstdoutfd); 1452 G.nonstdout = xfdopen_for_write(nonstdoutfd);
@@ -1438,15 +1457,20 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1438 * but GNU sed 4.2.1 does not preserve them either */ 1457 * but GNU sed 4.2.1 does not preserve them either */
1439 fchmod(nonstdoutfd, statbuf.st_mode); 1458 fchmod(nonstdoutfd, statbuf.st_mode);
1440 fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); 1459 fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid);
1441 add_input_file(file); 1460
1442 process_files(); 1461 process_files();
1443 fclose(G.nonstdout); 1462 fclose(G.nonstdout);
1444
1445 G.nonstdout = stdout; 1463 G.nonstdout = stdout;
1464
1446 /* unlink(argv[i]); */ 1465 /* unlink(argv[i]); */
1447 xrename(G.outname, argv[i]); 1466 xrename(G.outname, argv[i]);
1448 free(G.outname); 1467 free(G.outname);
1449 G.outname = NULL; 1468 G.outname = NULL;
1469
1470 /* Re-enable disabled range matches */
1471 for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
1472 sed_cmd->beg_line = sed_cmd->beg_line_orig;
1473 }
1450 } 1474 }
1451 /* Here, to handle "sed 'cmds' nonexistent_file" case we did: 1475 /* Here, to handle "sed 'cmds' nonexistent_file" case we did:
1452 * if (G.current_input_file >= G.input_file_count) 1476 * if (G.current_input_file >= G.input_file_count)
diff --git a/editors/vi.c b/editors/vi.c
index 9708679b4..d6d926e35 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -3072,7 +3072,6 @@ static void refresh(int full_screen)
3072//----- Execute a Vi Command ----------------------------------- 3072//----- Execute a Vi Command -----------------------------------
3073static void do_cmd(int c) 3073static void do_cmd(int c)
3074{ 3074{
3075 const char *msg = msg; // for compiler
3076 char *p, *q, *save_dot; 3075 char *p, *q, *save_dot;
3077 char buf[12]; 3076 char buf[12];
3078 int dir; 3077 int dir;
@@ -3081,8 +3080,8 @@ static void do_cmd(int c)
3081 3080
3082// c1 = c; // quiet the compiler 3081// c1 = c; // quiet the compiler
3083// cnt = yf = 0; // quiet the compiler 3082// cnt = yf = 0; // quiet the compiler
3084// msg = p = q = save_dot = buf; // quiet the compiler 3083// p = q = save_dot = buf; // quiet the compiler
3085 memset(buf, '\0', 12); 3084 memset(buf, '\0', sizeof(buf));
3086 3085
3087 show_status_line(); 3086 show_status_line();
3088 3087
@@ -3198,19 +3197,18 @@ static void do_cmd(int c)
3198 case KEYCODE_LEFT: // cursor key Left 3197 case KEYCODE_LEFT: // cursor key Left
3199 case 8: // ctrl-H- move left (This may be ERASE char) 3198 case 8: // ctrl-H- move left (This may be ERASE char)
3200 case 0x7f: // DEL- move left (This may be ERASE char) 3199 case 0x7f: // DEL- move left (This may be ERASE char)
3201 if (--cmdcnt > 0) { 3200 do {
3202 do_cmd(c); 3201 dot_left();
3203 } 3202 } while (--cmdcnt > 0);
3204 dot_left();
3205 break; 3203 break;
3206 case 10: // Newline ^J 3204 case 10: // Newline ^J
3207 case 'j': // j- goto next line, same col 3205 case 'j': // j- goto next line, same col
3208 case KEYCODE_DOWN: // cursor key Down 3206 case KEYCODE_DOWN: // cursor key Down
3209 if (--cmdcnt > 0) { 3207 do {
3210 do_cmd(c); 3208 dot_next(); // go to next B-o-l
3211 } 3209 // try stay in same col
3212 dot_next(); // go to next B-o-l 3210 dot = move_to_col(dot, ccol + offset);
3213 dot = move_to_col(dot, ccol + offset); // try stay in same col 3211 } while (--cmdcnt > 0);
3214 break; 3212 break;
3215 case 12: // ctrl-L force redraw whole screen 3213 case 12: // ctrl-L force redraw whole screen
3216 case 18: // ctrl-R force redraw 3214 case 18: // ctrl-R force redraw
@@ -3223,11 +3221,10 @@ static void do_cmd(int c)
3223 break; 3221 break;
3224 case 13: // Carriage Return ^M 3222 case 13: // Carriage Return ^M
3225 case '+': // +- goto next line 3223 case '+': // +- goto next line
3226 if (--cmdcnt > 0) { 3224 do {
3227 do_cmd(c); 3225 dot_next();
3228 } 3226 dot_skip_over_ws();
3229 dot_next(); 3227 } while (--cmdcnt > 0);
3230 dot_skip_over_ws();
3231 break; 3228 break;
3232 case 21: // ctrl-U scroll up half screen 3229 case 21: // ctrl-U scroll up half screen
3233 dot_scroll((rows - 2) / 2, -1); 3230 dot_scroll((rows - 2) / 2, -1);
@@ -3245,10 +3242,9 @@ static void do_cmd(int c)
3245 case ' ': // move right 3242 case ' ': // move right
3246 case 'l': // move right 3243 case 'l': // move right
3247 case KEYCODE_RIGHT: // Cursor Key Right 3244 case KEYCODE_RIGHT: // Cursor Key Right
3248 if (--cmdcnt > 0) { 3245 do {
3249 do_cmd(c); 3246 dot_right();
3250 } 3247 } while (--cmdcnt > 0);
3251 dot_right();
3252 break; 3248 break;
3253#if ENABLE_FEATURE_VI_YANKMARK 3249#if ENABLE_FEATURE_VI_YANKMARK
3254 case '"': // "- name a register to use for Delete/Yank 3250 case '"': // "- name a register to use for Delete/Yank
@@ -3330,11 +3326,12 @@ static void do_cmd(int c)
3330#endif /* FEATURE_VI_YANKMARK */ 3326#endif /* FEATURE_VI_YANKMARK */
3331 case '$': // $- goto end of line 3327 case '$': // $- goto end of line
3332 case KEYCODE_END: // Cursor Key End 3328 case KEYCODE_END: // Cursor Key End
3333 if (--cmdcnt > 0) { 3329 for (;;) {
3330 dot = end_line(dot);
3331 if (--cmdcnt > 0)
3332 break;
3334 dot_next(); 3333 dot_next();
3335 do_cmd(c);
3336 } 3334 }
3337 dot = end_line(dot);
3338 break; 3335 break;
3339 case '%': // %- find matching char of pair () [] {} 3336 case '%': // %- find matching char of pair () [] {}
3340 for (q = dot; q < end && *q != '\n'; q++) { 3337 for (q = dot; q < end && *q != '\n'; q++) {
@@ -3359,38 +3356,35 @@ static void do_cmd(int c)
3359 // 3356 //
3360 //**** fall through to ... ';' 3357 //**** fall through to ... ';'
3361 case ';': // ;- look at rest of line for last forward char 3358 case ';': // ;- look at rest of line for last forward char
3362 if (--cmdcnt > 0) { 3359 do {
3363 do_cmd(';'); 3360 if (last_forward_char == 0)
3364 } 3361 break;
3365 if (last_forward_char == 0) 3362 q = dot + 1;
3366 break; 3363 while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
3367 q = dot + 1; 3364 q++;
3368 while (q < end - 1 && *q != '\n' && *q != last_forward_char) { 3365 }
3369 q++; 3366 if (*q == last_forward_char)
3370 } 3367 dot = q;
3371 if (*q == last_forward_char) 3368 } while (--cmdcnt > 0);
3372 dot = q;
3373 break; 3369 break;
3374 case ',': // repeat latest 'f' in opposite direction 3370 case ',': // repeat latest 'f' in opposite direction
3375 if (--cmdcnt > 0) {
3376 do_cmd(',');
3377 }
3378 if (last_forward_char == 0) 3371 if (last_forward_char == 0)
3379 break; 3372 break;
3380 q = dot - 1; 3373 do {
3381 while (q >= text && *q != '\n' && *q != last_forward_char) { 3374 q = dot - 1;
3382 q--; 3375 while (q >= text && *q != '\n' && *q != last_forward_char) {
3383 } 3376 q--;
3384 if (q >= text && *q == last_forward_char) 3377 }
3385 dot = q; 3378 if (q >= text && *q == last_forward_char)
3379 dot = q;
3380 } while (--cmdcnt > 0);
3386 break; 3381 break;
3387 3382
3388 case '-': // -- goto prev line 3383 case '-': // -- goto prev line
3389 if (--cmdcnt > 0) { 3384 do {
3390 do_cmd(c); 3385 dot_prev();
3391 } 3386 dot_skip_over_ws();
3392 dot_prev(); 3387 } while (--cmdcnt > 0);
3393 dot_skip_over_ws();
3394 break; 3388 break;
3395#if ENABLE_FEATURE_VI_DOT_CMD 3389#if ENABLE_FEATURE_VI_DOT_CMD
3396 case '.': // .- repeat the last modifying command 3390 case '.': // .- repeat the last modifying command
@@ -3422,9 +3416,6 @@ static void do_cmd(int c)
3422 // user changed mind and erased the "/"- do nothing 3416 // user changed mind and erased the "/"- do nothing
3423 break; 3417 break;
3424 case 'N': // N- backward search for last pattern 3418 case 'N': // N- backward search for last pattern
3425 if (--cmdcnt > 0) {
3426 do_cmd(c);
3427 }
3428 dir = BACK; // assume BACKWARD search 3419 dir = BACK; // assume BACKWARD search
3429 p = dot - 1; 3420 p = dot - 1;
3430 if (last_search_pattern[0] == '?') { 3421 if (last_search_pattern[0] == '?') {
@@ -3436,41 +3427,41 @@ static void do_cmd(int c)
3436 case 'n': // n- repeat search for last pattern 3427 case 'n': // n- repeat search for last pattern
3437 // search rest of text[] starting at next char 3428 // search rest of text[] starting at next char
3438 // if search fails return orignal "p" not the "p+1" address 3429 // if search fails return orignal "p" not the "p+1" address
3439 if (--cmdcnt > 0) { 3430 do {
3440 do_cmd(c); 3431 const char *msg;
3441 }
3442 dc3: 3432 dc3:
3443 dir = FORWARD; // assume FORWARD search 3433 dir = FORWARD; // assume FORWARD search
3444 p = dot + 1; 3434 p = dot + 1;
3445 if (last_search_pattern[0] == '?') { 3435 if (last_search_pattern[0] == '?') {
3446 dir = BACK; 3436 dir = BACK;
3447 p = dot - 1; 3437 p = dot - 1;
3448 } 3438 }
3449 dc4: 3439 dc4:
3450 q = char_search(p, last_search_pattern + 1, dir, FULL); 3440 q = char_search(p, last_search_pattern + 1, dir, FULL);
3451 if (q != NULL) { 3441 if (q != NULL) {
3452 dot = q; // good search, update "dot" 3442 dot = q; // good search, update "dot"
3453 msg = ""; 3443 msg = NULL;
3454 goto dc2; 3444 goto dc2;
3455 } 3445 }
3456 // no pattern found between "dot" and "end"- continue at top 3446 // no pattern found between "dot" and "end"- continue at top
3457 p = text; 3447 p = text;
3458 if (dir == BACK) {
3459 p = end - 1;
3460 }
3461 q = char_search(p, last_search_pattern + 1, dir, FULL);
3462 if (q != NULL) { // found something
3463 dot = q; // found new pattern- goto it
3464 msg = "search hit BOTTOM, continuing at TOP";
3465 if (dir == BACK) { 3448 if (dir == BACK) {
3466 msg = "search hit TOP, continuing at BOTTOM"; 3449 p = end - 1;
3450 }
3451 q = char_search(p, last_search_pattern + 1, dir, FULL);
3452 if (q != NULL) { // found something
3453 dot = q; // found new pattern- goto it
3454 msg = "search hit BOTTOM, continuing at TOP";
3455 if (dir == BACK) {
3456 msg = "search hit TOP, continuing at BOTTOM";
3457 }
3458 } else {
3459 msg = "Pattern not found";
3467 } 3460 }
3468 } else {
3469 msg = "Pattern not found";
3470 }
3471 dc2: 3461 dc2:
3472 if (*msg) 3462 if (msg)
3473 status_line_bold("%s", msg); 3463 status_line_bold("%s", msg);
3464 } while (--cmdcnt > 0);
3474 break; 3465 break;
3475 case '{': // {- move backward paragraph 3466 case '{': // {- move backward paragraph
3476 q = char_search(dot, "\n\n", BACK, FULL); 3467 q = char_search(dot, "\n\n", BACK, FULL);
@@ -3589,18 +3580,17 @@ static void do_cmd(int c)
3589 case 'B': // B- back a blank-delimited Word 3580 case 'B': // B- back a blank-delimited Word
3590 case 'E': // E- end of a blank-delimited word 3581 case 'E': // E- end of a blank-delimited word
3591 case 'W': // W- forward a blank-delimited word 3582 case 'W': // W- forward a blank-delimited word
3592 if (--cmdcnt > 0) {
3593 do_cmd(c);
3594 }
3595 dir = FORWARD; 3583 dir = FORWARD;
3596 if (c == 'B') 3584 if (c == 'B')
3597 dir = BACK; 3585 dir = BACK;
3598 if (c == 'W' || isspace(dot[dir])) { 3586 do {
3599 dot = skip_thing(dot, 1, dir, S_TO_WS); 3587 if (c == 'W' || isspace(dot[dir])) {
3600 dot = skip_thing(dot, 2, dir, S_OVER_WS); 3588 dot = skip_thing(dot, 1, dir, S_TO_WS);
3601 } 3589 dot = skip_thing(dot, 2, dir, S_OVER_WS);
3602 if (c != 'W') 3590 }
3603 dot = skip_thing(dot, 1, dir, S_BEFORE_WS); 3591 if (c != 'W')
3592 dot = skip_thing(dot, 1, dir, S_BEFORE_WS);
3593 } while (--cmdcnt > 0);
3604 break; 3594 break;
3605 case 'C': // C- Change to e-o-l 3595 case 'C': // C- Change to e-o-l
3606 case 'D': // D- delete to e-o-l 3596 case 'D': // D- delete to e-o-l
@@ -3651,20 +3641,19 @@ static void do_cmd(int c)
3651 case 'i': // i- insert before current char 3641 case 'i': // i- insert before current char
3652 case KEYCODE_INSERT: // Cursor Key Insert 3642 case KEYCODE_INSERT: // Cursor Key Insert
3653 dc_i: 3643 dc_i:
3654 cmd_mode = 1; // start insrting 3644 cmd_mode = 1; // start inserting
3655 break; 3645 break;
3656 case 'J': // J- join current and next lines together 3646 case 'J': // J- join current and next lines together
3657 if (--cmdcnt > 1) { 3647 do {
3658 do_cmd(c); 3648 dot_end(); // move to NL
3659 } 3649 if (dot < end - 1) { // make sure not last char in text[]
3660 dot_end(); // move to NL 3650 *dot++ = ' '; // replace NL with space
3661 if (dot < end - 1) { // make sure not last char in text[] 3651 file_modified++;
3662 *dot++ = ' '; // replace NL with space 3652 while (isblank(*dot)) { // delete leading WS
3663 file_modified++; 3653 dot_delete();
3664 while (isblank(*dot)) { // delete leading WS 3654 }
3665 dot_delete();
3666 } 3655 }
3667 } 3656 } while (--cmdcnt > 0);
3668 end_cmd_q(); // stop adding to q 3657 end_cmd_q(); // stop adding to q
3669 break; 3658 break;
3670 case 'L': // L- goto bottom line on screen 3659 case 'L': // L- goto bottom line on screen
@@ -3708,20 +3697,19 @@ static void do_cmd(int c)
3708 case 'X': // X- delete char before dot 3697 case 'X': // X- delete char before dot
3709 case 'x': // x- delete the current char 3698 case 'x': // x- delete the current char
3710 case 's': // s- substitute the current char 3699 case 's': // s- substitute the current char
3711 if (--cmdcnt > 0) {
3712 do_cmd(c);
3713 }
3714 dir = 0; 3700 dir = 0;
3715 if (c == 'X') 3701 if (c == 'X')
3716 dir = -1; 3702 dir = -1;
3717 if (dot[dir] != '\n') { 3703 do {
3718 if (c == 'X') 3704 if (dot[dir] != '\n') {
3719 dot--; // delete prev char 3705 if (c == 'X')
3720 dot = yank_delete(dot, dot, 0, YANKDEL); // delete char 3706 dot--; // delete prev char
3721 } 3707 dot = yank_delete(dot, dot, 0, YANKDEL); // delete char
3722 if (c == 's') 3708 }
3723 goto dc_i; // start insrting 3709 } while (--cmdcnt > 0);
3724 end_cmd_q(); // stop adding to q 3710 end_cmd_q(); // stop adding to q
3711 if (c == 's')
3712 goto dc_i; // start inserting
3725 break; 3713 break;
3726 case 'Z': // Z- if modified, {write}; exit 3714 case 'Z': // Z- if modified, {write}; exit
3727 // ZZ means to save file (if necessary), then exit 3715 // ZZ means to save file (if necessary), then exit
@@ -3752,23 +3740,22 @@ static void do_cmd(int c)
3752 break; 3740 break;
3753 case 'b': // b- back a word 3741 case 'b': // b- back a word
3754 case 'e': // e- end of word 3742 case 'e': // e- end of word
3755 if (--cmdcnt > 0) {
3756 do_cmd(c);
3757 }
3758 dir = FORWARD; 3743 dir = FORWARD;
3759 if (c == 'b') 3744 if (c == 'b')
3760 dir = BACK; 3745 dir = BACK;
3761 if ((dot + dir) < text || (dot + dir) > end - 1) 3746 do {
3762 break; 3747 if ((dot + dir) < text || (dot + dir) > end - 1)
3763 dot += dir; 3748 break;
3764 if (isspace(*dot)) { 3749 dot += dir;
3765 dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); 3750 if (isspace(*dot)) {
3766 } 3751 dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS);
3767 if (isalnum(*dot) || *dot == '_') { 3752 }
3768 dot = skip_thing(dot, 1, dir, S_END_ALNUM); 3753 if (isalnum(*dot) || *dot == '_') {
3769 } else if (ispunct(*dot)) { 3754 dot = skip_thing(dot, 1, dir, S_END_ALNUM);
3770 dot = skip_thing(dot, 1, dir, S_END_PUNCT); 3755 } else if (ispunct(*dot)) {
3771 } 3756 dot = skip_thing(dot, 1, dir, S_END_PUNCT);
3757 }
3758 } while (--cmdcnt > 0);
3772 break; 3759 break;
3773 case 'c': // c- change something 3760 case 'c': // c- change something
3774 case 'd': // d- delete something 3761 case 'd': // d- delete something
@@ -3853,11 +3840,10 @@ static void do_cmd(int c)
3853 } 3840 }
3854 case 'k': // k- goto prev line, same col 3841 case 'k': // k- goto prev line, same col
3855 case KEYCODE_UP: // cursor key Up 3842 case KEYCODE_UP: // cursor key Up
3856 if (--cmdcnt > 0) { 3843 do {
3857 do_cmd(c); 3844 dot_prev();
3858 } 3845 dot = move_to_col(dot, ccol + offset); // try stay in same col
3859 dot_prev(); 3846 } while (--cmdcnt > 0);
3860 dot = move_to_col(dot, ccol + offset); // try stay in same col
3861 break; 3847 break;
3862 case 'r': // r- replace the current char with user input 3848 case 'r': // r- replace the current char with user input
3863 c1 = get_one_char(); // get the replacement char 3849 c1 = get_one_char(); // get the replacement char
@@ -3875,19 +3861,18 @@ static void do_cmd(int c)
3875 last_forward_char = 0; 3861 last_forward_char = 0;
3876 break; 3862 break;
3877 case 'w': // w- forward a word 3863 case 'w': // w- forward a word
3878 if (--cmdcnt > 0) { 3864 do {
3879 do_cmd(c); 3865 if (isalnum(*dot) || *dot == '_') { // we are on ALNUM
3880 } 3866 dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM);
3881 if (isalnum(*dot) || *dot == '_') { // we are on ALNUM 3867 } else if (ispunct(*dot)) { // we are on PUNCT
3882 dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); 3868 dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT);
3883 } else if (ispunct(*dot)) { // we are on PUNCT 3869 }
3884 dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); 3870 if (dot < end - 1)
3885 } 3871 dot++; // move over word
3886 if (dot < end - 1) 3872 if (isspace(*dot)) {
3887 dot++; // move over word 3873 dot = skip_thing(dot, 2, FORWARD, S_OVER_WS);
3888 if (isspace(*dot)) { 3874 }
3889 dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); 3875 } while (--cmdcnt > 0);
3890 }
3891 break; 3876 break;
3892 case 'z': // z- 3877 case 'z': // z-
3893 c1 = get_one_char(); // get the replacement char 3878 c1 = get_one_char(); // get the replacement char
@@ -3903,17 +3888,16 @@ static void do_cmd(int c)
3903 dot = move_to_col(dot, cmdcnt - 1); // try to move to column 3888 dot = move_to_col(dot, cmdcnt - 1); // try to move to column
3904 break; 3889 break;
3905 case '~': // ~- flip the case of letters a-z -> A-Z 3890 case '~': // ~- flip the case of letters a-z -> A-Z
3906 if (--cmdcnt > 0) { 3891 do {
3907 do_cmd(c); 3892 if (islower(*dot)) {
3908 } 3893 *dot = toupper(*dot);
3909 if (islower(*dot)) { 3894 file_modified++;
3910 *dot = toupper(*dot); 3895 } else if (isupper(*dot)) {
3911 file_modified++; 3896 *dot = tolower(*dot);
3912 } else if (isupper(*dot)) { 3897 file_modified++;
3913 *dot = tolower(*dot); 3898 }
3914 file_modified++; 3899 dot_right();
3915 } 3900 } while (--cmdcnt > 0);
3916 dot_right();
3917 end_cmd_q(); // stop adding to q 3901 end_cmd_q(); // stop adding to q
3918 break; 3902 break;
3919 //----- The Cursor and Function Keys ----------------------------- 3903 //----- The Cursor and Function Keys -----------------------------
diff --git a/examples/android-build b/examples/android-build
index f5fe49bda..89f3b637a 100755
--- a/examples/android-build
+++ b/examples/android-build
@@ -2,9 +2,10 @@
2# Build Busybox against Android's bionic 2# Build Busybox against Android's bionic
3# Originally by Dan Fandrich 3# Originally by Dan Fandrich
4# 4#
5# Configure with android_defconfig 5# Configure with "make android_defconfig"
6#
6# This file has been tested on Android Froyo (the lack of ttyname_r in 7# This file has been tested on Android Froyo (the lack of ttyname_r in
7# the must be patched around) and Gingerbread. 8# the android libc must be patched around) and Gingerbread.
8 9
9# Point this to the Android root directory; it's used in the defconfig CFLAGS 10# Point this to the Android root directory; it's used in the defconfig CFLAGS
10export A="$HOME/android" 11export A="$HOME/android"
diff --git a/examples/depmod.pl b/examples/depmod.pl
index f324b121a..809dc08b3 100755
--- a/examples/depmod.pl
+++ b/examples/depmod.pl
@@ -199,7 +199,7 @@ if ($stdout == 0) {
199 open(STDOUT, ">$basedir/modules.dep") 199 open(STDOUT, ">$basedir/modules.dep")
200 or die "cannot open $basedir/modules.dep: $!"; 200 or die "cannot open $basedir/modules.dep: $!";
201} 201}
202my $kseries = $basedir =~ m,/2\.6\.[^/]*, ? '2.6' : '2.4'; 202my $kseries = $basedir =~ m,/2\.4\.[^/]*, ? '2.4' : 'others';
203 203
204foreach my $module ( keys %$mod ) { 204foreach my $module ( keys %$mod ) {
205 if($kseries eq '2.4') { 205 if($kseries eq '2.4') {
diff --git a/findutils/find.c b/findutils/find.c
index 05f88d2f0..fc0fc5c9f 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -932,7 +932,10 @@ static action*** parse_params(char **argv)
932 * expression is reached. 932 * expression is reached.
933 */ 933 */
934 /* Options */ 934 /* Options */
935 if (0) { } 935 if (parm == OPT_FOLLOW) {
936 dbg("follow enabled: %d", __LINE__);
937 G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
938 }
936#if ENABLE_FEATURE_FIND_XDEV 939#if ENABLE_FEATURE_FIND_XDEV
937 else if (parm == OPT_XDEV) { 940 else if (parm == OPT_XDEV) {
938 dbg("%d", __LINE__); 941 dbg("%d", __LINE__);
diff --git a/findutils/grep.c b/findutils/grep.c
index fa3b8a3a9..f3463f94e 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -570,20 +570,20 @@ static char *add_grep_list_data(char *pattern)
570 570
571static void load_regexes_from_file(llist_t *fopt) 571static void load_regexes_from_file(llist_t *fopt)
572{ 572{
573 char *line;
574 FILE *f;
575
576 while (fopt) { 573 while (fopt) {
574 char *line;
575 FILE *fp;
577 llist_t *cur = fopt; 576 llist_t *cur = fopt;
578 char *ffile = cur->data; 577 char *ffile = cur->data;
579 578
580 fopt = cur->link; 579 fopt = cur->link;
581 free(cur); 580 free(cur);
582 f = xfopen_stdin(ffile); 581 fp = xfopen_stdin(ffile);
583 while ((line = xmalloc_fgetline(f)) != NULL) { 582 while ((line = xmalloc_fgetline(fp)) != NULL) {
584 llist_add_to(&pattern_head, 583 llist_add_to(&pattern_head,
585 new_grep_list_data(line, ALLOCATED)); 584 new_grep_list_data(line, ALLOCATED));
586 } 585 }
586 fclose_if_not_stdin(fp);
587 } 587 }
588} 588}
589 589
@@ -667,15 +667,19 @@ int grep_main(int argc UNUSED_PARAM, char **argv)
667#endif 667#endif
668 invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */ 668 invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */
669 669
670 if (pattern_head != NULL) { 670 { /* convert char **argv to grep_list_data_t */
671 /* convert char **argv to grep_list_data_t */
672 llist_t *cur; 671 llist_t *cur;
673
674 for (cur = pattern_head; cur; cur = cur->link) 672 for (cur = pattern_head; cur; cur = cur->link)
675 cur->data = new_grep_list_data(cur->data, 0); 673 cur->data = new_grep_list_data(cur->data, 0);
676 } 674 }
677 if (option_mask32 & OPT_f) 675 if (option_mask32 & OPT_f) {
678 load_regexes_from_file(fopt); 676 load_regexes_from_file(fopt);
677 if (!pattern_head) { /* -f EMPTY_FILE? */
678 /* GNU grep treats it as "nothing matches" */
679 llist_add_to(&pattern_head, new_grep_list_data((char*) "", 0));
680 invert_search ^= 1;
681 }
682 }
679 683
680 if (ENABLE_FEATURE_GREP_FGREP_ALIAS && applet_name[0] == 'f') 684 if (ENABLE_FEATURE_GREP_FGREP_ALIAS && applet_name[0] == 'f')
681 option_mask32 |= OPT_F; 685 option_mask32 |= OPT_F;
diff --git a/include/applets.src.h b/include/applets.src.h
index 87d9cbb7b..252a060fb 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -176,7 +176,6 @@ IF_HD(APPLET_NOEXEC(hd, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hd))
176IF_HDPARM(APPLET(hdparm, BB_DIR_SBIN, BB_SUID_DROP)) 176IF_HDPARM(APPLET(hdparm, BB_DIR_SBIN, BB_SUID_DROP))
177IF_HEAD(APPLET_NOEXEC(head, head, BB_DIR_USR_BIN, BB_SUID_DROP, head)) 177IF_HEAD(APPLET_NOEXEC(head, head, BB_DIR_USR_BIN, BB_SUID_DROP, head))
178IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hexdump)) 178IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hexdump))
179IF_HOSTID(APPLET_NOFORK(hostid, hostid, BB_DIR_USR_BIN, BB_SUID_DROP, hostid))
180IF_HOSTNAME(APPLET(hostname, BB_DIR_BIN, BB_SUID_DROP)) 179IF_HOSTNAME(APPLET(hostname, BB_DIR_BIN, BB_SUID_DROP))
181IF_HTTPD(APPLET(httpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) 180IF_HTTPD(APPLET(httpd, BB_DIR_USR_SBIN, BB_SUID_DROP))
182IF_HWCLOCK(APPLET(hwclock, BB_DIR_SBIN, BB_SUID_DROP)) 181IF_HWCLOCK(APPLET(hwclock, BB_DIR_SBIN, BB_SUID_DROP))
@@ -240,7 +239,6 @@ IF_MAKEMIME(APPLET(makemime, BB_DIR_BIN, BB_SUID_DROP))
240IF_MAN(APPLET(man, BB_DIR_SBIN, BB_SUID_DROP)) 239IF_MAN(APPLET(man, BB_DIR_SBIN, BB_SUID_DROP))
241IF_MATCHPATHCON(APPLET(matchpathcon, BB_DIR_USR_SBIN, BB_SUID_DROP)) 240IF_MATCHPATHCON(APPLET(matchpathcon, BB_DIR_USR_SBIN, BB_SUID_DROP))
242IF_MD5SUM(APPLET_NOEXEC(md5sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, md5sum)) 241IF_MD5SUM(APPLET_NOEXEC(md5sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, md5sum))
243IF_MDEV(APPLET(mdev, BB_DIR_SBIN, BB_SUID_DROP))
244IF_MICROCOM(APPLET(microcom, BB_DIR_USR_BIN, BB_SUID_DROP)) 242IF_MICROCOM(APPLET(microcom, BB_DIR_USR_BIN, BB_SUID_DROP))
245IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, BB_DIR_BIN, BB_SUID_DROP, mkdir)) 243IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, BB_DIR_BIN, BB_SUID_DROP, mkdir))
246IF_MKFS_VFAT(APPLET_ODDNAME(mkdosfs, mkfs_vfat, BB_DIR_SBIN, BB_SUID_DROP, mkfs_vfat)) 244IF_MKFS_VFAT(APPLET_ODDNAME(mkdosfs, mkfs_vfat, BB_DIR_SBIN, BB_SUID_DROP, mkfs_vfat))
diff --git a/include/archive.h b/include/bb_archive.h
index 9e176d335..9e176d335 100644
--- a/include/archive.h
+++ b/include/bb_archive.h
diff --git a/include/libbb.h b/include/libbb.h
index 6e63e65f5..a6ecac932 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -32,6 +32,11 @@
32#include <stdarg.h> 32#include <stdarg.h>
33#include <stddef.h> 33#include <stddef.h>
34#include <string.h> 34#include <string.h>
35/* There are two incompatible basename's, let not use them! */
36/* See the dirname/basename man page for details */
37#include <libgen.h> /* dirname,basename */
38#undef basename
39#define basename dont_use_basename
35#include <sys/poll.h> 40#include <sys/poll.h>
36#include <sys/ioctl.h> 41#include <sys/ioctl.h>
37#include <sys/mman.h> 42#include <sys/mman.h>
@@ -142,12 +147,6 @@ int vdprintf(int d, const char *format, va_list ap);
142#endif 147#endif
143/* klogctl is in libc's klog.h, but we cheat and not #include that */ 148/* klogctl is in libc's klog.h, but we cheat and not #include that */
144int klogctl(int type, char *b, int len); 149int klogctl(int type, char *b, int len);
145/* This is declared here rather than #including <libgen.h> in order to avoid
146 * confusing the two versions of basename. See the dirname/basename man page
147 * for details. */
148#if !defined __FreeBSD__
149char *dirname(char *path);
150#endif
151#ifndef PATH_MAX 150#ifndef PATH_MAX
152# define PATH_MAX 256 151# define PATH_MAX 256
153#endif 152#endif
@@ -268,13 +267,6 @@ typedef unsigned long uoff_t;
268#undef SKIP 267#undef SKIP
269#define SKIP ((int) 2) 268#define SKIP ((int) 2)
270 269
271/* for mtab.c */
272#define MTAB_GETMOUNTPT '1'
273#define MTAB_GETDEVICE '2'
274
275#define BUF_SIZE 8192
276#define EXPAND_ALLOC 1024
277
278/* Macros for min/max. */ 270/* Macros for min/max. */
279#ifndef MIN 271#ifndef MIN
280#define MIN(a,b) (((a)<(b))?(a):(b)) 272#define MIN(a,b) (((a)<(b))?(a):(b))
@@ -653,6 +645,7 @@ ssize_t recv_from_to(int fd, void *buf, size_t len, int flags,
653 struct sockaddr *to, 645 struct sockaddr *to,
654 socklen_t sa_size) FAST_FUNC; 646 socklen_t sa_size) FAST_FUNC;
655 647
648uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC;
656 649
657char *xstrdup(const char *s) FAST_FUNC RETURNS_MALLOC; 650char *xstrdup(const char *s) FAST_FUNC RETURNS_MALLOC;
658char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC; 651char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC;
@@ -697,10 +690,13 @@ void *malloc_or_warn(size_t size) FAST_FUNC RETURNS_MALLOC;
697void *xmalloc(size_t size) FAST_FUNC RETURNS_MALLOC; 690void *xmalloc(size_t size) FAST_FUNC RETURNS_MALLOC;
698void *xzalloc(size_t size) FAST_FUNC RETURNS_MALLOC; 691void *xzalloc(size_t size) FAST_FUNC RETURNS_MALLOC;
699void *xrealloc(void *old, size_t size) FAST_FUNC; 692void *xrealloc(void *old, size_t size) FAST_FUNC;
700/* After xrealloc_vector(v, 4, idx) it's ok to use 693/* After v = xrealloc_vector(v, SHIFT, idx) it's ok to use
701 * at least v[idx] and v[idx+1], for all idx values. 694 * at least v[idx] and v[idx+1], for all idx values.
702 * shift specifies how many new elements are added (1: 2, 2: 4... 8: 256...) 695 * SHIFT specifies how many new elements are added (1:2, 2:4, ..., 8:256...)
703 * when all elements are used up. New elements are zeroed out. */ 696 * when all elements are used up. New elements are zeroed out.
697 * xrealloc_vector(v, SHIFT, idx) *MUST* be called with consecutive IDXs -
698 * skipping an index is a bad bug - it may miss a realloc!
699 */
704#define xrealloc_vector(vector, shift, idx) \ 700#define xrealloc_vector(vector, shift, idx) \
705 xrealloc_vector_helper((vector), (sizeof((vector)[0]) << 8) + (shift), (idx)) 701 xrealloc_vector_helper((vector), (sizeof((vector)[0]) << 8) + (shift), (idx))
706void* xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx) FAST_FUNC; 702void* xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx) FAST_FUNC;
@@ -827,9 +823,9 @@ void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_F
827const char *make_human_readable_str(unsigned long long size, 823const char *make_human_readable_str(unsigned long long size,
828 unsigned long block_size, unsigned long display_unit) FAST_FUNC; 824 unsigned long block_size, unsigned long display_unit) FAST_FUNC;
829/* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */ 825/* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */
830char *bin2hex(char *buf, const char *cp, int count) FAST_FUNC; 826char *bin2hex(char *dst, const char *src, int count) FAST_FUNC;
831/* Reverse */ 827/* Reverse */
832char* hex2bin(char *dst, const char *str, int count) FAST_FUNC; 828char* hex2bin(char *dst, const char *src, int count) FAST_FUNC;
833 829
834/* Generate a UUID */ 830/* Generate a UUID */
835void generate_uuid(uint8_t *buf) FAST_FUNC; 831void generate_uuid(uint8_t *buf) FAST_FUNC;
@@ -1180,7 +1176,7 @@ extern int del_loop(const char *device) FAST_FUNC;
1180/* If *devname is not NULL, use that name, otherwise try to find free one, 1176/* If *devname is not NULL, use that name, otherwise try to find free one,
1181 * malloc and return it in *devname. 1177 * malloc and return it in *devname.
1182 * return value: 1: read-only loopdev was setup, 0: rw, < 0: error */ 1178 * return value: 1: read-only loopdev was setup, 0: rw, < 0: error */
1183extern int set_loop(char **devname, const char *file, unsigned long long offset) FAST_FUNC; 1179extern int set_loop(char **devname, const char *file, unsigned long long offset, int ro) FAST_FUNC;
1184 1180
1185/* Like bb_ask below, but asks on stdin with no timeout. */ 1181/* Like bb_ask below, but asks on stdin with no timeout. */
1186char *bb_ask_stdin(const char * prompt) FAST_FUNC; 1182char *bb_ask_stdin(const char * prompt) FAST_FUNC;
@@ -1378,25 +1374,37 @@ enum {
1378 KEYCODE_DELETE = -9, 1374 KEYCODE_DELETE = -9,
1379 KEYCODE_PAGEUP = -10, 1375 KEYCODE_PAGEUP = -10,
1380 KEYCODE_PAGEDOWN = -11, 1376 KEYCODE_PAGEDOWN = -11,
1381 1377 // -12 is reserved for Alt/Ctrl/Shift-TAB
1382 KEYCODE_CTRL_UP = KEYCODE_UP & ~0x40, 1378#if 0
1383 KEYCODE_CTRL_DOWN = KEYCODE_DOWN & ~0x40, 1379 KEYCODE_FUN1 = -13,
1380 KEYCODE_FUN2 = -14,
1381 KEYCODE_FUN3 = -15,
1382 KEYCODE_FUN4 = -16,
1383 KEYCODE_FUN5 = -17,
1384 KEYCODE_FUN6 = -18,
1385 KEYCODE_FUN7 = -19,
1386 KEYCODE_FUN8 = -20,
1387 KEYCODE_FUN9 = -21,
1388 KEYCODE_FUN10 = -22,
1389 KEYCODE_FUN11 = -23,
1390 KEYCODE_FUN12 = -24,
1391#endif
1392 /* Be sure that last defined value is small enough
1393 * to not interfere with Alt/Ctrl/Shift bits.
1394 * So far we do not exceed -31 (0xfff..fffe1),
1395 * which gives us three upper bits in LSB to play with.
1396 */
1397 //KEYCODE_SHIFT_TAB = (-12) & ~0x80,
1398 //KEYCODE_SHIFT_... = KEYCODE_... & ~0x80,
1399 //KEYCODE_CTRL_UP = KEYCODE_UP & ~0x40,
1400 //KEYCODE_CTRL_DOWN = KEYCODE_DOWN & ~0x40,
1384 KEYCODE_CTRL_RIGHT = KEYCODE_RIGHT & ~0x40, 1401 KEYCODE_CTRL_RIGHT = KEYCODE_RIGHT & ~0x40,
1385 KEYCODE_CTRL_LEFT = KEYCODE_LEFT & ~0x40, 1402 KEYCODE_CTRL_LEFT = KEYCODE_LEFT & ~0x40,
1386#if 0 1403 //KEYCODE_ALT_UP = KEYCODE_UP & ~0x20,
1387 KEYCODE_FUN1 = -12, 1404 //KEYCODE_ALT_DOWN = KEYCODE_DOWN & ~0x20,
1388 KEYCODE_FUN2 = -13, 1405 KEYCODE_ALT_RIGHT = KEYCODE_RIGHT & ~0x20,
1389 KEYCODE_FUN3 = -14, 1406 KEYCODE_ALT_LEFT = KEYCODE_LEFT & ~0x20,
1390 KEYCODE_FUN4 = -15, 1407
1391 KEYCODE_FUN5 = -16,
1392 KEYCODE_FUN6 = -17,
1393 KEYCODE_FUN7 = -18,
1394 KEYCODE_FUN8 = -19,
1395 KEYCODE_FUN9 = -20,
1396 KEYCODE_FUN10 = -21,
1397 KEYCODE_FUN11 = -22,
1398 KEYCODE_FUN12 = -23,
1399#endif
1400 KEYCODE_CURSOR_POS = -0x100, /* 0xfff..fff00 */ 1408 KEYCODE_CURSOR_POS = -0x100, /* 0xfff..fff00 */
1401 /* How long is the longest ESC sequence we know? 1409 /* How long is the longest ESC sequence we know?
1402 * We want it big enough to be able to contain 1410 * We want it big enough to be able to contain
@@ -1437,6 +1445,12 @@ typedef struct line_input_t {
1437 int cur_history; 1445 int cur_history;
1438 int max_history; /* must never be <= 0 */ 1446 int max_history; /* must never be <= 0 */
1439# if ENABLE_FEATURE_EDITING_SAVEHISTORY 1447# if ENABLE_FEATURE_EDITING_SAVEHISTORY
1448 /* meaning of this field depends on FEATURE_EDITING_SAVE_ON_EXIT:
1449 * if !FEATURE_EDITING_SAVE_ON_EXIT: "how many lines are
1450 * in on-disk history"
1451 * if FEATURE_EDITING_SAVE_ON_EXIT: "how many in-memory lines are
1452 * also in on-disk history (and thus need to be skipped on save)"
1453 */
1440 unsigned cnt_history_in_file; 1454 unsigned cnt_history_in_file;
1441 const char *hist_file; 1455 const char *hist_file;
1442# endif 1456# endif
@@ -1444,13 +1458,12 @@ typedef struct line_input_t {
1444# endif 1458# endif
1445} line_input_t; 1459} line_input_t;
1446enum { 1460enum {
1447 DO_HISTORY = 1 * (MAX_HISTORY > 0), 1461 DO_HISTORY = 1 * (MAX_HISTORY > 0),
1448 SAVE_HISTORY = 2 * (MAX_HISTORY > 0) * ENABLE_FEATURE_EDITING_SAVEHISTORY, 1462 TAB_COMPLETION = 2 * ENABLE_FEATURE_TAB_COMPLETION,
1449 TAB_COMPLETION = 4 * ENABLE_FEATURE_TAB_COMPLETION, 1463 USERNAME_COMPLETION = 4 * ENABLE_FEATURE_USERNAME_COMPLETION,
1450 USERNAME_COMPLETION = 8 * ENABLE_FEATURE_USERNAME_COMPLETION, 1464 VI_MODE = 8 * ENABLE_FEATURE_EDITING_VI,
1451 VI_MODE = 0x10 * ENABLE_FEATURE_EDITING_VI, 1465 WITH_PATH_LOOKUP = 0x10,
1452 WITH_PATH_LOOKUP = 0x20, 1466 FOR_SHELL = DO_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION,
1453 FOR_SHELL = DO_HISTORY | SAVE_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION,
1454}; 1467};
1455line_input_t *new_line_input_t(int flags) FAST_FUNC; 1468line_input_t *new_line_input_t(int flags) FAST_FUNC;
1456/* So far static: void free_line_input_t(line_input_t *n) FAST_FUNC; */ 1469/* So far static: void free_line_input_t(line_input_t *n) FAST_FUNC; */
@@ -1462,6 +1475,9 @@ line_input_t *new_line_input_t(int flags) FAST_FUNC;
1462 * >0 length of input string, including terminating '\n' 1475 * >0 length of input string, including terminating '\n'
1463 */ 1476 */
1464int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC; 1477int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC;
1478# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
1479void save_history(line_input_t *st);
1480# endif
1465#else 1481#else
1466#define MAX_HISTORY 0 1482#define MAX_HISTORY 0
1467int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; 1483int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC;
@@ -1589,6 +1605,15 @@ int starts_with_cpu(const char *str) FAST_FUNC;
1589unsigned get_cpu_count(void) FAST_FUNC; 1605unsigned get_cpu_count(void) FAST_FUNC;
1590 1606
1591 1607
1608/* Use strict=1 if you process input from untrusted source:
1609 * it will return NULL on invalid %xx (bad hex chars)
1610 * and str + 1 if decoded char is / or NUL.
1611 * In non-strict mode, it always succeeds (returns str),
1612 * and also it additionally decoded '+' to space.
1613 */
1614char *percent_decode_in_place(char *str, int strict) FAST_FUNC;
1615
1616
1592extern const char bb_uuenc_tbl_base64[]; 1617extern const char bb_uuenc_tbl_base64[];
1593extern const char bb_uuenc_tbl_std[]; 1618extern const char bb_uuenc_tbl_std[];
1594void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC; 1619void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC;
@@ -1597,7 +1622,8 @@ enum {
1597 /* Sign-extends to a value which never matches fgetc result: */ 1622 /* Sign-extends to a value which never matches fgetc result: */
1598 BASE64_FLAG_NO_STOP_CHAR = 0x80, 1623 BASE64_FLAG_NO_STOP_CHAR = 0x80,
1599}; 1624};
1600void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags); 1625const char *decode_base64(char **pp_dst, const char *src) FAST_FUNC;
1626void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC;
1601 1627
1602typedef struct md5_ctx_t { 1628typedef struct md5_ctx_t {
1603 uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */ 1629 uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */
diff --git a/include/platform.h b/include/platform.h
index e22c42007..96c603c1f 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -383,7 +383,7 @@ typedef unsigned smalluint;
383#if defined(__UCLIBC_MAJOR__) 383#if defined(__UCLIBC_MAJOR__)
384# if __UCLIBC_MAJOR__ == 0 \ 384# if __UCLIBC_MAJOR__ == 0 \
385 && ( __UCLIBC_MINOR__ < 9 \ 385 && ( __UCLIBC_MINOR__ < 9 \
386 || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 31) \ 386 || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 32) \
387 ) 387 )
388# undef HAVE_STRVERSCMP 388# undef HAVE_STRVERSCMP
389# endif 389# endif
@@ -451,6 +451,8 @@ typedef unsigned smalluint;
451# undef HAVE_STRVERSCMP 451# undef HAVE_STRVERSCMP
452# undef HAVE_XTABS 452# undef HAVE_XTABS
453# undef HAVE_DPRINTF 453# undef HAVE_DPRINTF
454# undef HAVE_UNLOCKED_STDIO
455# undef HAVE_UNLOCKED_LINE_OPS
454#endif 456#endif
455 457
456#if defined(__FreeBSD__) 458#if defined(__FreeBSD__)
@@ -465,7 +467,7 @@ typedef unsigned smalluint;
465# undef HAVE_STPCPY 467# undef HAVE_STPCPY
466#endif 468#endif
467 469
468#if defined(ANDROID) 470#if defined(ANDROID) || defined(__ANDROID__)
469# undef HAVE_DPRINTF 471# undef HAVE_DPRINTF
470# undef HAVE_GETLINE 472# undef HAVE_GETLINE
471# undef HAVE_STPCPY 473# undef HAVE_STPCPY
diff --git a/libbb/Config.src b/libbb/Config.src
index aa442365a..ee1b66a45 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -14,9 +14,9 @@ config PASSWORD_MINLEN
14 help 14 help
15 Minimum allowable password length. 15 Minimum allowable password length.
16 16
17config MD5_SIZE_VS_SPEED 17config MD5_SMALL
18 int "MD5: Trade bytes for speed (0:fast, 3:slow)" 18 int "MD5: Trade bytes for speed (0:fast, 3:slow)"
19 default 2 19 default 1
20 range 0 3 20 range 0 3
21 help 21 help
22 Trade binary size versus speed for the md5sum algorithm. 22 Trade binary size versus speed for the md5sum algorithm.
@@ -94,6 +94,13 @@ config FEATURE_EDITING_SAVEHISTORY
94 help 94 help
95 Enable history saving in shells. 95 Enable history saving in shells.
96 96
97config FEATURE_EDITING_SAVE_ON_EXIT
98 bool "Save history on shell exit, not after every command"
99 default n
100 depends on FEATURE_EDITING_SAVEHISTORY
101 help
102 Save history on shell exit, not after every command.
103
97config FEATURE_REVERSE_SEARCH 104config FEATURE_REVERSE_SEARCH
98 bool "Reverse history search" 105 bool "Reverse history search"
99 default y 106 default y
@@ -184,8 +191,8 @@ config FEATURE_SKIP_ROOTFS
184 191
185 However, some systems do not mount anything on /. 192 However, some systems do not mount anything on /.
186 If you need to configure busybox for one of these systems, 193 If you need to configure busybox for one of these systems,
187 you may find useful to turn this option off to make df show 194 you may find it useful to turn this option off to make df show
188 initramfs statistic. 195 initramfs statistics.
189 196
190 Otherwise, choose Y. 197 Otherwise, choose Y.
191 198
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index b5e9afc78..4cb063f89 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -168,6 +168,12 @@ lib-$(CONFIG_IOSTAT) += get_cpu_count.o
168lib-$(CONFIG_MPSTAT) += get_cpu_count.o 168lib-$(CONFIG_MPSTAT) += get_cpu_count.o
169lib-$(CONFIG_POWERTOP) += get_cpu_count.o 169lib-$(CONFIG_POWERTOP) += get_cpu_count.o
170 170
171lib-$(CONFIG_PING) += inet_cksum.o
172lib-$(CONFIG_TRACEROUTE) += inet_cksum.o
173lib-$(CONFIG_TRACEROUTE6) += inet_cksum.o
174lib-$(CONFIG_UDHCPC) += inet_cksum.o
175lib-$(CONFIG_UDHCPD) += inet_cksum.o
176
171# We shouldn't build xregcomp.c if we don't need it - this ensures we don't 177# We shouldn't build xregcomp.c if we don't need it - this ensures we don't
172# require regex.h to be in the include dir even if we don't need it thereby 178# require regex.h to be in the include dir even if we don't need it thereby
173# allowing us to build busybox even if uclibc regex support is disabled. 179# allowing us to build busybox even if uclibc regex support is disabled.
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 6d002b0dd..0c675db4d 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -62,7 +62,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
62#if ENABLE_FEATURE_COMPRESS_USAGE 62#if ENABLE_FEATURE_COMPRESS_USAGE
63 63
64static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; 64static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
65# include "archive.h" 65# include "bb_archive.h"
66static const char *unpack_usage_messages(void) 66static const char *unpack_usage_messages(void)
67{ 67{
68 char *outbuf = NULL; 68 char *outbuf = NULL;
diff --git a/libbb/bb_askpass.c b/libbb/bb_askpass.c
index 9a4188f52..fe2b50677 100644
--- a/libbb/bb_askpass.c
+++ b/libbb/bb_askpass.c
@@ -30,14 +30,23 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt)
30 struct sigaction sa, oldsa; 30 struct sigaction sa, oldsa;
31 struct termios tio, oldtio; 31 struct termios tio, oldtio;
32 32
33 tcgetattr(fd, &oldtio); 33 fputs(prompt, stdout);
34 fflush_all();
34 tcflush(fd, TCIFLUSH); 35 tcflush(fd, TCIFLUSH);
36
37 tcgetattr(fd, &oldtio);
35 tio = oldtio; 38 tio = oldtio;
36#ifndef IUCLC 39#if 0
37# define IUCLC 0 40 /* Switch off UPPERCASE->lowercase conversion (never used since 198x)
38#endif 41 * and XON/XOFF (why we want to mess with this??)
42 */
43# ifndef IUCLC
44# define IUCLC 0
45# endif
39 tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); 46 tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
40 tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP); 47#endif
48 /* Switch off echo */
49 tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL);
41 tcsetattr(fd, TCSANOW, &tio); 50 tcsetattr(fd, TCSANOW, &tio);
42 51
43 memset(&sa, 0, sizeof(sa)); 52 memset(&sa, 0, sizeof(sa));
@@ -50,9 +59,6 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt)
50 alarm(timeout); 59 alarm(timeout);
51 } 60 }
52 61
53 fputs(prompt, stdout);
54 fflush_all();
55
56 if (!passwd) 62 if (!passwd)
57 passwd = xmalloc(sizeof_passwd); 63 passwd = xmalloc(sizeof_passwd);
58 ret = passwd; 64 ret = passwd;
diff --git a/libbb/getpty.c b/libbb/getpty.c
index 6a15cff2f..435e4d09f 100644
--- a/libbb/getpty.c
+++ b/libbb/getpty.c
@@ -19,20 +19,22 @@ int FAST_FUNC xgetpty(char *line)
19 if (p > 0) { 19 if (p > 0) {
20 grantpt(p); /* chmod+chown corresponding slave pty */ 20 grantpt(p); /* chmod+chown corresponding slave pty */
21 unlockpt(p); /* (what does this do?) */ 21 unlockpt(p); /* (what does this do?) */
22#ifndef HAVE_PTSNAME_R 22# ifndef HAVE_PTSNAME_R
23 const char *name; 23 {
24 name = ptsname(p); /* find out the name of slave pty */ 24 const char *name;
25 if (!name) { 25 name = ptsname(p); /* find out the name of slave pty */
26 bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)"); 26 if (!name) {
27 bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)");
28 }
29 safe_strncpy(line, name, GETPTY_BUFSIZE);
27 } 30 }
28 safe_strncpy(line, name, GETPTY_BUFSIZE); 31# else
29#else
30 /* find out the name of slave pty */ 32 /* find out the name of slave pty */
31 if (ptsname_r(p, line, GETPTY_BUFSIZE-1) != 0) { 33 if (ptsname_r(p, line, GETPTY_BUFSIZE-1) != 0) {
32 bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)"); 34 bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)");
33 } 35 }
34 line[GETPTY_BUFSIZE-1] = '\0'; 36 line[GETPTY_BUFSIZE-1] = '\0';
35#endif 37# endif
36 return p; 38 return p;
37 } 39 }
38#else 40#else
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index b87d1dde8..a313c2a65 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -104,12 +104,12 @@ static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed)
104 */ 104 */
105 105
106/* 0: fastest, 3: smallest */ 106/* 0: fastest, 3: smallest */
107#if CONFIG_MD5_SIZE_VS_SPEED < 0 107#if CONFIG_MD5_SMALL < 0
108# define MD5_SIZE_VS_SPEED 0 108# define MD5_SMALL 0
109#elif CONFIG_MD5_SIZE_VS_SPEED > 3 109#elif CONFIG_MD5_SMALL > 3
110# define MD5_SIZE_VS_SPEED 3 110# define MD5_SMALL 3
111#else 111#else
112# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED 112# define MD5_SMALL CONFIG_MD5_SMALL
113#endif 113#endif
114 114
115/* These are the four functions used in the four steps of the MD5 algorithm 115/* These are the four functions used in the four steps of the MD5 algorithm
@@ -129,7 +129,7 @@ static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed)
129/* Hash a single block, 64 bytes long and 4-byte aligned */ 129/* Hash a single block, 64 bytes long and 4-byte aligned */
130static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) 130static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
131{ 131{
132#if MD5_SIZE_VS_SPEED > 0 132#if MD5_SMALL > 0
133 /* Before we start, one word to the strange constants. 133 /* Before we start, one word to the strange constants.
134 They are defined in RFC 1321 as 134 They are defined in RFC 1321 as
135 T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64 135 T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64
@@ -157,7 +157,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
157 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 157 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
158 }; 158 };
159 static const char P_array[] ALIGN1 = { 159 static const char P_array[] ALIGN1 = {
160# if MD5_SIZE_VS_SPEED > 1 160# if MD5_SMALL > 1
161 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ 161 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
162# endif 162# endif
163 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ 163 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
@@ -171,7 +171,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
171 uint32_t C = ctx->hash[2]; 171 uint32_t C = ctx->hash[2];
172 uint32_t D = ctx->hash[3]; 172 uint32_t D = ctx->hash[3];
173 173
174#if MD5_SIZE_VS_SPEED >= 2 /* 2 or 3 */ 174#if MD5_SMALL >= 2 /* 2 or 3 */
175 175
176 static const char S_array[] ALIGN1 = { 176 static const char S_array[] ALIGN1 = {
177 7, 12, 17, 22, 177 7, 12, 17, 22,
@@ -190,7 +190,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
190 words[i] = SWAP_LE32(words[i]); 190 words[i] = SWAP_LE32(words[i]);
191# endif 191# endif
192 192
193# if MD5_SIZE_VS_SPEED == 3 193# if MD5_SMALL == 3
194 pc = C_array; 194 pc = C_array;
195 pp = P_array; 195 pp = P_array;
196 ps = S_array - 4; 196 ps = S_array - 4;
@@ -220,7 +220,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
220 C = B; 220 C = B;
221 B = temp; 221 B = temp;
222 } 222 }
223# else /* MD5_SIZE_VS_SPEED == 2 */ 223# else /* MD5_SMALL == 2 */
224 pc = C_array; 224 pc = C_array;
225 pp = P_array; 225 pp = P_array;
226 ps = S_array; 226 ps = S_array;
@@ -271,13 +271,13 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
271 ctx->hash[2] += C; 271 ctx->hash[2] += C;
272 ctx->hash[3] += D; 272 ctx->hash[3] += D;
273 273
274#else /* MD5_SIZE_VS_SPEED == 0 or 1 */ 274#else /* MD5_SMALL == 0 or 1 */
275 275
276 uint32_t A_save = A; 276 uint32_t A_save = A;
277 uint32_t B_save = B; 277 uint32_t B_save = B;
278 uint32_t C_save = C; 278 uint32_t C_save = C;
279 uint32_t D_save = D; 279 uint32_t D_save = D;
280# if MD5_SIZE_VS_SPEED == 1 280# if MD5_SMALL == 1
281 const uint32_t *pc; 281 const uint32_t *pc;
282 const char *pp; 282 const char *pp;
283 int i; 283 int i;
@@ -299,7 +299,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
299 } while (0) 299 } while (0)
300 300
301 /* Round 1 */ 301 /* Round 1 */
302# if MD5_SIZE_VS_SPEED == 1 302# if MD5_SMALL == 1
303 pc = C_array; 303 pc = C_array;
304 for (i = 0; i < 4; i++) { 304 for (i = 0; i < 4; i++) {
305 OP(A, B, C, D, 7, *pc++); 305 OP(A, B, C, D, 7, *pc++);
@@ -339,7 +339,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
339 } while (0) 339 } while (0)
340 340
341 /* Round 2 */ 341 /* Round 2 */
342# if MD5_SIZE_VS_SPEED == 1 342# if MD5_SMALL == 1
343 pp = P_array; 343 pp = P_array;
344 for (i = 0; i < 4; i++) { 344 for (i = 0; i < 4; i++) {
345 OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++); 345 OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++);
@@ -367,7 +367,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
367# endif 367# endif
368 368
369 /* Round 3 */ 369 /* Round 3 */
370# if MD5_SIZE_VS_SPEED == 1 370# if MD5_SMALL == 1
371 for (i = 0; i < 4; i++) { 371 for (i = 0; i < 4; i++) {
372 OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++); 372 OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++);
373 OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++); 373 OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++);
@@ -394,7 +394,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
394# endif 394# endif
395 395
396 /* Round 4 */ 396 /* Round 4 */
397# if MD5_SIZE_VS_SPEED == 1 397# if MD5_SMALL == 1
398 for (i = 0; i < 4; i++) { 398 for (i = 0; i < 4; i++) {
399 OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++); 399 OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++);
400 OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++); 400 OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++);
diff --git a/libbb/hash_md5prime.c b/libbb/hash_md5prime.c
index 7986f4d29..e089a15f5 100644
--- a/libbb/hash_md5prime.c
+++ b/libbb/hash_md5prime.c
@@ -59,7 +59,7 @@
59 * Completely removed static PADDING array. 59 * Completely removed static PADDING array.
60 * 60 *
61 * Reintroduced the loop unrolling in md5_transform and added the 61 * Reintroduced the loop unrolling in md5_transform and added the
62 * MD5_SIZE_VS_SPEED option for configurability. Define below as: 62 * MD5_SMALL option for configurability. Define below as:
63 * 0 fully unrolled loops 63 * 0 fully unrolled loops
64 * 1 partially unrolled (4 ops per loop) 64 * 1 partially unrolled (4 ops per loop)
65 * 2 no unrolling -- introduces the need to swap 4 variables (slow) 65 * 2 no unrolling -- introduces the need to swap 4 variables (slow)
@@ -75,12 +75,12 @@
75#include "libbb.h" 75#include "libbb.h"
76 76
77/* 1: fastest, 3: smallest */ 77/* 1: fastest, 3: smallest */
78#if CONFIG_MD5_SIZE_VS_SPEED < 1 78#if CONFIG_MD5_SMALL < 1
79# define MD5_SIZE_VS_SPEED 1 79# define MD5_SMALL 1
80#elif CONFIG_MD5_SIZE_VS_SPEED > 3 80#elif CONFIG_MD5_SMALL > 3
81# define MD5_SIZE_VS_SPEED 3 81# define MD5_SMALL 3
82#else 82#else
83# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED 83# define MD5_SMALL CONFIG_MD5_SMALL
84#endif 84#endif
85 85
86#if BB_LITTLE_ENDIAN 86#if BB_LITTLE_ENDIAN
@@ -152,7 +152,7 @@ memcpy32_le2cpu(uint32_t *output, const unsigned char *input, unsigned len)
152static void md5_transform(uint32_t state[4], const unsigned char block[64]) 152static void md5_transform(uint32_t state[4], const unsigned char block[64])
153{ 153{
154 uint32_t a, b, c, d, x[16]; 154 uint32_t a, b, c, d, x[16];
155#if MD5_SIZE_VS_SPEED > 1 155#if MD5_SMALL > 1
156 uint32_t temp; 156 uint32_t temp;
157 const unsigned char *ps; 157 const unsigned char *ps;
158 158
@@ -162,9 +162,9 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64])
162 4, 11, 16, 23, 162 4, 11, 16, 23,
163 6, 10, 15, 21 163 6, 10, 15, 21
164 }; 164 };
165#endif /* MD5_SIZE_VS_SPEED > 1 */ 165#endif /* MD5_SMALL > 1 */
166 166
167#if MD5_SIZE_VS_SPEED > 0 167#if MD5_SMALL > 0
168 const uint32_t *pc; 168 const uint32_t *pc;
169 const unsigned char *pp; 169 const unsigned char *pp;
170 int i; 170 int i;
@@ -198,7 +198,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64])
198 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ 198 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
199 }; 199 };
200 200
201#endif /* MD5_SIZE_VS_SPEED > 0 */ 201#endif /* MD5_SMALL > 0 */
202 202
203 memcpy32_le2cpu(x, block, 64); 203 memcpy32_le2cpu(x, block, 64);
204 204
@@ -207,7 +207,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64])
207 c = state[2]; 207 c = state[2];
208 d = state[3]; 208 d = state[3];
209 209
210#if MD5_SIZE_VS_SPEED > 2 210#if MD5_SMALL > 2
211 pc = C; 211 pc = C;
212 pp = P; 212 pp = P;
213 ps = S - 4; 213 ps = S - 4;
@@ -233,7 +233,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64])
233 temp += b; 233 temp += b;
234 a = d; d = c; c = b; b = temp; 234 a = d; d = c; c = b; b = temp;
235 } 235 }
236#elif MD5_SIZE_VS_SPEED > 1 236#elif MD5_SMALL > 1
237 pc = C; 237 pc = C;
238 pp = P; 238 pp = P;
239 ps = S; 239 ps = S;
@@ -260,7 +260,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64])
260 II(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++; 260 II(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
261 temp = d; d = c; c = b; b = a; a = temp; 261 temp = d; d = c; c = b; b = a; a = temp;
262 } 262 }
263#elif MD5_SIZE_VS_SPEED > 0 263#elif MD5_SMALL > 0
264 pc = C; 264 pc = C;
265 pp = P; 265 pp = P;
266 /* Round 1 */ 266 /* Round 1 */
diff --git a/libbb/inet_cksum.c b/libbb/inet_cksum.c
new file mode 100644
index 000000000..3d5dc3adf
--- /dev/null
+++ b/libbb/inet_cksum.c
@@ -0,0 +1,36 @@
1/*
2 * Checksum routine for Internet Protocol family headers (C Version)
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6
7#include "libbb.h"
8
9uint16_t FAST_FUNC inet_cksum(uint16_t *addr, int nleft)
10{
11 /*
12 * Our algorithm is simple, using a 32 bit accumulator,
13 * we add sequential 16 bit words to it, and at the end, fold
14 * back all the carry bits from the top 16 bits into the lower
15 * 16 bits.
16 */
17 unsigned sum = 0;
18 while (nleft > 1) {
19 sum += *addr++;
20 nleft -= 2;
21 }
22
23 /* Mop up an odd byte, if necessary */
24 if (nleft == 1) {
25 if (BB_LITTLE_ENDIAN)
26 sum += *(uint8_t*)addr;
27 else
28 sum += *(uint8_t*)addr << 8;
29 }
30
31 /* Add back carry outs from top 16 bits to low 16 bits */
32 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
33 sum += (sum >> 16); /* add carry */
34
35 return (uint16_t)~sum;
36}
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 1b97e8609..c89c829ed 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -1359,7 +1359,9 @@ static void load_history(line_input_t *st_parm)
1359 1359
1360 /* fill temp_h[], retaining only last MAX_HISTORY lines */ 1360 /* fill temp_h[], retaining only last MAX_HISTORY lines */
1361 memset(temp_h, 0, sizeof(temp_h)); 1361 memset(temp_h, 0, sizeof(temp_h));
1362 st_parm->cnt_history_in_file = idx = 0; 1362 idx = 0;
1363 if (!ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1364 st_parm->cnt_history_in_file = 0;
1363 while ((line = xmalloc_fgetline(fp)) != NULL) { 1365 while ((line = xmalloc_fgetline(fp)) != NULL) {
1364 if (line[0] == '\0') { 1366 if (line[0] == '\0') {
1365 free(line); 1367 free(line);
@@ -1367,7 +1369,8 @@ static void load_history(line_input_t *st_parm)
1367 } 1369 }
1368 free(temp_h[idx]); 1370 free(temp_h[idx]);
1369 temp_h[idx] = line; 1371 temp_h[idx] = line;
1370 st_parm->cnt_history_in_file++; 1372 if (!ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1373 st_parm->cnt_history_in_file++;
1371 idx++; 1374 idx++;
1372 if (idx == st_parm->max_history) 1375 if (idx == st_parm->max_history)
1373 idx = 0; 1376 idx = 0;
@@ -1397,15 +1400,62 @@ static void load_history(line_input_t *st_parm)
1397 st_parm->history[i++] = line; 1400 st_parm->history[i++] = line;
1398 } 1401 }
1399 st_parm->cnt_history = i; 1402 st_parm->cnt_history = i;
1403 if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1404 st_parm->cnt_history_in_file = i;
1400 } 1405 }
1401} 1406}
1402 1407
1403/* state->flags is already checked to be nonzero */ 1408# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
1409void save_history(line_input_t *st)
1410{
1411 FILE *fp;
1412
1413 if (!st->hist_file)
1414 return;
1415 if (st->cnt_history <= st->cnt_history_in_file)
1416 return;
1417
1418 fp = fopen(st->hist_file, "a");
1419 if (fp) {
1420 int i, fd;
1421 char *new_name;
1422 line_input_t *st_temp;
1423
1424 for (i = st->cnt_history_in_file; i < st->cnt_history; i++)
1425 fprintf(fp, "%s\n", st->history[i]);
1426 fclose(fp);
1427
1428 /* we may have concurrently written entries from others.
1429 * load them */
1430 st_temp = new_line_input_t(st->flags);
1431 st_temp->hist_file = st->hist_file;
1432 st_temp->max_history = st->max_history;
1433 load_history(st_temp);
1434
1435 /* write out temp file and replace hist_file atomically */
1436 new_name = xasprintf("%s.%u.new", st->hist_file, (int) getpid());
1437 fd = open(new_name, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1438 if (fd >= 0) {
1439 fp = xfdopen_for_write(fd);
1440 for (i = 0; i < st_temp->cnt_history; i++)
1441 fprintf(fp, "%s\n", st_temp->history[i]);
1442 fclose(fp);
1443 if (rename(new_name, st->hist_file) == 0)
1444 st->cnt_history_in_file = st_temp->cnt_history;
1445 }
1446 free(new_name);
1447 free_line_input_t(st_temp);
1448 }
1449}
1450# else
1404static void save_history(char *str) 1451static void save_history(char *str)
1405{ 1452{
1406 int fd; 1453 int fd;
1407 int len, len2; 1454 int len, len2;
1408 1455
1456 if (!state->hist_file)
1457 return;
1458
1409 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); 1459 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600);
1410 if (fd < 0) 1460 if (fd < 0)
1411 return; 1461 return;
@@ -1433,7 +1483,7 @@ static void save_history(char *str)
1433 1483
1434 /* write out temp file and replace hist_file atomically */ 1484 /* write out temp file and replace hist_file atomically */
1435 new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid()); 1485 new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid());
1436 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_TRUNC, 0600); 1486 fd = open(new_name, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1437 if (fd >= 0) { 1487 if (fd >= 0) {
1438 FILE *fp; 1488 FILE *fp;
1439 int i; 1489 int i;
@@ -1449,6 +1499,7 @@ static void save_history(char *str)
1449 free_line_input_t(st_temp); 1499 free_line_input_t(st_temp);
1450 } 1500 }
1451} 1501}
1502# endif
1452# else 1503# else
1453# define load_history(a) ((void)0) 1504# define load_history(a) ((void)0)
1454# define save_history(a) ((void)0) 1505# define save_history(a) ((void)0)
@@ -1477,15 +1528,18 @@ static void remember_in_history(char *str)
1477 for (i = 0; i < state->max_history-1; i++) 1528 for (i = 0; i < state->max_history-1; i++)
1478 state->history[i] = state->history[i+1]; 1529 state->history[i] = state->history[i+1];
1479 /* i == state->max_history-1 */ 1530 /* i == state->max_history-1 */
1531# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
1532 if (state->cnt_history_in_file)
1533 state->cnt_history_in_file--;
1534# endif
1480 } 1535 }
1481 /* i <= state->max_history-1 */ 1536 /* i <= state->max_history-1 */
1482 state->history[i++] = xstrdup(str); 1537 state->history[i++] = xstrdup(str);
1483 /* i <= state->max_history */ 1538 /* i <= state->max_history */
1484 state->cur_history = i; 1539 state->cur_history = i;
1485 state->cnt_history = i; 1540 state->cnt_history = i;
1486# if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY 1541# if ENABLE_FEATURE_EDITING_SAVEHISTORY && !ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
1487 if ((state->flags & SAVE_HISTORY) && state->hist_file) 1542 save_history(str);
1488 save_history(str);
1489# endif 1543# endif
1490 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) 1544 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
1491} 1545}
@@ -2147,7 +2201,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2147 state = st ? st : (line_input_t*) &const_int_0; 2201 state = st ? st : (line_input_t*) &const_int_0;
2148#if MAX_HISTORY > 0 2202#if MAX_HISTORY > 0
2149# if ENABLE_FEATURE_EDITING_SAVEHISTORY 2203# if ENABLE_FEATURE_EDITING_SAVEHISTORY
2150 if ((state->flags & SAVE_HISTORY) && state->hist_file) 2204 if (state->hist_file)
2151 if (state->cnt_history == 0) 2205 if (state->cnt_history == 0)
2152 load_history(state); 2206 load_history(state);
2153# endif 2207# endif
@@ -2467,6 +2521,44 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2467 vi_cmdmode = 1; 2521 vi_cmdmode = 1;
2468 input_backward(1); 2522 input_backward(1);
2469 } 2523 }
2524 /* Handle a few ESC-<key> combinations the same way
2525 * standard readline bindings (IOW: bash) do.
2526 * Often, Alt-<key> generates ESC-<key>.
2527 */
2528 ic = lineedit_read_key(read_key_buffer, timeout);
2529 switch (ic) {
2530 //case KEYCODE_LEFT: - bash doesn't do this
2531 case 'b':
2532 ctrl_left();
2533 break;
2534 //case KEYCODE_RIGHT: - bash doesn't do this
2535 case 'f':
2536 ctrl_right();
2537 break;
2538 //case KEYCODE_DELETE: - bash doesn't do this
2539 case 'd': /* Alt-D */
2540 {
2541 /* Delete word forward */
2542 int nc, sc = cursor;
2543 ctrl_right();
2544 nc = cursor;
2545 input_backward(cursor - sc);
2546 while (--nc >= cursor)
2547 input_delete(1);
2548 break;
2549 }
2550 case '\b': /* Alt-Backspace(?) */
2551 case '\x7f': /* Alt-Backspace(?) */
2552 //case 'w': - bash doesn't do this
2553 {
2554 /* Delete word backward */
2555 int sc = cursor;
2556 ctrl_left();
2557 while (sc-- > cursor)
2558 input_delete(1);
2559 break;
2560 }
2561 }
2470 break; 2562 break;
2471#endif /* FEATURE_COMMAND_EDITING_VI */ 2563#endif /* FEATURE_COMMAND_EDITING_VI */
2472 2564
@@ -2495,9 +2587,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2495 input_backward(1); 2587 input_backward(1);
2496 break; 2588 break;
2497 case KEYCODE_CTRL_LEFT: 2589 case KEYCODE_CTRL_LEFT:
2590 case KEYCODE_ALT_LEFT: /* bash doesn't do it */
2498 ctrl_left(); 2591 ctrl_left();
2499 break; 2592 break;
2500 case KEYCODE_CTRL_RIGHT: 2593 case KEYCODE_CTRL_RIGHT:
2594 case KEYCODE_ALT_RIGHT: /* bash doesn't do it */
2501 ctrl_right(); 2595 ctrl_right();
2502 break; 2596 break;
2503 case KEYCODE_HOME: 2597 case KEYCODE_HOME:
diff --git a/libbb/loop.c b/libbb/loop.c
index b798932fa..b3a520848 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -84,7 +84,7 @@ int FAST_FUNC del_loop(const char *device)
84 search will re-use an existing loop device already bound to that 84 search will re-use an existing loop device already bound to that
85 file/offset if it finds one. 85 file/offset if it finds one.
86 */ 86 */
87int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset) 87int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, int ro)
88{ 88{
89 char dev[LOOP_NAMESIZE]; 89 char dev[LOOP_NAMESIZE];
90 char *try; 90 char *try;
@@ -93,11 +93,13 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
93 int i, dfd, ffd, mode, rc = -1; 93 int i, dfd, ffd, mode, rc = -1;
94 94
95 /* Open the file. Barf if this doesn't work. */ 95 /* Open the file. Barf if this doesn't work. */
96 mode = O_RDWR; 96 mode = ro ? O_RDONLY : O_RDWR;
97 ffd = open(file, mode); 97 ffd = open(file, mode);
98 if (ffd < 0) { 98 if (ffd < 0) {
99 mode = O_RDONLY; 99 if (mode != O_RDONLY) {
100 ffd = open(file, mode); 100 mode = O_RDONLY;
101 ffd = open(file, mode);
102 }
101 if (ffd < 0) 103 if (ffd < 0)
102 return -errno; 104 return -errno;
103 } 105 }
diff --git a/libbb/match_fstype.c b/libbb/match_fstype.c
index 83d6e6770..32c3d7f18 100644
--- a/libbb/match_fstype.c
+++ b/libbb/match_fstype.c
@@ -12,6 +12,8 @@
12 12
13#include "libbb.h" 13#include "libbb.h"
14 14
15#ifdef HAVE_MNTENT_H
16
15int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype) 17int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype)
16{ 18{
17 int match = 1; 19 int match = 1;
@@ -40,3 +42,5 @@ int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype)
40 42
41 return !match; 43 return !match;
42} 44}
45
46#endif /* HAVE_MNTENT_H */
diff --git a/libbb/percent_decode.c b/libbb/percent_decode.c
new file mode 100644
index 000000000..9a9d80c4a
--- /dev/null
+++ b/libbb/percent_decode.c
@@ -0,0 +1,69 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */
5
6//kbuild:lib-y += percent_decode.o
7
8#include "libbb.h"
9
10static unsigned hex_to_bin(unsigned char c)
11{
12 unsigned v;
13
14 v = c - '0';
15 if (v <= 9)
16 return v;
17 /* c | 0x20: letters to lower case, non-letters
18 * to (potentially different) non-letters */
19 v = (unsigned)(c | 0x20) - 'a';
20 if (v <= 5)
21 return v + 10;
22 return ~0;
23/* For testing:
24void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); }
25int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f');
26t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; }
27*/
28}
29
30char* FAST_FUNC percent_decode_in_place(char *str, int strict)
31{
32 /* note that decoded string is always shorter than original */
33 char *src = str;
34 char *dst = str;
35 char c;
36
37 while ((c = *src++) != '\0') {
38 unsigned v;
39
40 if (!strict && c == '+') {
41 *dst++ = ' ';
42 continue;
43 }
44 if (c != '%') {
45 *dst++ = c;
46 continue;
47 }
48 v = hex_to_bin(src[0]);
49 if (v > 15) {
50 bad_hex:
51 if (strict)
52 return NULL;
53 *dst++ = '%';
54 continue;
55 }
56 v = (v * 16) | hex_to_bin(src[1]);
57 if (v > 255)
58 goto bad_hex;
59 if (strict && (v == '/' || v == '\0')) {
60 /* caller takes it as indication of invalid
61 * (dangerous wrt exploits) chars */
62 return str + 1;
63 }
64 *dst++ = v;
65 src += 2;
66 }
67 *dst = '\0';
68 return str;
69}
diff --git a/libbb/procps.c b/libbb/procps.c
index b5582edfa..39ddd2c12 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -285,27 +285,25 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
285void BUG_comm_size(void); 285void BUG_comm_size(void);
286procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) 286procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
287{ 287{
288 struct dirent *entry;
289 char buf[PROCPS_BUFSIZE];
290 char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
291 char *filename_tail;
292 long tasknice;
293 unsigned pid;
294 int n;
295 struct stat sb;
296
297 if (!sp) 288 if (!sp)
298 sp = alloc_procps_scan(); 289 sp = alloc_procps_scan();
299 290
300 for (;;) { 291 for (;;) {
292 struct dirent *entry;
293 char buf[PROCPS_BUFSIZE];
294 long tasknice;
295 unsigned pid;
296 int n;
297 char filename[sizeof("/proc/%u/task/%u/cmdline") + sizeof(int)*3 * 2];
298 char *filename_tail;
299
301#if ENABLE_FEATURE_SHOW_THREADS 300#if ENABLE_FEATURE_SHOW_THREADS
302 if ((flags & PSSCAN_TASKS) && sp->task_dir) { 301 if (sp->task_dir) {
303 entry = readdir(sp->task_dir); 302 entry = readdir(sp->task_dir);
304 if (entry) 303 if (entry)
305 goto got_entry; 304 goto got_entry;
306 closedir(sp->task_dir); 305 closedir(sp->task_dir);
307 sp->task_dir = NULL; 306 sp->task_dir = NULL;
308 sp->main_thread_pid = 0;
309 } 307 }
310#endif 308#endif
311 entry = readdir(sp->dir); 309 entry = readdir(sp->dir);
@@ -322,9 +320,9 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
322 /* We found another /proc/PID. Do not use it, 320 /* We found another /proc/PID. Do not use it,
323 * there will be /proc/PID/task/PID (same PID!), 321 * there will be /proc/PID/task/PID (same PID!),
324 * so just go ahead and dive into /proc/PID/task. */ 322 * so just go ahead and dive into /proc/PID/task. */
325 char task_dir[sizeof("/proc/%u/task") + sizeof(int)*3]; 323 sprintf(filename, "/proc/%u/task", pid);
326 sprintf(task_dir, "/proc/%u/task", pid); 324 /* Note: if opendir fails, we just go to next /proc/XXX */
327 sp->task_dir = xopendir(task_dir); 325 sp->task_dir = opendir(filename);
328 sp->main_thread_pid = pid; 326 sp->main_thread_pid = pid;
329 continue; 327 continue;
330 } 328 }
@@ -348,9 +346,15 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
348 } 346 }
349#endif 347#endif
350 348
351 filename_tail = filename + sprintf(filename, "/proc/%u/", pid); 349#if ENABLE_FEATURE_SHOW_THREADS
350 if (sp->task_dir)
351 filename_tail = filename + sprintf(filename, "/proc/%u/task/%u/", sp->main_thread_pid, pid);
352 else
353#endif
354 filename_tail = filename + sprintf(filename, "/proc/%u/", pid);
352 355
353 if (flags & PSSCAN_UIDGID) { 356 if (flags & PSSCAN_UIDGID) {
357 struct stat sb;
354 if (stat(filename, &sb)) 358 if (stat(filename, &sb))
355 continue; /* process probably exited */ 359 continue; /* process probably exited */
356 /* Effective UID/GID, not real */ 360 /* Effective UID/GID, not real */
diff --git a/libbb/read_key.c b/libbb/read_key.c
index 5dcd19c3f..8d72d2a63 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -40,13 +40,14 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
40 '[','C' |0x80,KEYCODE_RIGHT , 40 '[','C' |0x80,KEYCODE_RIGHT ,
41 '[','D' |0x80,KEYCODE_LEFT , 41 '[','D' |0x80,KEYCODE_LEFT ,
42 /* ESC [ 1 ; 2 x, where x = A/B/C/D: Shift-<arrow> */ 42 /* ESC [ 1 ; 2 x, where x = A/B/C/D: Shift-<arrow> */
43 /* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt-<arrow> */ 43 /* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt-<arrow> - implemented below */
44 /* ESC [ 1 ; 4 x, where x = A/B/C/D: Alt-Shift-<arrow> */ 44 /* ESC [ 1 ; 4 x, where x = A/B/C/D: Alt-Shift-<arrow> */
45 /* ESC [ 1 ; 5 x, where x = A/B/C/D: Ctrl-<arrow> - implemented below */ 45 /* ESC [ 1 ; 5 x, where x = A/B/C/D: Ctrl-<arrow> - implemented below */
46 /* ESC [ 1 ; 6 x, where x = A/B/C/D: Ctrl-Shift-<arrow> */ 46 /* ESC [ 1 ; 6 x, where x = A/B/C/D: Ctrl-Shift-<arrow> */
47 '[','H' |0x80,KEYCODE_HOME , /* xterm */ 47 '[','H' |0x80,KEYCODE_HOME , /* xterm */
48 /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home */
49 '[','F' |0x80,KEYCODE_END , /* xterm */ 48 '[','F' |0x80,KEYCODE_END , /* xterm */
49 /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home (End similarly?) */
50 /* '[','Z' |0x80,KEYCODE_SHIFT_TAB, */
50 '[','1','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */ 51 '[','1','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */
51 '[','2','~' |0x80,KEYCODE_INSERT , 52 '[','2','~' |0x80,KEYCODE_INSERT ,
52 /* ESC [ 2 ; 3 ~ - Alt-Insert */ 53 /* ESC [ 2 ; 3 ~ - Alt-Insert */
@@ -86,8 +87,12 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
86 /* '[','1',';','5','B' |0x80,KEYCODE_CTRL_DOWN , - unused */ 87 /* '[','1',';','5','B' |0x80,KEYCODE_CTRL_DOWN , - unused */
87 '[','1',';','5','C' |0x80,KEYCODE_CTRL_RIGHT, 88 '[','1',';','5','C' |0x80,KEYCODE_CTRL_RIGHT,
88 '[','1',';','5','D' |0x80,KEYCODE_CTRL_LEFT , 89 '[','1',';','5','D' |0x80,KEYCODE_CTRL_LEFT ,
90 /* '[','1',';','3','A' |0x80,KEYCODE_ALT_UP , - unused */
91 /* '[','1',';','3','B' |0x80,KEYCODE_ALT_DOWN , - unused */
92 '[','1',';','3','C' |0x80,KEYCODE_ALT_RIGHT,
93 '[','1',';','3','D' |0x80,KEYCODE_ALT_LEFT ,
94 /* '[','3',';','3','~' |0x80,KEYCODE_ALT_DELETE, - unused */
89 0 95 0
90 /* ESC [ Z - Shift-Tab */
91 }; 96 };
92 97
93 pfd.fd = fd; 98 pfd.fd = fd;
diff --git a/libbb/read_printf.c b/libbb/read_printf.c
index 192f83d6e..0bbf7802a 100644
--- a/libbb/read_printf.c
+++ b/libbb/read_printf.c
@@ -15,7 +15,7 @@
15) 15)
16 16
17#if ZIPPED 17#if ZIPPED
18# include "archive.h" 18# include "bb_archive.h"
19#endif 19#endif
20 20
21 21
diff --git a/libbb/udp_io.c b/libbb/udp_io.c
index b8fb6755d..7985a9723 100644
--- a/libbb/udp_io.c
+++ b/libbb/udp_io.c
@@ -13,7 +13,7 @@
13 * We don't check for errors here. Not supported == won't be used 13 * We don't check for errors here. Not supported == won't be used
14 */ 14 */
15void FAST_FUNC 15void FAST_FUNC
16socket_want_pktinfo(int fd) 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(fd, IPPROTO_IP, IP_PKTINFO, &const_int_1, sizeof(int));
diff --git a/libbb/uuencode.c b/libbb/uuencode.c
index 03e708fd5..f7b248492 100644
--- a/libbb/uuencode.c
+++ b/libbb/uuencode.c
@@ -10,7 +10,7 @@
10#include "libbb.h" 10#include "libbb.h"
11 11
12/* Conversion table. for base 64 */ 12/* Conversion table. for base 64 */
13const char bb_uuenc_tbl_base64[65 + 2] ALIGN1 = { 13const char bb_uuenc_tbl_base64[65 + 1] ALIGN1 = {
14 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 14 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
15 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 15 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
16 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 16 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
@@ -20,7 +20,7 @@ const char bb_uuenc_tbl_base64[65 + 2] ALIGN1 = {
20 'w', 'x', 'y', 'z', '0', '1', '2', '3', 20 'w', 'x', 'y', 'z', '0', '1', '2', '3',
21 '4', '5', '6', '7', '8', '9', '+', '/', 21 '4', '5', '6', '7', '8', '9', '+', '/',
22 '=' /* termination character */, 22 '=' /* termination character */,
23 '\n', '\0' /* needed for uudecode.c */ 23 '\0' /* needed for uudecode.c only */
24}; 24};
25 25
26const char bb_uuenc_tbl_std[65] ALIGN1 = { 26const char bb_uuenc_tbl_std[65] ALIGN1 = {
@@ -73,23 +73,23 @@ void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl
73} 73}
74 74
75/* 75/*
76 * Decode base64 encoded stream. 76 * Decode base64 encoded string. Stops on '\0'.
77 * Can stop on EOF, specified char, or on uuencode-style "====" line: 77 *
78 * flags argument controls it. 78 * Returns: pointer to the undecoded part of source.
79 * If points to '\0', then the source was fully decoded.
80 * (*pp_dst): advanced past the last written byte.
79 */ 81 */
80void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) 82const char* FAST_FUNC decode_base64(char **pp_dst, const char *src)
81{ 83{
82/* Note that EOF _can_ be passed as exit_char too */ 84 char *dst = *pp_dst;
83#define exit_char ((int)(signed char)flags) 85 const char *src_tail;
84#define uu_style_end (flags & BASE64_FLAG_UU_STOP)
85
86 int term_count = 0;
87 86
88 while (1) { 87 while (1) {
89 unsigned char translated[4]; 88 unsigned char six_bit[4];
90 int count = 0; 89 int count = 0;
91 90
92 /* Process one group of 4 chars */ 91 /* Fetch up to four 6-bit values */
92 src_tail = src;
93 while (count < 4) { 93 while (count < 4) {
94 char *table_ptr; 94 char *table_ptr;
95 int ch; 95 int ch;
@@ -97,49 +97,128 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
97 /* Get next _valid_ character. 97 /* Get next _valid_ character.
98 * bb_uuenc_tbl_base64[] contains this string: 98 * bb_uuenc_tbl_base64[] contains this string:
99 * 0 1 2 3 4 5 6 99 * 0 1 2 3 4 5 6
100 * 012345678901234567890123456789012345678901234567890123456789012345 100 * 01234567890123456789012345678901234567890123456789012345678901234
101 * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n" 101 * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
102 */ 102 */
103 do { 103 do {
104 ch = fgetc(src_stream); 104 ch = *src;
105 if (ch == exit_char && count == 0) 105 if (ch == '\0') {
106 return; 106 if (count == 0) {
107 if (ch == EOF) 107 /* Example:
108 bb_error_msg_and_die("truncated base64 input"); 108 * If we decode "QUJD <NUL>", we want
109 * to return ptr to NUL, not to ' ',
110 * because we did fully decode
111 * the string (to "ABC").
112 */
113 src_tail = src;
114 }
115 goto ret;
116 }
117 src++;
109 table_ptr = strchr(bb_uuenc_tbl_base64, ch); 118 table_ptr = strchr(bb_uuenc_tbl_base64, ch);
110//TODO: add BASE64_FLAG_foo to die on bad char? 119//TODO: add BASE64_FLAG_foo to die on bad char?
111//Note that then we may need to still allow '\r' (for mail processing)
112 } while (!table_ptr); 120 } while (!table_ptr);
113 121
114 /* Convert encoded character to decimal */ 122 /* Convert encoded character to decimal */
115 ch = table_ptr - bb_uuenc_tbl_base64; 123 ch = table_ptr - bb_uuenc_tbl_base64;
116 124
117 if (ch == 65 /* '\n' */) {
118 /* Terminating "====" line? */
119 if (uu_style_end && term_count == 4)
120 return; /* yes */
121 term_count = 0;
122 continue;
123 }
124 /* ch is 64 if char was '=', otherwise 0..63 */ 125 /* ch is 64 if char was '=', otherwise 0..63 */
125 translated[count] = ch & 63; /* 64 -> 0 */ 126 if (ch == 64)
126 if (ch == 64) {
127 term_count++;
128 break; 127 break;
129 } 128 six_bit[count] = ch;
130 count++; 129 count++;
131 term_count = 0;
132 } 130 }
133 131
134 /* Merge 6 bit chars to 8 bit. 132 /* Transform 6-bit values to 8-bit ones.
135 * count can be < 4 when we decode the tail: 133 * count can be < 4 when we decode the tail:
136 * "eQ==" -> "y", not "y NUL NUL" 134 * "eQ==" -> "y", not "y NUL NUL".
135 * Note that (count > 1) is always true,
136 * "x===" encoding is not valid:
137 * even a single zero byte encodes as "AA==".
138 * However, with current logic we come here with count == 1
139 * when we decode "==" tail.
137 */ 140 */
138 if (count > 1) 141 if (count > 1)
139 fputc(translated[0] << 2 | translated[1] >> 4, dst_stream); 142 *dst++ = six_bit[0] << 2 | six_bit[1] >> 4;
140 if (count > 2) 143 if (count > 2)
141 fputc(translated[1] << 4 | translated[2] >> 2, dst_stream); 144 *dst++ = six_bit[1] << 4 | six_bit[2] >> 2;
142 if (count > 3) 145 if (count > 3)
143 fputc(translated[2] << 6 | translated[3], dst_stream); 146 *dst++ = six_bit[2] << 6 | six_bit[3];
147 /* Note that if we decode "AA==" and ate first '=',
148 * we just decoded one char (count == 2) and now we'll
149 * do the loop once more to decode second '='.
150 */
144 } /* while (1) */ 151 } /* while (1) */
152 ret:
153 *pp_dst = dst;
154 return src_tail;
155}
156
157/*
158 * Decode base64 encoded stream.
159 * Can stop on EOF, specified char, or on uuencode-style "====" line:
160 * flags argument controls it.
161 */
162void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
163{
164/* Note that EOF _can_ be passed as exit_char too */
165#define exit_char ((int)(signed char)flags)
166#define uu_style_end (flags & BASE64_FLAG_UU_STOP)
167
168 /* uuencoded files have 61 byte lines. Use 64 byte buffer
169 * to process line at a time.
170 */
171 enum { BUFFER_SIZE = 64 };
172
173 char in_buf[BUFFER_SIZE + 2];
174 char out_buf[BUFFER_SIZE / 4 * 3 + 2];
175 char *out_tail;
176 const char *in_tail;
177 int term_seen = 0;
178 int in_count = 0;
179
180 while (1) {
181 while (in_count < BUFFER_SIZE) {
182 int ch = fgetc(src_stream);
183 if (ch == exit_char) {
184 if (in_count == 0)
185 return;
186 term_seen = 1;
187 break;
188 }
189 if (ch == EOF) {
190 term_seen = 1;
191 break;
192 }
193 /* Prevent "====" line to be split: stop if we see '\n'.
194 * We can also skip other whitespace and skirt the problem
195 * of files with NULs by stopping on any control char or space:
196 */
197 if (ch <= ' ')
198 break;
199 in_buf[in_count++] = ch;
200 }
201 in_buf[in_count] = '\0';
202
203 /* Did we encounter "====" line? */
204 if (uu_style_end && strcmp(in_buf, "====") == 0)
205 return;
206
207 out_tail = out_buf;
208 in_tail = decode_base64(&out_tail, in_buf);
209
210 fwrite(out_buf, (out_tail - out_buf), 1, dst_stream);
211
212 if (term_seen) {
213 /* Did we consume ALL characters? */
214 if (*in_tail == '\0')
215 return;
216 /* No */
217 bb_error_msg_and_die("truncated base64 input");
218 }
219
220 /* It was partial decode */
221 in_count = strlen(in_tail);
222 memmove(in_buf, in_tail, in_count);
223 }
145} 224}
diff --git a/libbb/vdprintf.c b/libbb/vdprintf.c
index feeb403a0..05426873e 100644
--- a/libbb/vdprintf.c
+++ b/libbb/vdprintf.c
@@ -12,10 +12,10 @@
12#if defined(__GLIBC__) && __GLIBC__ < 2 12#if defined(__GLIBC__) && __GLIBC__ < 2
13int FAST_FUNC vdprintf(int d, const char *format, va_list ap) 13int FAST_FUNC vdprintf(int d, const char *format, va_list ap)
14{ 14{
15 char buf[BUF_SIZE]; 15 char buf[8 * 1024];
16 int len; 16 int len;
17 17
18 len = vsnprintf(buf, BUF_SIZE, format, ap); 18 len = vsnprintf(buf, sizeof(buf), format, ap);
19 return write(d, buf, len); 19 return write(d, buf, len);
20} 20}
21#endif 21#endif
diff --git a/loginutils/Config.src b/loginutils/Config.src
index 0d7f50cf1..14ce53434 100644
--- a/loginutils/Config.src
+++ b/loginutils/Config.src
@@ -205,6 +205,17 @@ config LOGIN
205 Note that Busybox binary must be setuid root for this applet to 205 Note that Busybox binary must be setuid root for this applet to
206 work properly. 206 work properly.
207 207
208config LOGIN_SESSION_AS_CHILD
209 bool "Run logged in session in a child process"
210 default y if PAM
211 depends on LOGIN
212 help
213 Run the logged in session in a child process. This allows
214 login to clean up things such as utmp entries or PAM sessions
215 when the login session is complete. If you use PAM, you
216 almost always would want this to be set to Y, else PAM session
217 will not be cleaned up.
218
208config PAM 219config PAM
209 bool "Support for PAM (Pluggable Authentication Modules)" 220 bool "Support for PAM (Pluggable Authentication Modules)"
210 default n 221 default n
diff --git a/loginutils/README b/loginutils/README
new file mode 100644
index 000000000..ce8851097
--- /dev/null
+++ b/loginutils/README
@@ -0,0 +1,70 @@
1 Getty
2
3??? Should getty open tty with or without O_NONBLOCK?
4For serial lines, it means "should getty wait for Carrier Detect pin?"
5I checked other getties:
6
7- agetty always uses O_NONBLOCK
8- mgetty uses O_NONBLOCK unless run with -b, or as "getty"
9
10??? If we decided to use O_NONBLOCK (perhaps optionally with -b),
11when getty should send -I INITSTR data to tty? After open succeeds?
12What if we also want to initialize *modem* with some AT commands?
13
14??? Should we check/create /var/lock/LCK..ttyPFX lockfiles?
15
16??? mgetty opens tty but does NOT lock it, then waits for input via
17select/poll, and when input is available, it checks lock file.
18If it exists, mgetty exits (it assumes someone else uses the line).
19If no, it creates the file (lock the tty). Sounds like a good algorithm
20to use if we are called with -w...
21
22Getty should establish a new session and process group, and ensure
23that tty is a ctty.
24
25??? Should getty ensure that other processes which might have opened
26fds to this tty be dusconnected? agetty has a -R option which makes
27agetty call vhangup() after tty is opened. (Then agetty opens it again,
28since it probably vhangup'ed its own fd too).
29
30Getty should leave the tty in approximately the same state as "stty sane"
31before it execs login program. Minor things we do conditionally are:
32 c_iflag |= ICRNL; // if '\r' was used to end username
33
34??? mgetty uses per-tty file to ignore connects, /etc/nologin.ttyxx -
35is it useful?
36
37It should be possible to run "getty 0 -" from a shell prompt.
38[This currently doesn't work from interactive shell since setsid()
39fails in process group leader. The workaround is to run it as a child
40of something. sh -c 'getty - 0; true' usually works. Should we fix this?]
41It should leave tty in a sane state when it exits (Ctrl-D, -t SEC timeout):
42echo should be on, speed, control chars properly set, etc.
43(However, it can't restore ctty. The symptom is that "</dev/tty"
44fails in the parent shell after getty exits: /dev/tty can't be opened).
45
46Getty should write LOGIN_PROCESS utmp record before it starts waiting
47for username to be entered.
48
49 Login
50
51Login should not try to set up tty parameters - apart from switching echo
52off while entering password, and switching it back on after.
53
54Login should not leave "echo off" state when it times out reading password
55or otherwise terminates (Ctrl-C, Ctrl-D etc).
56
57??? Should login establish a new session and/or process group, and ensure
58that tty is a ctty? Without this, running login directly (not via getty)
59from e.g. initscript will usually result with a login session without
60ctty and without session/pgrp properly created...
61
62It should be possible to run "login [USER]" from a shell prompt,
63and it should work (not block/die/error out).
64Similarly to getty, it should leave tty in the sane state when it exits.
65
66??? Should login write LOGIN_PROCESS utmp record before it starts waiting
67for username/password to be entered?
68
69Login should write USER_PROCESS utmp record just before it is about
70to exec user's shell.
diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c
index 2262b792a..b7df57e5d 100644
--- a/loginutils/chpasswd.c
+++ b/loginutils/chpasswd.c
@@ -33,9 +33,8 @@ static const char chpasswd_longopts[] ALIGN1 =
33int chpasswd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 33int chpasswd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
34int chpasswd_main(int argc UNUSED_PARAM, char **argv) 34int chpasswd_main(int argc UNUSED_PARAM, char **argv)
35{ 35{
36 char *name, *pass; 36 char *name;
37 char salt[sizeof("$N$XXXXXXXX")]; 37 int opt;
38 int opt, rc;
39 38
40 if (getuid() != 0) 39 if (getuid() != 0)
41 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 40 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
@@ -45,6 +44,10 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv)
45 opt = getopt32(argv, "em"); 44 opt = getopt32(argv, "em");
46 45
47 while ((name = xmalloc_fgetline(stdin)) != NULL) { 46 while ((name = xmalloc_fgetline(stdin)) != NULL) {
47 char *free_me;
48 char *pass;
49 int rc;
50
48 pass = strchr(name, ':'); 51 pass = strchr(name, ':');
49 if (!pass) 52 if (!pass)
50 bb_error_msg_and_die("missing new password"); 53 bb_error_msg_and_die("missing new password");
@@ -52,7 +55,10 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv)
52 55
53 xuname2uid(name); /* dies if there is no such user */ 56 xuname2uid(name); /* dies if there is no such user */
54 57
58 free_me = NULL;
55 if (!(opt & OPT_ENC)) { 59 if (!(opt & OPT_ENC)) {
60 char salt[sizeof("$N$XXXXXXXX")];
61
56 crypt_make_salt(salt, 1); 62 crypt_make_salt(salt, 1);
57 if (opt & OPT_MD5) { 63 if (opt & OPT_MD5) {
58 salt[0] = '$'; 64 salt[0] = '$';
@@ -60,7 +66,7 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv)
60 salt[2] = '$'; 66 salt[2] = '$';
61 crypt_make_salt(salt + 3, 4); 67 crypt_make_salt(salt + 3, 4);
62 } 68 }
63 pass = pw_encrypt(pass, salt, 0); 69 free_me = pass = pw_encrypt(pass, salt, 0);
64 } 70 }
65 71
66 /* This is rather complex: if user is not found in /etc/shadow, 72 /* This is rather complex: if user is not found in /etc/shadow,
@@ -81,8 +87,7 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv)
81 bb_info_msg("Password for '%s' changed", name); 87 bb_info_msg("Password for '%s' changed", name);
82 logmode = LOGMODE_STDIO; 88 logmode = LOGMODE_STDIO;
83 free(name); 89 free(name);
84 if (!(opt & OPT_ENC)) 90 free(free_me);
85 free(pass);
86 } 91 }
87 return EXIT_SUCCESS; 92 return EXIT_SUCCESS;
88} 93}
diff --git a/loginutils/getty.c b/loginutils/getty.c
index 62456651b..1f417591b 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -63,18 +63,8 @@ static FILE *dbf;
63 */ 63 */
64#define ISSUE "/etc/issue" 64#define ISSUE "/etc/issue"
65 65
66/* Some shorthands for control characters */ 66/* Macro to build Ctrl-LETTER. Assumes ASCII dialect */
67#define CTL(x) ((x) ^ 0100) /* Assumes ASCII dialect */ 67#define CTL(x) ((x) ^ 0100)
68#define BS CTL('H') /* back space */
69#define DEL CTL('?') /* delete */
70
71/* Defaults for line-editing etc. characters; you may want to change this */
72#define DEF_INTR CTL('C') /* default interrupt character */
73#define DEF_QUIT CTL('\\') /* default quit char */
74#define DEF_KILL CTL('U') /* default kill char */
75#define DEF_EOF CTL('D') /* default EOF char */
76#define DEF_EOL '\n'
77#define DEF_SWITCH 0 /* default switch char (none) */
78 68
79/* 69/*
80 * When multiple baud rates are specified on the command line, 70 * When multiple baud rates are specified on the command line,
@@ -83,16 +73,16 @@ static FILE *dbf;
83#define MAX_SPEED 10 /* max. nr. of baud rates */ 73#define MAX_SPEED 10 /* max. nr. of baud rates */
84 74
85struct globals { 75struct globals {
86 unsigned timeout; /* time-out period */ 76 unsigned timeout;
87 const char *login; /* login program */ 77 const char *login; /* login program */
88 const char *fakehost; 78 const char *fakehost;
89 const char *tty; /* name of tty */ 79 const char *tty_name;
90 char *initstring; /* modem init string */ 80 char *initstring; /* modem init string */
91 const char *issue; /* alternative issue file */ 81 const char *issue; /* alternative issue file */
92 int numspeed; /* number of baud rates to try */ 82 int numspeed; /* number of baud rates to try */
93 int speeds[MAX_SPEED]; /* baud rates to be tried */ 83 int speeds[MAX_SPEED]; /* baud rates to be tried */
94 unsigned char eol; /* end-of-line char seen (CR or NL) */ 84 unsigned char eol; /* end-of-line char seen (CR or NL) */
95 struct termios termios; /* terminal mode bits */ 85 struct termios tty_attrs;
96 char line_buf[128]; 86 char line_buf[128];
97}; 87};
98 88
@@ -104,7 +94,7 @@ struct globals {
104//usage:#define getty_trivial_usage 94//usage:#define getty_trivial_usage
105//usage: "[OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]" 95//usage: "[OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]"
106//usage:#define getty_full_usage "\n\n" 96//usage:#define getty_full_usage "\n\n"
107//usage: "Open a tty, prompt for a login name, then invoke /bin/login\n" 97//usage: "Open TTY, prompt for login name, then invoke /bin/login\n"
108//usage: "\n -h Enable hardware RTS/CTS flow control" 98//usage: "\n -h Enable hardware RTS/CTS flow control"
109//usage: "\n -L Set CLOCAL (ignore Carrier Detect state)" 99//usage: "\n -L Set CLOCAL (ignore Carrier Detect state)"
110//usage: "\n -m Get baud rate from modem's CONNECT status message" 100//usage: "\n -m Get baud rate from modem's CONNECT status message"
@@ -181,15 +171,14 @@ static void parse_args(char **argv)
181 debug("after getopt\n"); 171 debug("after getopt\n");
182 172
183 /* We loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ 173 /* We loosen up a bit and accept both "baudrate tty" and "tty baudrate" */
184 G.tty = argv[0]; /* tty name */ 174 G.tty_name = argv[0];
185 ts = argv[1]; /* baud rate(s) */ 175 ts = argv[1]; /* baud rate(s) */
186 if (isdigit(argv[0][0])) { 176 if (isdigit(argv[0][0])) {
187 /* A number first, assume it's a speed (BSD style) */ 177 /* A number first, assume it's a speed (BSD style) */
188 G.tty = ts; /* tty name is in argv[1] */ 178 G.tty_name = ts; /* tty name is in argv[1] */
189 ts = argv[0]; /* baud rate(s) */ 179 ts = argv[0]; /* baud rate(s) */
190 } 180 }
191 parse_speeds(ts); 181 parse_speeds(ts);
192 applet_name = xasprintf("getty: %s", G.tty);
193 182
194 if (argv[2]) 183 if (argv[2])
195 xsetenv("TERM", argv[2]); 184 xsetenv("TERM", argv[2]);
@@ -201,42 +190,49 @@ static void parse_args(char **argv)
201static void open_tty(void) 190static void open_tty(void)
202{ 191{
203 /* Set up new standard input, unless we are given an already opened port */ 192 /* Set up new standard input, unless we are given an already opened port */
204 if (NOT_LONE_DASH(G.tty)) { 193 if (NOT_LONE_DASH(G.tty_name)) {
205 if (G.tty[0] != '/') 194 if (G.tty_name[0] != '/')
206 G.tty = xasprintf("/dev/%s", G.tty); /* will leak it */ 195 G.tty_name = xasprintf("/dev/%s", G.tty_name); /* will leak it */
207 196
208 /* Open the tty as standard input */ 197 /* Open the tty as standard input */
209 debug("open(2)\n"); 198 debug("open(2)\n");
210 close(0); 199 close(0);
211 xopen(G.tty, O_RDWR | O_NONBLOCK); /* uses fd 0 */ 200 xopen(G.tty_name, O_RDWR | O_NONBLOCK); /* uses fd 0 */
212 201
213 /* Set proper protections and ownership */ 202 /* Set proper protections and ownership */
214 fchown(0, 0, 0); /* 0:0 */ 203 fchown(0, 0, 0); /* 0:0 */
215 fchmod(0, 0620); /* crw--w---- */ 204 fchmod(0, 0620); /* crw--w---- */
216 } else { 205 } else {
206 char *n;
217 /* 207 /*
218 * Standard input should already be connected to an open port. Make 208 * Standard input should already be connected to an open port.
219 * sure it is open for read/write. 209 * Make sure it is open for read/write.
220 */ 210 */
221 if ((fcntl(0, F_GETFL) & (O_RDWR|O_RDONLY|O_WRONLY)) != O_RDWR) 211 if ((fcntl(0, F_GETFL) & (O_RDWR|O_RDONLY|O_WRONLY)) != O_RDWR)
222 bb_error_msg_and_die("stdin is not open for read/write"); 212 bb_error_msg_and_die("stdin is not open for read/write");
213
214 /* Try to get real tty name instead of "-" */
215 n = xmalloc_ttyname(0);
216 if (n)
217 G.tty_name = n;
223 } 218 }
219 applet_name = xasprintf("getty: %s", skip_dev_pfx(G.tty_name));
224} 220}
225 221
226static void set_termios(void) 222static void set_tty_attrs(void)
227{ 223{
228 if (tcsetattr_stdin_TCSANOW(&G.termios) < 0) 224 if (tcsetattr_stdin_TCSANOW(&G.tty_attrs) < 0)
229 bb_perror_msg_and_die("tcsetattr"); 225 bb_perror_msg_and_die("tcsetattr");
230} 226}
231 227
232/* We manipulate termios this way: 228/* We manipulate tty_attrs this way:
233 * - first, we read existing termios settings 229 * - first, we read existing tty_attrs
234 * - termios_init modifies some parts and sets it 230 * - init_tty_attrs modifies some parts and sets it
235 * - auto_baud and/or BREAK processing can set different speed and set termios 231 * - auto_baud and/or BREAK processing can set different speed and set tty attrs
236 * - termios_final again modifies some parts and sets termios before 232 * - finalize_tty_attrs again modifies some parts and sets tty attrs before
237 * execing login 233 * execing login
238 */ 234 */
239static void termios_init(int speed) 235static void init_tty_attrs(int speed)
240{ 236{
241 /* Try to drain output buffer, with 5 sec timeout. 237 /* Try to drain output buffer, with 5 sec timeout.
242 * Added on request from users of ~600 baud serial interface 238 * Added on request from users of ~600 baud serial interface
@@ -248,21 +244,20 @@ static void termios_init(int speed)
248 alarm(5); 244 alarm(5);
249 tcdrain(STDIN_FILENO); 245 tcdrain(STDIN_FILENO);
250 alarm(0); 246 alarm(0);
251 signal(SIGALRM, SIG_DFL); /* do not break -t TIMEOUT! */
252 247
253 /* Flush input and output queues, important for modems! */ 248 /* Flush input and output queues, important for modems! */
254 tcflush(STDIN_FILENO, TCIOFLUSH); 249 tcflush(STDIN_FILENO, TCIOFLUSH);
255 250
256 /* Set speed if it wasn't specified as "0" on command line */ 251 /* Set speed if it wasn't specified as "0" on command line */
257 if (speed != B0) 252 if (speed != B0)
258 cfsetspeed(&G.termios, speed); 253 cfsetspeed(&G.tty_attrs, speed);
259 254
260 /* Initial termios settings: 8-bit characters, raw mode, blocking i/o. 255 /* Initial settings: 8-bit characters, raw mode, blocking i/o.
261 * Special characters are set after we have read the login name; all 256 * Special characters are set after we have read the login name; all
262 * reads will be done in raw mode anyway. 257 * reads will be done in raw mode anyway.
263 */ 258 */
264 /* Clear all bits except: */ 259 /* Clear all bits except: */
265 G.termios.c_cflag &= (0 260 G.tty_attrs.c_cflag &= (0
266 /* 2 stop bits (1 otherwise) 261 /* 2 stop bits (1 otherwise)
267 * Enable parity bit (both on input and output) 262 * Enable parity bit (both on input and output)
268 * Odd parity (else even) 263 * Odd parity (else even)
@@ -271,7 +266,9 @@ static void termios_init(int speed)
271#ifdef CMSPAR 266#ifdef CMSPAR
272 | CMSPAR /* mark or space parity */ 267 | CMSPAR /* mark or space parity */
273#endif 268#endif
269#ifdef CBAUD
274 | CBAUD /* (output) baud rate */ 270 | CBAUD /* (output) baud rate */
271#endif
275#ifdef CBAUDEX 272#ifdef CBAUDEX
276 | CBAUDEX /* (output) baud rate */ 273 | CBAUDEX /* (output) baud rate */
277#endif 274#endif
@@ -280,42 +277,42 @@ static void termios_init(int speed)
280#endif 277#endif
281 ); 278 );
282 /* Set: 8 bits; hang up (drop DTR) on last close; enable receive */ 279 /* Set: 8 bits; hang up (drop DTR) on last close; enable receive */
283 G.termios.c_cflag |= CS8 | HUPCL | CREAD; 280 G.tty_attrs.c_cflag |= CS8 | HUPCL | CREAD;
284 if (option_mask32 & F_LOCAL) { 281 if (option_mask32 & F_LOCAL) {
285 /* ignore Carrier Detect pin: 282 /* ignore Carrier Detect pin:
286 * opens don't block when CD is low, 283 * opens don't block when CD is low,
287 * losing CD doesn't hang up processes whose ctty is this tty 284 * losing CD doesn't hang up processes whose ctty is this tty
288 */ 285 */
289 G.termios.c_cflag |= CLOCAL; 286 G.tty_attrs.c_cflag |= CLOCAL;
290 } 287 }
291#ifdef CRTSCTS 288#ifdef CRTSCTS
292 if (option_mask32 & F_RTSCTS) 289 if (option_mask32 & F_RTSCTS)
293 G.termios.c_cflag |= CRTSCTS; /* flow control using RTS/CTS pins */ 290 G.tty_attrs.c_cflag |= CRTSCTS; /* flow control using RTS/CTS pins */
294#endif 291#endif
295 G.termios.c_iflag = 0; 292 G.tty_attrs.c_iflag = 0;
296 G.termios.c_lflag = 0; 293 G.tty_attrs.c_lflag = 0;
297 /* non-raw output; add CR to each NL */ 294 /* non-raw output; add CR to each NL */
298 G.termios.c_oflag = OPOST | ONLCR; 295 G.tty_attrs.c_oflag = OPOST | ONLCR;
299 296
300 G.termios.c_cc[VMIN] = 1; /* block reads if < 1 char is available */ 297 G.tty_attrs.c_cc[VMIN] = 1; /* block reads if < 1 char is available */
301 G.termios.c_cc[VTIME] = 0; /* no timeout (reads block forever) */ 298 G.tty_attrs.c_cc[VTIME] = 0; /* no timeout (reads block forever) */
302#ifdef __linux__ 299#ifdef __linux__
303 G.termios.c_line = 0; 300 G.tty_attrs.c_line = 0;
304#endif 301#endif
305 302
306 set_termios(); 303 set_tty_attrs();
307 304
308 debug("term_io 2\n"); 305 debug("term_io 2\n");
309} 306}
310 307
311static void termios_final(void) 308static void finalize_tty_attrs(void)
312{ 309{
313 /* software flow control on output (stop sending if XOFF is recvd); 310 /* software flow control on output (stop sending if XOFF is recvd);
314 * and on input (send XOFF when buffer is full) 311 * and on input (send XOFF when buffer is full)
315 */ 312 */
316 G.termios.c_iflag |= IXON | IXOFF; 313 G.tty_attrs.c_iflag |= IXON | IXOFF;
317 if (G.eol == '\r') { 314 if (G.eol == '\r') {
318 G.termios.c_iflag |= ICRNL; /* map CR on input to NL */ 315 G.tty_attrs.c_iflag |= ICRNL; /* map CR on input to NL */
319 } 316 }
320 /* Other bits in c_iflag: 317 /* Other bits in c_iflag:
321 * IXANY Any recvd char enables output (any char is also a XON) 318 * IXANY Any recvd char enables output (any char is also a XON)
@@ -342,7 +339,7 @@ static void termios_final(void)
342 * echo kill char specially, not as ^c (ECHOKE controls how exactly); 339 * echo kill char specially, not as ^c (ECHOKE controls how exactly);
343 * erase all input via BS-SP-BS on kill char (else go to next line) 340 * erase all input via BS-SP-BS on kill char (else go to next line)
344 */ 341 */
345 G.termios.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; 342 G.tty_attrs.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE;
346 /* Other bits in c_lflag: 343 /* Other bits in c_lflag:
347 * XCASE Map uppercase to \lowercase [tried, doesn't work] 344 * XCASE Map uppercase to \lowercase [tried, doesn't work]
348 * ECHONL Echo NL even if ECHO is not set 345 * ECHONL Echo NL even if ECHO is not set
@@ -360,17 +357,17 @@ static void termios_final(void)
360 * (why "stty sane" unsets this bit?) 357 * (why "stty sane" unsets this bit?)
361 */ 358 */
362 359
363 G.termios.c_cc[VINTR] = DEF_INTR; 360 G.tty_attrs.c_cc[VINTR] = CTL('C');
364 G.termios.c_cc[VQUIT] = DEF_QUIT; 361 G.tty_attrs.c_cc[VQUIT] = CTL('\\');
365 G.termios.c_cc[VEOF] = DEF_EOF; 362 G.tty_attrs.c_cc[VEOF] = CTL('D');
366 G.termios.c_cc[VEOL] = DEF_EOL; 363 G.tty_attrs.c_cc[VEOL] = '\n';
367#ifdef VSWTC 364#ifdef VSWTC
368 G.termios.c_cc[VSWTC] = DEF_SWITCH; 365 G.tty_attrs.c_cc[VSWTC] = 0;
369#endif 366#endif
370#ifdef VSWTCH 367#ifdef VSWTCH
371 G.termios.c_cc[VSWTCH] = DEF_SWITCH; 368 G.tty_attrs.c_cc[VSWTCH] = 0;
372#endif 369#endif
373 G.termios.c_cc[VKILL] = DEF_KILL; 370 G.tty_attrs.c_cc[VKILL] = CTL('U');
374 /* Other control chars: 371 /* Other control chars:
375 * VEOL2 372 * VEOL2
376 * VERASE, VWERASE - (word) erase. we may set VERASE in get_logname 373 * VERASE, VWERASE - (word) erase. we may set VERASE in get_logname
@@ -380,7 +377,10 @@ static void termios_final(void)
380 * VSTART, VSTOP - chars used for IXON/IXOFF 377 * VSTART, VSTOP - chars used for IXON/IXOFF
381 */ 378 */
382 379
383 set_termios(); 380 set_tty_attrs();
381
382 /* Now the newline character should be properly written */
383 full_write(STDOUT_FILENO, "\n", 1);
384} 384}
385 385
386/* extract baud rate from modem status message */ 386/* extract baud rate from modem status message */
@@ -403,8 +403,8 @@ static void auto_baud(void)
403 * modem status messages is enabled. 403 * modem status messages is enabled.
404 */ 404 */
405 405
406 G.termios.c_cc[VMIN] = 0; /* don't block reads (min read is 0 chars) */ 406 G.tty_attrs.c_cc[VMIN] = 0; /* don't block reads (min read is 0 chars) */
407 set_termios(); 407 set_tty_attrs();
408 408
409 /* 409 /*
410 * Wait for a while, then read everything the modem has said so far and 410 * Wait for a while, then read everything the modem has said so far and
@@ -420,15 +420,15 @@ static void auto_baud(void)
420 if (isdigit(*bp)) { 420 if (isdigit(*bp)) {
421 speed = bcode(bp); 421 speed = bcode(bp);
422 if (speed > 0) 422 if (speed > 0)
423 cfsetspeed(&G.termios, speed); 423 cfsetspeed(&G.tty_attrs, speed);
424 break; 424 break;
425 } 425 }
426 } 426 }
427 } 427 }
428 428
429 /* Restore terminal settings */ 429 /* Restore terminal settings */
430 G.termios.c_cc[VMIN] = 1; /* restore to value set by termios_init */ 430 G.tty_attrs.c_cc[VMIN] = 1; /* restore to value set by init_tty_attrs */
431 set_termios(); 431 set_tty_attrs();
432} 432}
433 433
434/* get user name, establish parity, speed, erase, kill, eol; 434/* get user name, establish parity, speed, erase, kill, eol;
@@ -444,42 +444,35 @@ static char *get_logname(void)
444 tcflush(STDIN_FILENO, TCIFLUSH); 444 tcflush(STDIN_FILENO, TCIFLUSH);
445 445
446 /* Prompt for and read a login name */ 446 /* Prompt for and read a login name */
447 G.line_buf[0] = '\0'; 447 do {
448 while (!G.line_buf[0]) {
449 /* Write issue file and prompt */ 448 /* Write issue file and prompt */
450#ifdef ISSUE 449#ifdef ISSUE
451 if (!(option_mask32 & F_NOISSUE)) 450 if (!(option_mask32 & F_NOISSUE))
452 print_login_issue(G.issue, G.tty); 451 print_login_issue(G.issue, G.tty_name);
453#endif 452#endif
454 print_login_prompt(); 453 print_login_prompt();
455 454
456 /* Read name, watch for break, parity, erase, kill, end-of-line */ 455 /* Read name, watch for break, erase, kill, end-of-line */
457 bp = G.line_buf; 456 bp = G.line_buf;
458 G.eol = '\0';
459 while (1) { 457 while (1) {
460 /* Do not report trivial EINTR/EIO errors */ 458 /* Do not report trivial EINTR/EIO errors */
461 errno = EINTR; /* make read of 0 bytes be silent too */ 459 errno = EINTR; /* make read of 0 bytes be silent too */
462 if (read(STDIN_FILENO, &c, 1) < 1) { 460 if (read(STDIN_FILENO, &c, 1) < 1) {
461 finalize_tty_attrs();
463 if (errno == EINTR || errno == EIO) 462 if (errno == EINTR || errno == EIO)
464 exit(EXIT_SUCCESS); 463 exit(EXIT_SUCCESS);
465 bb_perror_msg_and_die(bb_msg_read_error); 464 bb_perror_msg_and_die(bb_msg_read_error);
466 } 465 }
467 466
468 /* BREAK. If we have speeds to try,
469 * return NULL (will switch speeds and return here) */
470 if (c == '\0' && G.numspeed > 1)
471 return NULL;
472
473 /* Do erase, kill and end-of-line processing */
474 switch (c) { 467 switch (c) {
475 case '\r': 468 case '\r':
476 case '\n': 469 case '\n':
477 *bp = '\0'; 470 *bp = '\0';
478 G.eol = c; 471 G.eol = c;
479 goto got_logname; 472 goto got_logname;
480 case BS: 473 case CTL('H'):
481 case DEL: 474 case 0x7f:
482 G.termios.c_cc[VERASE] = c; 475 G.tty_attrs.c_cc[VERASE] = c;
483 if (bp > G.line_buf) { 476 if (bp > G.line_buf) {
484 full_write(STDOUT_FILENO, "\010 \010", 3); 477 full_write(STDOUT_FILENO, "\010 \010", 3);
485 bp--; 478 bp--;
@@ -491,8 +484,16 @@ static char *get_logname(void)
491 bp--; 484 bp--;
492 } 485 }
493 break; 486 break;
487 case CTL('C'):
494 case CTL('D'): 488 case CTL('D'):
489 finalize_tty_attrs();
495 exit(EXIT_SUCCESS); 490 exit(EXIT_SUCCESS);
491 case '\0':
492 /* BREAK. If we have speeds to try,
493 * return NULL (will switch speeds and return here) */
494 if (G.numspeed > 1)
495 return NULL;
496 /* fall through and ignore it */
496 default: 497 default:
497 if ((unsigned char)c < ' ') { 498 if ((unsigned char)c < ' ') {
498 /* ignore garbage characters */ 499 /* ignore garbage characters */
@@ -505,16 +506,22 @@ static char *get_logname(void)
505 } 506 }
506 } /* end of get char loop */ 507 } /* end of get char loop */
507 got_logname: ; 508 got_logname: ;
508 } /* while logname is empty */ 509 } while (G.line_buf[0] == '\0'); /* while logname is empty */
509 510
510 return G.line_buf; 511 return G.line_buf;
511} 512}
512 513
514static void alarm_handler(int sig UNUSED_PARAM)
515{
516 finalize_tty_attrs();
517 _exit(EXIT_SUCCESS);
518}
519
513int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 520int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
514int getty_main(int argc UNUSED_PARAM, char **argv) 521int getty_main(int argc UNUSED_PARAM, char **argv)
515{ 522{
516 int n; 523 int n;
517 pid_t pid; 524 pid_t pid, tsid;
518 char *logname; 525 char *logname;
519 526
520 INIT_G(); 527 INIT_G();
@@ -527,14 +534,37 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
527 /* Parse command-line arguments */ 534 /* Parse command-line arguments */
528 parse_args(argv); 535 parse_args(argv);
529 536
530 logmode = LOGMODE_NONE; 537 /* Create new session and pgrp, lose controlling tty */
538 pid = setsid(); /* this also gives us our pid :) */
539 if (pid < 0) {
540 int fd;
541 /* :(
542 * docs/ctty.htm says:
543 * "This is allowed only when the current process
544 * is not a process group leader".
545 * Thus, setsid() will fail if we _already_ are
546 * a session leader - which is quite possible for getty!
547 */
548 pid = getpid();
549 if (getsid(0) != pid)
550 bb_perror_msg_and_die("setsid");
551 /* Looks like we are already a session leader.
552 * In this case (setsid failed) we may still have ctty,
553 * and it may be different from tty we need to control!
554 * If we still have ctty, on Linux ioctl(TIOCSCTTY)
555 * (which we are going to use a bit later) always fails -
556 * even if we try to take ctty which is already ours!
557 * Try to drop old ctty now to prevent that.
558 * Use O_NONBLOCK: old ctty may be a serial line.
559 */
560 fd = open("/dev/tty", O_RDWR | O_NONBLOCK);
561 if (fd >= 0) {
562 ioctl(fd, TIOCNOTTY);
563 close(fd);
564 }
565 }
531 566
532 /* Create new session, lose controlling tty, if any */ 567 /* Close stdio, and stray descriptors, just in case */
533 /* docs/ctty.htm says:
534 * "This is allowed only when the current process
535 * is not a process group leader" - is this a problem? */
536 setsid();
537 /* close stdio, and stray descriptors, just in case */
538 n = xopen(bb_dev_null, O_RDWR); 568 n = xopen(bb_dev_null, O_RDWR);
539 /* dup2(n, 0); - no, we need to handle "getty - 9600" too */ 569 /* dup2(n, 0); - no, we need to handle "getty - 9600" too */
540 xdup2(n, 1); 570 xdup2(n, 1);
@@ -558,13 +588,25 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
558#endif 588#endif
559 589
560 /* Open the tty as standard input, if it is not "-" */ 590 /* Open the tty as standard input, if it is not "-" */
561 /* If it's not "-" and not taken yet, it will become our ctty */
562 debug("calling open_tty\n"); 591 debug("calling open_tty\n");
563 open_tty(); 592 open_tty();
564 ndelay_off(0); 593 ndelay_off(STDIN_FILENO);
565 debug("duping\n"); 594 debug("duping\n");
566 xdup2(0, 1); 595 xdup2(STDIN_FILENO, 1);
567 xdup2(0, 2); 596 xdup2(STDIN_FILENO, 2);
597
598 /* Steal ctty if we don't have it yet */
599 tsid = tcgetsid(STDIN_FILENO);
600 if (tsid < 0 || pid != tsid) {
601 if (ioctl(STDIN_FILENO, TIOCSCTTY, /*force:*/ (long)1) < 0)
602 bb_perror_msg_and_die("TIOCSCTTY");
603 }
604
605#ifdef __linux__
606 /* Make ourself a foreground process group within our session */
607 if (tcsetpgrp(STDIN_FILENO, pid) < 0)
608 bb_perror_msg_and_die("tcsetpgrp");
609#endif
568 610
569 /* 611 /*
570 * The following ioctl will fail if stdin is not a tty, but also when 612 * The following ioctl will fail if stdin is not a tty, but also when
@@ -574,25 +616,15 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
574 * by patching the SunOS kernel variable "zsadtrlow" to a larger value; 616 * by patching the SunOS kernel variable "zsadtrlow" to a larger value;
575 * 5 seconds seems to be a good value. 617 * 5 seconds seems to be a good value.
576 */ 618 */
577 if (tcgetattr(STDIN_FILENO, &G.termios) < 0) 619 if (tcgetattr(STDIN_FILENO, &G.tty_attrs) < 0)
578 bb_perror_msg_and_die("tcgetattr"); 620 bb_perror_msg_and_die("tcgetattr");
579 621
580 pid = getpid();
581#ifdef __linux__
582// FIXME: do we need this? Otherwise "-" case seems to be broken...
583 // /* Forcibly make fd 0 our controlling tty, even if another session
584 // * has it as a ctty. (Another session loses ctty). */
585 // ioctl(STDIN_FILENO, TIOCSCTTY, (void*)1);
586 /* Make ourself a foreground process group within our session */
587 tcsetpgrp(STDIN_FILENO, pid);
588#endif
589
590 /* Update the utmp file. This tty is ours now! */ 622 /* Update the utmp file. This tty is ours now! */
591 update_utmp(pid, LOGIN_PROCESS, G.tty, "LOGIN", G.fakehost); 623 update_utmp(pid, LOGIN_PROCESS, G.tty_name, "LOGIN", G.fakehost);
592 624
593 /* Initialize the termios settings (raw mode, eight-bit, blocking i/o) */ 625 /* Initialize tty attrs (raw mode, eight-bit, blocking i/o) */
594 debug("calling termios_init\n"); 626 debug("calling init_tty_attrs\n");
595 termios_init(G.speeds[0]); 627 init_tty_attrs(G.speeds[0]);
596 628
597 /* Write the modem init string and DON'T flush the buffers */ 629 /* Write the modem init string and DON'T flush the buffers */
598 if (option_mask32 & F_INITSTRING) { 630 if (option_mask32 & F_INITSTRING) {
@@ -606,8 +638,8 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
606 auto_baud(); 638 auto_baud();
607 639
608 /* Set the optional timer */ 640 /* Set the optional timer */
641 signal(SIGALRM, alarm_handler);
609 alarm(G.timeout); /* if 0, alarm is not set */ 642 alarm(G.timeout); /* if 0, alarm is not set */
610//BUG: death by signal won't restore termios
611 643
612 /* Optionally wait for CR or LF before writing /etc/issue */ 644 /* Optionally wait for CR or LF before writing /etc/issue */
613 if (option_mask32 & F_WAITCRLF) { 645 if (option_mask32 & F_WAITCRLF) {
@@ -622,7 +654,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
622 654
623 logname = NULL; 655 logname = NULL;
624 if (!(option_mask32 & F_NOPROMPT)) { 656 if (!(option_mask32 & F_NOPROMPT)) {
625 /* NB: termios_init already set line speed 657 /* NB: init_tty_attrs already set line speed
626 * to G.speeds[0] */ 658 * to G.speeds[0] */
627 int baud_index = 0; 659 int baud_index = 0;
628 660
@@ -634,19 +666,15 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
634 break; 666 break;
635 /* We are here only if G.numspeed > 1 */ 667 /* We are here only if G.numspeed > 1 */
636 baud_index = (baud_index + 1) % G.numspeed; 668 baud_index = (baud_index + 1) % G.numspeed;
637 cfsetspeed(&G.termios, G.speeds[baud_index]); 669 cfsetspeed(&G.tty_attrs, G.speeds[baud_index]);
638 set_termios(); 670 set_tty_attrs();
639 } 671 }
640 } 672 }
641 673
642 /* Disable timer */ 674 /* Disable timer */
643 alarm(0); 675 alarm(0);
644 676
645 /* Finalize the termios settings */ 677 finalize_tty_attrs();
646 termios_final();
647
648 /* Now the newline character should be properly written */
649 full_write(STDOUT_FILENO, "\n", 1);
650 678
651 /* Let the login program take care of password validation */ 679 /* Let the login program take care of password validation */
652 /* We use PATH because we trust that root doesn't set "bad" PATH, 680 /* We use PATH because we trust that root doesn't set "bad" PATH,
diff --git a/loginutils/login.c b/loginutils/login.c
index 2f7b9b212..73db8fa63 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -41,7 +41,12 @@ enum {
41 TTYNAME_SIZE = 32, 41 TTYNAME_SIZE = 32,
42}; 42};
43 43
44static char* short_tty; 44struct globals {
45 struct termios tty_attrs;
46} FIX_ALIASING;
47#define G (*(struct globals*)&bb_common_bufsiz1)
48#define INIT_G() do { } while (0)
49
45 50
46#if ENABLE_FEATURE_NOLOGIN 51#if ENABLE_FEATURE_NOLOGIN
47static void die_if_nologin(void) 52static void die_if_nologin(void)
@@ -74,7 +79,7 @@ static void die_if_nologin(void)
74#endif 79#endif
75 80
76#if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM 81#if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM
77static int check_securetty(void) 82static int check_securetty(const char *short_tty)
78{ 83{
79 char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */ 84 char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */
80 parser_t *parser = config_open2("/etc/securetty", fopen_for_read); 85 parser_t *parser = config_open2("/etc/securetty", fopen_for_read);
@@ -89,7 +94,7 @@ static int check_securetty(void)
89 return buf != NULL; 94 return buf != NULL;
90} 95}
91#else 96#else
92static ALWAYS_INLINE int check_securetty(void) { return 1; } 97static ALWAYS_INLINE int check_securetty(const char *short_tty UNUSED_PARAM) { return 1; }
93#endif 98#endif
94 99
95#if ENABLE_SELINUX 100#if ENABLE_SELINUX
@@ -142,6 +147,29 @@ static void run_login_script(struct passwd *pw, char *full_tty)
142void run_login_script(struct passwd *pw, char *full_tty); 147void run_login_script(struct passwd *pw, char *full_tty);
143#endif 148#endif
144 149
150#if ENABLE_LOGIN_SESSION_AS_CHILD && ENABLE_PAM
151static void login_pam_end(pam_handle_t *pamh)
152{
153 int pamret;
154
155 pamret = pam_setcred(pamh, PAM_DELETE_CRED);
156 if (pamret != PAM_SUCCESS) {
157 bb_error_msg("pam_%s failed: %s (%d)", "setcred",
158 pam_strerror(pamh, pamret), pamret);
159 }
160 pamret = pam_close_session(pamh, 0);
161 if (pamret != PAM_SUCCESS) {
162 bb_error_msg("pam_%s failed: %s (%d)", "close_session",
163 pam_strerror(pamh, pamret), pamret);
164 }
165 pamret = pam_end(pamh, pamret);
166 if (pamret != PAM_SUCCESS) {
167 bb_error_msg("pam_%s failed: %s (%d)", "end",
168 pam_strerror(pamh, pamret), pamret);
169 }
170}
171#endif /* ENABLE_PAM */
172
145static void get_username_or_die(char *buf, int size_buf) 173static void get_username_or_die(char *buf, int size_buf)
146{ 174{
147 int c, cntdown; 175 int c, cntdown;
@@ -185,15 +213,21 @@ static void motd(void)
185 213
186static void alarm_handler(int sig UNUSED_PARAM) 214static void alarm_handler(int sig UNUSED_PARAM)
187{ 215{
188 /* This is the escape hatch! Poor serial line users and the like 216 /* This is the escape hatch! Poor serial line users and the like
189 * arrive here when their connection is broken. 217 * arrive here when their connection is broken.
190 * We don't want to block here */ 218 * We don't want to block here */
191 ndelay_on(1); 219 ndelay_on(STDOUT_FILENO);
192 printf("\r\nLogin timed out after %d seconds\r\n", TIMEOUT); 220 /* Test for correct attr restoring:
221 * run "getty 0 -" from a shell, enter bogus username, stop at
222 * password prompt, let it time out. Without the tcsetattr below,
223 * when you are back at shell prompt, echo will be still off.
224 */
225 tcsetattr_stdin_TCSANOW(&G.tty_attrs);
226 printf("\r\nLogin timed out after %u seconds\r\n", TIMEOUT);
193 fflush_all(); 227 fflush_all();
194 /* unix API is brain damaged regarding O_NONBLOCK, 228 /* unix API is brain damaged regarding O_NONBLOCK,
195 * we should undo it, or else we can affect other processes */ 229 * we should undo it, or else we can affect other processes */
196 ndelay_off(1); 230 ndelay_off(STDOUT_FILENO);
197 _exit(EXIT_SUCCESS); 231 _exit(EXIT_SUCCESS);
198} 232}
199 233
@@ -214,6 +248,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
214 char *opt_host = NULL; 248 char *opt_host = NULL;
215 char *opt_user = opt_user; /* for compiler */ 249 char *opt_user = opt_user; /* for compiler */
216 char *full_tty; 250 char *full_tty;
251 char *short_tty;
217 IF_SELINUX(security_context_t user_sid = NULL;) 252 IF_SELINUX(security_context_t user_sid = NULL;)
218#if ENABLE_PAM 253#if ENABLE_PAM
219 int pamret; 254 int pamret;
@@ -224,10 +259,11 @@ int login_main(int argc UNUSED_PARAM, char **argv)
224 char pwdbuf[256]; 259 char pwdbuf[256];
225 char **pamenv; 260 char **pamenv;
226#endif 261#endif
262#if ENABLE_LOGIN_SESSION_AS_CHILD
263 pid_t child_pid;
264#endif
227 265
228 username[0] = '\0'; 266 INIT_G();
229 signal(SIGALRM, alarm_handler);
230 alarm(TIMEOUT);
231 267
232 /* More of suid paranoia if called by non-root: */ 268 /* More of suid paranoia if called by non-root: */
233 /* Clear dangerous stuff, set PATH */ 269 /* Clear dangerous stuff, set PATH */
@@ -239,6 +275,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
239 * (The name of the function is misleading. Not daemonizing here.) */ 275 * (The name of the function is misleading. Not daemonizing here.) */
240 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL); 276 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL);
241 277
278 username[0] = '\0';
242 opt = getopt32(argv, "f:h:p", &opt_user, &opt_host); 279 opt = getopt32(argv, "f:h:p", &opt_user, &opt_host);
243 if (opt & LOGIN_OPT_f) { 280 if (opt & LOGIN_OPT_f) {
244 if (!run_by_root) 281 if (!run_by_root)
@@ -249,9 +286,19 @@ int login_main(int argc UNUSED_PARAM, char **argv)
249 if (argv[0]) /* user from command line (getty) */ 286 if (argv[0]) /* user from command line (getty) */
250 safe_strncpy(username, argv[0], sizeof(username)); 287 safe_strncpy(username, argv[0], sizeof(username));
251 288
252 /* Let's find out and memorize our tty */ 289 /* Save tty attributes - and by doing it, check that it's indeed a tty */
253 if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO)) 290 if (tcgetattr(STDIN_FILENO, &G.tty_attrs) < 0
291 || !isatty(STDOUT_FILENO)
292 /*|| !isatty(STDERR_FILENO) - no, guess some people might want to redirect this */
293 ) {
254 return EXIT_FAILURE; /* Must be a terminal */ 294 return EXIT_FAILURE; /* Must be a terminal */
295 }
296
297 /* We install timeout handler only _after_ we saved G.tty_attrs */
298 signal(SIGALRM, alarm_handler);
299 alarm(TIMEOUT);
300
301 /* Find out and memorize our tty name */
255 full_tty = xmalloc_ttyname(STDIN_FILENO); 302 full_tty = xmalloc_ttyname(STDIN_FILENO);
256 if (!full_tty) 303 if (!full_tty)
257 full_tty = xstrdup("UNKNOWN"); 304 full_tty = xstrdup("UNKNOWN");
@@ -359,14 +406,17 @@ int login_main(int argc UNUSED_PARAM, char **argv)
359 if (opt & LOGIN_OPT_f) 406 if (opt & LOGIN_OPT_f)
360 break; /* -f USER: success without asking passwd */ 407 break; /* -f USER: success without asking passwd */
361 408
362 if (pw->pw_uid == 0 && !check_securetty()) 409 if (pw->pw_uid == 0 && !check_securetty(short_tty))
363 goto auth_failed; 410 goto auth_failed;
364 411
365 /* Don't check the password if password entry is empty (!) */ 412 /* Don't check the password if password entry is empty (!) */
366 if (!pw->pw_passwd[0]) 413 if (!pw->pw_passwd[0])
367 break; 414 break;
368 fake_it: 415 fake_it:
369 /* authorization takes place here */ 416 /* Password reading and authorization takes place here.
417 * Note that reads (in no-echo mode) trash tty attributes.
418 * If we get interrupted by SIGALRM, we need to restore attrs.
419 */
370 if (correct_password(pw)) 420 if (correct_password(pw))
371 break; 421 break;
372#endif /* ENABLE_PAM */ 422#endif /* ENABLE_PAM */
@@ -393,7 +443,22 @@ int login_main(int argc UNUSED_PARAM, char **argv)
393 if (pw->pw_uid != 0) 443 if (pw->pw_uid != 0)
394 die_if_nologin(); 444 die_if_nologin();
395 445
396 IF_SELINUX(initselinux(username, full_tty, &user_sid)); 446#if ENABLE_LOGIN_SESSION_AS_CHILD
447 child_pid = vfork();
448 if (child_pid != 0) {
449 if (child_pid < 0)
450 bb_perror_msg("vfork");
451 else {
452 if (safe_waitpid(child_pid, NULL, 0) == -1)
453 bb_perror_msg("waitpid");
454 update_utmp(child_pid, DEAD_PROCESS, NULL, NULL, NULL);
455 }
456 IF_PAM(login_pam_end(pamh);)
457 return 0;
458 }
459#endif
460
461 IF_SELINUX(initselinux(username, full_tty, &user_sid);)
397 462
398 /* Try these, but don't complain if they fail. 463 /* Try these, but don't complain if they fail.
399 * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */ 464 * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */
diff --git a/mailutils/mail.c b/mailutils/mail.c
index 66c79471f..f5260d9db 100644
--- a/mailutils/mail.c
+++ b/mailutils/mail.c
@@ -57,10 +57,13 @@ void FAST_FUNC launch_helper(const char **argv)
57 G.helper_pid = xvfork(); 57 G.helper_pid = xvfork();
58 58
59 i = (!G.helper_pid) * 2; // for parent:0, for child:2 59 i = (!G.helper_pid) * 2; // for parent:0, for child:2
60 close(pipes[i + 1]); // 1 or 3 - closing one write end 60 close(pipes[i + 1]); // 1 or 3 - closing one write end
61 close(pipes[2 - i]); // 2 or 0 - closing one read end 61 close(pipes[2 - i]); // 2 or 0 - closing one read end
62 xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end 62 xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end
63 xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - other write end 63 xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - using other write end
64 // End result:
65 // parent stdout [3] -> child stdin [2]
66 // child stdout [1] -> parent stdin [0]
64 67
65 if (!G.helper_pid) { 68 if (!G.helper_pid) {
66 // child: try to execute connection helper 69 // child: try to execute connection helper
diff --git a/mailutils/makemime.c b/mailutils/makemime.c
index 4dc53a3b2..a9ff03d03 100644
--- a/mailutils/makemime.c
+++ b/mailutils/makemime.c
@@ -164,7 +164,7 @@ int makemime_main(int argc UNUSED_PARAM, char **argv)
164 // parse options 164 // parse options
165 opt_complementary = "a::"; 165 opt_complementary = "a::";
166 opts = getopt32(argv, 166 opts = getopt32(argv,
167 "c:e:o:C:N:a", //:m:j:", 167 "c:e:o:C:N:a:", //:m:j:",
168 &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL 168 &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL
169 ); 169 );
170 //argc -= optind; 170 //argc -= optind;
diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c
index e0aff20fb..dbd491002 100644
--- a/mailutils/sendmail.c
+++ b/mailutils/sendmail.c
@@ -26,18 +26,18 @@
26//usage: "\n Examples:" 26//usage: "\n Examples:"
27//usage: "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp" 27//usage: "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp"
28//usage: "\n -connect smtp.gmail.com:25' <email.txt" 28//usage: "\n -connect smtp.gmail.com:25' <email.txt"
29//usage: "\n [4<username_and_passwd.txt | -au<username> -ap<password>]" 29//usage: "\n [4<username_and_passwd.txt | -auUSER -apPASS]"
30//usage: "\n -H 'exec openssl s_client -quiet -tls1" 30//usage: "\n -H 'exec openssl s_client -quiet -tls1"
31//usage: "\n -connect smtp.gmail.com:465' <email.txt" 31//usage: "\n -connect smtp.gmail.com:465' <email.txt"
32//usage: "\n [4<username_and_passwd.txt | -au<username> -ap<password>]" 32//usage: "\n [4<username_and_passwd.txt | -auUSER -apPASS]"
33//usage: "\n -S HOST[:PORT] Server" 33//usage: "\n -S HOST[:PORT] Server"
34//usage: "\n -au<username> Username for AUTH LOGIN" 34//usage: "\n -auUSER Username for AUTH LOGIN"
35//usage: "\n -ap<password> Password for AUTH LOGIN" 35//usage: "\n -apPASS Password for AUTH LOGIN"
36//usage: "\n -am<method> Authentication method. Ignored. LOGIN is implied" 36////usage: "\n -amMETHOD Authentication method. Ignored. LOGIN is implied"
37//usage: "\n" 37//usage: "\n"
38//usage: "\nOther options are silently ignored; -oi -t is implied" 38//usage: "\nOther options are silently ignored; -oi -t is implied"
39//usage: IF_MAKEMIME( 39//usage: IF_MAKEMIME(
40//usage: "\nUse makemime applet to create message with attachments" 40//usage: "\nUse makemime to create emails with attachments"
41//usage: ) 41//usage: )
42 42
43#include "libbb.h" 43#include "libbb.h"
@@ -66,7 +66,7 @@ static int smtp_checkp(const char *fmt, const char *param, int code)
66 // if not equal -> die saying msg 66 // if not equal -> die saying msg
67 while ((answer = xmalloc_fgetline(stdin)) != NULL) { 67 while ((answer = xmalloc_fgetline(stdin)) != NULL) {
68 if (verbose) 68 if (verbose)
69 bb_error_msg("recv:'%.*s' %d", (int)(strchrnul(answer, '\r') - answer), answer, verbose); 69 bb_error_msg("recv:'%.*s'", (int)(strchrnul(answer, '\r') - answer), answer);
70 if (strlen(answer) <= 3 || '-' != answer[3]) 70 if (strlen(answer) <= 3 || '-' != answer[3])
71 break; 71 break;
72 free(answer); 72 free(answer);
@@ -75,10 +75,11 @@ static int smtp_checkp(const char *fmt, const char *param, int code)
75 int n = atoi(answer); 75 int n = atoi(answer);
76 if (timeout) 76 if (timeout)
77 alarm(0); 77 alarm(0);
78 free(msg);
79 free(answer); 78 free(answer);
80 if (-1 == code || n == code) 79 if (-1 == code || n == code) {
80 free(msg);
81 return n; 81 return n;
82 }
82 } 83 }
83 bb_error_msg_and_die("%s failed", msg); 84 bb_error_msg_and_die("%s failed", msg);
84} 85}
@@ -176,11 +177,35 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
176 const char *args[] = { "sh", "-c", opt_connect, NULL }; 177 const char *args[] = { "sh", "-c", opt_connect, NULL };
177 // plug it in 178 // plug it in
178 launch_helper(args); 179 launch_helper(args);
179 // vanilla connection 180 // Now:
181 // our stdout will go to helper's stdin,
182 // helper's stdout will be available on our stdin.
183
184 // Wait for initial server message.
185 // If helper (such as openssl) invokes STARTTLS, the initial 220
186 // is swallowed by helper (and not repeated after TLS is initiated).
187 // We will send NOOP cmd to server and check the response.
188 // We should get 220+250 on plain connection, 250 on STARTTLSed session.
189 //
190 // The problem here is some servers delay initial 220 message,
191 // and consider client to be a spammer if it starts sending cmds
192 // before 220 reached it. The code below is unsafe in this regard:
193 // in non-STARTTLSed case, we potentially send NOOP before 220
194 // is sent by server.
195 // Ideas? (--delay SECS opt? --assume-starttls-helper opt?)
196 code = smtp_check("NOOP", -1);
197 if (code == 220)
198 // we got 220 - this is not STARTTLSed connection,
199 // eat 250 response to our NOOP
200 smtp_check(NULL, 250);
201 else
202 if (code != 250)
203 bb_error_msg_and_die("SMTP init failed");
180 } else { 204 } else {
205 // vanilla connection
181 int fd; 206 int fd;
182 // host[:port] not explicitly specified? -> use $SMTPHOST 207 // host[:port] not explicitly specified? -> use $SMTPHOST
183 // no $SMTPHOST ? -> use localhost 208 // no $SMTPHOST? -> use localhost
184 if (!(opts & OPT_S)) { 209 if (!(opts & OPT_S)) {
185 opt_connect = getenv("SMTPHOST"); 210 opt_connect = getenv("SMTPHOST");
186 if (!opt_connect) 211 if (!opt_connect)
@@ -191,25 +216,14 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
191 // and make ourselves a simple IO filter 216 // and make ourselves a simple IO filter
192 xmove_fd(fd, STDIN_FILENO); 217 xmove_fd(fd, STDIN_FILENO);
193 xdup2(STDIN_FILENO, STDOUT_FILENO); 218 xdup2(STDIN_FILENO, STDOUT_FILENO);
194 }
195 // N.B. from now we know nothing about network :)
196 219
197 // wait for initial server OK 220 // Wait for initial server 220 message
198 // N.B. if we used openssl the initial 220 answer is already swallowed during openssl TLS init procedure 221 smtp_check(NULL, 220);
199 // so we need to kick the server to see whether we are ok 222 }
200 code = smtp_check("NOOP", -1);
201 // 220 on plain connection, 250 on openssl-helped TLS session
202 if (220 == code)
203 smtp_check(NULL, 250); // reread the code to stay in sync
204 else if (250 != code)
205 bb_error_msg_and_die("INIT failed");
206 223
207 // we should start with modern EHLO 224 // we should start with modern EHLO
208 if (250 != smtp_checkp("EHLO %s", domain, -1)) { 225 if (250 != smtp_checkp("EHLO %s", domain, -1))
209 smtp_checkp("HELO %s", domain, 250); 226 smtp_checkp("HELO %s", domain, 250);
210 }
211 if (ENABLE_FEATURE_CLEAN_UP)
212 free(domain);
213 227
214 // perform authentication 228 // perform authentication
215 if (opts & OPT_a) { 229 if (opts & OPT_a) {
@@ -224,7 +238,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
224 } 238 }
225 239
226 // set sender 240 // set sender
227 // N.B. we have here a very loosely defined algotythm 241 // N.B. we have here a very loosely defined algorythm
228 // since sendmail historically offers no means to specify secrets on cmdline. 242 // since sendmail historically offers no means to specify secrets on cmdline.
229 // 1) server can require no authentication -> 243 // 1) server can require no authentication ->
230 // we must just provide a (possibly fake) reply address. 244 // we must just provide a (possibly fake) reply address.
@@ -241,8 +255,6 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
241 // G.user = xuid2uname(getuid()); 255 // G.user = xuid2uname(getuid());
242 // opt_from = xasprintf("%s@%s", G.user, domain); 256 // opt_from = xasprintf("%s@%s", G.user, domain);
243 //} 257 //}
244 //if (ENABLE_FEATURE_CLEAN_UP)
245 // free(domain);
246 smtp_checkp("MAIL FROM:<%s>", opt_from, 250); 258 smtp_checkp("MAIL FROM:<%s>", opt_from, 250);
247 259
248 // process message 260 // process message
@@ -272,26 +284,26 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
272 if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { 284 if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) {
273 rcptto(sane_address(s+3)); 285 rcptto(sane_address(s+3));
274 goto addheader; 286 goto addheader;
287 }
275 // Bcc: header adds blind copy (hidden) recipient 288 // Bcc: header adds blind copy (hidden) recipient
276 } else if (0 == strncasecmp("Bcc:", s, 4)) { 289 if (0 == strncasecmp("Bcc:", s, 4)) {
277 rcptto(sane_address(s+4)); 290 rcptto(sane_address(s+4));
278 free(s); 291 free(s);
279 // N.B. Bcc: vanishes from headers! 292 // N.B. Bcc: vanishes from headers!
280 293 } else
281 // other headers go verbatim 294 if (strchr(s, ':') || (list && skip_whitespace(s) != s)) {
282 295 // other headers go verbatim
283 // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. 296 // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines.
284 // Continuation is denoted by prefixing additional lines with whitespace(s). 297 // Continuation is denoted by prefixing additional lines with whitespace(s).
285 // Thanks (stefan.seyfried at googlemail.com) for pointing this out. 298 // Thanks (stefan.seyfried at googlemail.com) for pointing this out.
286 } else if (strchr(s, ':') || (list && skip_whitespace(s) != s)) {
287 addheader: 299 addheader:
288 // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks 300 // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks
289 if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) 301 if (MAX_HEADERS && ++nheaders >= MAX_HEADERS)
290 goto bail; 302 goto bail;
291 llist_add_to_end(&list, s); 303 llist_add_to_end(&list, s);
292 // a line without ":" (an empty line too, by definition) doesn't look like a valid header
293 // so stop "analyze headers" mode
294 } else { 304 } else {
305 // a line without ":" (an empty line too, by definition) doesn't look like a valid header
306 // so stop "analyze headers" mode
295 reenter: 307 reenter:
296 // put recipients specified on cmdline 308 // put recipients specified on cmdline
297 while (*argv) { 309 while (*argv) {
diff --git a/miscutils/bbconfig.c b/miscutils/bbconfig.c
index e8be81352..e5f4eb379 100644
--- a/miscutils/bbconfig.c
+++ b/miscutils/bbconfig.c
@@ -10,7 +10,7 @@
10#include "libbb.h" 10#include "libbb.h"
11#include "bbconfigopts.h" 11#include "bbconfigopts.h"
12#if ENABLE_FEATURE_COMPRESS_BBCONFIG 12#if ENABLE_FEATURE_COMPRESS_BBCONFIG
13# include "archive.h" 13# include "bb_archive.h"
14# include "bbconfigopts_bz2.h" 14# include "bbconfigopts_bz2.h"
15#endif 15#endif
16 16
diff --git a/miscutils/conspy.c b/miscutils/conspy.c
index 433c3e829..1a46a4340 100644
--- a/miscutils/conspy.c
+++ b/miscutils/conspy.c
@@ -16,7 +16,7 @@
16 16
17//config:config CONSPY 17//config:config CONSPY
18//config: bool "conspy" 18//config: bool "conspy"
19//config: default n 19//config: default y
20//config: select PLATFORM_LINUX 20//config: select PLATFORM_LINUX
21//config: help 21//config: help
22//config: A text-mode VNC like program for Linux virtual terminals. 22//config: A text-mode VNC like program for Linux virtual terminals.
@@ -25,25 +25,31 @@
25//config: or conspy -cs NUM poor man's GNU screen like 25//config: or conspy -cs NUM poor man's GNU screen like
26 26
27//usage:#define conspy_trivial_usage 27//usage:#define conspy_trivial_usage
28//usage: "[-vcsndf] [-x COL] [-y LINE] [CONSOLE_NO]" 28//usage: "[-vcsndfFQ] [-x COL] [-y LINE] [CONSOLE_NO]"
29//usage:#define conspy_full_usage "\n\n" 29//usage:#define conspy_full_usage "\n\n"
30//usage: "A text-mode VNC like program for Linux virtual consoles." 30//usage: "A text-mode VNC like program for Linux virtual consoles."
31//usage: "\nTo exit, quickly press ESC 3 times." 31//usage: "\nTo exit, quickly press ESC 3 times."
32//usage: "\n" 32//usage: "\n"
33//usage: "\n -v Don't send keystrokes to the console" 33//usage: "\n -v Don't send keystrokes to the console"
34//usage: "\n -c Create missing devices in /dev" 34//usage: "\n -c Create missing /dev/{tty,vcsa}N"
35//usage: "\n -s Open a SHELL session" 35//usage: "\n -s Open a SHELL session"
36//usage: "\n -n Black & white" 36//usage: "\n -n Black & white"
37//usage: "\n -d Dump console to stdout" 37//usage: "\n -d Dump console to stdout"
38//usage: "\n -f Follow cursor" 38//usage: "\n -f Follow cursor"
39//usage: "\n -F Assume console is on a framebuffer device"
40//usage: "\n -Q Disable exit on ESC-ESC-ESC"
39//usage: "\n -x COL Starting column" 41//usage: "\n -x COL Starting column"
40//usage: "\n -y LINE Starting line" 42//usage: "\n -y LINE Starting line"
41 43
42#include "libbb.h" 44#include "libbb.h"
43#include <sys/kd.h> 45#include <sys/kd.h>
44 46
45
46#define ESC "\033" 47#define ESC "\033"
48#define CURSOR_ON -1
49#define CURSOR_OFF 1
50
51#define DEV_TTY "/dev/tty"
52#define DEV_VCSA "/dev/vcsa"
47 53
48struct screen_info { 54struct screen_info {
49 unsigned char lines, cols, cursor_x, cursor_y; 55 unsigned char lines, cols, cursor_x, cursor_y;
@@ -72,19 +78,17 @@ struct globals {
72 unsigned col; 78 unsigned col;
73 unsigned line; 79 unsigned line;
74 smallint curoff; // unknown:0 cursor on:-1 cursor off:1 80 smallint curoff; // unknown:0 cursor on:-1 cursor off:1
75 char attrbuf[sizeof(ESC"[0;1;5;30;40m")]; 81 char attrbuf[sizeof("0;1;5;30;40m")];
76 // remote console 82 // remote console
77 struct screen_info remote; 83 struct screen_info remote;
78 // saved local tty terminfo 84 // saved local tty terminfo
79 struct termios term_orig; 85 struct termios term_orig;
80 char vcsa_name[sizeof("/dev/vcsaNN")]; 86 char vcsa_name[sizeof(DEV_VCSA "NN")];
81}; 87};
82 88
83#define G (*ptr_to_globals) 89#define G (*ptr_to_globals)
84#define INIT_G() do { \ 90#define INIT_G() do { \
85 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 91 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
86 G.attrbuf[0] = '\033'; \
87 G.attrbuf[1] = '['; \
88 G.width = G.height = UINT_MAX; \ 92 G.width = G.height = UINT_MAX; \
89 G.last_attr--; \ 93 G.last_attr--; \
90} while (0) 94} while (0)
@@ -92,18 +96,26 @@ struct globals {
92enum { 96enum {
93 FLAG_v, // view only 97 FLAG_v, // view only
94 FLAG_c, // create device if need 98 FLAG_c, // create device if need
99 FLAG_Q, // never exit
95 FLAG_s, // session 100 FLAG_s, // session
96 FLAG_n, // no colors 101 FLAG_n, // no colors
97 FLAG_d, // dump screen 102 FLAG_d, // dump screen
98 FLAG_f, // follow cursor 103 FLAG_f, // follow cursor
104 FLAG_F, // framebuffer
99}; 105};
100#define FLAG(x) (1 << FLAG_##x) 106#define FLAG(x) (1 << FLAG_##x)
101#define BW (option_mask32 & FLAG(n)) 107#define BW (option_mask32 & FLAG(n))
102 108
109static void putcsi(const char *s)
110{
111 fputs(ESC"[", stdout);
112 fputs(s, stdout);
113}
114
103static void clrscr(void) 115static void clrscr(void)
104{ 116{
105 // Home, clear till end of screen 117 // Home, clear till end of screen
106 fputs(ESC"[1;1H" ESC"[J", stdout); 118 putcsi("1;1H" ESC"[J");
107 G.col = G.line = 0; 119 G.col = G.line = 0;
108} 120}
109 121
@@ -111,7 +123,7 @@ static void set_cursor(int state)
111{ 123{
112 if (G.curoff != state) { 124 if (G.curoff != state) {
113 G.curoff = state; 125 G.curoff = state;
114 fputs(ESC"[?25", stdout); 126 putcsi("?25");
115 bb_putchar("h?l"[1 + state]); 127 bb_putchar("h?l"[1 + state]);
116 } 128 }
117} 129}
@@ -125,18 +137,19 @@ static void gotoxy(int col, int line)
125 } 137 }
126} 138}
127 139
140static void cleanup(int code) NORETURN;
128static void cleanup(int code) 141static void cleanup(int code)
129{ 142{
130 set_cursor(-1); // cursor on 143 set_cursor(CURSOR_ON);
131 tcsetattr(G.kbd_fd, TCSANOW, &G.term_orig); 144 tcsetattr(G.kbd_fd, TCSANOW, &G.term_orig);
132 if (ENABLE_FEATURE_CLEAN_UP) { 145 if (ENABLE_FEATURE_CLEAN_UP) {
133 close(G.kbd_fd); 146 close(G.kbd_fd);
134 } 147 }
135 // Reset attributes 148 // Reset attributes
136 if (!BW) 149 if (!BW)
137 fputs(ESC"[0m", stdout); 150 putcsi("0m");
138 bb_putchar('\n'); 151 bb_putchar('\n');
139 if (code > 1) 152 if (code > EXIT_FAILURE)
140 kill_myself_with_sig(code); 153 kill_myself_with_sig(code);
141 exit(code); 154 exit(code);
142} 155}
@@ -157,8 +170,8 @@ static void screen_read_close(void)
157 G.size = i; 170 G.size = i;
158 G.data = xzalloc(2 * i); 171 G.data = xzalloc(2 * i);
159 } 172 }
160 else if (G.size != i) { 173 if (G.size != i) {
161 cleanup(1); 174 cleanup(EXIT_FAILURE);
162 } 175 }
163 data = G.data + G.current; 176 data = G.data + G.current;
164 xread(vcsa_fd, data, G.size); 177 xread(vcsa_fd, data, G.size);
@@ -168,10 +181,15 @@ static void screen_read_close(void)
168 unsigned x = j - G.x; // if will catch j < G.x too 181 unsigned x = j - G.x; // if will catch j < G.x too
169 unsigned y = i - G.y; // if will catch i < G.y too 182 unsigned y = i - G.y; // if will catch i < G.y too
170 183
171 if (CHAR(data) < ' ')
172 CHAR(data) = ' ';
173 if (y >= G.height || x >= G.width) 184 if (y >= G.height || x >= G.width)
174 DATA(data) = 0; 185 DATA(data) = 0;
186 else {
187 uint8_t ch = CHAR(data);
188 if (ch < ' ')
189 CHAR(data) = ch | 0x40;
190 else if (ch > 0x7e)
191 CHAR(data) = '?';
192 }
175 } 193 }
176 } 194 }
177} 195}
@@ -179,10 +197,13 @@ static void screen_read_close(void)
179static void screen_char(char *data) 197static void screen_char(char *data)
180{ 198{
181 if (!BW) { 199 if (!BW) {
200 uint8_t attr_diff;
182 uint8_t attr = ATTR(data); 201 uint8_t attr = ATTR(data);
183 //uint8_t attr = ATTR(data) >> 1; // for framebuffer console
184 uint8_t attr_diff = G.last_attr ^ attr;
185 202
203 if (option_mask32 & FLAG(F)) {
204 attr >>= 1;
205 }
206 attr_diff = G.last_attr ^ attr;
186 if (attr_diff) { 207 if (attr_diff) {
187// Attribute layout for VGA compatible text videobuffer: 208// Attribute layout for VGA compatible text videobuffer:
188// blinking text 209// blinking text
@@ -213,7 +234,7 @@ static void screen_char(char *data)
213 const uint8_t bg_mask = 0x70, blink_mask = 0x80; 234 const uint8_t bg_mask = 0x70, blink_mask = 0x80;
214 char *ptr; 235 char *ptr;
215 236
216 ptr = G.attrbuf + 2; // skip "ESC [" 237 ptr = G.attrbuf;
217 238
218 // (G.last_attr & ~attr) has 1 only where 239 // (G.last_attr & ~attr) has 1 only where
219 // G.last_attr has 1 but attr has 0. 240 // G.last_attr has 1 but attr has 0.
@@ -244,12 +265,12 @@ static void screen_char(char *data)
244 if (attr_diff & bg_mask) { 265 if (attr_diff & bg_mask) {
245 *ptr++ = '4'; 266 *ptr++ = '4';
246 *ptr++ = color[(attr & bg_mask) >> 4]; 267 *ptr++ = color[(attr & bg_mask) >> 4];
247 *ptr++ = ';'; 268 ptr++; // last attribute
248 } 269 }
249 if (ptr != G.attrbuf + 2) { 270 if (ptr != G.attrbuf) {
250 ptr[-1] = 'm'; 271 ptr[-1] = 'm';
251 *ptr = '\0'; 272 *ptr = '\0';
252 fputs(G.attrbuf, stdout); 273 putcsi(G.attrbuf);
253 } 274 }
254 } 275 }
255 } 276 }
@@ -292,11 +313,11 @@ static void curmove(void)
292{ 313{
293 unsigned cx = G.remote.cursor_x - G.x; 314 unsigned cx = G.remote.cursor_x - G.x;
294 unsigned cy = G.remote.cursor_y - G.y; 315 unsigned cy = G.remote.cursor_y - G.y;
295 int cursor = 1; 316 int cursor = CURSOR_OFF;
296 317
297 if (cx < G.width && cy < G.height) { 318 if (cx < G.width && cy < G.height) {
298 gotoxy(cx, cy); 319 gotoxy(cx, cy);
299 cursor = -1; 320 cursor = CURSOR_ON;
300 } 321 }
301 set_cursor(cursor); 322 set_cursor(cursor);
302} 323}
@@ -341,7 +362,7 @@ static NOINLINE void start_shell_in_child(const char* tty_name)
341int conspy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 362int conspy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
342int conspy_main(int argc UNUSED_PARAM, char **argv) 363int conspy_main(int argc UNUSED_PARAM, char **argv)
343{ 364{
344 char tty_name[sizeof("/dev/ttyNN")]; 365 char tty_name[sizeof(DEV_TTY "NN")];
345#define keybuf bb_common_bufsiz1 366#define keybuf bb_common_bufsiz1
346 struct termios termbuf; 367 struct termios termbuf;
347 unsigned opts; 368 unsigned opts;
@@ -351,26 +372,28 @@ int conspy_main(int argc UNUSED_PARAM, char **argv)
351 static const char getopt_longopts[] ALIGN1 = 372 static const char getopt_longopts[] ALIGN1 =
352 "viewonly\0" No_argument "v" 373 "viewonly\0" No_argument "v"
353 "createdevice\0" No_argument "c" 374 "createdevice\0" No_argument "c"
375 "neverquit\0" No_argument "Q"
354 "session\0" No_argument "s" 376 "session\0" No_argument "s"
355 "nocolors\0" No_argument "n" 377 "nocolors\0" No_argument "n"
356 "dump\0" No_argument "d" 378 "dump\0" No_argument "d"
357 "follow\0" No_argument "f" 379 "follow\0" No_argument "f"
380 "framebuffer\0" No_argument "F"
358 ; 381 ;
359 382
360 applet_long_options = getopt_longopts; 383 applet_long_options = getopt_longopts;
361#endif 384#endif
362 INIT_G(); 385 INIT_G();
363 strcpy(G.vcsa_name, "/dev/vcsa"); 386 strcpy(G.vcsa_name, DEV_VCSA);
364 387
365 opt_complementary = "x+:y+"; // numeric params 388 opt_complementary = "x+:y+"; // numeric params
366 opts = getopt32(argv, "vcsndfx:y:", &G.x, &G.y); 389 opts = getopt32(argv, "vcQsndfFx:y:", &G.x, &G.y);
367 argv += optind; 390 argv += optind;
368 ttynum = 0; 391 ttynum = 0;
369 if (argv[0]) { 392 if (argv[0]) {
370 ttynum = xatou_range(argv[0], 0, 63); 393 ttynum = xatou_range(argv[0], 0, 63);
371 sprintf(G.vcsa_name + sizeof("/dev/vcsa")-1, "%u", ttynum); 394 sprintf(G.vcsa_name + sizeof(DEV_VCSA)-1, "%u", ttynum);
372 } 395 }
373 sprintf(tty_name, "%s%u", "/dev/tty", ttynum); 396 sprintf(tty_name, "%s%u", DEV_TTY, ttynum);
374 if (opts & FLAG(c)) { 397 if (opts & FLAG(c)) {
375 if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v)) 398 if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v))
376 create_cdev_if_doesnt_exist(tty_name, makedev(4, ttynum)); 399 create_cdev_if_doesnt_exist(tty_name, makedev(4, ttynum));
@@ -481,7 +504,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv)
481 char *k; 504 char *k;
482 case -1: 505 case -1:
483 if (errno != EINTR) 506 if (errno != EINTR)
484 cleanup(1); 507 goto abort;
485 break; 508 break;
486 case 0: 509 case 0:
487 if (++G.nokeys >= 4) 510 if (++G.nokeys >= 4)
@@ -492,14 +515,16 @@ int conspy_main(int argc UNUSED_PARAM, char **argv)
492 k = keybuf + G.key_count; 515 k = keybuf + G.key_count;
493 bytes_read = read(G.kbd_fd, k, sizeof(keybuf) - G.key_count); 516 bytes_read = read(G.kbd_fd, k, sizeof(keybuf) - G.key_count);
494 if (bytes_read < 0) 517 if (bytes_read < 0)
495 cleanup(1); 518 goto abort;
496 519
497 // Do exit processing 520 // Do exit processing
498 for (i = 0; i < bytes_read; i++) { 521 if (!(option_mask32 & FLAG(Q))) {
499 if (k[i] != '\033') 522 for (i = 0; i < bytes_read; i++) {
500 G.escape_count = 0; 523 if (k[i] != '\033')
501 else if (++G.escape_count >= 3) 524 G.escape_count = -1;
502 cleanup(0); 525 if (++G.escape_count >= 3)
526 cleanup(EXIT_SUCCESS);
527 }
503 } 528 }
504 } 529 }
505 poll_timeout_ms = 250; 530 poll_timeout_ms = 250;
@@ -519,6 +544,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv)
519 if (result >= 0) { 544 if (result >= 0) {
520 char *p = keybuf; 545 char *p = keybuf;
521 546
547 G.ioerror_count = 0;
522 if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE) { 548 if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE) {
523 G.key_count = 0; // scan code mode 549 G.key_count = 0; // scan code mode
524 } 550 }
@@ -534,16 +560,18 @@ int conspy_main(int argc UNUSED_PARAM, char **argv)
534 poll_timeout_ms = 20; 560 poll_timeout_ms = 20;
535 } 561 }
536 } 562 }
563 // We sometimes get spurious IO errors on the TTY
564 // as programs close and re-open it
565 else if (errno != EIO || ++G.ioerror_count > 4) {
566 if (ENABLE_FEATURE_CLEAN_UP)
567 close(handle);
568 goto abort;
569 }
537 // Close & re-open tty in case they have 570 // Close & re-open tty in case they have
538 // swapped virtual consoles 571 // swapped virtual consoles
539 close(handle); 572 close(handle);
540
541 // We sometimes get spurious IO errors on the TTY
542 // as programs close and re-open it
543 if (result >= 0)
544 G.ioerror_count = 0;
545 else if (errno != EIO || ++G.ioerror_count > 4)
546 cleanup(1);
547 } 573 }
548 } /* while (1) */ 574 } /* while (1) */
575 abort:
576 cleanup(EXIT_FAILURE);
549} 577}
diff --git a/miscutils/crond.c b/miscutils/crond.c
index 014016fb6..a0b73c774 100644
--- a/miscutils/crond.c
+++ b/miscutils/crond.c
@@ -861,7 +861,8 @@ int crond_main(int argc UNUSED_PARAM, char **argv)
861 861
862 /* "-b after -f is ignored", and so on for every pair a-b */ 862 /* "-b after -f is ignored", and so on for every pair a-b */
863 opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") 863 opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l")
864 ":l+:d+"; /* -l and -d have numeric param */ 864 /* -l and -d have numeric param */
865 ":l+" IF_FEATURE_CROND_D(":d+");
865 opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), 866 opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"),
866 &G.log_level, &G.log_filename, &G.crontab_dir_name 867 &G.log_level, &G.log_filename, &G.crontab_dir_name
867 IF_FEATURE_CROND_D(,&G.log_level)); 868 IF_FEATURE_CROND_D(,&G.log_level));
diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c
index 51ba4729e..04d583df6 100644
--- a/miscutils/fbsplash.c
+++ b/miscutils/fbsplash.c
@@ -74,6 +74,43 @@ struct globals {
74#define DEBUG_MESSAGE(...) ((void)0) 74#define DEBUG_MESSAGE(...) ((void)0)
75#endif 75#endif
76 76
77/**
78 * Configure palette for RGB:332
79 */
80static void fb_setpal(int fd)
81{
82 struct fb_cmap cmap;
83 /* fb colors are 16 bit */
84 unsigned short red[256], green[256], blue[256];
85 unsigned i;
86
87 /* RGB:332 */
88 for (i = 0; i < 256; i++) {
89 /* Color is encoded in pixel value as rrrgggbb.
90 * 3-bit color is mapped to 16-bit one as:
91 * 000 -> 00000000 00000000
92 * 001 -> 00100100 10010010
93 * ...
94 * 011 -> 01101101 10110110
95 * 100 -> 10010010 01001001
96 * ...
97 * 111 -> 11111111 11111111
98 */
99 red[i] = (( i >> 5 ) * 0x9249) >> 2; // rrr * 00 10010010 01001001 >> 2
100 green[i] = (((i >> 2) & 0x7) * 0x9249) >> 2; // ggg * 00 10010010 01001001 >> 2
101 /* 2-bit color is easier: */
102 blue[i] = ( i & 0x3) * 0x5555; // bb * 01010101 01010101
103 }
104
105 cmap.start = 0;
106 cmap.len = 256;
107 cmap.red = red;
108 cmap.green = green;
109 cmap.blue = blue;
110 cmap.transp = 0;
111
112 xioctl(fd, FBIOPUTCMAP, &cmap);
113}
77 114
78/** 115/**
79 * Open and initialize the framebuffer device 116 * Open and initialize the framebuffer device
@@ -87,8 +124,21 @@ static void fb_open(const char *strfb_device)
87 xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var); 124 xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var);
88 xioctl(fbfd, FBIOGET_FSCREENINFO, &G.scr_fix); 125 xioctl(fbfd, FBIOGET_FSCREENINFO, &G.scr_fix);
89 126
90 if (G.scr_var.bits_per_pixel < 16 || G.scr_var.bits_per_pixel > 32) 127 switch (G.scr_var.bits_per_pixel) {
128 case 8:
129 fb_setpal(fbfd);
130 break;
131
132 case 16:
133 case 24:
134 case 32:
135 break;
136
137 default:
91 bb_error_msg_and_die("unsupported %u bpp", (int)G.scr_var.bits_per_pixel); 138 bb_error_msg_and_die("unsupported %u bpp", (int)G.scr_var.bits_per_pixel);
139 break;
140 }
141
92 G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) >> 3; 142 G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) >> 3;
93 143
94 // map the device in memory 144 // map the device in memory
@@ -109,11 +159,17 @@ static void fb_open(const char *strfb_device)
109 */ 159 */
110static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b) 160static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b)
111{ 161{
162 if (G.bytes_per_pixel == 1) {
163 r = r & 0xe0; // 3-bit red
164 g = (g >> 3) & 0x1c; // 3-bit green
165 b = b >> 6; // 2-bit blue
166 return r + g + b;
167 }
112 if (G.bytes_per_pixel == 2) { 168 if (G.bytes_per_pixel == 2) {
113 r >>= 3; // 5-bit red 169 r = (r & 0xf8) << 8; // 5-bit red
114 g >>= 2; // 6-bit green 170 g = (g & 0xfc) << 3; // 6-bit green
115 b >>= 3; // 5-bit blue 171 b = b >> 3; // 5-bit blue
116 return b + (g << 5) + (r << (5+6)); 172 return r + g + b;
117 } 173 }
118 // RGB 888 174 // RGB 888
119 return b + (g << 8) + (r << 16); 175 return b + (g << 8) + (r << 16);
@@ -125,6 +181,9 @@ static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b)
125static void fb_write_pixel(unsigned char *addr, unsigned pixel) 181static void fb_write_pixel(unsigned char *addr, unsigned pixel)
126{ 182{
127 switch (G.bytes_per_pixel) { 183 switch (G.bytes_per_pixel) {
184 case 1:
185 *addr = pixel;
186 break;
128 case 2: 187 case 2:
129 *(uint16_t *)addr = pixel; 188 *(uint16_t *)addr = pixel;
130 break; 189 break;
@@ -213,14 +272,15 @@ static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos,
213 */ 272 */
214static void fb_drawprogressbar(unsigned percent) 273static void fb_drawprogressbar(unsigned percent)
215{ 274{
216 int i, left_x, top_y, width, height; 275 int left_x, top_y, pos_x;
276 unsigned width, height;
217 277
218 // outer box 278 // outer box
219 left_x = G.nbar_posx; 279 left_x = G.nbar_posx;
220 top_y = G.nbar_posy; 280 top_y = G.nbar_posy;
221 width = G.nbar_width - 1; 281 width = G.nbar_width - 1;
222 height = G.nbar_height - 1; 282 height = G.nbar_height - 1;
223 if ((height | width) < 0) 283 if ((int)(height | width) < 0)
224 return; 284 return;
225 // NB: "width" of 1 actually makes rect with width of 2! 285 // NB: "width" of 1 actually makes rect with width of 2!
226 fb_drawrectangle(); 286 fb_drawrectangle();
@@ -230,30 +290,37 @@ static void fb_drawprogressbar(unsigned percent)
230 top_y++; 290 top_y++;
231 width -= 2; 291 width -= 2;
232 height -= 2; 292 height -= 2;
233 if ((height | width) < 0) 293 if ((int)(height | width) < 0)
234 return; 294 return;
235 fb_drawfullrectangle(
236 left_x, top_y,
237 left_x + width, top_y + height,
238 G.nbar_colr, G.nbar_colg, G.nbar_colb);
239 295
296 pos_x = left_x;
240 if (percent > 0) { 297 if (percent > 0) {
298 int y;
299 unsigned i;
300
241 // actual progress bar 301 // actual progress bar
242 width = width * percent / 100; 302 pos_x += (unsigned)(width * percent) / 100;
303
304 y = top_y;
243 i = height; 305 i = height;
244 if (height == 0) 306 if (height == 0)
245 height++; // divide by 0 is bad 307 height++; // divide by 0 is bad
246 while (i >= 0) { 308 while (i >= 0) {
247 // draw one-line thick "rectangle" 309 // draw one-line thick "rectangle"
248 // top line will have gray lvl 200, bottom one 100 310 // top line will have gray lvl 200, bottom one 100
249 unsigned gray_level = 100 + i*100/height; 311 unsigned gray_level = 100 + i*100 / height;
250 fb_drawfullrectangle( 312 fb_drawfullrectangle(
251 left_x, top_y, left_x + width, top_y, 313 left_x, y, pos_x, y,
252 gray_level, gray_level, gray_level); 314 gray_level, gray_level, gray_level);
253 top_y++; 315 y++;
254 i--; 316 i--;
255 } 317 }
256 } 318 }
319
320 fb_drawfullrectangle(
321 pos_x, top_y,
322 left_x + width, top_y + height,
323 G.nbar_colr, G.nbar_colg, G.nbar_colb);
257} 324}
258 325
259 326
diff --git a/miscutils/hdparm.c b/miscutils/hdparm.c
index f30e7dec6..a97f3e7b5 100644
--- a/miscutils/hdparm.c
+++ b/miscutils/hdparm.c
@@ -433,6 +433,7 @@ struct BUG_G_too_big {
433#define hwif_data (G.hwif_data ) 433#define hwif_data (G.hwif_data )
434#define hwif_ctrl (G.hwif_ctrl ) 434#define hwif_ctrl (G.hwif_ctrl )
435#define hwif_irq (G.hwif_irq ) 435#define hwif_irq (G.hwif_irq )
436#define INIT_G() do { } while (0)
436 437
437 438
438/* Busybox messages and functions */ 439/* Busybox messages and functions */
@@ -2059,6 +2060,8 @@ int hdparm_main(int argc, char **argv)
2059 int c; 2060 int c;
2060 int flagcount = 0; 2061 int flagcount = 0;
2061 2062
2063 INIT_G();
2064
2062 while ((c = getopt(argc, argv, hdparm_options)) >= 0) { 2065 while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
2063 flagcount++; 2066 flagcount++;
2064 IF_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I')); 2067 IF_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
diff --git a/miscutils/inotifyd.c b/miscutils/inotifyd.c
index b64e0abb9..7a1a6a2e5 100644
--- a/miscutils/inotifyd.c
+++ b/miscutils/inotifyd.c
@@ -33,6 +33,7 @@
33//usage: "Run PROG on filesystem changes." 33//usage: "Run PROG on filesystem changes."
34//usage: "\nWhen a filesystem event matching MASK occurs on FILEn," 34//usage: "\nWhen a filesystem event matching MASK occurs on FILEn,"
35//usage: "\nPROG ACTUAL_EVENTS FILEn [SUBFILE] is run." 35//usage: "\nPROG ACTUAL_EVENTS FILEn [SUBFILE] is run."
36//usage: "\nIf PROG is -, events are sent to stdout."
36//usage: "\nEvents:" 37//usage: "\nEvents:"
37//usage: "\n a File is accessed" 38//usage: "\n a File is accessed"
38//usage: "\n c File is modified" 39//usage: "\n c File is modified"
@@ -177,12 +178,20 @@ int inotifyd_main(int argc, char **argv)
177 *s++ = mask_names[i]; 178 *s++ = mask_names[i];
178 } 179 }
179 *s = '\0'; 180 *s = '\0';
180// bb_error_msg("exec %s %08X\t%s\t%s\t%s", args[0], 181 if (LONE_CHAR(args[0], '-')) {
181// ie->mask, events, watches[ie->wd], ie->len ? ie->name : ""); 182 /* "inotifyd - FILE": built-in echo */
182 args[1] = events; 183 printf(ie->len ? "%s\t%s\t%s\n" : "%s\t%s\n", events,
183 args[2] = watches[ie->wd]; 184 watches[ie->wd],
184 args[3] = ie->len ? ie->name : NULL; 185 ie->name);
185 spawn_and_wait((char **)args); 186 fflush(stdout);
187 } else {
188// bb_error_msg("exec %s %08X\t%s\t%s\t%s", args[0],
189// ie->mask, events, watches[ie->wd], ie->len ? ie->name : "");
190 args[1] = events;
191 args[2] = watches[ie->wd];
192 args[3] = ie->len ? ie->name : NULL;
193 spawn_and_wait((char **)args);
194 }
186 // we are done if all files got final x event 195 // we are done if all files got final x event
187 if (ie->mask & 0x8000) { 196 if (ie->mask & 0x8000) {
188 if (--argc <= 0) 197 if (--argc <= 0)
diff --git a/miscutils/less.c b/miscutils/less.c
index 9543fb9f9..045fd2db3 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -721,8 +721,8 @@ static void print_found(const char *line)
721 while (match_status == 0) { 721 while (match_status == 0) {
722 char *new = xasprintf("%s%.*s"HIGHLIGHT"%.*s"NORMAL, 722 char *new = xasprintf("%s%.*s"HIGHLIGHT"%.*s"NORMAL,
723 growline ? growline : "", 723 growline ? growline : "",
724 match_structs.rm_so, str, 724 (int)match_structs.rm_so, str,
725 match_structs.rm_eo - match_structs.rm_so, 725 (int)(match_structs.rm_eo - match_structs.rm_so),
726 str + match_structs.rm_so); 726 str + match_structs.rm_so);
727 free(growline); 727 free(growline);
728 growline = new; 728 growline = new;
@@ -990,7 +990,8 @@ static int64_t less_getch(int pos)
990 */ 990 */
991 if (key >= 0 && key < ' ' && key != 0x0d && key != 8) 991 if (key >= 0 && key < ' ' && key != 0x0d && key != 8)
992 goto again; 992 goto again;
993 return key; 993
994 return key64;
994} 995}
995 996
996static char* less_gets(int sz) 997static char* less_gets(int sz)
diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c
index 562a34278..2ba6e3fe5 100644
--- a/miscutils/nandwrite.c
+++ b/miscutils/nandwrite.c
@@ -8,26 +8,26 @@
8 * TODO: add support for large (>4GB) MTD devices 8 * TODO: add support for large (>4GB) MTD devices
9 */ 9 */
10 10
11//applet:IF_NANDWRITE(APPLET(nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP))
12//applet:IF_NANDWRITE(APPLET_ODDNAME(nanddump, nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP, nanddump))
13
14//kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o
15//kbuild:lib-$(CONFIG_NANDDUMP) += nandwrite.o
16
17//config:config NANDWRITE 11//config:config NANDWRITE
18//config: bool "nandwrite" 12//config: bool "nandwrite"
19//config: default n 13//config: default y
20//config: select PLATFORM_LINUX 14//config: select PLATFORM_LINUX
21//config: help 15//config: help
22//config: Write to the specified MTD device, with bad blocks awareness 16//config: Write to the specified MTD device, with bad blocks awareness
23//config: 17//config:
24//config:config NANDDUMP 18//config:config NANDDUMP
25//config: bool "nanddump" 19//config: bool "nanddump"
26//config: default n 20//config: default y
27//config: select PLATFORM_LINUX 21//config: select PLATFORM_LINUX
28//config: help 22//config: help
29//config: Dump the content of raw NAND chip 23//config: Dump the content of raw NAND chip
30 24
25//applet:IF_NANDWRITE(APPLET(nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP))
26//applet:IF_NANDWRITE(APPLET_ODDNAME(nanddump, nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP, nanddump))
27
28//kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o
29//kbuild:lib-$(CONFIG_NANDDUMP) += nandwrite.o
30
31//usage:#define nandwrite_trivial_usage 31//usage:#define nandwrite_trivial_usage
32//usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]" 32//usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]"
33//usage:#define nandwrite_full_usage "\n\n" 33//usage:#define nandwrite_full_usage "\n\n"
diff --git a/miscutils/runlevel.c b/miscutils/runlevel.c
index 9d38b791f..76231df22 100644
--- a/miscutils/runlevel.c
+++ b/miscutils/runlevel.c
@@ -11,7 +11,7 @@
11 * 11 *
12 * initially busyboxified by Bernhard Reutner-Fischer 12 * initially busyboxified by Bernhard Reutner-Fischer
13 */ 13 */
14 14
15//usage:#define runlevel_trivial_usage 15//usage:#define runlevel_trivial_usage
16//usage: "[FILE]" 16//usage: "[FILE]"
17//usage:#define runlevel_full_usage "\n\n" 17//usage:#define runlevel_full_usage "\n\n"
diff --git a/miscutils/rx.c b/miscutils/rx.c
index e1225779e..c48a61fd0 100644
--- a/miscutils/rx.c
+++ b/miscutils/rx.c
@@ -108,12 +108,10 @@ static int receive(/*int read_fd, */int file_fd)
108 } 108 }
109 } 109 }
110 /* Write previously received block */ 110 /* Write previously received block */
111 if (blockLength) { 111 errno = 0;
112 errno = 0; 112 if (full_write(file_fd, blockBuf, blockLength) != blockLength) {
113 if (full_write(file_fd, blockBuf, blockLength) != blockLength) { 113 bb_perror_msg(bb_msg_write_error);
114 bb_perror_msg("can't write to file"); 114 goto fatal;
115 goto fatal;
116 }
117 } 115 }
118 116
119 timeout = TIMEOUT; 117 timeout = TIMEOUT;
@@ -155,23 +153,20 @@ static int receive(/*int read_fd, */int file_fd)
155 blockBuf[i] = cc; 153 blockBuf[i] = cc;
156 } 154 }
157 155
156 cksum_or_crc = read_byte(TIMEOUT);
157 if (cksum_or_crc < 0)
158 goto timeout;
158 if (do_crc) { 159 if (do_crc) {
159 cksum_or_crc = read_byte(TIMEOUT);
160 if (cksum_or_crc < 0)
161 goto timeout;
162 cksum_or_crc = (cksum_or_crc << 8) | read_byte(TIMEOUT); 160 cksum_or_crc = (cksum_or_crc << 8) | read_byte(TIMEOUT);
163 if (cksum_or_crc < 0) 161 if (cksum_or_crc < 0)
164 goto timeout; 162 goto timeout;
165 } else {
166 cksum_or_crc = read_byte(TIMEOUT);
167 if (cksum_or_crc < 0)
168 goto timeout;
169 } 163 }
170 164
171 if (blockNo == ((wantBlockNo - 1) & 0xff)) { 165 if (blockNo == ((wantBlockNo - 1) & 0xff)) {
172 /* a repeat of the last block is ok, just ignore it. */ 166 /* a repeat of the last block is ok, just ignore it. */
173 /* this also ignores the initial block 0 which is */ 167 /* this also ignores the initial block 0 which is */
174 /* meta data. */ 168 /* meta data. */
169 blockLength = 0;
175 goto next; 170 goto next;
176 } 171 }
177 if (blockNo != (wantBlockNo & 0xff)) { 172 if (blockNo != (wantBlockNo & 0xff)) {
diff --git a/modutils/modinfo.c b/modutils/modinfo.c
index 410b6fbe4..c0910ffed 100644
--- a/modutils/modinfo.c
+++ b/modutils/modinfo.c
@@ -13,6 +13,7 @@
13//config:config MODINFO 13//config:config MODINFO
14//config: bool "modinfo" 14//config: bool "modinfo"
15//config: default y 15//config: default y
16//config: select PLATFORM_LINUX
16//config: help 17//config: help
17//config: Show information about a Linux Kernel module 18//config: Show information about a Linux Kernel module
18 19
diff --git a/modutils/modutils-24.c b/modutils/modutils-24.c
index bbc54e316..12cb75c54 100644
--- a/modutils/modutils-24.c
+++ b/modutils/modutils-24.c
@@ -60,7 +60,6 @@
60 60
61#include "libbb.h" 61#include "libbb.h"
62#include "modutils.h" 62#include "modutils.h"
63#include <libgen.h>
64#include <sys/utsname.h> 63#include <sys/utsname.h>
65 64
66#if ENABLE_FEATURE_INSMOD_LOADINKMEM 65#if ENABLE_FEATURE_INSMOD_LOADINKMEM
diff --git a/networking/httpd.c b/networking/httpd.c
index ba5eebad5..24482fe52 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -820,78 +820,6 @@ static char *encodeString(const char *string)
820} 820}
821#endif 821#endif
822 822
823/*
824 * Given a URL encoded string, convert it to plain ascii.
825 * Since decoding always makes strings smaller, the decode is done in-place.
826 * Thus, callers should xstrdup() the argument if they do not want the
827 * argument modified. The return is the original pointer, allowing this
828 * function to be easily used as arguments to other functions.
829 *
830 * string The first string to decode.
831 * option_d 1 if called for httpd -d
832 *
833 * Returns a pointer to the decoded string (same as input).
834 */
835static unsigned hex_to_bin(unsigned char c)
836{
837 unsigned v;
838
839 v = c - '0';
840 if (v <= 9)
841 return v;
842 /* c | 0x20: letters to lower case, non-letters
843 * to (potentially different) non-letters */
844 v = (unsigned)(c | 0x20) - 'a';
845 if (v <= 5)
846 return v + 10;
847 return ~0;
848/* For testing:
849void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); }
850int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f');
851t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; }
852*/
853}
854static char *decodeString(char *orig, int option_d)
855{
856 /* note that decoded string is always shorter than original */
857 char *string = orig;
858 char *ptr = string;
859 char c;
860
861 while ((c = *ptr++) != '\0') {
862 unsigned v;
863
864 if (option_d && c == '+') {
865 *string++ = ' ';
866 continue;
867 }
868 if (c != '%') {
869 *string++ = c;
870 continue;
871 }
872 v = hex_to_bin(ptr[0]);
873 if (v > 15) {
874 bad_hex:
875 if (!option_d)
876 return NULL;
877 *string++ = '%';
878 continue;
879 }
880 v = (v * 16) | hex_to_bin(ptr[1]);
881 if (v > 255)
882 goto bad_hex;
883 if (!option_d && (v == '/' || v == '\0')) {
884 /* caller takes it as indication of invalid
885 * (dangerous wrt exploits) chars */
886 return orig + 1;
887 }
888 *string++ = v;
889 ptr += 2;
890 }
891 *string = '\0';
892 return orig;
893}
894
895#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 823#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
896/* 824/*
897 * Decode a base64 data stream as per rfc1521. 825 * Decode a base64 data stream as per rfc1521.
@@ -1949,7 +1877,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
1949 } 1877 }
1950 1878
1951 /* Decode URL escape sequences */ 1879 /* Decode URL escape sequences */
1952 tptr = decodeString(urlcopy, 0); 1880 tptr = percent_decode_in_place(urlcopy, /*strict:*/ 1);
1953 if (tptr == NULL) 1881 if (tptr == NULL)
1954 send_headers_and_exit(HTTP_BAD_REQUEST); 1882 send_headers_and_exit(HTTP_BAD_REQUEST);
1955 if (tptr == urlcopy + 1) { 1883 if (tptr == urlcopy + 1) {
@@ -2408,7 +2336,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2408 , &verbose 2336 , &verbose
2409 ); 2337 );
2410 if (opt & OPT_DECODE_URL) { 2338 if (opt & OPT_DECODE_URL) {
2411 fputs(decodeString(url_for_decode, 1), stdout); 2339 fputs(percent_decode_in_place(url_for_decode, /*strict:*/ 0), stdout);
2412 return 0; 2340 return 0;
2413 } 2341 }
2414#if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR 2342#if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 382033038..5946323d0 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -87,7 +87,6 @@ struct mapping_defn_t {
87 87
88 char *script; 88 char *script;
89 89
90 int max_mappings;
91 int n_mappings; 90 int n_mappings;
92 char **mapping; 91 char **mapping;
93}; 92};
@@ -102,7 +101,6 @@ struct interface_defn_t {
102 const struct method_t *method; 101 const struct method_t *method;
103 102
104 char *iface; 103 char *iface;
105 int max_options;
106 int n_options; 104 int n_options;
107 struct variable_t *option; 105 struct variable_t *option;
108}; 106};
@@ -138,6 +136,16 @@ struct globals {
138#define INIT_G() do { } while (0) 136#define INIT_G() do { } while (0)
139 137
140 138
139static const char keywords_up_down[] ALIGN1 =
140 "up\0"
141 "down\0"
142 "pre-up\0"
143 "pre-down\0"
144 "post-up\0"
145 "post-down\0"
146;
147
148
141#if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6 149#if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6
142 150
143static void addstr(char **bufp, const char *str, size_t str_length) 151static void addstr(char **bufp, const char *str, size_t str_length)
@@ -803,7 +811,6 @@ static struct interfaces_file_t *read_interfaces(const char *filename)
803 currmap->match = xrealloc_vector(currmap->match, 4, currmap->n_matches); 811 currmap->match = xrealloc_vector(currmap->match, 4, currmap->n_matches);
804 currmap->match[currmap->n_matches++] = xstrdup(first_word); 812 currmap->match[currmap->n_matches++] = xstrdup(first_word);
805 } 813 }
806 /*currmap->max_mappings = 0; - done by xzalloc */
807 /*currmap->n_mappings = 0;*/ 814 /*currmap->n_mappings = 0;*/
808 /*currmap->mapping = NULL;*/ 815 /*currmap->mapping = NULL;*/
809 /*currmap->script = NULL;*/ 816 /*currmap->script = NULL;*/
@@ -888,23 +895,16 @@ static struct interfaces_file_t *read_interfaces(const char *filename)
888 if (rest_of_line[0] == '\0') 895 if (rest_of_line[0] == '\0')
889 bb_error_msg_and_die("option with empty value \"%s\"", buf); 896 bb_error_msg_and_die("option with empty value \"%s\"", buf);
890 897
891 if (strcmp(first_word, "up") != 0 898 /* If not one of "up", "down",... words... */
892 && strcmp(first_word, "down") != 0 899 if (index_in_strings(keywords_up_down, first_word) < 0) {
893 && strcmp(first_word, "pre-up") != 0
894 && strcmp(first_word, "post-down") != 0
895 ) {
896 int i; 900 int i;
897 for (i = 0; i < currif->n_options; i++) { 901 for (i = 0; i < currif->n_options; i++) {
898 if (strcmp(currif->option[i].name, first_word) == 0) 902 if (strcmp(currif->option[i].name, first_word) == 0)
899 bb_error_msg_and_die("duplicate option \"%s\"", buf); 903 bb_error_msg_and_die("duplicate option \"%s\"", buf);
900 } 904 }
901 } 905 }
902 if (currif->n_options >= currif->max_options) {
903 currif->max_options += 10;
904 currif->option = xrealloc(currif->option,
905 sizeof(*currif->option) * currif->max_options);
906 }
907 debug_noise("\t%s=%s\n", first_word, rest_of_line); 906 debug_noise("\t%s=%s\n", first_word, rest_of_line);
907 currif->option = xrealloc_vector(currif->option, 4, currif->n_options);
908 currif->option[currif->n_options].name = xstrdup(first_word); 908 currif->option[currif->n_options].name = xstrdup(first_word);
909 currif->option[currif->n_options].value = xstrdup(rest_of_line); 909 currif->option[currif->n_options].value = xstrdup(rest_of_line);
910 currif->n_options++; 910 currif->n_options++;
@@ -916,11 +916,7 @@ static struct interfaces_file_t *read_interfaces(const char *filename)
916 bb_error_msg_and_die("duplicate script in mapping \"%s\"", buf); 916 bb_error_msg_and_die("duplicate script in mapping \"%s\"", buf);
917 currmap->script = xstrdup(next_word(&rest_of_line)); 917 currmap->script = xstrdup(next_word(&rest_of_line));
918 } else if (strcmp(first_word, "map") == 0) { 918 } else if (strcmp(first_word, "map") == 0) {
919 if (currmap->n_mappings >= currmap->max_mappings) { 919 currmap->mapping = xrealloc_vector(currmap->mapping, 2, currmap->n_mappings);
920 currmap->max_mappings = currmap->max_mappings * 2 + 1;
921 currmap->mapping = xrealloc(currmap->mapping,
922 sizeof(char *) * currmap->max_mappings);
923 }
924 currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&rest_of_line)); 920 currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&rest_of_line));
925 currmap->n_mappings++; 921 currmap->n_mappings++;
926 } else { 922 } else {
@@ -984,11 +980,7 @@ static void set_environ(struct interface_defn_t *iface, const char *mode)
984 pp = G.my_environ; 980 pp = G.my_environ;
985 981
986 for (i = 0; i < iface->n_options; i++) { 982 for (i = 0; i < iface->n_options; i++) {
987 if (strcmp(iface->option[i].name, "up") == 0 983 if (index_in_strings(keywords_up_down, iface->option[i].name) >= 0) {
988 || strcmp(iface->option[i].name, "down") == 0
989 || strcmp(iface->option[i].name, "pre-up") == 0
990 || strcmp(iface->option[i].name, "post-down") == 0
991 ) {
992 continue; 984 continue;
993 } 985 }
994 *pp++ = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value); 986 *pp++ = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value);
@@ -1056,6 +1048,7 @@ static int iface_up(struct interface_defn_t *iface)
1056 if (!execute_all(iface, "pre-up")) return 0; 1048 if (!execute_all(iface, "pre-up")) return 0;
1057 if (!iface->method->up(iface, doit)) return 0; 1049 if (!iface->method->up(iface, doit)) return 0;
1058 if (!execute_all(iface, "up")) return 0; 1050 if (!execute_all(iface, "up")) return 0;
1051 if (!execute_all(iface, "post-up")) return 0;
1059 return 1; 1052 return 1;
1060} 1053}
1061 1054
@@ -1063,6 +1056,7 @@ static int iface_down(struct interface_defn_t *iface)
1063{ 1056{
1064 if (!iface->method->down(iface,check)) return -1; 1057 if (!iface->method->down(iface,check)) return -1;
1065 set_environ(iface, "stop"); 1058 set_environ(iface, "stop");
1059 if (!execute_all(iface, "pre-down")) return 0;
1066 if (!execute_all(iface, "down")) return 0; 1060 if (!execute_all(iface, "down")) return 0;
1067 if (!iface->method->down(iface, doit)) return 0; 1061 if (!iface->method->down(iface, doit)) return 0;
1068 if (!execute_all(iface, "post-down")) return 0; 1062 if (!execute_all(iface, "post-down")) return 0;
diff --git a/networking/inetd.c b/networking/inetd.c
index 873fd9528..26b66992d 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -357,10 +357,26 @@ struct BUG_G_too_big {
357 config_filename = "/etc/inetd.conf"; \ 357 config_filename = "/etc/inetd.conf"; \
358} while (0) 358} while (0)
359 359
360#if 1
361# define dbg(...) ((void)0)
362#else
363# define dbg(...) \
364do { \
365 int dbg_fd = open("inetd_debug.log", O_WRONLY | O_CREAT | O_APPEND, 0666); \
366 if (dbg_fd >= 0) { \
367 fdprintf(dbg_fd, "%d: ", getpid()); \
368 fdprintf(dbg_fd, __VA_ARGS__); \
369 close(dbg_fd); \
370 } \
371} while (0)
372#endif
373
360static void maybe_close(int fd) 374static void maybe_close(int fd)
361{ 375{
362 if (fd >= 0) 376 if (fd >= 0) {
363 close(fd); 377 close(fd);
378 dbg("closed fd:%d\n", fd);
379 }
364} 380}
365 381
366// TODO: move to libbb? 382// TODO: move to libbb?
@@ -464,7 +480,9 @@ static void remove_fd_from_set(int fd)
464{ 480{
465 if (fd >= 0) { 481 if (fd >= 0) {
466 FD_CLR(fd, &allsock); 482 FD_CLR(fd, &allsock);
483 dbg("stopped listening on fd:%d\n", fd);
467 maxsock = -1; 484 maxsock = -1;
485 dbg("maxsock:%d\n", maxsock);
468 } 486 }
469} 487}
470 488
@@ -472,8 +490,10 @@ static void add_fd_to_set(int fd)
472{ 490{
473 if (fd >= 0) { 491 if (fd >= 0) {
474 FD_SET(fd, &allsock); 492 FD_SET(fd, &allsock);
493 dbg("started listening on fd:%d\n", fd);
475 if (maxsock >= 0 && fd > maxsock) { 494 if (maxsock >= 0 && fd > maxsock) {
476 prev_maxsock = maxsock = fd; 495 prev_maxsock = maxsock = fd;
496 dbg("maxsock:%d\n", maxsock);
477 if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN) 497 if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN)
478 bump_nofile(); 498 bump_nofile();
479 } 499 }
@@ -492,6 +512,7 @@ static void recalculate_maxsock(void)
492 maxsock = fd; 512 maxsock = fd;
493 fd++; 513 fd++;
494 } 514 }
515 dbg("recalculated maxsock:%d\n", maxsock);
495 prev_maxsock = maxsock; 516 prev_maxsock = maxsock;
496 if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) 517 if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
497 bump_nofile(); 518 bump_nofile();
@@ -549,8 +570,13 @@ static void prepare_socket_fd(servtab_t *sep)
549 rearm_alarm(); 570 rearm_alarm();
550 return; 571 return;
551 } 572 }
552 if (sep->se_socktype == SOCK_STREAM) 573
574 if (sep->se_socktype == SOCK_STREAM) {
553 listen(fd, global_queuelen); 575 listen(fd, global_queuelen);
576 dbg("new sep->se_fd:%d (stream)\n", fd);
577 } else {
578 dbg("new sep->se_fd:%d (!stream)\n", fd);
579 }
554 580
555 add_fd_to_set(fd); 581 add_fd_to_set(fd);
556 sep->se_fd = fd; 582 sep->se_fd = fd;
@@ -1012,7 +1038,7 @@ static void reread_config_file(int sig UNUSED_PARAM)
1012 * new config file doesnt have them. */ 1038 * new config file doesnt have them. */
1013 block_CHLD_HUP_ALRM(&omask); 1039 block_CHLD_HUP_ALRM(&omask);
1014 sepp = &serv_list; 1040 sepp = &serv_list;
1015 while ((sep = *sepp)) { 1041 while ((sep = *sepp) != NULL) {
1016 if (sep->se_checked) { 1042 if (sep->se_checked) {
1017 sepp = &sep->se_next; 1043 sepp = &sep->se_next;
1018 continue; 1044 continue;
@@ -1206,11 +1232,13 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1206 } 1232 }
1207 continue; 1233 continue;
1208 } 1234 }
1235 dbg("ready_fd_cnt:%d\n", ready_fd_cnt);
1209 1236
1210 for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) { 1237 for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) {
1211 if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) 1238 if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
1212 continue; 1239 continue;
1213 1240
1241 dbg("ready fd:%d\n", sep->se_fd);
1214 ready_fd_cnt--; 1242 ready_fd_cnt--;
1215 ctrl = sep->se_fd; 1243 ctrl = sep->se_fd;
1216 accepted_fd = -1; 1244 accepted_fd = -1;
@@ -1218,6 +1246,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1218 if (!sep->se_wait) { 1246 if (!sep->se_wait) {
1219 if (sep->se_socktype == SOCK_STREAM) { 1247 if (sep->se_socktype == SOCK_STREAM) {
1220 ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL); 1248 ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL);
1249 dbg("accepted_fd:%d\n", accepted_fd);
1221 if (ctrl < 0) { 1250 if (ctrl < 0) {
1222 if (errno != EINTR) 1251 if (errno != EINTR)
1223 bb_perror_msg("accept (for %s)", sep->se_service); 1252 bb_perror_msg("accept (for %s)", sep->se_service);
@@ -1238,19 +1267,22 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1238 * (can create many copies of same child, etc). 1267 * (can create many copies of same child, etc).
1239 * Parent must create and use new socket instead. */ 1268 * Parent must create and use new socket instead. */
1240 new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0); 1269 new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0);
1270 dbg("new_udp_fd:%d\n", new_udp_fd);
1241 if (new_udp_fd < 0) { /* error: eat packet, forget about it */ 1271 if (new_udp_fd < 0) { /* error: eat packet, forget about it */
1242 udp_err: 1272 udp_err:
1243 recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT); 1273 recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT);
1244 continue; 1274 continue;
1245 } 1275 }
1246 setsockopt_reuseaddr(new_udp_fd); 1276 setsockopt_reuseaddr(new_udp_fd);
1247 /* TODO: better do bind after vfork in parent, 1277 /* TODO: better do bind after fork in parent,
1248 * so that we don't have two wildcard bound sockets 1278 * so that we don't have two wildcard bound sockets
1249 * even for a brief moment? */ 1279 * even for a brief moment? */
1250 if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) { 1280 if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) {
1281 dbg("bind(new_udp_fd) failed\n");
1251 close(new_udp_fd); 1282 close(new_udp_fd);
1252 goto udp_err; 1283 goto udp_err;
1253 } 1284 }
1285 dbg("bind(new_udp_fd) succeeded\n");
1254 } 1286 }
1255 } 1287 }
1256 1288
@@ -1278,6 +1310,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1278 sep->se_count = 0; 1310 sep->se_count = 0;
1279 rearm_alarm(); /* will revive it in RETRYTIME sec */ 1311 rearm_alarm(); /* will revive it in RETRYTIME sec */
1280 restore_sigmask(&omask); 1312 restore_sigmask(&omask);
1313 maybe_close(new_udp_fd);
1281 maybe_close(accepted_fd); 1314 maybe_close(accepted_fd);
1282 continue; /* -> check next fd in fd set */ 1315 continue; /* -> check next fd in fd set */
1283 } 1316 }
@@ -1298,17 +1331,18 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1298 bb_perror_msg("vfork"+1); 1331 bb_perror_msg("vfork"+1);
1299 sleep(1); 1332 sleep(1);
1300 restore_sigmask(&omask); 1333 restore_sigmask(&omask);
1334 maybe_close(new_udp_fd);
1301 maybe_close(accepted_fd); 1335 maybe_close(accepted_fd);
1302 continue; /* -> check next fd in fd set */ 1336 continue; /* -> check next fd in fd set */
1303 } 1337 }
1304 if (pid == 0) 1338 if (pid == 0)
1305 pid--; /* -1: "we did fork and we are child" */ 1339 pid--; /* -1: "we did fork and we are child" */
1306 } 1340 }
1307 /* if pid == 0 here, we never forked */ 1341 /* if pid == 0 here, we didn't fork */
1308 1342
1309 if (pid > 0) { /* parent */ 1343 if (pid > 0) { /* parent */
1310 if (sep->se_wait) { 1344 if (sep->se_wait) {
1311 /* tcp wait: we passed listening socket to child, 1345 /* wait: we passed socket to child,
1312 * will wait for child to terminate */ 1346 * will wait for child to terminate */
1313 sep->se_wait = pid; 1347 sep->se_wait = pid;
1314 remove_fd_from_set(sep->se_fd); 1348 remove_fd_from_set(sep->se_fd);
@@ -1317,17 +1351,19 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1317 /* udp nowait: child connected the socket, 1351 /* udp nowait: child connected the socket,
1318 * we created and will use new, unconnected one */ 1352 * we created and will use new, unconnected one */
1319 xmove_fd(new_udp_fd, sep->se_fd); 1353 xmove_fd(new_udp_fd, sep->se_fd);
1354 dbg("moved new_udp_fd:%d to sep->se_fd:%d\n", new_udp_fd, sep->se_fd);
1320 } 1355 }
1321 restore_sigmask(&omask); 1356 restore_sigmask(&omask);
1322 maybe_close(accepted_fd); 1357 maybe_close(accepted_fd);
1323 continue; /* -> check next fd in fd set */ 1358 continue; /* -> check next fd in fd set */
1324 } 1359 }
1325 1360
1326 /* we are either child or didn't vfork at all */ 1361 /* we are either child or didn't fork at all */
1327#ifdef INETD_BUILTINS_ENABLED 1362#ifdef INETD_BUILTINS_ENABLED
1328 if (sep->se_builtin) { 1363 if (sep->se_builtin) {
1329 if (pid) { /* "pid" is -1: we did vfork */ 1364 if (pid) { /* "pid" is -1: we did fork */
1330 close(sep->se_fd); /* listening socket */ 1365 close(sep->se_fd); /* listening socket */
1366 dbg("closed sep->se_fd:%d\n", sep->se_fd);
1331 logmode = LOGMODE_NONE; /* make xwrite etc silent */ 1367 logmode = LOGMODE_NONE; /* make xwrite etc silent */
1332 } 1368 }
1333 restore_sigmask(&omask); 1369 restore_sigmask(&omask);
@@ -1335,7 +1371,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1335 sep->se_builtin->bi_stream_fn(ctrl, sep); 1371 sep->se_builtin->bi_stream_fn(ctrl, sep);
1336 else 1372 else
1337 sep->se_builtin->bi_dgram_fn(ctrl, sep); 1373 sep->se_builtin->bi_dgram_fn(ctrl, sep);
1338 if (pid) /* we did vfork */ 1374 if (pid) /* we did fork */
1339 _exit(EXIT_FAILURE); 1375 _exit(EXIT_FAILURE);
1340 maybe_close(accepted_fd); 1376 maybe_close(accepted_fd);
1341 continue; /* -> check next fd in fd set */ 1377 continue; /* -> check next fd in fd set */
@@ -1345,9 +1381,14 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1345 setsid(); 1381 setsid();
1346 /* "nowait" udp */ 1382 /* "nowait" udp */
1347 if (new_udp_fd >= 0) { 1383 if (new_udp_fd >= 0) {
1348 len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family); 1384 len_and_sockaddr *lsa;
1385 int r;
1386
1387 close(new_udp_fd);
1388 dbg("closed new_udp_fd:%d\n", new_udp_fd);
1389 lsa = xzalloc_lsa(sep->se_family);
1349 /* peek at the packet and remember peer addr */ 1390 /* peek at the packet and remember peer addr */
1350 int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, 1391 r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
1351 &lsa->u.sa, &lsa->len); 1392 &lsa->u.sa, &lsa->len);
1352 if (r < 0) 1393 if (r < 0)
1353 goto do_exit1; 1394 goto do_exit1;
@@ -1355,6 +1396,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1355 * only packets from this peer will be recv'ed, 1396 * only packets from this peer will be recv'ed,
1356 * and bare write()/send() will work on it */ 1397 * and bare write()/send() will work on it */
1357 connect(ctrl, &lsa->u.sa, lsa->len); 1398 connect(ctrl, &lsa->u.sa, lsa->len);
1399 dbg("connected ctrl:%d to remote peer\n", ctrl);
1358 free(lsa); 1400 free(lsa);
1359 } 1401 }
1360 /* prepare env and exec program */ 1402 /* prepare env and exec program */
@@ -1372,7 +1414,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1372 bb_error_msg("non-root must run services as himself"); 1414 bb_error_msg("non-root must run services as himself");
1373 goto do_exit1; 1415 goto do_exit1;
1374 } 1416 }
1375 if (pwd->pw_uid) { 1417 if (pwd->pw_uid != 0) {
1376 if (sep->se_group) 1418 if (sep->se_group)
1377 pwd->pw_gid = grp->gr_gid; 1419 pwd->pw_gid = grp->gr_gid;
1378 /* initgroups, setgid, setuid: */ 1420 /* initgroups, setgid, setuid: */
@@ -1391,6 +1433,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1391 */ 1433 */
1392 xmove_fd(ctrl, STDIN_FILENO); 1434 xmove_fd(ctrl, STDIN_FILENO);
1393 xdup2(STDIN_FILENO, STDOUT_FILENO); 1435 xdup2(STDIN_FILENO, STDOUT_FILENO);
1436 dbg("moved ctrl:%d to fd 0,1[,2]\n", ctrl);
1394 /* manpages of inetd I managed to find either say 1437 /* manpages of inetd I managed to find either say
1395 * that stderr is also redirected to the network, 1438 * that stderr is also redirected to the network,
1396 * or do not talk about redirection at all (!) */ 1439 * or do not talk about redirection at all (!) */
@@ -1403,6 +1446,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
1403 maybe_close(sep2->se_fd); 1446 maybe_close(sep2->se_fd);
1404 sigaction_set(SIGPIPE, &saved_pipe_handler); 1447 sigaction_set(SIGPIPE, &saved_pipe_handler);
1405 restore_sigmask(&omask); 1448 restore_sigmask(&omask);
1449 dbg("execing:'%s'\n", sep->se_program);
1406 BB_EXECVP(sep->se_program, sep->se_argv); 1450 BB_EXECVP(sep->se_program, sep->se_argv);
1407 bb_perror_msg("can't execute '%s'", sep->se_program); 1451 bb_perror_msg("can't execute '%s'", sep->se_program);
1408 do_exit1: 1452 do_exit1:
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 1daad1358..d184f689b 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -428,8 +428,7 @@ create new one, and bind() it. TODO */
428 428
429 rr = getsockopt(netfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x); 429 rr = getsockopt(netfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x);
430 if (rr >= 0 && x) { /* we've got options, lessee em... */ 430 if (rr >= 0 && x) { /* we've got options, lessee em... */
431 bin2hex(bigbuf_net, optbuf, x); 431 *bin2hex(bigbuf_net, optbuf, x) = '\0';
432 bigbuf_net[2*x] = '\0';
433 fprintf(stderr, "IP options: %s\n", bigbuf_net); 432 fprintf(stderr, "IP options: %s\n", bigbuf_net);
434 } 433 }
435#endif 434#endif
diff --git a/networking/ping.c b/networking/ping.c
index efd4f210b..b8a438ba8 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -149,31 +149,6 @@ enum {
149 PINGINTERVAL = 1, /* 1 second */ 149 PINGINTERVAL = 1, /* 1 second */
150}; 150};
151 151
152/* Common routines */
153
154static int in_cksum(unsigned short *buf, int sz)
155{
156 int nleft = sz;
157 int sum = 0;
158 unsigned short *w = buf;
159 unsigned short ans = 0;
160
161 while (nleft > 1) {
162 sum += *w++;
163 nleft -= 2;
164 }
165
166 if (nleft == 1) {
167 *(unsigned char *) (&ans) = *(unsigned char *) w;
168 sum += ans;
169 }
170
171 sum = (sum >> 16) + (sum & 0xFFFF);
172 sum += (sum >> 16);
173 ans = ~sum;
174 return ans;
175}
176
177#if !ENABLE_FEATURE_FANCY_PING 152#if !ENABLE_FEATURE_FANCY_PING
178 153
179/* Simple version */ 154/* Simple version */
@@ -201,7 +176,7 @@ static void ping4(len_and_sockaddr *lsa)
201 pkt = (struct icmp *) G.packet; 176 pkt = (struct icmp *) G.packet;
202 memset(pkt, 0, sizeof(G.packet)); 177 memset(pkt, 0, sizeof(G.packet));
203 pkt->icmp_type = ICMP_ECHO; 178 pkt->icmp_type = ICMP_ECHO;
204 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(G.packet)); 179 pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet));
205 180
206 xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); 181 xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len);
207 182
@@ -493,7 +468,7 @@ static void sendping4(int junk UNUSED_PARAM)
493 /* No hton: we'll read it back on the same machine */ 468 /* No hton: we'll read it back on the same machine */
494 *(uint32_t*)&pkt->icmp_dun = monotonic_us(); 469 *(uint32_t*)&pkt->icmp_dun = monotonic_us();
495 470
496 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, datalen + ICMP_MINLEN); 471 pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, datalen + ICMP_MINLEN);
497 472
498 sendping_tail(sendping4, ICMP_MINLEN); 473 sendping_tail(sendping4, ICMP_MINLEN);
499} 474}
@@ -512,7 +487,7 @@ static void sendping6(int junk UNUSED_PARAM)
512 /*if (datalen >= 4)*/ 487 /*if (datalen >= 4)*/
513 *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); 488 *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us();
514 489
515 //TODO? pkt->icmp_cksum = in_cksum(...); 490 //TODO? pkt->icmp_cksum = inet_cksum(...);
516 491
517 sendping_tail(sendping6, sizeof(struct icmp6_hdr)); 492 sendping_tail(sendping6, sizeof(struct icmp6_hdr));
518} 493}
@@ -638,7 +613,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from)
638 } 613 }
639} 614}
640#if ENABLE_PING6 615#if ENABLE_PING6
641static void unpack6(char *packet, int sz, /*struct sockaddr_in6 *from,*/ int hoplimit) 616static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
642{ 617{
643 struct icmp6_hdr *icmppkt; 618 struct icmp6_hdr *icmppkt;
644 char buf[INET6_ADDRSTRLEN]; 619 char buf[INET6_ADDRSTRLEN];
@@ -658,7 +633,7 @@ static void unpack6(char *packet, int sz, /*struct sockaddr_in6 *from,*/ int hop
658 if (sz >= sizeof(struct icmp6_hdr) + sizeof(uint32_t)) 633 if (sz >= sizeof(struct icmp6_hdr) + sizeof(uint32_t))
659 tp = (uint32_t *) &icmppkt->icmp6_data8[4]; 634 tp = (uint32_t *) &icmppkt->icmp6_data8[4];
660 unpack_tail(sz, tp, 635 unpack_tail(sz, tp,
661 inet_ntop(AF_INET6, &pingaddr.sin6.sin6_addr, 636 inet_ntop(AF_INET6, &from->sin6_addr,
662 buf, sizeof(buf)), 637 buf, sizeof(buf)),
663 recv_seq, hoplimit); 638 recv_seq, hoplimit);
664 } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) { 639 } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) {
@@ -808,7 +783,7 @@ static void ping6(len_and_sockaddr *lsa)
808 move_from_unaligned_int(hoplimit, CMSG_DATA(mp)); 783 move_from_unaligned_int(hoplimit, CMSG_DATA(mp));
809 } 784 }
810 } 785 }
811 unpack6(G.rcv_packet, c, /*&from,*/ hoplimit); 786 unpack6(G.rcv_packet, c, &from, hoplimit);
812 if (pingcount && nreceived >= pingcount) 787 if (pingcount && nreceived >= pingcount)
813 break; 788 break;
814 } 789 }
diff --git a/networking/tftp.c b/networking/tftp.c
index 17485a527..043b879af 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -813,7 +813,8 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
813 goto err; 813 goto err;
814 } 814 }
815 mode = local_file + strlen(local_file) + 1; 815 mode = local_file + strlen(local_file) + 1;
816 if (mode >= block_buf + result || strcmp(mode, "octet") != 0) { 816 /* RFC 1350 says mode string is case independent */
817 if (mode >= block_buf + result || strcasecmp(mode, "octet") != 0) {
817 goto err; 818 goto err;
818 } 819 }
819# if ENABLE_FEATURE_TFTP_BLOCKSIZE 820# if ENABLE_FEATURE_TFTP_BLOCKSIZE
diff --git a/networking/traceroute.c b/networking/traceroute.c
index c32103519..d197e5410 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -418,39 +418,6 @@ wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timest
418 return read_len; 418 return read_len;
419} 419}
420 420
421/*
422 * Checksum routine for Internet Protocol family headers (C Version)
423 */
424static uint16_t
425in_cksum(uint16_t *addr, int len)
426{
427 int nleft = len;
428 uint16_t *w = addr;
429 uint16_t answer;
430 int sum = 0;
431
432 /*
433 * Our algorithm is simple, using a 32 bit accumulator (sum),
434 * we add sequential 16 bit words to it, and at the end, fold
435 * back all the carry bits from the top 16 bits into the lower
436 * 16 bits.
437 */
438 while (nleft > 1) {
439 sum += *w++;
440 nleft -= 2;
441 }
442
443 /* mop up an odd byte, if necessary */
444 if (nleft == 1)
445 sum += *(unsigned char *)w;
446
447 /* add back carry outs from top 16 bits to low 16 bits */
448 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
449 sum += (sum >> 16); /* add carry */
450 answer = ~sum; /* truncate to 16 bits */
451 return answer;
452}
453
454static void 421static void
455send_probe(int seq, int ttl) 422send_probe(int seq, int ttl)
456{ 423{
@@ -477,7 +444,7 @@ send_probe(int seq, int ttl)
477 444
478 /* Always calculate checksum for icmp packets */ 445 /* Always calculate checksum for icmp packets */
479 outicmp->icmp_cksum = 0; 446 outicmp->icmp_cksum = 0;
480 outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, 447 outicmp->icmp_cksum = inet_cksum((uint16_t *)outicmp,
481 packlen - (sizeof(*outip) + optlen)); 448 packlen - (sizeof(*outip) + optlen));
482 if (outicmp->icmp_cksum == 0) 449 if (outicmp->icmp_cksum == 0)
483 outicmp->icmp_cksum = 0xffff; 450 outicmp->icmp_cksum = 0xffff;
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 70e34614c..2e6113627 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -36,6 +36,9 @@ const struct dhcp_optflag dhcp_optflags[] = {
36 { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */ 36 { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */
37 { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */ 37 { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */
38 { OPTION_U16 , 0x1a }, /* DHCP_MTU */ 38 { OPTION_U16 , 0x1a }, /* DHCP_MTU */
39//TODO: why do we request DHCP_BROADCAST? Can't we assume that
40//in the unlikely case it is different from typical N.N.255.255,
41//server would let us know anyway?
39 { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ 42 { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */
40 { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */ 43 { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */
41 { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ 44 { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */
@@ -59,6 +62,7 @@ const struct dhcp_optflag dhcp_optflags[] = {
59 { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */ 62 { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */
60 { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */ 63 { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */
61#endif 64#endif
65 { OPTION_6RD , 0xd4 }, /* DHCP_6RD */
62 { OPTION_STATIC_ROUTES , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ 66 { OPTION_STATIC_ROUTES , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
63 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ 67 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */
64 68
@@ -126,6 +130,7 @@ const char dhcp_option_strings[] ALIGN1 =
126 "vlanid" "\0" /* DHCP_VLAN_ID */ 130 "vlanid" "\0" /* DHCP_VLAN_ID */
127 "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */ 131 "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */
128#endif 132#endif
133 "ip6rd" "\0" /* DHCP_6RD */
129 "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ 134 "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
130 "wpad" "\0" /* DHCP_WPAD */ 135 "wpad" "\0" /* DHCP_WPAD */
131 ; 136 ;
@@ -154,6 +159,7 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = {
154 [OPTION_S32] = 4, 159 [OPTION_S32] = 4,
155 /* Just like OPTION_STRING, we use minimum length here */ 160 /* Just like OPTION_STRING, we use minimum length here */
156 [OPTION_STATIC_ROUTES] = 5, 161 [OPTION_STATIC_ROUTES] = 5,
162 [OPTION_6RD] = 22, /* ignored by udhcp_str2optset */
157}; 163};
158 164
159 165
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index ad6991c94..a7f9395b8 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -88,6 +88,7 @@ enum {
88 OPTION_S32, 88 OPTION_S32,
89 OPTION_BIN, 89 OPTION_BIN,
90 OPTION_STATIC_ROUTES, 90 OPTION_STATIC_ROUTES,
91 OPTION_6RD,
91#if ENABLE_FEATURE_UDHCP_RFC3397 92#if ENABLE_FEATURE_UDHCP_RFC3397
92 OPTION_DNS_STRING, /* RFC1035 compressed domain name list */ 93 OPTION_DNS_STRING, /* RFC1035 compressed domain name list */
93 OPTION_SIP_SERVERS, 94 OPTION_SIP_SERVERS,
@@ -103,7 +104,7 @@ enum {
103/* DHCP option codes (partial list). See RFC 2132 and 104/* DHCP option codes (partial list). See RFC 2132 and
104 * http://www.iana.org/assignments/bootp-dhcp-parameters/ 105 * http://www.iana.org/assignments/bootp-dhcp-parameters/
105 * Commented out options are handled by common option machinery, 106 * Commented out options are handled by common option machinery,
106 * uncommented ones have spacial cases (grep for them to see). 107 * uncommented ones have special cases (grep for them to see).
107 */ 108 */
108#define DHCP_PADDING 0x00 109#define DHCP_PADDING 0x00
109#define DHCP_SUBNET 0x01 110#define DHCP_SUBNET 0x01
@@ -248,6 +249,7 @@ struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code)
248/*** Logging ***/ 249/*** Logging ***/
249 250
250#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 251#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
252# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
251extern unsigned dhcp_verbose; 253extern unsigned dhcp_verbose;
252# define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0) 254# define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0)
253# if CONFIG_UDHCP_DEBUG >= 2 255# if CONFIG_UDHCP_DEBUG >= 2
@@ -263,6 +265,7 @@ void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC;
263# define log3(...) ((void)0) 265# define log3(...) ((void)0)
264# endif 266# endif
265#else 267#else
268# define IF_UDHCP_VERBOSE(...)
266# define udhcp_dump_packet(...) ((void)0) 269# define udhcp_dump_packet(...) ((void)0)
267# define log1(...) ((void)0) 270# define log1(...) ((void)0)
268# define log2(...) ((void)0) 271# define log2(...) ((void)0)
@@ -277,8 +280,6 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg);
277/* 2nd param is "struct option_set**" */ 280/* 2nd param is "struct option_set**" */
278int FAST_FUNC udhcp_str2optset(const char *str, void *arg); 281int FAST_FUNC udhcp_str2optset(const char *str, void *arg);
279 282
280uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC;
281
282void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; 283void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC;
283 284
284int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC; 285int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC;
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 4d755e6b8..3d4c397ff 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -100,6 +100,7 @@ static const uint8_t len_of_option_as_string[] = {
100 [OPTION_IP ] = sizeof("255.255.255.255 "), 100 [OPTION_IP ] = sizeof("255.255.255.255 "),
101 [OPTION_IP_PAIR ] = sizeof("255.255.255.255 ") * 2, 101 [OPTION_IP_PAIR ] = sizeof("255.255.255.255 ") * 2,
102 [OPTION_STATIC_ROUTES ] = sizeof("255.255.255.255/32 255.255.255.255 "), 102 [OPTION_STATIC_ROUTES ] = sizeof("255.255.255.255/32 255.255.255.255 "),
103 [OPTION_6RD ] = sizeof("32 128 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 255.255.255.255 "),
103 [OPTION_STRING ] = 1, 104 [OPTION_STRING ] = 1,
104#if ENABLE_FEATURE_UDHCP_RFC3397 105#if ENABLE_FEATURE_UDHCP_RFC3397
105 [OPTION_DNS_STRING ] = 1, /* unused */ 106 [OPTION_DNS_STRING ] = 1, /* unused */
@@ -123,6 +124,24 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
123 return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); 124 return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
124} 125}
125 126
127static int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip)
128{
129 char hexstrbuf[16 * 2];
130 bin2hex(hexstrbuf, (void*)ip, 16);
131 return sprintf(dest, /* "%s" */
132 "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s",
133 /* pre, */
134 hexstrbuf + 0 * 4,
135 hexstrbuf + 1 * 4,
136 hexstrbuf + 2 * 4,
137 hexstrbuf + 3 * 4,
138 hexstrbuf + 4 * 4,
139 hexstrbuf + 5 * 4,
140 hexstrbuf + 6 * 4,
141 hexstrbuf + 7 * 4
142 );
143}
144
126/* really simple implementation, just count the bits */ 145/* really simple implementation, just count the bits */
127static int mton(uint32_t mask) 146static int mton(uint32_t mask)
128{ 147{
@@ -142,27 +161,25 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
142 int len, type, optlen; 161 int len, type, optlen;
143 char *dest, *ret; 162 char *dest, *ret;
144 163
145 /* option points to OPT_DATA, need to go back and get OPT_LEN */ 164 /* option points to OPT_DATA, need to go back to get OPT_LEN */
146 len = option[OPT_LEN - OPT_DATA]; 165 len = option[-OPT_DATA + OPT_LEN];
147 166
148 type = optflag->flags & OPTION_TYPE_MASK; 167 type = optflag->flags & OPTION_TYPE_MASK;
149 optlen = dhcp_option_lengths[type]; 168 optlen = dhcp_option_lengths[type];
150 upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen); 169 upper_length = len_of_option_as_string[type]
170 * ((unsigned)(len + optlen - 1) / (unsigned)optlen);
151 171
152 dest = ret = xmalloc(upper_length + strlen(opt_name) + 2); 172 dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
153 dest += sprintf(ret, "%s=", opt_name); 173 dest += sprintf(ret, "%s=", opt_name);
154 174
155 while (len >= optlen) { 175 while (len >= optlen) {
156 unsigned ip_ofs = 0;
157
158 switch (type) { 176 switch (type) {
177 case OPTION_IP:
159 case OPTION_IP_PAIR: 178 case OPTION_IP_PAIR:
160 dest += sprint_nip(dest, "", option); 179 dest += sprint_nip(dest, "", option);
161 *dest++ = '/'; 180 if (type == OPTION_IP)
162 ip_ofs = 4; 181 break;
163 /* fall through */ 182 dest += sprint_nip(dest, "/", option + 4);
164 case OPTION_IP:
165 dest += sprint_nip(dest, "", option + ip_ofs);
166 break; 183 break;
167// case OPTION_BOOLEAN: 184// case OPTION_BOOLEAN:
168// dest += sprintf(dest, *option ? "yes" : "no"); 185// dest += sprintf(dest, *option ? "yes" : "no");
@@ -184,10 +201,14 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
184 dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32)); 201 dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32));
185 break; 202 break;
186 } 203 }
204 /* Note: options which use 'return' instead of 'break'
205 * (for example, OPTION_STRING) skip the code which handles
206 * the case of list of options.
207 */
187 case OPTION_STRING: 208 case OPTION_STRING:
188 memcpy(dest, option, len); 209 memcpy(dest, option, len);
189 dest[len] = '\0'; 210 dest[len] = '\0';
190 return ret; /* Short circuit this case */ 211 return ret;
191 case OPTION_STATIC_ROUTES: { 212 case OPTION_STATIC_ROUTES: {
192 /* Option binary format: 213 /* Option binary format:
193 * mask [one byte, 0..32] 214 * mask [one byte, 0..32]
@@ -232,6 +253,53 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
232 253
233 return ret; 254 return ret;
234 } 255 }
256 case OPTION_6RD:
257 /* Option binary format (see RFC 5969):
258 * 0 1 2 3
259 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
260 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
261 * | OPTION_6RD | option-length | IPv4MaskLen | 6rdPrefixLen |
262 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
263 * | 6rdPrefix |
264 * ... (16 octets) ...
265 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
266 * ... 6rdBRIPv4Address(es) ...
267 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
268 * We convert it to a string
269 * "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address..."
270 *
271 * Sanity check: ensure that our length is at least 22 bytes, that
272 * IPv4MaskLen <= 32,
273 * 6rdPrefixLen <= 128,
274 * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128
275 * (2nd condition need no check - it follows from 1st and 3rd).
276 * Else, return envvar with empty value ("optname=")
277 */
278 if (len >= (1 + 1 + 16 + 4)
279 && option[0] <= 32
280 && (option[1] + 32 - option[0]) <= 128
281 ) {
282 /* IPv4MaskLen */
283 dest += sprintf(dest, "%u ", *option++);
284 /* 6rdPrefixLen */
285 dest += sprintf(dest, "%u ", *option++);
286 /* 6rdPrefix */
287 dest += sprint_nip6(dest, /* "", */ option);
288 option += 16;
289 len -= 1 + 1 + 16 + 4;
290 /* "+ 4" above corresponds to the length of IPv4 addr
291 * we consume in the loop below */
292 while (1) {
293 /* 6rdBRIPv4Address(es) */
294 dest += sprint_nip(dest, " ", option);
295 option += 4;
296 len -= 4; /* do we have yet another 4+ bytes? */
297 if (len < 0)
298 break; /* no */
299 }
300 }
301
302 return ret;
235#if ENABLE_FEATURE_UDHCP_RFC3397 303#if ENABLE_FEATURE_UDHCP_RFC3397
236 case OPTION_DNS_STRING: 304 case OPTION_DNS_STRING:
237 /* unpack option into dest; use ret for prefix (i.e., "optname=") */ 305 /* unpack option into dest; use ret for prefix (i.e., "optname=") */
@@ -271,16 +339,21 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
271 return ret; 339 return ret;
272#endif 340#endif
273 } /* switch */ 341 } /* switch */
342
343 /* If we are here, try to format any remaining data
344 * in the option as another, similarly-formatted option
345 */
274 option += optlen; 346 option += optlen;
275 len -= optlen; 347 len -= optlen;
276// TODO: it can be a list only if (optflag->flags & OPTION_LIST). 348// TODO: it can be a list only if (optflag->flags & OPTION_LIST).
277// Should we bail out/warn if we see multi-ip option which is 349// Should we bail out/warn if we see multi-ip option which is
278// not allowed to be such (for example, DHCP_BROADCAST)? - 350// not allowed to be such (for example, DHCP_BROADCAST)? -
279 if (len <= 0 /* || !(optflag->flags & OPTION_LIST) */) 351 if (len < optlen /* || !(optflag->flags & OPTION_LIST) */)
280 break; 352 break;
281 *dest++ = ' '; 353 *dest++ = ' ';
282 *dest = '\0'; 354 *dest = '\0';
283 } 355 } /* while */
356
284 return ret; 357 return ret;
285} 358}
286 359
@@ -320,7 +393,7 @@ static char **fill_envp(struct dhcp_packet *packet)
320 if (i == DHCP_OPTION_OVERLOAD) 393 if (i == DHCP_OPTION_OVERLOAD)
321 overload = *temp; 394 overload = *temp;
322 else if (i == DHCP_SUBNET) 395 else if (i == DHCP_SUBNET)
323 envc++; /* for mton */ 396 envc++; /* for $mask */
324 envc++; 397 envc++;
325 /*if (i != DHCP_MESSAGE_TYPE)*/ 398 /*if (i != DHCP_MESSAGE_TYPE)*/
326 FOUND_OPTS(i) |= BMASK(i); 399 FOUND_OPTS(i) |= BMASK(i);
@@ -335,10 +408,42 @@ static char **fill_envp(struct dhcp_packet *packet)
335 if (!packet) 408 if (!packet)
336 return envp; 409 return envp;
337 410
411 /* Export BOOTP fields. Fields we don't (yet?) export:
412 * uint8_t op; // always BOOTREPLY
413 * uint8_t htype; // hardware address type. 1 = 10mb ethernet
414 * uint8_t hlen; // hardware address length
415 * uint8_t hops; // used by relay agents only
416 * uint32_t xid;
417 * uint16_t secs; // elapsed since client began acquisition/renewal
418 * uint16_t flags; // only one flag so far: bcast. Never set by server
419 * uint32_t ciaddr; // client IP (usually == yiaddr. can it be different
420 * // if during renew server wants to give us differn IP?)
421 * uint32_t gateway_nip; // relay agent IP address
422 * uint8_t chaddr[16]; // link-layer client hardware address (MAC)
423 * TODO: export gateway_nip as $giaddr?
424 */
425 /* Most important one: yiaddr as $ip */
338 *curr = xmalloc(sizeof("ip=255.255.255.255")); 426 *curr = xmalloc(sizeof("ip=255.255.255.255"));
339 sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr); 427 sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr);
340 putenv(*curr++); 428 putenv(*curr++);
429 if (packet->siaddr_nip) {
430 /* IP address of next server to use in bootstrap */
431 *curr = xmalloc(sizeof("siaddr=255.255.255.255"));
432 sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip);
433 putenv(*curr++);
434 }
435 if (!(overload & FILE_FIELD) && packet->file[0]) {
436 /* watch out for invalid packets */
437 *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file);
438 putenv(*curr++);
439 }
440 if (!(overload & SNAME_FIELD) && packet->sname[0]) {
441 /* watch out for invalid packets */
442 *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname);
443 putenv(*curr++);
444 }
341 445
446 /* Export known DHCP options */
342 opt_name = dhcp_option_strings; 447 opt_name = dhcp_option_strings;
343 i = 0; 448 i = 0;
344 while (*opt_name) { 449 while (*opt_name) {
@@ -355,29 +460,14 @@ static char **fill_envp(struct dhcp_packet *packet)
355 /* Subnet option: make things like "$ip/$mask" possible */ 460 /* Subnet option: make things like "$ip/$mask" possible */
356 uint32_t subnet; 461 uint32_t subnet;
357 move_from_unaligned32(subnet, temp); 462 move_from_unaligned32(subnet, temp);
358 *curr = xasprintf("mask=%d", mton(subnet)); 463 *curr = xasprintf("mask=%u", mton(subnet));
359 putenv(*curr++); 464 putenv(*curr++);
360 } 465 }
361 next: 466 next:
362 opt_name += strlen(opt_name) + 1; 467 opt_name += strlen(opt_name) + 1;
363 i++; 468 i++;
364 } 469 }
365 if (packet->siaddr_nip) { 470 /* Export unknown options */
366 *curr = xmalloc(sizeof("siaddr=255.255.255.255"));
367 sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip);
368 putenv(*curr++);
369 }
370 if (!(overload & FILE_FIELD) && packet->file[0]) {
371 /* watch out for invalid packets */
372 *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file);
373 putenv(*curr++);
374 }
375 if (!(overload & SNAME_FIELD) && packet->sname[0]) {
376 /* watch out for invalid packets */
377 *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname);
378 putenv(*curr++);
379 }
380 /* Handle unknown options */
381 for (i = 0; i < 256;) { 471 for (i = 0; i < 256;) {
382 BITMAP bitmap = FOUND_OPTS(i); 472 BITMAP bitmap = FOUND_OPTS(i);
383 if (!bitmap) { 473 if (!bitmap) {
@@ -394,11 +484,12 @@ static char **fill_envp(struct dhcp_packet *packet)
394 len = temp[-OPT_DATA + OPT_LEN]; 484 len = temp[-OPT_DATA + OPT_LEN];
395 *curr = xmalloc(sizeof("optNNN=") + 1 + len*2); 485 *curr = xmalloc(sizeof("optNNN=") + 1 + len*2);
396 ofs = sprintf(*curr, "opt%u=", i); 486 ofs = sprintf(*curr, "opt%u=", i);
397 bin2hex(*curr + ofs, (void*) temp, len)[0] = '\0'; 487 *bin2hex(*curr + ofs, (void*) temp, len) = '\0';
398 putenv(*curr++); 488 putenv(*curr++);
399 } 489 }
400 i++; 490 i++;
401 } 491 }
492
402 return envp; 493 return envp;
403} 494}
404 495
@@ -726,7 +817,8 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
726 bytes = ntohs(packet.ip.tot_len); 817 bytes = ntohs(packet.ip.tot_len);
727 818
728 /* make sure its the right packet for us, and that it passes sanity checks */ 819 /* make sure its the right packet for us, and that it passes sanity checks */
729 if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION 820 if (packet.ip.protocol != IPPROTO_UDP
821 || packet.ip.version != IPVERSION
730 || packet.ip.ihl != (sizeof(packet.ip) >> 2) 822 || packet.ip.ihl != (sizeof(packet.ip) >> 2)
731 || packet.udp.dest != htons(CLIENT_PORT) 823 || packet.udp.dest != htons(CLIENT_PORT)
732 /* || bytes > (int) sizeof(packet) - can't happen */ 824 /* || bytes > (int) sizeof(packet) - can't happen */
@@ -739,7 +831,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
739 /* verify IP checksum */ 831 /* verify IP checksum */
740 check = packet.ip.check; 832 check = packet.ip.check;
741 packet.ip.check = 0; 833 packet.ip.check = 0;
742 if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) { 834 if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) {
743 log1("Bad IP header checksum, ignoring"); 835 log1("Bad IP header checksum, ignoring");
744 return -2; 836 return -2;
745 } 837 }
@@ -750,20 +842,22 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
750 packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ 842 packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
751 check = packet.udp.check; 843 check = packet.udp.check;
752 packet.udp.check = 0; 844 packet.udp.check = 0;
753 if (check && check != udhcp_checksum(&packet, bytes)) { 845 if (check && check != inet_cksum((uint16_t *)&packet, bytes)) {
754 log1("Packet with bad UDP checksum received, ignoring"); 846 log1("Packet with bad UDP checksum received, ignoring");
755 return -2; 847 return -2;
756 } 848 }
757 849
758 memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp))); 850 if (packet.data.cookie != htonl(DHCP_MAGIC)) {
759
760 if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) {
761 bb_info_msg("Packet with bad magic, ignoring"); 851 bb_info_msg("Packet with bad magic, ignoring");
762 return -2; 852 return -2;
763 } 853 }
854
764 log1("Got valid DHCP packet"); 855 log1("Got valid DHCP packet");
765 udhcp_dump_packet(dhcp_pkt); 856 udhcp_dump_packet(&packet.data);
766 return bytes - (sizeof(packet.ip) + sizeof(packet.udp)); 857
858 bytes -= sizeof(packet.ip) + sizeof(packet.udp);
859 memcpy(dhcp_pkt, &packet.data, bytes);
860 return bytes;
767} 861}
768 862
769 863
@@ -1077,11 +1171,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1077 1171
1078 /* Parse command line */ 1172 /* Parse command line */
1079 /* O,x: list; -T,-t,-A take numeric param */ 1173 /* O,x: list; -T,-t,-A take numeric param */
1080 opt_complementary = "O::x::T+:t+:A+" 1174 opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ;
1081#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
1082 ":vv"
1083#endif
1084 ;
1085 IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) 1175 IF_LONG_OPTS(applet_long_options = udhcpc_longopts;)
1086 opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB" 1176 opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB"
1087 USE_FOR_MMU("b") 1177 USE_FOR_MMU("b")
@@ -1095,9 +1185,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1095 , &list_O 1185 , &list_O
1096 , &list_x 1186 , &list_x
1097 IF_FEATURE_UDHCP_PORT(, &str_P) 1187 IF_FEATURE_UDHCP_PORT(, &str_P)
1098#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 1188 IF_UDHCP_VERBOSE(, &dhcp_verbose)
1099 , &dhcp_verbose
1100#endif
1101 ); 1189 );
1102 if (opt & (OPT_h|OPT_H)) 1190 if (opt & (OPT_h|OPT_H))
1103 client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); 1191 client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
@@ -1361,9 +1449,23 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1361 switch (udhcp_sp_read(&rfds)) { 1449 switch (udhcp_sp_read(&rfds)) {
1362 case SIGUSR1: 1450 case SIGUSR1:
1363 client_config.first_secs = 0; /* make secs field count from 0 */ 1451 client_config.first_secs = 0; /* make secs field count from 0 */
1452 already_waited_sec = 0;
1364 perform_renew(); 1453 perform_renew();
1365 if (state == RENEW_REQUESTED) 1454 if (state == RENEW_REQUESTED) {
1455 /* We might be either on the same network
1456 * (in which case renew might work),
1457 * or we might be on a completely different one
1458 * (in which case renew won't ever succeed).
1459 * For the second case, must make sure timeout
1460 * is not too big, or else we can send
1461 * futile renew requests for hours.
1462 * (Ab)use -A TIMEOUT value (usually 20 sec)
1463 * as a cap on the timeout.
1464 */
1465 if (timeout > tryagain_timeout)
1466 timeout = tryagain_timeout;
1366 goto case_RENEW_REQUESTED; 1467 goto case_RENEW_REQUESTED;
1468 }
1367 /* Start things over */ 1469 /* Start things over */
1368 packet_num = 0; 1470 packet_num = 0;
1369 /* Kill any timeouts, user wants this to hurry along */ 1471 /* Kill any timeouts, user wants this to hurry along */
@@ -1431,7 +1533,25 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1431 case INIT_SELECTING: 1533 case INIT_SELECTING:
1432 /* Must be a DHCPOFFER to one of our xid's */ 1534 /* Must be a DHCPOFFER to one of our xid's */
1433 if (*message == DHCPOFFER) { 1535 if (*message == DHCPOFFER) {
1434 /* TODO: why we don't just fetch server's IP from IP header? */ 1536/* What exactly is server's IP? There are several values.
1537 * Example DHCP offer captured with tchdump:
1538 *
1539 * 10.34.25.254:67 > 10.34.25.202:68 // IP header's src
1540 * BOOTP fields:
1541 * Your-IP 10.34.25.202
1542 * Server-IP 10.34.32.125 // "next server" IP
1543 * Gateway-IP 10.34.25.254 // relay's address (if DHCP relays are in use)
1544 * DHCP options:
1545 * DHCP-Message Option 53, length 1: Offer
1546 * Server-ID Option 54, length 4: 10.34.255.7 // "server ID"
1547 * Default-Gateway Option 3, length 4: 10.34.25.254 // router
1548 *
1549 * We think that real server IP (one to use in renew/release)
1550 * is one in Server-ID option. But I am not 100% sure.
1551 * IP header's src and Gateway-IP (same in this example)
1552 * might work too.
1553 * "Next server" and router are definitely wrong ones to use, though...
1554 */
1435 temp = udhcp_get_option(&packet, DHCP_SERVER_ID); 1555 temp = udhcp_get_option(&packet, DHCP_SERVER_ID);
1436 if (!temp) { 1556 if (!temp) {
1437 bb_error_msg("no server ID, ignoring packet"); 1557 bb_error_msg("no server ID, ignoring packet");
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 747472d0c..dd55e70f4 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -314,9 +314,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
314#endif 314#endif
315 opt = getopt32(argv, "fSv" 315 opt = getopt32(argv, "fSv"
316 IF_FEATURE_UDHCP_PORT("P:", &str_P) 316 IF_FEATURE_UDHCP_PORT("P:", &str_P)
317#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 317 IF_UDHCP_VERBOSE(, &dhcp_verbose)
318 , &dhcp_verbose
319#endif
320 ); 318 );
321 if (!(opt & 1)) { /* no -f */ 319 if (!(opt & 1)) { /* no -f */
322 bb_daemonize_or_rexec(0, argv); 320 bb_daemonize_or_rexec(0, argv);
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c
index 66b42c5e1..4d5ff0676 100644
--- a/networking/udhcp/packet.c
+++ b/networking/udhcp/packet.c
@@ -129,35 +129,6 @@ int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd)
129 return bytes; 129 return bytes;
130} 130}
131 131
132uint16_t FAST_FUNC udhcp_checksum(void *addr, int count)
133{
134 /* Compute Internet Checksum for "count" bytes
135 * beginning at location "addr".
136 */
137 int32_t sum = 0;
138 uint16_t *source = (uint16_t *) addr;
139
140 while (count > 1) {
141 /* This is the inner loop */
142 sum += *source++;
143 count -= 2;
144 }
145
146 /* Add left-over byte, if any */
147 if (count > 0) {
148 /* Make sure that the left-over byte is added correctly both
149 * with little and big endian hosts */
150 uint16_t tmp = 0;
151 *(uint8_t*)&tmp = *(uint8_t*)source;
152 sum += tmp;
153 }
154 /* Fold 32-bit sum to 16 bits */
155 while (sum >> 16)
156 sum = (sum & 0xffff) + (sum >> 16);
157
158 return ~sum;
159}
160
161/* Construct a ip/udp header for a packet, send packet */ 132/* Construct a ip/udp header for a packet, send packet */
162int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, 133int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
163 uint32_t source_nip, int source_port, 134 uint32_t source_nip, int source_port,
@@ -212,13 +183,14 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
212 packet.udp.len = htons(UDP_DHCP_SIZE - padding); 183 packet.udp.len = htons(UDP_DHCP_SIZE - padding);
213 /* for UDP checksumming, ip.len is set to UDP packet len */ 184 /* for UDP checksumming, ip.len is set to UDP packet len */
214 packet.ip.tot_len = packet.udp.len; 185 packet.ip.tot_len = packet.udp.len;
215 packet.udp.check = udhcp_checksum(&packet, IP_UDP_DHCP_SIZE - padding); 186 packet.udp.check = inet_cksum((uint16_t *)&packet,
187 IP_UDP_DHCP_SIZE - padding);
216 /* but for sending, it is set to IP packet len */ 188 /* but for sending, it is set to IP packet len */
217 packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); 189 packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding);
218 packet.ip.ihl = sizeof(packet.ip) >> 2; 190 packet.ip.ihl = sizeof(packet.ip) >> 2;
219 packet.ip.version = IPVERSION; 191 packet.ip.version = IPVERSION;
220 packet.ip.ttl = IPDEFTTL; 192 packet.ip.ttl = IPDEFTTL;
221 packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip)); 193 packet.ip.check = inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip));
222 194
223 udhcp_dump_packet(dhcp_pkt); 195 udhcp_dump_packet(dhcp_pkt);
224 result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, 196 result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0,
diff --git a/networking/wget.c b/networking/wget.c
index eca673a86..4dd42de9d 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -298,8 +298,13 @@ static void parse_url(const char *src_url, struct host_info *h)
298 298
299 sp = strrchr(h->host, '@'); 299 sp = strrchr(h->host, '@');
300 if (sp != NULL) { 300 if (sp != NULL) {
301 h->user = h->host; 301 // URL-decode "user:password" string before base64-encoding:
302 // wget http://test:my%20pass@example.com should send
303 // Authorization: Basic dGVzdDpteSBwYXNz
304 // which decodes to "test:my pass".
305 // Standard wget and curl do this too.
302 *sp = '\0'; 306 *sp = '\0';
307 h->user = percent_decode_in_place(h->host, /*strict:*/ 0);
303 h->host = sp + 1; 308 h->host = sp + 1;
304 } 309 }
305 310
@@ -660,12 +665,6 @@ static void download_one_url(const char *url)
660 665
661#if ENABLE_FEATURE_WGET_AUTHENTICATION 666#if ENABLE_FEATURE_WGET_AUTHENTICATION
662 if (target.user) { 667 if (target.user) {
663//TODO: URL-decode "user:password" string before base64-encoding:
664//wget http://test:my%20pass@example.com should send
665// Authorization: Basic dGVzdDpteSBwYXNz
666//which decodes to "test:my pass", instead of what we send now:
667// Authorization: Basic dGVzdDpteSUyMHBhc3M=
668//Can reuse decodeString() from httpd.c
669 fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, 668 fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6,
670 base64enc(target.user)); 669 base64enc(target.user));
671 } 670 }
diff --git a/networking/zcip.c b/networking/zcip.c
index 8a35eca5d..7314ff8db 100644
--- a/networking/zcip.c
+++ b/networking/zcip.c
@@ -91,6 +91,7 @@ struct globals {
91#define G (*(struct globals*)&bb_common_bufsiz1) 91#define G (*(struct globals*)&bb_common_bufsiz1)
92#define saddr (G.saddr ) 92#define saddr (G.saddr )
93#define eth_addr (G.eth_addr) 93#define eth_addr (G.eth_addr)
94#define INIT_G() do { } while (0)
94 95
95 96
96/** 97/**
@@ -223,6 +224,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
223#define verbose (L.verbose ) 224#define verbose (L.verbose )
224 225
225 memset(&L, 0, sizeof(L)); 226 memset(&L, 0, sizeof(L));
227 INIT_G();
226 228
227#define FOREGROUND (opts & 1) 229#define FOREGROUND (opts & 1)
228#define QUIT (opts & 2) 230#define QUIT (opts & 2)
diff --git a/procps/Config.src b/procps/Config.src
index 570b026da..5cd47c84f 100644
--- a/procps/Config.src
+++ b/procps/Config.src
@@ -90,12 +90,20 @@ config PS
90config FEATURE_PS_WIDE 90config FEATURE_PS_WIDE
91 bool "Enable wide output option (-w)" 91 bool "Enable wide output option (-w)"
92 default y 92 default y
93 depends on PS 93 depends on PS && !DESKTOP
94 help 94 help
95 Support argument 'w' for wide output. 95 Support argument 'w' for wide output.
96 If given once, 132 chars are printed, and if given more 96 If given once, 132 chars are printed, and if given more
97 than once, the length is unlimited. 97 than once, the length is unlimited.
98 98
99config FEATURE_PS_LONG
100 bool "Enable long output option (-l)"
101 default y
102 depends on PS && !DESKTOP
103 help
104 Support argument 'l' for long output.
105 Adds fields PPID, RSS, START, TIME & TTY
106
99config FEATURE_PS_TIME 107config FEATURE_PS_TIME
100 bool "Enable time and elapsed time output" 108 bool "Enable time and elapsed time output"
101 default y 109 default y
diff --git a/procps/nmeter.c b/procps/nmeter.c
index 999955982..ed5479024 100644
--- a/procps/nmeter.c
+++ b/procps/nmeter.c
@@ -274,30 +274,56 @@ static int rdval_loadavg(const char* p, ullong *vec, ...)
274// 1 2 3 4 5 6(rd) 7 8 9 10(wr) 11 12 13 14 274// 1 2 3 4 5 6(rd) 7 8 9 10(wr) 11 12 13 14
275// 3 0 hda 51292 14441 841783 926052 25717 79650 843256 3029804 0 148459 3956933 275// 3 0 hda 51292 14441 841783 926052 25717 79650 843256 3029804 0 148459 3956933
276// 3 1 hda1 0 0 0 0 <- ignore if only 4 fields 276// 3 1 hda1 0 0 0 0 <- ignore if only 4 fields
277// Linux 3.0 (maybe earlier) started printing full stats for hda1 too.
278// Had to add code which skips such devices.
277static int rdval_diskstats(const char* p, ullong *vec) 279static int rdval_diskstats(const char* p, ullong *vec)
278{ 280{
279 ullong rd = rd; // for compiler 281 char devname[32];
280 int indexline = 0; 282 unsigned devname_len = 0;
283 int value_idx = 0;
284
281 vec[0] = 0; 285 vec[0] = 0;
282 vec[1] = 0; 286 vec[1] = 0;
283 while (1) { 287 while (1) {
284 indexline++; 288 value_idx++;
285 while (*p == ' ' || *p == '\t') p++; 289 while (*p == ' ' || *p == '\t')
286 if (*p == '\0') break; 290 p++;
291 if (*p == '\0')
292 break;
287 if (*p == '\n') { 293 if (*p == '\n') {
288 indexline = 0; 294 value_idx = 0;
289 p++; 295 p++;
290 continue; 296 continue;
291 } 297 }
292 if (indexline == 6) { 298 if (value_idx == 3) {
293 rd = strtoull(p, NULL, 10); 299 char *end = strchrnul(p, ' ');
294 } else if (indexline == 10) { 300 /* If this a hda1-like device (same prefix as last one + digit)? */
295 vec[0] += rd; // TODO: *sectorsize (don't know how to find out sectorsize) 301 if (devname_len && strncmp(devname, p, devname_len) == 0 && isdigit(p[devname_len])) {
302 p = end;
303 goto skip_line; /* skip entire line */
304 }
305 /* It is not. Remember the name for future checks */
306 devname_len = end - p;
307 if (devname_len > sizeof(devname)-1)
308 devname_len = sizeof(devname)-1;
309 strncpy(devname, p, devname_len);
310 /* devname[devname_len] = '\0'; - not really needed */
311 p = end;
312 } else
313 if (value_idx == 6) {
314 // TODO: *sectorsize (don't know how to find out sectorsize)
315 vec[0] += strtoull(p, NULL, 10);
316 } else
317 if (value_idx == 10) {
318 // TODO: *sectorsize (don't know how to find out sectorsize)
296 vec[1] += strtoull(p, NULL, 10); 319 vec[1] += strtoull(p, NULL, 10);
297 while (*p != '\n' && *p != '\0') p++; 320 skip_line:
321 while (*p != '\n' && *p != '\0')
322 p++;
298 continue; 323 continue;
299 } 324 }
300 while (*p > ' ') p++; // skip over value 325 while ((unsigned char)(*p) > ' ') // skip over value
326 p++;
301 } 327 }
302 return 0; 328 return 0;
303} 329}
diff --git a/procps/ps.c b/procps/ps.c
index af57f7aee..aa004aa22 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -39,6 +39,12 @@
39//usage: IF_FEATURE_PS_WIDE( 39//usage: IF_FEATURE_PS_WIDE(
40//usage: "\n w Wide output" 40//usage: "\n w Wide output"
41//usage: ) 41//usage: )
42//usage: IF_FEATURE_PS_LONG(
43//usage: "\n l Long output"
44//usage: )
45//usage: IF_FEATURE_SHOW_THREADS(
46//usage: "\n T Show threads"
47//usage: )
42//usage: 48//usage:
43//usage:#endif /* ENABLE_DESKTOP */ 49//usage:#endif /* ENABLE_DESKTOP */
44//usage: 50//usage:
@@ -56,15 +62,15 @@
56//usage: " 2990 andersen andersen R ps\n" 62//usage: " 2990 andersen andersen R ps\n"
57 63
58#include "libbb.h" 64#include "libbb.h"
65#ifdef __linux__
66# include <sys/sysinfo.h>
67#endif
59 68
60/* Absolute maximum on output line length */ 69/* Absolute maximum on output line length */
61enum { MAX_WIDTH = 2*1024 }; 70enum { MAX_WIDTH = 2*1024 };
62 71
63#if ENABLE_DESKTOP 72#if ENABLE_DESKTOP
64 73
65#ifdef __linux__
66# include <sys/sysinfo.h>
67#endif
68#include <sys/times.h> /* for times() */ 74#include <sys/times.h> /* for times() */
69#ifndef AT_CLKTCK 75#ifndef AT_CLKTCK
70# define AT_CLKTCK 17 76# define AT_CLKTCK 17
@@ -635,15 +641,21 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
635 enum { 641 enum {
636 OPT_Z = (1 << 0) * ENABLE_SELINUX, 642 OPT_Z = (1 << 0) * ENABLE_SELINUX,
637 OPT_T = (1 << ENABLE_SELINUX) * ENABLE_FEATURE_SHOW_THREADS, 643 OPT_T = (1 << ENABLE_SELINUX) * ENABLE_FEATURE_SHOW_THREADS,
644 OPT_l = (1 << ENABLE_SELINUX) * (1 << ENABLE_FEATURE_SHOW_THREADS) * ENABLE_FEATURE_PS_LONG,
638 }; 645 };
646#if ENABLE_FEATURE_PS_LONG
647 time_t now = now;
648 struct sysinfo info;
649#endif
639 int opts = 0; 650 int opts = 0;
640 /* If we support any options, parse argv */ 651 /* If we support any options, parse argv */
641#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE 652#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE || ENABLE_FEATURE_PS_LONG
642# if ENABLE_FEATURE_PS_WIDE 653# if ENABLE_FEATURE_PS_WIDE
643 /* -w is a bit complicated */ 654 /* -w is a bit complicated */
644 int w_count = 0; 655 int w_count = 0;
645 opt_complementary = "-:ww"; 656 opt_complementary = "-:ww";
646 opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")"w", &w_count); 657 opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")
658 "w", &w_count);
647 /* if w is given once, GNU ps sets the width to 132, 659 /* if w is given once, GNU ps sets the width to 132,
648 * if w is given more than once, it is "unlimited" 660 * if w is given more than once, it is "unlimited"
649 */ 661 */
@@ -658,23 +670,51 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
658# else 670# else
659 /* -w is not supported, only -Z and/or -T */ 671 /* -w is not supported, only -Z and/or -T */
660 opt_complementary = "-"; 672 opt_complementary = "-";
661 opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")); 673 opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l"));
662# endif 674# endif
663#endif
664 675
665#if ENABLE_SELINUX 676# if ENABLE_SELINUX
666 if ((opts & OPT_Z) && is_selinux_enabled()) { 677 if ((opts & OPT_Z) && is_selinux_enabled()) {
667 psscan_flags = PSSCAN_PID | PSSCAN_CONTEXT 678 psscan_flags = PSSCAN_PID | PSSCAN_CONTEXT
668 | PSSCAN_STATE | PSSCAN_COMM; 679 | PSSCAN_STATE | PSSCAN_COMM;
669 puts(" PID CONTEXT STAT COMMAND"); 680 puts(" PID CONTEXT STAT COMMAND");
670 } else 681 } else
682# endif
683 if (opts & OPT_l) {
684 psscan_flags = PSSCAN_STATE | PSSCAN_UIDGID | PSSCAN_PID | PSSCAN_PPID
685 | PSSCAN_TTY | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_COMM
686 | PSSCAN_VSZ | PSSCAN_RSS;
687/* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
688 * mandates for -l:
689 * -F Flags (?)
690 * S State
691 * UID,PID,PPID
692 * -C CPU usage
693 * -PRI The priority of the process; higher numbers mean lower priority
694 * -NI Nice value
695 * -ADDR The address of the process (?)
696 * SZ The size in blocks of the core image
697 * -WCHAN The event for which the process is waiting or sleeping
698 * TTY
699 * TIME The cumulative execution time
700 * CMD
701 * We don't show fields marked with '-'.
702 * We show VSZ and RSS instead of SZ.
703 * We also show STIME (standard says that -f shows it, -l doesn't).
704 */
705 puts("S UID PID PPID VSZ RSS TTY STIME TIME CMD");
706#if ENABLE_FEATURE_PS_LONG
707 now = time(NULL);
708 sysinfo(&info);
671#endif 709#endif
672 { 710 }
711 else {
673 puts(" PID USER VSZ STAT COMMAND"); 712 puts(" PID USER VSZ STAT COMMAND");
674 } 713 }
675 if (opts & OPT_T) { 714 if (opts & OPT_T) {
676 psscan_flags |= PSSCAN_TASKS; 715 psscan_flags |= PSSCAN_TASKS;
677 } 716 }
717#endif
678 718
679 p = NULL; 719 p = NULL;
680 while ((p = procps_scan(p, psscan_flags)) != NULL) { 720 while ((p = procps_scan(p, psscan_flags)) != NULL) {
@@ -688,15 +728,49 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
688 } else 728 } else
689#endif 729#endif
690 { 730 {
691 const char *user = get_cached_username(p->uid); 731 char buf6[6];
692 //if (p->vsz == 0) 732 smart_ulltoa5(p->vsz, buf6, " mgtpezy");
693 // len = printf("%5u %-8.8s %s ", 733 buf6[5] = '\0';
694 // p->pid, user, p->state); 734#if ENABLE_FEATURE_PS_LONG
695 //else 735 if (opts & OPT_l) {
736 char bufr[6], stime_str[6];
737 char tty[2 * sizeof(int)*3 + 2];
738 char *endp;
739 unsigned sut = (p->stime + p->utime) / 100;
740 unsigned elapsed = info.uptime - (p->start_time / 100);
741 time_t start = now - elapsed;
742 struct tm *tm = localtime(&start);
743
744 smart_ulltoa5(p->rss, bufr, " mgtpezy");
745 bufr[5] = '\0';
746
747 if (p->tty_major == 136)
748 /* It should be pts/N, not ptsN, but N > 9
749 * will overflow field width...
750 */
751 endp = stpcpy(tty, "pts");
752 else
753 if (p->tty_major == 4) {
754 endp = stpcpy(tty, "tty");
755 if (p->tty_minor >= 64) {
756 p->tty_minor -= 64;
757 *endp++ = 'S';
758 }
759 }
760 else
761 endp = tty + sprintf(tty, "%d:", p->tty_major);
762 strcpy(endp, utoa(p->tty_minor));
763
764 strftime(stime_str, 6, (elapsed >= (24 * 60 * 60)) ? "%b%d" : "%H:%M", tm);
765 stime_str[5] = '\0';
766 // S UID PID PPID VSZ RSS TTY STIME TIME CMD
767 len = printf("%c %5u %5u %5u %5s %5s %-5s %s %02u:%02u:%02u ",
768 p->state[0], p->uid, p->pid, p->ppid, buf6, bufr, tty,
769 stime_str, sut / 3600, (sut % 3600) / 60, sut % 60);
770 } else
771#endif
696 { 772 {
697 char buf6[6]; 773 const char *user = get_cached_username(p->uid);
698 smart_ulltoa5(p->vsz, buf6, " mgtpezy");
699 buf6[5] = '\0';
700 len = printf("%5u %-8.8s %s %s ", 774 len = printf("%5u %-8.8s %s %s ",
701 p->pid, user, buf6, p->state); 775 p->pid, user, buf6, p->state);
702 } 776 }
diff --git a/procps/smemcap.c b/procps/smemcap.c
index e108d88ad..9d1126a49 100644
--- a/procps/smemcap.c
+++ b/procps/smemcap.c
@@ -20,7 +20,7 @@
20//config: a memory usage statistic tool. 20//config: a memory usage statistic tool.
21 21
22#include "libbb.h" 22#include "libbb.h"
23#include "archive.h" 23#include "bb_archive.h"
24 24
25struct fileblock { 25struct fileblock {
26 struct fileblock *next; 26 struct fileblock *next;
diff --git a/procps/top.c b/procps/top.c
index 011bbf183..15eb624cc 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -126,7 +126,6 @@ struct BUG_bad_size {
126 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; 126 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
127 char BUG_line_buf_too_small[LINE_BUF_SIZE > 80 ? 1 : -1]; 127 char BUG_line_buf_too_small[LINE_BUF_SIZE > 80 ? 1 : -1];
128}; 128};
129#define INIT_G() do { } while (0)
130#define top (G.top ) 129#define top (G.top )
131#define ntop (G.ntop ) 130#define ntop (G.ntop )
132#define sort_field (G.sort_field ) 131#define sort_field (G.sort_field )
@@ -143,6 +142,7 @@ struct BUG_bad_size {
143#define num_cpus (G.num_cpus ) 142#define num_cpus (G.num_cpus )
144#define total_pcpu (G.total_pcpu ) 143#define total_pcpu (G.total_pcpu )
145#define line_buf (G.line_buf ) 144#define line_buf (G.line_buf )
145#define INIT_G() do { } while (0)
146 146
147enum { 147enum {
148 OPT_d = (1 << 0), 148 OPT_d = (1 << 0),
diff --git a/runit/chpst.c b/runit/chpst.c
index 185706089..9b8c99bdd 100644
--- a/runit/chpst.c
+++ b/runit/chpst.c
@@ -405,19 +405,17 @@ int chpst_main(int argc UNUSED_PARAM, char **argv)
405 if (opt & OPT_e) 405 if (opt & OPT_e)
406 edir(env_dir); 406 edir(env_dir);
407 407
408 // FIXME: chrooted jail must have /etc/passwd if we move this after chroot! 408 if (opt & (OPT_u|OPT_U))
409 // OTOH chroot fails for non-roots! 409 xget_uidgid(&ugid, set_user);
410 // SOLUTION: cache uid/gid before chroot, apply uid/gid after 410
411 // chrooted jail must have /etc/passwd if we move this after chroot.
412 // OTOH chroot fails for non-roots.
413 // Solution: cache uid/gid before chroot, apply uid/gid after.
411 if (opt & OPT_U) { 414 if (opt & OPT_U) {
412 xget_uidgid(&ugid, env_user);
413 xsetenv("GID", utoa(ugid.gid)); 415 xsetenv("GID", utoa(ugid.gid));
414 xsetenv("UID", utoa(ugid.uid)); 416 xsetenv("UID", utoa(ugid.uid));
415 } 417 }
416 418
417 if (opt & OPT_u) {
418 xget_uidgid(&ugid, set_user);
419 }
420
421 if (opt & OPT_root) { 419 if (opt & OPT_root) {
422 xchdir(root); 420 xchdir(root);
423 xchroot("."); 421 xchroot(".");
diff --git a/runit/runsvdir.c b/runit/runsvdir.c
index 9495a2a4f..32526cf4c 100644
--- a/runit/runsvdir.c
+++ b/runit/runsvdir.c
@@ -75,8 +75,7 @@ struct globals {
75#define logpipe (G.logpipe ) 75#define logpipe (G.logpipe )
76#define pfd (G.pfd ) 76#define pfd (G.pfd )
77#define stamplog (G.stamplog ) 77#define stamplog (G.stamplog )
78#define INIT_G() do { \ 78#define INIT_G() do { } while (0)
79} while (0)
80 79
81static void fatal2_cannot(const char *m1, const char *m2) 80static void fatal2_cannot(const char *m1, const char *m2)
82{ 81{
diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c
index 0984e7d4b..b12569832 100644
--- a/scripts/basic/docproc.c
+++ b/scripts/basic/docproc.c
@@ -39,6 +39,7 @@
39#include <limits.h> 39#include <limits.h>
40#include <sys/types.h> 40#include <sys/types.h>
41#include <sys/wait.h> 41#include <sys/wait.h>
42#include <alloca.h>
42 43
43/* exitstatus is used to keep track of any failing calls to kernel-doc, 44/* exitstatus is used to keep track of any failing calls to kernel-doc,
44 * but execution continues. */ 45 * but execution continues. */
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index fd2e2375f..b7f9e0c2f 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -117,6 +117,7 @@
117#ifndef __MINGW32__ 117#ifndef __MINGW32__
118#include <arpa/inet.h> 118#include <arpa/inet.h>
119#endif 119#endif
120#include <alloca.h>
120 121
121/* bbox: not needed 122/* bbox: not needed
122#define INT_CONF ntohl(0x434f4e46) 123#define INT_CONF ntohl(0x434f4e46)
diff --git a/scripts/defconfig.tig b/scripts/defconfig.tig
index 5da784617..2de0d8041 100644
--- a/scripts/defconfig.tig
+++ b/scripts/defconfig.tig
@@ -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.19.0 3# Busybox version: 1.20.0.git
4# Thu Mar 22 15:45:17 2012 4# Fri Mar 23 10:48:09 2012
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set 7# CONFIG_PLATFORM_POSIX is not set
@@ -95,7 +95,7 @@ CONFIG_PREFIX=""
95# CONFIG_FEATURE_SYSTEMD is not set 95# CONFIG_FEATURE_SYSTEMD is not set
96CONFIG_FEATURE_RTMINMAX=y 96CONFIG_FEATURE_RTMINMAX=y
97CONFIG_PASSWORD_MINLEN=6 97CONFIG_PASSWORD_MINLEN=6
98CONFIG_MD5_SIZE_VS_SPEED=2 98CONFIG_MD5_SMALL=1
99# CONFIG_FEATURE_FAST_TOP is not set 99# CONFIG_FEATURE_FAST_TOP is not set
100# CONFIG_FEATURE_ETC_NETWORKS is not set 100# CONFIG_FEATURE_ETC_NETWORKS is not set
101# CONFIG_FEATURE_USE_TERMIOS is not set 101# CONFIG_FEATURE_USE_TERMIOS is not set
@@ -104,6 +104,7 @@ CONFIG_FEATURE_EDITING_MAX_LEN=1024
104# CONFIG_FEATURE_EDITING_VI is not set 104# CONFIG_FEATURE_EDITING_VI is not set
105CONFIG_FEATURE_EDITING_HISTORY=255 105CONFIG_FEATURE_EDITING_HISTORY=255
106# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set 106# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
107# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
107# CONFIG_FEATURE_REVERSE_SEARCH is not set 108# CONFIG_FEATURE_REVERSE_SEARCH is not set
108CONFIG_FEATURE_TAB_COMPLETION=y 109CONFIG_FEATURE_TAB_COMPLETION=y
109# CONFIG_FEATURE_USERNAME_COMPLETION is not set 110# CONFIG_FEATURE_USERNAME_COMPLETION is not set
@@ -143,6 +144,7 @@ CONFIG_FEATURE_CPIO_P=y
143CONFIG_GUNZIP=y 144CONFIG_GUNZIP=y
144CONFIG_GZIP=y 145CONFIG_GZIP=y
145CONFIG_FEATURE_GZIP_LONG_OPTIONS=y 146CONFIG_FEATURE_GZIP_LONG_OPTIONS=y
147CONFIG_GZIP_FAST=2
146CONFIG_LZOP=y 148CONFIG_LZOP=y
147# CONFIG_LZOP_COMPR_HIGH is not set 149# CONFIG_LZOP_COMPR_HIGH is not set
148CONFIG_RPM2CPIO=y 150CONFIG_RPM2CPIO=y
@@ -176,6 +178,7 @@ CONFIG_DATE=y
176CONFIG_FEATURE_DATE_ISOFMT=y 178CONFIG_FEATURE_DATE_ISOFMT=y
177# CONFIG_FEATURE_DATE_NANO is not set 179# CONFIG_FEATURE_DATE_NANO is not set
178CONFIG_FEATURE_DATE_COMPAT=y 180CONFIG_FEATURE_DATE_COMPAT=y
181# CONFIG_HOSTID is not set
179# CONFIG_ID is not set 182# CONFIG_ID is not set
180# CONFIG_GROUPS is not set 183# CONFIG_GROUPS is not set
181CONFIG_TEST=y 184CONFIG_TEST=y
@@ -223,7 +226,6 @@ CONFIG_FOLD=y
223# CONFIG_FSYNC is not set 226# CONFIG_FSYNC is not set
224CONFIG_HEAD=y 227CONFIG_HEAD=y
225CONFIG_FEATURE_FANCY_HEAD=y 228CONFIG_FEATURE_FANCY_HEAD=y
226# CONFIG_HOSTID is not set
227# CONFIG_INSTALL is not set 229# CONFIG_INSTALL is not set
228# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set 230# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
229# CONFIG_LN is not set 231# CONFIG_LN is not set
@@ -460,6 +462,7 @@ CONFIG_LAST_SYSTEM_ID=0
460# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set 462# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
461# CONFIG_GETTY is not set 463# CONFIG_GETTY is not set
462# CONFIG_LOGIN is not set 464# CONFIG_LOGIN is not set
465# CONFIG_LOGIN_SESSION_AS_CHILD is not set
463# CONFIG_PAM is not set 466# CONFIG_PAM is not set
464# CONFIG_LOGIN_SCRIPTS is not set 467# CONFIG_LOGIN_SCRIPTS is not set
465# CONFIG_FEATURE_NOLOGIN is not set 468# CONFIG_FEATURE_NOLOGIN is not set
@@ -517,6 +520,12 @@ CONFIG_DEFAULT_DEPMOD_FILE=""
517# Linux System Utilities 520# Linux System Utilities
518# 521#
519# CONFIG_BLOCKDEV is not set 522# CONFIG_BLOCKDEV is not set
523# CONFIG_MDEV is not set
524# CONFIG_FEATURE_MDEV_CONF is not set
525# CONFIG_FEATURE_MDEV_RENAME is not set
526# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
527# CONFIG_FEATURE_MDEV_EXEC is not set
528# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
520# CONFIG_REV is not set 529# CONFIG_REV is not set
521# CONFIG_ACPID is not set 530# CONFIG_ACPID is not set
522# CONFIG_FEATURE_ACPID_COMPAT is not set 531# CONFIG_FEATURE_ACPID_COMPAT is not set
@@ -560,12 +569,6 @@ CONFIG_HD=y
560# CONFIG_LOSETUP is not set 569# CONFIG_LOSETUP is not set
561# CONFIG_LSPCI is not set 570# CONFIG_LSPCI is not set
562# CONFIG_LSUSB is not set 571# CONFIG_LSUSB is not set
563# CONFIG_MDEV is not set
564# CONFIG_FEATURE_MDEV_CONF is not set
565# CONFIG_FEATURE_MDEV_RENAME is not set
566# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
567# CONFIG_FEATURE_MDEV_EXEC is not set
568# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
569# CONFIG_MKSWAP is not set 572# CONFIG_MKSWAP is not set
570# CONFIG_FEATURE_MKSWAP_UUID is not set 573# CONFIG_FEATURE_MKSWAP_UUID is not set
571# CONFIG_MORE is not set 574# CONFIG_MORE is not set
@@ -889,6 +892,7 @@ CONFIG_FEATURE_PIDOF_OMIT=y
889# CONFIG_PKILL is not set 892# CONFIG_PKILL is not set
890CONFIG_PS=y 893CONFIG_PS=y
891# CONFIG_FEATURE_PS_WIDE is not set 894# CONFIG_FEATURE_PS_WIDE is not set
895# CONFIG_FEATURE_PS_LONG is not set
892# CONFIG_FEATURE_PS_TIME is not set 896# CONFIG_FEATURE_PS_TIME is not set
893# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set 897# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
894# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set 898# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh
index e518a9008..c42fe9fbb 100755
--- a/scripts/gen_build_files.sh
+++ b/scripts/gen_build_files.sh
@@ -19,25 +19,20 @@ chk() { status "CHK" "$@"; }
19 19
20generate() 20generate()
21{ 21{
22 local src="$1" dst="$2" header="$3" insert="$4" 22 # NB: data to be inserted at INSERT line is coming on stdin
23 local src="$1" dst="$2" header="$3"
23 #chk "${dst}" 24 #chk "${dst}"
24 ( 25 {
25 # Need to use printf: different shells have inconsistent 26 # Need to use printf: different shells have inconsistent
26 # rules re handling of "\n" in echo params, 27 # rules re handling of "\n" in echo params.
27 # and ${insert} definitely contains "\n".
28 # Therefore, echo "${header}" would not work:
29 printf "%s\n" "${header}" 28 printf "%s\n" "${header}"
30 if grep -qs '^INSERT$' "${src}"; then 29 # print everything up to INSERT line
31 sed -n '1,/^INSERT$/p' "${src}" 30 sed -n '/^INSERT$/ q; p' "${src}"
32 printf "%s\n" "${insert}" 31 # copy stdin to stdout
33 sed -n '/^INSERT$/,$p' "${src}" 32 cat
34 else 33 # print everything after INSERT line
35 if [ -n "${insert}" ]; then 34 sed -n '/^INSERT$/ { :l; n; p; bl }' "${src}"
36 printf "%s\n" "ERROR: INSERT line missing in: ${src}" 1>&2 35 } >"${dst}.tmp"
37 fi
38 cat "${src}"
39 fi
40 ) | sed '/^INSERT$/d' > "${dst}.tmp"
41 if ! cmp -s "${dst}" "${dst}.tmp"; then 36 if ! cmp -s "${dst}" "${dst}.tmp"; then
42 gen "${dst}" 37 gen "${dst}"
43 mv "${dst}.tmp" "${dst}" 38 mv "${dst}.tmp" "${dst}"
@@ -47,24 +42,21 @@ generate()
47} 42}
48 43
49# (Re)generate include/applets.h 44# (Re)generate include/applets.h
50s=`sed -n 's@^//applet:@@p' "$srctree"/*/*.c "$srctree"/*/*/*.c` 45sed -n 's@^//applet:@@p' "$srctree"/*/*.c "$srctree"/*/*/*.c \
51generate \ 46| generate \
52 "$srctree/include/applets.src.h" \ 47 "$srctree/include/applets.src.h" \
53 "include/applets.h" \ 48 "include/applets.h" \
54 "/* DO NOT EDIT. This file is generated from applets.src.h */" \ 49 "/* DO NOT EDIT. This file is generated from applets.src.h */"
55 "${s}"
56 50
57# (Re)generate include/usage.h 51# (Re)generate include/usage.h
58# We add line continuation backslash after each line, 52# We add line continuation backslash after each line,
59# and insert empty line before each line which doesn't start 53# and insert empty line before each line which doesn't start
60# with space or tab 54# with space or tab
61# (note: we need to use \\\\ because of ``) 55sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\@p' "$srctree"/*/*.c "$srctree"/*/*/*.c \
62s=`sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\\\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\\\@p' "$srctree"/*/*.c "$srctree"/*/*/*.c` 56| generate \
63generate \
64 "$srctree/include/usage.src.h" \ 57 "$srctree/include/usage.src.h" \
65 "include/usage.h" \ 58 "include/usage.h" \
66 "/* DO NOT EDIT. This file is generated from usage.src.h */" \ 59 "/* DO NOT EDIT. This file is generated from usage.src.h */"
67 "${s}"
68 60
69# (Re)generate */Kbuild and */Config.in 61# (Re)generate */Kbuild and */Config.in
70{ cd -- "$srctree" && find . -type d; } | while read -r d; do 62{ cd -- "$srctree" && find . -type d; } | while read -r d; do
@@ -75,11 +67,10 @@ generate \
75 if test -f "$src"; then 67 if test -f "$src"; then
76 mkdir -p -- "$d" 2>/dev/null 68 mkdir -p -- "$d" 2>/dev/null
77 69
78 s=`sed -n 's@^//kbuild:@@p' "$srctree/$d"/*.c` 70 sed -n 's@^//kbuild:@@p' "$srctree/$d"/*.c \
79 generate \ 71 | generate \
80 "${src}" "${dst}" \ 72 "${src}" "${dst}" \
81 "# DO NOT EDIT. This file is generated from Kbuild.src" \ 73 "# DO NOT EDIT. This file is generated from Kbuild.src"
82 "${s}"
83 fi 74 fi
84 75
85 src="$srctree/$d/Config.src" 76 src="$srctree/$d/Config.src"
@@ -87,11 +78,10 @@ generate \
87 if test -f "$src"; then 78 if test -f "$src"; then
88 mkdir -p -- "$d" 2>/dev/null 79 mkdir -p -- "$d" 2>/dev/null
89 80
90 s=`sed -n 's@^//config:@@p' "$srctree/$d"/*.c` 81 sed -n 's@^//config:@@p' "$srctree/$d"/*.c \
91 generate \ 82 | generate \
92 "${src}" "${dst}" \ 83 "${src}" "${dst}" \
93 "# DO NOT EDIT. This file is generated from Config.src" \ 84 "# DO NOT EDIT. This file is generated from Config.src"
94 "${s}"
95 fi 85 fi
96done 86done
97 87
diff --git a/shell/ash.c b/shell/ash.c
index a809bf181..a79099bc5 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -13431,6 +13431,10 @@ exitshell(void)
13431 char *p; 13431 char *p;
13432 int status; 13432 int status;
13433 13433
13434#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13435 save_history(line_input_state);
13436#endif
13437
13434 status = exitstatus; 13438 status = exitstatus;
13435 TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); 13439 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13436 if (setjmp(loc.loc)) { 13440 if (setjmp(loc.loc)) {
@@ -13816,7 +13820,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13816 } 13820 }
13817 13821
13818 if (sflag || minusc == NULL) { 13822 if (sflag || minusc == NULL) {
13819#if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY 13823#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
13820 if (iflag) { 13824 if (iflag) {
13821 const char *hp = lookupvar("HISTFILE"); 13825 const char *hp = lookupvar("HISTFILE");
13822 if (hp) 13826 if (hp)
diff --git a/shell/cttyhack.c b/shell/cttyhack.c
index 4261289b4..6ff867413 100644
--- a/shell/cttyhack.c
+++ b/shell/cttyhack.c
@@ -50,9 +50,12 @@
50//config: 50//config:
51//config: # exec setsid sh -c 'exec sh </dev/tty1 >/dev/tty1 2>&1' 51//config: # exec setsid sh -c 'exec sh </dev/tty1 >/dev/tty1 2>&1'
52//config: 52//config:
53//config: Starting getty on a controlling tty from a shell script:
54//config:
55//config: # getty 115200 $(cttyhack)
53 56
54//usage:#define cttyhack_trivial_usage 57//usage:#define cttyhack_trivial_usage
55//usage: "PROG ARGS" 58//usage: "[PROG ARGS]"
56//usage:#define cttyhack_full_usage "\n\n" 59//usage:#define cttyhack_full_usage "\n\n"
57//usage: "Give PROG a controlling tty if possible." 60//usage: "Give PROG a controlling tty if possible."
58//usage: "\nExample for /etc/inittab (for busybox init):" 61//usage: "\nExample for /etc/inittab (for busybox init):"
@@ -108,59 +111,71 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv)
108 char paranoia[sizeof(struct serial_struct) * 3]; 111 char paranoia[sizeof(struct serial_struct) * 3];
109 } u; 112 } u;
110 113
111 if (!*++argv) {
112 bb_show_usage();
113 }
114
115 strcpy(console, "/dev/tty"); 114 strcpy(console, "/dev/tty");
116 fd = open(console, O_RDWR); 115 fd = open(console, O_RDWR);
117 if (fd >= 0) { 116 if (fd < 0) {
118 /* We already have ctty, nothing to do */
119 close(fd);
120 } else {
121 /* We don't have ctty (or don't have "/dev/tty" node...) */ 117 /* We don't have ctty (or don't have "/dev/tty" node...) */
122 do { 118 do {
123#ifdef __linux__ 119#ifdef __linux__
120 /* Note that this method does not use _stdin_.
121 * Thus, "cttyhack </dev/something" can't be used.
122 * However, this method is more reliable than
123 * TIOCGSERIAL check, which assumes that all
124 * serial lines follow /dev/ttySn convention -
125 * which is not always the case.
126 * Therefore, we use this methos first:
127 */
124 int s = open_read_close("/sys/class/tty/console/active", 128 int s = open_read_close("/sys/class/tty/console/active",
125 console + 5, sizeof(console) - 5 - 1); 129 console + 5, sizeof(console) - 5);
126 if (s > 0) { 130 if (s > 0) {
127 /* found active console via sysfs (Linux 2.6.38+) */ 131 /* found active console via sysfs (Linux 2.6.38+)
128 console[5 + s] = '\0'; 132 * sysfs string looks like "ttyS0\n" so zap the newline:
133 */
134 console[4 + s] = '\0';
129 break; 135 break;
130 } 136 }
131 137
132 if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { 138 if (ioctl(0, VT_GETSTATE, &u.vt) == 0) {
133 /* this is linux virtual tty */ 139 /* this is linux virtual tty */
134 sprintf(console + 8, "S%d" + 1, u.vt.v_active); 140 sprintf(console + 8, "S%u" + 1, (int)u.vt.v_active);
135 break; 141 break;
136 } 142 }
137#endif 143#endif
138#ifdef TIOCGSERIAL 144#ifdef TIOCGSERIAL
139 if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { 145 if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) {
140 /* this is a serial console, asuming it is named /dev/ttySn */ 146 /* this is a serial console; assuming it is named /dev/ttySn */
141 sprintf(console + 8, "S%d", u.sr.line); 147 sprintf(console + 8, "S%u", (int)u.sr.line);
142 break; 148 break;
143 } 149 }
144#endif 150#endif
145 /* nope, could not find it */ 151 /* nope, could not find it */
146 goto ret; 152 console[0] = '\0';
147 } while (0); 153 } while (0);
154 }
155
156 argv++;
157 if (!argv[0]) {
158 if (!console[0])
159 return EXIT_FAILURE;
160 puts(console);
161 return EXIT_SUCCESS;
162 }
148 163
164 if (fd < 0) {
149 fd = open_or_warn(console, O_RDWR); 165 fd = open_or_warn(console, O_RDWR);
150 if (fd < 0) 166 if (fd < 0)
151 goto ret; 167 goto ret;
152 //bb_error_msg("switching to '%s'", console);
153 dup2(fd, 0);
154 dup2(fd, 1);
155 dup2(fd, 2);
156 while (fd > 2)
157 close(fd--);
158 /* Some other session may have it as ctty,
159 * steal it from them:
160 */
161 ioctl(0, TIOCSCTTY, 1);
162 } 168 }
163 169 //bb_error_msg("switching to '%s'", console);
164ret: 170 dup2(fd, 0);
171 dup2(fd, 1);
172 dup2(fd, 2);
173 while (fd > 2)
174 close(fd--);
175 /* Some other session may have it as ctty,
176 * try to steal it from them:
177 */
178 ioctl(0, TIOCSCTTY, 1);
179 ret:
165 BB_EXECVP_or_die(argv); 180 BB_EXECVP_or_die(argv);
166} 181}
diff --git a/shell/hush.c b/shell/hush.c
index e4138adf7..7a34f59ae 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1541,6 +1541,10 @@ static sighandler_t pick_sighandler(unsigned sig)
1541static void hush_exit(int exitcode) NORETURN; 1541static void hush_exit(int exitcode) NORETURN;
1542static void hush_exit(int exitcode) 1542static void hush_exit(int exitcode)
1543{ 1543{
1544#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
1545 save_history(G.line_input_state);
1546#endif
1547
1544 fflush_all(); 1548 fflush_all();
1545 if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { 1549 if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) {
1546 char *argv[3]; 1550 char *argv[3];
@@ -7817,22 +7821,6 @@ int hush_main(int argc, char **argv)
7817 7821
7818#if ENABLE_FEATURE_EDITING 7822#if ENABLE_FEATURE_EDITING
7819 G.line_input_state = new_line_input_t(FOR_SHELL); 7823 G.line_input_state = new_line_input_t(FOR_SHELL);
7820# if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_HUSH_SAVEHISTORY
7821 {
7822 const char *hp = get_local_var_value("HISTFILE");
7823 if (!hp) {
7824 hp = get_local_var_value("HOME");
7825 if (hp) {
7826 G.line_input_state->hist_file = concat_path_file(hp, ".hush_history");
7827 //set_local_var(xasprintf("HISTFILE=%s", ...));
7828 }
7829 }
7830# if ENABLE_FEATURE_SH_HISTFILESIZE
7831 hp = get_local_var_value("HISTFILESIZE");
7832 G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
7833# endif
7834 }
7835# endif
7836#endif 7824#endif
7837 7825
7838 /* Initialize some more globals to non-zero values */ 7826 /* Initialize some more globals to non-zero values */
@@ -8104,6 +8092,27 @@ int hush_main(int argc, char **argv)
8104 /* -1 is special - makes xfuncs longjmp, not exit 8092 /* -1 is special - makes xfuncs longjmp, not exit
8105 * (we reset die_sleep = 0 whereever we [v]fork) */ 8093 * (we reset die_sleep = 0 whereever we [v]fork) */
8106 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */ 8094 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
8095
8096# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0
8097 {
8098 const char *hp = get_local_var_value("HISTFILE");
8099 if (!hp) {
8100 hp = get_local_var_value("HOME");
8101 if (hp)
8102 hp = concat_path_file(hp, ".hush_history");
8103 } else {
8104 hp = xstrdup(hp);
8105 }
8106 if (hp) {
8107 G.line_input_state->hist_file = hp;
8108 //set_local_var(xasprintf("HISTFILE=%s", ...));
8109 }
8110# if ENABLE_FEATURE_SH_HISTFILESIZE
8111 hp = get_local_var_value("HISTFILESIZE");
8112 G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
8113# endif
8114 }
8115# endif
8107 } else { 8116 } else {
8108 install_special_sighandlers(); 8117 install_special_sighandlers();
8109 } 8118 }
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index 2f0ca6ac5..fc380d9f9 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -278,7 +278,7 @@ static void parse_syslogdcfg(const char *file)
278 parser_t *parser; 278 parser_t *parser;
279 279
280 parser = config_open2(file ? file : "/etc/syslog.conf", 280 parser = config_open2(file ? file : "/etc/syslog.conf",
281 file ? xfopen_for_read : fopen_or_warn_stdin); 281 file ? xfopen_for_read : fopen_for_read);
282 if (!parser) 282 if (!parser)
283 /* didn't find default /etc/syslog.conf */ 283 /* didn't find default /etc/syslog.conf */
284 /* proceed as if we built busybox without config support */ 284 /* proceed as if we built busybox without config support */
@@ -594,6 +594,14 @@ static void log_locally(time_t now, char *msg, logFile_t *log_file)
594 } 594 }
595 /* newFile == "f.0" now */ 595 /* newFile == "f.0" now */
596 rename(log_file->path, newFile); 596 rename(log_file->path, newFile);
597 /* Incredibly, if F and F.0 are hardlinks, POSIX
598 * _demands_ that rename returns 0 but does not
599 * remove F!!!
600 * (hardlinked F/F.0 pair was observed after
601 * power failure during rename()).
602 * Ensure old file is gone:
603 */
604 unlink(log_file->path);
597#ifdef SYSLOGD_WRLOCK 605#ifdef SYSLOGD_WRLOCK
598 fl.l_type = F_UNLCK; 606 fl.l_type = F_UNLCK;
599 fcntl(log_file->fd, F_SETLKW, &fl); 607 fcntl(log_file->fd, F_SETLKW, &fl);
@@ -678,7 +686,7 @@ static void timestamp_and_log(int pri, char *msg, int len)
678 if (LOG_PRI(pri) < G.logLevel) { 686 if (LOG_PRI(pri) < G.logLevel) {
679#if ENABLE_FEATURE_IPC_SYSLOG 687#if ENABLE_FEATURE_IPC_SYSLOG
680 if ((option_mask32 & OPT_circularlog) && G.shbuf) { 688 if ((option_mask32 & OPT_circularlog) && G.shbuf) {
681 log_to_shmem(msg); 689 log_to_shmem(G.printbuf);
682 return; 690 return;
683 } 691 }
684#endif 692#endif
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index 0afe9b9e7..5a323047d 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -202,4 +202,7 @@ end d
202" \ 202" \
203 "" "" 203 "" ""
204 204
205testing "awk handles empty ()" \
206 "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" ""
207
205exit $FAILCOUNT 208exit $FAILCOUNT
diff --git a/testsuite/bzcat.tests b/testsuite/bzcat.tests
index 5b4f3f4b3..1c1fd6563 100755
--- a/testsuite/bzcat.tests
+++ b/testsuite/bzcat.tests
@@ -51,4 +51,34 @@ prep; check "bzcat: dont delete src" "${bb}bzcat t2.bz2; test -f t2.bz2 && echo
51) 51)
52rm -rf testdir 52rm -rf testdir
53 53
54
55
56# Copyright 2011 by Denys Vlasenko
57# Licensed under GPLv2, see file LICENSE in this source tree.
58
59. ./testing.sh
60
61# testing "test name" "command" "expected result" "file input" "stdin"
62
63# "input" file is bzipped file with "a\n" data
64testing "bzcat can print many files" \
65"$ECHO -ne '$hexdump' | bzcat input input; echo \$?" \
66"\
67a
68a
690
70" "\
71\x42\x5a\x68\x39\x31\x41\x59\x26\x53\x59\x63\x3e\xd6\xe2\x00\x00\
72\x00\xc1\x00\x00\x10\x20\x00\x20\x00\x21\x00\x82\xb1\x77\x24\x53\
73\x85\x09\x06\x33\xed\x6e\x20\
74" ""
75
76# "input" file is bzipped zero byte file
77testing "bzcat can handle compressed zero-length bzip2 files" \
78"$ECHO -ne '$hexdump' | bzcat input input; echo \$?" \
79"0\n" \
80"\x42\x5a\x68\x39\x17\x72\x45\x38\x50\x90\x00\x00\x00\x00" ""
81
82
83
54exit $((FAILCOUNT <= 255 ? FAILCOUNT : 255)) 84exit $((FAILCOUNT <= 255 ? FAILCOUNT : 255))
diff --git a/testsuite/grep.tests b/testsuite/grep.tests
index ffce033e6..006a215e1 100755
--- a/testsuite/grep.tests
+++ b/testsuite/grep.tests
@@ -7,7 +7,7 @@
7 7
8. ./testing.sh 8. ./testing.sh
9 9
10# testing "test name" "options" "expected result" "file input" "stdin" 10# testing "test name" "commands" "expected result" "file input" "stdin"
11# file input will be file called "input" 11# file input will be file called "input"
12# test can create a file "actual" instead of writing to stdout 12# test can create a file "actual" instead of writing to stdout
13 13
@@ -103,4 +103,20 @@ testing "grep -o does not loop forever on zero-length match" \
103 "" \ 103 "" \
104 "" "test\n" 104 "" "test\n"
105 105
106testing "grep -f EMPTY_FILE" \
107 "grep -f input" \
108 "" \
109 "" \
110 "test\n"
111
112testing "grep -v -f EMPTY_FILE" \
113 "grep -v -f input" \
114 "test\n" \
115 "" \
116 "test\n"
117
118# testing "test name" "commands" "expected result" "file input" "stdin"
119# file input will be file called "input"
120# test can create a file "actual" instead of writing to stdout
121
106exit $FAILCOUNT 122exit $FAILCOUNT
diff --git a/testsuite/patch.tests b/testsuite/patch.tests
index c604b9c1d..2759d2ad4 100755
--- a/testsuite/patch.tests
+++ b/testsuite/patch.tests
@@ -212,6 +212,36 @@ patching file input
212 666 212 666
213" \ 213" \
214 214
215# testing "test name" "command(s)" "expected result" "file input" "stdin"
216testing "patch creates new file" \
217 'patch 2>&1; echo $?; cat testfile; rm testfile' \
218"\
219creating testfile
2200
221qwerty
222" "" "\
223--- /dev/null
224+++ testfile
225@@ -0,0 +1 @@
226+qwerty
227"
228
229# testing "test name" "command(s)" "expected result" "file input" "stdin"
230testing "patch understands ...dir///dir..." \
231 'patch -p1 2>&1; echo $?' \
232"\
233patching file dir2///file
234patch: can't open 'dir2///file': No such file or directory
2351
236" "" "\
237--- bogus_dir///dir2///file
238+++ bogus_dir///dir2///file
239@@ -1,2 +1,3 @@
240 qwe
241+asd
242 zxc
243"
244
215rm input.orig 2>/dev/null 245rm input.orig 2>/dev/null
216 246
217exit $FAILCOUNT 247exit $FAILCOUNT
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index e9d0ed601..ba163e9e9 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -6,7 +6,7 @@
6 6
7. ./testing.sh 7. ./testing.sh
8 8
9# testing "description" "arguments" "result" "infile" "stdin" 9# testing "description" "commands" "result" "infile" "stdin"
10 10
11# Corner cases 11# Corner cases
12testing "sed no files (stdin)" 'sed ""' "hello\n" "" "hello\n" 12testing "sed no files (stdin)" 'sed ""' "hello\n" "" "hello\n"
@@ -225,7 +225,7 @@ testing "sed s/xxx/[/" "sed -e 's/xxx/[/'" "[\n" "" "xxx\n"
225#testing "sed -g (exhaustive)" "sed -e 's/[[:space:]]*/,/g'" ",1,2,3,4,5," \ 225#testing "sed -g (exhaustive)" "sed -e 's/[[:space:]]*/,/g'" ",1,2,3,4,5," \
226# "" "12345" 226# "" "12345"
227 227
228# testing "description" "arguments" "result" "infile" "stdin" 228# testing "description" "commands" "result" "infile" "stdin"
229 229
230testing "sed n command must reset 'substituted' bit" \ 230testing "sed n command must reset 'substituted' bit" \
231 "sed 's/1/x/;T;n;: next;s/3/y/;t quit;n;b next;: quit;q'" \ 231 "sed 's/1/x/;T;n;: next;s/3/y/;t quit;n;b next;: quit;q'" \
@@ -291,6 +291,10 @@ testing "sed understands \r" \
291 "sed 's/r/\r/'" \ 291 "sed 's/r/\r/'" \
292 "\rrr\n" "" "rrr\n" 292 "\rrr\n" "" "rrr\n"
293 293
294# testing "description" "arguments" "result" "infile" "stdin" 294testing "sed -i finishes ranges correctly" \
295 "sed '1,2d' -i input; echo \$?; cat input" \
296 "0\n3\n4\n" "1\n2\n3\n4\n" ""
297
298# testing "description" "commands" "result" "infile" "stdin"
295 299
296exit $FAILCOUNT 300exit $FAILCOUNT
diff --git a/testsuite/tail.tests b/testsuite/tail.tests
index 7140da262..305a83b15 100755
--- a/testsuite/tail.tests
+++ b/testsuite/tail.tests
@@ -14,4 +14,12 @@ testing "tail: +N with N > file length" \
14 "0\n" \ 14 "0\n" \
15 "" "qw" 15 "" "qw"
16 16
17testing "tail: -c +N with largish N" \
18 "
19 dd if=/dev/zero bs=16k count=1 2>/dev/null | tail -c +8200 | wc -c;
20 dd if=/dev/zero bs=16k count=1 2>/dev/null | tail -c +8208 | wc -c;
21 " \
22 "8185\n8177\n" \
23 "" ""
24
17exit $FAILCOUNT 25exit $FAILCOUNT
diff --git a/testsuite/uncompress.tests b/testsuite/uncompress.tests
new file mode 100755
index 000000000..51a233493
--- /dev/null
+++ b/testsuite/uncompress.tests
@@ -0,0 +1,20 @@
1#!/bin/sh
2# Copyright 2011 by Denys Vlasenko
3# Licensed under GPLv2, see file LICENSE in this source tree.
4
5. ./testing.sh
6
7# testing "test name" "commands" "expected result" "file input" "stdin"
8
9testing "uncompress < \x1f\x9d\x90 \x01 x N" \
10'uncompress 2>&1 1>/dev/null; echo $?' \
11"\
12uncompress: corrupted data
131
14" \
15"" "\
16\x1f\x9d\x90\
17\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\
18"
19
20exit $FAILCOUNT
diff --git a/testsuite/uuencode.tests b/testsuite/uuencode.tests
index cd6191b1b..6ce70f747 100755
--- a/testsuite/uuencode.tests
+++ b/testsuite/uuencode.tests
@@ -8,9 +8,9 @@
8 8
9. ./testing.sh 9. ./testing.sh
10 10
11# testing "test name" "options" "expected result" "file input" "stdin" 11# testing "test name" "command(s)" "expected result" "file input" "stdin"
12# file input will be file called "input" 12# file input will be file called "input"
13# test can create a file "actual" instead of writing to stdout 13# test can create a file "actual" instead of writing to stdout
14 14
15# Test setup of standard input 15# Test setup of standard input
16umask 0 16umask 0
@@ -24,4 +24,99 @@ testing "uuencode correct encoding" "uuencode bb_uuenc_test.out" \
24testing "uuencode correct base64 encoding" "uuencode -m bb_uuenc_test.out" \ 24testing "uuencode correct base64 encoding" "uuencode -m bb_uuenc_test.out" \
25"begin-base64 644 bb_uuenc_test.out\nVGhlIGZhc3QgZ3JleSBmb3gganVtcGVkIG92ZXIgdGhlIGxhenkgYnJvd24g\nZG9nLgo=\n====\n" \ 25"begin-base64 644 bb_uuenc_test.out\nVGhlIGZhc3QgZ3JleSBmb3gganVtcGVkIG92ZXIgdGhlIGxhenkgYnJvd24g\nZG9nLgo=\n====\n" \
26 "" "The fast grey fox jumped over the lazy brown dog.\n" 26 "" "The fast grey fox jumped over the lazy brown dog.\n"
27
28testing "uuencode empty file" 'r=`uuencode FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
29'begin 644 FILE
30`
31end
32' "" ""
33testing "uuencode -m empty file" 'r=`uuencode -m FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
34'begin-base64 644 FILE
35====
36' "" ""
37
38testing "uuencode file 'A'" 'r=`uuencode FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
39'begin 644 FILE
40!00``
41`
42end
43A' "" "A"
44testing "uuencode -m file 'A'" 'r=`uuencode -m FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
45'begin-base64 644 FILE
46QQ==
47====
48A' "" "A"
49
50testing "uuencode file 'AB'" 'r=`uuencode FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
51'begin 644 FILE
52"04(`
53`
54end
55AB' "" "AB"
56testing "uuencode -m file 'AB'" 'r=`uuencode -m FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
57'begin-base64 644 FILE
58QUI=
59====
60AB' "" "AB"
61
62testing "uuencode file 'ABC'" 'r=`uuencode FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
63'begin 644 FILE
64#04)#
65`
66end
67ABC' "" "ABC"
68testing "uuencode -m file 'ABC'" 'r=`uuencode -m FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
69'begin-base64 644 FILE
70QUJD
71====
72ABC' "" "ABC"
73
74testing "uuencode file 'ABCD'" 'r=`uuencode FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
75'begin 644 FILE
76$04)#1```
77`
78end
79ABCD' "" "ABCD"
80testing "uuencode -m file 'ABCD'" 'r=`uuencode -m FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
81'begin-base64 644 FILE
82QUJDRA==
83====
84ABCD' "" "ABCD"
85
86testing "uuencode file 'ABCDE'" 'r=`uuencode FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
87'begin 644 FILE
88%04)#1$4`
89`
90end
91ABCDE' "" "ABCDE"
92testing "uuencode -m file 'ABCDE'" 'r=`uuencode -m FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
93'begin-base64 644 FILE
94QUJDREU=
95====
96ABCDE' "" "ABCDE"
97
98testing "uuencode file 'ABCDEF'" 'r=`uuencode FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
99'begin 644 FILE
100&04)#1$5&
101`
102end
103ABCDEF' "" "ABCDEF"
104testing "uuencode -m file 'ABCDEF'" 'r=`uuencode -m FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
105'begin-base64 644 FILE
106QUJDREVG
107====
108ABCDEF' "" "ABCDEF"
109
110testing "uuencode file 'A<NUL><0xff>Z'" 'r=`uuencode FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
111'begin 644 FILE
112$00#_6@``
113`
114end
115A\x0\xffZ' "" "A\x0\xffZ"
116testing "uuencode -m file 'A<NUL><0xff>Z'" 'r=`uuencode -m FILE`; echo "$r"; echo "$r" | uudecode -o -;' \
117'begin-base64 644 FILE
118QQD/Wg==
119====
120A\x0\xffZ' "" "A\x0\xffZ"
121
27exit $FAILCOUNT 122exit $FAILCOUNT
diff --git a/util-linux/Config.src b/util-linux/Config.src
index bb45705a9..888bc8f3b 100644
--- a/util-linux/Config.src
+++ b/util-linux/Config.src
@@ -404,64 +404,6 @@ config LSUSB
404 404
405 This version uses sysfs (/sys/bus/usb/devices) only. 405 This version uses sysfs (/sys/bus/usb/devices) only.
406 406
407config MDEV
408 bool "mdev"
409 default y
410 select PLATFORM_LINUX
411 help
412 mdev is a mini-udev implementation for dynamically creating device
413 nodes in the /dev directory.
414
415 For more information, please see docs/mdev.txt
416
417config FEATURE_MDEV_CONF
418 bool "Support /etc/mdev.conf"
419 default y
420 depends on MDEV
421 help
422 Add support for the mdev config file to control ownership and
423 permissions of the device nodes.
424
425 For more information, please see docs/mdev.txt
426
427config FEATURE_MDEV_RENAME
428 bool "Support subdirs/symlinks"
429 default y
430 depends on FEATURE_MDEV_CONF
431 help
432 Add support for renaming devices and creating symlinks.
433
434 For more information, please see docs/mdev.txt
435
436config FEATURE_MDEV_RENAME_REGEXP
437 bool "Support regular expressions substitutions when renaming device"
438 default y
439 depends on FEATURE_MDEV_RENAME
440 help
441 Add support for regular expressions substitutions when renaming
442 device.
443
444config FEATURE_MDEV_EXEC
445 bool "Support command execution at device addition/removal"
446 default y
447 depends on FEATURE_MDEV_CONF
448 help
449 This adds support for an optional field to /etc/mdev.conf for
450 executing commands when devices are created/removed.
451
452 For more information, please see docs/mdev.txt
453
454config FEATURE_MDEV_LOAD_FIRMWARE
455 bool "Support loading of firmwares"
456 default y
457 depends on MDEV
458 help
459 Some devices need to load firmware before they can be usable.
460
461 These devices will request userspace look up the files in
462 /lib/firmware/ and if it exists, send it to the kernel for
463 loading into the hardware.
464
465config MKSWAP 407config MKSWAP
466 bool "mkswap" 408 bool "mkswap"
467 default y 409 default y
diff --git a/util-linux/Kbuild.src b/util-linux/Kbuild.src
index c06d911ec..468fc6bc1 100644
--- a/util-linux/Kbuild.src
+++ b/util-linux/Kbuild.src
@@ -26,7 +26,6 @@ lib-$(CONFIG_IPCS) += ipcs.o
26lib-$(CONFIG_LOSETUP) += losetup.o 26lib-$(CONFIG_LOSETUP) += losetup.o
27lib-$(CONFIG_LSPCI) += lspci.o 27lib-$(CONFIG_LSPCI) += lspci.o
28lib-$(CONFIG_LSUSB) += lsusb.o 28lib-$(CONFIG_LSUSB) += lsusb.o
29lib-$(CONFIG_MDEV) += mdev.o
30lib-$(CONFIG_MKFS_EXT2) += mkfs_ext2.o 29lib-$(CONFIG_MKFS_EXT2) += mkfs_ext2.o
31lib-$(CONFIG_MKFS_MINIX) += mkfs_minix.o 30lib-$(CONFIG_MKFS_MINIX) += mkfs_minix.o
32lib-$(CONFIG_MKFS_REISER) += mkfs_reiser.o 31lib-$(CONFIG_MKFS_REISER) += mkfs_reiser.o
diff --git a/util-linux/losetup.c b/util-linux/losetup.c
index 9b7c49f50..21108d0bf 100644
--- a/util-linux/losetup.c
+++ b/util-linux/losetup.c
@@ -8,11 +8,12 @@
8 */ 8 */
9 9
10//usage:#define losetup_trivial_usage 10//usage:#define losetup_trivial_usage
11//usage: "[-o OFS] LOOPDEV FILE - associate loop devices\n" 11//usage: "[-r] [-o OFS] LOOPDEV FILE - associate loop devices\n"
12//usage: " losetup -d LOOPDEV - disassociate\n" 12//usage: " losetup -d LOOPDEV - disassociate\n"
13//usage: " losetup [-f] - show" 13//usage: " losetup [-f] - show"
14//usage:#define losetup_full_usage "\n\n" 14//usage:#define losetup_full_usage "\n\n"
15//usage: " -o OFS Start OFS bytes into FILE" 15//usage: " -o OFS Start OFS bytes into FILE"
16//usage: "\n -r Read-only"
16//usage: "\n -f Show first free loop device" 17//usage: "\n -f Show first free loop device"
17//usage: 18//usage:
18//usage:#define losetup_notes_usage 19//usage:#define losetup_notes_usage
@@ -37,11 +38,12 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
37 OPT_d = (1 << 0), 38 OPT_d = (1 << 0),
38 OPT_o = (1 << 1), 39 OPT_o = (1 << 1),
39 OPT_f = (1 << 2), 40 OPT_f = (1 << 2),
41 OPT_r = (1 << 3), /* must be last */
40 }; 42 };
41 43
42 /* max 2 args, all opts are mutually exclusive */ 44 /* max 2 args, -d,-o,-f opts are mutually exclusive */
43 opt_complementary = "?2:d--of:o--df:f--do"; 45 opt_complementary = "?2:d--of:o--df:f--do";
44 opt = getopt32(argv, "do:f", &opt_o); 46 opt = getopt32(argv, "do:fr", &opt_o);
45 argv += optind; 47 argv += optind;
46 48
47 if (opt == OPT_o) 49 if (opt == OPT_o)
@@ -63,12 +65,12 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
63 bb_show_usage(); 65 bb_show_usage();
64 66
65 if (argv[1]) { 67 if (argv[1]) {
66 /* [-o OFS] BLOCKDEV FILE */ 68 /* [-r] [-o OFS] BLOCKDEV FILE */
67 if (set_loop(&argv[0], argv[1], offset) < 0) 69 if (set_loop(&argv[0], argv[1], offset, (opt / OPT_r)) < 0)
68 bb_simple_perror_msg_and_die(argv[0]); 70 bb_simple_perror_msg_and_die(argv[0]);
69 return EXIT_SUCCESS; 71 return EXIT_SUCCESS;
70 } 72 }
71 /* [-o OFS] BLOCKDEV */ 73 /* [-r] [-o OFS] BLOCKDEV */
72 s = query_loop(argv[0]); 74 s = query_loop(argv[0]);
73 if (!s) 75 if (!s)
74 bb_simple_perror_msg_and_die(argv[0]); 76 bb_simple_perror_msg_and_die(argv[0]);
@@ -78,7 +80,7 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
78 return EXIT_SUCCESS; 80 return EXIT_SUCCESS;
79 } 81 }
80 82
81 /* [-o OFS|-f] with no params */ 83 /* [-r] [-o OFS|-f] with no params */
82 n = 0; 84 n = 0;
83 while (1) { 85 while (1) {
84 char *s; 86 char *s;
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index 7cabb1df6..c6be1b872 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -8,39 +8,91 @@
8 * Licensed under GPLv2, see file LICENSE in this source tree. 8 * Licensed under GPLv2, see file LICENSE in this source tree.
9 */ 9 */
10 10
11//config:config MDEV
12//config: bool "mdev"
13//config: default y
14//config: select PLATFORM_LINUX
15//config: help
16//config: mdev is a mini-udev implementation for dynamically creating device
17//config: nodes in the /dev directory.
18//config:
19//config: For more information, please see docs/mdev.txt
20//config:
21//config:config FEATURE_MDEV_CONF
22//config: bool "Support /etc/mdev.conf"
23//config: default y
24//config: depends on MDEV
25//config: help
26//config: Add support for the mdev config file to control ownership and
27//config: permissions of the device nodes.
28//config:
29//config: For more information, please see docs/mdev.txt
30//config:
31//config:config FEATURE_MDEV_RENAME
32//config: bool "Support subdirs/symlinks"
33//config: default y
34//config: depends on FEATURE_MDEV_CONF
35//config: help
36//config: Add support for renaming devices and creating symlinks.
37//config:
38//config: For more information, please see docs/mdev.txt
39//config:
40//config:config FEATURE_MDEV_RENAME_REGEXP
41//config: bool "Support regular expressions substitutions when renaming device"
42//config: default y
43//config: depends on FEATURE_MDEV_RENAME
44//config: help
45//config: Add support for regular expressions substitutions when renaming
46//config: device.
47//config:
48//config:config FEATURE_MDEV_EXEC
49//config: bool "Support command execution at device addition/removal"
50//config: default y
51//config: depends on FEATURE_MDEV_CONF
52//config: help
53//config: This adds support for an optional field to /etc/mdev.conf for
54//config: executing commands when devices are created/removed.
55//config:
56//config: For more information, please see docs/mdev.txt
57//config:
58//config:config FEATURE_MDEV_LOAD_FIRMWARE
59//config: bool "Support loading of firmwares"
60//config: default y
61//config: depends on MDEV
62//config: help
63//config: Some devices need to load firmware before they can be usable.
64//config:
65//config: These devices will request userspace look up the files in
66//config: /lib/firmware/ and if it exists, send it to the kernel for
67//config: loading into the hardware.
68
69//applet:IF_MDEV(APPLET(mdev, BB_DIR_SBIN, BB_SUID_DROP))
70
71//kbuild:lib-$(CONFIG_MDEV) += mdev.o
72
11//usage:#define mdev_trivial_usage 73//usage:#define mdev_trivial_usage
12//usage: "[-s]" 74//usage: "[-s]"
13//usage:#define mdev_full_usage "\n\n" 75//usage:#define mdev_full_usage "\n\n"
14//usage: " -s Scan /sys and populate /dev during system boot\n" 76//usage: "mdev -s is to be run during boot to scan /sys and populate /dev.\n"
15//usage: "\n" 77//usage: "\n"
16//usage: "It can be run by kernel as a hotplug helper. To activate it:\n" 78//usage: "Bare mdev is a kernel hotplug helper. To activate it:\n"
17//usage: " echo /sbin/mdev > /proc/sys/kernel/hotplug\n" 79//usage: " echo /sbin/mdev >/proc/sys/kernel/hotplug\n"
18//usage: IF_FEATURE_MDEV_CONF( 80//usage: IF_FEATURE_MDEV_CONF(
81//usage: "\n"
19//usage: "It uses /etc/mdev.conf with lines\n" 82//usage: "It uses /etc/mdev.conf with lines\n"
20//usage: "[-]DEVNAME UID:GID PERM" 83//usage: " [-]DEVNAME UID:GID PERM"
21//usage: IF_FEATURE_MDEV_RENAME(" [>|=PATH]") 84//usage: IF_FEATURE_MDEV_RENAME(" [>|=PATH]|[!]")
22//usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") 85//usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]")
86//usage: "\n"
87//usage: "where DEVNAME is device name regex, @major,minor[-minor2], or\n"
88//usage: "environment variable regex. A common use of the latter is\n"
89//usage: "to load modules for hotplugged devices:\n"
90//usage: " $MODALIAS=.* 0:0 660 @modprobe \"$MODALIAS\"\n"
23//usage: ) 91//usage: )
24//usage: 92//usage: "\n"
25//usage:#define mdev_notes_usage "" 93//usage: "If /dev/mdev.seq file exists, mdev will wait for its value\n"
26//usage: IF_FEATURE_MDEV_CONFIG( 94//usage: "to match $SEQNUM variable. This prevents plug/unplug races.\n"
27//usage: "The mdev config file contains lines that look like:\n" 95//usage: "To activate this feature, create empty /dev/mdev.seq at boot."
28//usage: " hd[a-z][0-9]* 0:3 660\n\n"
29//usage: "That's device name (with regex match), uid:gid, and permissions.\n\n"
30//usage: IF_FEATURE_MDEV_EXEC(
31//usage: "Optionally, that can be followed (on the same line) by a special character\n"
32//usage: "and a command line to run after creating/before deleting the corresponding\n"
33//usage: "device(s). The environment variable $MDEV indicates the active device node\n"
34//usage: "(which is useful if it's a regex match). For example:\n\n"
35//usage: " hdc root:cdrom 660 *ln -s $MDEV cdrom\n\n"
36//usage: "The special characters are @ (run after creating), $ (run before deleting),\n"
37//usage: "and * (run both after creating and before deleting). The commands run in\n"
38//usage: "the /dev directory, and use system() which calls /bin/sh.\n\n"
39//usage: )
40//usage: "Config file parsing stops on the first matching line. If no config\n"
41//usage: "entry is matched, devices are created with default 0:0 660. (Make\n"
42//usage: "the last line match .* to override this.)\n\n"
43//usage: )
44 96
45#include "libbb.h" 97#include "libbb.h"
46#include "xregex.h" 98#include "xregex.h"
@@ -62,20 +114,11 @@
62 * (todo: explain "delete" and $FIRMWARE) 114 * (todo: explain "delete" and $FIRMWARE)
63 * 115 *
64 * If /etc/mdev.conf exists, it may modify /dev/device_name's properties. 116 * If /etc/mdev.conf exists, it may modify /dev/device_name's properties.
65 * /etc/mdev.conf file format:
66 *
67 * [-][subsystem/]device user:grp mode [>|=path] [@|$|*command args...]
68 * [-]@maj,min[-min2] user:grp mode [>|=path] [@|$|*command args...]
69 * [-]$envvar=val user:grp mode [>|=path] [@|$|*command args...]
70 * 117 *
71 * Leading minus in 1st field means "don't stop on this line", otherwise 118 * Leading minus in 1st field means "don't stop on this line", otherwise
72 * search is stopped after the matching line is encountered. 119 * search is stopped after the matching line is encountered.
73 * 120 *
74 * The device name or "subsystem/device" combo is matched against 1st field 121 * $envvar=regex format is useful for loading modules for hot-plugged devices
75 * (which is a regex), or maj,min is matched against 1st field,
76 * or specified environment variable (as regex) is matched against 1st field.
77 *
78 * $envvar=val format is useful for loading modules for hot-plugged devices
79 * which do not have driver loaded yet. In this case /sys/class/.../dev 122 * which do not have driver loaded yet. In this case /sys/class/.../dev
80 * does not exist, but $MODALIAS is set to needed module's name 123 * does not exist, but $MODALIAS is set to needed module's name
81 * (actually, an alias to it) by kernel. This rule instructs mdev 124 * (actually, an alias to it) by kernel. This rule instructs mdev
@@ -96,11 +139,33 @@
96 * This happens regardless of /sys/class/.../dev existence. 139 * This happens regardless of /sys/class/.../dev existence.
97 */ 140 */
98 141
142struct rule {
143 bool keep_matching;
144 bool regex_compiled;
145 bool regex_has_slash;
146 mode_t mode;
147 int maj, min0, min1;
148 struct bb_uidgid_t ugid;
149 char *envvar;
150 char *ren_mov;
151 IF_FEATURE_MDEV_EXEC(char *r_cmd;)
152 regex_t match;
153};
154
99struct globals { 155struct globals {
100 int root_major, root_minor; 156 int root_major, root_minor;
101 char *subsystem; 157 char *subsystem;
158#if ENABLE_FEATURE_MDEV_CONF
159 const char *filename;
160 parser_t *parser;
161 struct rule **rule_vec;
162 unsigned rule_idx;
163#endif
164 struct rule cur_rule;
102} FIX_ALIASING; 165} FIX_ALIASING;
103#define G (*(struct globals*)&bb_common_bufsiz1) 166#define G (*(struct globals*)&bb_common_bufsiz1)
167#define INIT_G() do { } while (0)
168
104 169
105/* Prevent infinite loops in /sys symlinks */ 170/* Prevent infinite loops in /sys symlinks */
106#define MAX_SYSFS_DEPTH 3 171#define MAX_SYSFS_DEPTH 3
@@ -108,6 +173,165 @@ struct globals {
108/* We use additional 64+ bytes in make_device() */ 173/* We use additional 64+ bytes in make_device() */
109#define SCRATCH_SIZE 80 174#define SCRATCH_SIZE 80
110 175
176#if 0
177# define dbg(...) bb_error_msg(__VA_ARGS__)
178#else
179# define dbg(...) ((void)0)
180#endif
181
182
183#if ENABLE_FEATURE_MDEV_CONF
184
185static void make_default_cur_rule(void)
186{
187 memset(&G.cur_rule, 0, sizeof(G.cur_rule));
188 G.cur_rule.maj = -1; /* "not a @major,minor rule" */
189 G.cur_rule.mode = 0660;
190}
191
192static void clean_up_cur_rule(void)
193{
194 free(G.cur_rule.envvar);
195 if (G.cur_rule.regex_compiled)
196 regfree(&G.cur_rule.match);
197 free(G.cur_rule.ren_mov);
198 IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);)
199 make_default_cur_rule();
200}
201
202static void parse_next_rule(void)
203{
204 /* Note: on entry, G.cur_rule is set to default */
205 while (1) {
206 char *tokens[4];
207 char *val;
208
209 if (!config_read(G.parser, tokens, 4, 3, "# \t", PARSE_NORMAL))
210 break;
211
212 /* Fields: [-]regex uid:gid mode [alias] [cmd] */
213 dbg("token1:'%s'", tokens[1]);
214
215 /* 1st field */
216 val = tokens[0];
217 G.cur_rule.keep_matching = ('-' == val[0]);
218 val += G.cur_rule.keep_matching; /* swallow leading dash */
219 if (val[0] == '@') {
220 /* @major,minor[-minor2] */
221 /* (useful when name is ambiguous:
222 * "/sys/class/usb/lp0" and
223 * "/sys/class/printer/lp0")
224 */
225 int sc = sscanf(val, "@%u,%u-%u", &G.cur_rule.maj, &G.cur_rule.min0, &G.cur_rule.min1);
226 if (sc < 2 || G.cur_rule.maj < 0) {
227 bb_error_msg("bad @maj,min on line %d", G.parser->lineno);
228 goto next_rule;
229 }
230 if (sc == 2)
231 G.cur_rule.min1 = G.cur_rule.min0;
232 } else {
233 if (val[0] == '$') {
234 char *eq = strchr(++val, '=');
235 if (!eq) {
236 bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno);
237 goto next_rule;
238 }
239 G.cur_rule.envvar = xstrndup(val, eq - val);
240 val = eq + 1;
241 }
242 xregcomp(&G.cur_rule.match, val, REG_EXTENDED);
243 G.cur_rule.regex_compiled = 1;
244 G.cur_rule.regex_has_slash = (strchr(val, '/') != NULL);
245 }
246
247 /* 2nd field: uid:gid - device ownership */
248 if (get_uidgid(&G.cur_rule.ugid, tokens[1], /*allow_numeric:*/ 1) == 0) {
249 bb_error_msg("unknown user/group '%s' on line %d", tokens[1], G.parser->lineno);
250 goto next_rule;
251 }
252
253 /* 3rd field: mode - device permissions */
254 bb_parse_mode(tokens[2], &G.cur_rule.mode);
255
256 /* 4th field (opt): ">|=alias" or "!" to not create the node */
257 val = tokens[3];
258 if (ENABLE_FEATURE_MDEV_RENAME && val && strchr(">=!", val[0])) {
259 char *s = skip_non_whitespace(val);
260 G.cur_rule.ren_mov = xstrndup(val, s - val);
261 val = skip_whitespace(s);
262 }
263
264 if (ENABLE_FEATURE_MDEV_EXEC && val && val[0]) {
265 const char *s = "$@*";
266 const char *s2 = strchr(s, val[0]);
267 if (!s2) {
268 bb_error_msg("bad line %u", G.parser->lineno);
269 goto next_rule;
270 }
271 IF_FEATURE_MDEV_EXEC(G.cur_rule.r_cmd = xstrdup(val);)
272 }
273
274 return;
275 next_rule:
276 clean_up_cur_rule();
277 } /* while (config_read) */
278
279 dbg("config_close(G.parser)");
280 config_close(G.parser);
281 G.parser = NULL;
282
283 return;
284}
285
286/* If mdev -s, we remember rules in G.rule_vec[].
287 * Otherwise, there is no point in doing it, and we just
288 * save only one parsed rule in G.cur_rule.
289 */
290static const struct rule *next_rule(void)
291{
292 struct rule *rule;
293
294 /* Open conf file if we didn't do it yet */
295 if (!G.parser && G.filename) {
296 dbg("config_open('%s')", G.filename);
297 G.parser = config_open2(G.filename, fopen_for_read);
298 G.filename = NULL;
299 }
300
301 if (G.rule_vec) {
302 /* mdev -s */
303 /* Do we have rule parsed already? */
304 if (G.rule_vec[G.rule_idx]) {
305 dbg("< G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]);
306 return G.rule_vec[G.rule_idx++];
307 }
308 make_default_cur_rule();
309 } else {
310 /* not mdev -s */
311 clean_up_cur_rule();
312 }
313
314 /* Parse one more rule if file isn't fully read */
315 rule = &G.cur_rule;
316 if (G.parser) {
317 parse_next_rule();
318 if (G.rule_vec) { /* mdev -s */
319 rule = memcpy(xmalloc(sizeof(G.cur_rule)), &G.cur_rule, sizeof(G.cur_rule));
320 G.rule_vec = xrealloc_vector(G.rule_vec, 4, G.rule_idx);
321 G.rule_vec[G.rule_idx++] = rule;
322 dbg("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]);
323 }
324 }
325
326 return rule;
327}
328
329#else
330
331# define next_rule() (&G.cur_rule)
332
333#endif
334
111/* Builds an alias path. 335/* Builds an alias path.
112 * This function potentionally reallocates the alias parameter. 336 * This function potentionally reallocates the alias parameter.
113 * Only used for ENABLE_FEATURE_MDEV_RENAME 337 * Only used for ENABLE_FEATURE_MDEV_RENAME
@@ -143,8 +367,8 @@ static void make_device(char *path, int delete)
143{ 367{
144 char *device_name, *subsystem_slash_devname; 368 char *device_name, *subsystem_slash_devname;
145 int major, minor, type, len; 369 int major, minor, type, len;
146 mode_t mode; 370
147 parser_t *parser; 371 dbg("%s('%s', delete:%d)", __func__, path, delete);
148 372
149 /* Try to read major/minor string. Note that the kernel puts \n after 373 /* Try to read major/minor string. Note that the kernel puts \n after
150 * the data, so we don't need to worry about null terminating the string 374 * the data, so we don't need to worry about null terminating the string
@@ -197,246 +421,184 @@ static void make_device(char *path, int delete)
197 path = subsystem_slash_devname; 421 path = subsystem_slash_devname;
198 } 422 }
199 423
200 /* If we have config file, look up user settings */ 424#if ENABLE_FEATURE_MDEV_CONF
201 if (ENABLE_FEATURE_MDEV_CONF) 425 G.rule_idx = 0; /* restart from the beginning (think mdev -s) */
202 parser = config_open2("/etc/mdev.conf", fopen_for_read); 426#endif
203 427 for (;;) {
204 do { 428 const char *str_to_match;
205 int keep_matching; 429 regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP];
206 struct bb_uidgid_t ugid; 430 char *command;
207 char *tokens[4]; 431 char *alias;
208 char *command = NULL;
209 char *alias = NULL;
210 char aliaslink = aliaslink; /* for compiler */ 432 char aliaslink = aliaslink; /* for compiler */
433 const char *node_name;
434 const struct rule *rule;
211 435
212 /* Defaults in case we won't match any line */ 436 str_to_match = "";
213 ugid.uid = ugid.gid = 0; 437
214 keep_matching = 0; 438 rule = next_rule();
215 mode = 0660; 439
216 440#if ENABLE_FEATURE_MDEV_CONF
217 if (ENABLE_FEATURE_MDEV_CONF 441 if (rule->maj >= 0) { /* @maj,min rule */
218 && config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL) 442 if (major != rule->maj)
219 ) { 443 continue;
220 char *val; 444 if (minor < rule->min0 || minor > rule->min1)
221 char *str_to_match; 445 continue;
222 regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP]; 446 memset(off, 0, sizeof(off));
223 447 goto rule_matches;
224 val = tokens[0]; 448 }
225 keep_matching = ('-' == val[0]); 449 if (rule->envvar) { /* $envvar=regex rule */
226 val += keep_matching; /* swallow leading dash */ 450 str_to_match = getenv(rule->envvar);
227 451 dbg("getenv('%s'):'%s'", rule->envvar, str_to_match);
228 /* Match against either "subsystem/device_name" 452 if (!str_to_match)
229 * or "device_name" alone */ 453 continue;
230 str_to_match = strchr(val, '/') ? path : device_name; 454 } else {
231 455 /* regex to match [subsystem/]device_name */
232 /* Fields: regex uid:gid mode [alias] [cmd] */ 456 str_to_match = (rule->regex_has_slash ? path : device_name);
233 457 }
234 if (val[0] == '@') { 458
235 /* @major,minor[-minor2] */ 459 if (rule->regex_compiled) {
236 /* (useful when name is ambiguous: 460 int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0);
237 * "/sys/class/usb/lp0" and 461 dbg("regex_match for '%s':%d", str_to_match, regex_match);
238 * "/sys/class/printer/lp0") */ 462 //bb_error_msg("matches:");
239 int cmaj, cmin0, cmin1, sc; 463 //for (int i = 0; i < ARRAY_SIZE(off); i++) {
240 if (major < 0) 464 // if (off[i].rm_so < 0) continue;
241 continue; /* no dev, no match */ 465 // bb_error_msg("match %d: '%.*s'\n", i,
242 sc = sscanf(val, "@%u,%u-%u", &cmaj, &cmin0, &cmin1); 466 // (int)(off[i].rm_eo - off[i].rm_so),
243 if (sc < 1 467 // device_name + off[i].rm_so);
244 || major != cmaj 468 //}
245 || (sc == 2 && minor != cmin0) 469
246 || (sc == 3 && (minor < cmin0 || minor > cmin1)) 470 if (regex_match != 0
247 ) { 471 /* regexec returns whole pattern as "range" 0 */
248 continue; /* this line doesn't match */ 472 || off[0].rm_so != 0
249 } 473 || (int)off[0].rm_eo != (int)strlen(str_to_match)
250 goto line_matches; 474 ) {
251 } 475 continue; /* this rule doesn't match */
252 if (val[0] == '$') {
253 /* regex to match an environment variable */
254 char *eq = strchr(++val, '=');
255 if (!eq)
256 continue;
257 *eq = '\0';
258 str_to_match = getenv(val);
259 if (!str_to_match)
260 continue;
261 str_to_match -= strlen(val) + 1;
262 *eq = '=';
263 } 476 }
264 /* else: regex to match [subsystem/]device_name */ 477 }
265 478 /* else: it's final implicit "match-all" rule */
266 { 479#endif
267 regex_t match; 480
268 int result; 481 rule_matches:
269 482 dbg("rule matched");
270 xregcomp(&match, val, REG_EXTENDED); 483
271 result = regexec(&match, str_to_match, ARRAY_SIZE(off), off, 0); 484 /* Build alias name */
272 regfree(&match); 485 alias = NULL;
273 //bb_error_msg("matches:"); 486 if (ENABLE_FEATURE_MDEV_RENAME && rule->ren_mov) {
274 //for (int i = 0; i < ARRAY_SIZE(off); i++) { 487 aliaslink = rule->ren_mov[0];
275 // if (off[i].rm_so < 0) continue; 488 if (aliaslink == '!') {
276 // bb_error_msg("match %d: '%.*s'\n", i, 489 /* "!": suppress node creation/deletion */
277 // (int)(off[i].rm_eo - off[i].rm_so), 490 major = -2;
278 // device_name + off[i].rm_so);
279 //}
280
281 /* If no match, skip rest of line */
282 /* (regexec returns whole pattern as "range" 0) */
283 if (result
284 || off[0].rm_so
285 || ((int)off[0].rm_eo != (int)strlen(str_to_match))
286 ) {
287 continue; /* this line doesn't match */
288 }
289 } 491 }
290 line_matches: 492 else if (aliaslink == '>' || aliaslink == '=') {
291 /* This line matches. Stop parsing after parsing 493 if (ENABLE_FEATURE_MDEV_RENAME_REGEXP) {
292 * the rest the line unless keep_matching == 1 */ 494 char *s;
293 495 char *p;
294 /* 2nd field: uid:gid - device ownership */ 496 unsigned n;
295 if (get_uidgid(&ugid, tokens[1], /*allow_numeric:*/ 1) == 0) 497
296 bb_error_msg("unknown user/group %s on line %d", tokens[1], parser->lineno); 498 /* substitute %1..9 with off[1..9], if any */
297 499 n = 0;
298 /* 3rd field: mode - device permissions */ 500 s = rule->ren_mov;
299 bb_parse_mode(tokens[2], &mode); 501 while (*s)
300 502 if (*s++ == '%')
301 val = tokens[3]; 503 n++;
302 /* 4th field (opt): ">|=alias" or "!" to not create the node */ 504
303 505 p = alias = xzalloc(strlen(rule->ren_mov) + n * strlen(str_to_match));
304 if (ENABLE_FEATURE_MDEV_RENAME && val) { 506 s = rule->ren_mov + 1;
305 char *a, *s, *st; 507 while (*s) {
306 508 *p = *s;
307 a = val; 509 if ('%' == *s) {
308 s = strchrnul(val, ' '); 510 unsigned i = (s[1] - '0');
309 st = strchrnul(val, '\t'); 511 if (i <= 9 && off[i].rm_so >= 0) {
310 if (st < s) 512 n = off[i].rm_eo - off[i].rm_so;
311 s = st; 513 strncpy(p, str_to_match + off[i].rm_so, n);
312 st = (s[0] && s[1]) ? s+1 : NULL; 514 p += n - 1;
313 515 s++;
314 aliaslink = a[0];
315 if (aliaslink == '!' && s == a+1) {
316 val = st;
317 /* "!": suppress node creation/deletion */
318 major = -2;
319 }
320 else if (aliaslink == '>' || aliaslink == '=') {
321 val = st;
322 s[0] = '\0';
323 if (ENABLE_FEATURE_MDEV_RENAME_REGEXP) {
324 char *p;
325 unsigned i, n;
326
327 /* substitute %1..9 with off[1..9], if any */
328 n = 0;
329 s = a;
330 while (*s)
331 if (*s++ == '%')
332 n++;
333
334 p = alias = xzalloc(strlen(a) + n * strlen(str_to_match));
335 s = a + 1;
336 while (*s) {
337 *p = *s;
338 if ('%' == *s) {
339 i = (s[1] - '0');
340 if (i <= 9 && off[i].rm_so >= 0) {
341 n = off[i].rm_eo - off[i].rm_so;
342 strncpy(p, str_to_match + off[i].rm_so, n);
343 p += n - 1;
344 s++;
345 }
346 } 516 }
347 p++;
348 s++;
349 } 517 }
350 } else { 518 p++;
351 alias = xstrdup(a + 1); 519 s++;
352 } 520 }
521 } else {
522 alias = xstrdup(rule->ren_mov + 1);
353 } 523 }
354 } 524 }
525 }
526 dbg("alias:'%s'", alias);
355 527
356 if (ENABLE_FEATURE_MDEV_EXEC && val) { 528 command = NULL;
357 const char *s = "$@*"; 529 IF_FEATURE_MDEV_EXEC(command = rule->r_cmd;)
358 const char *s2 = strchr(s, val[0]); 530 if (command) {
359 531 const char *s = "$@*";
360 if (!s2) { 532 const char *s2 = strchr(s, command[0]);
361 bb_error_msg("bad line %u", parser->lineno);
362 if (ENABLE_FEATURE_MDEV_RENAME)
363 free(alias);
364 continue;
365 }
366 533
367 /* Are we running this command now? 534 /* Are we running this command now?
368 * Run $cmd on delete, @cmd on create, *cmd on both 535 * Run $cmd on delete, @cmd on create, *cmd on both
536 */
537 if (s2 - s != delete) {
538 /* We are here if: '*',
539 * or: '@' and delete = 0,
540 * or: '$' and delete = 1
369 */ 541 */
370 if (s2 - s != delete) { 542 command++;
371 /* We are here if: '*', 543 } else {
372 * or: '@' and delete = 0, 544 command = NULL;
373 * or: '$' and delete = 1
374 */
375 command = xstrdup(val + 1);
376 }
377 } 545 }
378 } 546 }
379 547 dbg("command:'%s'", command);
380 /* End of field parsing */
381 548
382 /* "Execute" the line we found */ 549 /* "Execute" the line we found */
383 { 550 node_name = device_name;
384 const char *node_name; 551 if (ENABLE_FEATURE_MDEV_RENAME && alias) {
385 552 node_name = alias = build_alias(alias, device_name);
386 node_name = device_name; 553 dbg("alias2:'%s'", alias);
387 if (ENABLE_FEATURE_MDEV_RENAME && alias) 554 }
388 node_name = alias = build_alias(alias, device_name);
389
390 if (!delete && major >= 0) {
391 if (mknod(node_name, mode | type, makedev(major, minor)) && errno != EEXIST)
392 bb_perror_msg("can't create '%s'", node_name);
393 if (major == G.root_major && minor == G.root_minor)
394 symlink(node_name, "root");
395 if (ENABLE_FEATURE_MDEV_CONF) {
396 chmod(node_name, mode);
397 chown(node_name, ugid.uid, ugid.gid);
398 }
399 if (ENABLE_FEATURE_MDEV_RENAME && alias) {
400 if (aliaslink == '>')
401 symlink(node_name, device_name);
402 }
403 }
404 555
405 if (ENABLE_FEATURE_MDEV_EXEC && command) { 556 if (!delete && major >= 0) {
406 /* setenv will leak memory, use putenv/unsetenv/free */ 557 dbg("mknod('%s',%o,(%d,%d))", node_name, rule->mode | type, major, minor);
407 char *s = xasprintf("%s=%s", "MDEV", node_name); 558 if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST)
408 char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); 559 bb_perror_msg("can't create '%s'", node_name);
409 putenv(s); 560 if (major == G.root_major && minor == G.root_minor)
410 putenv(s1); 561 symlink(node_name, "root");
411 if (system(command) == -1) 562 if (ENABLE_FEATURE_MDEV_CONF) {
412 bb_perror_msg("can't run '%s'", command); 563 chmod(node_name, rule->mode);
413 bb_unsetenv_and_free(s1); 564 chown(node_name, rule->ugid.uid, rule->ugid.gid);
414 bb_unsetenv_and_free(s);
415 free(command);
416 } 565 }
417 566 if (ENABLE_FEATURE_MDEV_RENAME && alias) {
418 if (delete && major >= -1) { 567 if (aliaslink == '>')
419 if (ENABLE_FEATURE_MDEV_RENAME && alias) { 568 symlink(node_name, device_name);
420 if (aliaslink == '>')
421 unlink(device_name);
422 }
423 unlink(node_name);
424 } 569 }
570 }
571
572 if (ENABLE_FEATURE_MDEV_EXEC && command) {
573 /* setenv will leak memory, use putenv/unsetenv/free */
574 char *s = xasprintf("%s=%s", "MDEV", node_name);
575 char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem);
576 putenv(s);
577 putenv(s1);
578 if (system(command) == -1)
579 bb_perror_msg("can't run '%s'", command);
580 bb_unsetenv_and_free(s1);
581 bb_unsetenv_and_free(s);
582 }
425 583
426 if (ENABLE_FEATURE_MDEV_RENAME) 584 if (delete && major >= -1) {
427 free(alias); 585 if (ENABLE_FEATURE_MDEV_RENAME && alias) {
586 if (aliaslink == '>')
587 unlink(device_name);
588 }
589 unlink(node_name);
428 } 590 }
429 591
592 if (ENABLE_FEATURE_MDEV_RENAME)
593 free(alias);
594
430 /* We found matching line. 595 /* We found matching line.
431 * Stop unless it was prefixed with '-' */ 596 * Stop unless it was prefixed with '-'
432 if (ENABLE_FEATURE_MDEV_CONF && !keep_matching) 597 */
598 if (!ENABLE_FEATURE_MDEV_CONF || !rule->keep_matching)
433 break; 599 break;
600 } /* for (;;) */
434 601
435 /* end of "while line is read from /etc/mdev.conf" */
436 } while (ENABLE_FEATURE_MDEV_CONF);
437
438 if (ENABLE_FEATURE_MDEV_CONF)
439 config_close(parser);
440 free(subsystem_slash_devname); 602 free(subsystem_slash_devname);
441} 603}
442 604
@@ -541,6 +703,12 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
541{ 703{
542 RESERVE_CONFIG_BUFFER(temp, PATH_MAX + SCRATCH_SIZE); 704 RESERVE_CONFIG_BUFFER(temp, PATH_MAX + SCRATCH_SIZE);
543 705
706 INIT_G();
707
708#if ENABLE_FEATURE_MDEV_CONF
709 G.filename = "/etc/mdev.conf";
710#endif
711
544 /* We can be called as hotplug helper */ 712 /* We can be called as hotplug helper */
545 /* Kernel cannot provide suitable stdio fds for us, do it ourself */ 713 /* Kernel cannot provide suitable stdio fds for us, do it ourself */
546 bb_sanitize_stdio(); 714 bb_sanitize_stdio();
@@ -556,6 +724,10 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
556 */ 724 */
557 struct stat st; 725 struct stat st;
558 726
727#if ENABLE_FEATURE_MDEV_CONF
728 /* Same as xrealloc_vector(NULL, 4, 0): */
729 G.rule_vec = xzalloc((1 << 4) * sizeof(*G.rule_vec));
730#endif
559 xstat("/", &st); 731 xstat("/", &st);
560 G.root_major = major(st.st_dev); 732 G.root_major = major(st.st_dev);
561 G.root_minor = minor(st.st_dev); 733 G.root_minor = minor(st.st_dev);
diff --git a/util-linux/mount.c b/util-linux/mount.c
index 05e532cda..f94b6e643 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -38,7 +38,7 @@
38//usage: ) 38//usage: )
39//usage: "\n -r Read-only mount" 39//usage: "\n -r Read-only mount"
40//usage: "\n -w Read-write mount (default)" 40//usage: "\n -w Read-write mount (default)"
41//usage: "\n -t FSTYPE Filesystem type" 41//usage: "\n -t FSTYPE[,...] Filesystem type(s)"
42//usage: "\n -O OPT Mount only filesystems with option OPT (-a only)" 42//usage: "\n -O OPT Mount only filesystems with option OPT (-a only)"
43//usage: "\n-o OPT:" 43//usage: "\n-o OPT:"
44//usage: IF_FEATURE_MOUNT_LOOP( 44//usage: IF_FEATURE_MOUNT_LOOP(
@@ -339,6 +339,7 @@ enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_b
339#endif 339#endif
340#define fslist (G.fslist ) 340#define fslist (G.fslist )
341#define getmntent_buf (G.getmntent_buf ) 341#define getmntent_buf (G.getmntent_buf )
342#define INIT_G() do { } while (0)
342 343
343#if ENABLE_FEATURE_MTAB_SUPPORT 344#if ENABLE_FEATURE_MTAB_SUPPORT
344/* 345/*
@@ -521,12 +522,13 @@ static llist_t *get_block_backed_filesystems(void)
521 522
522 while ((buf = xmalloc_fgetline(f)) != NULL) { 523 while ((buf = xmalloc_fgetline(f)) != NULL) {
523 if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5])) 524 if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5]))
524 continue; 525 goto next;
525 fs = skip_whitespace(buf); 526 fs = skip_whitespace(buf);
526 if (*fs == '#' || *fs == '*' || !*fs) 527 if (*fs == '#' || *fs == '*' || !*fs)
527 continue; 528 goto next;
528 529
529 llist_add_to_end(&list, xstrdup(fs)); 530 llist_add_to_end(&list, xstrdup(fs));
531 next:
530 free(buf); 532 free(buf);
531 } 533 }
532 if (ENABLE_FEATURE_CLEAN_UP) fclose(f); 534 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
@@ -1809,7 +1811,7 @@ static int singlemount(struct mntent *mp, int ignore_busy)
1809 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) { 1811 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1810 loopFile = bb_simplify_path(mp->mnt_fsname); 1812 loopFile = bb_simplify_path(mp->mnt_fsname);
1811 mp->mnt_fsname = NULL; // will receive malloced loop dev name 1813 mp->mnt_fsname = NULL; // will receive malloced loop dev name
1812 if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) { 1814 if (set_loop(&mp->mnt_fsname, loopFile, 0, /*ro:*/ 0) < 0) {
1813 if (errno == EPERM || errno == EACCES) 1815 if (errno == EPERM || errno == EACCES)
1814 bb_error_msg(bb_msg_perm_denied_are_you_root); 1816 bb_error_msg(bb_msg_perm_denied_are_you_root);
1815 else 1817 else
@@ -1825,7 +1827,16 @@ static int singlemount(struct mntent *mp, int ignore_busy)
1825 // If we know the fstype (or don't need to), jump straight 1827 // If we know the fstype (or don't need to), jump straight
1826 // to the actual mount. 1828 // to the actual mount.
1827 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) { 1829 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
1828 rc = mount_it_now(mp, vfsflags, filteropts); 1830 char *next;
1831 for (;;) {
1832 next = mp->mnt_type ? strchr(mp->mnt_type, ',') : NULL;
1833 if (next)
1834 *next = '\0';
1835 rc = mount_it_now(mp, vfsflags, filteropts);
1836 if (rc == 0 || !next)
1837 break;
1838 mp->mnt_type = next + 1;
1839 }
1829 } else { 1840 } else {
1830 // Loop through filesystem types until mount succeeds 1841 // Loop through filesystem types until mount succeeds
1831 // or we run out 1842 // or we run out
@@ -1842,7 +1853,7 @@ static int singlemount(struct mntent *mp, int ignore_busy)
1842 for (fl = fslist; fl; fl = fl->link) { 1853 for (fl = fslist; fl; fl = fl->link) {
1843 mp->mnt_type = fl->data; 1854 mp->mnt_type = fl->data;
1844 rc = mount_it_now(mp, vfsflags, filteropts); 1855 rc = mount_it_now(mp, vfsflags, filteropts);
1845 if (!rc) 1856 if (rc == 0)
1846 break; 1857 break;
1847 } 1858 }
1848 } 1859 }
@@ -1944,6 +1955,8 @@ int mount_main(int argc UNUSED_PARAM, char **argv)
1944 1955
1945 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid(); 1956 IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
1946 1957
1958 INIT_G();
1959
1947 // Parse long options, like --bind and --move. Note that -o option 1960 // Parse long options, like --bind and --move. Note that -o option
1948 // and --option are synonymous. Yes, this means --remount,rw works. 1961 // and --option are synonymous. Yes, this means --remount,rw works.
1949 for (i = j = 1; argv[i]; i++) { 1962 for (i = j = 1; argv[i]; i++) {
diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c
index 43ddb4031..54867ec36 100644
--- a/util-linux/swaponoff.c
+++ b/util-linux/swaponoff.c
@@ -24,7 +24,6 @@
24 24
25#include "libbb.h" 25#include "libbb.h"
26#include <mntent.h> 26#include <mntent.h>
27#include <sys/swap.h>
28#ifndef __BIONIC__ 27#ifndef __BIONIC__
29# include <sys/swap.h> 28# include <sys/swap.h>
30#endif 29#endif
@@ -48,6 +47,7 @@ struct globals {
48#else 47#else
49#define g_flags 0 48#define g_flags 0
50#endif 49#endif
50#define INIT_G() do { } while (0)
51 51
52static int swap_enable_disable(char *device) 52static int swap_enable_disable(char *device)
53{ 53{
@@ -111,10 +111,13 @@ int swap_on_off_main(int argc UNUSED_PARAM, char **argv)
111{ 111{
112 int ret; 112 int ret;
113 113
114 INIT_G();
115
114#if !ENABLE_FEATURE_SWAPON_PRI 116#if !ENABLE_FEATURE_SWAPON_PRI
115 ret = getopt32(argv, "a"); 117 ret = getopt32(argv, "a");
116#else 118#else
117 opt_complementary = "p+"; 119 if (applet_name[5] == 'n')
120 opt_complementary = "p+";
118 ret = getopt32(argv, (applet_name[5] == 'n') ? "ap:" : "a", &g_flags); 121 ret = getopt32(argv, (applet_name[5] == 'n') ? "ap:" : "a", &g_flags);
119 122
120 if (ret & 2) { // -p 123 if (ret & 2) { // -p