aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2012-03-23 12:12:03 +0000
committerRon Yorston <rmy@pobox.com>2012-03-23 12:12:03 +0000
commitb0f54743e36af163ae2530c381c485bb29df13dc (patch)
treecda4cfeaae6e47fe4f14c1b566092be4da9affc4
parent40514a0309939f2446f0d4ed9600cad5de396e7f (diff)
parentba88826c66411affc1da3614742b454654f7298a (diff)
downloadbusybox-w32-b0f54743e36af163ae2530c381c485bb29df13dc.tar.gz
busybox-w32-b0f54743e36af163ae2530c381c485bb29df13dc.tar.bz2
busybox-w32-b0f54743e36af163ae2530c381c485bb29df13dc.zip
Merge branch 'busybox' into merge
Conflicts: Makefile.flags
-rw-r--r--Config.in44
-rw-r--r--Makefile.flags35
-rw-r--r--applets/applet_tables.c9
-rw-r--r--applets_sh/README5
-rwxr-xr-xapplets_sh/dos2unix5
-rwxr-xr-xapplets_sh/nologin4
-rwxr-xr-xapplets_sh/tac7
-rwxr-xr-xapplets_sh/unix2dos5
-rw-r--r--archival/Config.src4
-rw-r--r--archival/bbunzip.c72
-rw-r--r--archival/bzip2.c2
-rw-r--r--archival/cpio.c1
-rw-r--r--archival/gzip.c2
-rw-r--r--archival/libarchive/Kbuild.src21
-rw-r--r--archival/libarchive/data_extract_all.c8
-rw-r--r--archival/libarchive/data_extract_to_command.c8
-rw-r--r--archival/libarchive/decompress_bunzip2.c18
-rw-r--r--archival/libarchive/decompress_gunzip.c (renamed from archival/libarchive/decompress_unzip.c)69
-rw-r--r--archival/libarchive/decompress_uncompress.c15
-rw-r--r--archival/libarchive/decompress_unlzma.c2
-rw-r--r--archival/libarchive/decompress_unxz.c12
-rw-r--r--archival/libarchive/get_header_tar.c100
-rw-r--r--archival/libarchive/get_header_tar_bz2.c2
-rw-r--r--archival/libarchive/get_header_tar_gz.c17
-rw-r--r--archival/libarchive/get_header_tar_lzma.c2
-rw-r--r--archival/libarchive/open_transformer.c193
-rw-r--r--archival/lzop.c13
-rw-r--r--archival/rpm.c2
-rw-r--r--archival/rpm2cpio.c54
-rw-r--r--archival/tar.c103
-rw-r--r--archival/unzip.c10
-rw-r--r--configs/android_defconfig16
-rw-r--r--configs/android_ndk_defconfig1016
-rw-r--r--coreutils/chroot.c1
-rw-r--r--coreutils/cp.c4
-rw-r--r--coreutils/date.c3
-rw-r--r--coreutils/du.c24
-rw-r--r--coreutils/ln.c4
-rw-r--r--coreutils/mkdir.c7
-rw-r--r--coreutils/printf.c26
-rw-r--r--coreutils/test.c15
-rw-r--r--coreutils/touch.c26
-rw-r--r--coreutils/uudecode.c2
-rw-r--r--coreutils/uuencode.c4
-rw-r--r--debianutils/start_stop_daemon.c19
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/probe.c9
-rw-r--r--editors/sed.c38
-rw-r--r--editors/vi.c97
-rw-r--r--examples/udhcp/udhcpd.conf6
-rw-r--r--findutils/grep.c12
-rw-r--r--include/bb_archive.h71
-rw-r--r--include/grp_.h2
-rw-r--r--include/libbb.h72
-rw-r--r--include/pwd_.h2
-rw-r--r--include/volume_id.h2
-rw-r--r--include/xatonum.h9
-rw-r--r--init/bootchartd.c41
-rw-r--r--init/init.c68
-rw-r--r--libbb/appletlib.c9
-rw-r--r--libbb/bb_strtonum.c59
-rw-r--r--libbb/dump.c25
-rw-r--r--libbb/find_mount_point.c3
-rw-r--r--libbb/isdirectory.c15
-rw-r--r--libbb/lineedit.c15
-rw-r--r--libbb/parse_config.c2
-rw-r--r--libbb/procps.c16
-rw-r--r--libbb/read_printf.c139
-rw-r--r--libbb/vfork_daemon_rexec.c10
-rw-r--r--libbb/xconnect.c16
-rw-r--r--libbb/xfuncs_printf.c1
-rw-r--r--libpwdgrp/pwd_grp.c103
-rw-r--r--loginutils/Config.src7
-rw-r--r--loginutils/chpasswd.c2
-rw-r--r--loginutils/cryptpw.c2
-rw-r--r--loginutils/getty.c6
-rw-r--r--loginutils/login.c18
-rw-r--r--loginutils/passwd.c2
-rw-r--r--mailutils/mail.c2
-rw-r--r--mailutils/mail.h7
-rw-r--r--mailutils/makemime.c36
-rw-r--r--mailutils/reformime.c1
-rw-r--r--mailutils/sendmail.c22
-rw-r--r--miscutils/fbsplash.c16
-rw-r--r--miscutils/man.c41
-rw-r--r--miscutils/rx.c1
-rw-r--r--miscutils/ubi_tools.c4
-rw-r--r--modutils/depmod.c27
-rw-r--r--modutils/modprobe-small.c6
-rw-r--r--modutils/modprobe.c15
-rw-r--r--networking/Config.src16
-rw-r--r--networking/ftpd.c3
-rw-r--r--networking/ftpgetput.c34
-rw-r--r--networking/httpd.c276
-rw-r--r--networking/httpd_indexcgi.c27
-rw-r--r--networking/ifupdown.c14
-rw-r--r--networking/ip.c13
-rw-r--r--networking/nc_bloaty.c43
-rw-r--r--networking/ntpd.c281
-rw-r--r--networking/tftp.c5
-rw-r--r--networking/udhcp/common.c88
-rw-r--r--networking/udhcp/common.h6
-rw-r--r--networking/udhcp/d6_common.h123
-rw-r--r--networking/udhcp/d6_dhcpc.c1483
-rw-r--r--networking/udhcp/d6_packet.c172
-rw-r--r--networking/udhcp/d6_socket.c34
-rw-r--r--networking/udhcp/dhcpc.c168
-rw-r--r--networking/udhcp/packet.c57
-rw-r--r--networking/vconfig.c102
-rw-r--r--networking/wget.c6
-rw-r--r--procps/kill.c11
-rw-r--r--procps/sysctl.c4
-rw-r--r--runit/chpst.c3
-rw-r--r--scripts/defconfig.tig8
-rwxr-xr-xscripts/gen_build_files.sh7
-rw-r--r--shell/ash.c18
-rw-r--r--shell/cttyhack.c13
-rw-r--r--shell/shell_common.c8
-rwxr-xr-xtestsuite/tar.tests19
-rw-r--r--util-linux/Config.src11
-rw-r--r--util-linux/acpid.c62
-rw-r--r--util-linux/blkid.c9
-rw-r--r--util-linux/getopt.c51
-rw-r--r--util-linux/mdev.c11
-rw-r--r--util-linux/mkfs_ext2.c6
-rw-r--r--util-linux/more.c3
-rw-r--r--util-linux/mount.c99
-rw-r--r--util-linux/rdev.c4
-rw-r--r--util-linux/switch_root.c2
-rw-r--r--util-linux/volume_id/get_devname.c57
129 files changed, 4967 insertions, 1458 deletions
diff --git a/Config.in b/Config.in
index 9edf28d79..cd51e2b45 100644
--- a/Config.in
+++ b/Config.in
@@ -106,20 +106,21 @@ config FEATURE_BUFFERS_GO_IN_BSS
106endchoice 106endchoice
107 107
108config SHOW_USAGE 108config SHOW_USAGE
109 bool "Show terse applet usage messages" 109 bool "Show applet usage messages"
110 default y 110 default y
111 help 111 help
112 All BusyBox applets will show help messages when invoked with 112 Enabling this option, BusyBox applets will show terse help messages
113 wrong arguments. You can turn off printing these terse usage 113 when invoked with wrong arguments.
114 messages if you say no here. 114 If you do not want to show any (helpful) usage message when
115 This will save you up to 7k. 115 issuing wrong command syntax, you can say 'N' here,
116 saving approximately 7k.
116 117
117config FEATURE_VERBOSE_USAGE 118config FEATURE_VERBOSE_USAGE
118 bool "Show verbose applet usage messages" 119 bool "Show verbose applet usage messages"
119 default y 120 default y
120 depends on SHOW_USAGE 121 depends on SHOW_USAGE
121 help 122 help
122 All BusyBox applets will show more verbose help messages when 123 All BusyBox applets will show verbose help messages when
123 busybox is invoked with --help. This will add a lot of text to the 124 busybox is invoked with --help. This will add a lot of text to the
124 busybox binary. In the default configuration, this will add about 125 busybox binary. In the default configuration, this will add about
125 13k, but it can add much more depending on your configuration. 126 13k, but it can add much more depending on your configuration.
@@ -129,8 +130,8 @@ config FEATURE_COMPRESS_USAGE
129 default y 130 default y
130 depends on SHOW_USAGE 131 depends on SHOW_USAGE
131 help 132 help
132 Store usage messages in compressed form, uncompress them on-the-fly 133 Store usage messages in .bz compressed form, uncompress them
133 when <applet> --help is called. 134 on-the-fly when <applet> --help is called.
134 135
135 If you have a really tiny busybox with few applets enabled (and 136 If you have a really tiny busybox with few applets enabled (and
136 bunzip2 isn't one of them), the overhead of the decompressor might 137 bunzip2 isn't one of them), the overhead of the decompressor might
@@ -622,12 +623,39 @@ config CROSS_COMPILER_PREFIX
622 623
623 Native builds leave this empty. 624 Native builds leave this empty.
624 625
626config SYSROOT
627 string "Path to sysroot"
628 default ""
629 help
630 If you want to build BusyBox with a cross compiler, then you
631 might also need to specify where /usr/include and /usr/lib
632 will be found.
633
634 For example, BusyBox can be built against an installed
635 Android NDK, platform version 9, for ARM ABI with
636
637 CONFIG_SYSROOT=/opt/android-ndk/platforms/android-9/arch-arm
638
639 Native builds leave this empty.
640
625config EXTRA_CFLAGS 641config EXTRA_CFLAGS
626 string "Additional CFLAGS" 642 string "Additional CFLAGS"
627 default "" 643 default ""
628 help 644 help
629 Additional CFLAGS to pass to the compiler verbatim. 645 Additional CFLAGS to pass to the compiler verbatim.
630 646
647config EXTRA_LDFLAGS
648 string "Additional LDFLAGS"
649 default ""
650 help
651 Additional LDFLAGS to pass to the linker verbatim.
652
653config EXTRA_LDLIBS
654 string "Additional LDLIBS"
655 default ""
656 help
657 Additional LDLIBS to pass to the linker with -l.
658
631endmenu 659endmenu
632 660
633menu 'Debugging Options' 661menu 'Debugging Options'
diff --git a/Makefile.flags b/Makefile.flags
index b653d55c1..2a3aa5812 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -97,6 +97,13 @@ CFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_CFLAGS)))
97#")) 97#"))
98endif 98endif
99 99
100# Note: both "" (string consisting of two quote chars) and empty string
101# are possible, and should be skipped below.
102ifneq ($(subst "",,$(CONFIG_SYSROOT)),)
103CFLAGS += --sysroot=$(CONFIG_SYSROOT)
104export SYSROOT=$(CONFIG_SYSROOT)
105endif
106
100ifeq ($(CONFIG_PLATFORM_MINGW32),y) 107ifeq ($(CONFIG_PLATFORM_MINGW32),y)
101# These defintions are not strictly needed, but they help shut up fnmatch.c warnings 108# These defintions are not strictly needed, but they help shut up fnmatch.c warnings
102CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy 109CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy
@@ -104,17 +111,25 @@ EXEEXT = .exe
104ifeq ($(CONFIG_WIN32_NET),y) 111ifeq ($(CONFIG_WIN32_NET),y)
105LDLIBS += ws2_32 112LDLIBS += ws2_32
106endif 113endif
107else 114endif
108ifneq ($(CONFIG_CROSS_COMPILER_PREFIX),"arm-linux-androideabi-") 115
116# Android has no separate crypt library
117CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) -lcrypt -o /dev/null -xc - >/dev/null 2>&1 && echo "y")
118ifeq ($(CRYPT_AVAILABLE),y)
109LDLIBS += m crypt 119LDLIBS += m crypt
110else 120else
111# Android libc has no crypt. TODO: make a generic CONFIG_LINK_WITH_CRYPT option?
112LDLIBS += m 121LDLIBS += m
113endif 122endif
114endif
115 123
116ifeq ($(CONFIG_PAM),y) 124ifeq ($(CONFIG_PAM),y)
117LDLIBS += pam pam_misc 125# libpam uses libpthread, so for static builds busybox must be linked to
126# libpthread. On some platforms that requires an explicit -lpthread, so
127# it should be in LDLIBS. For non-static builds, scripts/trylink will
128# take care of removing -lpthread if possible. (Not bothering to check
129# CONFIG_STATIC because even in a non-static build it could be that the
130# only libpam available is libpam.a, so -lpthread could still be
131# needed.)
132LDLIBS += pam pam_misc pthread
118endif 133endif
119 134
120ifeq ($(CONFIG_SELINUX),y) 135ifeq ($(CONFIG_SELINUX),y)
@@ -139,6 +154,16 @@ ifneq (,$(findstring $(W_ELF2FLT),$(LDFLAGS) $(CFLAGS_busybox)))
139SKIP_STRIP = y 154SKIP_STRIP = y
140endif 155endif
141 156
157ifneq ($(CONFIG_EXTRA_LDFLAGS),)
158EXTRA_LDFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_LDFLAGS)))
159#"))
160endif
161
162ifneq ($(CONFIG_EXTRA_LDLIBS),)
163LDLIBS += $(strip $(subst ",,$(CONFIG_EXTRA_LDLIBS)))
164#"))
165endif
166
142# Busybox is a stack-fatty so make sure we increase default size 167# Busybox is a stack-fatty so make sure we increase default size
143# TODO: use "make stksizes" to find & fix big stack users 168# TODO: use "make stksizes" to find & fix big stack users
144# (we stole scripts/checkstack.pl from the kernel... thanks guys!) 169# (we stole scripts/checkstack.pl from the kernel... thanks guys!)
diff --git a/applets/applet_tables.c b/applets/applet_tables.c
index a47574737..152d5f441 100644
--- a/applets/applet_tables.c
+++ b/applets/applet_tables.c
@@ -80,15 +80,8 @@ 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;
84 printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name); 83 printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name);
85 /* Example: "ether-wake" -> "ether_wake" */ 84 printf("#define SINGLE_APPLET_MAIN %s_main\n", applets[0].main);
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);
92 } 85 }
93 printf("\n"); 86 printf("\n");
94 87
diff --git a/applets_sh/README b/applets_sh/README
new file mode 100644
index 000000000..9dcd38ae3
--- /dev/null
+++ b/applets_sh/README
@@ -0,0 +1,5 @@
1This directory contains examples of applets implemented as shell scripts.
2
3So far these scripts are not hooked to the build system and are not
4installed by "make install". If you want to use them,
5you need to install them by hand.
diff --git a/applets_sh/dos2unix b/applets_sh/dos2unix
new file mode 100755
index 000000000..0fd5206f6
--- /dev/null
+++ b/applets_sh/dos2unix
@@ -0,0 +1,5 @@
1#!/bin/sh
2# TODO: use getopt to avoid parsing options as filenames,
3# and to support -- and --help
4[ $# -ne 0 ] && DASH_I=-i
5sed $DASH_I -e 's/\r$//' "$@"
diff --git a/applets_sh/nologin b/applets_sh/nologin
new file mode 100755
index 000000000..3768eaaa7
--- /dev/null
+++ b/applets_sh/nologin
@@ -0,0 +1,4 @@
1#!/bin/sh
2cat /etc/nologin.txt 2>/dev/null || echo "This account is not available"
3sleep 5
4exit 1
diff --git a/applets_sh/tac b/applets_sh/tac
new file mode 100755
index 000000000..c5a8e39c1
--- /dev/null
+++ b/applets_sh/tac
@@ -0,0 +1,7 @@
1#!/bin/sh
2# TODO: use getopt to avoid parsing options as filenames,
3# and to support -- and --help
4for i in "$@"
5do
6sed -e '1!G;h;$!d' "$i"
7done
diff --git a/applets_sh/unix2dos b/applets_sh/unix2dos
new file mode 100755
index 000000000..70e042906
--- /dev/null
+++ b/applets_sh/unix2dos
@@ -0,0 +1,5 @@
1#!/bin/sh
2# TODO: use getopt to avoid parsing options as filenames,
3# and to support -- and --help
4[ $# -ne 0 ] && DASH_I=-i
5sed $DASH_I -e 's/$/\r/' "$@"
diff --git a/archival/Config.src b/archival/Config.src
index f1d6d3511..13c33c795 100644
--- a/archival/Config.src
+++ b/archival/Config.src
@@ -32,10 +32,10 @@ config FEATURE_SEAMLESS_GZ
32 Make tar, rpm, modprobe etc understand .gz data. 32 Make tar, rpm, modprobe etc understand .gz data.
33 33
34config FEATURE_SEAMLESS_Z 34config FEATURE_SEAMLESS_Z
35 bool "Make tar and gunzip understand .Z data" 35 bool "tar, rpm, modprobe etc understand .Z data"
36 default n 36 default n
37 help 37 help
38 Make tar and gunzip understand .Z data. 38 Make tar, rpm, modprobe etc understand .Z data.
39 39
40config AR 40config AR
41 bool "ar" 41 bool "ar"
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index c96e5396a..66a046052 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -33,7 +33,7 @@ char* FAST_FUNC append_ext(char *filename, const char *expected_ext)
33} 33}
34 34
35int FAST_FUNC bbunpack(char **argv, 35int FAST_FUNC bbunpack(char **argv,
36 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(unpack_info_t *info), 36 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux),
37 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), 37 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
38 const char *expected_ext 38 const char *expected_ext
39) 39)
@@ -42,7 +42,7 @@ int FAST_FUNC bbunpack(char **argv,
42 IF_DESKTOP(long long) int status; 42 IF_DESKTOP(long long) int status;
43 char *filename, *new_name; 43 char *filename, *new_name;
44 smallint exitcode = 0; 44 smallint exitcode = 0;
45 unpack_info_t info; 45 transformer_aux_data_t aux;
46 46
47 do { 47 do {
48 /* NB: new_name is *maybe* malloc'ed! */ 48 /* NB: new_name is *maybe* malloc'ed! */
@@ -98,9 +98,9 @@ int FAST_FUNC bbunpack(char **argv,
98 "use -f to force it"); 98 "use -f to force it");
99 } 99 }
100 100
101 /* memset(&info, 0, sizeof(info)); */ 101 init_transformer_aux_data(&aux);
102 info.mtime = 0; /* so far it has one member only */ 102 aux.check_signature = 1;
103 status = unpacker(&info); 103 status = unpacker(&aux);
104 if (status < 0) 104 if (status < 0)
105 exitcode = 1; 105 exitcode = 1;
106 106
@@ -111,10 +111,10 @@ int FAST_FUNC bbunpack(char **argv,
111 char *del = new_name; 111 char *del = new_name;
112 if (status >= 0) { 112 if (status >= 0) {
113 /* TODO: restore other things? */ 113 /* TODO: restore other things? */
114 if (info.mtime) { 114 if (aux.mtime != 0) {
115 struct timeval times[2]; 115 struct timeval times[2];
116 116
117 times[1].tv_sec = times[0].tv_sec = info.mtime; 117 times[1].tv_sec = times[0].tv_sec = aux.mtime;
118 times[1].tv_usec = times[0].tv_usec = 0; 118 times[1].tv_usec = times[0].tv_usec = 0;
119 /* Note: we closed it first. 119 /* Note: we closed it first.
120 * On some systems calling utimes 120 * On some systems calling utimes
@@ -184,16 +184,9 @@ char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext)
184 184
185#if ENABLE_UNCOMPRESS 185#if ENABLE_UNCOMPRESS
186static 186static
187IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(unpack_info_t *info UNUSED_PARAM) 187IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux)
188{ 188{
189 IF_DESKTOP(long long) int status = -1; 189 return unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO);
190
191 if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) {
192 bb_error_msg("invalid magic");
193 } else {
194 status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO);
195 }
196 return status;
197} 190}
198int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 191int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
199int uncompress_main(int argc UNUSED_PARAM, char **argv) 192int uncompress_main(int argc UNUSED_PARAM, char **argv)
@@ -281,31 +274,9 @@ char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UN
281 return filename; 274 return filename;
282} 275}
283static 276static
284IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(unpack_info_t *info) 277IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux)
285{ 278{
286 IF_DESKTOP(long long) int status = -1; 279 return unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
287
288 /* do the decompression, and cleanup */
289 if (xread_char(STDIN_FILENO) == 0x1f) {
290 unsigned char magic2;
291
292 magic2 = xread_char(STDIN_FILENO);
293 if (ENABLE_FEATURE_SEAMLESS_Z && magic2 == 0x9d) {
294 status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO);
295 } else if (magic2 == 0x8b) {
296 status = unpack_gz_stream_with_info(STDIN_FILENO, STDOUT_FILENO, info);
297 } else {
298 goto bad_magic;
299 }
300 if (status < 0) {
301 bb_error_msg("error inflating");
302 }
303 } else {
304 bad_magic:
305 bb_error_msg("invalid magic");
306 /* status is still == -1 */
307 }
308 return status;
309} 280}
310/* 281/*
311 * Linux kernel build uses gzip -d -n. We accept and ignore it. 282 * Linux kernel build uses gzip -d -n. We accept and ignore it.
@@ -354,9 +325,9 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
354//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat)) 325//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat))
355#if ENABLE_BUNZIP2 326#if ENABLE_BUNZIP2
356static 327static
357IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(unpack_info_t *info UNUSED_PARAM) 328IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux)
358{ 329{
359 return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO); 330 return unpack_bz2_stream(aux, STDIN_FILENO, STDOUT_FILENO);
360} 331}
361int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 332int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
362int bunzip2_main(int argc UNUSED_PARAM, char **argv) 333int bunzip2_main(int argc UNUSED_PARAM, char **argv)
@@ -422,9 +393,9 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
422 393
423#if ENABLE_UNLZMA 394#if ENABLE_UNLZMA
424static 395static
425IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(unpack_info_t *info UNUSED_PARAM) 396IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux)
426{ 397{
427 return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO); 398 return unpack_lzma_stream(aux, STDIN_FILENO, STDOUT_FILENO);
428} 399}
429int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 400int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
430int unlzma_main(int argc UNUSED_PARAM, char **argv) 401int unlzma_main(int argc UNUSED_PARAM, char **argv)
@@ -447,18 +418,9 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv)
447 418
448#if ENABLE_UNXZ 419#if ENABLE_UNXZ
449static 420static
450IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM) 421IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux)
451{ 422{
452 struct { 423 return unpack_xz_stream(aux, STDIN_FILENO, STDOUT_FILENO);
453 uint32_t v1;
454 uint16_t v2;
455 } magic;
456 xread(STDIN_FILENO, &magic, 6);
457 if (magic.v1 != XZ_MAGIC1a || magic.v2 != XZ_MAGIC2a) {
458 bb_error_msg("invalid magic");
459 return -1;
460 }
461 return unpack_xz_stream(STDIN_FILENO, STDOUT_FILENO);
462} 424}
463int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 425int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
464int unxz_main(int argc UNUSED_PARAM, char **argv) 426int unxz_main(int argc UNUSED_PARAM, char **argv)
diff --git a/archival/bzip2.c b/archival/bzip2.c
index 0716fa89b..dd77c8efc 100644
--- a/archival/bzip2.c
+++ b/archival/bzip2.c
@@ -111,7 +111,7 @@ IF_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, vo
111} 111}
112 112
113static 113static
114IF_DESKTOP(long long) int FAST_FUNC compressStream(unpack_info_t *info UNUSED_PARAM) 114IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_aux_data_t *aux UNUSED_PARAM)
115{ 115{
116 IF_DESKTOP(long long) int total; 116 IF_DESKTOP(long long) int total;
117 ssize_t count; 117 ssize_t count;
diff --git a/archival/cpio.c b/archival/cpio.c
index c2a5b8ab9..98cc18fa0 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -384,6 +384,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
384 goto dump; 384 goto dump;
385 } 385 }
386 /* parent */ 386 /* parent */
387 USE_FOR_NOMMU(argv[-optind][0] &= 0x7f); /* undo fork_or_rexec() damage */
387 xchdir(*argv++); 388 xchdir(*argv++);
388 close(pp.wr); 389 close(pp.wr);
389 xmove_fd(pp.rd, STDIN_FILENO); 390 xmove_fd(pp.rd, STDIN_FILENO);
diff --git a/archival/gzip.c b/archival/gzip.c
index f590fffa5..025e0a9f6 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -2015,7 +2015,7 @@ static void zip(ulg time_stamp)
2015 2015
2016/* ======================================================================== */ 2016/* ======================================================================== */
2017static 2017static
2018IF_DESKTOP(long long) int FAST_FUNC pack_gzip(unpack_info_t *info UNUSED_PARAM) 2018IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_aux_data_t *aux UNUSED_PARAM)
2019{ 2019{
2020 struct stat s; 2020 struct stat s;
2021 2021
diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src
index b0bc4e5aa..39c18f264 100644
--- a/archival/libarchive/Kbuild.src
+++ b/archival/libarchive/Kbuild.src
@@ -28,10 +28,13 @@ COMMON_FILES:= \
28 init_handle.o 28 init_handle.o
29 29
30DPKG_FILES:= \ 30DPKG_FILES:= \
31 get_header_ar.o \
32 unpack_ar_archive.o \ 31 unpack_ar_archive.o \
32 filter_accept_list_reassign.o \
33 get_header_ar.o \
33 get_header_tar.o \ 34 get_header_tar.o \
34 filter_accept_list_reassign.o 35 get_header_tar_gz.o \
36 get_header_tar_bz2.o \
37 get_header_tar_lzma.o \
35 38
36INSERT 39INSERT
37 40
@@ -42,18 +45,18 @@ lib-$(CONFIG_UNXZ) += decompress_unxz.o
42lib-$(CONFIG_CPIO) += get_header_cpio.o 45lib-$(CONFIG_CPIO) += get_header_cpio.o
43lib-$(CONFIG_DPKG) += $(DPKG_FILES) 46lib-$(CONFIG_DPKG) += $(DPKG_FILES)
44lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) 47lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES)
45lib-$(CONFIG_GUNZIP) += decompress_unzip.o 48lib-$(CONFIG_GUNZIP) += decompress_gunzip.o
46lib-$(CONFIG_RPM2CPIO) += decompress_unzip.o get_header_cpio.o 49lib-$(CONFIG_RPM2CPIO) += decompress_gunzip.o get_header_cpio.o
47lib-$(CONFIG_RPM) += open_transformer.o decompress_unzip.o get_header_cpio.o 50lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o
48lib-$(CONFIG_TAR) += get_header_tar.o 51lib-$(CONFIG_TAR) += get_header_tar.o
49lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o 52lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o
50lib-$(CONFIG_UNZIP) += decompress_unzip.o 53lib-$(CONFIG_UNZIP) += decompress_gunzip.o
51lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o 54lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o
52lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o 55lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o
53lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o 56lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o
54lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_unzip.o get_header_tar_gz.o 57lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_gunzip.o
55lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o 58lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o
56lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o 59lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o
57lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o 60lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o
58lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o 61lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o
59lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += decompress_bunzip2.o 62lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += decompress_bunzip2.o
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index f565e5471..3f67b835f 100644
--- a/archival/libarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -13,13 +13,13 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
13 int res; 13 int res;
14 14
15#if ENABLE_FEATURE_TAR_SELINUX 15#if ENABLE_FEATURE_TAR_SELINUX
16 char *sctx = archive_handle->tar__next_file_sctx; 16 char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
17 if (!sctx) 17 if (!sctx)
18 sctx = archive_handle->tar__global_sctx; 18 sctx = archive_handle->tar__sctx[PAX_GLOBAL];
19 if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ 19 if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
20 setfscreatecon(sctx); 20 setfscreatecon(sctx);
21 free(archive_handle->tar__next_file_sctx); 21 free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
22 archive_handle->tar__next_file_sctx = NULL; 22 archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
23 } 23 }
24#endif 24#endif
25 25
diff --git a/archival/libarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c
index cc2ff7798..a2ce33b51 100644
--- a/archival/libarchive/data_extract_to_command.c
+++ b/archival/libarchive/data_extract_to_command.c
@@ -64,13 +64,13 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle)
64 file_header_t *file_header = archive_handle->file_header; 64 file_header_t *file_header = archive_handle->file_header;
65 65
66#if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */ 66#if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */
67 char *sctx = archive_handle->tar__next_file_sctx; 67 char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
68 if (!sctx) 68 if (!sctx)
69 sctx = archive_handle->tar__global_sctx; 69 sctx = archive_handle->tar__sctx[PAX_GLOBAL];
70 if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ 70 if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
71 setfscreatecon(sctx); 71 setfscreatecon(sctx);
72 free(archive_handle->tar__next_file_sctx); 72 free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
73 archive_handle->tar__next_file_sctx = NULL; 73 archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
74 } 74 }
75#endif 75#endif
76 76
diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c
index c4640d489..dc252bb82 100644
--- a/archival/libarchive/decompress_bunzip2.c
+++ b/archival/libarchive/decompress_bunzip2.c
@@ -721,7 +721,7 @@ void FAST_FUNC dealloc_bunzip(bunzip_data *bd)
721 721
722/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */ 722/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */
723IF_DESKTOP(long long) int FAST_FUNC 723IF_DESKTOP(long long) int FAST_FUNC
724unpack_bz2_stream(int src_fd, int dst_fd) 724unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
725{ 725{
726 IF_DESKTOP(long long total_written = 0;) 726 IF_DESKTOP(long long total_written = 0;)
727 bunzip_data *bd; 727 bunzip_data *bd;
@@ -729,6 +729,9 @@ unpack_bz2_stream(int src_fd, int dst_fd)
729 int i; 729 int i;
730 unsigned len; 730 unsigned len;
731 731
732 if (check_signature16(aux, src_fd, BZIP2_MAGIC))
733 return -1;
734
732 outbuf = xmalloc(IOBUF_SIZE); 735 outbuf = xmalloc(IOBUF_SIZE);
733 len = 0; 736 len = 0;
734 while (1) { /* "Process one BZ... stream" loop */ 737 while (1) { /* "Process one BZ... stream" loop */
@@ -794,17 +797,6 @@ unpack_bz2_stream(int src_fd, int dst_fd)
794 return i ? i : IF_DESKTOP(total_written) + 0; 797 return i ? i : IF_DESKTOP(total_written) + 0;
795} 798}
796 799
797IF_DESKTOP(long long) int FAST_FUNC
798unpack_bz2_stream_prime(int src_fd, int dst_fd)
799{
800 uint16_t magic2;
801 xread(src_fd, &magic2, 2);
802 if (magic2 != BZIP2_MAGIC) {
803 bb_error_msg_and_die("invalid magic");
804 }
805 return unpack_bz2_stream(src_fd, dst_fd);
806}
807
808#ifdef TESTING 800#ifdef TESTING
809 801
810static char *const bunzip_errors[] = { 802static char *const bunzip_errors[] = {
@@ -819,7 +811,7 @@ int main(int argc, char **argv)
819 int i; 811 int i;
820 char c; 812 char c;
821 813
822 int i = unpack_bz2_stream_prime(0, 1); 814 int i = unpack_bz2_stream(0, 1);
823 if (i < 0) 815 if (i < 0)
824 fprintf(stderr, "%s\n", bunzip_errors[-i]); 816 fprintf(stderr, "%s\n", bunzip_errors[-i]);
825 else if (read(STDIN_FILENO, &c, 1)) 817 else if (read(STDIN_FILENO, &c, 1))
diff --git a/archival/libarchive/decompress_unzip.c b/archival/libarchive/decompress_gunzip.c
index aa5d22d0a..2d5ab3eb3 100644
--- a/archival/libarchive/decompress_unzip.c
+++ b/archival/libarchive/decompress_gunzip.c
@@ -1034,22 +1034,22 @@ inflate_unzip_internal(STATE_PARAM int in, int out)
1034/* For unzip */ 1034/* For unzip */
1035 1035
1036IF_DESKTOP(long long) int FAST_FUNC 1036IF_DESKTOP(long long) int FAST_FUNC
1037inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out) 1037inflate_unzip(transformer_aux_data_t *aux, int in, int out)
1038{ 1038{
1039 IF_DESKTOP(long long) int n; 1039 IF_DESKTOP(long long) int n;
1040 DECLARE_STATE; 1040 DECLARE_STATE;
1041 1041
1042 ALLOC_STATE; 1042 ALLOC_STATE;
1043 1043
1044 to_read = compr_size; 1044 to_read = aux->bytes_in;
1045// bytebuffer_max = 0x8000; 1045// bytebuffer_max = 0x8000;
1046 bytebuffer_offset = 4; 1046 bytebuffer_offset = 4;
1047 bytebuffer = xmalloc(bytebuffer_max); 1047 bytebuffer = xmalloc(bytebuffer_max);
1048 n = inflate_unzip_internal(PASS_STATE in, out); 1048 n = inflate_unzip_internal(PASS_STATE in, out);
1049 free(bytebuffer); 1049 free(bytebuffer);
1050 1050
1051 res->crc = gunzip_crc; 1051 aux->crc32 = gunzip_crc;
1052 res->bytes_out = gunzip_bytes_out; 1052 aux->bytes_out = gunzip_bytes_out;
1053 DEALLOC_STATE; 1053 DEALLOC_STATE;
1054 return n; 1054 return n;
1055} 1055}
@@ -1107,7 +1107,7 @@ static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY)
1107 return res; 1107 return res;
1108} 1108}
1109 1109
1110static int check_header_gzip(STATE_PARAM unpack_info_t *info) 1110static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux)
1111{ 1111{
1112 union { 1112 union {
1113 unsigned char raw[8]; 1113 unsigned char raw[8];
@@ -1169,8 +1169,8 @@ static int check_header_gzip(STATE_PARAM unpack_info_t *info)
1169 } 1169 }
1170 } 1170 }
1171 1171
1172 if (info) 1172 if (aux)
1173 info->mtime = SWAP_LE32(header.formatted.mtime); 1173 aux->mtime = SWAP_LE32(header.formatted.mtime);
1174 1174
1175 /* Read the header checksum */ 1175 /* Read the header checksum */
1176 if (header.formatted.flags & 0x02) { 1176 if (header.formatted.flags & 0x02) {
@@ -1182,33 +1182,58 @@ static int check_header_gzip(STATE_PARAM unpack_info_t *info)
1182} 1182}
1183 1183
1184IF_DESKTOP(long long) int FAST_FUNC 1184IF_DESKTOP(long long) int FAST_FUNC
1185unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) 1185unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
1186{ 1186{
1187 uint32_t v32; 1187 uint32_t v32;
1188 IF_DESKTOP(long long) int n; 1188 IF_DESKTOP(long long) int total, n;
1189 DECLARE_STATE; 1189 DECLARE_STATE;
1190 1190
1191 n = 0; 1191#if !ENABLE_FEATURE_SEAMLESS_Z
1192 if (check_signature16(aux, src_fd, GZIP_MAGIC))
1193 return -1;
1194#else
1195 if (aux && aux->check_signature) {
1196 uint16_t magic2;
1197
1198 if (full_read(src_fd, &magic2, 2) != 2) {
1199 bad_magic:
1200 bb_error_msg("invalid magic");
1201 return -1;
1202 }
1203 if (magic2 == COMPRESS_MAGIC) {
1204 aux->check_signature = 0;
1205 return unpack_Z_stream(aux, src_fd, dst_fd);
1206 }
1207 if (magic2 != GZIP_MAGIC)
1208 goto bad_magic;
1209 }
1210#endif
1211
1212 total = 0;
1192 1213
1193 ALLOC_STATE; 1214 ALLOC_STATE;
1194 to_read = -1; 1215 to_read = -1;
1195// bytebuffer_max = 0x8000; 1216// bytebuffer_max = 0x8000;
1196 bytebuffer = xmalloc(bytebuffer_max); 1217 bytebuffer = xmalloc(bytebuffer_max);
1197 gunzip_src_fd = in; 1218 gunzip_src_fd = src_fd;
1198 1219
1199 again: 1220 again:
1200 if (!check_header_gzip(PASS_STATE info)) { 1221 if (!check_header_gzip(PASS_STATE aux)) {
1201 bb_error_msg("corrupted data"); 1222 bb_error_msg("corrupted data");
1202 n = -1; 1223 total = -1;
1203 goto ret; 1224 goto ret;
1204 } 1225 }
1205 n += inflate_unzip_internal(PASS_STATE in, out); 1226
1206 if (n < 0) 1227 n = inflate_unzip_internal(PASS_STATE src_fd, dst_fd);
1228 if (n < 0) {
1229 total = -1;
1207 goto ret; 1230 goto ret;
1231 }
1232 total += n;
1208 1233
1209 if (!top_up(PASS_STATE 8)) { 1234 if (!top_up(PASS_STATE 8)) {
1210 bb_error_msg("corrupted data"); 1235 bb_error_msg("corrupted data");
1211 n = -1; 1236 total = -1;
1212 goto ret; 1237 goto ret;
1213 } 1238 }
1214 1239
@@ -1216,7 +1241,7 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info)
1216 v32 = buffer_read_le_u32(PASS_STATE_ONLY); 1241 v32 = buffer_read_le_u32(PASS_STATE_ONLY);
1217 if ((~gunzip_crc) != v32) { 1242 if ((~gunzip_crc) != v32) {
1218 bb_error_msg("crc error"); 1243 bb_error_msg("crc error");
1219 n = -1; 1244 total = -1;
1220 goto ret; 1245 goto ret;
1221 } 1246 }
1222 1247
@@ -1224,7 +1249,7 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info)
1224 v32 = buffer_read_le_u32(PASS_STATE_ONLY); 1249 v32 = buffer_read_le_u32(PASS_STATE_ONLY);
1225 if ((uint32_t)gunzip_bytes_out != v32) { 1250 if ((uint32_t)gunzip_bytes_out != v32) {
1226 bb_error_msg("incorrect length"); 1251 bb_error_msg("incorrect length");
1227 n = -1; 1252 total = -1;
1228 } 1253 }
1229 1254
1230 if (!top_up(PASS_STATE 2)) 1255 if (!top_up(PASS_STATE 2))
@@ -1242,11 +1267,5 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info)
1242 ret: 1267 ret:
1243 free(bytebuffer); 1268 free(bytebuffer);
1244 DEALLOC_STATE; 1269 DEALLOC_STATE;
1245 return n; 1270 return total;
1246}
1247
1248IF_DESKTOP(long long) int FAST_FUNC
1249unpack_gz_stream(int in, int out)
1250{
1251 return unpack_gz_stream_with_info(in, out, NULL);
1252} 1271}
diff --git a/archival/libarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c
index c6040d04b..e9bbfb9bd 100644
--- a/archival/libarchive/decompress_uncompress.c
+++ b/archival/libarchive/decompress_uncompress.c
@@ -73,7 +73,7 @@
73 */ 73 */
74 74
75IF_DESKTOP(long long) int FAST_FUNC 75IF_DESKTOP(long long) int FAST_FUNC
76unpack_Z_stream(int fd_in, int fd_out) 76unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
77{ 77{
78 IF_DESKTOP(long long total_written = 0;) 78 IF_DESKTOP(long long total_written = 0;)
79 IF_DESKTOP(long long) int retval = -1; 79 IF_DESKTOP(long long) int retval = -1;
@@ -103,16 +103,19 @@ unpack_Z_stream(int fd_in, int fd_out)
103 /* block compress mode -C compatible with 2.0 */ 103 /* block compress mode -C compatible with 2.0 */
104 int block_mode; /* = BLOCK_MODE; */ 104 int block_mode; /* = BLOCK_MODE; */
105 105
106 if (check_signature16(aux, src_fd, COMPRESS_MAGIC))
107 return -1;
108
106 inbuf = xzalloc(IBUFSIZ + 64); 109 inbuf = xzalloc(IBUFSIZ + 64);
107 outbuf = xzalloc(OBUFSIZ + 2048); 110 outbuf = xzalloc(OBUFSIZ + 2048);
108 htab = xzalloc(HSIZE); /* wsn't zeroed out before, maybe can xmalloc? */ 111 htab = xzalloc(HSIZE); /* wasn't zeroed out before, maybe can xmalloc? */
109 codetab = xzalloc(HSIZE * sizeof(codetab[0])); 112 codetab = xzalloc(HSIZE * sizeof(codetab[0]));
110 113
111 insize = 0; 114 insize = 0;
112 115
113 /* xread isn't good here, we have to return - caller may want 116 /* xread isn't good here, we have to return - caller may want
114 * to do some cleanup (e.g. delete incomplete unpacked file etc) */ 117 * to do some cleanup (e.g. delete incomplete unpacked file etc) */
115 if (full_read(fd_in, inbuf, 1) != 1) { 118 if (full_read(src_fd, inbuf, 1) != 1) {
116 bb_error_msg("short read"); 119 bb_error_msg("short read");
117 goto err; 120 goto err;
118 } 121 }
@@ -162,7 +165,7 @@ unpack_Z_stream(int fd_in, int fd_out)
162 } 165 }
163 166
164 if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { 167 if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) {
165 rsize = safe_read(fd_in, inbuf + insize, IBUFSIZ); 168 rsize = safe_read(src_fd, inbuf + insize, IBUFSIZ);
166 if (rsize < 0) 169 if (rsize < 0)
167 bb_error_msg_and_die(bb_msg_read_error); 170 bb_error_msg_and_die(bb_msg_read_error);
168 insize += rsize; 171 insize += rsize;
@@ -268,7 +271,7 @@ unpack_Z_stream(int fd_in, int fd_out)
268 } 271 }
269 272
270 if (outpos >= OBUFSIZ) { 273 if (outpos >= OBUFSIZ) {
271 xwrite(fd_out, outbuf, outpos); 274 xwrite(dst_fd, outbuf, outpos);
272 IF_DESKTOP(total_written += outpos;) 275 IF_DESKTOP(total_written += outpos;)
273 outpos = 0; 276 outpos = 0;
274 } 277 }
@@ -296,7 +299,7 @@ unpack_Z_stream(int fd_in, int fd_out)
296 } while (rsize > 0); 299 } while (rsize > 0);
297 300
298 if (outpos > 0) { 301 if (outpos > 0) {
299 xwrite(fd_out, outbuf, outpos); 302 xwrite(dst_fd, outbuf, outpos);
300 IF_DESKTOP(total_written += outpos;) 303 IF_DESKTOP(total_written += outpos;)
301 } 304 }
302 305
diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c
index 3631b50cc..cfde8ea56 100644
--- a/archival/libarchive/decompress_unlzma.c
+++ b/archival/libarchive/decompress_unlzma.c
@@ -213,7 +213,7 @@ enum {
213 213
214 214
215IF_DESKTOP(long long) int FAST_FUNC 215IF_DESKTOP(long long) int FAST_FUNC
216unpack_lzma_stream(int src_fd, int dst_fd) 216unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst_fd)
217{ 217{
218 IF_DESKTOP(long long total_written = 0;) 218 IF_DESKTOP(long long total_written = 0;)
219 lzma_header_t header; 219 lzma_header_t header;
diff --git a/archival/libarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
index 3e5d4edca..79b48a152 100644
--- a/archival/libarchive/decompress_unxz.c
+++ b/archival/libarchive/decompress_unxz.c
@@ -38,7 +38,7 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
38#include "unxz/xz_dec_stream.c" 38#include "unxz/xz_dec_stream.c"
39 39
40IF_DESKTOP(long long) int FAST_FUNC 40IF_DESKTOP(long long) int FAST_FUNC
41unpack_xz_stream(int src_fd, int dst_fd) 41unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd)
42{ 42{
43 struct xz_buf iobuf; 43 struct xz_buf iobuf;
44 struct xz_dec *state; 44 struct xz_dec *state;
@@ -49,13 +49,17 @@ unpack_xz_stream(int src_fd, int dst_fd)
49 global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0); 49 global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0);
50 50
51 memset(&iobuf, 0, sizeof(iobuf)); 51 memset(&iobuf, 0, sizeof(iobuf));
52 /* Preload XZ file signature */ 52 membuf = xmalloc(2 * BUFSIZ);
53 membuf = (void*) strcpy(xmalloc(2 * BUFSIZ), HEADER_MAGIC);
54 iobuf.in = membuf; 53 iobuf.in = membuf;
55 iobuf.in_size = HEADER_MAGIC_SIZE;
56 iobuf.out = membuf + BUFSIZ; 54 iobuf.out = membuf + BUFSIZ;
57 iobuf.out_size = BUFSIZ; 55 iobuf.out_size = BUFSIZ;
58 56
57 if (!aux || aux->check_signature == 0) {
58 /* Preload XZ file signature */
59 strcpy((char*)membuf, HEADER_MAGIC);
60 iobuf.in_size = HEADER_MAGIC_SIZE;
61 } /* else: let xz code read & check it */
62
59 /* Limit memory usage to about 64 MiB. */ 63 /* Limit memory usage to about 64 MiB. */
60 state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); 64 state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024);
61 65
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index a63c0fb01..80a709144 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -90,23 +90,20 @@ static unsigned long long getOctal(char *str, int len)
90} 90}
91#define GET_OCTAL(a) getOctal((a), sizeof(a)) 91#define GET_OCTAL(a) getOctal((a), sizeof(a))
92 92
93#if ENABLE_FEATURE_TAR_SELINUX 93/* "global" is 0 or 1 */
94/* Scan a PAX header for SELinux contexts, via "RHT.security.selinux" keyword. 94static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global)
95 * This is what Red Hat's patched version of tar uses.
96 */
97# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
98static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, unsigned sz)
99{ 95{
100 char *buf, *p; 96 char *buf, *p;
101 char *result; 97 unsigned blk_sz;
98
99 blk_sz = (sz + 511) & (~511);
100 p = buf = xmalloc(blk_sz + 1);
101 xread(archive_handle->src_fd, buf, blk_sz);
102 archive_handle->offset += blk_sz;
102 103
103 p = buf = xmalloc(sz + 1);
104 /* prevent bb_strtou from running off the buffer */ 104 /* prevent bb_strtou from running off the buffer */
105 buf[sz] = '\0'; 105 buf[sz] = '\0';
106 xread(archive_handle->src_fd, buf, sz);
107 archive_handle->offset += sz;
108 106
109 result = NULL;
110 while (sz != 0) { 107 while (sz != 0) {
111 char *end, *value; 108 char *end, *value;
112 unsigned len; 109 unsigned len;
@@ -133,19 +130,33 @@ static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, uns
133 * (we do not bother to check that it *was* a newline) 130 * (we do not bother to check that it *was* a newline)
134 */ 131 */
135 p[-1] = '\0'; 132 p[-1] = '\0';
136 /* Is it selinux security context? */
137 value = end + 1; 133 value = end + 1;
134
135#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
136 if (!global && strncmp(value, "path=", sizeof("path=") - 1) == 0) {
137 value += sizeof("path=") - 1;
138 free(archive_handle->tar__longname);
139 archive_handle->tar__longname = xstrdup(value);
140 continue;
141 }
142#endif
143
144#if ENABLE_FEATURE_TAR_SELINUX
145 /* Scan for SELinux contexts, via "RHT.security.selinux" keyword.
146 * This is what Red Hat's patched version of tar uses.
147 */
148# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
138 if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) { 149 if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) {
139 value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1; 150 value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1;
140 result = xstrdup(value); 151 free(archive_handle->tar__sctx[global]);
141 break; 152 archive_handle->tar__sctx[global] = xstrdup(value);
153 continue;
142 } 154 }
155#endif
143 } 156 }
144 157
145 free(buf); 158 free(buf);
146 return result;
147} 159}
148#endif
149 160
150char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) 161char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
151{ 162{
@@ -224,43 +235,18 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
224 || memcmp(tar.magic, "\0\0\0\0", 5) != 0) 235 || memcmp(tar.magic, "\0\0\0\0", 5) != 0)
225 ) { 236 ) {
226#if ENABLE_FEATURE_TAR_AUTODETECT 237#if ENABLE_FEATURE_TAR_AUTODETECT
227 char FAST_FUNC (*get_header_ptr)(archive_handle_t *);
228 uint16_t magic2;
229
230 autodetect: 238 autodetect:
231 magic2 = *(bb__aliased_uint16_t*)tar.name;
232 /* tar gz/bz autodetect: check for gz/bz2 magic.
233 * If we see the magic, and it is the very first block,
234 * we can switch to get_header_tar_gz/bz2/lzma().
235 * Needs seekable fd. I wish recv(MSG_PEEK) works
236 * on any fd... */
237# if ENABLE_FEATURE_SEAMLESS_GZ
238 if (magic2 == GZIP_MAGIC) {
239 get_header_ptr = get_header_tar_gz;
240 } else
241# endif
242# if ENABLE_FEATURE_SEAMLESS_BZ2
243 if (magic2 == BZIP2_MAGIC
244 && tar.name[2] == 'h' && isdigit(tar.name[3])
245 ) { /* bzip2 */
246 get_header_ptr = get_header_tar_bz2;
247 } else
248# endif
249# if ENABLE_FEATURE_SEAMLESS_XZ
250 //TODO: if (magic2 == XZ_MAGIC1)...
251 //else
252# endif
253 goto err;
254 /* Two different causes for lseek() != 0: 239 /* Two different causes for lseek() != 0:
255 * unseekable fd (would like to support that too, but...), 240 * unseekable fd (would like to support that too, but...),
256 * or not first block (false positive, it's not .gz/.bz2!) */ 241 * or not first block (false positive, it's not .gz/.bz2!) */
257 if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0) 242 if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0)
258 goto err; 243 goto err;
259 while (get_header_ptr(archive_handle) == EXIT_SUCCESS) 244 if (setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 0) != 0)
260 continue;
261 return EXIT_FAILURE;
262 err: 245 err:
263#endif /* FEATURE_TAR_AUTODETECT */ 246 bb_error_msg_and_die("invalid tar magic");
247 archive_handle->offset = 0;
248 goto again_after_align;
249#endif
264 bb_error_msg_and_die("invalid tar magic"); 250 bb_error_msg_and_die("invalid tar magic");
265 } 251 }
266 252
@@ -418,12 +404,14 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
418 case 'S': /* Sparse file */ 404 case 'S': /* Sparse file */
419 case 'V': /* Volume header */ 405 case 'V': /* Volume header */
420#endif 406#endif
421#if !ENABLE_FEATURE_TAR_SELINUX
422 case 'g': /* pax global header */ 407 case 'g': /* pax global header */
423 case 'x': /* pax extended header */ 408 case 'x': { /* pax extended header */
424#else 409 if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
410 goto skip_ext_hdr;
411 process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g'));
412 goto again_after_align;
413 }
425 skip_ext_hdr: 414 skip_ext_hdr:
426#endif
427 { 415 {
428 off_t sz; 416 off_t sz;
429 bb_error_msg("warning: skipping header '%c'", tar.typeflag); 417 bb_error_msg("warning: skipping header '%c'", tar.typeflag);
@@ -435,18 +423,6 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
435 /* return get_header_tar(archive_handle); */ 423 /* return get_header_tar(archive_handle); */
436 goto again_after_align; 424 goto again_after_align;
437 } 425 }
438#if ENABLE_FEATURE_TAR_SELINUX
439 case 'g': /* pax global header */
440 case 'x': { /* pax extended header */
441 char **pp;
442 if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
443 goto skip_ext_hdr;
444 pp = (tar.typeflag == 'g') ? &archive_handle->tar__global_sctx : &archive_handle->tar__next_file_sctx;
445 free(*pp);
446 *pp = get_selinux_sctx_from_pax_hdr(archive_handle, file_header->size);
447 goto again;
448 }
449#endif
450 default: 426 default:
451 bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); 427 bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag);
452 } 428 }
diff --git a/archival/libarchive/get_header_tar_bz2.c b/archival/libarchive/get_header_tar_bz2.c
index e012dec3b..0ee00df53 100644
--- a/archival/libarchive/get_header_tar_bz2.c
+++ b/archival/libarchive/get_header_tar_bz2.c
@@ -11,7 +11,7 @@ char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle)
11 /* Can't lseek over pipes */ 11 /* Can't lseek over pipes */
12 archive_handle->seek = seek_by_read; 12 archive_handle->seek = seek_by_read;
13 13
14 open_transformer(archive_handle->src_fd, unpack_bz2_stream_prime, "bunzip2"); 14 open_transformer_with_sig(archive_handle->src_fd, unpack_bz2_stream, "bunzip2");
15 archive_handle->offset = 0; 15 archive_handle->offset = 0;
16 while (get_header_tar(archive_handle) == EXIT_SUCCESS) 16 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
17 continue; 17 continue;
diff --git a/archival/libarchive/get_header_tar_gz.c b/archival/libarchive/get_header_tar_gz.c
index b9679b0bd..03284342b 100644
--- a/archival/libarchive/get_header_tar_gz.c
+++ b/archival/libarchive/get_header_tar_gz.c
@@ -8,25 +8,10 @@
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{
11#if BB_MMU
12 uint16_t magic;
13#endif
14
15 /* Can't lseek over pipes */ 11 /* Can't lseek over pipes */
16 archive_handle->seek = seek_by_read; 12 archive_handle->seek = seek_by_read;
17 13
18 /* Check gzip magic only if open_transformer will invoke unpack_gz_stream (MMU case). 14 open_transformer_with_sig(archive_handle->src_fd, unpack_gz_stream, "gunzip");
19 * Otherwise, it will invoke an external helper "gunzip -cf" (NOMMU case) which will
20 * need the header. */
21#if BB_MMU
22 xread(archive_handle->src_fd, &magic, 2);
23 /* Can skip this check, but error message will be less clear */
24 if (magic != GZIP_MAGIC) {
25 bb_error_msg_and_die("invalid gzip magic");
26 }
27#endif
28
29 open_transformer(archive_handle->src_fd, unpack_gz_stream, "gunzip");
30 archive_handle->offset = 0; 15 archive_handle->offset = 0;
31 while (get_header_tar(archive_handle) == EXIT_SUCCESS) 16 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
32 continue; 17 continue;
diff --git a/archival/libarchive/get_header_tar_lzma.c b/archival/libarchive/get_header_tar_lzma.c
index 666700729..d565a217d 100644
--- a/archival/libarchive/get_header_tar_lzma.c
+++ b/archival/libarchive/get_header_tar_lzma.c
@@ -14,7 +14,7 @@ char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle)
14 /* Can't lseek over pipes */ 14 /* Can't lseek over pipes */
15 archive_handle->seek = seek_by_read; 15 archive_handle->seek = seek_by_read;
16 16
17 open_transformer(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); 17 open_transformer_with_sig(archive_handle->src_fd, unpack_lzma_stream, "unlzma");
18 archive_handle->offset = 0; 18 archive_handle->offset = 0;
19 while (get_header_tar(archive_handle) == EXIT_SUCCESS) 19 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
20 continue; 20 continue;
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index aa8c1021c..f2edc2a2b 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -6,14 +6,64 @@
6#include "libbb.h" 6#include "libbb.h"
7#include "bb_archive.h" 7#include "bb_archive.h"
8 8
9void FAST_FUNC init_transformer_aux_data(transformer_aux_data_t *aux)
10{
11 memset(aux, 0, sizeof(*aux));
12}
13
14int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16)
15{
16 if (aux && aux->check_signature) {
17 uint16_t magic2;
18 if (full_read(src_fd, &magic2, 2) != 2 || magic2 != magic16) {
19 bb_error_msg("invalid magic");
20#if 0 /* possible future extension */
21 if (aux->check_signature > 1)
22 xfunc_die();
23#endif
24 return -1;
25 }
26 }
27 return 0;
28}
29
30#if !ENABLE_PLATFORM_MINGW32
31void check_errors_in_children(int signo)
32{
33 int status;
34
35 if (!signo) {
36 /* block waiting for any child */
37 if (wait(&status) < 0)
38 return; /* probably there are no children */
39 goto check_status;
40 }
41
42 /* Wait for any child without blocking */
43 for (;;) {
44 if (wait_any_nohang(&status) < 0)
45 /* wait failed?! I'm confused... */
46 return;
47 check_status:
48 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
49 /* this child exited with 0 */
50 continue;
51 /* Cannot happen?
52 if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; */
53 bb_got_signal = 1;
54 }
55}
56#endif
57
9/* transformer(), more than meets the eye */ 58/* transformer(), more than meets the eye */
10/* 59#if BB_MMU
11 * On MMU machine, the transform_prog is removed by macro magic
12 * in include/archive.h. On NOMMU, transformer is removed.
13 */
14void FAST_FUNC open_transformer(int fd, 60void FAST_FUNC open_transformer(int fd,
15 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd), 61 int check_signature,
16 const char *transform_prog) 62 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd)
63)
64#else
65void FAST_FUNC open_transformer(int fd, const char *transform_prog)
66#endif
17{ 67{
18 struct fd_pair fd_pipe; 68 struct fd_pair fd_pipe;
19 int pid; 69 int pid;
@@ -25,13 +75,18 @@ void FAST_FUNC open_transformer(int fd,
25 close(fd_pipe.rd); /* we don't want to read from the parent */ 75 close(fd_pipe.rd); /* we don't want to read from the parent */
26 // FIXME: error check? 76 // FIXME: error check?
27#if BB_MMU 77#if BB_MMU
28 transformer(fd, fd_pipe.wr); 78 {
29 if (ENABLE_FEATURE_CLEAN_UP) { 79 transformer_aux_data_t aux;
30 close(fd_pipe.wr); /* send EOF */ 80 init_transformer_aux_data(&aux);
31 close(fd); 81 aux.check_signature = check_signature;
82 transformer(&aux, fd, fd_pipe.wr);
83 if (ENABLE_FEATURE_CLEAN_UP) {
84 close(fd_pipe.wr); /* send EOF */
85 close(fd);
86 }
87 /* must be _exit! bug was actually seen here */
88 _exit(EXIT_SUCCESS);
32 } 89 }
33 /* must be _exit! bug was actually seen here */
34 _exit(EXIT_SUCCESS);
35#else 90#else
36 { 91 {
37 char *argv[4]; 92 char *argv[4];
@@ -52,3 +107,117 @@ void FAST_FUNC open_transformer(int fd,
52 close(fd_pipe.wr); /* don't want to write to the child */ 107 close(fd_pipe.wr); /* don't want to write to the child */
53 xmove_fd(fd_pipe.rd, fd); 108 xmove_fd(fd_pipe.rd, fd);
54} 109}
110
111
112#if SEAMLESS_COMPRESSION
113
114/* Used by e.g. rpm which gives us a fd without filename,
115 * thus we can't guess the format from filename's extension.
116 */
117int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_detected)
118{
119 union {
120 uint8_t b[4];
121 uint16_t b16[2];
122 uint32_t b32[1];
123 } magic;
124 int offset = -2;
125 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);)
126 USE_FOR_NOMMU(const char *xformer_prog;)
127
128 /* .gz and .bz2 both have 2-byte signature, and their
129 * unpack_XXX_stream wants this header skipped. */
130 xread(fd, magic.b16, sizeof(magic.b16[0]));
131 if (ENABLE_FEATURE_SEAMLESS_GZ
132 && magic.b16[0] == GZIP_MAGIC
133 ) {
134 USE_FOR_MMU(xformer = unpack_gz_stream;)
135 USE_FOR_NOMMU(xformer_prog = "gunzip";)
136 goto found_magic;
137 }
138 if (ENABLE_FEATURE_SEAMLESS_BZ2
139 && magic.b16[0] == BZIP2_MAGIC
140 ) {
141 USE_FOR_MMU(xformer = unpack_bz2_stream;)
142 USE_FOR_NOMMU(xformer_prog = "bunzip2";)
143 goto found_magic;
144 }
145 if (ENABLE_FEATURE_SEAMLESS_XZ
146 && magic.b16[0] == XZ_MAGIC1
147 ) {
148 offset = -6;
149 xread(fd, magic.b32, sizeof(magic.b32[0]));
150 if (magic.b32[0] == XZ_MAGIC2) {
151 USE_FOR_MMU(xformer = unpack_xz_stream;)
152 USE_FOR_NOMMU(xformer_prog = "unxz";)
153 goto found_magic;
154 }
155 }
156
157 /* No known magic seen */
158 if (fail_if_not_detected)
159 bb_error_msg_and_die("no gzip"
160 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
161 IF_FEATURE_SEAMLESS_XZ("/xz")
162 " magic");
163 xlseek(fd, offset, SEEK_CUR);
164 return 1;
165
166 found_magic:
167# if BB_MMU
168 open_transformer_with_no_sig(fd, xformer);
169# else
170 /* NOMMU version of open_transformer execs
171 * an external unzipper that wants
172 * file position at the start of the file */
173 xlseek(fd, offset, SEEK_CUR);
174 open_transformer_with_sig(fd, xformer, xformer_prog);
175# endif
176 return 0;
177}
178
179int FAST_FUNC open_zipped(const char *fname)
180{
181 char *sfx;
182 int fd;
183
184 fd = open(fname, O_RDONLY);
185 if (fd < 0)
186 return fd;
187
188 sfx = strrchr(fname, '.');
189 if (sfx) {
190 sfx++;
191 if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0)
192 /* .lzma has no header/signature, just trust it */
193 open_transformer_with_sig(fd, unpack_lzma_stream, "unlzma");
194 else
195 if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0)
196 || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0)
197 || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0)
198 ) {
199 setup_unzip_on_fd(fd, /*fail_if_not_detected:*/ 1);
200 }
201 }
202
203 return fd;
204}
205
206#endif /* SEAMLESS_COMPRESSION */
207
208void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
209{
210 int fd;
211 char *image;
212
213 fd = open_zipped(fname);
214 if (fd < 0)
215 return NULL;
216
217 image = xmalloc_read(fd, maxsz_p);
218 if (!image)
219 bb_perror_msg("read error from '%s'", fname);
220 close(fd);
221
222 return image;
223}
diff --git a/archival/lzop.c b/archival/lzop.c
index 7e30091d9..fbe08417d 100644
--- a/archival/lzop.c
+++ b/archival/lzop.c
@@ -201,7 +201,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len,
201 /* remove short run */ 201 /* remove short run */
202 *litp &= ~3; 202 *litp &= ~3;
203 /* copy over the 2 literals that replace the match */ 203 /* copy over the 2 literals that replace the match */
204 copy2(ip-3+1,m_pos,pd(op,m_pos)); 204 copy2(ip-3+1, m_pos, pd(op, m_pos));
205 /* move literals 1 byte ahead */ 205 /* move literals 1 byte ahead */
206 litp += 2; 206 litp += 2;
207 if (lit > 0) 207 if (lit > 0)
@@ -211,7 +211,8 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len,
211 *litp = (unsigned char)(lit - 3); 211 *litp = (unsigned char)(lit - 3);
212 212
213 o_m1_b++; 213 o_m1_b++;
214 *op++ = *m_pos++; *op++ = *m_pos++; 214 *op++ = *m_pos++;
215 *op++ = *m_pos++;
215 goto copy_literal_run; 216 goto copy_literal_run;
216 } 217 }
217 copy_m1: 218 copy_m1:
@@ -240,7 +241,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len,
240 ) { 241 ) {
241 t = *ip++; 242 t = *ip++;
242 /* copy over the 3 literals that replace the match */ 243 /* copy over the 3 literals that replace the match */
243 copy3(ip-1-2,m_pos,pd(op,m_pos)); 244 copy3(ip-1-2, m_pos, pd(op, m_pos));
244 /* set new length of previous literal run */ 245 /* set new length of previous literal run */
245 lit += 3 + t + 3; 246 lit += 3 + t + 3;
246 *litp = (unsigned char)(lit - 3); 247 *litp = (unsigned char)(lit - 3);
@@ -289,7 +290,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len,
289 lit += 3; 290 lit += 3;
290 *litp = (unsigned char)((*litp & ~3) | lit); 291 *litp = (unsigned char)((*litp & ~3) | lit);
291 /* copy over the 3 literals that replace the match */ 292 /* copy over the 3 literals that replace the match */
292 copy3(ip-3,m_pos,pd(op,m_pos)); 293 copy3(ip-3, m_pos, pd(op, m_pos));
293 o_m3_a++; 294 o_m3_a++;
294 } 295 }
295 /* test if a literal run follows */ 296 /* test if a literal run follows */
@@ -300,7 +301,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len,
300 /* remove short run */ 301 /* remove short run */
301 *litp &= ~3; 302 *litp &= ~3;
302 /* copy over the 3 literals that replace the match */ 303 /* copy over the 3 literals that replace the match */
303 copy3(ip-4+1,m_pos,pd(op,m_pos)); 304 copy3(ip-4+1, m_pos, pd(op, m_pos));
304 /* move literals 1 byte ahead */ 305 /* move literals 1 byte ahead */
305 litp += 2; 306 litp += 2;
306 if (lit > 0) 307 if (lit > 0)
@@ -1076,7 +1077,7 @@ static char* FAST_FUNC make_new_name_lzop(char *filename, const char *expected_e
1076 return xasprintf("%s.lzo", filename); 1077 return xasprintf("%s.lzo", filename);
1077} 1078}
1078 1079
1079static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(unpack_info_t *info UNUSED_PARAM) 1080static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_aux_data_t *aux UNUSED_PARAM)
1080{ 1081{
1081 if (option_mask32 & OPT_DECOMPRESS) 1082 if (option_mask32 & OPT_DECOMPRESS)
1082 return do_lzo_decompress(); 1083 return do_lzo_decompress();
diff --git a/archival/rpm.c b/archival/rpm.c
index 089b68983..6757a6ceb 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -236,7 +236,7 @@ static void extract_cpio(int fd, const char *source_rpm)
236 archive_handle->src_fd = fd; 236 archive_handle->src_fd = fd;
237 /*archive_handle->offset = 0; - init_handle() did it */ 237 /*archive_handle->offset = 0; - init_handle() did it */
238 238
239 setup_unzip_on_fd(archive_handle->src_fd /*, fail_if_not_detected: 1*/); 239 setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 1);
240 while (get_header_cpio(archive_handle) == EXIT_SUCCESS) 240 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
241 continue; 241 continue;
242} 242}
diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c
index 28b43a181..898d4aca4 100644
--- a/archival/rpm2cpio.c
+++ b/archival/rpm2cpio.c
@@ -66,54 +66,24 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
66 /* Skip the main header */ 66 /* Skip the main header */
67 skip_header(); 67 skip_header();
68 68
69#if 0 69 //if (SEAMLESS_COMPRESSION)
70 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */
71 // signal(SIGCHLD, check_errors_in_children);
72
70 /* This works, but doesn't report uncompress errors (they happen in child) */ 73 /* This works, but doesn't report uncompress errors (they happen in child) */
71 setup_unzip_on_fd(rpm_fd /*fail_if_not_detected: 1*/); 74 setup_unzip_on_fd(rpm_fd, /*fail_if_not_detected:*/ 1);
72 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) 75 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
73 bb_error_msg_and_die("error unpacking"); 76 bb_error_msg_and_die("error unpacking");
74#else
75 /* BLOAT */
76 {
77 union {
78 uint8_t b[4];
79 uint16_t b16[2];
80 uint32_t b32[1];
81 } magic;
82 IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd);
83
84 xread(rpm_fd, magic.b16, sizeof(magic.b16[0]));
85 if (magic.b16[0] == GZIP_MAGIC) {
86 unpack = unpack_gz_stream;
87 } else
88 if (ENABLE_FEATURE_SEAMLESS_BZ2
89 && magic.b16[0] == BZIP2_MAGIC
90 ) {
91 unpack = unpack_bz2_stream;
92 } else
93 if (ENABLE_FEATURE_SEAMLESS_XZ
94 && magic.b16[0] == XZ_MAGIC1
95 ) {
96 xread(rpm_fd, magic.b32, sizeof(magic.b32[0]));
97 if (magic.b32[0] != XZ_MAGIC2)
98 goto no_magic;
99 /* unpack_xz_stream wants fd at position 6, no need to seek */
100 //xlseek(rpm_fd, -6, SEEK_CUR);
101 unpack = unpack_xz_stream;
102 } else {
103 no_magic:
104 bb_error_msg_and_die("no gzip"
105 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
106 IF_FEATURE_SEAMLESS_XZ("/xz")
107 " magic");
108 }
109 if (unpack(rpm_fd, STDOUT_FILENO) < 0)
110 bb_error_msg_and_die("error unpacking");
111 }
112#endif
113 77
114 if (ENABLE_FEATURE_CLEAN_UP) { 78 if (ENABLE_FEATURE_CLEAN_UP) {
115 close(rpm_fd); 79 close(rpm_fd);
116 } 80 }
117 81
118 return 0; 82#if !ENABLE_PLATFORM_MINGW32
83 if (SEAMLESS_COMPRESSION) {
84 check_errors_in_children(0);
85 return bb_got_signal;
86 }
87#endif
88 return EXIT_SUCCESS;
119} 89}
diff --git a/archival/tar.c b/archival/tar.c
index 2b752f640..fcd128a91 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -692,54 +692,6 @@ static llist_t *append_file_list_to_list(llist_t *list)
692# define append_file_list_to_list(x) 0 692# define append_file_list_to_list(x) 0
693#endif 693#endif
694 694
695#if ENABLE_FEATURE_SEAMLESS_Z
696static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle)
697{
698 /* Can't lseek over pipes */
699 archive_handle->seek = seek_by_read;
700
701 /* do the decompression, and cleanup */
702 if (xread_char(archive_handle->src_fd) != 0x1f
703 || xread_char(archive_handle->src_fd) != 0x9d
704 ) {
705 bb_error_msg_and_die("invalid magic");
706 }
707
708 open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress");
709 archive_handle->offset = 0;
710 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
711 continue;
712
713 /* Can only do one file at a time */
714 return EXIT_FAILURE;
715}
716#else
717# define get_header_tar_Z NULL
718#endif
719
720#ifdef CHECK_FOR_CHILD_EXITCODE
721/* Looks like it isn't needed - tar detects malformed (truncated)
722 * archive if e.g. bunzip2 fails */
723static int child_error;
724
725static void handle_SIGCHLD(int status)
726{
727 /* Actually, 'status' is a signo. We reuse it for other needs */
728
729 /* Wait for any child without blocking */
730 if (wait_any_nohang(&status) < 0)
731 /* wait failed?! I'm confused... */
732 return;
733
734 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
735 /* child exited with 0 */
736 return;
737 /* Cannot happen?
738 if (!WIFSIGNALED(status) && !WIFEXITED(status)) return; */
739 child_error = 1;
740}
741#endif
742
743//usage:#define tar_trivial_usage 695//usage:#define tar_trivial_usage
744//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" 696//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt"
745//usage: IF_FEATURE_SEAMLESS_Z("Z") 697//usage: IF_FEATURE_SEAMLESS_Z("Z")
@@ -845,6 +797,8 @@ enum {
845 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner 797 OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner
846 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions 798 OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions
847 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite 799 OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite
800
801 OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_COMPRESS),
848}; 802};
849#if ENABLE_FEATURE_TAR_LONG_OPTIONS 803#if ENABLE_FEATURE_TAR_LONG_OPTIONS
850static const char tar_longopts[] ALIGN1 = 804static const char tar_longopts[] ALIGN1 =
@@ -903,7 +857,6 @@ static const char tar_longopts[] ALIGN1 =
903int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 857int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
904int tar_main(int argc UNUSED_PARAM, char **argv) 858int tar_main(int argc UNUSED_PARAM, char **argv)
905{ 859{
906 char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar;
907 archive_handle_t *tar_handle; 860 archive_handle_t *tar_handle;
908 char *base_dir = NULL; 861 char *base_dir = NULL;
909 const char *tar_filename = "-"; 862 const char *tar_filename = "-";
@@ -1019,18 +972,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1019 tar_handle->ah_flags |= ARCHIVE_O_TRUNC; 972 tar_handle->ah_flags |= ARCHIVE_O_TRUNC;
1020 } 973 }
1021 974
1022 if (opt & OPT_GZIP)
1023 get_header_ptr = get_header_tar_gz;
1024
1025 if (opt & OPT_BZIP2)
1026 get_header_ptr = get_header_tar_bz2;
1027
1028 if (opt & OPT_LZMA)
1029 get_header_ptr = get_header_tar_lzma;
1030
1031 if (opt & OPT_COMPRESS)
1032 get_header_ptr = get_header_tar_Z;
1033
1034 if (opt & OPT_NOPRESERVE_TIME) 975 if (opt & OPT_NOPRESERVE_TIME)
1035 tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE; 976 tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE;
1036 977
@@ -1083,7 +1024,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1083 } else { 1024 } else {
1084 if (ENABLE_FEATURE_TAR_AUTODETECT 1025 if (ENABLE_FEATURE_TAR_AUTODETECT
1085 && flags == O_RDONLY 1026 && flags == O_RDONLY
1086 && get_header_ptr == get_header_tar 1027 && !(opt & OPT_ANY_COMPRESS)
1087 ) { 1028 ) {
1088 tar_handle->src_fd = open_zipped(tar_filename); 1029 tar_handle->src_fd = open_zipped(tar_filename);
1089 if (tar_handle->src_fd < 0) 1030 if (tar_handle->src_fd < 0)
@@ -1097,10 +1038,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1097 if (base_dir) 1038 if (base_dir)
1098 xchdir(base_dir); 1039 xchdir(base_dir);
1099 1040
1100#ifdef CHECK_FOR_CHILD_EXITCODE 1041 //if (SEAMLESS_COMPRESSION || OPT_COMPRESS)
1101 /* We need to know whether child (gzip/bzip/etc) exits abnormally */ 1042 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */
1102 signal(SIGCHLD, handle_SIGCHLD); 1043 // signal(SIGCHLD, check_errors_in_children);
1103#endif
1104 1044
1105 /* Create an archive */ 1045 /* Create an archive */
1106 if (opt & OPT_CREATE) { 1046 if (opt & OPT_CREATE) {
@@ -1117,7 +1057,30 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1117 tar_handle->reject, zipMode); 1057 tar_handle->reject, zipMode);
1118 } 1058 }
1119 1059
1120 while (get_header_ptr(tar_handle) == EXIT_SUCCESS) 1060 if (opt & OPT_ANY_COMPRESS) {
1061 USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);)
1062 USE_FOR_NOMMU(const char *xformer_prog;)
1063
1064 if (opt & OPT_COMPRESS)
1065 USE_FOR_MMU(xformer = unpack_Z_stream;)
1066 USE_FOR_NOMMU(xformer_prog = "uncompress";)
1067 if (opt & OPT_GZIP)
1068 USE_FOR_MMU(xformer = unpack_gz_stream;)
1069 USE_FOR_NOMMU(xformer_prog = "gunzip";)
1070 if (opt & OPT_BZIP2)
1071 USE_FOR_MMU(xformer = unpack_bz2_stream;)
1072 USE_FOR_NOMMU(xformer_prog = "bunzip2";)
1073 if (opt & OPT_LZMA)
1074 USE_FOR_MMU(xformer = unpack_lzma_stream;)
1075 USE_FOR_NOMMU(xformer_prog = "unlzma";)
1076
1077 open_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog);
1078 /* Can't lseek over pipes */
1079 tar_handle->seek = seek_by_read;
1080 /*tar_handle->offset = 0; - already is */
1081 }
1082
1083 while (get_header_tar(tar_handle) == EXIT_SUCCESS)
1121 continue; 1084 continue;
1122 1085
1123 /* Check that every file that should have been extracted was */ 1086 /* Check that every file that should have been extracted was */
@@ -1133,5 +1096,11 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1133 if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */) 1096 if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */)
1134 close(tar_handle->src_fd); 1097 close(tar_handle->src_fd);
1135 1098
1099#if !ENABLE_PLATFORM_MINGW32
1100 if (SEAMLESS_COMPRESSION || OPT_COMPRESS) {
1101 check_errors_in_children(0);
1102 return bb_got_signal;
1103 }
1104#endif
1136 return EXIT_SUCCESS; 1105 return EXIT_SUCCESS;
1137} 1106}
diff --git a/archival/unzip.c b/archival/unzip.c
index 3a11f78a5..3c76cdafc 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -249,15 +249,17 @@ static void unzip_extract(zip_header_t *zip_header, int dst_fd)
249 bb_copyfd_exact_size(zip_fd, dst_fd, size); 249 bb_copyfd_exact_size(zip_fd, dst_fd, size);
250 } else { 250 } else {
251 /* Method 8 - inflate */ 251 /* Method 8 - inflate */
252 inflate_unzip_result res; 252 transformer_aux_data_t aux;
253 if (inflate_unzip(&res, zip_header->formatted.cmpsize, zip_fd, dst_fd) < 0) 253 init_transformer_aux_data(&aux);
254 aux.bytes_in = zip_header->formatted.cmpsize;
255 if (inflate_unzip(&aux, zip_fd, dst_fd) < 0)
254 bb_error_msg_and_die("inflate error"); 256 bb_error_msg_and_die("inflate error");
255 /* Validate decompression - crc */ 257 /* Validate decompression - crc */
256 if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) { 258 if (zip_header->formatted.crc32 != (aux.crc32 ^ 0xffffffffL)) {
257 bb_error_msg_and_die("crc error"); 259 bb_error_msg_and_die("crc error");
258 } 260 }
259 /* Validate decompression - size */ 261 /* Validate decompression - size */
260 if (zip_header->formatted.ucmpsize != res.bytes_out) { 262 if (zip_header->formatted.ucmpsize != aux.bytes_out) {
261 /* Don't die. Who knows, maybe len calculation 263 /* Don't die. Who knows, maybe len calculation
262 * was botched somewhere. After all, crc matched! */ 264 * was botched somewhere. After all, crc matched! */
263 bb_error_msg("bad length"); 265 bb_error_msg("bad length");
diff --git a/configs/android_defconfig b/configs/android_defconfig
index b9df0ea02..a9a8d5e1f 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.20.0.git 3# Busybox version: 1.20.0.git
4# Wed Nov 2 17:54:00 2011 4# Sun Nov 6 07:51:38 2011
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7 7
@@ -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
63CONFIG_LFS=y 63# CONFIG_LFS is not set
64CONFIG_CROSS_COMPILER_PREFIX="arm-eabi-" 64CONFIG_CROSS_COMPILER_PREFIX="arm-eabi-"
65# 65#
66# Removed: 66# Removed:
@@ -199,6 +199,7 @@ CONFIG_CAT=y
199CONFIG_TEST=y 199CONFIG_TEST=y
200CONFIG_FEATURE_TEST_64=y 200CONFIG_FEATURE_TEST_64=y
201CONFIG_TOUCH=y 201CONFIG_TOUCH=y
202CONFIG_FEATURE_TOUCH_SUSV3=y
202CONFIG_TR=y 203CONFIG_TR=y
203CONFIG_FEATURE_TR_CLASSES=y 204CONFIG_FEATURE_TR_CLASSES=y
204CONFIG_FEATURE_TR_EQUIV=y 205CONFIG_FEATURE_TR_EQUIV=y
@@ -554,7 +555,7 @@ CONFIG_FEATURE_FBSET_READMODE=y
554CONFIG_FDFLUSH=y 555CONFIG_FDFLUSH=y
555CONFIG_FDFORMAT=y 556CONFIG_FDFORMAT=y
556CONFIG_FDISK=y 557CONFIG_FDISK=y
557# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set 558CONFIG_FDISK_SUPPORT_LARGE_DISKS=y
558CONFIG_FEATURE_FDISK_WRITABLE=y 559CONFIG_FEATURE_FDISK_WRITABLE=y
559# CONFIG_FEATURE_AIX_LABEL is not set 560# CONFIG_FEATURE_AIX_LABEL is not set
560# CONFIG_FEATURE_SGI_LABEL is not set 561# CONFIG_FEATURE_SGI_LABEL is not set
@@ -790,7 +791,7 @@ CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y
790CONFIG_FEATURE_IFUPDOWN_IPV4=y 791CONFIG_FEATURE_IFUPDOWN_IPV4=y
791# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set 792# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
792CONFIG_FEATURE_IFUPDOWN_MAPPING=y 793CONFIG_FEATURE_IFUPDOWN_MAPPING=y
793# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set 794CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y
794# CONFIG_INETD is not set 795# CONFIG_INETD is not set
795# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set 796# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
796# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set 797# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
@@ -841,13 +842,14 @@ CONFIG_FEATURE_TFTP_PUT=y
841CONFIG_FEATURE_TFTP_BLOCKSIZE=y 842CONFIG_FEATURE_TFTP_BLOCKSIZE=y
842CONFIG_FEATURE_TFTP_PROGRESS_BAR=y 843CONFIG_FEATURE_TFTP_PROGRESS_BAR=y
843# CONFIG_TFTP_DEBUG is not set 844# CONFIG_TFTP_DEBUG is not set
844# CONFIG_TRACEROUTE is not set 845CONFIG_TRACEROUTE=y
845# CONFIG_TRACEROUTE6 is not set 846# CONFIG_TRACEROUTE6 is not set
846# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set 847CONFIG_FEATURE_TRACEROUTE_VERBOSE=y
847# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set 848# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set
848# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set 849# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
849CONFIG_TUNCTL=y 850CONFIG_TUNCTL=y
850CONFIG_FEATURE_TUNCTL_UG=y 851CONFIG_FEATURE_TUNCTL_UG=y
852# CONFIG_UDHCPC6 is not set
851# CONFIG_UDHCPD is not set 853# CONFIG_UDHCPD is not set
852# CONFIG_DHCPRELAY is not set 854# CONFIG_DHCPRELAY is not set
853# CONFIG_DUMPLEASES is not set 855# CONFIG_DUMPLEASES is not set
@@ -856,7 +858,7 @@ CONFIG_FEATURE_TUNCTL_UG=y
856CONFIG_DHCPD_LEASES_FILE="" 858CONFIG_DHCPD_LEASES_FILE=""
857CONFIG_UDHCPC=y 859CONFIG_UDHCPC=y
858CONFIG_FEATURE_UDHCPC_ARPING=y 860CONFIG_FEATURE_UDHCPC_ARPING=y
859# CONFIG_FEATURE_UDHCP_PORT is not set 861CONFIG_FEATURE_UDHCP_PORT=y
860CONFIG_UDHCP_DEBUG=9 862CONFIG_UDHCP_DEBUG=9
861CONFIG_FEATURE_UDHCP_RFC3397=y 863CONFIG_FEATURE_UDHCP_RFC3397=y
862CONFIG_FEATURE_UDHCP_8021Q=y 864CONFIG_FEATURE_UDHCP_8021Q=y
diff --git a/configs/android_ndk_defconfig b/configs/android_ndk_defconfig
new file mode 100644
index 000000000..bf8827a58
--- /dev/null
+++ b/configs/android_ndk_defconfig
@@ -0,0 +1,1016 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.20.0.git
4# Fri Mar 2 16:53:26 2012
5#
6CONFIG_HAVE_DOT_CONFIG=y
7
8#
9# Busybox Settings
10#
11
12#
13# General Configuration
14#
15CONFIG_DESKTOP=y
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_SYSROOT="/opt/android-ndk/platforms/android-9/arch-arm"
66CONFIG_EXTRA_CFLAGS="-DANDROID -D__ANDROID__ -DSK_RELEASE -nostdlib -march=armv7-a -msoft-float -mfloat-abi=softfp -mfpu=neon -mthumb -mthumb-interwork -fpic -fno-short-enums -fgcse-after-reload -frename-registers"
67CONFIG_EXTRA_LDFLAGS="-Xlinker -z -Xlinker muldefs -nostdlib -Bdynamic -Xlinker -dynamic-linker -Xlinker /system/bin/linker -Xlinker -z -Xlinker nocopyreloc -Xlinker --no-undefined ${SYSROOT}/usr/lib/crtbegin_dynamic.o ${SYSROOT}/usr/lib/crtend_android.o"
68CONFIG_EXTRA_LDLIBS="dl m c gcc"
69
70
71#
72# Debugging Options
73#
74# CONFIG_DEBUG is not set
75# CONFIG_DEBUG_PESSIMIZE is not set
76# CONFIG_WERROR is not set
77CONFIG_NO_DEBUG_LIB=y
78# CONFIG_DMALLOC is not set
79# CONFIG_EFENCE is not set
80
81#
82# Installation Options ("make install" behavior)
83#
84CONFIG_INSTALL_APPLET_SYMLINKS=y
85# CONFIG_INSTALL_APPLET_HARDLINKS is not set
86# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
87# CONFIG_INSTALL_APPLET_DONT is not set
88# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
89# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
90# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
91CONFIG_PREFIX="./_install"
92
93#
94# Busybox Library Tuning
95#
96# CONFIG_FEATURE_SYSTEMD is not set
97# CONFIG_FEATURE_RTMINMAX is not set
98CONFIG_PASSWORD_MINLEN=6
99CONFIG_MD5_SMALL=1
100# CONFIG_FEATURE_FAST_TOP is not set
101# CONFIG_FEATURE_ETC_NETWORKS is not set
102CONFIG_FEATURE_USE_TERMIOS=y
103# CONFIG_FEATURE_EDITING is not set
104CONFIG_FEATURE_EDITING_MAX_LEN=0
105# CONFIG_FEATURE_EDITING_VI is not set
106CONFIG_FEATURE_EDITING_HISTORY=0
107# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
108# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
109# CONFIG_FEATURE_REVERSE_SEARCH is not set
110# CONFIG_FEATURE_TAB_COMPLETION is not set
111# CONFIG_FEATURE_USERNAME_COMPLETION is not set
112# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set
113# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
114# CONFIG_FEATURE_NON_POSIX_CP is not set
115# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
116CONFIG_FEATURE_COPYBUF_KB=4
117# CONFIG_FEATURE_SKIP_ROOTFS is not set
118# CONFIG_MONOTONIC_SYSCALL is not set
119# CONFIG_IOCTL_HEX2STR_ERROR is not set
120# CONFIG_FEATURE_HWIB is not set
121
122#
123# Applets
124#
125
126#
127# Archival Utilities
128#
129CONFIG_FEATURE_SEAMLESS_XZ=y
130CONFIG_FEATURE_SEAMLESS_LZMA=y
131CONFIG_FEATURE_SEAMLESS_BZ2=y
132CONFIG_FEATURE_SEAMLESS_GZ=y
133CONFIG_FEATURE_SEAMLESS_Z=y
134CONFIG_AR=y
135CONFIG_FEATURE_AR_LONG_FILENAMES=y
136CONFIG_FEATURE_AR_CREATE=y
137CONFIG_BUNZIP2=y
138CONFIG_BZIP2=y
139CONFIG_CPIO=y
140CONFIG_FEATURE_CPIO_O=y
141CONFIG_FEATURE_CPIO_P=y
142CONFIG_DPKG=y
143CONFIG_DPKG_DEB=y
144# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set
145CONFIG_GUNZIP=y
146CONFIG_GZIP=y
147# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set
148CONFIG_GZIP_FAST=0
149CONFIG_LZOP=y
150CONFIG_LZOP_COMPR_HIGH=y
151CONFIG_RPM2CPIO=y
152CONFIG_RPM=y
153CONFIG_TAR=y
154CONFIG_FEATURE_TAR_CREATE=y
155CONFIG_FEATURE_TAR_AUTODETECT=y
156CONFIG_FEATURE_TAR_FROM=y
157CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
158CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y
159CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
160# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set
161# CONFIG_FEATURE_TAR_TO_COMMAND is not set
162CONFIG_FEATURE_TAR_UNAME_GNAME=y
163CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
164# CONFIG_FEATURE_TAR_SELINUX is not set
165CONFIG_UNCOMPRESS=y
166CONFIG_UNLZMA=y
167CONFIG_FEATURE_LZMA_FAST=y
168CONFIG_LZMA=y
169CONFIG_UNXZ=y
170CONFIG_XZ=y
171CONFIG_UNZIP=y
172
173#
174# Coreutils
175#
176CONFIG_BASENAME=y
177CONFIG_CAT=y
178# CONFIG_DATE is not set
179# CONFIG_FEATURE_DATE_ISOFMT is not set
180# CONFIG_FEATURE_DATE_NANO is not set
181# CONFIG_FEATURE_DATE_COMPAT is not set
182# CONFIG_HOSTID is not set
183# CONFIG_ID is not set
184# CONFIG_GROUPS is not set
185CONFIG_TEST=y
186CONFIG_FEATURE_TEST_64=y
187CONFIG_TOUCH=y
188CONFIG_FEATURE_TOUCH_SUSV3=y
189CONFIG_TR=y
190CONFIG_FEATURE_TR_CLASSES=y
191CONFIG_FEATURE_TR_EQUIV=y
192CONFIG_BASE64=y
193# CONFIG_WHO is not set
194# CONFIG_USERS is not set
195CONFIG_CAL=y
196CONFIG_CATV=y
197CONFIG_CHGRP=y
198CONFIG_CHMOD=y
199CONFIG_CHOWN=y
200# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
201CONFIG_CHROOT=y
202CONFIG_CKSUM=y
203CONFIG_COMM=y
204CONFIG_CP=y
205# CONFIG_FEATURE_CP_LONG_OPTIONS is not set
206CONFIG_CUT=y
207CONFIG_DD=y
208CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
209CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y
210CONFIG_FEATURE_DD_IBS_OBS=y
211# CONFIG_DF is not set
212# CONFIG_FEATURE_DF_FANCY is not set
213CONFIG_DIRNAME=y
214CONFIG_DOS2UNIX=y
215CONFIG_UNIX2DOS=y
216CONFIG_DU=y
217CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
218CONFIG_ECHO=y
219CONFIG_FEATURE_FANCY_ECHO=y
220CONFIG_ENV=y
221# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set
222CONFIG_EXPAND=y
223# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set
224CONFIG_EXPR=y
225CONFIG_EXPR_MATH_SUPPORT_64=y
226CONFIG_FALSE=y
227CONFIG_FOLD=y
228CONFIG_FSYNC=y
229CONFIG_HEAD=y
230CONFIG_FEATURE_FANCY_HEAD=y
231CONFIG_INSTALL=y
232# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
233CONFIG_LN=y
234# CONFIG_LOGNAME is not set
235CONFIG_LS=y
236CONFIG_FEATURE_LS_FILETYPES=y
237CONFIG_FEATURE_LS_FOLLOWLINKS=y
238CONFIG_FEATURE_LS_RECURSIVE=y
239CONFIG_FEATURE_LS_SORTFILES=y
240CONFIG_FEATURE_LS_TIMESTAMPS=y
241CONFIG_FEATURE_LS_USERNAME=y
242# CONFIG_FEATURE_LS_COLOR is not set
243# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set
244CONFIG_MD5SUM=y
245CONFIG_MKDIR=y
246# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set
247CONFIG_MKFIFO=y
248CONFIG_MKNOD=y
249CONFIG_MV=y
250# CONFIG_FEATURE_MV_LONG_OPTIONS is not set
251CONFIG_NICE=y
252CONFIG_NOHUP=y
253CONFIG_OD=y
254CONFIG_PRINTENV=y
255CONFIG_PRINTF=y
256CONFIG_PWD=y
257CONFIG_READLINK=y
258CONFIG_FEATURE_READLINK_FOLLOW=y
259CONFIG_REALPATH=y
260CONFIG_RM=y
261CONFIG_RMDIR=y
262# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set
263CONFIG_SEQ=y
264CONFIG_SHA1SUM=y
265CONFIG_SHA256SUM=y
266CONFIG_SHA512SUM=y
267CONFIG_SLEEP=y
268CONFIG_FEATURE_FANCY_SLEEP=y
269CONFIG_FEATURE_FLOAT_SLEEP=y
270CONFIG_SORT=y
271CONFIG_FEATURE_SORT_BIG=y
272CONFIG_SPLIT=y
273CONFIG_FEATURE_SPLIT_FANCY=y
274# CONFIG_STAT is not set
275# CONFIG_FEATURE_STAT_FORMAT is not set
276CONFIG_STTY=y
277CONFIG_SUM=y
278CONFIG_SYNC=y
279CONFIG_TAC=y
280CONFIG_TAIL=y
281CONFIG_FEATURE_FANCY_TAIL=y
282CONFIG_TEE=y
283CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
284CONFIG_TRUE=y
285# CONFIG_TTY is not set
286CONFIG_UNAME=y
287CONFIG_UNEXPAND=y
288# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set
289CONFIG_UNIQ=y
290CONFIG_USLEEP=y
291CONFIG_UUDECODE=y
292CONFIG_UUENCODE=y
293CONFIG_WC=y
294CONFIG_FEATURE_WC_LARGE=y
295CONFIG_WHOAMI=y
296CONFIG_YES=y
297
298#
299# Common options for cp and mv
300#
301CONFIG_FEATURE_PRESERVE_HARDLINKS=y
302
303#
304# Common options for ls, more and telnet
305#
306CONFIG_FEATURE_AUTOWIDTH=y
307
308#
309# Common options for df, du, ls
310#
311CONFIG_FEATURE_HUMAN_READABLE=y
312
313#
314# Common options for md5sum, sha1sum, sha256sum, sha512sum
315#
316CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
317
318#
319# Console Utilities
320#
321CONFIG_CHVT=y
322CONFIG_FGCONSOLE=y
323CONFIG_CLEAR=y
324CONFIG_DEALLOCVT=y
325CONFIG_DUMPKMAP=y
326# CONFIG_KBD_MODE is not set
327# CONFIG_LOADFONT is not set
328CONFIG_LOADKMAP=y
329CONFIG_OPENVT=y
330CONFIG_RESET=y
331CONFIG_RESIZE=y
332CONFIG_FEATURE_RESIZE_PRINT=y
333CONFIG_SETCONSOLE=y
334# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
335# CONFIG_SETFONT is not set
336# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
337CONFIG_DEFAULT_SETFONT_DIR=""
338CONFIG_SETKEYCODES=y
339CONFIG_SETLOGCONS=y
340CONFIG_SHOWKEY=y
341# CONFIG_FEATURE_LOADFONT_PSF2 is not set
342# CONFIG_FEATURE_LOADFONT_RAW is not set
343
344#
345# Debian Utilities
346#
347CONFIG_MKTEMP=y
348CONFIG_PIPE_PROGRESS=y
349CONFIG_RUN_PARTS=y
350# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
351CONFIG_FEATURE_RUN_PARTS_FANCY=y
352CONFIG_START_STOP_DAEMON=y
353CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y
354# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
355CONFIG_WHICH=y
356
357#
358# Editors
359#
360CONFIG_PATCH=y
361CONFIG_VI=y
362CONFIG_FEATURE_VI_MAX_LEN=4096
363CONFIG_FEATURE_VI_8BIT=y
364CONFIG_FEATURE_VI_COLON=y
365CONFIG_FEATURE_VI_YANKMARK=y
366CONFIG_FEATURE_VI_SEARCH=y
367# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
368CONFIG_FEATURE_VI_USE_SIGNALS=y
369CONFIG_FEATURE_VI_DOT_CMD=y
370CONFIG_FEATURE_VI_READONLY=y
371CONFIG_FEATURE_VI_SETOPTS=y
372CONFIG_FEATURE_VI_SET=y
373CONFIG_FEATURE_VI_WIN_RESIZE=y
374CONFIG_FEATURE_VI_ASK_TERMINAL=y
375CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
376CONFIG_AWK=y
377CONFIG_FEATURE_AWK_LIBM=y
378CONFIG_CMP=y
379CONFIG_DIFF=y
380# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set
381CONFIG_FEATURE_DIFF_DIR=y
382CONFIG_ED=y
383CONFIG_SED=y
384CONFIG_FEATURE_ALLOW_EXEC=y
385
386#
387# Finding Utilities
388#
389CONFIG_FIND=y
390CONFIG_FEATURE_FIND_PRINT0=y
391CONFIG_FEATURE_FIND_MTIME=y
392CONFIG_FEATURE_FIND_MMIN=y
393CONFIG_FEATURE_FIND_PERM=y
394CONFIG_FEATURE_FIND_TYPE=y
395CONFIG_FEATURE_FIND_XDEV=y
396CONFIG_FEATURE_FIND_MAXDEPTH=y
397CONFIG_FEATURE_FIND_NEWER=y
398CONFIG_FEATURE_FIND_INUM=y
399CONFIG_FEATURE_FIND_EXEC=y
400CONFIG_FEATURE_FIND_USER=y
401CONFIG_FEATURE_FIND_GROUP=y
402CONFIG_FEATURE_FIND_NOT=y
403CONFIG_FEATURE_FIND_DEPTH=y
404CONFIG_FEATURE_FIND_PAREN=y
405CONFIG_FEATURE_FIND_SIZE=y
406CONFIG_FEATURE_FIND_PRUNE=y
407CONFIG_FEATURE_FIND_DELETE=y
408CONFIG_FEATURE_FIND_PATH=y
409CONFIG_FEATURE_FIND_REGEX=y
410# CONFIG_FEATURE_FIND_CONTEXT is not set
411CONFIG_FEATURE_FIND_LINKS=y
412CONFIG_GREP=y
413CONFIG_FEATURE_GREP_EGREP_ALIAS=y
414CONFIG_FEATURE_GREP_FGREP_ALIAS=y
415CONFIG_FEATURE_GREP_CONTEXT=y
416CONFIG_XARGS=y
417CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
418CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
419CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
420CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
421
422#
423# Init Utilities
424#
425CONFIG_BOOTCHARTD=y
426CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y
427CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y
428CONFIG_HALT=y
429# CONFIG_FEATURE_CALL_TELINIT is not set
430CONFIG_TELINIT_PATH=""
431CONFIG_INIT=y
432CONFIG_FEATURE_USE_INITTAB=y
433# CONFIG_FEATURE_KILL_REMOVED is not set
434CONFIG_FEATURE_KILL_DELAY=0
435CONFIG_FEATURE_INIT_SCTTY=y
436CONFIG_FEATURE_INIT_SYSLOG=y
437CONFIG_FEATURE_EXTRA_QUIET=y
438CONFIG_FEATURE_INIT_COREDUMPS=y
439CONFIG_FEATURE_INITRD=y
440CONFIG_INIT_TERMINAL_TYPE="linux"
441CONFIG_MESG=y
442CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y
443
444#
445# Login/Password Management Utilities
446#
447# CONFIG_ADD_SHELL is not set
448# CONFIG_REMOVE_SHELL is not set
449# CONFIG_FEATURE_SHADOWPASSWDS is not set
450# CONFIG_USE_BB_PWD_GRP is not set
451# CONFIG_USE_BB_SHADOW is not set
452# CONFIG_USE_BB_CRYPT is not set
453# CONFIG_USE_BB_CRYPT_SHA is not set
454# CONFIG_ADDUSER is not set
455# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
456# CONFIG_FEATURE_CHECK_NAMES is not set
457CONFIG_FIRST_SYSTEM_ID=0
458CONFIG_LAST_SYSTEM_ID=0
459# CONFIG_ADDGROUP is not set
460# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set
461# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
462# CONFIG_DELUSER is not set
463# CONFIG_DELGROUP is not set
464# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
465# CONFIG_GETTY is not set
466# CONFIG_LOGIN is not set
467# CONFIG_LOGIN_SESSION_AS_CHILD is not set
468# CONFIG_PAM is not set
469# CONFIG_LOGIN_SCRIPTS is not set
470# CONFIG_FEATURE_NOLOGIN is not set
471# CONFIG_FEATURE_SECURETTY is not set
472# CONFIG_PASSWD is not set
473# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
474# CONFIG_CRYPTPW is not set
475# CONFIG_CHPASSWD is not set
476CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
477# CONFIG_SU is not set
478# CONFIG_FEATURE_SU_SYSLOG is not set
479# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
480# CONFIG_SULOGIN is not set
481# CONFIG_VLOCK is not set
482
483#
484# Linux Ext2 FS Progs
485#
486CONFIG_CHATTR=y
487# CONFIG_FSCK is not set
488CONFIG_LSATTR=y
489CONFIG_TUNE2FS=y
490
491#
492# Linux Module Utilities
493#
494CONFIG_MODINFO=y
495CONFIG_MODPROBE_SMALL=y
496CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y
497CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y
498# CONFIG_INSMOD is not set
499# CONFIG_RMMOD is not set
500# CONFIG_LSMOD is not set
501# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
502# CONFIG_MODPROBE is not set
503# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
504# CONFIG_DEPMOD is not set
505
506#
507# Options common to multiple modutils
508#
509# CONFIG_FEATURE_2_4_MODULES is not set
510# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
511# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
512# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
513# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
514# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
515# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
516# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
517# CONFIG_FEATURE_MODUTILS_ALIAS is not set
518# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
519CONFIG_DEFAULT_MODULES_DIR="/lib/modules"
520CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
521
522#
523# Linux System Utilities
524#
525CONFIG_BLOCKDEV=y
526CONFIG_MDEV=y
527CONFIG_FEATURE_MDEV_CONF=y
528CONFIG_FEATURE_MDEV_RENAME=y
529CONFIG_FEATURE_MDEV_RENAME_REGEXP=y
530CONFIG_FEATURE_MDEV_EXEC=y
531CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y
532CONFIG_REV=y
533# CONFIG_ACPID is not set
534# CONFIG_FEATURE_ACPID_COMPAT is not set
535CONFIG_BLKID=y
536CONFIG_FEATURE_BLKID_TYPE=y
537CONFIG_DMESG=y
538CONFIG_FEATURE_DMESG_PRETTY=y
539CONFIG_FBSET=y
540CONFIG_FEATURE_FBSET_FANCY=y
541CONFIG_FEATURE_FBSET_READMODE=y
542CONFIG_FDFLUSH=y
543CONFIG_FDFORMAT=y
544CONFIG_FDISK=y
545CONFIG_FDISK_SUPPORT_LARGE_DISKS=y
546CONFIG_FEATURE_FDISK_WRITABLE=y
547# CONFIG_FEATURE_AIX_LABEL is not set
548# CONFIG_FEATURE_SGI_LABEL is not set
549# CONFIG_FEATURE_SUN_LABEL is not set
550# CONFIG_FEATURE_OSF_LABEL is not set
551# CONFIG_FEATURE_GPT_LABEL is not set
552CONFIG_FEATURE_FDISK_ADVANCED=y
553CONFIG_FINDFS=y
554CONFIG_FLOCK=y
555CONFIG_FREERAMDISK=y
556# CONFIG_FSCK_MINIX is not set
557# CONFIG_MKFS_EXT2 is not set
558# CONFIG_MKFS_MINIX is not set
559# CONFIG_FEATURE_MINIX2 is not set
560# CONFIG_MKFS_REISER is not set
561# CONFIG_MKFS_VFAT is not set
562CONFIG_GETOPT=y
563CONFIG_FEATURE_GETOPT_LONG=y
564CONFIG_HEXDUMP=y
565CONFIG_FEATURE_HEXDUMP_REVERSE=y
566CONFIG_HD=y
567CONFIG_HWCLOCK=y
568# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
569# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
570# CONFIG_IPCRM is not set
571# CONFIG_IPCS is not set
572CONFIG_LOSETUP=y
573CONFIG_LSPCI=y
574CONFIG_LSUSB=y
575CONFIG_MKSWAP=y
576CONFIG_FEATURE_MKSWAP_UUID=y
577CONFIG_MORE=y
578# CONFIG_MOUNT is not set
579# CONFIG_FEATURE_MOUNT_FAKE is not set
580# CONFIG_FEATURE_MOUNT_VERBOSE is not set
581# CONFIG_FEATURE_MOUNT_HELPERS is not set
582# CONFIG_FEATURE_MOUNT_LABEL is not set
583# CONFIG_FEATURE_MOUNT_NFS is not set
584# CONFIG_FEATURE_MOUNT_CIFS is not set
585# CONFIG_FEATURE_MOUNT_FLAGS is not set
586# CONFIG_FEATURE_MOUNT_FSTAB is not set
587# CONFIG_PIVOT_ROOT is not set
588# CONFIG_RDATE is not set
589CONFIG_RDEV=y
590CONFIG_READPROFILE=y
591CONFIG_RTCWAKE=y
592CONFIG_SCRIPT=y
593CONFIG_SCRIPTREPLAY=y
594# CONFIG_SETARCH is not set
595# CONFIG_SWAPONOFF is not set
596# CONFIG_FEATURE_SWAPON_PRI is not set
597CONFIG_SWITCH_ROOT=y
598# CONFIG_UMOUNT is not set
599# CONFIG_FEATURE_UMOUNT_ALL is not set
600# CONFIG_FEATURE_MOUNT_LOOP is not set
601# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
602# CONFIG_FEATURE_MTAB_SUPPORT is not set
603CONFIG_VOLUMEID=y
604
605#
606# Filesystem/Volume identification
607#
608CONFIG_FEATURE_VOLUMEID_EXT=y
609CONFIG_FEATURE_VOLUMEID_BTRFS=y
610CONFIG_FEATURE_VOLUMEID_REISERFS=y
611CONFIG_FEATURE_VOLUMEID_FAT=y
612CONFIG_FEATURE_VOLUMEID_HFS=y
613CONFIG_FEATURE_VOLUMEID_JFS=y
614CONFIG_FEATURE_VOLUMEID_XFS=y
615CONFIG_FEATURE_VOLUMEID_NTFS=y
616CONFIG_FEATURE_VOLUMEID_ISO9660=y
617CONFIG_FEATURE_VOLUMEID_UDF=y
618CONFIG_FEATURE_VOLUMEID_LUKS=y
619CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y
620CONFIG_FEATURE_VOLUMEID_CRAMFS=y
621CONFIG_FEATURE_VOLUMEID_ROMFS=y
622CONFIG_FEATURE_VOLUMEID_SYSV=y
623CONFIG_FEATURE_VOLUMEID_OCFS2=y
624CONFIG_FEATURE_VOLUMEID_LINUXRAID=y
625
626#
627# Miscellaneous Utilities
628#
629# CONFIG_CONSPY is not set
630CONFIG_LESS=y
631CONFIG_FEATURE_LESS_MAXLINES=9999999
632CONFIG_FEATURE_LESS_BRACKETS=y
633CONFIG_FEATURE_LESS_FLAGS=y
634CONFIG_FEATURE_LESS_MARKS=y
635CONFIG_FEATURE_LESS_REGEXP=y
636CONFIG_FEATURE_LESS_WINCH=y
637CONFIG_FEATURE_LESS_ASK_TERMINAL=y
638CONFIG_FEATURE_LESS_DASHCMD=y
639CONFIG_FEATURE_LESS_LINENUMS=y
640# CONFIG_NANDWRITE is not set
641CONFIG_NANDDUMP=y
642CONFIG_SETSERIAL=y
643# CONFIG_UBIATTACH is not set
644# CONFIG_UBIDETACH is not set
645# CONFIG_UBIMKVOL is not set
646# CONFIG_UBIRMVOL is not set
647# CONFIG_UBIRSVOL is not set
648# CONFIG_UBIUPDATEVOL is not set
649# CONFIG_ADJTIMEX is not set
650# CONFIG_BBCONFIG is not set
651# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
652CONFIG_BEEP=y
653CONFIG_FEATURE_BEEP_FREQ=4000
654CONFIG_FEATURE_BEEP_LENGTH_MS=30
655CONFIG_CHAT=y
656CONFIG_FEATURE_CHAT_NOFAIL=y
657# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
658CONFIG_FEATURE_CHAT_IMPLICIT_CR=y
659CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y
660CONFIG_FEATURE_CHAT_SEND_ESCAPES=y
661CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y
662CONFIG_FEATURE_CHAT_CLR_ABORT=y
663CONFIG_CHRT=y
664CONFIG_CROND=y
665CONFIG_FEATURE_CROND_D=y
666CONFIG_FEATURE_CROND_CALL_SENDMAIL=y
667CONFIG_FEATURE_CROND_DIR="/var/spool/cron"
668CONFIG_CRONTAB=y
669CONFIG_DC=y
670CONFIG_FEATURE_DC_LIBM=y
671# CONFIG_DEVFSD is not set
672# CONFIG_DEVFSD_MODLOAD is not set
673# CONFIG_DEVFSD_FG_NP is not set
674# CONFIG_DEVFSD_VERBOSE is not set
675# CONFIG_FEATURE_DEVFS is not set
676CONFIG_DEVMEM=y
677# CONFIG_EJECT is not set
678# CONFIG_FEATURE_EJECT_SCSI is not set
679CONFIG_FBSPLASH=y
680CONFIG_FLASHCP=y
681CONFIG_FLASH_LOCK=y
682CONFIG_FLASH_UNLOCK=y
683# CONFIG_FLASH_ERASEALL is not set
684# CONFIG_IONICE is not set
685CONFIG_INOTIFYD=y
686# CONFIG_LAST is not set
687# CONFIG_FEATURE_LAST_SMALL is not set
688# CONFIG_FEATURE_LAST_FANCY is not set
689CONFIG_HDPARM=y
690CONFIG_FEATURE_HDPARM_GET_IDENTITY=y
691CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y
692CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y
693CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y
694CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y
695CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y
696CONFIG_MAKEDEVS=y
697# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
698CONFIG_FEATURE_MAKEDEVS_TABLE=y
699CONFIG_MAN=y
700# CONFIG_MICROCOM is not set
701# CONFIG_MOUNTPOINT is not set
702# CONFIG_MT is not set
703CONFIG_RAIDAUTORUN=y
704# CONFIG_READAHEAD is not set
705# CONFIG_RFKILL is not set
706# CONFIG_RUNLEVEL is not set
707CONFIG_RX=y
708CONFIG_SETSID=y
709CONFIG_STRINGS=y
710# CONFIG_TASKSET is not set
711# CONFIG_FEATURE_TASKSET_FANCY is not set
712CONFIG_TIME=y
713CONFIG_TIMEOUT=y
714CONFIG_TTYSIZE=y
715CONFIG_VOLNAME=y
716# CONFIG_WALL is not set
717# CONFIG_WATCHDOG is not set
718
719#
720# Networking Utilities
721#
722# CONFIG_NAMEIF is not set
723# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
724CONFIG_NBDCLIENT=y
725CONFIG_NC=y
726CONFIG_NC_SERVER=y
727CONFIG_NC_EXTRA=y
728# CONFIG_NC_110_COMPAT is not set
729CONFIG_PING=y
730# CONFIG_PING6 is not set
731CONFIG_FEATURE_FANCY_PING=y
732CONFIG_WHOIS=y
733# CONFIG_FEATURE_IPV6 is not set
734# CONFIG_FEATURE_UNIX_LOCAL is not set
735# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set
736# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
737CONFIG_ARP=y
738# CONFIG_ARPING is not set
739# CONFIG_BRCTL is not set
740# CONFIG_FEATURE_BRCTL_FANCY is not set
741# CONFIG_FEATURE_BRCTL_SHOW is not set
742CONFIG_DNSD=y
743# CONFIG_ETHER_WAKE is not set
744CONFIG_FAKEIDENTD=y
745CONFIG_FTPD=y
746CONFIG_FEATURE_FTP_WRITE=y
747CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y
748CONFIG_FTPGET=y
749CONFIG_FTPPUT=y
750# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set
751# CONFIG_HOSTNAME is not set
752CONFIG_HTTPD=y
753CONFIG_FEATURE_HTTPD_RANGES=y
754CONFIG_FEATURE_HTTPD_USE_SENDFILE=y
755CONFIG_FEATURE_HTTPD_SETUID=y
756CONFIG_FEATURE_HTTPD_BASIC_AUTH=y
757# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
758CONFIG_FEATURE_HTTPD_CGI=y
759CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y
760CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y
761CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y
762CONFIG_FEATURE_HTTPD_ERROR_PAGES=y
763CONFIG_FEATURE_HTTPD_PROXY=y
764CONFIG_FEATURE_HTTPD_GZIP=y
765CONFIG_IFCONFIG=y
766CONFIG_FEATURE_IFCONFIG_STATUS=y
767# CONFIG_FEATURE_IFCONFIG_SLIP is not set
768CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y
769CONFIG_FEATURE_IFCONFIG_HW=y
770CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y
771# CONFIG_IFENSLAVE is not set
772# CONFIG_IFPLUGD is not set
773CONFIG_IFUPDOWN=y
774CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate"
775CONFIG_FEATURE_IFUPDOWN_IP=y
776CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y
777# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set
778CONFIG_FEATURE_IFUPDOWN_IPV4=y
779# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
780CONFIG_FEATURE_IFUPDOWN_MAPPING=y
781CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y
782# CONFIG_INETD is not set
783# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
784# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
785# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
786# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
787# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
788# CONFIG_FEATURE_INETD_RPC is not set
789CONFIG_IP=y
790CONFIG_FEATURE_IP_ADDRESS=y
791CONFIG_FEATURE_IP_LINK=y
792CONFIG_FEATURE_IP_ROUTE=y
793CONFIG_FEATURE_IP_TUNNEL=y
794CONFIG_FEATURE_IP_RULE=y
795CONFIG_FEATURE_IP_SHORT_FORMS=y
796# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
797CONFIG_IPADDR=y
798CONFIG_IPLINK=y
799CONFIG_IPROUTE=y
800CONFIG_IPTUNNEL=y
801CONFIG_IPRULE=y
802CONFIG_IPCALC=y
803CONFIG_FEATURE_IPCALC_FANCY=y
804# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set
805CONFIG_NETSTAT=y
806CONFIG_FEATURE_NETSTAT_WIDE=y
807CONFIG_FEATURE_NETSTAT_PRG=y
808# CONFIG_NSLOOKUP is not set
809# CONFIG_NTPD is not set
810# CONFIG_FEATURE_NTPD_SERVER is not set
811CONFIG_PSCAN=y
812CONFIG_ROUTE=y
813# CONFIG_SLATTACH is not set
814CONFIG_TCPSVD=y
815CONFIG_TELNET=y
816CONFIG_FEATURE_TELNET_TTYPE=y
817CONFIG_FEATURE_TELNET_AUTOLOGIN=y
818CONFIG_TELNETD=y
819CONFIG_FEATURE_TELNETD_STANDALONE=y
820CONFIG_FEATURE_TELNETD_INETD_WAIT=y
821CONFIG_TFTP=y
822CONFIG_TFTPD=y
823
824#
825# Common options for tftp/tftpd
826#
827CONFIG_FEATURE_TFTP_GET=y
828CONFIG_FEATURE_TFTP_PUT=y
829CONFIG_FEATURE_TFTP_BLOCKSIZE=y
830CONFIG_FEATURE_TFTP_PROGRESS_BAR=y
831# CONFIG_TFTP_DEBUG is not set
832CONFIG_TRACEROUTE=y
833# CONFIG_TRACEROUTE6 is not set
834CONFIG_FEATURE_TRACEROUTE_VERBOSE=y
835# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set
836# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
837CONFIG_TUNCTL=y
838CONFIG_FEATURE_TUNCTL_UG=y
839# CONFIG_UDHCPC6 is not set
840# CONFIG_UDHCPD is not set
841# CONFIG_DHCPRELAY is not set
842# CONFIG_DUMPLEASES is not set
843# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
844# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
845CONFIG_DHCPD_LEASES_FILE=""
846CONFIG_UDHCPC=y
847CONFIG_FEATURE_UDHCPC_ARPING=y
848CONFIG_FEATURE_UDHCP_PORT=y
849CONFIG_UDHCP_DEBUG=9
850CONFIG_FEATURE_UDHCP_RFC3397=y
851CONFIG_FEATURE_UDHCP_8021Q=y
852CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script"
853CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80
854CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n"
855CONFIG_UDPSVD=y
856CONFIG_VCONFIG=y
857CONFIG_WGET=y
858CONFIG_FEATURE_WGET_STATUSBAR=y
859CONFIG_FEATURE_WGET_AUTHENTICATION=y
860# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set
861CONFIG_FEATURE_WGET_TIMEOUT=y
862# CONFIG_ZCIP is not set
863
864#
865# Print Utilities
866#
867CONFIG_LPD=y
868CONFIG_LPR=y
869CONFIG_LPQ=y
870
871#
872# Mail Utilities
873#
874CONFIG_MAKEMIME=y
875CONFIG_FEATURE_MIME_CHARSET="us-ascii"
876CONFIG_POPMAILDIR=y
877CONFIG_FEATURE_POPMAILDIR_DELIVERY=y
878CONFIG_REFORMIME=y
879CONFIG_FEATURE_REFORMIME_COMPAT=y
880CONFIG_SENDMAIL=y
881
882#
883# Process Utilities
884#
885CONFIG_IOSTAT=y
886CONFIG_MPSTAT=y
887CONFIG_NMETER=y
888CONFIG_PMAP=y
889CONFIG_POWERTOP=y
890CONFIG_PSTREE=y
891CONFIG_PWDX=y
892CONFIG_SMEMCAP=y
893CONFIG_UPTIME=y
894# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
895CONFIG_FREE=y
896CONFIG_FUSER=y
897# CONFIG_KILL is not set
898# CONFIG_KILLALL is not set
899# CONFIG_KILLALL5 is not set
900# CONFIG_PGREP is not set
901CONFIG_PIDOF=y
902CONFIG_FEATURE_PIDOF_SINGLE=y
903CONFIG_FEATURE_PIDOF_OMIT=y
904# CONFIG_PKILL is not set
905CONFIG_PS=y
906# CONFIG_FEATURE_PS_WIDE is not set
907# CONFIG_FEATURE_PS_LONG is not set
908CONFIG_FEATURE_PS_TIME=y
909CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y
910# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
911CONFIG_RENICE=y
912CONFIG_BB_SYSCTL=y
913CONFIG_TOP=y
914CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
915CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
916CONFIG_FEATURE_TOP_SMP_CPU=y
917CONFIG_FEATURE_TOP_DECIMALS=y
918CONFIG_FEATURE_TOP_SMP_PROCESS=y
919CONFIG_FEATURE_TOPMEM=y
920CONFIG_FEATURE_SHOW_THREADS=y
921CONFIG_WATCH=y
922
923#
924# Runit Utilities
925#
926CONFIG_RUNSV=y
927CONFIG_RUNSVDIR=y
928# CONFIG_FEATURE_RUNSVDIR_LOG is not set
929CONFIG_SV=y
930CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service"
931CONFIG_SVLOGD=y
932CONFIG_CHPST=y
933CONFIG_SETUIDGID=y
934CONFIG_ENVUIDGID=y
935CONFIG_ENVDIR=y
936CONFIG_SOFTLIMIT=y
937# CONFIG_CHCON is not set
938# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
939# CONFIG_GETENFORCE is not set
940# CONFIG_GETSEBOOL is not set
941# CONFIG_LOAD_POLICY is not set
942# CONFIG_MATCHPATHCON is not set
943# CONFIG_RESTORECON is not set
944# CONFIG_RUNCON is not set
945# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
946# CONFIG_SELINUXENABLED is not set
947# CONFIG_SETENFORCE is not set
948# CONFIG_SETFILES is not set
949# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
950# CONFIG_SETSEBOOL is not set
951# CONFIG_SESTATUS is not set
952
953#
954# Shells
955#
956# CONFIG_ASH is not set
957# CONFIG_ASH_BASH_COMPAT is not set
958# CONFIG_ASH_IDLE_TIMEOUT is not set
959# CONFIG_ASH_JOB_CONTROL is not set
960# CONFIG_ASH_ALIAS is not set
961# CONFIG_ASH_GETOPTS is not set
962# CONFIG_ASH_BUILTIN_ECHO is not set
963# CONFIG_ASH_BUILTIN_PRINTF is not set
964# CONFIG_ASH_BUILTIN_TEST is not set
965# CONFIG_ASH_CMDCMD is not set
966# CONFIG_ASH_MAIL is not set
967# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set
968# CONFIG_ASH_RANDOM_SUPPORT is not set
969# CONFIG_ASH_EXPAND_PRMT is not set
970CONFIG_CTTYHACK=y
971# CONFIG_HUSH is not set
972# CONFIG_HUSH_BASH_COMPAT is not set
973# CONFIG_HUSH_BRACE_EXPANSION is not set
974# CONFIG_HUSH_HELP is not set
975# CONFIG_HUSH_INTERACTIVE is not set
976# CONFIG_HUSH_SAVEHISTORY is not set
977# CONFIG_HUSH_JOB is not set
978# CONFIG_HUSH_TICK is not set
979# CONFIG_HUSH_IF is not set
980# CONFIG_HUSH_LOOPS is not set
981# CONFIG_HUSH_CASE is not set
982# CONFIG_HUSH_FUNCTIONS is not set
983# CONFIG_HUSH_LOCAL is not set
984# CONFIG_HUSH_RANDOM_SUPPORT is not set
985# CONFIG_HUSH_EXPORT_N is not set
986# CONFIG_HUSH_MODE_X is not set
987# CONFIG_MSH is not set
988# CONFIG_FEATURE_SH_IS_ASH is not set
989# CONFIG_FEATURE_SH_IS_HUSH is not set
990CONFIG_FEATURE_SH_IS_NONE=y
991# CONFIG_FEATURE_BASH_IS_ASH is not set
992# CONFIG_FEATURE_BASH_IS_HUSH is not set
993CONFIG_FEATURE_BASH_IS_NONE=y
994# CONFIG_SH_MATH_SUPPORT is not set
995# CONFIG_SH_MATH_SUPPORT_64 is not set
996# CONFIG_FEATURE_SH_EXTRA_QUIET is not set
997# CONFIG_FEATURE_SH_STANDALONE is not set
998# CONFIG_FEATURE_SH_NOFORK is not set
999# CONFIG_FEATURE_SH_HISTFILESIZE is not set
1000
1001#
1002# System Logging Utilities
1003#
1004# CONFIG_SYSLOGD is not set
1005# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1006# CONFIG_FEATURE_REMOTE_LOG is not set
1007# CONFIG_FEATURE_SYSLOGD_DUP is not set
1008# CONFIG_FEATURE_SYSLOGD_CFG is not set
1009CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1010# CONFIG_FEATURE_IPC_SYSLOG is not set
1011CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1012# CONFIG_LOGREAD is not set
1013# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1014CONFIG_KLOGD=y
1015CONFIG_FEATURE_KLOGD_KLOGCTL=y
1016# CONFIG_LOGGER is not set
diff --git a/coreutils/chroot.c b/coreutils/chroot.c
index ab8beb023..633e66b38 100644
--- a/coreutils/chroot.c
+++ b/coreutils/chroot.c
@@ -31,7 +31,6 @@ int chroot_main(int argc UNUSED_PARAM, char **argv)
31 if (!*argv) 31 if (!*argv)
32 bb_show_usage(); 32 bb_show_usage();
33 xchroot(*argv); 33 xchroot(*argv);
34 xchdir("/");
35 34
36 ++argv; 35 ++argv;
37 if (!*argv) { /* no 2nd param (PROG), use shell */ 36 if (!*argv) { /* no 2nd param (PROG), use shell */
diff --git a/coreutils/cp.c b/coreutils/cp.c
index f276d25d7..45efaba72 100644
--- a/coreutils/cp.c
+++ b/coreutils/cp.c
@@ -16,9 +16,9 @@
16 */ 16 */
17 17
18//usage:#define cp_trivial_usage 18//usage:#define cp_trivial_usage
19//usage: "[OPTIONS] SOURCE DEST" 19//usage: "[OPTIONS] SOURCE... DEST"
20//usage:#define cp_full_usage "\n\n" 20//usage:#define cp_full_usage "\n\n"
21//usage: "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY\n" 21//usage: "Copy SOURCE(s) to DEST\n"
22//usage: "\n -a Same as -dpR" 22//usage: "\n -a Same as -dpR"
23//usage: IF_SELINUX( 23//usage: IF_SELINUX(
24//usage: "\n -c Preserve security context" 24//usage: "\n -c Preserve security context"
diff --git a/coreutils/date.c b/coreutils/date.c
index d90e620a0..62cceff9c 100644
--- a/coreutils/date.c
+++ b/coreutils/date.c
@@ -129,6 +129,9 @@
129//usage: "\n [YYYY.]MM.DD-hh:mm[:ss]" 129//usage: "\n [YYYY.]MM.DD-hh:mm[:ss]"
130//usage: "\n YYYY-MM-DD hh:mm[:ss]" 130//usage: "\n YYYY-MM-DD hh:mm[:ss]"
131//usage: "\n [[[[[YY]YY]MM]DD]hh]mm[.ss]" 131//usage: "\n [[[[[YY]YY]MM]DD]hh]mm[.ss]"
132//usage: IF_FEATURE_DATE_COMPAT(
133//usage: "\n 'date TIME' form accepts MMDDhhmm[[YY]YY][.ss] instead"
134//usage: )
132//usage: 135//usage:
133//usage:#define date_example_usage 136//usage:#define date_example_usage
134//usage: "$ date\n" 137//usage: "$ date\n"
diff --git a/coreutils/du.c b/coreutils/du.c
index 34a549f02..19a0319f1 100644
--- a/coreutils/du.c
+++ b/coreutils/du.c
@@ -26,11 +26,7 @@
26//usage:#define du_trivial_usage 26//usage:#define du_trivial_usage
27//usage: "[-aHLdclsx" IF_FEATURE_HUMAN_READABLE("hm") "k] [FILE]..." 27//usage: "[-aHLdclsx" IF_FEATURE_HUMAN_READABLE("hm") "k] [FILE]..."
28//usage:#define du_full_usage "\n\n" 28//usage:#define du_full_usage "\n\n"
29//usage: "Summarize disk space used for each FILE and/or directory.\n" 29//usage: "Summarize disk space used for each FILE and/or directory\n"
30//usage: "Disk space is printed in units of "
31//usage: IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("1024")
32//usage: IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("512")
33//usage: " bytes.\n"
34//usage: "\n -a Show file sizes too" 30//usage: "\n -a Show file sizes too"
35//usage: "\n -L Follow all symlinks" 31//usage: "\n -L Follow all symlinks"
36//usage: "\n -H Follow symlinks on command line" 32//usage: "\n -H Follow symlinks on command line"
@@ -40,11 +36,13 @@
40//usage: "\n -s Display only a total for each argument" 36//usage: "\n -s Display only a total for each argument"
41//usage: "\n -x Skip directories on different filesystems" 37//usage: "\n -x Skip directories on different filesystems"
42//usage: IF_FEATURE_HUMAN_READABLE( 38//usage: IF_FEATURE_HUMAN_READABLE(
43//usage: "\n -h Sizes in human readable format (e.g., 1K 243M 2G )" 39//usage: "\n -h Sizes in human readable format (e.g., 1K 243M 2G)"
44//usage: "\n -m Sizes in megabytes" 40//usage: "\n -m Sizes in megabytes"
45//usage: ) 41//usage: )
46//usage: "\n -k Sizes in kilobytes" 42//usage: "\n -k Sizes in kilobytes" IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(" (default)")
47//usage: IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(" (default)") 43//usage: IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(
44//usage: "\n Default unit is 512 bytes"
45//usage: )
48//usage: 46//usage:
49//usage:#define du_example_usage 47//usage:#define du_example_usage
50//usage: "$ du\n" 48//usage: "$ du\n"
@@ -91,7 +89,7 @@ struct globals {
91#define INIT_G() do { } while (0) 89#define INIT_G() do { } while (0)
92 90
93 91
94static void print(unsigned long size, const char *filename) 92static void print(unsigned long long size, const char *filename)
95{ 93{
96 /* TODO - May not want to defer error checking here. */ 94 /* TODO - May not want to defer error checking here. */
97#if ENABLE_FEATURE_HUMAN_READABLE 95#if ENABLE_FEATURE_HUMAN_READABLE
@@ -105,15 +103,15 @@ static void print(unsigned long size, const char *filename)
105 size++; 103 size++;
106 size >>= 1; 104 size >>= 1;
107 } 105 }
108 printf("%lu\t%s\n", size, filename); 106 printf("%llu\t%s\n", size, filename);
109#endif 107#endif
110} 108}
111 109
112/* tiny recursive du */ 110/* tiny recursive du */
113static unsigned long du(const char *filename) 111static unsigned long long du(const char *filename)
114{ 112{
115 struct stat statbuf; 113 struct stat statbuf;
116 unsigned long sum; 114 unsigned long long sum;
117 115
118 if (lstat(filename, &statbuf) != 0) { 116 if (lstat(filename, &statbuf) != 0) {
119 bb_simple_perror_msg(filename); 117 bb_simple_perror_msg(filename);
@@ -190,7 +188,7 @@ static unsigned long du(const char *filename)
190int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 188int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
191int du_main(int argc UNUSED_PARAM, char **argv) 189int du_main(int argc UNUSED_PARAM, char **argv)
192{ 190{
193 unsigned long total; 191 unsigned long long total;
194 int slink_depth_save; 192 int slink_depth_save;
195 unsigned opt; 193 unsigned opt;
196 194
diff --git a/coreutils/ln.c b/coreutils/ln.c
index 88a9a8f91..0eb3e6579 100644
--- a/coreutils/ln.c
+++ b/coreutils/ln.c
@@ -69,8 +69,8 @@ int ln_main(int argc, char **argv)
69 src = last; 69 src = last;
70 70
71 if (is_directory(src, 71 if (is_directory(src,
72 (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE, 72 (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE
73 NULL) 73 )
74 ) { 74 ) {
75 src_name = xstrdup(*argv); 75 src_name = xstrdup(*argv);
76 src = concat_path_file(src, bb_get_last_path_component_strip(src_name)); 76 src = concat_path_file(src, bb_get_last_path_component_strip(src_name));
diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c
index a4429b1cb..b33b6bba3 100644
--- a/coreutils/mkdir.c
+++ b/coreutils/mkdir.c
@@ -54,7 +54,7 @@ static const char mkdir_longopts[] ALIGN1 =
54int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 54int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
55int mkdir_main(int argc UNUSED_PARAM, char **argv) 55int mkdir_main(int argc UNUSED_PARAM, char **argv)
56{ 56{
57 mode_t mode = (mode_t)(-1); 57 long mode = -1;
58 int status = EXIT_SUCCESS; 58 int status = EXIT_SUCCESS;
59 int flags = 0; 59 int flags = 0;
60 unsigned opt; 60 unsigned opt;
@@ -68,10 +68,11 @@ int mkdir_main(int argc UNUSED_PARAM, char **argv)
68#endif 68#endif
69 opt = getopt32(argv, "m:p" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); 69 opt = getopt32(argv, "m:p" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext));
70 if (opt & 1) { 70 if (opt & 1) {
71 mode = 0777; 71 mode_t mmode = 0777;
72 if (!bb_parse_mode(smode, &mode)) { 72 if (!bb_parse_mode(smode, &mmode)) {
73 bb_error_msg_and_die("invalid mode '%s'", smode); 73 bb_error_msg_and_die("invalid mode '%s'", smode);
74 } 74 }
75 mode = mmode;
75 } 76 }
76 if (opt & 2) 77 if (opt & 2)
77 flags |= FILEUTILS_RECUR; 78 flags |= FILEUTILS_RECUR;
diff --git a/coreutils/printf.c b/coreutils/printf.c
index f53aa4787..3dd43a978 100644
--- a/coreutils/printf.c
+++ b/coreutils/printf.c
@@ -36,13 +36,12 @@
36 David MacKenzie <djm@gnu.ai.mit.edu> 36 David MacKenzie <djm@gnu.ai.mit.edu>
37*/ 37*/
38 38
39// 19990508 Busy Boxed! Dave Cinege 39/* 19990508 Busy Boxed! Dave Cinege */
40 40
41//usage:#define printf_trivial_usage 41//usage:#define printf_trivial_usage
42//usage: "FORMAT [ARGUMENT]..." 42//usage: "FORMAT [ARG]..."
43//usage:#define printf_full_usage "\n\n" 43//usage:#define printf_full_usage "\n\n"
44//usage: "Format and print ARGUMENT(s) according to FORMAT,\n" 44//usage: "Format and print ARG(s) according to FORMAT (a-la C printf)"
45//usage: "where FORMAT controls the output exactly as in C printf"
46//usage: 45//usage:
47//usage:#define printf_example_usage 46//usage:#define printf_example_usage
48//usage: "$ printf \"Val=%d\\n\" 5\n" 47//usage: "$ printf \"Val=%d\\n\" 5\n"
@@ -132,13 +131,28 @@ static double my_xstrtod(const char *arg)
132 return result; 131 return result;
133} 132}
134 133
134/* Handles %b */
135static void print_esc_string(const char *str) 135static void print_esc_string(const char *str)
136{ 136{
137 char c; 137 char c;
138 while ((c = *str) != '\0') { 138 while ((c = *str) != '\0') {
139 str++; 139 str++;
140 if (c == '\\') 140 if (c == '\\') {
141 c = bb_process_escape_sequence(&str); 141 /* %b also accepts 4-digit octals of the form \0### */
142 if (*str == '0') {
143 if ((unsigned char)(str[1] - '0') < 8) {
144 /* 2nd char is 0..7: skip leading '0' */
145 str++;
146 }
147 }
148 {
149 /* optimization: don't force arg to be on-stack,
150 * use another variable for that. */
151 const char *z = str;
152 c = bb_process_escape_sequence(&z);
153 str = z;
154 }
155 }
142 putchar(c); 156 putchar(c);
143 } 157 }
144} 158}
diff --git a/coreutils/test.c b/coreutils/test.c
index 2e896f4c7..ccfa923da 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -737,7 +737,8 @@ static number_t nexpr(enum token n)
737 if (n == EOI) { 737 if (n == EOI) {
738 /* special case: [ ! ], [ a -a ! ] are valid */ 738 /* special case: [ ! ], [ a -a ! ] are valid */
739 /* IOW, "! ARG" may miss ARG */ 739 /* IOW, "! ARG" may miss ARG */
740 unnest_msg("<nexpr:1 (!EOI)\n"); 740 args--;
741 unnest_msg("<nexpr:1 (!EOI), args:%s(%p)\n", args[0], &args[0]);
741 return 1; 742 return 1;
742 } 743 }
743 res = !nexpr(n); 744 res = !nexpr(n);
@@ -756,15 +757,15 @@ static number_t aexpr(enum token n)
756 757
757 nest_msg(">aexpr(%s)\n", TOKSTR[n]); 758 nest_msg(">aexpr(%s)\n", TOKSTR[n]);
758 res = nexpr(n); 759 res = nexpr(n);
759 dbg_msg("aexpr: nexpr:%lld, next args:%s\n", res, args[1]); 760 dbg_msg("aexpr: nexpr:%lld, next args:%s(%p)\n", res, args[1], &args[1]);
760 if (check_operator(*++args) == BAND) { 761 if (check_operator(*++args) == BAND) {
761 dbg_msg("aexpr: arg is AND, next args:%s\n", args[1]); 762 dbg_msg("aexpr: arg is AND, next args:%s(%p)\n", args[1], &args[1]);
762 res = aexpr(check_operator(*++args)) && res; 763 res = aexpr(check_operator(*++args)) && res;
763 unnest_msg("<aexpr:%lld\n", res); 764 unnest_msg("<aexpr:%lld\n", res);
764 return res; 765 return res;
765 } 766 }
766 args--; 767 args--;
767 unnest_msg("<aexpr:%lld, args:%s\n", res, args[0]); 768 unnest_msg("<aexpr:%lld, args:%s(%p)\n", res, args[0], &args[0]);
768 return res; 769 return res;
769} 770}
770 771
@@ -775,15 +776,15 @@ static number_t oexpr(enum token n)
775 776
776 nest_msg(">oexpr(%s)\n", TOKSTR[n]); 777 nest_msg(">oexpr(%s)\n", TOKSTR[n]);
777 res = aexpr(n); 778 res = aexpr(n);
778 dbg_msg("oexpr: aexpr:%lld, next args:%s\n", res, args[1]); 779 dbg_msg("oexpr: aexpr:%lld, next args:%s(%p)\n", res, args[1], &args[1]);
779 if (check_operator(*++args) == BOR) { 780 if (check_operator(*++args) == BOR) {
780 dbg_msg("oexpr: next arg is OR, next args:%s\n", args[1]); 781 dbg_msg("oexpr: next arg is OR, next args:%s(%p)\n", args[1], &args[1]);
781 res = oexpr(check_operator(*++args)) || res; 782 res = oexpr(check_operator(*++args)) || res;
782 unnest_msg("<oexpr:%lld\n", res); 783 unnest_msg("<oexpr:%lld\n", res);
783 return res; 784 return res;
784 } 785 }
785 args--; 786 args--;
786 unnest_msg("<oexpr:%lld, args:%s\n", res, args[0]); 787 unnest_msg("<oexpr:%lld, args:%s(%p)\n", res, args[0], &args[0]);
787 return res; 788 return res;
788} 789}
789 790
diff --git a/coreutils/touch.c b/coreutils/touch.c
index 0f980fd7b..1216ca202 100644
--- a/coreutils/touch.c
+++ b/coreutils/touch.c
@@ -7,7 +7,7 @@
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9 9
10/* BB_AUDIT SUSv3 _NOT_ compliant -- options -a, -m, -r, -t not supported. */ 10/* BB_AUDIT SUSv3 _NOT_ compliant -- options -a, -m not supported. */
11/* http://www.opengroup.org/onlinepubs/007904975/utilities/touch.html */ 11/* http://www.opengroup.org/onlinepubs/007904975/utilities/touch.html */
12 12
13/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) 13/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
@@ -25,18 +25,26 @@
25//config: help 25//config: help
26//config: touch is used to create or change the access and/or 26//config: touch is used to create or change the access and/or
27//config: modification timestamp of specified files. 27//config: modification timestamp of specified files.
28//config:
29//config:config FEATURE_TOUCH_SUSV3
30//config: bool "Add support for SUSV3 features (-d -t -r)"
31//config: default y
32//config: depends on TOUCH
33//config: help
34//config: Enable touch to use a reference file or a given date/time argument.
28 35
29//applet:IF_TOUCH(APPLET_NOFORK(touch, touch, BB_DIR_BIN, BB_SUID_DROP, touch)) 36//applet:IF_TOUCH(APPLET_NOFORK(touch, touch, BB_DIR_BIN, BB_SUID_DROP, touch))
30 37
31//kbuild:lib-$(CONFIG_TOUCH) += touch.o 38//kbuild:lib-$(CONFIG_TOUCH) += touch.o
32 39
33//usage:#define touch_trivial_usage 40//usage:#define touch_trivial_usage
34//usage: "[-c]" IF_DESKTOP(" [-d DATE] [-r FILE]") " FILE [FILE]..." 41//usage: "[-c]" IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") " FILE..."
35//usage:#define touch_full_usage "\n\n" 42//usage:#define touch_full_usage "\n\n"
36//usage: "Update the last-modified date on the given FILE[s]\n" 43//usage: "Update the last-modified date on the given FILE[s]\n"
37//usage: "\n -c Don't create files" 44//usage: "\n -c Don't create files"
38//usage: IF_DESKTOP( 45//usage: IF_FEATURE_TOUCH_SUSV3(
39//usage: "\n -d DT Date/time to use" 46//usage: "\n -d DT Date/time to use"
47//usage: "\n -t DT Date/time to use"
40//usage: "\n -r FILE Use FILE's date/time" 48//usage: "\n -r FILE Use FILE's date/time"
41//usage: ) 49//usage: )
42//usage: 50//usage:
@@ -71,7 +79,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
71 int fd; 79 int fd;
72 int status = EXIT_SUCCESS; 80 int status = EXIT_SUCCESS;
73 int opts; 81 int opts;
74#if ENABLE_DESKTOP 82#if ENABLE_FEATURE_TOUCH_SUSV3
75# if ENABLE_LONG_OPTS 83# if ENABLE_LONG_OPTS
76 static const char touch_longopts[] ALIGN1 = 84 static const char touch_longopts[] ALIGN1 =
77 /* name, has_arg, val */ 85 /* name, has_arg, val */
@@ -90,17 +98,17 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
90# define timebuf ((struct timeval*)NULL) 98# define timebuf ((struct timeval*)NULL)
91#endif 99#endif
92 100
93#if ENABLE_DESKTOP && ENABLE_LONG_OPTS 101#if ENABLE_FEATURE_TOUCH_SUSV3 && ENABLE_LONG_OPTS
94 applet_long_options = touch_longopts; 102 applet_long_options = touch_longopts;
95#endif 103#endif
96 /* -d and -t both set time. In coreutils, 104 /* -d and -t both set time. In coreutils,
97 * accepted data format differs a bit between -d and -t. 105 * accepted data format differs a bit between -d and -t.
98 * We accept the same formats for both */ 106 * We accept the same formats for both */
99 opts = getopt32(argv, "c" IF_DESKTOP("r:d:t:") 107 opts = getopt32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:")
100 /*ignored:*/ "fma" 108 /*ignored:*/ "fma"
101 IF_DESKTOP(, &reference_file) 109 IF_FEATURE_TOUCH_SUSV3(, &reference_file)
102 IF_DESKTOP(, &date_str) 110 IF_FEATURE_TOUCH_SUSV3(, &date_str)
103 IF_DESKTOP(, &date_str) 111 IF_FEATURE_TOUCH_SUSV3(, &date_str)
104 ); 112 );
105 113
106 opts &= 1; /* only -c bit is left */ 114 opts &= 1; /* only -c bit is left */
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c
index 23ff711fa..b298fcb95 100644
--- a/coreutils/uudecode.c
+++ b/coreutils/uudecode.c
@@ -15,7 +15,7 @@
15//usage: "[-o OUTFILE] [INFILE]" 15//usage: "[-o OUTFILE] [INFILE]"
16//usage:#define uudecode_full_usage "\n\n" 16//usage:#define uudecode_full_usage "\n\n"
17//usage: "Uudecode a file\n" 17//usage: "Uudecode a file\n"
18//usage: "Finds outfile name in uuencoded source unless -o is given" 18//usage: "Finds OUTFILE in uuencoded source unless -o is given"
19//usage: 19//usage:
20//usage:#define uudecode_example_usage 20//usage:#define uudecode_example_usage
21//usage: "$ uudecode -o busybox busybox.uu\n" 21//usage: "$ uudecode -o busybox busybox.uu\n"
diff --git a/coreutils/uuencode.c b/coreutils/uuencode.c
index 84a489a11..673ef36e7 100644
--- a/coreutils/uuencode.c
+++ b/coreutils/uuencode.c
@@ -9,9 +9,9 @@
9 */ 9 */
10 10
11//usage:#define uuencode_trivial_usage 11//usage:#define uuencode_trivial_usage
12//usage: "[-m] [INFILE] STORED_FILENAME" 12//usage: "[-m] [FILE] STORED_FILENAME"
13//usage:#define uuencode_full_usage "\n\n" 13//usage:#define uuencode_full_usage "\n\n"
14//usage: "Uuencode a file to stdout\n" 14//usage: "Uuencode FILE (or stdin) to stdout\n"
15//usage: "\n -m Use base64 encoding per RFC1521" 15//usage: "\n -m Use base64 encoding per RFC1521"
16//usage: 16//usage:
17//usage:#define uuencode_example_usage 17//usage:#define uuencode_example_usage
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c
index 02609c04f..7dadc3c9e 100644
--- a/debianutils/start_stop_daemon.c
+++ b/debianutils/start_stop_daemon.c
@@ -31,7 +31,8 @@ Options controlling process matching
31[TODO: can PROCESS_NAME be a full pathname? Should we require full match then 31[TODO: can PROCESS_NAME be a full pathname? Should we require full match then
32with /proc/$PID/exe or argv[0] (comm can't be matched, it never contains path)] 32with /proc/$PID/exe or argv[0] (comm can't be matched, it never contains path)]
33 -x,--exec EXECUTABLE Look for processes that were started with this 33 -x,--exec EXECUTABLE Look for processes that were started with this
34 command in /proc/$PID/cmdline. 34 command in /proc/$PID/exe and /proc/$PID/cmdline
35 (/proc/$PID/cmdline is a bbox extension)
35 Unlike -n, we match against the full path: 36 Unlike -n, we match against the full path:
36 "ntpd" != "./ntpd" != "/path/to/ntpd" 37 "ntpd" != "./ntpd" != "/path/to/ntpd"
37 -p,--pidfile PID_FILE Look for processes with PID from this file 38 -p,--pidfile PID_FILE Look for processes with PID from this file
@@ -68,7 +69,7 @@ Misc options:
68//usage: "\n -n,--name NAME Match processes with NAME" 69//usage: "\n -n,--name NAME Match processes with NAME"
69//usage: "\n in comm field in /proc/PID/stat" 70//usage: "\n in comm field in /proc/PID/stat"
70//usage: "\n -x,--exec EXECUTABLE Match processes with this command" 71//usage: "\n -x,--exec EXECUTABLE Match processes with this command"
71//usage: "\n in /proc/PID/cmdline" 72//usage: "\n in /proc/PID/{exe,cmdline}"
72//usage: "\n -p,--pidfile FILE Match a process with PID from the file" 73//usage: "\n -p,--pidfile FILE Match a process with PID from the file"
73//usage: "\n All specified conditions must match" 74//usage: "\n All specified conditions must match"
74//usage: "\n-S only:" 75//usage: "\n-S only:"
@@ -198,8 +199,18 @@ static int pid_is_exec(pid_t pid)
198{ 199{
199 ssize_t bytes; 200 ssize_t bytes;
200 char buf[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; 201 char buf[sizeof("/proc/%u/cmdline") + sizeof(int)*3];
202 char *procname, *exelink;
203 int match;
201 204
202 sprintf(buf, "/proc/%u/cmdline", (unsigned)pid); 205 procname = buf + sprintf(buf, "/proc/%u/exe", (unsigned)pid) - 3;
206
207 exelink = xmalloc_readlink(buf);
208 match = (exelink && strcmp(execname, exelink) == 0);
209 free(exelink);
210 if (match)
211 return match;
212
213 strcpy(procname, "cmdline");
203 bytes = open_read_close(buf, G.execname_cmpbuf, G.execname_sizeof); 214 bytes = open_read_close(buf, G.execname_cmpbuf, G.execname_sizeof);
204 if (bytes > 0) { 215 if (bytes > 0) {
205 G.execname_cmpbuf[bytes] = '\0'; 216 G.execname_cmpbuf[bytes] = '\0';
@@ -474,7 +485,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
474 *--argv = startas; 485 *--argv = startas;
475 if (opt & OPT_BACKGROUND) { 486 if (opt & OPT_BACKGROUND) {
476#if BB_MMU 487#if BB_MMU
477 bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); 488 bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK);
478 /* DAEMON_DEVNULL_STDIO is superfluous - 489 /* DAEMON_DEVNULL_STDIO is superfluous -
479 * it's always done by bb_daemonize() */ 490 * it's always done by bb_daemonize() */
480#else 491#else
diff --git a/e2fsprogs/old_e2fsprogs/blkid/probe.c b/e2fsprogs/old_e2fsprogs/blkid/probe.c
index 77bfc737d..651193b42 100644
--- a/e2fsprogs/old_e2fsprogs/blkid/probe.c
+++ b/e2fsprogs/old_e2fsprogs/blkid/probe.c
@@ -575,8 +575,12 @@ blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev)
575 printf("need to revalidate %s (time since last check %lu)\n", 575 printf("need to revalidate %s (time since last check %lu)\n",
576 dev->bid_name, diff)); 576 dev->bid_name, diff));
577 577
578 if (((fd = open(dev->bid_name, O_RDONLY)) < 0) || 578 fd = open(dev->bid_name, O_RDONLY);
579 (fstat(fd, &st) < 0)) { 579 if (fd < 0
580 || fstat(fd, &st) < 0
581 ) {
582 if (fd >= 0)
583 close(fd);
580 if (errno == ENXIO || errno == ENODEV || errno == ENOENT) { 584 if (errno == ENXIO || errno == ENODEV || errno == ENOENT) {
581 blkid_free_dev(dev); 585 blkid_free_dev(dev);
582 return NULL; 586 return NULL;
@@ -653,6 +657,7 @@ try_again:
653 657
654 if (!dev->bid_type) { 658 if (!dev->bid_type) {
655 blkid_free_dev(dev); 659 blkid_free_dev(dev);
660 close(fd);
656 return NULL; 661 return NULL;
657 } 662 }
658 663
diff --git a/editors/sed.c b/editors/sed.c
index c8bb503ea..4e9babb9d 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -282,7 +282,7 @@ static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str)
282static int parse_regex_delim(const char *cmdstr, char **match, char **replace) 282static int parse_regex_delim(const char *cmdstr, char **match, char **replace)
283{ 283{
284 const char *cmdstr_ptr = cmdstr; 284 const char *cmdstr_ptr = cmdstr;
285 char delimiter; 285 unsigned char delimiter;
286 int idx = 0; 286 int idx = 0;
287 287
288 /* verify that the 's' or 'y' is followed by something. That something 288 /* verify that the 's' or 'y' is followed by something. That something
@@ -297,7 +297,7 @@ static int parse_regex_delim(const char *cmdstr, char **match, char **replace)
297 297
298 /* save the replacement string */ 298 /* save the replacement string */
299 cmdstr_ptr += idx + 1; 299 cmdstr_ptr += idx + 1;
300 idx = index_of_next_unescaped_regexp_delim(-delimiter, cmdstr_ptr); 300 idx = index_of_next_unescaped_regexp_delim(- (int)delimiter, cmdstr_ptr);
301 *replace = copy_parsing_escapes(cmdstr_ptr, idx); 301 *replace = copy_parsing_escapes(cmdstr_ptr, idx);
302 302
303 return ((cmdstr_ptr - cmdstr) + idx); 303 return ((cmdstr_ptr - cmdstr) + idx);
@@ -322,10 +322,11 @@ static int get_address(const char *my_str, int *linenum, regex_t ** regex)
322 char *temp; 322 char *temp;
323 323
324 delimiter = '/'; 324 delimiter = '/';
325 if (*my_str == '\\') delimiter = *++pos; 325 if (*my_str == '\\')
326 delimiter = *++pos;
326 next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); 327 next = index_of_next_unescaped_regexp_delim(delimiter, ++pos);
327 temp = copy_parsing_escapes(pos, next); 328 temp = copy_parsing_escapes(pos, next);
328 *regex = xmalloc(sizeof(regex_t)); 329 *regex = xzalloc(sizeof(regex_t));
329 xregcomp(*regex, temp, G.regex_type|REG_NEWLINE); 330 xregcomp(*regex, temp, G.regex_type|REG_NEWLINE);
330 free(temp); 331 free(temp);
331 /* Move position to next character after last delimiter */ 332 /* Move position to next character after last delimiter */
@@ -434,8 +435,10 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
434 /* compile the match string into a regex */ 435 /* compile the match string into a regex */
435 if (*match != '\0') { 436 if (*match != '\0') {
436 /* If match is empty, we use last regex used at runtime */ 437 /* If match is empty, we use last regex used at runtime */
437 sed_cmd->sub_match = xmalloc(sizeof(regex_t)); 438 sed_cmd->sub_match = xzalloc(sizeof(regex_t));
439 dbg("xregcomp('%s',%x)", match, cflags);
438 xregcomp(sed_cmd->sub_match, match, cflags); 440 xregcomp(sed_cmd->sub_match, match, cflags);
441 dbg("regcomp ok");
439 } 442 }
440 free(match); 443 free(match);
441 444
@@ -717,8 +720,12 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p)
717 G.previous_regex_ptr = current_regex; 720 G.previous_regex_ptr = current_regex;
718 721
719 /* Find the first match */ 722 /* Find the first match */
720 if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) 723 dbg("matching '%s'", line);
724 if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) {
725 dbg("no match");
721 return 0; 726 return 0;
727 }
728 dbg("match");
722 729
723 /* Initialize temporary output buffer. */ 730 /* Initialize temporary output buffer. */
724 G.pipeline.buf = xmalloc(PIPE_GROW); 731 G.pipeline.buf = xmalloc(PIPE_GROW);
@@ -730,9 +737,10 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p)
730 int i; 737 int i;
731 738
732 /* Work around bug in glibc regexec, demonstrated by: 739 /* Work around bug in glibc regexec, demonstrated by:
733 echo " a.b" | busybox sed 's [^ .]* x g' 740 * echo " a.b" | busybox sed 's [^ .]* x g'
734 The match_count check is so not to break 741 * The match_count check is so not to break
735 echo "hi" | busybox sed 's/^/!/g' */ 742 * echo "hi" | busybox sed 's/^/!/g'
743 */
736 if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) { 744 if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) {
737 pipe_putc(*line++); 745 pipe_putc(*line++);
738 continue; 746 continue;
@@ -763,11 +771,14 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p)
763 altered++; 771 altered++;
764 772
765 /* if we're not doing this globally, get out now */ 773 /* if we're not doing this globally, get out now */
766 if (sed_cmd->which_match) 774 if (sed_cmd->which_match != 0)
775 break;
776
777 if (*line == '\0')
767 break; 778 break;
768 779
769//maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? 780//maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL?
770 } while (*line && regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); 781 } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH);
771 782
772 /* Copy rest of string into output pipeline */ 783 /* Copy rest of string into output pipeline */
773 while (1) { 784 while (1) {
@@ -1067,8 +1078,8 @@ static void process_files(void)
1067 } 1078 }
1068 1079
1069 /* actual sedding */ 1080 /* actual sedding */
1070 //bb_error_msg("pattern_space:'%s' next_line:'%s' cmd:%c", 1081 dbg("pattern_space:'%s' next_line:'%s' cmd:%c",
1071 //pattern_space, next_line, sed_cmd->cmd); 1082 pattern_space, next_line, sed_cmd->cmd);
1072 switch (sed_cmd->cmd) { 1083 switch (sed_cmd->cmd) {
1073 1084
1074 /* Print line number */ 1085 /* Print line number */
@@ -1115,6 +1126,7 @@ static void process_files(void)
1115 case 's': 1126 case 's':
1116 if (!do_subst_command(sed_cmd, &pattern_space)) 1127 if (!do_subst_command(sed_cmd, &pattern_space))
1117 break; 1128 break;
1129 dbg("do_subst_command succeeeded:'%s'", pattern_space);
1118 substituted |= 1; 1130 substituted |= 1;
1119 1131
1120 /* handle p option */ 1132 /* handle p option */
diff --git a/editors/vi.c b/editors/vi.c
index d6d926e35..6fae221ac 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -278,7 +278,6 @@ struct globals {
278 smallint cmd_mode; // 0=command 1=insert 2=replace 278 smallint cmd_mode; // 0=command 1=insert 2=replace
279 int file_modified; // buffer contents changed (counter, not flag!) 279 int file_modified; // buffer contents changed (counter, not flag!)
280 int last_file_modified; // = -1; 280 int last_file_modified; // = -1;
281 int fn_start; // index of first cmd line file name
282 int save_argc; // how many file names on cmd line 281 int save_argc; // how many file names on cmd line
283 int cmdcnt; // repetition count 282 int cmdcnt; // repetition count
284 unsigned rows, columns; // the terminal screen is this size 283 unsigned rows, columns; // the terminal screen is this size
@@ -363,7 +362,6 @@ struct globals {
363#define cmd_mode (G.cmd_mode ) 362#define cmd_mode (G.cmd_mode )
364#define file_modified (G.file_modified ) 363#define file_modified (G.file_modified )
365#define last_file_modified (G.last_file_modified ) 364#define last_file_modified (G.last_file_modified )
366#define fn_start (G.fn_start )
367#define save_argc (G.save_argc ) 365#define save_argc (G.save_argc )
368#define cmdcnt (G.cmdcnt ) 366#define cmdcnt (G.cmdcnt )
369#define rows (G.rows ) 367#define rows (G.rows )
@@ -599,9 +597,10 @@ int vi_main(int argc, char **argv)
599 } 597 }
600 598
601 // The argv array can be used by the ":next" and ":rewind" commands 599 // The argv array can be used by the ":next" and ":rewind" commands
602 // save optind. 600 argv += optind;
603 fn_start = optind; // remember first file name for :next and :rew 601 argc -= optind;
604 save_argc = argc; 602 save_argc = argc;
603 optind = 0;
605 604
606 //----- This is the main file handling loop -------------- 605 //----- This is the main file handling loop --------------
607 while (1) { 606 while (1) {
@@ -1021,7 +1020,7 @@ static void colon(char *buf)
1021 } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file 1020 } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file
1022 // don't edit, if the current file has been modified 1021 // don't edit, if the current file has been modified
1023 if (file_modified && !useforce) { 1022 if (file_modified && !useforce) {
1024 status_line_bold("No write since last change (:edit! overrides)"); 1023 status_line_bold("No write since last change (:%s! overrides)", cmd);
1025 goto ret; 1024 goto ret;
1026 } 1025 }
1027 if (args[0]) { 1026 if (args[0]) {
@@ -1040,13 +1039,13 @@ static void colon(char *buf)
1040 goto ret; 1039 goto ret;
1041 1040
1042#if ENABLE_FEATURE_VI_YANKMARK 1041#if ENABLE_FEATURE_VI_YANKMARK
1043 if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { 1042 if (Ureg >= 0 && Ureg < 28) {
1044 free(reg[Ureg]); // free orig line reg- for 'U' 1043 free(reg[Ureg]); // free orig line reg- for 'U'
1045 reg[Ureg]= 0; 1044 reg[Ureg] = NULL;
1046 } 1045 }
1047 if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) { 1046 if (YDreg >= 0 && YDreg < 28) {
1048 free(reg[YDreg]); // free default yank/delete register 1047 free(reg[YDreg]); // free default yank/delete register
1049 reg[YDreg]= 0; 1048 reg[YDreg] = NULL;
1050 } 1049 }
1051#endif 1050#endif
1052 // how many lines in text[]? 1051 // how many lines in text[]?
@@ -1111,11 +1110,12 @@ static void colon(char *buf)
1111 Hit_Return(); 1110 Hit_Return();
1112 } else if (strncmp(cmd, "quit", i) == 0 // quit 1111 } else if (strncmp(cmd, "quit", i) == 0 // quit
1113 || strncmp(cmd, "next", i) == 0 // edit next file 1112 || strncmp(cmd, "next", i) == 0 // edit next file
1113 || strncmp(cmd, "prev", i) == 0 // edit previous file
1114 ) { 1114 ) {
1115 int n; 1115 int n;
1116 if (useforce) { 1116 if (useforce) {
1117 // force end of argv list
1118 if (*cmd == 'q') { 1117 if (*cmd == 'q') {
1118 // force end of argv list
1119 optind = save_argc; 1119 optind = save_argc;
1120 } 1120 }
1121 editing = 0; 1121 editing = 0;
@@ -1123,8 +1123,7 @@ static void colon(char *buf)
1123 } 1123 }
1124 // don't exit if the file been modified 1124 // don't exit if the file been modified
1125 if (file_modified) { 1125 if (file_modified) {
1126 status_line_bold("No write since last change (:%s! overrides)", 1126 status_line_bold("No write since last change (:%s! overrides)", cmd);
1127 (*cmd == 'q' ? "quit" : "next"));
1128 goto ret; 1127 goto ret;
1129 } 1128 }
1130 // are there other file to edit 1129 // are there other file to edit
@@ -1137,6 +1136,14 @@ static void colon(char *buf)
1137 status_line_bold("No more files to edit"); 1136 status_line_bold("No more files to edit");
1138 goto ret; 1137 goto ret;
1139 } 1138 }
1139 if (*cmd == 'p') {
1140 // are there previous files to edit
1141 if (optind < 1) {
1142 status_line_bold("No previous files to edit");
1143 goto ret;
1144 }
1145 optind -= 2;
1146 }
1140 editing = 0; 1147 editing = 0;
1141 } else if (strncmp(cmd, "read", i) == 0) { // read file into text[] 1148 } else if (strncmp(cmd, "read", i) == 0) { // read file into text[]
1142 fn = args; 1149 fn = args;
@@ -1172,10 +1179,10 @@ static void colon(char *buf)
1172 } 1179 }
1173 } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args 1180 } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args
1174 if (file_modified && !useforce) { 1181 if (file_modified && !useforce) {
1175 status_line_bold("No write since last change (:rewind! overrides)"); 1182 status_line_bold("No write since last change (:%s! overrides)", cmd);
1176 } else { 1183 } else {
1177 // reset the filenames to edit 1184 // reset the filenames to edit
1178 optind = fn_start - 1; 1185 optind = -1; /* start from 0th file */
1179 editing = 0; 1186 editing = 0;
1180 } 1187 }
1181#if ENABLE_FEATURE_VI_SET 1188#if ENABLE_FEATURE_VI_SET
@@ -1225,51 +1232,53 @@ static void colon(char *buf)
1225#endif /* FEATURE_VI_SET */ 1232#endif /* FEATURE_VI_SET */
1226#if ENABLE_FEATURE_VI_SEARCH 1233#if ENABLE_FEATURE_VI_SEARCH
1227 } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern 1234 } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern
1228 char *ls, *F, *R; 1235 char *F, *R, *flags;
1229 int gflag; 1236 size_t len_F, len_R;
1237 int gflag; // global replace flag
1230 1238
1231 // F points to the "find" pattern 1239 // F points to the "find" pattern
1232 // R points to the "replace" pattern 1240 // R points to the "replace" pattern
1233 // replace the cmd line delimiters "/" with NULLs 1241 // replace the cmd line delimiters "/" with NULs
1234 gflag = 0; // global replace flag
1235 c = orig_buf[1]; // what is the delimiter 1242 c = orig_buf[1]; // what is the delimiter
1236 F = orig_buf + 2; // start of "find" 1243 F = orig_buf + 2; // start of "find"
1237 R = strchr(F, c); // middle delimiter 1244 R = strchr(F, c); // middle delimiter
1238 if (!R) 1245 if (!R)
1239 goto colon_s_fail; 1246 goto colon_s_fail;
1247 len_F = R - F;
1240 *R++ = '\0'; // terminate "find" 1248 *R++ = '\0'; // terminate "find"
1241 buf1 = strchr(R, c); 1249 flags = strchr(R, c);
1242 if (!buf1) 1250 if (!flags)
1243 goto colon_s_fail; 1251 goto colon_s_fail;
1244 *buf1++ = '\0'; // terminate "replace" 1252 len_R = flags - R;
1245 if (*buf1 == 'g') { // :s/foo/bar/g 1253 *flags++ = '\0'; // terminate "replace"
1246 buf1++; 1254 gflag = *flags;
1247 gflag++; // turn on gflag 1255
1248 }
1249 q = begin_line(q); 1256 q = begin_line(q);
1250 if (b < 0) { // maybe :s/foo/bar/ 1257 if (b < 0) { // maybe :s/foo/bar/
1251 q = begin_line(dot); // start with cur line 1258 q = begin_line(dot); // start with cur line
1252 b = count_lines(text, q); // cur line number 1259 b = count_lines(text, q); // cur line number
1253 } 1260 }
1254 if (e < 0) 1261 if (e < 0)
1255 e = b; // maybe :.s/foo/bar/ 1262 e = b; // maybe :.s/foo/bar/
1263
1256 for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 1264 for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0
1257 ls = q; // orig line start 1265 char *ls = q; // orig line start
1266 char *found;
1258 vc4: 1267 vc4:
1259 buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" 1268 found = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find"
1260 if (buf1) { 1269 if (found) {
1261 uintptr_t bias; 1270 uintptr_t bias;
1262 // we found the "find" pattern - delete it 1271 // we found the "find" pattern - delete it
1263 text_hole_delete(buf1, buf1 + strlen(F) - 1); 1272 text_hole_delete(found, found + len_F - 1);
1264 // inset the "replace" patern 1273 // inset the "replace" patern
1265 bias = string_insert(buf1, R); // insert the string 1274 bias = string_insert(found, R); // insert the string
1266 buf1 += bias; 1275 found += bias;
1267 ls += bias; 1276 ls += bias;
1268 /*q += bias; - recalculated anyway */ 1277 /*q += bias; - recalculated anyway */
1269 // check for "global" :s/foo/bar/g 1278 // check for "global" :s/foo/bar/g
1270 if (gflag == 1) { 1279 if (gflag == 'g') {
1271 if ((buf1 + strlen(R)) < end_line(ls)) { 1280 if ((found + len_R) < end_line(ls)) {
1272 q = buf1 + strlen(R); 1281 q = found + len_R;
1273 goto vc4; // don't let q move past cur line 1282 goto vc4; // don't let q move past cur line
1274 } 1283 }
1275 } 1284 }
@@ -2073,6 +2082,14 @@ static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte
2073 dot += bias; 2082 dot += bias;
2074 end += bias; 2083 end += bias;
2075 p += bias; 2084 p += bias;
2085#if ENABLE_FEATURE_VI_YANKMARK
2086 {
2087 int i;
2088 for (i = 0; i < ARRAY_SIZE(mark); i++)
2089 if (mark[i])
2090 mark[i] += bias;
2091 }
2092#endif
2076 text = new_text; 2093 text = new_text;
2077 } 2094 }
2078 memmove(p + size, p, end - size - p); 2095 memmove(p + size, p, end - size - p);
@@ -2304,7 +2321,7 @@ static void rawmode(void)
2304{ 2321{
2305 tcgetattr(0, &term_orig); 2322 tcgetattr(0, &term_orig);
2306 term_vi = term_orig; 2323 term_vi = term_orig;
2307 term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's 2324 term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG on - allow intr's
2308 term_vi.c_iflag &= (~IXON & ~ICRNL); 2325 term_vi.c_iflag &= (~IXON & ~ICRNL);
2309 term_vi.c_oflag &= (~ONLCR); 2326 term_vi.c_oflag &= (~ONLCR);
2310 term_vi.c_cc[VMIN] = 1; 2327 term_vi.c_cc[VMIN] = 1;
@@ -3314,7 +3331,7 @@ static void do_cmd(int c)
3314 end_cmd_q(); // stop adding to q 3331 end_cmd_q(); // stop adding to q
3315 break; 3332 break;
3316 case 'U': // U- Undo; replace current line with original version 3333 case 'U': // U- Undo; replace current line with original version
3317 if (reg[Ureg] != 0) { 3334 if (reg[Ureg] != NULL) {
3318 p = begin_line(dot); 3335 p = begin_line(dot);
3319 q = end_line(dot); 3336 q = end_line(dot);
3320 p = text_hole_delete(p, q); // delete cur line 3337 p = text_hole_delete(p, q); // delete cur line
@@ -3328,7 +3345,7 @@ static void do_cmd(int c)
3328 case KEYCODE_END: // Cursor Key End 3345 case KEYCODE_END: // Cursor Key End
3329 for (;;) { 3346 for (;;) {
3330 dot = end_line(dot); 3347 dot = end_line(dot);
3331 if (--cmdcnt > 0) 3348 if (--cmdcnt <= 0)
3332 break; 3349 break;
3333 dot_next(); 3350 dot_next();
3334 } 3351 }
@@ -3506,7 +3523,7 @@ static void do_cmd(int c)
3506 || strncmp(p, "q!", cnt) == 0 // delete lines 3523 || strncmp(p, "q!", cnt) == 0 // delete lines
3507 ) { 3524 ) {
3508 if (file_modified && p[1] != '!') { 3525 if (file_modified && p[1] != '!') {
3509 status_line_bold("No write since last change (:quit! overrides)"); 3526 status_line_bold("No write since last change (:%s! overrides)", p);
3510 } else { 3527 } else {
3511 editing = 0; 3528 editing = 0;
3512 } 3529 }
diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf
index cd2957ccc..eca44c0ab 100644
--- a/examples/udhcp/udhcpd.conf
+++ b/examples/udhcp/udhcpd.conf
@@ -68,6 +68,8 @@ opt wins 192.168.10.10
68option dns 129.219.13.81 # appended to above DNS servers for a total of 3 68option dns 129.219.13.81 # appended to above DNS servers for a total of 3
69option domain local 69option domain local
70option lease 864000 # default: 10 days 70option lease 864000 # default: 10 days
71option msstaticroutes 10.0.0.0/8 10.127.0.1 # single static route
72option staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
71# Arbitrary option in hex form: 73# Arbitrary option in hex form:
72option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" 74option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4"
73 75
@@ -101,6 +103,8 @@ option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4"
101#opt swapsrv IP 103#opt swapsrv IP
102# Options specifying routes 104# Options specifying routes
103#opt routes IP_PAIR_LIST 105#opt routes IP_PAIR_LIST
106#opt staticroutes STATIC_ROUTES # RFC 3442 classless static route option
107#opt msstaticroutes STATIC_ROUTES # same, using MS option number
104# Obsolete options, no longer supported 108# Obsolete options, no longer supported
105#opt logsrv IP_LIST # 704/UDP log server (not syslog!) 109#opt logsrv IP_LIST # 704/UDP log server (not syslog!)
106#opt namesrv IP_LIST # IEN 116 name server, obsolete (August 1979!!!) 110#opt namesrv IP_LIST # IEN 116 name server, obsolete (August 1979!!!)
@@ -109,5 +113,3 @@ option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4"
109# TODO: in development 113# TODO: in development
110#opt userclass STRING # RFC 3004. set of LASCII strings. "I am a printer" etc 114#opt userclass STRING # RFC 3004. set of LASCII strings. "I am a printer" etc
111#opt sipserv STRING LIST # RFC 3361. flag byte, then: 0: domain names, 1: IP addrs 115#opt sipserv STRING LIST # RFC 3361. flag byte, then: 0: domain names, 1: IP addrs
112#opt staticroutes STATIC_ROUTES
113#opt msstaticroutes STATIC_ROUTES
diff --git a/findutils/grep.c b/findutils/grep.c
index f3463f94e..5b8ae3bff 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -85,6 +85,7 @@
85//usage: "\n -r Recurse" 85//usage: "\n -r Recurse"
86//usage: "\n -i Ignore case" 86//usage: "\n -i Ignore case"
87//usage: "\n -w Match whole words only" 87//usage: "\n -w Match whole words only"
88//usage: "\n -x Match whole lines only"
88//usage: "\n -F PATTERN is a literal (not regexp)" 89//usage: "\n -F PATTERN is a literal (not regexp)"
89//usage: IF_FEATURE_GREP_EGREP_ALIAS( 90//usage: IF_FEATURE_GREP_EGREP_ALIAS(
90//usage: "\n -E PATTERN is an extended regexp" 91//usage: "\n -E PATTERN is an extended regexp"
@@ -113,7 +114,7 @@
113//usage:#define fgrep_full_usage "" 114//usage:#define fgrep_full_usage ""
114 115
115#define OPTSTR_GREP \ 116#define OPTSTR_GREP \
116 "lnqvscFiHhe:f:Lorm:w" \ 117 "lnqvscFiHhe:f:Lorm:wx" \
117 IF_FEATURE_GREP_CONTEXT("A:B:C:") \ 118 IF_FEATURE_GREP_CONTEXT("A:B:C:") \
118 IF_FEATURE_GREP_EGREP_ALIAS("E") \ 119 IF_FEATURE_GREP_EGREP_ALIAS("E") \
119 IF_EXTRA_COMPAT("z") \ 120 IF_EXTRA_COMPAT("z") \
@@ -138,6 +139,7 @@ enum {
138 OPTBIT_r, /* recurse dirs */ 139 OPTBIT_r, /* recurse dirs */
139 OPTBIT_m, /* -m MAX_MATCHES */ 140 OPTBIT_m, /* -m MAX_MATCHES */
140 OPTBIT_w, /* -w whole word match */ 141 OPTBIT_w, /* -w whole word match */
142 OPTBIT_x, /* -x whole line match */
141 IF_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */ 143 IF_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */
142 IF_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */ 144 IF_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */
143 IF_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */ 145 IF_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */
@@ -160,6 +162,7 @@ enum {
160 OPT_r = 1 << OPTBIT_r, 162 OPT_r = 1 << OPTBIT_r,
161 OPT_m = 1 << OPTBIT_m, 163 OPT_m = 1 << OPTBIT_m,
162 OPT_w = 1 << OPTBIT_w, 164 OPT_w = 1 << OPTBIT_w,
165 OPT_x = 1 << OPTBIT_x,
163 OPT_A = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0, 166 OPT_A = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0,
164 OPT_B = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0, 167 OPT_B = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0,
165 OPT_C = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0, 168 OPT_C = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0,
@@ -378,9 +381,12 @@ static int grep_file(FILE *file)
378 &gl->matched_range) >= 0 381 &gl->matched_range) >= 0
379#endif 382#endif
380 ) { 383 ) {
381 if (!(option_mask32 & OPT_w)) 384 if (option_mask32 & OPT_x) {
385 found = (gl->matched_range.rm_so == 0
386 && line[gl->matched_range.rm_eo] == '\0');
387 } else if (!(option_mask32 & OPT_w)) {
382 found = 1; 388 found = 1;
383 else { 389 } else {
384 char c = ' '; 390 char c = ' ';
385 if (gl->matched_range.rm_so) 391 if (gl->matched_range.rm_so)
386 c = line[gl->matched_range.rm_so - 1]; 392 c = line[gl->matched_range.rm_so - 1];
diff --git a/include/bb_archive.h b/include/bb_archive.h
index 9e176d335..2043d8570 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -12,9 +12,10 @@ enum {
12 /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ 12 /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */
13 /* More info at: http://tukaani.org/xz/xz-file-format.txt */ 13 /* More info at: http://tukaani.org/xz/xz-file-format.txt */
14 XZ_MAGIC1 = 256 * 0xfd + '7', 14 XZ_MAGIC1 = 256 * 0xfd + '7',
15 XZ_MAGIC2 = 256 * (256 * (256 * 'z' + 'X') + 'Z') + 0, 15 XZ_MAGIC2 = 256 * (unsigned)(256 * (256 * 'z' + 'X') + 'Z') + 0,
16 /* Different form: 32 bits, then 16 bits: */ 16 /* Different form: 32 bits, then 16 bits: */
17 XZ_MAGIC1a = 256 * (256 * (256 * 0xfd + '7') + 'z') + 'X', 17 /* (unsigned) cast suppresses "integer overflow in expression" warning */
18 XZ_MAGIC1a = 256 * (unsigned)(256 * (256 * 0xfd + '7') + 'z') + 'X',
18 XZ_MAGIC2a = 256 * 'Z' + 0, 19 XZ_MAGIC2a = 256 * 'Z' + 0,
19#else 20#else
20 COMPRESS_MAGIC = 0x9d1f, 21 COMPRESS_MAGIC = 0x9d1f,
@@ -76,19 +77,20 @@ typedef struct archive_handle_t {
76 off_t offset; 77 off_t offset;
77 78
78 /* Archiver specific. Can make it a union if it ever gets big */ 79 /* Archiver specific. Can make it a union if it ever gets big */
80#define PAX_NEXT_FILE 0
81#define PAX_GLOBAL 1
79#if ENABLE_TAR || ENABLE_DPKG || ENABLE_DPKG_DEB 82#if ENABLE_TAR || ENABLE_DPKG || ENABLE_DPKG_DEB
80 smallint tar__end; 83 smallint tar__end;
81# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS 84# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
82 char* tar__longname; 85 char* tar__longname;
83 char* tar__linkname; 86 char* tar__linkname;
84# endif 87# endif
85#if ENABLE_FEATURE_TAR_TO_COMMAND 88# if ENABLE_FEATURE_TAR_TO_COMMAND
86 char* tar__to_command; 89 char* tar__to_command;
87 const char* tar__to_command_shell; 90 const char* tar__to_command_shell;
88#endif 91# endif
89# if ENABLE_FEATURE_TAR_SELINUX 92# if ENABLE_FEATURE_TAR_SELINUX
90 char* tar__global_sctx; 93 char* tar__sctx[2];
91 char* tar__next_file_sctx;
92# endif 94# endif
93#endif 95#endif
94#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM 96#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM
@@ -154,12 +156,6 @@ struct BUG_tar_header {
154 156
155 157
156 158
157/* Info struct unpackers can fill out to inform users of thing like
158 * timestamps of unpacked files */
159typedef struct unpack_info_t {
160 time_t mtime;
161} unpack_info_t;
162
163archive_handle_t *init_handle(void) FAST_FUNC; 159archive_handle_t *init_handle(void) FAST_FUNC;
164 160
165char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC; 161char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC;
@@ -202,40 +198,47 @@ int start_bunzip(bunzip_data **bdp, int in_fd, const void *inbuf, int len) FAST_
202int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; 198int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC;
203void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; 199void dealloc_bunzip(bunzip_data *bd) FAST_FUNC;
204 200
205typedef struct inflate_unzip_result { 201/* Meaning and direction (input/output) of the fields are transformer-specific */
206 off_t bytes_out; 202typedef struct transformer_aux_data_t {
207 uint32_t crc; 203 smallint check_signature; /* most often referenced member */
208} inflate_unzip_result; 204 off_t bytes_out;
209 205 off_t bytes_in; /* used in unzip code only: needs to know packed size */
210IF_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC; 206 uint32_t crc32;
211/* xz unpacker takes .xz stream from offset 6 */ 207 time_t mtime; /* gunzip code may set this on exit */
212IF_DESKTOP(long long) int unpack_xz_stream(int src_fd, int dst_fd) FAST_FUNC; 208} transformer_aux_data_t;
213/* lzma unpacker takes .lzma stream from offset 0 */ 209
214IF_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; 210void init_transformer_aux_data(transformer_aux_data_t *aux) FAST_FUNC;
215/* the rest wants 2 first bytes already skipped by the caller */ 211int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) FAST_FUNC;
216IF_DESKTOP(long long) int unpack_bz2_stream(int src_fd, int dst_fd) FAST_FUNC; 212
217IF_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd) FAST_FUNC; 213IF_DESKTOP(long long) int inflate_unzip(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
218IF_DESKTOP(long long) int unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) FAST_FUNC; 214IF_DESKTOP(long long) int unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
219IF_DESKTOP(long long) int unpack_Z_stream(int src_fd, int dst_fd) FAST_FUNC; 215IF_DESKTOP(long long) int unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
220/* wrapper which checks first two bytes to be "BZ" */ 216IF_DESKTOP(long long) int unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
221IF_DESKTOP(long long) int unpack_bz2_stream_prime(int src_fd, int dst_fd) FAST_FUNC; 217IF_DESKTOP(long long) int unpack_lzma_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
218IF_DESKTOP(long long) int unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC;
222 219
223char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; 220char* append_ext(char *filename, const char *expected_ext) FAST_FUNC;
224int bbunpack(char **argv, 221int bbunpack(char **argv,
225 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(unpack_info_t *info), 222 IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux),
226 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), 223 char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
227 const char *expected_ext 224 const char *expected_ext
228) FAST_FUNC; 225) FAST_FUNC;
229 226
227void check_errors_in_children(int signo);
230#if BB_MMU 228#if BB_MMU
231void open_transformer(int fd, 229void open_transformer(int fd,
232 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd)) FAST_FUNC; 230 int check_signature,
233#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transformer) 231 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd)
232) FAST_FUNC;
233#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), 1, (transformer))
234#define open_transformer_with_no_sig(fd, transformer) open_transformer((fd), 0, (transformer))
234#else 235#else
235void open_transformer(int src_fd, const char *transform_prog) FAST_FUNC; 236void open_transformer(int fd, const char *transform_prog) FAST_FUNC;
236#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transform_prog) 237#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), (transform_prog))
238/* open_transformer_with_no_sig() does not exist on NOMMU */
237#endif 239#endif
238 240
241
239POP_SAVED_FUNCTION_VISIBILITY 242POP_SAVED_FUNCTION_VISIBILITY
240 243
241#endif 244#endif
diff --git a/include/grp_.h b/include/grp_.h
index 5c24d558a..82ad90492 100644
--- a/include/grp_.h
+++ b/include/grp_.h
@@ -29,7 +29,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
29 * We will use libc-defined structures, but will #define function names 29 * We will use libc-defined structures, but will #define function names
30 * so that function calls are directed to bb_internal_XXX replacements 30 * so that function calls are directed to bb_internal_XXX replacements
31 */ 31 */
32 32#undef endgrent
33#define setgrent bb_internal_setgrent 33#define setgrent bb_internal_setgrent
34#define endgrent bb_internal_endgrent 34#define endgrent bb_internal_endgrent
35#define getgrent bb_internal_getgrent 35#define getgrent bb_internal_getgrent
diff --git a/include/libbb.h b/include/libbb.h
index a6ecac932..e776951f0 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -51,6 +51,20 @@
51#include <termios.h> 51#include <termios.h>
52#include <time.h> 52#include <time.h>
53#include <sys/param.h> 53#include <sys/param.h>
54#include <pwd.h>
55#include <grp.h>
56#if ENABLE_FEATURE_SHADOWPASSWDS
57# if !ENABLE_USE_BB_SHADOW
58/* If using busybox's shadow implementation, do not include the shadow.h
59 * header as the toolchain may not provide it at all.
60 */
61# include <shadow.h>
62# endif
63#endif
64#if defined(ANDROID) || defined(__ANDROID__)
65# define endpwent() ((void)0)
66# define endgrent() ((void)0)
67#endif
54#ifdef HAVE_MNTENT_H 68#ifdef HAVE_MNTENT_H
55# include <mntent.h> 69# include <mntent.h>
56#endif 70#endif
@@ -80,16 +94,6 @@
80#ifdef DMALLOC 94#ifdef DMALLOC
81# include <dmalloc.h> 95# include <dmalloc.h>
82#endif 96#endif
83#include <pwd.h>
84#include <grp.h>
85#if ENABLE_FEATURE_SHADOWPASSWDS
86# if !ENABLE_USE_BB_SHADOW
87/* If using busybox's shadow implementation, do not include the shadow.h
88 * header as the toolchain may not provide it at all.
89 */
90# include <shadow.h>
91# endif
92#endif
93/* Just in case libc doesn't define some of these... */ 97/* Just in case libc doesn't define some of these... */
94#ifndef _PATH_PASSWD 98#ifndef _PATH_PASSWD
95#define _PATH_PASSWD "/etc/passwd" 99#define _PATH_PASSWD "/etc/passwd"
@@ -224,7 +228,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
224# if ULONG_MAX > 0xffffffff 228# if ULONG_MAX > 0xffffffff
225/* "long" is long enough on this system */ 229/* "long" is long enough on this system */
226typedef unsigned long uoff_t; 230typedef unsigned long uoff_t;
227# define XATOOFF(a) xatoul_range(a, 0, LONG_MAX) 231# define XATOOFF(a) xatoul_range((a), 0, LONG_MAX)
228/* usage: sz = BB_STRTOOFF(s, NULL, 10); if (errno || sz < 0) die(); */ 232/* usage: sz = BB_STRTOOFF(s, NULL, 10); if (errno || sz < 0) die(); */
229# define BB_STRTOOFF bb_strtoul 233# define BB_STRTOOFF bb_strtoul
230# define STRTOOFF strtoul 234# define STRTOOFF strtoul
@@ -233,7 +237,7 @@ typedef unsigned long uoff_t;
233# else 237# else
234/* "long" is too short, need "long long" */ 238/* "long" is too short, need "long long" */
235typedef unsigned long long uoff_t; 239typedef unsigned long long uoff_t;
236# define XATOOFF(a) xatoull_range(a, 0, LLONG_MAX) 240# define XATOOFF(a) xatoull_range((a), 0, LLONG_MAX)
237# define BB_STRTOOFF bb_strtoull 241# define BB_STRTOOFF bb_strtoull
238# define STRTOOFF strtoull 242# define STRTOOFF strtoull
239# define OFF_FMT "ll" 243# define OFF_FMT "ll"
@@ -250,7 +254,7 @@ typedef unsigned long uoff_t;
250# define OFF_FMT "l" 254# define OFF_FMT "l"
251# else 255# else
252typedef unsigned long uoff_t; 256typedef unsigned long uoff_t;
253# define XATOOFF(a) xatoul_range(a, 0, LONG_MAX) 257# define XATOOFF(a) xatoul_range((a), 0, LONG_MAX)
254# define BB_STRTOOFF bb_strtoul 258# define BB_STRTOOFF bb_strtoul
255# define STRTOOFF strtol 259# define STRTOOFF strtol
256# define OFF_FMT "l" 260# define OFF_FMT "l"
@@ -258,6 +262,12 @@ typedef unsigned long uoff_t;
258#endif 262#endif
259/* scary. better ideas? (but do *test* them first!) */ 263/* scary. better ideas? (but do *test* them first!) */
260#define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1))) 264#define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1)))
265/* Users report bionic to use 32-bit off_t even if LARGEFILE support is requested.
266 * We misdetected that. Don't let it build:
267 */
268struct BUG_off_t_size_is_misdetected {
269 char BUG_off_t_size_is_misdetected[sizeof(off_t) == sizeof(uoff_t) ? 1 : -1];
270};
261 271
262/* Some useful definitions */ 272/* Some useful definitions */
263#undef FALSE 273#undef FALSE
@@ -321,7 +331,7 @@ extern char *strrstr(const char *haystack, const char *needle) FAST_FUNC;
321 331
322//TODO: supply a pointer to char[11] buffer (avoid statics)? 332//TODO: supply a pointer to char[11] buffer (avoid statics)?
323extern const char *bb_mode_string(mode_t mode) FAST_FUNC; 333extern const char *bb_mode_string(mode_t mode) FAST_FUNC;
324extern int is_directory(const char *name, int followLinks, struct stat *statBuf) FAST_FUNC; 334extern int is_directory(const char *name, int followLinks) FAST_FUNC;
325enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */ 335enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */
326 FILEUTILS_PRESERVE_STATUS = 1 << 0, /* -p */ 336 FILEUTILS_PRESERVE_STATUS = 1 << 0, /* -p */
327 FILEUTILS_DEREFERENCE = 1 << 1, /* !-d */ 337 FILEUTILS_DEREFERENCE = 1 << 1, /* !-d */
@@ -571,12 +581,7 @@ enum {
571 * and if kernel doesn't support it, fall back to IPv4. 581 * and if kernel doesn't support it, fall back to IPv4.
572 * This is useful if you plan to bind to resulting local lsa. 582 * This is useful if you plan to bind to resulting local lsa.
573 */ 583 */
574#if ENABLE_FEATURE_IPV6
575int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC; 584int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC;
576#else
577int xsocket_type(len_and_sockaddr **lsap, int sock_type) FAST_FUNC;
578#define xsocket_type(lsap, af, sock_type) xsocket_type((lsap), (sock_type))
579#endif
580int xsocket_stream(len_and_sockaddr **lsap) FAST_FUNC; 585int xsocket_stream(len_and_sockaddr **lsap) FAST_FUNC;
581/* Create server socket bound to bindaddr:port. bindaddr can be NULL, 586/* Create server socket bound to bindaddr:port. bindaddr can be NULL,
582 * numeric IP ("N.N.N.N") or numeric IPv6 address, 587 * numeric IP ("N.N.N.N") or numeric IPv6 address,
@@ -721,17 +726,23 @@ extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
721extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 726extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
722/* Never returns NULL */ 727/* Never returns NULL */
723extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 728extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
724/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ 729
725#if ENABLE_FEATURE_SEAMLESS_LZMA \ 730#define SEAMLESS_COMPRESSION (0 \
731 || ENABLE_FEATURE_SEAMLESS_XZ \
732 || ENABLE_FEATURE_SEAMLESS_LZMA \
726 || ENABLE_FEATURE_SEAMLESS_BZ2 \ 733 || ENABLE_FEATURE_SEAMLESS_BZ2 \
727 || ENABLE_FEATURE_SEAMLESS_GZ \ 734 || ENABLE_FEATURE_SEAMLESS_GZ \
728 /* || ENABLE_FEATURE_SEAMLESS_Z */ 735 || ENABLE_FEATURE_SEAMLESS_Z)
729extern void setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) FAST_FUNC; 736
730#else 737#if SEAMLESS_COMPRESSION
731# define setup_unzip_on_fd(...) ((void)0) 738/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */
732#endif 739extern int setup_unzip_on_fd(int fd, int fail_if_not_detected) FAST_FUNC;
733/* Autodetects .gz etc */ 740/* Autodetects .gz etc */
734extern int open_zipped(const char *fname) FAST_FUNC; 741extern int open_zipped(const char *fname) FAST_FUNC;
742#else
743# define setup_unzip_on_fd(...) (0)
744# define open_zipped(fname) open((fname), O_RDONLY);
745#endif
735extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 746extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
736 747
737extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC; 748extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC;
@@ -982,6 +993,7 @@ enum {
982 DAEMON_DEVNULL_STDIO = 2, 993 DAEMON_DEVNULL_STDIO = 2,
983 DAEMON_CLOSE_EXTRA_FDS = 4, 994 DAEMON_CLOSE_EXTRA_FDS = 4,
984 DAEMON_ONLY_SANITIZE = 8, /* internal use */ 995 DAEMON_ONLY_SANITIZE = 8, /* internal use */
996 DAEMON_DOUBLE_FORK = 16, /* double fork to avoid controlling tty */
985}; 997};
986#if BB_MMU 998#if BB_MMU
987 enum { re_execed = 0 }; 999 enum { re_execed = 0 };
@@ -990,6 +1002,9 @@ enum {
990# define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) 1002# define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus)
991#else 1003#else
992 extern bool re_execed; 1004 extern bool re_execed;
1005 /* Note: re_exec() and fork_or_rexec() do argv[0][0] |= 0x80 on NOMMU!
1006 * _Parent_ needs to undo it if it doesn't want to have argv[0] mangled.
1007 */
993 void re_exec(char **argv) NORETURN FAST_FUNC; 1008 void re_exec(char **argv) NORETURN FAST_FUNC;
994 pid_t fork_or_rexec(char **argv) FAST_FUNC; 1009 pid_t fork_or_rexec(char **argv) FAST_FUNC;
995 int BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC; 1010 int BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC;
@@ -1197,13 +1212,14 @@ enum {
1197 PARSE_MIN_DIE = 0x00100000, // die if < min tokens found 1212 PARSE_MIN_DIE = 0x00100000, // die if < min tokens found
1198 // keep a copy of current line 1213 // keep a copy of current line
1199 PARSE_KEEP_COPY = 0x00200000 * ENABLE_FEATURE_CROND_D, 1214 PARSE_KEEP_COPY = 0x00200000 * ENABLE_FEATURE_CROND_D,
1200// PARSE_ESCAPE = 0x00400000, // process escape sequences in tokens 1215 PARSE_EOL_COMMENTS = 0x00400000, // comments are recognized even if they aren't the first char
1201 // NORMAL is: 1216 // NORMAL is:
1202 // * remove leading and trailing delimiters and collapse 1217 // * remove leading and trailing delimiters and collapse
1203 // multiple delimiters into one 1218 // multiple delimiters into one
1204 // * warn and continue if less than mintokens delimiters found 1219 // * warn and continue if less than mintokens delimiters found
1205 // * grab everything into last token 1220 // * grab everything into last token
1206 PARSE_NORMAL = PARSE_COLLAPSE | PARSE_TRIM | PARSE_GREEDY, 1221 // * comments are recognized even if they aren't the first char
1222 PARSE_NORMAL = PARSE_COLLAPSE | PARSE_TRIM | PARSE_GREEDY | PARSE_EOL_COMMENTS,
1207}; 1223};
1208typedef struct parser_t { 1224typedef struct parser_t {
1209 FILE *fp; 1225 FILE *fp;
diff --git a/include/pwd_.h b/include/pwd_.h
index e40b71dab..ea158da45 100644
--- a/include/pwd_.h
+++ b/include/pwd_.h
@@ -30,7 +30,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
30 * We will use libc-defined structures, but will #define function names 30 * We will use libc-defined structures, but will #define function names
31 * so that function calls are directed to bb_internal_XXX replacements 31 * so that function calls are directed to bb_internal_XXX replacements
32 */ 32 */
33 33#undef endpwent
34#define setpwent bb_internal_setpwent 34#define setpwent bb_internal_setpwent
35#define endpwent bb_internal_endpwent 35#define endpwent bb_internal_endpwent
36#define getpwent bb_internal_getpwent 36#define getpwent bb_internal_getpwent
diff --git a/include/volume_id.h b/include/volume_id.h
index 4a78cd1e4..a83da899e 100644
--- a/include/volume_id.h
+++ b/include/volume_id.h
@@ -20,7 +20,7 @@
20 20
21char *get_devname_from_label(const char *spec); 21char *get_devname_from_label(const char *spec);
22char *get_devname_from_uuid(const char *spec); 22char *get_devname_from_uuid(const char *spec);
23void display_uuid_cache(void); 23void display_uuid_cache(int scan_devices);
24 24
25/* Returns: 25/* Returns:
26 * 0: no UUID= or LABEL= prefix found 26 * 0: no UUID= or LABEL= prefix found
diff --git a/include/xatonum.h b/include/xatonum.h
index 6f76a3c96..45ebbfc00 100644
--- a/include/xatonum.h
+++ b/include/xatonum.h
@@ -168,6 +168,15 @@ uint32_t bb_strtou32(const char *arg, char **endp, int base)
168 return bb_strtoul(arg, endp, base); 168 return bb_strtoul(arg, endp, base);
169 return BUG_bb_strtou32_unimplemented(); 169 return BUG_bb_strtou32_unimplemented();
170} 170}
171static ALWAYS_INLINE
172int32_t bb_strtoi32(const char *arg, char **endp, int base)
173{
174 if (sizeof(int32_t) == sizeof(int))
175 return bb_strtoi(arg, endp, base);
176 if (sizeof(int32_t) == sizeof(long))
177 return bb_strtol(arg, endp, base);
178 return BUG_bb_strtou32_unimplemented();
179}
171 180
172/* Floating point */ 181/* Floating point */
173 182
diff --git a/init/bootchartd.c b/init/bootchartd.c
index 5f6121fa4..9fd623357 100644
--- a/init/bootchartd.c
+++ b/init/bootchartd.c
@@ -208,14 +208,8 @@ static char *make_tempdir(void)
208 return tempdir; 208 return tempdir;
209} 209}
210 210
211static void do_logging(unsigned sample_period_us) 211static void do_logging(unsigned sample_period_us, int process_accounting)
212{ 212{
213 //# Enable process accounting if configured
214 //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then
215 // [ -e kernel_pacct ] || : > kernel_pacct
216 // accton kernel_pacct
217 //fi
218
219 FILE *proc_stat = xfopen("proc_stat.log", "w"); 213 FILE *proc_stat = xfopen("proc_stat.log", "w");
220 FILE *proc_diskstats = xfopen("proc_diskstats.log", "w"); 214 FILE *proc_diskstats = xfopen("proc_diskstats.log", "w");
221 //FILE *proc_netdev = xfopen("proc_netdev.log", "w"); 215 //FILE *proc_netdev = xfopen("proc_netdev.log", "w");
@@ -223,6 +217,11 @@ static void do_logging(unsigned sample_period_us)
223 int look_for_login_process = (getppid() == 1); 217 int look_for_login_process = (getppid() == 1);
224 unsigned count = 60*1000*1000 / sample_period_us; /* ~1 minute */ 218 unsigned count = 60*1000*1000 / sample_period_us; /* ~1 minute */
225 219
220 if (process_accounting) {
221 close(xopen("kernel_pacct", O_WRONLY | O_CREAT | O_TRUNC));
222 acct("kernel_pacct");
223 }
224
226 while (--count && !bb_got_signal) { 225 while (--count && !bb_got_signal) {
227 char *p; 226 char *p;
228 int len = open_read_close("/proc/uptime", G.jiffy_line, sizeof(G.jiffy_line)-2); 227 int len = open_read_close("/proc/uptime", G.jiffy_line, sizeof(G.jiffy_line)-2);
@@ -253,11 +252,9 @@ static void do_logging(unsigned sample_period_us)
253 wait_more: 252 wait_more:
254 usleep(sample_period_us); 253 usleep(sample_period_us);
255 } 254 }
256
257 // [ -e kernel_pacct ] && accton off
258} 255}
259 256
260static void finalize(char *tempdir, const char *prog) 257static void finalize(char *tempdir, const char *prog, int process_accounting)
261{ 258{
262 //# Stop process accounting if configured 259 //# Stop process accounting if configured
263 //local pacct= 260 //local pacct=
@@ -265,6 +262,9 @@ static void finalize(char *tempdir, const char *prog)
265 262
266 FILE *header_fp = xfopen("header", "w"); 263 FILE *header_fp = xfopen("header", "w");
267 264
265 if (process_accounting)
266 acct(NULL);
267
268 if (prog) 268 if (prog)
269 fprintf(header_fp, "profile.process = %s\n", prog); 269 fprintf(header_fp, "profile.process = %s\n", prog);
270 270
@@ -307,7 +307,7 @@ static void finalize(char *tempdir, const char *prog)
307 fclose(header_fp); 307 fclose(header_fp);
308 308
309 /* Package log files */ 309 /* Package log files */
310 system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct 310 system(xasprintf("tar -zcf /var/log/bootlog.tgz header %s *.log", process_accounting ? "kernel_pacct" : ""));
311 /* Clean up (if we are not in detached tmpfs) */ 311 /* Clean up (if we are not in detached tmpfs) */
312 if (tempdir) { 312 if (tempdir) {
313 unlink("header"); 313 unlink("header");
@@ -315,6 +315,8 @@ static void finalize(char *tempdir, const char *prog)
315 unlink("proc_diskstats.log"); 315 unlink("proc_diskstats.log");
316 //unlink("proc_netdev.log"); 316 //unlink("proc_netdev.log");
317 unlink("proc_ps.log"); 317 unlink("proc_ps.log");
318 if (process_accounting)
319 unlink("kernel_pacct");
318 rmdir(tempdir); 320 rmdir(tempdir);
319 } 321 }
320 322
@@ -338,6 +340,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
338 unsigned sample_period_us; 340 unsigned sample_period_us;
339 pid_t parent_pid, logger_pid; 341 pid_t parent_pid, logger_pid;
340 smallint cmd; 342 smallint cmd;
343 int process_accounting;
341 enum { 344 enum {
342 CMD_STOP = 0, 345 CMD_STOP = 0,
343 CMD_START, 346 CMD_START,
@@ -371,6 +374,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
371 374
372 /* Read config file: */ 375 /* Read config file: */
373 sample_period_us = 200 * 1000; 376 sample_period_us = 200 * 1000;
377 process_accounting = 0;
374 if (ENABLE_FEATURE_BOOTCHARTD_CONFIG_FILE) { 378 if (ENABLE_FEATURE_BOOTCHARTD_CONFIG_FILE) {
375 char* token[2]; 379 char* token[2];
376 parser_t *parser = config_open2("/etc/bootchartd.conf" + 5, fopen_for_read); 380 parser_t *parser = config_open2("/etc/bootchartd.conf" + 5, fopen_for_read);
@@ -379,11 +383,16 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
379 while (config_read(parser, token, 2, 0, "#=", PARSE_NORMAL & ~PARSE_COLLAPSE)) { 383 while (config_read(parser, token, 2, 0, "#=", PARSE_NORMAL & ~PARSE_COLLAPSE)) {
380 if (strcmp(token[0], "SAMPLE_PERIOD") == 0 && token[1]) 384 if (strcmp(token[0], "SAMPLE_PERIOD") == 0 && token[1])
381 sample_period_us = atof(token[1]) * 1000000; 385 sample_period_us = atof(token[1]) * 1000000;
386 if (strcmp(token[0], "PROCESS_ACCOUNTING") == 0 && token[1]
387 && (strcmp(token[1], "on") == 0 || strcmp(token[1], "yes") == 0)
388 ) {
389 process_accounting = 1;
390 }
382 } 391 }
383 config_close(parser); 392 config_close(parser);
393 if ((int)sample_period_us <= 0)
394 sample_period_us = 1; /* prevent division by 0 */
384 } 395 }
385 if ((int)sample_period_us <= 0)
386 sample_period_us = 1; /* prevent division by 0 */
387 396
388 /* Create logger child: */ 397 /* Create logger child: */
389 logger_pid = fork_or_rexec(argv); 398 logger_pid = fork_or_rexec(argv);
@@ -411,13 +420,15 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
411 putenv((char*)bb_PATH_root_path); 420 putenv((char*)bb_PATH_root_path);
412 421
413 tempdir = make_tempdir(); 422 tempdir = make_tempdir();
414 do_logging(sample_period_us); 423 do_logging(sample_period_us, process_accounting);
415 finalize(tempdir, cmd == CMD_START ? argv[2] : NULL); 424 finalize(tempdir, cmd == CMD_START ? argv[2] : NULL, process_accounting);
416 return EXIT_SUCCESS; 425 return EXIT_SUCCESS;
417 } 426 }
418 427
419 /* parent */ 428 /* parent */
420 429
430 USE_FOR_NOMMU(argv[0][0] &= 0x7f); /* undo fork_or_rexec() damage */
431
421 if (DO_SIGNAL_SYNC) { 432 if (DO_SIGNAL_SYNC) {
422 /* Wait for logger child to set handlers, then unpause it. 433 /* Wait for logger child to set handlers, then unpause it.
423 * Otherwise with short-lived PROG (e.g. "bootchartd start true") 434 * Otherwise with short-lived PROG (e.g. "bootchartd start true")
diff --git a/init/init.c b/init/init.c
index 645f694c0..724894698 100644
--- a/init/init.c
+++ b/init/init.c
@@ -108,6 +108,8 @@
108//config: Note that on Linux, init attempts to detect serial terminal and 108//config: Note that on Linux, init attempts to detect serial terminal and
109//config: sets TERM to "vt102" if one is found. 109//config: sets TERM to "vt102" if one is found.
110 110
111#define DEBUG_SEGV_HANDLER 0
112
111#include "libbb.h" 113#include "libbb.h"
112#include <syslog.h> 114#include <syslog.h>
113#include <paths.h> 115#include <paths.h>
@@ -118,6 +120,15 @@
118#endif 120#endif
119#include "reboot.h" /* reboot() constants */ 121#include "reboot.h" /* reboot() constants */
120 122
123#if DEBUG_SEGV_HANDLER
124# undef _GNU_SOURCE
125# define _GNU_SOURCE 1
126# undef __USE_GNU
127# define __USE_GNU 1
128# include <execinfo.h>
129# include <sys/ucontext.h>
130#endif
131
121/* Used only for sanitizing purposes in set_sane_term() below. On systems where 132/* Used only for sanitizing purposes in set_sane_term() below. On systems where
122 * the baud rate is stored in a separate field, we can safely disable them. */ 133 * the baud rate is stored in a separate field, we can safely disable them. */
123#ifndef CBAUD 134#ifndef CBAUD
@@ -523,15 +534,17 @@ static struct init_action *mark_terminated(pid_t pid)
523 struct init_action *a; 534 struct init_action *a;
524 535
525 if (pid > 0) { 536 if (pid > 0) {
537 update_utmp(pid, DEAD_PROCESS,
538 /*tty_name:*/ NULL,
539 /*username:*/ NULL,
540 /*hostname:*/ NULL
541 );
526 for (a = init_action_list; a; a = a->next) { 542 for (a = init_action_list; a; a = a->next) {
527 if (a->pid == pid) { 543 if (a->pid == pid) {
528 a->pid = 0; 544 a->pid = 0;
529 return a; 545 return a;
530 } 546 }
531 } 547 }
532 update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL,
533 /*username:*/ NULL,
534 /*hostname:*/ NULL);
535 } 548 }
536 return NULL; 549 return NULL;
537} 550}
@@ -596,7 +609,7 @@ static void new_init_action(uint8_t action_type, const char *command, const char
596 */ 609 */
597 nextp = &init_action_list; 610 nextp = &init_action_list;
598 while ((a = *nextp) != NULL) { 611 while ((a = *nextp) != NULL) {
599 /* Don't enter action if it's already in the list, 612 /* Don't enter action if it's already in the list.
600 * This prevents losing running RESPAWNs. 613 * This prevents losing running RESPAWNs.
601 */ 614 */
602 if (strcmp(a->command, command) == 0 615 if (strcmp(a->command, command) == 0
@@ -608,14 +621,15 @@ static void new_init_action(uint8_t action_type, const char *command, const char
608 while (*nextp != NULL) 621 while (*nextp != NULL)
609 nextp = &(*nextp)->next; 622 nextp = &(*nextp)->next;
610 a->next = NULL; 623 a->next = NULL;
611 break; 624 goto append;
612 } 625 }
613 nextp = &a->next; 626 nextp = &a->next;
614 } 627 }
615 628
616 if (!a) 629 a = xzalloc(sizeof(*a));
617 a = xzalloc(sizeof(*a)); 630
618 /* Append to the end of the list */ 631 /* Append to the end of the list */
632 append:
619 *nextp = a; 633 *nextp = a;
620 a->action_type = action_type; 634 a->action_type = action_type;
621 safe_strncpy(a->command, command, sizeof(a->command)); 635 safe_strncpy(a->command, command, sizeof(a->command));
@@ -954,6 +968,33 @@ static int check_delayed_sigs(void)
954 } 968 }
955} 969}
956 970
971#if DEBUG_SEGV_HANDLER
972static
973void handle_sigsegv(int sig, siginfo_t *info, void *ucontext)
974{
975 long ip;
976 ucontext_t *uc;
977
978 uc = ucontext;
979 ip = uc->uc_mcontext.gregs[REG_EIP];
980 fdprintf(2, "signal:%d address:0x%lx ip:0x%lx\n",
981 sig,
982 /* this is void*, but using %p would print "(null)"
983 * even for ptrs which are not exactly 0, but, say, 0x123:
984 */
985 (long)info->si_addr,
986 ip);
987 {
988 /* glibc extension */
989 void *array[50];
990 int size;
991 size = backtrace(array, 50);
992 backtrace_symbols_fd(array, size, 2);
993 }
994 for (;;) sleep(9999);
995}
996#endif
997
957int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 998int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
958int init_main(int argc UNUSED_PARAM, char **argv) 999int init_main(int argc UNUSED_PARAM, char **argv)
959{ 1000{
@@ -961,6 +1002,19 @@ int init_main(int argc UNUSED_PARAM, char **argv)
961 return kill(1, SIGHUP); 1002 return kill(1, SIGHUP);
962 } 1003 }
963 1004
1005#if DEBUG_SEGV_HANDLER
1006 {
1007 struct sigaction sa;
1008 memset(&sa, 0, sizeof(sa));
1009 sa.sa_sigaction = handle_sigsegv;
1010 sa.sa_flags = SA_SIGINFO;
1011 sigaction(SIGSEGV, &sa, NULL);
1012 sigaction(SIGILL, &sa, NULL);
1013 sigaction(SIGFPE, &sa, NULL);
1014 sigaction(SIGBUS, &sa, NULL);
1015 }
1016#endif
1017
964 if (!DEBUG_INIT) { 1018 if (!DEBUG_INIT) {
965 /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ 1019 /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
966 if (getpid() != 1 1020 if (getpid() != 1
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 0c675db4d..116e275be 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -632,7 +632,10 @@ static int busybox_main(char **argv)
632 "See source distribution for full notice.\n" 632 "See source distribution for full notice.\n"
633 "\n" 633 "\n"
634 "Usage: busybox [function] [arguments]...\n" 634 "Usage: busybox [function] [arguments]...\n"
635 " or: busybox --list[-full]\n" 635 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n"
636 IF_FEATURE_INSTALLER(
637 " or: busybox --install [-s] [DIR]\n"
638 )
636 " or: function [arguments]...\n" 639 " or: function [arguments]...\n"
637 "\n" 640 "\n"
638 "\tBusyBox is a multi-call binary that combines many common Unix\n" 641 "\tBusyBox is a multi-call binary that combines many common Unix\n"
@@ -672,7 +675,7 @@ static int busybox_main(char **argv)
672 dup2(1, 2); 675 dup2(1, 2);
673 while (*a) { 676 while (*a) {
674# if ENABLE_FEATURE_INSTALLER 677# if ENABLE_FEATURE_INSTALLER
675 if (argv[1][6]) /* --list-path? */ 678 if (argv[1][6]) /* --list-full? */
676 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); 679 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
677# endif 680# endif
678 full_write2_str(a); 681 full_write2_str(a);
@@ -702,7 +705,7 @@ static int busybox_main(char **argv)
702 * -s: make symlinks 705 * -s: make symlinks
703 * DIR: directory to install links to 706 * DIR: directory to install links to
704 */ 707 */
705 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && argv++); 708 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv);
706 install_links(busybox, use_symbolic_links, argv[2]); 709 install_links(busybox, use_symbolic_links, argv[2]);
707 return 0; 710 return 0;
708 } 711 }
diff --git a/libbb/bb_strtonum.c b/libbb/bb_strtonum.c
index c66c774f4..949f26bee 100644
--- a/libbb/bb_strtonum.c
+++ b/libbb/bb_strtonum.c
@@ -36,14 +36,14 @@ static unsigned long long ret_ERANGE(void)
36 return ULLONG_MAX; 36 return ULLONG_MAX;
37} 37}
38 38
39static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr) 39static unsigned long long handle_errors(unsigned long long v, char **endp)
40{ 40{
41 if (endp) *endp = endptr; 41 char next_ch = **endp;
42 42
43 /* errno is already set to ERANGE by strtoXXX if value overflowed */ 43 /* errno is already set to ERANGE by strtoXXX if value overflowed */
44 if (endptr[0]) { 44 if (next_ch) {
45 /* "1234abcg" or out-of-range? */ 45 /* "1234abcg" or out-of-range? */
46 if (isalnum(endptr[0]) || errno) 46 if (isalnum(next_ch) || errno)
47 return ret_ERANGE(); 47 return ret_ERANGE();
48 /* good number, just suspicious terminator */ 48 /* good number, just suspicious terminator */
49 errno = EINVAL; 49 errno = EINVAL;
@@ -57,30 +57,37 @@ unsigned long long FAST_FUNC bb_strtoull(const char *arg, char **endp, int base)
57 unsigned long long v; 57 unsigned long long v;
58 char *endptr; 58 char *endptr;
59 59
60 if (!endp) endp = &endptr;
61 *endp = (char*) arg;
62
60 /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */ 63 /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */
61 /* I don't think that this is right. Preventing this... */ 64 /* I don't think that this is right. Preventing this... */
62 if (!isalnum(arg[0])) return ret_ERANGE(); 65 if (!isalnum(arg[0])) return ret_ERANGE();
63 66
64 /* not 100% correct for lib func, but convenient for the caller */ 67 /* not 100% correct for lib func, but convenient for the caller */
65 errno = 0; 68 errno = 0;
66 v = strtoull(arg, &endptr, base); 69 v = strtoull(arg, endp, base);
67 return handle_errors(v, endp, endptr); 70 return handle_errors(v, endp);
68} 71}
69 72
70long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base) 73long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base)
71{ 74{
72 unsigned long long v; 75 unsigned long long v;
73 char *endptr; 76 char *endptr;
77 char first;
78
79 if (!endp) endp = &endptr;
80 *endp = (char*) arg;
74 81
75 /* Check for the weird "feature": 82 /* Check for the weird "feature":
76 * a "-" string is apparently a valid "number" for strto[u]l[l]! 83 * a "-" string is apparently a valid "number" for strto[u]l[l]!
77 * It returns zero and errno is 0! :( */ 84 * It returns zero and errno is 0! :( */
78 char first = (arg[0] != '-' ? arg[0] : arg[1]); 85 first = (arg[0] != '-' ? arg[0] : arg[1]);
79 if (!isalnum(first)) return ret_ERANGE(); 86 if (!isalnum(first)) return ret_ERANGE();
80 87
81 errno = 0; 88 errno = 0;
82 v = strtoll(arg, &endptr, base); 89 v = strtoll(arg, endp, base);
83 return handle_errors(v, endp, endptr); 90 return handle_errors(v, endp);
84} 91}
85 92
86#if ULONG_MAX != ULLONG_MAX 93#if ULONG_MAX != ULLONG_MAX
@@ -89,23 +96,30 @@ unsigned long FAST_FUNC bb_strtoul(const char *arg, char **endp, int base)
89 unsigned long v; 96 unsigned long v;
90 char *endptr; 97 char *endptr;
91 98
99 if (!endp) endp = &endptr;
100 *endp = (char*) arg;
101
92 if (!isalnum(arg[0])) return ret_ERANGE(); 102 if (!isalnum(arg[0])) return ret_ERANGE();
93 errno = 0; 103 errno = 0;
94 v = strtoul(arg, &endptr, base); 104 v = strtoul(arg, endp, base);
95 return handle_errors(v, endp, endptr); 105 return handle_errors(v, endp);
96} 106}
97 107
98long FAST_FUNC bb_strtol(const char *arg, char **endp, int base) 108long FAST_FUNC bb_strtol(const char *arg, char **endp, int base)
99{ 109{
100 long v; 110 long v;
101 char *endptr; 111 char *endptr;
112 char first;
102 113
103 char first = (arg[0] != '-' ? arg[0] : arg[1]); 114 if (!endp) endp = &endptr;
115 *endp = (char*) arg;
116
117 first = (arg[0] != '-' ? arg[0] : arg[1]);
104 if (!isalnum(first)) return ret_ERANGE(); 118 if (!isalnum(first)) return ret_ERANGE();
105 119
106 errno = 0; 120 errno = 0;
107 v = strtol(arg, &endptr, base); 121 v = strtol(arg, endp, base);
108 return handle_errors(v, endp, endptr); 122 return handle_errors(v, endp);
109} 123}
110#endif 124#endif
111 125
@@ -115,25 +129,32 @@ unsigned FAST_FUNC bb_strtou(const char *arg, char **endp, int base)
115 unsigned long v; 129 unsigned long v;
116 char *endptr; 130 char *endptr;
117 131
132 if (!endp) endp = &endptr;
133 *endp = (char*) arg;
134
118 if (!isalnum(arg[0])) return ret_ERANGE(); 135 if (!isalnum(arg[0])) return ret_ERANGE();
119 errno = 0; 136 errno = 0;
120 v = strtoul(arg, &endptr, base); 137 v = strtoul(arg, endp, base);
121 if (v > UINT_MAX) return ret_ERANGE(); 138 if (v > UINT_MAX) return ret_ERANGE();
122 return handle_errors(v, endp, endptr); 139 return handle_errors(v, endp);
123} 140}
124 141
125int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base) 142int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base)
126{ 143{
127 long v; 144 long v;
128 char *endptr; 145 char *endptr;
146 char first;
147
148 if (!endp) endp = &endptr;
149 *endp = (char*) arg;
129 150
130 char first = (arg[0] != '-' ? arg[0] : arg[1]); 151 first = (arg[0] != '-' ? arg[0] : arg[1]);
131 if (!isalnum(first)) return ret_ERANGE(); 152 if (!isalnum(first)) return ret_ERANGE();
132 153
133 errno = 0; 154 errno = 0;
134 v = strtol(arg, &endptr, base); 155 v = strtol(arg, endp, base);
135 if (v > INT_MAX) return ret_ERANGE(); 156 if (v > INT_MAX) return ret_ERANGE();
136 if (v < INT_MIN) return ret_ERANGE(); 157 if (v < INT_MIN) return ret_ERANGE();
137 return handle_errors(v, endp, endptr); 158 return handle_errors(v, endp);
138} 159}
139#endif 160#endif
diff --git a/libbb/dump.c b/libbb/dump.c
index 919fe135c..7e435643b 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -71,7 +71,8 @@ static NOINLINE int bb_dump_size(FS *fs)
71 * skip any special chars -- save precision in 71 * skip any special chars -- save precision in
72 * case it's a %s format. 72 * case it's a %s format.
73 */ 73 */
74 while (strchr(index_str + 1, *++fmt)); 74 while (strchr(index_str + 1, *++fmt))
75 continue;
75 if (*fmt == '.' && isdigit(*++fmt)) { 76 if (*fmt == '.' && isdigit(*++fmt)) {
76 prec = atoi(fmt); 77 prec = atoi(fmt);
77 while (isdigit(*++fmt)) 78 while (isdigit(*++fmt))
@@ -99,8 +100,8 @@ static NOINLINE int bb_dump_size(FS *fs)
99static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) 100static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
100{ 101{
101 enum { NOTOKAY, USEBCNT, USEPREC } sokay; 102 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
102 PR *pr;
103 FU *fu; 103 FU *fu;
104 PR *pr;
104 char *p1, *p2, *p3; 105 char *p1, *p2, *p3;
105 char savech, *fmtp; 106 char savech, *fmtp;
106 const char *byte_count_str; 107 const char *byte_count_str;
@@ -292,16 +293,18 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
292 * interprets any data at all, and has no iteration count, 293 * interprets any data at all, and has no iteration count,
293 * repeat it as necessary. 294 * repeat it as necessary.
294 * 295 *
295 * if, rep count is greater than 1, no trailing whitespace 296 * if rep count is greater than 1, no trailing whitespace
296 * gets output from the last iteration of the format unit. 297 * gets output from the last iteration of the format unit.
297 */ 298 */
298 for (fu = fs->nextfu; fu; fu = fu->nextfu) { 299 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
299 if (!fu->nextfu && fs->bcnt < dumper->blocksize 300 if (!fu->nextfu
300 && !(fu->flags & F_SETREP) && fu->bcnt 301 && fs->bcnt < dumper->blocksize
302 && !(fu->flags & F_SETREP)
303 && fu->bcnt
301 ) { 304 ) {
302 fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt; 305 fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt;
303 } 306 }
304 if (fu->reps > 1) { 307 if (fu->reps > 1 && fu->nextpr) {
305 for (pr = fu->nextpr;; pr = pr->nextpr) 308 for (pr = fu->nextpr;; pr = pr->nextpr)
306 if (!pr->nextpr) 309 if (!pr->nextpr)
307 break; 310 break;
@@ -721,7 +724,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
721 p = fmt; 724 p = fmt;
722 for (;;) { 725 for (;;) {
723 p = skip_whitespace(p); 726 p = skip_whitespace(p);
724 if (!*p) { 727 if (*p == '\0') {
725 break; 728 break;
726 } 729 }
727 730
@@ -749,7 +752,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
749 752
750 /* skip slash and trailing white space */ 753 /* skip slash and trailing white space */
751 if (*p == '/') { 754 if (*p == '/') {
752 p = skip_whitespace(++p); 755 p = skip_whitespace(p + 1);
753 } 756 }
754 757
755 /* byte count */ 758 /* byte count */
@@ -763,7 +766,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
763 } 766 }
764 tfu->bcnt = atoi(savep); 767 tfu->bcnt = atoi(savep);
765 /* skip trailing white space */ 768 /* skip trailing white space */
766 p = skip_whitespace(++p); 769 p = skip_whitespace(p + 1);
767 } 770 }
768 771
769 /* format */ 772 /* format */
@@ -771,7 +774,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
771 bb_error_msg_and_die("bad format {%s}", fmt); 774 bb_error_msg_and_die("bad format {%s}", fmt);
772 } 775 }
773 for (savep = ++p; *p != '"';) { 776 for (savep = ++p; *p != '"';) {
774 if (*p++ == 0) { 777 if (*p++ == '\0') {
775 bb_error_msg_and_die("bad format {%s}", fmt); 778 bb_error_msg_and_die("bad format {%s}", fmt);
776 } 779 }
777 } 780 }
@@ -782,7 +785,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
782 785
783 /* alphabetic escape sequences have to be done in place */ 786 /* alphabetic escape sequences have to be done in place */
784 for (p2 = p1;; ++p1, ++p2) { 787 for (p2 = p1;; ++p1, ++p2) {
785 if (!*p1) { 788 if (*p1 == '\0') {
786 *p2 = *p1; 789 *p2 = *p1;
787 break; 790 break;
788 } 791 }
diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c
index 56637ad92..9676b5f52 100644
--- a/libbb/find_mount_point.c
+++ b/libbb/find_mount_point.c
@@ -30,7 +30,8 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
30 30
31 devno_of_name = s.st_dev; 31 devno_of_name = s.st_dev;
32 block_dev = 0; 32 block_dev = 0;
33 if (S_ISBLK(s.st_mode)) { 33 /* Why S_ISCHR? - UBI volumes use char devices, not block */
34 if (S_ISBLK(s.st_mode) || S_ISCHR(s.st_mode)) {
34 devno_of_name = s.st_rdev; 35 devno_of_name = s.st_rdev;
35 block_dev = 1; 36 block_dev = 1;
36 } 37 }
diff --git a/libbb/isdirectory.c b/libbb/isdirectory.c
index 9861be6f8..ba6c52ce8 100644
--- a/libbb/isdirectory.c
+++ b/libbb/isdirectory.c
@@ -15,22 +15,17 @@
15 * Return TRUE if fileName is a directory. 15 * Return TRUE if fileName is a directory.
16 * Nonexistent files return FALSE. 16 * Nonexistent files return FALSE.
17 */ 17 */
18int FAST_FUNC is_directory(const char *fileName, int followLinks, struct stat *statBuf) 18int FAST_FUNC is_directory(const char *fileName, int followLinks)
19{ 19{
20 int status; 20 int status;
21 struct stat astatBuf; 21 struct stat statBuf;
22
23 if (statBuf == NULL) {
24 /* use auto stack buffer */
25 statBuf = &astatBuf;
26 }
27 22
28 if (followLinks) 23 if (followLinks)
29 status = stat(fileName, statBuf); 24 status = stat(fileName, &statBuf);
30 else 25 else
31 status = lstat(fileName, statBuf); 26 status = lstat(fileName, &statBuf);
32 27
33 status = (status == 0 && S_ISDIR(statBuf->st_mode)); 28 status = (status == 0 && S_ISDIR(statBuf.st_mode));
34 29
35 return status; 30 return status;
36} 31}
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index c89c829ed..78244c395 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -2221,14 +2221,17 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2221#define command command_must_not_be_used 2221#define command command_must_not_be_used
2222 2222
2223 new_settings = initial_settings; 2223 new_settings = initial_settings;
2224 new_settings.c_lflag &= ~ICANON; /* unbuffered input */ 2224 /* ~ICANON: unbuffered input (most c_cc[] are disabled, VMIN/VTIME are enabled) */
2225 /* Turn off echoing and CTRL-C, so we can trap it */ 2225 /* ~ECHO, ~ECHONL: turn off echoing, including newline echoing */
2226 new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); 2226 /* ~ISIG: turn off INTR (ctrl-C), QUIT, SUSP */
2227 /* Hmm, in linux c_cc[] is not parsed if ICANON is off */ 2227 new_settings.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG);
2228 /* reads would block only if < 1 char is available */
2228 new_settings.c_cc[VMIN] = 1; 2229 new_settings.c_cc[VMIN] = 1;
2230 /* no timeout (reads block forever) */
2229 new_settings.c_cc[VTIME] = 0; 2231 new_settings.c_cc[VTIME] = 0;
2230 /* Turn off CTRL-C, so we can trap it */ 2232 /* Should be not needed if ISIG is off: */
2231 new_settings.c_cc[VINTR] = _POSIX_VDISABLE; 2233 /* Turn off CTRL-C */
2234 /* new_settings.c_cc[VINTR] = _POSIX_VDISABLE; */
2232 tcsetattr_stdin_TCSANOW(&new_settings); 2235 tcsetattr_stdin_TCSANOW(&new_settings);
2233 2236
2234#if ENABLE_USERNAME_OR_HOMEDIR 2237#if ENABLE_USERNAME_OR_HOMEDIR
diff --git a/libbb/parse_config.c b/libbb/parse_config.c
index cf5ba4deb..1590d9a4c 100644
--- a/libbb/parse_config.c
+++ b/libbb/parse_config.c
@@ -204,7 +204,7 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
204 line += strcspn(line, delims[0] ? delims : delims + 1); 204 line += strcspn(line, delims[0] ? delims : delims + 1);
205 } else { 205 } else {
206 /* Combining, find comment char if any */ 206 /* Combining, find comment char if any */
207 line = strchrnul(line, delims[0]); 207 line = strchrnul(line, PARSE_EOL_COMMENTS ? delims[0] : '\0');
208 208
209 /* Trim any extra delimiters from the end */ 209 /* Trim any extra delimiters from the end */
210 if (flags & PARSE_TRIM) { 210 if (flags & PARSE_TRIM) {
diff --git a/libbb/procps.c b/libbb/procps.c
index 39ddd2c12..dbae46e33 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -128,10 +128,11 @@ static unsigned long fast_strtoul_16(char **endptr)
128 char *str = *endptr; 128 char *str = *endptr;
129 unsigned long n = 0; 129 unsigned long n = 0;
130 130
131 while ((c = *str++) != ' ') { 131 /* Need to stop on both ' ' and '\n' */
132 while ((c = *str++) > ' ') {
132 c = ((c|0x20) - '0'); 133 c = ((c|0x20) - '0');
133 if (c > 9) 134 if (c > 9)
134 // c = c + '0' - 'a' + 10: 135 /* c = c + '0' - 'a' + 10: */
135 c = c - ('a' - '0' - 10); 136 c = c - ('a' - '0' - 10);
136 n = n*16 + c; 137 n = n*16 + c;
137 } 138 }
@@ -144,11 +145,12 @@ static unsigned long fast_strtoul_16(char **endptr)
144/* We cut a lot of corners here for speed */ 145/* We cut a lot of corners here for speed */
145static unsigned long fast_strtoul_10(char **endptr) 146static unsigned long fast_strtoul_10(char **endptr)
146{ 147{
147 char c; 148 unsigned char c;
148 char *str = *endptr; 149 char *str = *endptr;
149 unsigned long n = *str - '0'; 150 unsigned long n = *str - '0';
150 151
151 while ((c = *++str) != ' ') 152 /* Need to stop on both ' ' and '\n' */
153 while ((c = *++str) > ' ')
152 n = n*10 + (c - '0'); 154 n = n*10 + (c - '0');
153 155
154 *endptr = str + 1; /* We skip trailing space! */ 156 *endptr = str + 1; /* We skip trailing space! */
@@ -199,7 +201,7 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
199 memset(&currec, 0, sizeof(currec)); 201 memset(&currec, 0, sizeof(currec));
200 while (fgets(buf, PROCPS_BUFSIZE, file)) { 202 while (fgets(buf, PROCPS_BUFSIZE, file)) {
201 // Each mapping datum has this form: 203 // Each mapping datum has this form:
202 // f7d29000-f7d39000 rw-s ADR M:m OFS FILE 204 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME
203 // Size: nnn kB 205 // Size: nnn kB
204 // Rss: nnn kB 206 // Rss: nnn kB
205 // ..... 207 // .....
@@ -224,7 +226,7 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
224 tp = strchr(buf, '-'); 226 tp = strchr(buf, '-');
225 if (tp) { 227 if (tp) {
226 // We reached next mapping - the line of this form: 228 // We reached next mapping - the line of this form:
227 // f7d29000-f7d39000 rw-s ADR M:m OFS FILE 229 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME
228 230
229 if (cb) { 231 if (cb) {
230 /* If we have a previous record, there's nothing more 232 /* If we have a previous record, there's nothing more
@@ -243,7 +245,7 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
243 245
244 strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); 246 strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1);
245 247
246 // skipping "rw-s ADR M:m OFS " 248 // skipping "rw-s FILEOFS M:m INODE "
247 tp = skip_whitespace(skip_fields(tp, 4)); 249 tp = skip_whitespace(skip_fields(tp, 4));
248 // filter out /dev/something (something != zero) 250 // filter out /dev/something (something != zero)
249 if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) { 251 if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) {
diff --git a/libbb/read_printf.c b/libbb/read_printf.c
index 0bbf7802a..5ed6e3632 100644
--- a/libbb/read_printf.c
+++ b/libbb/read_printf.c
@@ -8,16 +8,6 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \
12 || ENABLE_FEATURE_SEAMLESS_BZ2 \
13 || ENABLE_FEATURE_SEAMLESS_GZ \
14 /* || ENABLE_FEATURE_SEAMLESS_Z */ \
15)
16
17#if ZIPPED
18# include "bb_archive.h"
19#endif
20
21 11
22/* Suppose that you are a shell. You start child processes. 12/* Suppose that you are a shell. You start child processes.
23 * They work and eventually exit. You want to get user input. 13 * They work and eventually exit. You want to get user input.
@@ -244,132 +234,3 @@ void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p)
244 bb_perror_msg_and_die("can't read '%s'", filename); 234 bb_perror_msg_and_die("can't read '%s'", filename);
245 return buf; 235 return buf;
246} 236}
247
248/* Used by e.g. rpm which gives us a fd without filename,
249 * thus we can't guess the format from filename's extension.
250 */
251#if ZIPPED
252void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/)
253{
254 const int fail_if_not_detected = 1;
255 union {
256 uint8_t b[4];
257 uint16_t b16[2];
258 uint32_t b32[1];
259 } magic;
260 int offset = -2;
261# if BB_MMU
262 IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd);
263 enum { xformer_prog = 0 };
264# else
265 enum { xformer = 0 };
266 const char *xformer_prog;
267# endif
268
269 /* .gz and .bz2 both have 2-byte signature, and their
270 * unpack_XXX_stream wants this header skipped. */
271 xread(fd, magic.b16, sizeof(magic.b16[0]));
272 if (ENABLE_FEATURE_SEAMLESS_GZ
273 && magic.b16[0] == GZIP_MAGIC
274 ) {
275# if BB_MMU
276 xformer = unpack_gz_stream;
277# else
278 xformer_prog = "gunzip";
279# endif
280 goto found_magic;
281 }
282 if (ENABLE_FEATURE_SEAMLESS_BZ2
283 && magic.b16[0] == BZIP2_MAGIC
284 ) {
285# if BB_MMU
286 xformer = unpack_bz2_stream;
287# else
288 xformer_prog = "bunzip2";
289# endif
290 goto found_magic;
291 }
292 if (ENABLE_FEATURE_SEAMLESS_XZ
293 && magic.b16[0] == XZ_MAGIC1
294 ) {
295 offset = -6;
296 xread(fd, magic.b32, sizeof(magic.b32[0]));
297 if (magic.b32[0] == XZ_MAGIC2) {
298# if BB_MMU
299 xformer = unpack_xz_stream;
300 /* unpack_xz_stream wants fd at position 6, no need to seek */
301 //xlseek(fd, offset, SEEK_CUR);
302# else
303 xformer_prog = "unxz";
304# endif
305 goto found_magic;
306 }
307 }
308
309 /* No known magic seen */
310 if (fail_if_not_detected)
311 bb_error_msg_and_die("no gzip"
312 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
313 IF_FEATURE_SEAMLESS_XZ("/xz")
314 " magic");
315 xlseek(fd, offset, SEEK_CUR);
316 return;
317
318 found_magic:
319# if !BB_MMU
320 /* NOMMU version of open_transformer execs
321 * an external unzipper that wants
322 * file position at the start of the file */
323 xlseek(fd, offset, SEEK_CUR);
324# endif
325 open_transformer(fd, xformer, xformer_prog);
326}
327#endif /* ZIPPED */
328
329int FAST_FUNC open_zipped(const char *fname)
330{
331#if !ZIPPED
332 return open(fname, O_RDONLY);
333#else
334 char *sfx;
335 int fd;
336
337 fd = open(fname, O_RDONLY);
338 if (fd < 0)
339 return fd;
340
341 sfx = strrchr(fname, '.');
342 if (sfx) {
343 sfx++;
344 if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0)
345 /* .lzma has no header/signature, just trust it */
346 open_transformer(fd, unpack_lzma_stream, "unlzma");
347 else
348 if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0)
349 || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0)
350 || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0)
351 ) {
352 setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/);
353 }
354 }
355
356 return fd;
357#endif
358}
359
360void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p)
361{
362 int fd;
363 char *image;
364
365 fd = open_zipped(fname);
366 if (fd < 0)
367 return NULL;
368
369 image = xmalloc_read(fd, maxsz_p);
370 if (!image)
371 bb_perror_msg("read error from '%s'", fname);
372 close(fd);
373
374 return image;
375}
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 5d8056bd6..6611dabfa 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -256,11 +256,19 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
256 if (!(flags & DAEMON_ONLY_SANITIZE)) { 256 if (!(flags & DAEMON_ONLY_SANITIZE)) {
257 if (fork_or_rexec(argv)) 257 if (fork_or_rexec(argv))
258 exit(EXIT_SUCCESS); /* parent */ 258 exit(EXIT_SUCCESS); /* parent */
259 /* if daemonizing, make sure we detach from stdio & ctty */ 259 /* if daemonizing, detach from stdio & ctty */
260 setsid(); 260 setsid();
261 dup2(fd, 0); 261 dup2(fd, 0);
262 dup2(fd, 1); 262 dup2(fd, 1);
263 dup2(fd, 2); 263 dup2(fd, 2);
264 if (flags & DAEMON_DOUBLE_FORK) {
265 /* On Linux, session leader can acquire ctty
266 * unknowingly, by opening a tty.
267 * Prevent this: stop being a session leader.
268 */
269 if (fork_or_rexec(argv))
270 exit(EXIT_SUCCESS); /* parent */
271 }
264 } 272 }
265 while (fd > 2) { 273 while (fd > 2) {
266 close(fd--); 274 close(fd--);
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 4b7c110d3..1c8bb2b73 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -322,26 +322,28 @@ len_and_sockaddr* FAST_FUNC xdotted2sockaddr(const char *host, int port)
322 return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR); 322 return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR);
323} 323}
324 324
325#undef xsocket_type 325int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, int family, int sock_type)
326int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int sock_type)
327{ 326{
328 IF_NOT_FEATURE_IPV6(enum { family = AF_INET };)
329 len_and_sockaddr *lsa; 327 len_and_sockaddr *lsa;
330 int fd; 328 int fd;
331 int len; 329 int len;
332 330
333#if ENABLE_FEATURE_IPV6
334 if (family == AF_UNSPEC) { 331 if (family == AF_UNSPEC) {
332#if ENABLE_FEATURE_IPV6
335 fd = socket(AF_INET6, sock_type, 0); 333 fd = socket(AF_INET6, sock_type, 0);
336 if (fd >= 0) { 334 if (fd >= 0) {
337 family = AF_INET6; 335 family = AF_INET6;
338 goto done; 336 goto done;
339 } 337 }
338#endif
340 family = AF_INET; 339 family = AF_INET;
341 } 340 }
342#endif 341
343 fd = xsocket(family, sock_type, 0); 342 fd = xsocket(family, sock_type, 0);
343
344 len = sizeof(struct sockaddr_in); 344 len = sizeof(struct sockaddr_in);
345 if (family == AF_UNIX)
346 len = sizeof(struct sockaddr_un);
345#if ENABLE_FEATURE_IPV6 347#if ENABLE_FEATURE_IPV6
346 if (family == AF_INET6) { 348 if (family == AF_INET6) {
347 done: 349 done:
@@ -357,7 +359,7 @@ int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,)
357 359
358int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap) 360int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap)
359{ 361{
360 return xsocket_type(lsap, IF_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM); 362 return xsocket_type(lsap, AF_UNSPEC, SOCK_STREAM);
361} 363}
362 364
363static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type) 365static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)
@@ -370,7 +372,7 @@ static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)
370 /* user specified bind addr dictates family */ 372 /* user specified bind addr dictates family */
371 fd = xsocket(lsa->u.sa.sa_family, sock_type, 0); 373 fd = xsocket(lsa->u.sa.sa_family, sock_type, 0);
372 } else { 374 } else {
373 fd = xsocket_type(&lsa, IF_FEATURE_IPV6(AF_UNSPEC,) sock_type); 375 fd = xsocket_type(&lsa, AF_UNSPEC, sock_type);
374 set_nport(&lsa->u.sa, htons(port)); 376 set_nport(&lsa->u.sa, htons(port));
375 } 377 }
376 setsockopt_reuseaddr(fd); 378 setsockopt_reuseaddr(fd);
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 8a6d7e1d1..70d3fc96c 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -376,6 +376,7 @@ void FAST_FUNC xchroot(const char *path)
376{ 376{
377 if (chroot(path)) 377 if (chroot(path))
378 bb_perror_msg_and_die("can't change root directory to %s", path); 378 bb_perror_msg_and_die("can't change root directory to %s", path);
379 xchdir("/");
379} 380}
380 381
381// Print a warning message if opendir() fails, but don't die. 382// Print a warning message if opendir() fails, but don't die.
diff --git a/libpwdgrp/pwd_grp.c b/libpwdgrp/pwd_grp.c
index 2eb9d9dd1..edf53f350 100644
--- a/libpwdgrp/pwd_grp.c
+++ b/libpwdgrp/pwd_grp.c
@@ -23,8 +23,6 @@
23/**********************************************************************/ 23/**********************************************************************/
24/* Sizes for statically allocated buffers. */ 24/* Sizes for statically allocated buffers. */
25 25
26/* If you change these values, also change _SC_GETPW_R_SIZE_MAX and
27 * _SC_GETGR_R_SIZE_MAX in libc/unistd/sysconf.c to match */
28#define PWD_BUFFER_SIZE 256 26#define PWD_BUFFER_SIZE 256
29#define GRP_BUFFER_SIZE 256 27#define GRP_BUFFER_SIZE 256
30 28
@@ -49,46 +47,24 @@ static int FAST_FUNC bb__parsespent(void *sp, char *line);
49 47
50struct statics { 48struct statics {
51 /* Smaller things first */ 49 /* Smaller things first */
52 struct passwd getpwuid_resultbuf; 50 /* It's ok to use one buffer for getpwuid and getpwnam. Manpage says:
53 struct group getgrgid_resultbuf; 51 * "The return value may point to a static area, and may be overwritten
54 struct passwd getpwnam_resultbuf; 52 * by subsequent calls to getpwent(), getpwnam(), or getpwuid()."
55 struct group getgrnam_resultbuf; 53 */
56 54 struct passwd getpw_resultbuf;
57 char getpwuid_buffer[PWD_BUFFER_SIZE]; 55 struct group getgr_resultbuf;
58 char getgrgid_buffer[GRP_BUFFER_SIZE]; 56
59 char getpwnam_buffer[PWD_BUFFER_SIZE]; 57 char getpw_buffer[PWD_BUFFER_SIZE];
60 char getgrnam_buffer[GRP_BUFFER_SIZE]; 58 char getgr_buffer[GRP_BUFFER_SIZE];
61#if 0
62 struct passwd fgetpwent_resultbuf;
63 struct group fgetgrent_resultbuf;
64 struct spwd fgetspent_resultbuf;
65 char fgetpwent_buffer[PWD_BUFFER_SIZE];
66 char fgetgrent_buffer[GRP_BUFFER_SIZE];
67 char fgetspent_buffer[PWD_BUFFER_SIZE];
68#endif
69#if 0 //ENABLE_USE_BB_SHADOW 59#if 0 //ENABLE_USE_BB_SHADOW
70 struct spwd getspuid_resultbuf; 60 struct spwd getsp_resultbuf;
71 struct spwd getspnam_resultbuf; 61 char getsp_buffer[PWD_BUFFER_SIZE];
72 char getspuid_buffer[PWD_BUFFER_SIZE];
73 char getspnam_buffer[PWD_BUFFER_SIZE];
74#endif 62#endif
75// Not converted - too small to bother 63// Not converted - too small to bother
76//pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER; 64//pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
77//FILE *pwf /*= NULL*/; 65//FILE *pwf /*= NULL*/;
78//FILE *grf /*= NULL*/; 66//FILE *grf /*= NULL*/;
79//FILE *spf /*= NULL*/; 67//FILE *spf /*= NULL*/;
80#if 0
81 struct passwd getpwent_pwd;
82 struct group getgrent_gr;
83 char getpwent_line_buff[PWD_BUFFER_SIZE];
84 char getgrent_line_buff[GRP_BUFFER_SIZE];
85#endif
86#if 0 //ENABLE_USE_BB_SHADOW
87 struct spwd getspent_spwd;
88 struct spwd sgetspent_spwd;
89 char getspent_line_buff[PWD_BUFFER_SIZE];
90 char sgetspent_line_buff[PWD_BUFFER_SIZE];
91#endif
92}; 68};
93 69
94static struct statics *ptr_to_statics; 70static struct statics *ptr_to_statics;
@@ -182,22 +158,22 @@ int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
182struct passwd *fgetpwent(FILE *stream) 158struct passwd *fgetpwent(FILE *stream)
183{ 159{
184 struct statics *S; 160 struct statics *S;
185 struct passwd *resultbuf = RESULTBUF(fgetpwent); 161 struct passwd *resultbuf = RESULTBUF(getpw);
186 char *buffer = BUFFER(fgetpwent); 162 char *buffer = BUFFER(getpw);
187 struct passwd *result; 163 struct passwd *result;
188 164
189 fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetpwent)), &result); 165 fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(getpw)), &result);
190 return result; 166 return result;
191} 167}
192 168
193struct group *fgetgrent(FILE *stream) 169struct group *fgetgrent(FILE *stream)
194{ 170{
195 struct statics *S; 171 struct statics *S;
196 struct group *resultbuf = RESULTBUF(fgetgrent); 172 struct group *resultbuf = RESULTBUF(getgr);
197 char *buffer = BUFFER(fgetgrent); 173 char *buffer = BUFFER(getgr);
198 struct group *result; 174 struct group *result;
199 175
200 fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetgrent)), &result); 176 fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(getgr)), &result);
201 return result; 177 return result;
202} 178}
203#endif 179#endif
@@ -207,11 +183,11 @@ struct group *fgetgrent(FILE *stream)
207struct spwd *fgetspent(FILE *stream) 183struct spwd *fgetspent(FILE *stream)
208{ 184{
209 struct statics *S; 185 struct statics *S;
210 struct spwd *resultbuf = RESULTBUF(fgetspent); 186 struct spwd *resultbuf = RESULTBUF(getsp);
211 char *buffer = BUFFER(fgetspent); 187 char *buffer = BUFFER(getsp);
212 struct spwd *result; 188 struct spwd *result;
213 189
214 fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetspent)), &result); 190 fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(getsp)), &result);
215 return result; 191 return result;
216} 192}
217#endif 193#endif
@@ -299,11 +275,11 @@ int sgetspent_r(const char *string, struct spwd *result_buf,
299struct passwd *getpwuid(uid_t uid) 275struct passwd *getpwuid(uid_t uid)
300{ 276{
301 struct statics *S; 277 struct statics *S;
302 struct passwd *resultbuf = RESULTBUF(getpwuid); 278 struct passwd *resultbuf = RESULTBUF(getpw);
303 char *buffer = BUFFER(getpwuid); 279 char *buffer = BUFFER(getpw);
304 struct passwd *result; 280 struct passwd *result;
305 281
306 getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpwuid)), &result); 282 getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpw)), &result);
307 return result; 283 return result;
308} 284}
309 285
@@ -311,11 +287,11 @@ struct passwd *getpwuid(uid_t uid)
311struct group *getgrgid(gid_t gid) 287struct group *getgrgid(gid_t gid)
312{ 288{
313 struct statics *S; 289 struct statics *S;
314 struct group *resultbuf = RESULTBUF(getgrgid); 290 struct group *resultbuf = RESULTBUF(getgr);
315 char *buffer = BUFFER(getgrgid); 291 char *buffer = BUFFER(getgr);
316 struct group *result; 292 struct group *result;
317 293
318 getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgrgid)), &result); 294 getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgr)), &result);
319 return result; 295 return result;
320} 296}
321 297
@@ -346,11 +322,11 @@ int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf,
346struct spwd *getspuid(uid_t uid) 322struct spwd *getspuid(uid_t uid)
347{ 323{
348 struct statics *S; 324 struct statics *S;
349 struct spwd *resultbuf = RESULTBUF(getspuid); 325 struct spwd *resultbuf = RESULTBUF(getsp);
350 char *buffer = BUFFER(getspuid); 326 char *buffer = BUFFER(getsp);
351 struct spwd *result; 327 struct spwd *result;
352 328
353 getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getspuid)), &result); 329 getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getsp)), &result);
354 return result; 330 return result;
355} 331}
356#endif 332#endif
@@ -359,11 +335,11 @@ struct spwd *getspuid(uid_t uid)
359struct passwd *getpwnam(const char *name) 335struct passwd *getpwnam(const char *name)
360{ 336{
361 struct statics *S; 337 struct statics *S;
362 struct passwd *resultbuf = RESULTBUF(getpwnam); 338 struct passwd *resultbuf = RESULTBUF(getpw);
363 char *buffer = BUFFER(getpwnam); 339 char *buffer = BUFFER(getpw);
364 struct passwd *result; 340 struct passwd *result;
365 341
366 getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpwnam)), &result); 342 getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpw)), &result);
367 return result; 343 return result;
368} 344}
369 345
@@ -371,11 +347,11 @@ struct passwd *getpwnam(const char *name)
371struct group *getgrnam(const char *name) 347struct group *getgrnam(const char *name)
372{ 348{
373 struct statics *S; 349 struct statics *S;
374 struct group *resultbuf = RESULTBUF(getgrnam); 350 struct group *resultbuf = RESULTBUF(getgr);
375 char *buffer = BUFFER(getgrnam); 351 char *buffer = BUFFER(getgr);
376 struct group *result; 352 struct group *result;
377 353
378 getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgrnam)), &result); 354 getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgr)), &result);
379 return result; 355 return result;
380} 356}
381 357
@@ -383,11 +359,11 @@ struct group *getgrnam(const char *name)
383struct spwd *getspnam(const char *name) 359struct spwd *getspnam(const char *name)
384{ 360{
385 struct statics *S; 361 struct statics *S;
386 struct spwd *resultbuf = RESULTBUF(getspnam); 362 struct spwd *resultbuf = RESULTBUF(getsp);
387 char *buffer = BUFFER(getspnam); 363 char *buffer = BUFFER(getsp);
388 struct spwd *result; 364 struct spwd *result;
389 365
390 getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getspnam)), &result); 366 getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getsp)), &result);
391 return result; 367 return result;
392} 368}
393#endif 369#endif
@@ -441,6 +417,7 @@ int getpwent_r(struct passwd *__restrict resultbuf,
441 rv = errno; 417 rv = errno;
442 goto ERR; 418 goto ERR;
443 } 419 }
420 close_on_exec_on(fileno(pwf));
444 } 421 }
445 422
446 rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, pwf); 423 rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, pwf);
@@ -488,6 +465,7 @@ int getgrent_r(struct group *__restrict resultbuf,
488 rv = errno; 465 rv = errno;
489 goto ERR; 466 goto ERR;
490 } 467 }
468 close_on_exec_on(fileno(grf));
491 } 469 }
492 470
493 rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, grf); 471 rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, grf);
@@ -536,6 +514,7 @@ int getspent_r(struct spwd *resultbuf, char *buffer,
536 rv = errno; 514 rv = errno;
537 goto ERR; 515 goto ERR;
538 } 516 }
517 close_on_exec_on(fileno(spf));
539 } 518 }
540 519
541 rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, spf); 520 rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, spf);
diff --git a/loginutils/Config.src b/loginutils/Config.src
index 14ce53434..9bf79afee 100644
--- a/loginutils/Config.src
+++ b/loginutils/Config.src
@@ -283,6 +283,13 @@ config CHPASSWD
283 Reads a file of user name and password pairs from standard input 283 Reads a file of user name and password pairs from standard input
284 and uses this information to update a group of existing users. 284 and uses this information to update a group of existing users.
285 285
286config FEATURE_DEFAULT_PASSWD_ALGO
287 string "Default password encryption method (passwd -a, cryptpw -m parameter)"
288 default "des"
289 depends on PASSWD || CRYPTPW
290 help
291 Possible choices are "d[es]", "m[d5]", "s[ha256]" or "sha512".
292
286config SU 293config SU
287 bool "su" 294 bool "su"
288 default y 295 default y
diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c
index b7df57e5d..54ed73795 100644
--- a/loginutils/chpasswd.c
+++ b/loginutils/chpasswd.c
@@ -20,6 +20,8 @@
20//usage: "\n -m Use MD5 encryption instead of DES" 20//usage: "\n -m Use MD5 encryption instead of DES"
21//usage: ) 21//usage: )
22 22
23//TODO: implement -c ALGO
24
23#if ENABLE_LONG_OPTS 25#if ENABLE_LONG_OPTS
24static const char chpasswd_longopts[] ALIGN1 = 26static const char chpasswd_longopts[] ALIGN1 =
25 "encrypted\0" No_argument "e" 27 "encrypted\0" No_argument "e"
diff --git a/loginutils/cryptpw.c b/loginutils/cryptpw.c
index b244f55e3..a36f920f4 100644
--- a/loginutils/cryptpw.c
+++ b/loginutils/cryptpw.c
@@ -105,7 +105,7 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv)
105 applet_long_options = mkpasswd_longopts; 105 applet_long_options = mkpasswd_longopts;
106#endif 106#endif
107 fd = STDIN_FILENO; 107 fd = STDIN_FILENO;
108 opt_m = "d"; 108 opt_m = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
109 opt_S = NULL; 109 opt_S = NULL;
110 /* at most two non-option arguments; -P NUM */ 110 /* at most two non-option arguments; -P NUM */
111 opt_complementary = "?2:P+"; 111 opt_complementary = "?2:P+";
diff --git a/loginutils/getty.c b/loginutils/getty.c
index 1f417591b..afb411b98 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -294,8 +294,10 @@ static void init_tty_attrs(int speed)
294 /* non-raw output; add CR to each NL */ 294 /* non-raw output; add CR to each NL */
295 G.tty_attrs.c_oflag = OPOST | ONLCR; 295 G.tty_attrs.c_oflag = OPOST | ONLCR;
296 296
297 G.tty_attrs.c_cc[VMIN] = 1; /* block reads if < 1 char is available */ 297 /* reads would block only if < 1 char is available */
298 G.tty_attrs.c_cc[VTIME] = 0; /* no timeout (reads block forever) */ 298 G.tty_attrs.c_cc[VMIN] = 1;
299 /* no timeout (reads block forever) */
300 G.tty_attrs.c_cc[VTIME] = 0;
299#ifdef __linux__ 301#ifdef __linux__
300 G.tty_attrs.c_line = 0; 302 G.tty_attrs.c_line = 0;
301#endif 303#endif
diff --git a/loginutils/login.c b/loginutils/login.c
index 73db8fa63..bf43f3aba 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -342,14 +342,16 @@ int login_main(int argc UNUSED_PARAM, char **argv)
342 goto pam_auth_failed; 342 goto pam_auth_failed;
343 } 343 }
344 } 344 }
345 pamret = pam_authenticate(pamh, 0); 345 if (!(opt & LOGIN_OPT_f)) {
346 if (pamret != PAM_SUCCESS) { 346 pamret = pam_authenticate(pamh, 0);
347 failed_msg = "authenticate"; 347 if (pamret != PAM_SUCCESS) {
348 goto pam_auth_failed; 348 failed_msg = "authenticate";
349 /* TODO: or just "goto auth_failed" 349 goto pam_auth_failed;
350 * since user seems to enter wrong password 350 /* TODO: or just "goto auth_failed"
351 * (in this case pamret == 7) 351 * since user seems to enter wrong password
352 */ 352 * (in this case pamret == 7)
353 */
354 }
353 } 355 }
354 /* check that the account is healthy */ 356 /* check that the account is healthy */
355 pamret = pam_acct_mgmt(pamh, 0); 357 pamret = pam_acct_mgmt(pamh, 0);
diff --git a/loginutils/passwd.c b/loginutils/passwd.c
index 1cfafaec3..b83db0083 100644
--- a/loginutils/passwd.c
+++ b/loginutils/passwd.c
@@ -94,7 +94,7 @@ int passwd_main(int argc UNUSED_PARAM, char **argv)
94 }; 94 };
95 unsigned opt; 95 unsigned opt;
96 int rc; 96 int rc;
97 const char *opt_a = "d"; /* des */ 97 const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO;
98 const char *filename; 98 const char *filename;
99 char *myname; 99 char *myname;
100 char *name; 100 char *name;
diff --git a/mailutils/mail.c b/mailutils/mail.c
index f5260d9db..199f64407 100644
--- a/mailutils/mail.c
+++ b/mailutils/mail.c
@@ -119,7 +119,7 @@ static char* FAST_FUNC parse_url(char *url, char **user, char **pass)
119void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol) 119void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol)
120{ 120{
121 enum { 121 enum {
122 SRC_BUF_SIZE = 45, /* This *MUST* be a multiple of 3 */ 122 SRC_BUF_SIZE = 57, /* This *MUST* be a multiple of 3 */
123 DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), 123 DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3),
124 }; 124 };
125#define src_buf text 125#define src_buf text
diff --git a/mailutils/mail.h b/mailutils/mail.h
index d1d783055..fa0c5b378 100644
--- a/mailutils/mail.h
+++ b/mailutils/mail.h
@@ -16,22 +16,15 @@ struct globals {
16 char *pass; 16 char *pass;
17 FILE *fp0; // initial stdin 17 FILE *fp0; // initial stdin
18 char *opt_charset; 18 char *opt_charset;
19 char *content_type;
20}; 19};
21 20
22#define G (*ptr_to_globals) 21#define G (*ptr_to_globals)
23#define timeout (G.timeout ) 22#define timeout (G.timeout )
24#define verbose (G.verbose ) 23#define verbose (G.verbose )
25#define opts (G.opts ) 24#define opts (G.opts )
26//#define user (G.user )
27//#define pass (G.pass )
28//#define fp0 (G.fp0 )
29//#define opt_charset (G.opt_charset)
30//#define content_type (G.content_type)
31#define INIT_G() do { \ 25#define INIT_G() do { \
32 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 26 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
33 G.opt_charset = (char *)CONFIG_FEATURE_MIME_CHARSET; \ 27 G.opt_charset = (char *)CONFIG_FEATURE_MIME_CHARSET; \
34 G.content_type = (char *)"text/plain"; \
35} while (0) 28} while (0)
36 29
37//char FAST_FUNC *parse_url(char *url, char **user, char **pass); 30//char FAST_FUNC *parse_url(char *url, char **user, char **pass);
diff --git a/mailutils/makemime.c b/mailutils/makemime.c
index a9ff03d03..1dadd715f 100644
--- a/mailutils/makemime.c
+++ b/mailutils/makemime.c
@@ -1,7 +1,6 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * makemime: create MIME-encoded message 3 * makemime: create MIME-encoded message
4 * reformime: parse MIME-encoded message
5 * 4 *
6 * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com> 5 * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
7 * 6 *
@@ -133,21 +132,44 @@ Content-Transfer-Encoding: 7bit
133//usage: "Create multipart MIME-encoded message from FILEs\n" 132//usage: "Create multipart MIME-encoded message from FILEs\n"
134/* //usage: "Transfer encoding is base64, disposition is inline (not attachment)\n" */ 133/* //usage: "Transfer encoding is base64, disposition is inline (not attachment)\n" */
135//usage: "\n -o FILE Output. Default: stdout" 134//usage: "\n -o FILE Output. Default: stdout"
136//usage: "\n -a HDR Add header. Examples:" 135//usage: "\n -a HDR Add header(s). Examples:"
137//usage: "\n \"From: user@host.org\", \"Date: `date -R`\"" 136//usage: "\n \"From: user@host.org\", \"Date: `date -R`\""
138//usage: "\n -c CT Content type. Default: text/plain" 137//usage: "\n -c CT Content type. Default: application/octet-stream"
139//usage: "\n -C CS Charset. Default: " CONFIG_FEATURE_MIME_CHARSET 138//usage: "\n -C CS Charset. Default: " CONFIG_FEATURE_MIME_CHARSET
140/* //usage: "\n -e ENC Transfer encoding. Ignored. base64 is assumed" */ 139/* //usage: "\n -e ENC Transfer encoding. Ignored. base64 is assumed" */
141//usage: "\n" 140//usage: "\n"
142//usage: "\nOther options are silently ignored" 141//usage: "\nOther options are silently ignored"
143 142
143/*
144 * -c [Content-Type] should create just one MIME section
145 * with "Content-Type:", "Content-Transfer-Encoding:", and HDRs from "-a HDR".
146 * NB: without "Content-Disposition:" auto-added, unlike we do now
147 * NB2: -c has *optional* param which nevertheless _can_ be specified after a space :(
148 *
149 * -m [multipart/mixed] should create multipart MIME section
150 * with "Content-Type:", "Content-Transfer-Encoding:", and HDRs from "-a HDR",
151 * and add FILE to it _verbatim_:
152 * HEADERS
153 *
154 * --=_1_1321709112_1605
155 * FILE_CONTENTS
156 * --=_1_1321709112_1605
157 * without any encoding of FILE_CONTENTS. (Basically, it expects that FILE
158 * is the result of "makemime -c").
159 *
160 * -j MULTIPART_FILE1 SINGLE_FILE2 should output MULTIPART_FILE1 + SINGLE_FILE2
161 *
162 * Our current behavior is a mutant "-m + -c + -j" one: we create multipart MIME
163 * and we put "-c" encoded FILEs into many multipart sections.
164 */
165
144int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 166int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
145int makemime_main(int argc UNUSED_PARAM, char **argv) 167int makemime_main(int argc UNUSED_PARAM, char **argv)
146{ 168{
147 llist_t *opt_headers = NULL, *l; 169 llist_t *opt_headers = NULL, *l;
148 const char *opt_output; 170 const char *opt_output;
171 const char *content_type = "application/octet-stream";
149#define boundary opt_output 172#define boundary opt_output
150
151 enum { 173 enum {
152 OPT_c = 1 << 0, // create (non-multipart) section 174 OPT_c = 1 << 0, // create (non-multipart) section
153 OPT_e = 1 << 1, // Content-Transfer-Encoding. Ignored. Assumed base64 175 OPT_e = 1 << 1, // Content-Transfer-Encoding. Ignored. Assumed base64
@@ -164,8 +186,8 @@ int makemime_main(int argc UNUSED_PARAM, char **argv)
164 // parse options 186 // parse options
165 opt_complementary = "a::"; 187 opt_complementary = "a::";
166 opts = getopt32(argv, 188 opts = getopt32(argv,
167 "c:e:o:C:N:a:", //:m:j:", 189 "c:e:o:C:N:a:", // "m:j:",
168 &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL 190 &content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL
169 ); 191 );
170 //argc -= optind; 192 //argc -= optind;
171 argv += optind; 193 argv += optind;
@@ -202,7 +224,7 @@ int makemime_main(int argc UNUSED_PARAM, char **argv)
202 "Content-Disposition: inline; filename=\"%s\"\n" 224 "Content-Disposition: inline; filename=\"%s\"\n"
203 "Content-Transfer-Encoding: base64\n" 225 "Content-Transfer-Encoding: base64\n"
204 , boundary 226 , boundary
205 , G.content_type 227 , content_type
206 , G.opt_charset 228 , G.opt_charset
207 , bb_get_last_path_component_strip(*argv) 229 , bb_get_last_path_component_strip(*argv)
208 ); 230 );
diff --git a/mailutils/reformime.c b/mailutils/reformime.c
index 5e28ef729..8e7d455f6 100644
--- a/mailutils/reformime.c
+++ b/mailutils/reformime.c
@@ -1,6 +1,5 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * makemime: create MIME-encoded message
4 * reformime: parse MIME-encoded message 3 * reformime: parse MIME-encoded message
5 * 4 *
6 * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com> 5 * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c
index dbd491002..aa381c60f 100644
--- a/mailutils/sendmail.c
+++ b/mailutils/sendmail.c
@@ -281,17 +281,19 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
281 281
282 // analyze headers 282 // analyze headers
283 // To: or Cc: headers add recipients 283 // To: or Cc: headers add recipients
284 if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { 284 if (opts & OPT_t) {
285 rcptto(sane_address(s+3)); 285 if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) {
286 goto addheader; 286 rcptto(sane_address(s+3));
287 goto addheader;
288 }
289 // Bcc: header adds blind copy (hidden) recipient
290 if (0 == strncasecmp("Bcc:", s, 4)) {
291 rcptto(sane_address(s+4));
292 free(s);
293 continue; // N.B. Bcc: vanishes from headers!
294 }
287 } 295 }
288 // Bcc: header adds blind copy (hidden) recipient 296 if (strchr(s, ':') || (list && isspace(s[0]))) {
289 if (0 == strncasecmp("Bcc:", s, 4)) {
290 rcptto(sane_address(s+4));
291 free(s);
292 // N.B. Bcc: vanishes from headers!
293 } else
294 if (strchr(s, ':') || (list && skip_whitespace(s) != s)) {
295 // other headers go verbatim 297 // other headers go verbatim
296 // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. 298 // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines.
297 // Continuation is denoted by prefixing additional lines with whitespace(s). 299 // Continuation is denoted by prefixing additional lines with whitespace(s).
diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c
index 04d583df6..988439b25 100644
--- a/miscutils/fbsplash.c
+++ b/miscutils/fbsplash.c
@@ -143,7 +143,7 @@ static void fb_open(const char *strfb_device)
143 143
144 // map the device in memory 144 // map the device in memory
145 G.addr = mmap(NULL, 145 G.addr = mmap(NULL,
146 G.scr_var.xres * G.scr_var.yres * G.bytes_per_pixel, 146 G.scr_var.yres * G.scr_fix.line_length,
147 PROT_WRITE, MAP_SHARED, fbfd, 0); 147 PROT_WRITE, MAP_SHARED, fbfd, 0);
148 if (G.addr == MAP_FAILED) 148 if (G.addr == MAP_FAILED)
149 bb_perror_msg_and_die("mmap"); 149 bb_perror_msg_and_die("mmap");
@@ -213,8 +213,8 @@ static void fb_drawrectangle(void)
213 thispix = fb_pixel_value(nred, ngreen, nblue); 213 thispix = fb_pixel_value(nred, ngreen, nblue);
214 214
215 // horizontal lines 215 // horizontal lines
216 ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; 216 ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel;
217 ptr2 = G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; 217 ptr2 = G.addr + (G.nbar_posy + G.nbar_height - 1) * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel;
218 cnt = G.nbar_width - 1; 218 cnt = G.nbar_width - 1;
219 do { 219 do {
220 fb_write_pixel(ptr1, thispix); 220 fb_write_pixel(ptr1, thispix);
@@ -224,14 +224,14 @@ static void fb_drawrectangle(void)
224 } while (--cnt >= 0); 224 } while (--cnt >= 0);
225 225
226 // vertical lines 226 // vertical lines
227 ptr1 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * G.bytes_per_pixel; 227 ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel;
228 ptr2 = G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel; 228 ptr2 = G.addr + G.nbar_posy * G.scr_fix.line_length + (G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel;
229 cnt = G.nbar_height - 1; 229 cnt = G.nbar_height - 1;
230 do { 230 do {
231 fb_write_pixel(ptr1, thispix); 231 fb_write_pixel(ptr1, thispix);
232 fb_write_pixel(ptr2, thispix); 232 fb_write_pixel(ptr2, thispix);
233 ptr1 += G.scr_var.xres * G.bytes_per_pixel; 233 ptr1 += G.scr_fix.line_length;
234 ptr2 += G.scr_var.xres * G.bytes_per_pixel; 234 ptr2 += G.scr_fix.line_length;
235 } while (--cnt >= 0); 235 } while (--cnt >= 0);
236} 236}
237 237
@@ -254,7 +254,7 @@ static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos,
254 cnt1 = ny2pos - ny1pos; 254 cnt1 = ny2pos - ny1pos;
255 nypos = ny1pos; 255 nypos = ny1pos;
256 do { 256 do {
257 ptr = G.addr + (nypos * G.scr_var.xres + nx1pos) * G.bytes_per_pixel; 257 ptr = G.addr + nypos * G.scr_fix.line_length + nx1pos * G.bytes_per_pixel;
258 cnt2 = nx2pos - nx1pos; 258 cnt2 = nx2pos - nx1pos;
259 do { 259 do {
260 fb_write_pixel(ptr, thispix); 260 fb_write_pixel(ptr, thispix);
diff --git a/miscutils/man.c b/miscutils/man.c
index 3bf7e84b6..611466349 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -30,16 +30,6 @@ echo ".pl \n(nlu+10"
30 30
31*/ 31*/
32 32
33#if ENABLE_FEATURE_SEAMLESS_LZMA
34#define Z_SUFFIX ".lzma"
35#elif ENABLE_FEATURE_SEAMLESS_BZ2
36#define Z_SUFFIX ".bz2"
37#elif ENABLE_FEATURE_SEAMLESS_GZ
38#define Z_SUFFIX ".gz"
39#else
40#define Z_SUFFIX ""
41#endif
42
43static int show_manpage(const char *pager, char *man_filename, int man, int level); 33static int show_manpage(const char *pager, char *man_filename, int man, int level);
44 34
45static int run_pipe(const char *pager, char *man_filename, int man, int level) 35static int run_pipe(const char *pager, char *man_filename, int man, int level)
@@ -102,7 +92,7 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level)
102 92
103 /* Links do not have .gz extensions, even if manpage 93 /* Links do not have .gz extensions, even if manpage
104 * is compressed */ 94 * is compressed */
105 man_filename = xasprintf("%s/%s" Z_SUFFIX, man_filename, linkname); 95 man_filename = xasprintf("%s/%s", man_filename, linkname);
106 free(line); 96 free(line);
107 /* Note: we leak "new" man_filename string as well... */ 97 /* Note: we leak "new" man_filename string as well... */
108 if (show_manpage(pager, man_filename, man, level + 1)) 98 if (show_manpage(pager, man_filename, man, level + 1))
@@ -124,32 +114,37 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level)
124 return 1; 114 return 1;
125} 115}
126 116
127/* man_filename is of the form "/dir/dir/dir/name.s" Z_SUFFIX */ 117/* man_filename is of the form "/dir/dir/dir/name.s" */
128static int show_manpage(const char *pager, char *man_filename, int man, int level) 118static int show_manpage(const char *pager, char *man_filename, int man, int level)
129{ 119{
120#if SEAMLESS_COMPRESSION
121 /* We leak this allocation... */
122 char *filename_with_zext = xasprintf("%s.lzma", man_filename);
123 char *ext = strrchr(filename_with_zext, '.') + 1;
124#endif
125
130#if ENABLE_FEATURE_SEAMLESS_LZMA 126#if ENABLE_FEATURE_SEAMLESS_LZMA
127 if (run_pipe(pager, filename_with_zext, man, level))
128 return 1;
129#endif
130#if ENABLE_FEATURE_SEAMLESS_XZ
131 strcpy(ext, "xz");
131 if (run_pipe(pager, man_filename, man, level)) 132 if (run_pipe(pager, man_filename, man, level))
132 return 1; 133 return 1;
133#endif 134#endif
134
135#if ENABLE_FEATURE_SEAMLESS_BZ2 135#if ENABLE_FEATURE_SEAMLESS_BZ2
136#if ENABLE_FEATURE_SEAMLESS_LZMA 136 strcpy(ext, "bz2");
137 strcpy(strrchr(man_filename, '.') + 1, "bz2");
138#endif
139 if (run_pipe(pager, man_filename, man, level)) 137 if (run_pipe(pager, man_filename, man, level))
140 return 1; 138 return 1;
141#endif 139#endif
142
143#if ENABLE_FEATURE_SEAMLESS_GZ 140#if ENABLE_FEATURE_SEAMLESS_GZ
144#if ENABLE_FEATURE_SEAMLESS_LZMA || ENABLE_FEATURE_SEAMLESS_BZ2 141 strcpy(ext, "gz");
145 strcpy(strrchr(man_filename, '.') + 1, "gz");
146#endif
147 if (run_pipe(pager, man_filename, man, level)) 142 if (run_pipe(pager, man_filename, man, level))
148 return 1; 143 return 1;
149#endif 144#endif
150 145
151#if ENABLE_FEATURE_SEAMLESS_LZMA || ENABLE_FEATURE_SEAMLESS_BZ2 || ENABLE_FEATURE_SEAMLESS_GZ 146#if SEAMLESS_COMPRESSION
152 *strrchr(man_filename, '.') = '\0'; 147 ext[-1] = '\0';
153#endif 148#endif
154 if (run_pipe(pager, man_filename, man, level)) 149 if (run_pipe(pager, man_filename, man, level))
155 return 1; 150 return 1;
@@ -262,7 +257,7 @@ int man_main(int argc UNUSED_PARAM, char **argv)
262 /* Search for cat, then man page */ 257 /* Search for cat, then man page */
263 while (cat0man1 < 2) { 258 while (cat0man1 < 2) {
264 int found_here; 259 int found_here;
265 man_filename = xasprintf("%s/%s%.*s/%s.%.*s" Z_SUFFIX, 260 man_filename = xasprintf("%s/%s%.*s/%s.%.*s",
266 cur_path, 261 cur_path,
267 "cat\0man" + (cat0man1 * 4), 262 "cat\0man" + (cat0man1 * 4),
268 sect_len, cur_sect, 263 sect_len, cur_sect,
diff --git a/miscutils/rx.c b/miscutils/rx.c
index c48a61fd0..af597320c 100644
--- a/miscutils/rx.c
+++ b/miscutils/rx.c
@@ -207,6 +207,7 @@ static int receive(/*int read_fd, */int file_fd)
207 continue; 207 continue;
208 error: 208 error:
209 timeout: 209 timeout:
210 blockLength = 0;
210 errors++; 211 errors++;
211 if (errors == MAXERRORS) { 212 if (errors == MAXERRORS) {
212 /* Abort */ 213 /* Abort */
diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c
index 2a426dbdc..dd99a44f4 100644
--- a/miscutils/ubi_tools.c
+++ b/miscutils/ubi_tools.c
@@ -60,6 +60,10 @@
60//kbuild:lib-$(CONFIG_UBIUPDATEVOL) += ubi_tools.o 60//kbuild:lib-$(CONFIG_UBIUPDATEVOL) += ubi_tools.o
61 61
62#include "libbb.h" 62#include "libbb.h"
63/* Some versions of kernel have broken headers, need this hack */
64#ifndef __packed
65# define __packed __attribute__((packed))
66#endif
63#include <mtd/ubi-user.h> 67#include <mtd/ubi-user.h>
64 68
65#define OPTION_M (1 << 0) 69#define OPTION_M (1 << 0)
diff --git a/modutils/depmod.c b/modutils/depmod.c
index f6c0bf33a..775236126 100644
--- a/modutils/depmod.c
+++ b/modutils/depmod.c
@@ -10,11 +10,6 @@
10 10
11//applet:IF_DEPMOD(APPLET(depmod, BB_DIR_SBIN, BB_SUID_DROP)) 11//applet:IF_DEPMOD(APPLET(depmod, BB_DIR_SBIN, BB_SUID_DROP))
12 12
13//usage:#if !ENABLE_MODPROBE_SMALL
14//usage:#define depmod_trivial_usage NOUSAGE_STR
15//usage:#define depmod_full_usage ""
16//usage:#endif
17
18#include "libbb.h" 13#include "libbb.h"
19#include "modutils.h" 14#include "modutils.h"
20#include <sys/utsname.h> /* uname() */ 15#include <sys/utsname.h> /* uname() */
@@ -131,7 +126,16 @@ static void xfreopen_write(const char *file, FILE *f)
131 bb_perror_msg_and_die("can't open '%s'", file); 126 bb_perror_msg_and_die("can't open '%s'", file);
132} 127}
133 128
134/* Usage: 129//usage:#if !ENABLE_MODPROBE_SMALL
130//usage:#define depmod_trivial_usage "[-n] [-b BASE] [VERSION] [MODFILES]..."
131//usage:#define depmod_full_usage "\n\n"
132//usage: "Generate modules.dep, alias, and symbols files"
133//usage: "\n"
134//usage: "\n -b BASE Use BASE/lib/modules/VERSION"
135//usage: "\n -n Dry run: print files to stdout"
136//usage:#endif
137
138/* Upstream usage:
135 * [-aAenv] [-C FILE or DIR] [-b BASE] [-F System.map] [VERSION] [MODFILES]... 139 * [-aAenv] [-C FILE or DIR] [-b BASE] [-F System.map] [VERSION] [MODFILES]...
136 * -a --all 140 * -a --all
137 * Probe all modules. Default if no MODFILES. 141 * Probe all modules. Default if no MODFILES.
@@ -142,7 +146,7 @@ static void xfreopen_write(const char *file, FILE *f)
142 * -C --config FILE or DIR 146 * -C --config FILE or DIR
143 * Path to /etc/depmod.conf or /etc/depmod.d/ 147 * Path to /etc/depmod.conf or /etc/depmod.d/
144 * -e --errsyms 148 * -e --errsyms
145 * When combined with the -F option, this reports any symbols which 149 * When combined with the -F option, this reports any symbols
146 * which are not supplied by other modules or kernel. 150 * which are not supplied by other modules or kernel.
147 * -F --filesyms System.map 151 * -F --filesyms System.map
148 * -n --dry-run 152 * -n --dry-run
@@ -154,8 +158,13 @@ static void xfreopen_write(const char *file, FILE *f)
154 * -u No-op 158 * -u No-op
155 * -q No-op 159 * -q No-op
156 * 160 *
157 * So far we only support: [-rn] [-b BASE] [VERSION] [MODFILES]... 161 * So far we only support: [-n] [-b BASE] [VERSION] [MODFILES]...
158 * -aAeF are accepted but ignored. -vC are not accepted. 162 * Accepted but ignored:
163 * -aAe
164 * -F System.map
165 * -C FILE/DIR
166 *
167 * Not accepted: -v
159 */ 168 */
160enum { 169enum {
161 //OPT_a = (1 << 0), /* All modules, ignore mods in argv */ 170 //OPT_a = (1 << 0), /* All modules, ignore mods in argv */
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index f5b283b47..bd855f628 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -696,6 +696,10 @@ The following options are useful for people managing distributions:
696 696
697//usage:#if ENABLE_MODPROBE_SMALL 697//usage:#if ENABLE_MODPROBE_SMALL
698 698
699//// Note: currently, help system shows modprobe --help text for all aliased cmds
700//// (see APPLET_ODDNAME macro definition).
701//// All other help texts defined below are not used. FIXME?
702
699//usage:#define depmod_trivial_usage NOUSAGE_STR 703//usage:#define depmod_trivial_usage NOUSAGE_STR
700//usage:#define depmod_full_usage "" 704//usage:#define depmod_full_usage ""
701 705
@@ -805,7 +809,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
805 opt_complementary = "-1"; 809 opt_complementary = "-1";
806 /* only -q (quiet) and -r (rmmod), 810 /* only -q (quiet) and -r (rmmod),
807 * the rest are accepted and ignored (compat) */ 811 * the rest are accepted and ignored (compat) */
808 getopt32(argv, "qrfsvw"); 812 getopt32(argv, "qrfsvwb");
809 argv += optind; 813 argv += optind;
810 814
811 /* are we rmmod? -> simulate modprobe -r */ 815 /* are we rmmod? -> simulate modprobe -r */
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index c1a1828d7..fb6c65990 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -101,12 +101,15 @@
101//usage: ) 101//usage: )
102//usage:#endif /* !ENABLE_MODPROBE_SMALL */ 102//usage:#endif /* !ENABLE_MODPROBE_SMALL */
103 103
104/* Note that usage text doesn't document various 2.4 options 104/* Note: usage text doesn't document various 2.4 options
105 * we pull in through INSMOD_OPTS define */ 105 * we pull in through INSMOD_OPTS define
106#define MODPROBE_OPTS "alrD" IF_FEATURE_MODPROBE_BLACKLIST("b") 106 * Note2: -b is always accepted, but if !FEATURE_MODPROBE_BLACKLIST,
107 * it is a no-op.
108 */
109#define MODPROBE_OPTS "alrDb"
107/* -a and -D _are_ in fact compatible */ 110/* -a and -D _are_ in fact compatible */
108#define MODPROBE_COMPLEMENTARY ("q-v:v-q:l--arD:r--alD:a--lr:D--rl") 111#define MODPROBE_COMPLEMENTARY ("q-v:v-q:l--arD:r--alD:a--lr:D--rl")
109//#define MODPROBE_OPTS "acd:lnrt:C:" IF_FEATURE_MODPROBE_BLACKLIST("b") 112//#define MODPROBE_OPTS "acd:lnrt:C:b"
110//#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al" 113//#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al"
111enum { 114enum {
112 OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ 115 OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */
@@ -133,10 +136,8 @@ static const char modprobe_longopts[] ALIGN1 =
133 /* module-init-tools 3.11.1 has only long opt --show-depends 136 /* module-init-tools 3.11.1 has only long opt --show-depends
134 * but no short -D, we provide long opt for scripts which 137 * but no short -D, we provide long opt for scripts which
135 * were written for 3.11.1: */ 138 * were written for 3.11.1: */
136 "show-depends\0" No_argument "D" 139 "show-depends\0" No_argument "D"
137 // IF_FEATURE_MODPROBE_BLACKLIST(
138 // "use-blacklist\0" No_argument "b" 140 // "use-blacklist\0" No_argument "b"
139 // )
140 ; 141 ;
141#endif 142#endif
142 143
diff --git a/networking/Config.src b/networking/Config.src
index 8aeba0ef9..fb7dca7d4 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -199,14 +199,22 @@ config FEATURE_HTTPD_BASIC_AUTH
199 help 199 help
200 Utilizes password settings from /etc/httpd.conf for basic 200 Utilizes password settings from /etc/httpd.conf for basic
201 authentication on a per url basis. 201 authentication on a per url basis.
202 Example for httpd.conf file:
203 /adm:toor:PaSsWd
202 204
203config FEATURE_HTTPD_AUTH_MD5 205config FEATURE_HTTPD_AUTH_MD5
204 bool "Support MD5 crypted passwords for http Authentication" 206 bool "Support MD5 crypted passwords for http Authentication"
205 default y 207 default y
206 depends on FEATURE_HTTPD_BASIC_AUTH 208 depends on FEATURE_HTTPD_BASIC_AUTH
207 help 209 help
208 Enables basic per URL authentication from /etc/httpd.conf 210 Enables encrypted passwords, and wildcard user/passwords
209 using md5 passwords. 211 in httpd.conf file.
212 User '*' means 'any system user name is ok',
213 password of '*' means 'use system password for this user'
214 Examples:
215 /adm:toor:$1$P/eKnWXS$aI1aPGxT.dJD5SzqAKWrF0
216 /adm:root:*
217 /wiki:*:*
210 218
211config FEATURE_HTTPD_CGI 219config FEATURE_HTTPD_CGI
212 bool "Support Common Gateway Interface (CGI)" 220 bool "Support Common Gateway Interface (CGI)"
@@ -223,8 +231,8 @@ config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
223 help 231 help
224 This option enables support for running scripts through an 232 This option enables support for running scripts through an
225 interpreter. Turn this on if you want PHP scripts to work 233 interpreter. Turn this on if you want PHP scripts to work
226 properly. You need to supply an additional line in your httpd 234 properly. You need to supply an additional line in your
227 config file: 235 httpd.conf file:
228 *.php:/path/to/your/php 236 *.php:/path/to/your/php
229 237
230config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV 238config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
diff --git a/networking/ftpd.c b/networking/ftpd.c
index e38138c0a..1c97df564 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -1179,8 +1179,7 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
1179#endif 1179#endif
1180 1180
1181 if (argv[optind]) { 1181 if (argv[optind]) {
1182 xchdir(argv[optind]); 1182 xchroot(argv[optind]);
1183 chroot(".");
1184 } 1183 }
1185 1184
1186 //umask(077); - admin can set umask before starting us 1185 //umask(077); - admin can set umask before starting us
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index abdf94c45..8283366cc 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -16,37 +16,37 @@
16//usage:#define ftpget_trivial_usage 16//usage:#define ftpget_trivial_usage
17//usage: "[OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE" 17//usage: "[OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE"
18//usage:#define ftpget_full_usage "\n\n" 18//usage:#define ftpget_full_usage "\n\n"
19//usage: "Retrieve a remote file via FTP\n" 19//usage: "Download a file via FTP\n"
20//usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS( 20//usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS(
21//usage: "\n -c,--continue Continue previous transfer" 21//usage: "\n -c,--continue Continue previous transfer"
22//usage: "\n -v,--verbose Verbose" 22//usage: "\n -v,--verbose Verbose"
23//usage: "\n -u,--username Username" 23//usage: "\n -u,--username USER Username"
24//usage: "\n -p,--password Password" 24//usage: "\n -p,--password PASS Password"
25//usage: "\n -P,--port Port number" 25//usage: "\n -P,--port NUM Port"
26//usage: ) 26//usage: )
27//usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( 27//usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS(
28//usage: "\n -c Continue previous transfer" 28//usage: "\n -c Continue previous transfer"
29//usage: "\n -v Verbose" 29//usage: "\n -v Verbose"
30//usage: "\n -u Username" 30//usage: "\n -u USER Username"
31//usage: "\n -p Password" 31//usage: "\n -p PASS Password"
32//usage: "\n -P Port number" 32//usage: "\n -P NUM Port"
33//usage: ) 33//usage: )
34//usage: 34//usage:
35//usage:#define ftpput_trivial_usage 35//usage:#define ftpput_trivial_usage
36//usage: "[OPTIONS] HOST [REMOTE_FILE] LOCAL_FILE" 36//usage: "[OPTIONS] HOST [REMOTE_FILE] LOCAL_FILE"
37//usage:#define ftpput_full_usage "\n\n" 37//usage:#define ftpput_full_usage "\n\n"
38//usage: "Store a local file on a remote machine via FTP\n" 38//usage: "Upload a file to a FTP server\n"
39//usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS( 39//usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS(
40//usage: "\n -v,--verbose Verbose" 40//usage: "\n -v,--verbose Verbose"
41//usage: "\n -u,--username Username" 41//usage: "\n -u,--username USER Username"
42//usage: "\n -p,--password Password" 42//usage: "\n -p,--password PASS Password"
43//usage: "\n -P,--port Port number" 43//usage: "\n -P,--port NUM Port"
44//usage: ) 44//usage: )
45//usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( 45//usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS(
46//usage: "\n -v Verbose" 46//usage: "\n -v Verbose"
47//usage: "\n -u Username" 47//usage: "\n -u USER Username"
48//usage: "\n -p Password" 48//usage: "\n -p PASS Password"
49//usage: "\n -P Port number" 49//usage: "\n -P NUM Port number"
50//usage: ) 50//usage: )
51 51
52#include "libbb.h" 52#include "libbb.h"
diff --git a/networking/httpd.c b/networking/httpd.c
index 24482fe52..f233cb0ba 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -54,6 +54,8 @@
54 * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/ 54 * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/
55 * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ 55 * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/
56 * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ 56 * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/
57 * /adm:root:* # or user root, pwd from /etc/passwd on urls starting with /adm/
58 * /wiki:*:* # or any user from /etc/passwd with according pwd on urls starting with /wiki/
57 * .au:audio/basic # additional mime type for audio.au files 59 * .au:audio/basic # additional mime type for audio.au files
58 * *.php:/path/php # run xxx.php through an interpreter 60 * *.php:/path/php # run xxx.php through an interpreter
59 * 61 *
@@ -123,6 +125,14 @@
123//usage: "\n -d STRING URL decode STRING" 125//usage: "\n -d STRING URL decode STRING"
124 126
125#include "libbb.h" 127#include "libbb.h"
128#if ENABLE_PAM
129/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
130# undef setlocale
131/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx.
132 * Apparently they like to confuse people. */
133# include <security/pam_appl.h>
134# include <security/pam_misc.h>
135#endif
126#if ENABLE_FEATURE_HTTPD_USE_SENDFILE 136#if ENABLE_FEATURE_HTTPD_USE_SENDFILE
127# include <sys/sendfile.h> 137# include <sys/sendfile.h>
128#endif 138#endif
@@ -338,7 +348,7 @@ struct globals {
338#define range_len (G.range_len ) 348#define range_len (G.range_len )
339#else 349#else
340enum { 350enum {
341 range_start = 0, 351 range_start = -1,
342 range_end = MAXINT(off_t) - 1, 352 range_end = MAXINT(off_t) - 1,
343 range_len = MAXINT(off_t), 353 range_len = MAXINT(off_t),
344}; 354};
@@ -360,6 +370,7 @@ enum {
360#define INIT_G() do { \ 370#define INIT_G() do { \
361 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 371 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
362 IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \ 372 IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
373 IF_FEATURE_HTTPD_RANGES(range_start = -1;) \
363 bind_addr_or_port = "80"; \ 374 bind_addr_or_port = "80"; \
364 index_page = index_html; \ 375 index_page = index_html; \
365 file_size = -1; \ 376 file_size = -1; \
@@ -1255,18 +1266,21 @@ static void setenv1(const char *name, const char *value)
1255 * 1266 *
1256 * Parameters: 1267 * Parameters:
1257 * const char *url The requested URL (with leading /). 1268 * const char *url The requested URL (with leading /).
1269 * const char *orig_uri The original URI before rewriting (if any)
1258 * int post_len Length of the POST body. 1270 * int post_len Length of the POST body.
1259 * const char *cookie For set HTTP_COOKIE. 1271 * const char *cookie For set HTTP_COOKIE.
1260 * const char *content_type For set CONTENT_TYPE. 1272 * const char *content_type For set CONTENT_TYPE.
1261 */ 1273 */
1262static void send_cgi_and_exit( 1274static void send_cgi_and_exit(
1263 const char *url, 1275 const char *url,
1276 const char *orig_uri,
1264 const char *request, 1277 const char *request,
1265 int post_len, 1278 int post_len,
1266 const char *cookie, 1279 const char *cookie,
1267 const char *content_type) NORETURN; 1280 const char *content_type) NORETURN;
1268static void send_cgi_and_exit( 1281static void send_cgi_and_exit(
1269 const char *url, 1282 const char *url,
1283 const char *orig_uri,
1270 const char *request, 1284 const char *request,
1271 int post_len, 1285 int post_len,
1272 const char *cookie, 1286 const char *cookie,
@@ -1274,7 +1288,7 @@ static void send_cgi_and_exit(
1274{ 1288{
1275 struct fd_pair fromCgi; /* CGI -> httpd pipe */ 1289 struct fd_pair fromCgi; /* CGI -> httpd pipe */
1276 struct fd_pair toCgi; /* httpd -> CGI pipe */ 1290 struct fd_pair toCgi; /* httpd -> CGI pipe */
1277 char *script; 1291 char *script, *last_slash;
1278 int pid; 1292 int pid;
1279 1293
1280 /* Make a copy. NB: caller guarantees: 1294 /* Make a copy. NB: caller guarantees:
@@ -1288,22 +1302,25 @@ static void send_cgi_and_exit(
1288 */ 1302 */
1289 1303
1290 /* Check for [dirs/]script.cgi/PATH_INFO */ 1304 /* Check for [dirs/]script.cgi/PATH_INFO */
1291 script = (char*)url; 1305 last_slash = script = (char*)url;
1292 while ((script = strchr(script + 1, '/')) != NULL) { 1306 while ((script = strchr(script + 1, '/')) != NULL) {
1307 int dir;
1293 *script = '\0'; 1308 *script = '\0';
1294 if (!is_directory(url + 1, 1, NULL)) { 1309 dir = is_directory(url + 1, /*followlinks:*/ 1);
1310 *script = '/';
1311 if (!dir) {
1295 /* not directory, found script.cgi/PATH_INFO */ 1312 /* not directory, found script.cgi/PATH_INFO */
1296 *script = '/';
1297 break; 1313 break;
1298 } 1314 }
1299 *script = '/'; /* is directory, find next '/' */ 1315 /* is directory, find next '/' */
1316 last_slash = script;
1300 } 1317 }
1301 setenv1("PATH_INFO", script); /* set to /PATH_INFO or "" */ 1318 setenv1("PATH_INFO", script); /* set to /PATH_INFO or "" */
1302 setenv1("REQUEST_METHOD", request); 1319 setenv1("REQUEST_METHOD", request);
1303 if (g_query) { 1320 if (g_query) {
1304 putenv(xasprintf("%s=%s?%s", "REQUEST_URI", url, g_query)); 1321 putenv(xasprintf("%s=%s?%s", "REQUEST_URI", orig_uri, g_query));
1305 } else { 1322 } else {
1306 setenv1("REQUEST_URI", url); 1323 setenv1("REQUEST_URI", orig_uri);
1307 } 1324 }
1308 if (script != NULL) 1325 if (script != NULL)
1309 *script = '\0'; /* cut off /PATH_INFO */ 1326 *script = '\0'; /* cut off /PATH_INFO */
@@ -1377,7 +1394,7 @@ static void send_cgi_and_exit(
1377 log_and_exit(); 1394 log_and_exit();
1378 } 1395 }
1379 1396
1380 if (!pid) { 1397 if (pid == 0) {
1381 /* Child process */ 1398 /* Child process */
1382 char *argv[3]; 1399 char *argv[3];
1383 1400
@@ -1393,7 +1410,7 @@ static void send_cgi_and_exit(
1393 /* dup2(1, 2); */ 1410 /* dup2(1, 2); */
1394 1411
1395 /* Chdiring to script's dir */ 1412 /* Chdiring to script's dir */
1396 script = strrchr(url, '/'); 1413 script = last_slash;
1397 if (script != url) { /* paranoia */ 1414 if (script != url) { /* paranoia */
1398 *script = '\0'; 1415 *script = '\0';
1399 if (chdir(url + 1) != 0) { 1416 if (chdir(url + 1) != 0) {
@@ -1573,10 +1590,10 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1573 if (what == SEND_BODY /* err pages and ranges don't mix */ 1590 if (what == SEND_BODY /* err pages and ranges don't mix */
1574 || content_gzip /* we are sending compressed page: can't do ranges */ ///why? 1591 || content_gzip /* we are sending compressed page: can't do ranges */ ///why?
1575 ) { 1592 ) {
1576 range_start = 0; 1593 range_start = -1;
1577 } 1594 }
1578 range_len = MAXINT(off_t); 1595 range_len = MAXINT(off_t);
1579 if (range_start) { 1596 if (range_start >= 0) {
1580 if (!range_end) { 1597 if (!range_end) {
1581 range_end = file_size - 1; 1598 range_end = file_size - 1;
1582 } 1599 }
@@ -1584,7 +1601,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1584 || lseek(fd, range_start, SEEK_SET) != range_start 1601 || lseek(fd, range_start, SEEK_SET) != range_start
1585 ) { 1602 ) {
1586 lseek(fd, 0, SEEK_SET); 1603 lseek(fd, 0, SEEK_SET);
1587 range_start = 0; 1604 range_start = -1;
1588 } else { 1605 } else {
1589 range_len = range_end - range_start + 1; 1606 range_len = range_end - range_start + 1;
1590 send_headers(HTTP_PARTIAL_CONTENT); 1607 send_headers(HTTP_PARTIAL_CONTENT);
@@ -1607,7 +1624,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
1607 break; /* fall back to read/write loop */ 1624 break; /* fall back to read/write loop */
1608 goto fin; 1625 goto fin;
1609 } 1626 }
1610 IF_FEATURE_HTTPD_RANGES(range_len -= sz;) 1627 IF_FEATURE_HTTPD_RANGES(range_len -= count;)
1611 if (count == 0 || range_len == 0) 1628 if (count == 0 || range_len == 0)
1612 log_and_exit(); 1629 log_and_exit();
1613 } 1630 }
@@ -1658,6 +1675,56 @@ static int checkPermIP(void)
1658} 1675}
1659 1676
1660#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1677#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
1678
1679# if ENABLE_FEATURE_HTTPD_AUTH_MD5 && ENABLE_PAM
1680struct pam_userinfo {
1681 const char *name;
1682 const char *pw;
1683};
1684
1685static int pam_talker(int num_msg,
1686 const struct pam_message **msg,
1687 struct pam_response **resp,
1688 void *appdata_ptr)
1689{
1690 int i;
1691 struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr;
1692 struct pam_response *response;
1693
1694 if (!resp || !msg || !userinfo)
1695 return PAM_CONV_ERR;
1696
1697 /* allocate memory to store response */
1698 response = xzalloc(num_msg * sizeof(*response));
1699
1700 /* copy values */
1701 for (i = 0; i < num_msg; i++) {
1702 const char *s;
1703
1704 switch (msg[i]->msg_style) {
1705 case PAM_PROMPT_ECHO_ON:
1706 s = userinfo->name;
1707 break;
1708 case PAM_PROMPT_ECHO_OFF:
1709 s = userinfo->pw;
1710 break;
1711 case PAM_ERROR_MSG:
1712 case PAM_TEXT_INFO:
1713 s = "";
1714 break;
1715 default:
1716 free(response);
1717 return PAM_CONV_ERR;
1718 }
1719 response[i].resp = xstrdup(s);
1720 if (PAM_SUCCESS != 0)
1721 response[i].resp_retcode = PAM_SUCCESS;
1722 }
1723 *resp = response;
1724 return PAM_SUCCESS;
1725}
1726# endif
1727
1661/* 1728/*
1662 * Config file entries are of the form "/<path>:<user>:<passwd>". 1729 * Config file entries are of the form "/<path>:<user>:<passwd>".
1663 * If config file has no prefix match for path, access is allowed. 1730 * If config file has no prefix match for path, access is allowed.
@@ -1667,7 +1734,7 @@ static int checkPermIP(void)
1667 * 1734 *
1668 * Returns 1 if user_and_passwd is OK. 1735 * Returns 1 if user_and_passwd is OK.
1669 */ 1736 */
1670static int check_user_passwd(const char *path, const char *user_and_passwd) 1737static int check_user_passwd(const char *path, char *user_and_passwd)
1671{ 1738{
1672 Htaccess *cur; 1739 Htaccess *cur;
1673 const char *prev = NULL; 1740 const char *prev = NULL;
@@ -1675,6 +1742,7 @@ static int check_user_passwd(const char *path, const char *user_and_passwd)
1675 for (cur = g_auth; cur; cur = cur->next) { 1742 for (cur = g_auth; cur; cur = cur->next) {
1676 const char *dir_prefix; 1743 const char *dir_prefix;
1677 size_t len; 1744 size_t len;
1745 int r;
1678 1746
1679 dir_prefix = cur->before_colon; 1747 dir_prefix = cur->before_colon;
1680 1748
@@ -1690,7 +1758,8 @@ static int check_user_passwd(const char *path, const char *user_and_passwd)
1690 len = strlen(dir_prefix); 1758 len = strlen(dir_prefix);
1691 if (len != 1 /* dir_prefix "/" matches all, don't need to check */ 1759 if (len != 1 /* dir_prefix "/" matches all, don't need to check */
1692 && (strncmp(dir_prefix, path, len) != 0 1760 && (strncmp(dir_prefix, path, len) != 0
1693 || (path[len] != '/' && path[len] != '\0')) 1761 || (path[len] != '/' && path[len] != '\0')
1762 )
1694 ) { 1763 ) {
1695 continue; 1764 continue;
1696 } 1765 }
@@ -1699,38 +1768,103 @@ static int check_user_passwd(const char *path, const char *user_and_passwd)
1699 prev = dir_prefix; 1768 prev = dir_prefix;
1700 1769
1701 if (ENABLE_FEATURE_HTTPD_AUTH_MD5) { 1770 if (ENABLE_FEATURE_HTTPD_AUTH_MD5) {
1702 char *md5_passwd; 1771 char *colon_after_user;
1772 const char *passwd;
1773# if ENABLE_FEATURE_SHADOWPASSWDS && !ENABLE_PAM
1774 char sp_buf[256];
1775# endif
1703 1776
1704 md5_passwd = strchr(cur->after_colon, ':'); 1777 colon_after_user = strchr(user_and_passwd, ':');
1705 if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1' 1778 if (!colon_after_user)
1706 && md5_passwd[3] == '$' && md5_passwd[4] 1779 goto bad_input;
1707 ) {
1708 char *encrypted;
1709 int r, user_len_p1;
1710 1780
1711 md5_passwd++; 1781 /* compare "user:" */
1712 user_len_p1 = md5_passwd - cur->after_colon; 1782 if (cur->after_colon[0] != '*'
1713 /* comparing "user:" */ 1783 && strncmp(cur->after_colon, user_and_passwd,
1714 if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) { 1784 colon_after_user - user_and_passwd + 1) != 0
1785 ) {
1786 continue;
1787 }
1788 /* this cfg entry is '*' or matches username from peer */
1789
1790 passwd = strchr(cur->after_colon, ':');
1791 if (!passwd)
1792 goto bad_input;
1793 passwd++;
1794 if (passwd[0] == '*') {
1795# if ENABLE_PAM
1796 struct pam_userinfo userinfo;
1797 struct pam_conv conv_info = { &pam_talker, (void *) &userinfo };
1798 pam_handle_t *pamh;
1799
1800 *colon_after_user = '\0';
1801 userinfo.name = user_and_passwd;
1802 userinfo.pw = colon_after_user + 1;
1803 r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS;
1804 if (r == 0) {
1805 r = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS
1806 || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS
1807 ;
1808 pam_end(pamh, PAM_SUCCESS);
1809 }
1810 *colon_after_user = ':';
1811 goto end_check_passwd;
1812# else
1813# if ENABLE_FEATURE_SHADOWPASSWDS
1814 /* Using _r function to avoid pulling in static buffers */
1815 struct spwd spw;
1816# endif
1817 struct passwd *pw;
1818
1819 *colon_after_user = '\0';
1820 pw = getpwnam(user_and_passwd);
1821 *colon_after_user = ':';
1822 if (!pw || !pw->pw_passwd)
1715 continue; 1823 continue;
1824 passwd = pw->pw_passwd;
1825# if ENABLE_FEATURE_SHADOWPASSWDS
1826 if ((passwd[0] == 'x' || passwd[0] == '*') && !passwd[1]) {
1827 /* getspnam_r may return 0 yet set result to NULL.
1828 * At least glibc 2.4 does this. Be extra paranoid here. */
1829 struct spwd *result = NULL;
1830 r = getspnam_r(pw->pw_name, &spw, sp_buf, sizeof(sp_buf), &result);
1831 if (r == 0 && result)
1832 passwd = result->sp_pwdp;
1716 } 1833 }
1834# endif
1835 /* In this case, passwd is ALWAYS encrypted:
1836 * it came from /etc/passwd or /etc/shadow!
1837 */
1838 goto check_encrypted;
1839# endif /* ENABLE_PAM */
1840 }
1841 /* Else: passwd is from httpd.conf, it is either plaintext or encrypted */
1717 1842
1843 if (passwd[0] == '$' && isdigit(passwd[1])) {
1844 char *encrypted;
1845 check_encrypted:
1846 /* encrypt pwd from peer and check match with local one */
1718 encrypted = pw_encrypt( 1847 encrypted = pw_encrypt(
1719 user_and_passwd + user_len_p1 /* cleartext pwd from user */, 1848 /* pwd (from peer): */ colon_after_user + 1,
1720 md5_passwd /*salt */, 1 /* cleanup */); 1849 /* salt: */ passwd,
1721 r = strcmp(encrypted, md5_passwd); 1850 /* cleanup: */ 0
1851 );
1852 r = strcmp(encrypted, passwd);
1722 free(encrypted); 1853 free(encrypted);
1723 if (r == 0) 1854 } else {
1724 goto set_remoteuser_var; /* Ok */ 1855 /* local passwd is from httpd.conf and it's plaintext */
1725 continue; 1856 r = strcmp(colon_after_user + 1, passwd);
1726 } 1857 }
1858 goto end_check_passwd;
1727 } 1859 }
1728 1860 bad_input:
1729 /* Comparing plaintext "user:pass" in one go */ 1861 /* Comparing plaintext "user:pass" in one go */
1730 if (strcmp(cur->after_colon, user_and_passwd) == 0) { 1862 r = strcmp(cur->after_colon, user_and_passwd);
1731 set_remoteuser_var: 1863 end_check_passwd:
1864 if (r == 0) {
1732 remoteuser = xstrndup(user_and_passwd, 1865 remoteuser = xstrndup(user_and_passwd,
1733 strchrnul(user_and_passwd, ':') - user_and_passwd); 1866 strchrnul(user_and_passwd, ':') - user_and_passwd
1867 );
1734 return 1; /* Ok */ 1868 return 1; /* Ok */
1735 } 1869 }
1736 } /* for */ 1870 } /* for */
@@ -1869,7 +2003,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
1869 /* NB: urlcopy ptr is never changed after this */ 2003 /* NB: urlcopy ptr is never changed after this */
1870 2004
1871 /* Extract url args if present */ 2005 /* Extract url args if present */
1872 g_query = NULL; 2006 /* g_query = NULL; - already is */
1873 tptr = strchr(urlcopy, '?'); 2007 tptr = strchr(urlcopy, '?');
1874 if (tptr) { 2008 if (tptr) {
1875 *tptr++ = '\0'; 2009 *tptr++ = '\0';
@@ -1889,34 +2023,40 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
1889 /* Algorithm stolen from libbb bb_simplify_path(), 2023 /* Algorithm stolen from libbb bb_simplify_path(),
1890 * but don't strdup, retain trailing slash, protect root */ 2024 * but don't strdup, retain trailing slash, protect root */
1891 urlp = tptr = urlcopy; 2025 urlp = tptr = urlcopy;
1892 do { 2026 for (;;) {
1893 if (*urlp == '/') { 2027 if (*urlp == '/') {
1894 /* skip duplicate (or initial) slash */ 2028 /* skip duplicate (or initial) slash */
1895 if (*tptr == '/') { 2029 if (*tptr == '/') {
1896 continue; 2030 goto next_char;
1897 } 2031 }
1898 if (*tptr == '.') { 2032 if (*tptr == '.') {
1899 /* skip extra "/./" */ 2033 if (tptr[1] == '.' && (tptr[2] == '/' || tptr[2] == '\0')) {
1900 if (tptr[1] == '/' || !tptr[1]) { 2034 /* "..": be careful */
1901 continue; 2035 /* protect root */
1902 } 2036 if (urlp == urlcopy)
1903 /* "..": be careful */
1904 if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) {
1905 ++tptr;
1906 if (urlp == urlcopy) /* protect root */
1907 send_headers_and_exit(HTTP_BAD_REQUEST); 2037 send_headers_and_exit(HTTP_BAD_REQUEST);
1908 while (*--urlp != '/') /* omit previous dir */; 2038 /* omit previous dir */
2039 while (*--urlp != '/')
1909 continue; 2040 continue;
2041 /* skip to "./" or ".<NUL>" */
2042 tptr++;
2043 }
2044 if (tptr[1] == '/' || tptr[1] == '\0') {
2045 /* skip extra "/./" */
2046 goto next_char;
1910 } 2047 }
1911 } 2048 }
1912 } 2049 }
1913 *++urlp = *tptr; 2050 *++urlp = *tptr;
1914 } while (*++tptr); 2051 if (*urlp == '\0')
1915 *++urlp = '\0'; /* terminate after last character */ 2052 break;
2053 next_char:
2054 tptr++;
2055 }
1916 2056
1917 /* If URL is a directory, add '/' */ 2057 /* If URL is a directory, add '/' */
1918 if (urlp[-1] != '/') { 2058 if (urlp[-1] != '/') {
1919 if (is_directory(urlcopy + 1, 1, NULL)) { 2059 if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) {
1920 found_moved_temporarily = urlcopy; 2060 found_moved_temporarily = urlcopy;
1921 } 2061 }
1922 } 2062 }
@@ -1930,7 +2070,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
1930 while (ip_allowed && (tptr = strchr(tptr + 1, '/')) != NULL) { 2070 while (ip_allowed && (tptr = strchr(tptr + 1, '/')) != NULL) {
1931 /* have path1/path2 */ 2071 /* have path1/path2 */
1932 *tptr = '\0'; 2072 *tptr = '\0';
1933 if (is_directory(urlcopy + 1, 1, NULL)) { 2073 if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) {
1934 /* may have subdir config */ 2074 /* may have subdir config */
1935 parse_conf(urlcopy + 1, SUBDIR_PARSE); 2075 parse_conf(urlcopy + 1, SUBDIR_PARSE);
1936 ip_allowed = checkPermIP(); 2076 ip_allowed = checkPermIP();
@@ -2029,11 +2169,11 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2029 s += sizeof("bytes=")-1; 2169 s += sizeof("bytes=")-1;
2030 range_start = BB_STRTOOFF(s, &s, 10); 2170 range_start = BB_STRTOOFF(s, &s, 10);
2031 if (s[0] != '-' || range_start < 0) { 2171 if (s[0] != '-' || range_start < 0) {
2032 range_start = 0; 2172 range_start = -1;
2033 } else if (s[1]) { 2173 } else if (s[1]) {
2034 range_end = BB_STRTOOFF(s+1, NULL, 10); 2174 range_end = BB_STRTOOFF(s+1, NULL, 10);
2035 if (errno || range_end < range_start) 2175 if (errno || range_end < range_start)
2036 range_start = 0; 2176 range_start = -1;
2037 } 2177 }
2038 } 2178 }
2039 } 2179 }
@@ -2067,10 +2207,10 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2067 } 2207 }
2068 2208
2069#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 2209#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
2070 /* Case: no "Authorization:" was seen, but page does require passwd. 2210 /* Case: no "Authorization:" was seen, but page might require passwd.
2071 * Check that with dummy user:pass */ 2211 * Check that with dummy user:pass */
2072 if (authorized < 0) 2212 if (authorized < 0)
2073 authorized = check_user_passwd(urlcopy, ":"); 2213 authorized = check_user_passwd(urlcopy, (char *) "");
2074 if (!authorized) 2214 if (!authorized)
2075 send_headers_and_exit(HTTP_UNAUTHORIZED); 2215 send_headers_and_exit(HTTP_UNAUTHORIZED);
2076#endif 2216#endif
@@ -2116,12 +2256,20 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2116 /* protect listing "cgi-bin/" */ 2256 /* protect listing "cgi-bin/" */
2117 send_headers_and_exit(HTTP_FORBIDDEN); 2257 send_headers_and_exit(HTTP_FORBIDDEN);
2118 } 2258 }
2119 send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type); 2259 send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type);
2120 } 2260 }
2121#endif 2261#endif
2122 2262
2123 if (urlp[-1] == '/') 2263 if (urlp[-1] == '/') {
2264 /* When index_page string is appended to <dir>/ URL, it overwrites
2265 * the query string. If we fall back to call /cgi-bin/index.cgi,
2266 * query string would be lost and not available to the CGI.
2267 * Work around it by making a deep copy.
2268 */
2269 if (ENABLE_FEATURE_HTTPD_CGI)
2270 g_query = xstrdup(g_query); /* ok for NULL too */
2124 strcpy(urlp, index_page); 2271 strcpy(urlp, index_page);
2272 }
2125 if (stat(tptr, &sb) == 0) { 2273 if (stat(tptr, &sb) == 0) {
2126#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 2274#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
2127 char *suffix = strrchr(tptr, '.'); 2275 char *suffix = strrchr(tptr, '.');
@@ -2129,7 +2277,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2129 Htaccess *cur; 2277 Htaccess *cur;
2130 for (cur = script_i; cur; cur = cur->next) { 2278 for (cur = script_i; cur; cur = cur->next) {
2131 if (strcmp(cur->before_colon + 1, suffix) == 0) { 2279 if (strcmp(cur->before_colon + 1, suffix) == 0) {
2132 send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type); 2280 send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type);
2133 } 2281 }
2134 } 2282 }
2135 } 2283 }
@@ -2142,9 +2290,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
2142 /* It's a dir URL and there is no index.html 2290 /* It's a dir URL and there is no index.html
2143 * Try cgi-bin/index.cgi */ 2291 * Try cgi-bin/index.cgi */
2144 if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) { 2292 if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) {
2145 urlp[0] = '\0'; 2293 urlp[0] = '\0'; /* remove index_page */
2146 g_query = urlcopy; 2294 send_cgi_and_exit("/cgi-bin/index.cgi", urlcopy, prequest, length, cookie, content_type);
2147 send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type);
2148 } 2295 }
2149 } 2296 }
2150 /* else fall through to send_file, it errors out if open fails: */ 2297 /* else fall through to send_file, it errors out if open fails: */
@@ -2243,6 +2390,7 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv)
2243 /* Run a copy of ourself in inetd mode */ 2390 /* Run a copy of ourself in inetd mode */
2244 re_exec(argv_copy); 2391 re_exec(argv_copy);
2245 } 2392 }
2393 argv_copy[0][0] &= 0x7f;
2246 /* parent, or vfork failed */ 2394 /* parent, or vfork failed */
2247 close(n); 2395 close(n);
2248 } /* while (1) */ 2396 } /* while (1) */
@@ -2352,7 +2500,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
2352 salt[1] = '1'; 2500 salt[1] = '1';
2353 salt[2] = '$'; 2501 salt[2] = '$';
2354 crypt_make_salt(salt + 3, 4); 2502 crypt_make_salt(salt + 3, 4);
2355 puts(pw_encrypt(pass, salt, 1)); 2503 puts(pw_encrypt(pass, salt, /*cleanup:*/ 0));
2356 return 0; 2504 return 0;
2357 } 2505 }
2358#endif 2506#endif
diff --git a/networking/httpd_indexcgi.c b/networking/httpd_indexcgi.c
index 7e0225e19..d732cd4f8 100644
--- a/networking/httpd_indexcgi.c
+++ b/networking/httpd_indexcgi.c
@@ -221,20 +221,25 @@ int main(int argc, char *argv[])
221 unsigned long long size_total; 221 unsigned long long size_total;
222 int odd; 222 int odd;
223 DIR *dirp; 223 DIR *dirp;
224 char *QUERY_STRING; 224 char *location;
225 225
226 QUERY_STRING = getenv("QUERY_STRING"); 226 location = getenv("REQUEST_URI");
227 if (!QUERY_STRING 227 if (!location)
228 || QUERY_STRING[0] != '/' 228 return 1;
229 || strstr(QUERY_STRING, "//") 229
230 || strstr(QUERY_STRING, "/../") 230 /* drop URL arguments if any */
231 || strcmp(strrchr(QUERY_STRING, '/'), "/..") == 0 231 strchrnul(location, '?')[0] = '\0';
232
233 if (location[0] != '/'
234 || strstr(location, "//")
235 || strstr(location, "/../")
236 || strcmp(strrchr(location, '/'), "/..") == 0
232 ) { 237 ) {
233 return 1; 238 return 1;
234 } 239 }
235 240
236 if (chdir("..") 241 if (chdir("..")
237 || (QUERY_STRING[1] && chdir(QUERY_STRING + 1)) 242 || (location[1] && chdir(location + 1))
238 ) { 243 ) {
239 return 1; 244 return 1;
240 } 245 }
@@ -271,14 +276,14 @@ int main(int argc, char *argv[])
271 "\r\n" /* Mandatory empty line after headers */ 276 "\r\n" /* Mandatory empty line after headers */
272 "<html><head><title>Index of "); 277 "<html><head><title>Index of ");
273 /* Guard against directories with &, > etc */ 278 /* Guard against directories with &, > etc */
274 fmt_html(QUERY_STRING); 279 fmt_html(location);
275 fmt_str( 280 fmt_str(
276 "</title>\n" 281 "</title>\n"
277 STYLE_STR 282 STYLE_STR
278 "</head>" "\n" 283 "</head>" "\n"
279 "<body>" "\n" 284 "<body>" "\n"
280 "<h1>Index of "); 285 "<h1>Index of ");
281 fmt_html(QUERY_STRING); 286 fmt_html(location);
282 fmt_str( 287 fmt_str(
283 "</h1>" "\n" 288 "</h1>" "\n"
284 "<table>" "\n" 289 "<table>" "\n"
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 5946323d0..dfda20670 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -403,11 +403,11 @@ static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec)
403 result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec); 403 result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec);
404 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); 404 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
405 /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */ 405 /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */
406 result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec); 406 result += execute("[[ip route add ::/0 via %gateway%]][[ prio %metric%]]", ifd, exec);
407# else 407# else
408 result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec); 408 result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec);
409 result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec); 409 result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec);
410 result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec); 410 result += execute("[[route -A inet6 add ::/0 gw %gateway%[[ metric %metric%]]]]", ifd, exec);
411# endif 411# endif
412 return ((result == 3) ? 3 : 0); 412 return ((result == 3) ? 3 : 0);
413} 413}
@@ -490,7 +490,7 @@ static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec)
490 result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] " 490 result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
491 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec); 491 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
492 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); 492 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
493 result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec); 493 result += execute("[[ip route add default via %gateway% dev %iface%[[ prio %metric%]]]]", ifd, exec);
494 return ((result == 3) ? 3 : 0); 494 return ((result == 3) ? 3 : 0);
495# else 495# else
496 /* ifconfig said to set iface up before it processes hw %hwaddress%, 496 /* ifconfig said to set iface up before it processes hw %hwaddress%,
@@ -500,7 +500,7 @@ static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec)
500 result += execute("ifconfig %iface% %address% netmask %netmask%" 500 result += execute("ifconfig %iface% %address% netmask %netmask%"
501 "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ", 501 "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ",
502 ifd, exec); 502 ifd, exec);
503 result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec); 503 result += execute("[[route add default gw %gateway%[[ metric %metric%]] %iface%]]", ifd, exec);
504 return ((result == 3) ? 3 : 0); 504 return ((result == 3) ? 3 : 0);
505# endif 505# endif
506} 506}
@@ -1311,9 +1311,9 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv)
1311 llist_t *state_list = read_iface_state(); 1311 llist_t *state_list = read_iface_state();
1312 llist_t *iface_state = find_iface_state(state_list, iface); 1312 llist_t *iface_state = find_iface_state(state_list, iface);
1313 1313
1314 if (cmds == iface_up) { 1314 if (cmds == iface_up && !any_failures) {
1315 char * const newiface = xasprintf("%s=%s", iface, liface); 1315 char *newiface = xasprintf("%s=%s", iface, liface);
1316 if (iface_state == NULL) { 1316 if (!iface_state) {
1317 llist_add_to_end(&state_list, newiface); 1317 llist_add_to_end(&state_list, newiface);
1318 } else { 1318 } else {
1319 free(iface_state->data); 1319 free(iface_state->data);
diff --git a/networking/ip.c b/networking/ip.c
index fb2f5e2da..98fe621b1 100644
--- a/networking/ip.c
+++ b/networking/ip.c
@@ -50,16 +50,15 @@
50//usage: "iplink show [DEVICE]" 50//usage: "iplink show [DEVICE]"
51//usage: 51//usage:
52//usage:#define iproute_trivial_usage 52//usage:#define iproute_trivial_usage
53//usage: "{ list | flush | { add | del | change | append |\n" 53//usage: "{ list | flush | add | del | change | append |\n"
54//usage: " replace | monitor } ROUTE }" 54//usage: " replace | test } ROUTE"
55//usage:#define iproute_full_usage "\n\n" 55//usage:#define iproute_full_usage "\n\n"
56//usage: "iproute { list | flush } SELECTOR\n" 56//usage: "iproute { list | flush } SELECTOR\n"
57//usage: "iproute get ADDRESS [from ADDRESS iif STRING]\n" 57//usage: "iproute get ADDRESS [from ADDRESS iif STRING]\n"
58//usage: " [oif STRING] [tos TOS]\n" 58//usage: " [oif STRING] [tos TOS]\n"
59//usage: "iproute { add | del | change | append | replace | monitor } ROUTE\n" 59//usage: "iproute { add | del | change | append | replace | test } ROUTE\n"
60//usage: " SELECTOR := [root PREFIX] [match PREFIX] [proto RTPROTO]\n" 60//usage: " SELECTOR := [root PREFIX] [match PREFIX] [proto RTPROTO]\n"
61//usage: " ROUTE := [TYPE] PREFIX [tos TOS] [proto RTPROTO]\n" 61//usage: " ROUTE := [TYPE] PREFIX [tos TOS] [proto RTPROTO] [metric METRIC]"
62//usage: " [metric METRIC]"
63//usage: 62//usage:
64//usage:#define iprule_trivial_usage 63//usage:#define iprule_trivial_usage
65//usage: "{[list | add | del] RULE}" 64//usage: "{[list | add | del] RULE}"
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index d184f689b..62a025116 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -115,6 +115,7 @@ struct globals {
115 unsigned wrote_out; /* total stdout bytes */ 115 unsigned wrote_out; /* total stdout bytes */
116 unsigned wrote_net; /* total net bytes */ 116 unsigned wrote_net; /* total net bytes */
117#endif 117#endif
118 char *proggie0saved;
118 /* ouraddr is never NULL and goes through three states as we progress: 119 /* ouraddr is never NULL and goes through three states as we progress:
119 1 - local address before bind (IP/port possibly zero) 120 1 - local address before bind (IP/port possibly zero)
120 2 - local address after bind (port is nonzero) 121 2 - local address after bind (port is nonzero)
@@ -127,7 +128,6 @@ struct globals {
127 128
128 jmp_buf jbuf; /* timer crud */ 129 jmp_buf jbuf; /* timer crud */
129 130
130 /* will malloc up the following globals: */
131 fd_set ding1; /* for select loop */ 131 fd_set ding1; /* for select loop */
132 fd_set ding2; 132 fd_set ding2;
133 char bigbuf_in[BIGSIZ]; /* data buffers */ 133 char bigbuf_in[BIGSIZ]; /* data buffers */
@@ -159,17 +159,16 @@ struct globals {
159 159
160/* Must match getopt32 call! */ 160/* Must match getopt32 call! */
161enum { 161enum {
162 OPT_h = (1 << 0), 162 OPT_n = (1 << 0),
163 OPT_n = (1 << 1), 163 OPT_p = (1 << 1),
164 OPT_p = (1 << 2), 164 OPT_s = (1 << 2),
165 OPT_s = (1 << 3), 165 OPT_u = (1 << 3),
166 OPT_u = (1 << 4), 166 OPT_v = (1 << 4),
167 OPT_v = (1 << 5), 167 OPT_w = (1 << 5),
168 OPT_w = (1 << 6), 168 OPT_l = (1 << 6) * ENABLE_NC_SERVER,
169 OPT_l = (1 << 7) * ENABLE_NC_SERVER, 169 OPT_i = (1 << (6+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
170 OPT_i = (1 << (7+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, 170 OPT_o = (1 << (7+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
171 OPT_o = (1 << (8+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, 171 OPT_z = (1 << (8+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
172 OPT_z = (1 << (9+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
173}; 172};
174 173
175#define o_nflag (option_mask32 & OPT_n) 174#define o_nflag (option_mask32 & OPT_n)
@@ -263,6 +262,8 @@ Debug("findline returning whole thing: %d", siz);
263static int doexec(char **proggie) NORETURN; 262static int doexec(char **proggie) NORETURN;
264static int doexec(char **proggie) 263static int doexec(char **proggie)
265{ 264{
265 if (G.proggie0saved)
266 proggie[0] = G.proggie0saved;
266 xmove_fd(netfd, 0); 267 xmove_fd(netfd, 0);
267 dup2(0, 1); 268 dup2(0, 1);
268 /* dup2(0, 2); - do we *really* want this? NO! 269 /* dup2(0, 2); - do we *really* want this? NO!
@@ -726,7 +727,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv)
726{ 727{
727 char *str_p, *str_s; 728 char *str_p, *str_s;
728 IF_NC_EXTRA(char *str_i, *str_o;) 729 IF_NC_EXTRA(char *str_i, *str_o;)
729 char *themdotted = themdotted; /* gcc */ 730 char *themdotted = themdotted; /* for compiler */
730 char **proggie; 731 char **proggie;
731 int x; 732 int x;
732 unsigned o_lport = 0; 733 unsigned o_lport = 0;
@@ -754,13 +755,27 @@ int nc_main(int argc UNUSED_PARAM, char **argv)
754 proggie++; 755 proggie++;
755 goto e_found; 756 goto e_found;
756 } 757 }
758 /* -<other_opts>e PROG [ARGS] ? */
759 /* (aboriginal linux uses this form) */
760 if (proggie[0][0] == '-') {
761 char *optpos = *proggie + 1;
762 /* Skip all valid opts w/o params */
763 optpos = optpos + strspn(optpos, "nuv"IF_NC_SERVER("l")IF_NC_EXTRA("z"));
764 if (*optpos == 'e' && !optpos[1]) {
765 *optpos = '\0';
766 proggie++;
767 G.proggie0saved = *proggie;
768 *proggie = NULL; /* terminate argv for getopt32 */
769 goto e_found;
770 }
771 }
757 } 772 }
758 proggie = NULL; 773 proggie = NULL;
759 e_found: 774 e_found:
760 775
761 // -g -G -t -r deleted, unimplemented -a deleted too 776 // -g -G -t -r deleted, unimplemented -a deleted too
762 opt_complementary = "?2:vv:w+"; /* max 2 params; -v is a counter; -w N */ 777 opt_complementary = "?2:vv:w+"; /* max 2 params; -v is a counter; -w N */
763 getopt32(argv, "hnp:s:uvw:" IF_NC_SERVER("l") 778 getopt32(argv, "np:s:uvw:" IF_NC_SERVER("l")
764 IF_NC_EXTRA("i:o:z"), 779 IF_NC_EXTRA("i:o:z"),
765 &str_p, &str_s, &o_wait 780 &str_p, &str_s, &o_wait
766 IF_NC_EXTRA(, &str_i, &str_o), &o_verbose); 781 IF_NC_EXTRA(, &str_i, &str_o), &o_verbose);
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 206af00c7..4d939458c 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -107,12 +107,15 @@
107#define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */ 107#define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */
108#define BURSTPOLL 0 /* initial poll */ 108#define BURSTPOLL 0 /* initial poll */
109#define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ 109#define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */
110#define BIGPOLL 10 /* drop to lower poll at any trouble (10: 17 min) */ 110/* If offset > discipline_jitter * POLLADJ_GATE, and poll interval is >= 2^BIGPOLL,
111 * then it is decreased _at once_. (If < 2^BIGPOLL, it will be decreased _eventually_).
112 */
113#define BIGPOLL 10 /* 2^10 sec ~= 17 min */
111#define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ 114#define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */
112/* Actively lower poll when we see such big offsets. 115/* Actively lower poll when we see such big offsets.
113 * With STEP_THRESHOLD = 0.125, it means we try to sync more aggressively 116 * With STEP_THRESHOLD = 0.125, it means we try to sync more aggressively
114 * if offset increases over 0.03 sec */ 117 * if offset increases over ~0.04 sec */
115#define POLLDOWN_OFFSET (STEP_THRESHOLD / 4) 118#define POLLDOWN_OFFSET (STEP_THRESHOLD / 3)
116#define MINDISP 0.01 /* minimum dispersion (sec) */ 119#define MINDISP 0.01 /* minimum dispersion (sec) */
117#define MAXDISP 16 /* maximum dispersion (sec) */ 120#define MAXDISP 16 /* maximum dispersion (sec) */
118#define MAXSTRAT 16 /* maximum stratum (infinity metric) */ 121#define MAXSTRAT 16 /* maximum stratum (infinity metric) */
@@ -124,17 +127,18 @@
124 127
125/* Poll-adjust threshold. 128/* Poll-adjust threshold.
126 * When we see that offset is small enough compared to discipline jitter, 129 * When we see that offset is small enough compared to discipline jitter,
127 * we grow a counter: += MINPOLL. When it goes over POLLADJ_LIMIT, 130 * we grow a counter: += MINPOLL. When counter goes over POLLADJ_LIMIT,
128 * we poll_exp++. If offset isn't small, counter -= poll_exp*2, 131 * we poll_exp++. If offset isn't small, counter -= poll_exp*2,
129 * and when it goes below -POLLADJ_LIMIT, we poll_exp-- 132 * and when it goes below -POLLADJ_LIMIT, we poll_exp--.
130 * (bumped from 30 to 36 since otherwise I often see poll_exp going *2* steps down) 133 * (Bumped from 30 to 40 since otherwise I often see poll_exp going *2* steps down)
131 */ 134 */
132#define POLLADJ_LIMIT 36 135#define POLLADJ_LIMIT 40
133/* If offset < POLLADJ_GATE * discipline_jitter, then we can increase 136/* If offset < discipline_jitter * POLLADJ_GATE, then we decide to increase
134 * poll interval (we think we can't improve timekeeping 137 * poll interval (we think we can't improve timekeeping
135 * by staying at smaller poll). 138 * by staying at smaller poll).
136 */ 139 */
137#define POLLADJ_GATE 4 140#define POLLADJ_GATE 4
141#define TIMECONST_HACK_GATE 2
138/* Compromise Allan intercept (sec). doc uses 1500, std ntpd uses 512 */ 142/* Compromise Allan intercept (sec). doc uses 1500, std ntpd uses 512 */
139#define ALLAN 512 143#define ALLAN 512
140/* PLL loop gain */ 144/* PLL loop gain */
@@ -208,8 +212,8 @@ typedef struct {
208} msg_t; 212} msg_t;
209 213
210typedef struct { 214typedef struct {
211 double d_recv_time;
212 double d_offset; 215 double d_offset;
216 double d_recv_time;
213 double d_dispersion; 217 double d_dispersion;
214} datapoint_t; 218} datapoint_t;
215 219
@@ -255,7 +259,7 @@ enum {
255 OPT_S = (1 << 6), 259 OPT_S = (1 << 6),
256 OPT_l = (1 << 7) * ENABLE_FEATURE_NTPD_SERVER, 260 OPT_l = (1 << 7) * ENABLE_FEATURE_NTPD_SERVER,
257 /* We hijack some bits for other purposes */ 261 /* We hijack some bits for other purposes */
258 OPT_qq = (1 << 8), 262 OPT_qq = (1 << 31),
259}; 263};
260 264
261struct globals { 265struct globals {
@@ -276,11 +280,12 @@ struct globals {
276 unsigned verbose; 280 unsigned verbose;
277 unsigned peer_cnt; 281 unsigned peer_cnt;
278 /* refid: 32-bit code identifying the particular server or reference clock 282 /* refid: 32-bit code identifying the particular server or reference clock
279 * in stratum 0 packets this is a four-character ASCII string, 283 * in stratum 0 packets this is a four-character ASCII string,
280 * called the kiss code, used for debugging and monitoring 284 * called the kiss code, used for debugging and monitoring
281 * in stratum 1 packets this is a four-character ASCII string 285 * in stratum 1 packets this is a four-character ASCII string
282 * assigned to the reference clock by IANA. Example: "GPS " 286 * assigned to the reference clock by IANA. Example: "GPS "
283 * in stratum 2+ packets, it's IPv4 address or 4 first bytes of MD5 hash of IPv6 287 * in stratum 2+ packets, it's IPv4 address or 4 first bytes
288 * of MD5 hash of IPv6
284 */ 289 */
285 uint32_t refid; 290 uint32_t refid;
286 uint8_t ntp_status; 291 uint8_t ntp_status;
@@ -289,27 +294,35 @@ struct globals {
289 * mains-frequency clock incrementing at 60 Hz is 16 ms, even when the 294 * mains-frequency clock incrementing at 60 Hz is 16 ms, even when the
290 * system clock hardware representation is to the nanosecond. 295 * system clock hardware representation is to the nanosecond.
291 * 296 *
292 * Delays, jitters of various kinds are clamper down to precision. 297 * Delays, jitters of various kinds are clamped down to precision.
293 * 298 *
294 * If precision_sec is too large, discipline_jitter gets clamped to it 299 * If precision_sec is too large, discipline_jitter gets clamped to it
295 * and if offset is much smaller than discipline_jitter, poll interval 300 * and if offset is smaller than discipline_jitter * POLLADJ_GATE, poll
296 * grows even though we really can benefit from staying at smaller one, 301 * interval grows even though we really can benefit from staying at
297 * collecting non-lagged datapoits and correcting the offset. 302 * smaller one, collecting non-lagged datapoits and correcting offset.
298 * (Lagged datapoits exist when poll_exp is large but we still have 303 * (Lagged datapoits exist when poll_exp is large but we still have
299 * systematic offset error - the time distance between datapoints 304 * systematic offset error - the time distance between datapoints
300 * is significat and older datapoints have smaller offsets. 305 * is significant and older datapoints have smaller offsets.
301 * This makes our offset estimation a bit smaller than reality) 306 * This makes our offset estimation a bit smaller than reality)
302 * Due to this effect, setting G_precision_sec close to 307 * Due to this effect, setting G_precision_sec close to
303 * STEP_THRESHOLD isn't such a good idea - offsets may grow 308 * STEP_THRESHOLD isn't such a good idea - offsets may grow
304 * too big and we will step. I observed it with -6. 309 * too big and we will step. I observed it with -6.
305 * 310 *
306 * OTOH, setting precision too small would result in futile attempts 311 * OTOH, setting precision_sec far too small would result in futile
307 * to syncronize to the unachievable precision. 312 * attempts to syncronize to an unachievable precision.
308 * 313 *
309 * -6 is 1/64 sec, -7 is 1/128 sec and so on. 314 * -6 is 1/64 sec, -7 is 1/128 sec and so on.
315 * -8 is 1/256 ~= 0.003906 (worked well for me --vda)
316 * -9 is 1/512 ~= 0.001953 (let's try this for some time)
310 */ 317 */
311#define G_precision_exp -8 318#define G_precision_exp -9
312#define G_precision_sec (1.0 / (1 << (- G_precision_exp))) 319 /*
320 * G_precision_exp is used only for construction outgoing packets.
321 * It's ok to set G_precision_sec to a slightly different value
322 * (One which is "nicer looking" in logs).
323 * Exact value would be (1.0 / (1 << (- G_precision_exp))):
324 */
325#define G_precision_sec 0.002
313 uint8_t stratum; 326 uint8_t stratum;
314 /* Bool. After set to 1, never goes back to 0: */ 327 /* Bool. After set to 1, never goes back to 0: */
315 smallint initial_poll_complete; 328 smallint initial_poll_complete;
@@ -327,6 +340,10 @@ struct globals {
327 double last_update_offset; // c.last 340 double last_update_offset; // c.last
328 double last_update_recv_time; // s.t 341 double last_update_recv_time; // s.t
329 double discipline_jitter; // c.jitter 342 double discipline_jitter; // c.jitter
343 /* Since we only compare it with ints, can simplify code
344 * by not making this variable floating point:
345 */
346 unsigned offset_to_jitter_ratio;
330 //double cluster_offset; // s.offset 347 //double cluster_offset; // s.offset
331 //double cluster_jitter; // s.jitter 348 //double cluster_jitter; // s.jitter
332#if !USING_KERNEL_PLL_LOOP 349#if !USING_KERNEL_PLL_LOOP
@@ -500,23 +517,34 @@ static void
500filter_datapoints(peer_t *p) 517filter_datapoints(peer_t *p)
501{ 518{
502 int i, idx; 519 int i, idx;
520 double sum, wavg;
521 datapoint_t *fdp;
522
523#if 0
524/* Simulations have shown that use of *averaged* offset for p->filter_offset
525 * is in fact worse than simply using last received one: with large poll intervals
526 * (>= 2048) averaging code uses offset values which are outdated by hours,
527 * and time/frequency correction goes totally wrong when fed essentially bogus offsets.
528 */
503 int got_newest; 529 int got_newest;
504 double minoff, maxoff, wavg, sum, w; 530 double minoff, maxoff, w;
505 double x = x; /* for compiler */ 531 double x = x; /* for compiler */
506 double oldest_off = oldest_off; 532 double oldest_off = oldest_off;
507 double oldest_age = oldest_age; 533 double oldest_age = oldest_age;
508 double newest_off = newest_off; 534 double newest_off = newest_off;
509 double newest_age = newest_age; 535 double newest_age = newest_age;
510 536
511 minoff = maxoff = p->filter_datapoint[0].d_offset; 537 fdp = p->filter_datapoint;
538
539 minoff = maxoff = fdp[0].d_offset;
512 for (i = 1; i < NUM_DATAPOINTS; i++) { 540 for (i = 1; i < NUM_DATAPOINTS; i++) {
513 if (minoff > p->filter_datapoint[i].d_offset) 541 if (minoff > fdp[i].d_offset)
514 minoff = p->filter_datapoint[i].d_offset; 542 minoff = fdp[i].d_offset;
515 if (maxoff < p->filter_datapoint[i].d_offset) 543 if (maxoff < fdp[i].d_offset)
516 maxoff = p->filter_datapoint[i].d_offset; 544 maxoff = fdp[i].d_offset;
517 } 545 }
518 546
519 idx = p->datapoint_idx; /* most recent datapoint */ 547 idx = p->datapoint_idx; /* most recent datapoint's index */
520 /* Average offset: 548 /* Average offset:
521 * Drop two outliers and take weighted average of the rest: 549 * Drop two outliers and take weighted average of the rest:
522 * most_recent/2 + older1/4 + older2/8 ... + older5/32 + older6/32 550 * most_recent/2 + older1/4 + older2/8 ... + older5/32 + older6/32
@@ -538,24 +566,24 @@ filter_datapoints(peer_t *p)
538 VERB4 { 566 VERB4 {
539 bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s", 567 bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s",
540 i, 568 i,
541 p->filter_datapoint[idx].d_offset, 569 fdp[idx].d_offset,
542 p->filter_datapoint[idx].d_dispersion, dispersion(&p->filter_datapoint[idx]), 570 fdp[idx].d_dispersion, dispersion(&fdp[idx]),
543 G.cur_time - p->filter_datapoint[idx].d_recv_time, 571 G.cur_time - fdp[idx].d_recv_time,
544 (minoff == p->filter_datapoint[idx].d_offset || maxoff == p->filter_datapoint[idx].d_offset) 572 (minoff == fdp[idx].d_offset || maxoff == fdp[idx].d_offset)
545 ? " (outlier by offset)" : "" 573 ? " (outlier by offset)" : ""
546 ); 574 );
547 } 575 }
548 576
549 sum += dispersion(&p->filter_datapoint[idx]) / (2 << i); 577 sum += dispersion(&fdp[idx]) / (2 << i);
550 578
551 if (minoff == p->filter_datapoint[idx].d_offset) { 579 if (minoff == fdp[idx].d_offset) {
552 minoff -= 1; /* so that we don't match it ever again */ 580 minoff -= 1; /* so that we don't match it ever again */
553 } else 581 } else
554 if (maxoff == p->filter_datapoint[idx].d_offset) { 582 if (maxoff == fdp[idx].d_offset) {
555 maxoff += 1; 583 maxoff += 1;
556 } else { 584 } else {
557 oldest_off = p->filter_datapoint[idx].d_offset; 585 oldest_off = fdp[idx].d_offset;
558 oldest_age = G.cur_time - p->filter_datapoint[idx].d_recv_time; 586 oldest_age = G.cur_time - fdp[idx].d_recv_time;
559 if (!got_newest) { 587 if (!got_newest) {
560 got_newest = 1; 588 got_newest = 1;
561 newest_off = oldest_off; 589 newest_off = oldest_off;
@@ -588,6 +616,32 @@ filter_datapoints(peer_t *p)
588 } 616 }
589 p->filter_offset = wavg; 617 p->filter_offset = wavg;
590 618
619#else
620
621 fdp = p->filter_datapoint;
622 idx = p->datapoint_idx; /* most recent datapoint's index */
623
624 /* filter_offset: simply use the most recent value */
625 p->filter_offset = fdp[idx].d_offset;
626
627 /* n-1
628 * --- dispersion(i)
629 * filter_dispersion = \ -------------
630 * / (i+1)
631 * --- 2
632 * i=0
633 */
634 wavg = 0;
635 sum = 0;
636 for (i = 0; i < NUM_DATAPOINTS; i++) {
637 sum += dispersion(&fdp[idx]) / (2 << i);
638 wavg += fdp[idx].d_offset;
639 idx = (idx - 1) & (NUM_DATAPOINTS - 1);
640 }
641 wavg /= NUM_DATAPOINTS;
642 p->filter_dispersion = sum;
643#endif
644
591 /* +----- -----+ ^ 1/2 645 /* +----- -----+ ^ 1/2
592 * | n-1 | 646 * | n-1 |
593 * | --- | 647 * | --- |
@@ -601,13 +655,13 @@ filter_datapoints(peer_t *p)
601 */ 655 */
602 sum = 0; 656 sum = 0;
603 for (i = 0; i < NUM_DATAPOINTS; i++) { 657 for (i = 0; i < NUM_DATAPOINTS; i++) {
604 sum += SQUARE(wavg - p->filter_datapoint[i].d_offset); 658 sum += SQUARE(wavg - fdp[i].d_offset);
605 } 659 }
606 sum = SQRT(sum / NUM_DATAPOINTS); 660 sum = SQRT(sum / NUM_DATAPOINTS);
607 p->filter_jitter = sum > G_precision_sec ? sum : G_precision_sec; 661 p->filter_jitter = sum > G_precision_sec ? sum : G_precision_sec;
608 662
609 VERB3 bb_error_msg("filter offset:%f(corr:%e) disp:%f jitter:%f", 663 VERB3 bb_error_msg("filter offset:%+f disp:%f jitter:%f",
610 p->filter_offset, x, 664 p->filter_offset,
611 p->filter_dispersion, 665 p->filter_dispersion,
612 p->filter_jitter); 666 p->filter_jitter);
613} 667}
@@ -622,7 +676,11 @@ reset_peer_stats(peer_t *p, double offset)
622 if (small_ofs) { 676 if (small_ofs) {
623 p->filter_datapoint[i].d_recv_time += offset; 677 p->filter_datapoint[i].d_recv_time += offset;
624 if (p->filter_datapoint[i].d_offset != 0) { 678 if (p->filter_datapoint[i].d_offset != 0) {
625 p->filter_datapoint[i].d_offset += offset; 679 p->filter_datapoint[i].d_offset -= offset;
680 //bb_error_msg("p->filter_datapoint[%d].d_offset %f -> %f",
681 // i,
682 // p->filter_datapoint[i].d_offset + offset,
683 // p->filter_datapoint[i].d_offset);
626 } 684 }
627 } else { 685 } else {
628 p->filter_datapoint[i].d_recv_time = G.cur_time; 686 p->filter_datapoint[i].d_recv_time = G.cur_time;
@@ -719,6 +777,12 @@ send_query_to_peer(peer_t *p)
719 free(local_lsa); 777 free(local_lsa);
720 } 778 }
721 779
780 /* Emit message _before_ attempted send. Think of a very short
781 * roundtrip networks: we need to go back to recv loop ASAP,
782 * to reduce delay. Printing messages after send works against that.
783 */
784 VERB1 bb_error_msg("sending query to %s", p->p_dotted);
785
722 /* 786 /*
723 * Send out a random 64-bit number as our transmit time. The NTP 787 * Send out a random 64-bit number as our transmit time. The NTP
724 * server will copy said number into the originate field on the 788 * server will copy said number into the originate field on the
@@ -746,7 +810,6 @@ send_query_to_peer(peer_t *p)
746 } 810 }
747 811
748 p->reachable_bits <<= 1; 812 p->reachable_bits <<= 1;
749 VERB1 bb_error_msg("sent query to %s", p->p_dotted);
750 set_next(p, RESPONSE_INTERVAL); 813 set_next(p, RESPONSE_INTERVAL);
751} 814}
752 815
@@ -808,22 +871,24 @@ step_time(double offset)
808{ 871{
809 llist_t *item; 872 llist_t *item;
810 double dtime; 873 double dtime;
811 struct timeval tv; 874 struct timeval tvc, tvn;
812 char buf[80]; 875 char buf[sizeof("yyyy-mm-dd hh:mm:ss") + /*paranoia:*/ 4];
813 time_t tval; 876 time_t tval;
814 877
815 gettimeofday(&tv, NULL); /* never fails */ 878 gettimeofday(&tvc, NULL); /* never fails */
816 dtime = offset + tv.tv_sec; 879 dtime = tvc.tv_sec + (1.0e-6 * tvc.tv_usec) + offset;
817 dtime += 1.0e-6 * tv.tv_usec; 880 d_to_tv(dtime, &tvn);
818 d_to_tv(dtime, &tv); 881 if (settimeofday(&tvn, NULL) == -1)
819
820 if (settimeofday(&tv, NULL) == -1)
821 bb_perror_msg_and_die("settimeofday"); 882 bb_perror_msg_and_die("settimeofday");
822 883
823 tval = tv.tv_sec; 884 VERB2 {
824 strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime(&tval)); 885 tval = tvc.tv_sec;
825 886 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tval));
826 bb_error_msg("setting clock to %s (offset %fs)", buf, offset); 887 bb_error_msg("current time is %s.%06u", buf, (unsigned)tvc.tv_usec);
888 }
889 tval = tvn.tv_sec;
890 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&tval));
891 bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset);
827 892
828 /* Correct various fields which contain time-relative values: */ 893 /* Correct various fields which contain time-relative values: */
829 894
@@ -831,7 +896,7 @@ step_time(double offset)
831 for (item = G.ntp_peers; item != NULL; item = item->link) { 896 for (item = G.ntp_peers; item != NULL; item = item->link) {
832 peer_t *pp = (peer_t *) item->data; 897 peer_t *pp = (peer_t *) item->data;
833 reset_peer_stats(pp, offset); 898 reset_peer_stats(pp, offset);
834 //bb_error_msg("offset:%f pp->next_action_time:%f -> %f", 899 //bb_error_msg("offset:%+f pp->next_action_time:%f -> %f",
835 // offset, pp->next_action_time, pp->next_action_time + offset); 900 // offset, pp->next_action_time, pp->next_action_time + offset);
836 pp->next_action_time += offset; 901 pp->next_action_time += offset;
837 } 902 }
@@ -1167,7 +1232,7 @@ select_and_cluster(void)
1167 } 1232 }
1168 G.last_update_peer = p; 1233 G.last_update_peer = p;
1169 keep_old: 1234 keep_old:
1170 VERB3 bb_error_msg("selected peer %s filter_offset:%f age:%f", 1235 VERB3 bb_error_msg("selected peer %s filter_offset:%+f age:%f",
1171 p->p_dotted, 1236 p->p_dotted,
1172 p->filter_offset, 1237 p->filter_offset,
1173 G.cur_time - p->lastpkt_recv_time 1238 G.cur_time - p->lastpkt_recv_time
@@ -1258,7 +1323,7 @@ update_local_clock(peer_t *p)
1258 switch (G.discipline_state) { 1323 switch (G.discipline_state) {
1259 case STATE_SYNC: 1324 case STATE_SYNC:
1260 /* The first outlyer: ignore it, switch to SPIK state */ 1325 /* The first outlyer: ignore it, switch to SPIK state */
1261 VERB3 bb_error_msg("offset:%f - spike detected", offset); 1326 VERB3 bb_error_msg("offset:%+f - spike detected", offset);
1262 G.discipline_state = STATE_SPIK; 1327 G.discipline_state = STATE_SPIK;
1263 return -1; /* "decrease poll interval" */ 1328 return -1; /* "decrease poll interval" */
1264 1329
@@ -1295,7 +1360,7 @@ update_local_clock(peer_t *p)
1295 * is always suppressed, even at the longer poll 1360 * is always suppressed, even at the longer poll
1296 * intervals. 1361 * intervals.
1297 */ 1362 */
1298 VERB3 bb_error_msg("stepping time by %f; poll_exp=MINPOLL", offset); 1363 VERB3 bb_error_msg("stepping time by %+f; poll_exp=MINPOLL", offset);
1299 step_time(offset); 1364 step_time(offset);
1300 if (option_mask32 & OPT_q) { 1365 if (option_mask32 & OPT_q) {
1301 /* We were only asked to set time once. Done. */ 1366 /* We were only asked to set time once. Done. */
@@ -1314,12 +1379,13 @@ update_local_clock(peer_t *p)
1314 return 1; /* "ok to increase poll interval" */ 1379 return 1; /* "ok to increase poll interval" */
1315 } 1380 }
1316#endif 1381#endif
1317 set_new_values(STATE_SYNC, /*offset:*/ 0, recv_time); 1382 abs_offset = offset = 0;
1383 set_new_values(STATE_SYNC, offset, recv_time);
1318 1384
1319 } else { /* abs_offset <= STEP_THRESHOLD */ 1385 } else { /* abs_offset <= STEP_THRESHOLD */
1320 1386
1321 if (G.poll_exp < MINPOLL && G.initial_poll_complete) { 1387 if (G.poll_exp < MINPOLL && G.initial_poll_complete) {
1322 VERB3 bb_error_msg("small offset:%f, disabling burst mode", offset); 1388 VERB3 bb_error_msg("small offset:%+f, disabling burst mode", offset);
1323 G.polladj_count = 0; 1389 G.polladj_count = 0;
1324 G.poll_exp = MINPOLL; 1390 G.poll_exp = MINPOLL;
1325 } 1391 }
@@ -1328,9 +1394,8 @@ update_local_clock(peer_t *p)
1328 * weighted offset differences. Used by the poll adjust code. 1394 * weighted offset differences. Used by the poll adjust code.
1329 */ 1395 */
1330 etemp = SQUARE(G.discipline_jitter); 1396 etemp = SQUARE(G.discipline_jitter);
1331 dtemp = SQUARE(MAXD(fabs(offset - G.last_update_offset), G_precision_sec)); 1397 dtemp = SQUARE(offset - G.last_update_offset);
1332 G.discipline_jitter = SQRT(etemp + (dtemp - etemp) / AVG); 1398 G.discipline_jitter = SQRT(etemp + (dtemp - etemp) / AVG);
1333 VERB3 bb_error_msg("discipline jitter=%f", G.discipline_jitter);
1334 1399
1335 switch (G.discipline_state) { 1400 switch (G.discipline_state) {
1336 case STATE_NSET: 1401 case STATE_NSET:
@@ -1407,6 +1472,10 @@ update_local_clock(peer_t *p)
1407 } 1472 }
1408 } 1473 }
1409 1474
1475 if (G.discipline_jitter < G_precision_sec)
1476 G.discipline_jitter = G_precision_sec;
1477 G.offset_to_jitter_ratio = abs_offset / G.discipline_jitter;
1478
1410 G.reftime = G.cur_time; 1479 G.reftime = G.cur_time;
1411 G.ntp_status = p->lastpkt_status; 1480 G.ntp_status = p->lastpkt_status;
1412 G.refid = p->lastpkt_refid; 1481 G.refid = p->lastpkt_refid;
@@ -1418,7 +1487,7 @@ update_local_clock(peer_t *p)
1418 1487
1419 /* We are in STATE_SYNC now, but did not do adjtimex yet. 1488 /* We are in STATE_SYNC now, but did not do adjtimex yet.
1420 * (Any other state does not reach this, they all return earlier) 1489 * (Any other state does not reach this, they all return earlier)
1421 * By this time, freq_drift and G.last_update_offset are set 1490 * By this time, freq_drift and offset are set
1422 * to values suitable for adjtimex. 1491 * to values suitable for adjtimex.
1423 */ 1492 */
1424#if !USING_KERNEL_PLL_LOOP 1493#if !USING_KERNEL_PLL_LOOP
@@ -1444,8 +1513,8 @@ update_local_clock(peer_t *p)
1444 memset(&tmx, 0, sizeof(tmx)); 1513 memset(&tmx, 0, sizeof(tmx));
1445 if (adjtimex(&tmx) < 0) 1514 if (adjtimex(&tmx) < 0)
1446 bb_perror_msg_and_die("adjtimex"); 1515 bb_perror_msg_and_die("adjtimex");
1447 VERB3 bb_error_msg("p adjtimex freq:%ld offset:%ld constant:%ld status:0x%x", 1516 bb_error_msg("p adjtimex freq:%ld offset:%+ld status:0x%x tc:%ld",
1448 tmx.freq, tmx.offset, tmx.constant, tmx.status); 1517 tmx.freq, tmx.offset, tmx.status, tmx.constant);
1449 } 1518 }
1450 1519
1451 memset(&tmx, 0, sizeof(tmx)); 1520 memset(&tmx, 0, sizeof(tmx));
@@ -1457,40 +1526,42 @@ update_local_clock(peer_t *p)
1457 tmx.modes = ADJ_FREQUENCY | ADJ_OFFSET; 1526 tmx.modes = ADJ_FREQUENCY | ADJ_OFFSET;
1458 /* 65536 is one ppm */ 1527 /* 65536 is one ppm */
1459 tmx.freq = G.discipline_freq_drift * 65536e6; 1528 tmx.freq = G.discipline_freq_drift * 65536e6;
1460 tmx.offset = G.last_update_offset * 1000000; /* usec */
1461#endif 1529#endif
1462 tmx.modes = ADJ_OFFSET | ADJ_STATUS | ADJ_TIMECONST;// | ADJ_MAXERROR | ADJ_ESTERROR; 1530 tmx.modes = ADJ_OFFSET | ADJ_STATUS | ADJ_TIMECONST;// | ADJ_MAXERROR | ADJ_ESTERROR;
1463 tmx.offset = (G.last_update_offset * 1000000); /* usec */ 1531 tmx.offset = (offset * 1000000); /* usec */
1464 /* + (G.last_update_offset < 0 ? -0.5 : 0.5) - too small to bother */
1465 tmx.status = STA_PLL; 1532 tmx.status = STA_PLL;
1466 if (G.ntp_status & LI_PLUSSEC) 1533 if (G.ntp_status & LI_PLUSSEC)
1467 tmx.status |= STA_INS; 1534 tmx.status |= STA_INS;
1468 if (G.ntp_status & LI_MINUSSEC) 1535 if (G.ntp_status & LI_MINUSSEC)
1469 tmx.status |= STA_DEL; 1536 tmx.status |= STA_DEL;
1537
1470 tmx.constant = G.poll_exp - 4; 1538 tmx.constant = G.poll_exp - 4;
1471 //tmx.esterror = (u_int32)(clock_jitter * 1e6); 1539 /* EXPERIMENTAL.
1472 //tmx.maxerror = (u_int32)((sys_rootdelay / 2 + sys_rootdisp) * 1e6); 1540 * The below if statement should be unnecessary, but...
1541 * It looks like Linux kernel's PLL is far too gentle in changing
1542 * tmx.freq in response to clock offset. Offset keeps growing
1543 * and eventually we fall back to smaller poll intervals.
1544 * We can make correction more agressive (about x2) by supplying
1545 * PLL time constant which is one less than the real one.
1546 * To be on a safe side, let's do it only if offset is significantly
1547 * larger than jitter.
1548 */
1549 if (tmx.constant > 0 && G.offset_to_jitter_ratio >= TIMECONST_HACK_GATE)
1550 tmx.constant--;
1551
1552 //tmx.esterror = (uint32_t)(clock_jitter * 1e6);
1553 //tmx.maxerror = (uint32_t)((sys_rootdelay / 2 + sys_rootdisp) * 1e6);
1473 rc = adjtimex(&tmx); 1554 rc = adjtimex(&tmx);
1474 if (rc < 0) 1555 if (rc < 0)
1475 bb_perror_msg_and_die("adjtimex"); 1556 bb_perror_msg_and_die("adjtimex");
1476 /* NB: here kernel returns constant == G.poll_exp, not == G.poll_exp - 4. 1557 /* NB: here kernel returns constant == G.poll_exp, not == G.poll_exp - 4.
1477 * Not sure why. Perhaps it is normal. 1558 * Not sure why. Perhaps it is normal.
1478 */ 1559 */
1479 VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%ld constant:%ld status:0x%x", 1560 VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%+ld status:0x%x",
1480 rc, tmx.freq, tmx.offset, tmx.constant, tmx.status); 1561 rc, tmx.freq, tmx.offset, tmx.status);
1481#if 0
1482 VERB3 {
1483 /* always gives the same output as above msg */
1484 memset(&tmx, 0, sizeof(tmx));
1485 if (adjtimex(&tmx) < 0)
1486 bb_perror_msg_and_die("adjtimex");
1487 VERB3 bb_error_msg("c adjtimex freq:%ld offset:%ld constant:%ld status:0x%x",
1488 tmx.freq, tmx.offset, tmx.constant, tmx.status);
1489 }
1490#endif
1491 G.kernel_freq_drift = tmx.freq / 65536; 1562 G.kernel_freq_drift = tmx.freq / 65536;
1492 VERB2 bb_error_msg("update peer:%s, offset:%f, clock drift:%ld ppm", 1563 VERB2 bb_error_msg("update from:%s offset:%+f jitter:%f clock drift:%+.3fppm tc:%d",
1493 p->p_dotted, G.last_update_offset, G.kernel_freq_drift); 1564 p->p_dotted, offset, G.discipline_jitter, (double)tmx.freq / 65536, (int)tmx.constant);
1494 1565
1495 return 1; /* "ok to increase poll interval" */ 1566 return 1; /* "ok to increase poll interval" */
1496} 1567}
@@ -1626,22 +1697,22 @@ recv_and_process_peer_pkt(peer_t *p)
1626 if (!p->reachable_bits) { 1697 if (!p->reachable_bits) {
1627 /* 1st datapoint ever - replicate offset in every element */ 1698 /* 1st datapoint ever - replicate offset in every element */
1628 int i; 1699 int i;
1629 for (i = 1; i < NUM_DATAPOINTS; i++) { 1700 for (i = 0; i < NUM_DATAPOINTS; i++) {
1630 p->filter_datapoint[i].d_offset = datapoint->d_offset; 1701 p->filter_datapoint[i].d_offset = datapoint->d_offset;
1631 } 1702 }
1632 } 1703 }
1633 1704
1634 p->reachable_bits |= 1; 1705 p->reachable_bits |= 1;
1635 if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { 1706 if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) {
1636 bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f status 0x%02x strat %d refid 0x%08x rootdelay %f", 1707 bb_error_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x",
1637 p->p_dotted, 1708 p->p_dotted,
1638 p->reachable_bits,
1639 datapoint->d_offset, 1709 datapoint->d_offset,
1640 p->lastpkt_delay, 1710 p->lastpkt_delay,
1641 p->lastpkt_status, 1711 p->lastpkt_status,
1642 p->lastpkt_stratum, 1712 p->lastpkt_stratum,
1643 p->lastpkt_refid, 1713 p->lastpkt_refid,
1644 p->lastpkt_rootdelay 1714 p->lastpkt_rootdelay,
1715 p->reachable_bits
1645 /* not shown: m_ppoll, m_precision_exp, m_rootdisp, 1716 /* not shown: m_ppoll, m_precision_exp, m_rootdisp,
1646 * m_reftime, m_orgtime, m_rectime, m_xmttime 1717 * m_reftime, m_orgtime, m_rectime, m_xmttime
1647 */ 1718 */
@@ -1660,7 +1731,7 @@ recv_and_process_peer_pkt(peer_t *p)
1660 * drop poll interval one step down. 1731 * drop poll interval one step down.
1661 */ 1732 */
1662 if (fabs(q->filter_offset) >= POLLDOWN_OFFSET) { 1733 if (fabs(q->filter_offset) >= POLLDOWN_OFFSET) {
1663 VERB3 bb_error_msg("offset:%f > POLLDOWN_OFFSET", q->filter_offset); 1734 VERB3 bb_error_msg("offset:%+f > POLLDOWN_OFFSET", q->filter_offset);
1664 goto poll_down; 1735 goto poll_down;
1665 } 1736 }
1666 } 1737 }
@@ -1674,14 +1745,7 @@ recv_and_process_peer_pkt(peer_t *p)
1674 * is increased, otherwise it is decreased. A bit of hysteresis 1745 * is increased, otherwise it is decreased. A bit of hysteresis
1675 * helps calm the dance. Works best using burst mode. 1746 * helps calm the dance. Works best using burst mode.
1676 */ 1747 */
1677 VERB4 if (rc > 0) { 1748 if (rc > 0 && G.offset_to_jitter_ratio <= POLLADJ_GATE) {
1678 bb_error_msg("offset:%f POLLADJ_GATE*discipline_jitter:%f poll:%s",
1679 q->filter_offset, POLLADJ_GATE * G.discipline_jitter,
1680 fabs(q->filter_offset) < POLLADJ_GATE * G.discipline_jitter
1681 ? "grows" : "falls"
1682 );
1683 }
1684 if (rc > 0 && fabs(q->filter_offset) < POLLADJ_GATE * G.discipline_jitter) {
1685 /* was += G.poll_exp but it is a bit 1749 /* was += G.poll_exp but it is a bit
1686 * too optimistic for my taste at high poll_exp's */ 1750 * too optimistic for my taste at high poll_exp's */
1687 G.polladj_count += MINPOLL; 1751 G.polladj_count += MINPOLL;
@@ -2060,8 +2124,23 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
2060 timeout++; /* (nextaction - G.cur_time) rounds down, compensating */ 2124 timeout++; /* (nextaction - G.cur_time) rounds down, compensating */
2061 2125
2062 /* Here we may block */ 2126 /* Here we may block */
2063 VERB2 bb_error_msg("poll %us, sockets:%u, poll interval:%us", timeout, i, 1 << G.poll_exp); 2127 VERB2 {
2128 if (i > (ENABLE_FEATURE_NTPD_SERVER && G.listen_fd != -1)) {
2129 /* We wait for at least one reply.
2130 * Poll for it, without wasting time for message.
2131 * Since replies often come under 1 second, this also
2132 * reduces clutter in logs.
2133 */
2134 nfds = poll(pfd, i, 1000);
2135 if (nfds != 0)
2136 goto did_poll;
2137 if (--timeout <= 0)
2138 goto did_poll;
2139 }
2140 bb_error_msg("poll:%us sockets:%u interval:%us", timeout, i, 1 << G.poll_exp);
2141 }
2064 nfds = poll(pfd, i, timeout * 1000); 2142 nfds = poll(pfd, i, timeout * 1000);
2143 did_poll:
2065 gettime1900d(); /* sets G.cur_time */ 2144 gettime1900d(); /* sets G.cur_time */
2066 if (nfds <= 0) { 2145 if (nfds <= 0) {
2067 if (G.script_name && G.cur_time - G.last_script_run > 11*60) { 2146 if (G.script_name && G.cur_time - G.last_script_run > 11*60) {
diff --git a/networking/tftp.c b/networking/tftp.c
index 043b879af..ce48a1edd 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -789,8 +789,9 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv)
789 openlog(applet_name, LOG_PID, LOG_DAEMON); 789 openlog(applet_name, LOG_PID, LOG_DAEMON);
790 logmode = LOGMODE_SYSLOG; 790 logmode = LOGMODE_SYSLOG;
791 } 791 }
792 if (argv[0]) 792 if (argv[0]) {
793 xchdir(argv[0]); 793 xchroot(argv[0]);
794 }
794 795
795 result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf), 796 result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf),
796 0 /* flags */, 797 0 /* flags */,
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 2e6113627..ae0e0d306 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -29,9 +29,9 @@ const struct dhcp_optflag dhcp_optflags[] = {
29// { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */ 29// { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */
30// { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */ 30// { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */
31 { OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */ 31 { OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */
32 { OPTION_STRING | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */ 32 { OPTION_STRING_HOST | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */
33 { OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */ 33 { OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */
34 { OPTION_STRING | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */ 34 { OPTION_STRING_HOST | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */
35 { OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */ 35 { OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */
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 */
@@ -41,7 +41,7 @@ const struct dhcp_optflag dhcp_optflags[] = {
41//server would let us know anyway? 41//server would let us know anyway?
42 { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ 42 { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */
43 { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */ 43 { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */
44 { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ 44 { OPTION_STRING_HOST , 0x28 }, /* DHCP_NIS_DOMAIN */
45 { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */ 45 { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */
46 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */ 46 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */
47 { OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */ 47 { OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */
@@ -49,7 +49,7 @@ const struct dhcp_optflag dhcp_optflags[] = {
49 { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */ 49 { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */
50 { OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */ 50 { OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */
51//TODO: must be combined with 'sname' and 'file' handling: 51//TODO: must be combined with 'sname' and 'file' handling:
52 { OPTION_STRING , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ 52 { OPTION_STRING_HOST , 0x42 }, /* DHCP_TFTP_SERVER_NAME */
53 { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */ 53 { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */
54//TODO: not a string, but a set of LASCII strings: 54//TODO: not a string, but a set of LASCII strings:
55// { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */ 55// { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */
@@ -57,13 +57,13 @@ const struct dhcp_optflag dhcp_optflags[] = {
57 { OPTION_DNS_STRING | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */ 57 { OPTION_DNS_STRING | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */
58 { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */ 58 { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */
59#endif 59#endif
60 { OPTION_STATIC_ROUTES , 0x79 }, /* DHCP_STATIC_ROUTES */ 60 { OPTION_STATIC_ROUTES | OPTION_LIST , 0x79 }, /* DHCP_STATIC_ROUTES */
61#if ENABLE_FEATURE_UDHCP_8021Q 61#if ENABLE_FEATURE_UDHCP_8021Q
62 { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */ 62 { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */
63 { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */ 63 { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */
64#endif 64#endif
65 { OPTION_6RD , 0xd4 }, /* DHCP_6RD */ 65 { OPTION_6RD , 0xd4 }, /* DHCP_6RD */
66 { OPTION_STATIC_ROUTES , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ 66 { OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
67 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ 67 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */
68 68
69 /* Options below have no match in dhcp_option_strings[], 69 /* Options below have no match in dhcp_option_strings[],
@@ -123,8 +123,6 @@ const char dhcp_option_strings[] ALIGN1 =
123// is not handled yet by "string->option" conversion code: 123// is not handled yet by "string->option" conversion code:
124 "sipsrv" "\0" /* DHCP_SIP_SERVERS */ 124 "sipsrv" "\0" /* DHCP_SIP_SERVERS */
125#endif 125#endif
126// doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES
127// is not handled yet by "string->option" conversion code:
128 "staticroutes" "\0"/* DHCP_STATIC_ROUTES */ 126 "staticroutes" "\0"/* DHCP_STATIC_ROUTES */
129#if ENABLE_FEATURE_UDHCP_8021Q 127#if ENABLE_FEATURE_UDHCP_8021Q
130 "vlanid" "\0" /* DHCP_VLAN_ID */ 128 "vlanid" "\0" /* DHCP_VLAN_ID */
@@ -148,6 +146,7 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = {
148 [OPTION_IP_PAIR] = 8, 146 [OPTION_IP_PAIR] = 8,
149// [OPTION_BOOLEAN] = 1, 147// [OPTION_BOOLEAN] = 1,
150 [OPTION_STRING] = 1, /* ignored by udhcp_str2optset */ 148 [OPTION_STRING] = 1, /* ignored by udhcp_str2optset */
149 [OPTION_STRING_HOST] = 1, /* ignored by udhcp_str2optset */
151#if ENABLE_FEATURE_UDHCP_RFC3397 150#if ENABLE_FEATURE_UDHCP_RFC3397
152 [OPTION_DNS_STRING] = 1, /* ignored by both udhcp_str2optset and xmalloc_optname_optval */ 151 [OPTION_DNS_STRING] = 1, /* ignored by both udhcp_str2optset and xmalloc_optname_optval */
153 [OPTION_SIP_SERVERS] = 1, 152 [OPTION_SIP_SERVERS] = 1,
@@ -337,7 +336,8 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg)
337 lsa = host_and_af2sockaddr(str, 0, AF_INET); 336 lsa = host_and_af2sockaddr(str, 0, AF_INET);
338 if (!lsa) 337 if (!lsa)
339 return 0; 338 return 0;
340 *(uint32_t*)arg = lsa->u.sin.sin_addr.s_addr; 339 /* arg maybe unaligned */
340 move_to_unaligned32((uint32_t*)arg, lsa->u.sin.sin_addr.s_addr);
341 free(lsa); 341 free(lsa);
342 return 1; 342 return 1;
343} 343}
@@ -417,7 +417,9 @@ static NOINLINE void attach_option(
417 /* actually 255 is ok too, but adding a space can overlow it */ 417 /* actually 255 is ok too, but adding a space can overlow it */
418 418
419 existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length); 419 existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length);
420 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING) { 420 if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING
421 || (optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING_HOST
422 ) {
421 /* add space separator between STRING options in a list */ 423 /* add space separator between STRING options in a list */
422 existing->data[OPT_DATA + old_len] = ' '; 424 existing->data[OPT_DATA + old_len] = ' ';
423 old_len++; 425 old_len++;
@@ -434,13 +436,14 @@ static NOINLINE void attach_option(
434int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) 436int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
435{ 437{
436 struct option_set **opt_list = arg; 438 struct option_set **opt_list = arg;
437 char *opt, *val, *endptr; 439 char *opt, *val;
438 char *str; 440 char *str;
439 const struct dhcp_optflag *optflag; 441 const struct dhcp_optflag *optflag;
440 struct dhcp_optflag bin_optflag; 442 struct dhcp_optflag bin_optflag;
441 unsigned optcode; 443 unsigned optcode;
442 int retval, length; 444 int retval, length;
443 char buffer[8] ALIGNED(4); 445 /* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */
446 char buffer[9] ALIGNED(4);
444 uint16_t *result_u16 = (uint16_t *) buffer; 447 uint16_t *result_u16 = (uint16_t *) buffer;
445 uint32_t *result_u32 = (uint32_t *) buffer; 448 uint32_t *result_u32 = (uint32_t *) buffer;
446 449
@@ -481,6 +484,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
481 retval = udhcp_str2nip(val, buffer + 4); 484 retval = udhcp_str2nip(val, buffer + 4);
482 break; 485 break;
483 case OPTION_STRING: 486 case OPTION_STRING:
487 case OPTION_STRING_HOST:
484#if ENABLE_FEATURE_UDHCP_RFC3397 488#if ENABLE_FEATURE_UDHCP_RFC3397
485 case OPTION_DNS_STRING: 489 case OPTION_DNS_STRING:
486#endif 490#endif
@@ -497,34 +501,53 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
497// break; 501// break;
498// } 502// }
499 case OPTION_U8: 503 case OPTION_U8:
500 buffer[0] = strtoul(val, &endptr, 0); 504 buffer[0] = bb_strtou32(val, NULL, 0);
501 retval = (endptr[0] == '\0'); 505 retval = (errno == 0);
502 break; 506 break;
503 /* htonX are macros in older libc's, using temp var 507 /* htonX are macros in older libc's, using temp var
504 * in code below for safety */ 508 * in code below for safety */
505 /* TODO: use bb_strtoX? */ 509 /* TODO: use bb_strtoX? */
506 case OPTION_U16: { 510 case OPTION_U16: {
507 unsigned long tmp = strtoul(val, &endptr, 0); 511 uint32_t tmp = bb_strtou32(val, NULL, 0);
508 *result_u16 = htons(tmp); 512 *result_u16 = htons(tmp);
509 retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/); 513 retval = (errno == 0 /*&& tmp < 0x10000*/);
510 break; 514 break;
511 } 515 }
512// case OPTION_S16: { 516// case OPTION_S16: {
513// long tmp = strtol(val, &endptr, 0); 517// long tmp = bb_strtoi32(val, NULL, 0);
514// *result_u16 = htons(tmp); 518// *result_u16 = htons(tmp);
515// retval = (endptr[0] == '\0'); 519// retval = (errno == 0);
516// break; 520// break;
517// } 521// }
518 case OPTION_U32: { 522 case OPTION_U32: {
519 unsigned long tmp = strtoul(val, &endptr, 0); 523 uint32_t tmp = bb_strtou32(val, NULL, 0);
520 *result_u32 = htonl(tmp); 524 *result_u32 = htonl(tmp);
521 retval = (endptr[0] == '\0'); 525 retval = (errno == 0);
522 break; 526 break;
523 } 527 }
524 case OPTION_S32: { 528 case OPTION_S32: {
525 long tmp = strtol(val, &endptr, 0); 529 int32_t tmp = bb_strtoi32(val, NULL, 0);
526 *result_u32 = htonl(tmp); 530 *result_u32 = htonl(tmp);
527 retval = (endptr[0] == '\0'); 531 retval = (errno == 0);
532 break;
533 }
534 case OPTION_STATIC_ROUTES: {
535 /* Input: "a.b.c.d/m" */
536 /* Output: mask(1 byte),pfx(0-4 bytes),gw(4 bytes) */
537 unsigned mask;
538 char *slash = strchr(val, '/');
539 if (slash) {
540 *slash = '\0';
541 retval = udhcp_str2nip(val, buffer + 1);
542 buffer[0] = mask = bb_strtou(slash + 1, NULL, 10);
543 val = strtok(NULL, ", \t/-");
544 if (!val || mask > 32 || errno)
545 retval = 0;
546 if (retval) {
547 length = ((mask + 7) >> 3) + 5;
548 retval = udhcp_str2nip(val, buffer + (length - 4));
549 }
550 }
528 break; 551 break;
529 } 552 }
530 case OPTION_BIN: /* handled in attach_option() */ 553 case OPTION_BIN: /* handled in attach_option() */
@@ -535,7 +558,26 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
535 } 558 }
536 if (retval) 559 if (retval)
537 attach_option(opt_list, optflag, opt, length); 560 attach_option(opt_list, optflag, opt, length);
538 } while (retval && optflag->flags & OPTION_LIST); 561 } while (retval && (optflag->flags & OPTION_LIST));
539 562
540 return retval; 563 return retval;
541} 564}
565
566/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */
567int FAST_FUNC sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip)
568{
569 char hexstrbuf[16 * 2];
570 bin2hex(hexstrbuf, (void*)ip, 16);
571 return sprintf(dest, /* "%s" */
572 "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s",
573 /* pre, */
574 hexstrbuf + 0 * 4,
575 hexstrbuf + 1 * 4,
576 hexstrbuf + 2 * 4,
577 hexstrbuf + 3 * 4,
578 hexstrbuf + 4 * 4,
579 hexstrbuf + 5 * 4,
580 hexstrbuf + 6 * 4,
581 hexstrbuf + 7 * 4
582 );
583}
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index a7f9395b8..cfd58679a 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -80,6 +80,9 @@ enum {
80 OPTION_IP = 1, 80 OPTION_IP = 1,
81 OPTION_IP_PAIR, 81 OPTION_IP_PAIR,
82 OPTION_STRING, 82 OPTION_STRING,
83 /* Opts of STRING_HOST type will be sanitized before they are passed
84 * to udhcpc script's environment: */
85 OPTION_STRING_HOST,
83// OPTION_BOOLEAN, 86// OPTION_BOOLEAN,
84 OPTION_U8, 87 OPTION_U8,
85 OPTION_U16, 88 OPTION_U16,
@@ -308,6 +311,9 @@ int arpping(uint32_t test_nip,
308 uint8_t *from_mac, 311 uint8_t *from_mac,
309 const char *interface) FAST_FUNC; 312 const char *interface) FAST_FUNC;
310 313
314/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */
315int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) FAST_FUNC;
316
311POP_SAVED_FUNCTION_VISIBILITY 317POP_SAVED_FUNCTION_VISIBILITY
312 318
313#endif 319#endif
diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h
new file mode 100644
index 000000000..4dd7e621e
--- /dev/null
+++ b/networking/udhcp/d6_common.h
@@ -0,0 +1,123 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2011 Denys Vlasenko.
4 *
5 * Licensed under GPLv2, see file LICENSE in this source tree.
6 */
7#ifndef UDHCP_D6_COMMON_H
8#define UDHCP_D6_COMMON_H 1
9
10#include <netinet/ip6.h>
11
12PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
13
14
15/*** DHCPv6 packet ***/
16
17/* DHCPv6 protocol. See RFC 3315 */
18#define D6_MSG_SOLICIT 1
19#define D6_MSG_ADVERTISE 2
20#define D6_MSG_REQUEST 3
21#define D6_MSG_CONFIRM 4
22#define D6_MSG_RENEW 5
23#define D6_MSG_REBIND 6
24#define D6_MSG_REPLY 7
25#define D6_MSG_RELEASE 8
26#define D6_MSG_DECLINE 9
27#define D6_MSG_RECONFIGURE 10
28#define D6_MSG_INFORMATION_REQUEST 11
29#define D6_MSG_RELAY_FORW 12
30#define D6_MSG_RELAY_REPL 13
31
32struct d6_packet {
33 union {
34 uint8_t d6_msg_type;
35 uint32_t d6_xid32;
36 } d6_u;
37 uint8_t d6_options[576 - sizeof(struct iphdr) - sizeof(struct udphdr) - 4
38 + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS];
39} PACKED;
40#define d6_msg_type d6_u.d6_msg_type
41#define d6_xid32 d6_u.d6_xid32
42
43struct ip6_udp_d6_packet {
44 struct ip6_hdr ip6;
45 struct udphdr udp;
46 struct d6_packet data;
47} PACKED;
48
49struct udp_d6_packet {
50 struct udphdr udp;
51 struct d6_packet data;
52} PACKED;
53
54/*** Options ***/
55
56struct d6_option {
57 uint8_t code_hi;
58 uint8_t code;
59 uint8_t len_hi;
60 uint8_t len;
61 uint8_t data[1];
62} PACKED;
63
64#define D6_OPT_CLIENTID 1
65#define D6_OPT_SERVERID 2
66#define D6_OPT_IA_NA 3
67#define D6_OPT_IA_TA 4
68#define D6_OPT_IAADDR 5
69#define D6_OPT_ORO 6
70#define D6_OPT_PREFERENCE 7
71#define D6_OPT_ELAPSED_TIME 8
72#define D6_OPT_RELAY_MSG 9
73#define D6_OPT_AUTH 11
74#define D6_OPT_UNICAST 12
75#define D6_OPT_STATUS_CODE 13
76#define D6_OPT_RAPID_COMMIT 14
77#define D6_OPT_USER_CLASS 15
78#define D6_OPT_VENDOR_CLASS 16
79#define D6_OPT_VENDOR_OPTS 17
80#define D6_OPT_INTERFACE_ID 18
81#define D6_OPT_RECONF_MSG 19
82#define D6_OPT_RECONF_ACCEPT 20
83
84#define D6_OPT_IA_PD 25
85#define D6_OPT_IAPREFIX 26
86
87/*** Other shared functions ***/
88
89struct client6_data_t {
90 struct d6_option *server_id;
91 struct d6_option *ia_na;
92 char **env_ptr;
93 unsigned env_idx;
94};
95
96#define client6_data (*(struct client6_data_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE - sizeof(struct client6_data_t)]))
97
98int FAST_FUNC d6_listen_socket(int port, const char *inf);
99
100int FAST_FUNC d6_recv_kernel_packet(
101 struct in6_addr *peer_ipv6,
102 struct d6_packet *packet, int fd
103);
104
105int FAST_FUNC d6_send_raw_packet(
106 struct d6_packet *d6_pkt, unsigned d6_pkt_size,
107 struct in6_addr *src_ipv6, int source_port,
108 struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp,
109 int ifindex
110);
111
112int FAST_FUNC d6_send_kernel_packet(
113 struct d6_packet *d6_pkt, unsigned d6_pkt_size,
114 struct in6_addr *src_ipv6, int source_port,
115 struct in6_addr *dst_ipv6, int dest_port
116);
117
118void FAST_FUNC d6_dump_packet(struct d6_packet *packet);
119
120
121POP_SAVED_FUNCTION_VISIBILITY
122
123#endif
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
new file mode 100644
index 000000000..23e6862dc
--- /dev/null
+++ b/networking/udhcp/d6_dhcpc.c
@@ -0,0 +1,1483 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * DHCPv6 client.
4 *
5 * 2011-11.
6 * WARNING: THIS CODE IS INCOMPLETE. IT IS NOWHERE NEAR
7 * TO BE READY FOR PRODUCTION USE.
8 *
9 * Copyright (C) 2011 Denys Vlasenko.
10 *
11 * Licensed under GPLv2, see file LICENSE in this source tree.
12 */
13
14//config:config UDHCPC6
15//config: bool "udhcp client for DHCPv6 (udhcpc6)"
16//config: default n # not yet ready
17//config: help
18//config: udhcpc6 is a DHCPv6 client
19
20//applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP))
21
22//kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o
23
24
25#include <syslog.h>
26/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */
27#define WANT_PIDFILE 1
28#include "common.h"
29#include "dhcpd.h"
30#include "dhcpc.h"
31#include "d6_common.h"
32
33#include <netinet/if_ether.h>
34#include <netpacket/packet.h>
35#include <linux/filter.h>
36
37/* "struct client_config_t client_config" is in bb_common_bufsiz1 */
38
39
40#if ENABLE_LONG_OPTS
41static const char udhcpc6_longopts[] ALIGN1 =
42 "interface\0" Required_argument "i"
43 "now\0" No_argument "n"
44 "pidfile\0" Required_argument "p"
45 "quit\0" No_argument "q"
46 "release\0" No_argument "R"
47 "request\0" Required_argument "r"
48 "script\0" Required_argument "s"
49 "timeout\0" Required_argument "T"
50 "retries\0" Required_argument "t"
51 "tryagain\0" Required_argument "A"
52 "syslog\0" No_argument "S"
53 "request-option\0" Required_argument "O"
54 "no-default-options\0" No_argument "o"
55 "foreground\0" No_argument "f"
56 "background\0" No_argument "b"
57/// IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a")
58 IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P")
59 ;
60#endif
61/* Must match getopt32 option string order */
62enum {
63 OPT_i = 1 << 0,
64 OPT_n = 1 << 1,
65 OPT_p = 1 << 2,
66 OPT_q = 1 << 3,
67 OPT_R = 1 << 4,
68 OPT_r = 1 << 5,
69 OPT_s = 1 << 6,
70 OPT_T = 1 << 7,
71 OPT_t = 1 << 8,
72 OPT_S = 1 << 9,
73 OPT_A = 1 << 10,
74 OPT_O = 1 << 11,
75 OPT_o = 1 << 12,
76 OPT_x = 1 << 13,
77 OPT_f = 1 << 14,
78/* The rest has variable bit positions, need to be clever */
79 OPTBIT_f = 14,
80 USE_FOR_MMU( OPTBIT_b,)
81 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
82 IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
83 USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,)
84 ///IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
85 IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,)
86};
87
88
89/*** Utility functions ***/
90
91static void *d6_find_option(uint8_t *option, uint8_t *option_end, unsigned code)
92{
93 /* "length minus 4" */
94 int len_m4 = option_end - option - 4;
95 while (len_m4 >= 0) {
96 /* Next option's len is too big? */
97 if (option[3] > len_m4)
98 return NULL; /* yes. bogus packet! */
99 /* So far we treat any opts with code >255
100 * or len >255 as bogus, and stop at once.
101 * This simplifies big-endian handling.
102 */
103 if (option[0] != 0 || option[2] != 0)
104 return NULL;
105 /* Option seems to be valid */
106 /* Does its code match? */
107 if (option[1] == code)
108 return option; /* yes! */
109 option += option[3] + 4;
110 len_m4 -= option[3] + 4;
111 }
112 return NULL;
113}
114
115static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code)
116{
117 uint8_t *opt = d6_find_option(option, option_end, code);
118 if (!opt)
119 return opt;
120 return memcpy(xmalloc(opt[3] + 4), opt, opt[3] + 4);
121}
122
123static void *d6_store_blob(void *dst, const void *src, unsigned len)
124{
125 memcpy(dst, src, len);
126 return dst + len;
127}
128
129
130/*** Script execution code ***/
131
132static char** new_env(void)
133{
134 client6_data.env_ptr = xrealloc_vector(client6_data.env_ptr, 3, client6_data.env_idx);
135 return &client6_data.env_ptr[client6_data.env_idx++];
136}
137
138/* put all the parameters into the environment */
139static void option_to_env(uint8_t *option, uint8_t *option_end)
140{
141 /* "length minus 4" */
142 int len_m4 = option_end - option - 4;
143 while (len_m4 >= 0) {
144 uint32_t v32;
145 char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
146
147 if (option[0] != 0 || option[2] != 0)
148 break;
149
150 switch (option[1]) {
151 //case D6_OPT_CLIENTID:
152 //case D6_OPT_SERVERID:
153 case D6_OPT_IA_NA:
154 case D6_OPT_IA_PD:
155 option_to_env(option + 16, option + 4 + option[3]);
156 break;
157 //case D6_OPT_IA_TA:
158 case D6_OPT_IAADDR:
159/* 0 1 2 3
160 * 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
161 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
162 * | OPTION_IAADDR | option-len |
163 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
164 * | |
165 * | IPv6 address |
166 * | |
167 * | |
168 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
169 * | preferred-lifetime |
170 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
171 * | valid-lifetime |
172 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
173 */
174 sprint_nip6(ipv6str, option + 4);
175 *new_env() = xasprintf("ipv6=%s", ipv6str);
176
177 move_from_unaligned32(v32, option + 4 + 16 + 4);
178 *new_env() = xasprintf("lease=%u", (unsigned)v32);
179 break;
180
181 //case D6_OPT_ORO:
182 //case D6_OPT_PREFERENCE:
183 //case D6_OPT_ELAPSED_TIME:
184 //case D6_OPT_RELAY_MSG:
185 //case D6_OPT_AUTH:
186 //case D6_OPT_UNICAST:
187 //case D6_OPT_STATUS_CODE:
188 //case D6_OPT_RAPID_COMMIT:
189 //case D6_OPT_USER_CLASS:
190 //case D6_OPT_VENDOR_CLASS:
191 //case D6_OPT_VENDOR_OPTS:
192 //case D6_OPT_INTERFACE_ID:
193 //case D6_OPT_RECONF_MSG:
194 //case D6_OPT_RECONF_ACCEPT:
195
196 case D6_OPT_IAPREFIX:
197/* 0 1 2 3
198 * 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
199 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
200 * | OPTION_IAPREFIX | option-length |
201 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
202 * | preferred-lifetime |
203 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
204 * | valid-lifetime |
205 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
206 * | prefix-length | |
207 * +-+-+-+-+-+-+-+-+ IPv6 prefix |
208 * | (16 octets) |
209 * | |
210 * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
211 * | |
212 * +-+-+-+-+-+-+-+-+
213 */
214 //move_from_unaligned32(v32, option + 4 + 4);
215 //*new_env() = xasprintf("lease=%u", (unsigned)v32);
216
217 sprint_nip6(ipv6str, option + 4 + 4 + 1);
218 *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4]));
219 }
220 option += 4 + option[3];
221 len_m4 -= 4 + option[3];
222 }
223}
224
225static char **fill_envp(struct d6_packet *packet)
226{
227 char **envp, **curr;
228
229 client6_data.env_ptr = NULL;
230 client6_data.env_idx = 0;
231
232 *new_env() = xasprintf("interface=%s", client_config.interface);
233
234 if (packet)
235 option_to_env(packet->d6_options, packet->d6_options + sizeof(packet->d6_options));
236
237 envp = curr = client6_data.env_ptr;
238 while (*curr)
239 putenv(*curr++);
240
241 return envp;
242}
243
244/* Call a script with a par file and env vars */
245static void d6_run_script(struct d6_packet *packet, const char *name)
246{
247 char **envp, **curr;
248 char *argv[3];
249
250 envp = fill_envp(packet);
251
252 /* call script */
253 log1("Executing %s %s", client_config.script, name);
254 argv[0] = (char*) client_config.script;
255 argv[1] = (char*) name;
256 argv[2] = NULL;
257 spawn_and_wait(argv);
258
259 for (curr = envp; *curr; curr++) {
260 log2(" %s", *curr);
261 bb_unsetenv_and_free(*curr);
262 }
263 free(envp);
264}
265
266
267/*** Sending/receiving packets ***/
268
269static ALWAYS_INLINE uint32_t random_xid(void)
270{
271 uint32_t t = rand() & htonl(0x00ffffff);
272 return t;
273}
274
275/* Initialize the packet with the proper defaults */
276static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid)
277{
278 struct d6_option *clientid;
279
280 memset(packet, 0, sizeof(*packet));
281
282 packet->d6_xid32 = xid;
283 packet->d6_msg_type = type;
284
285 clientid = (void*)client_config.clientid;
286 return d6_store_blob(packet->d6_options, clientid, clientid->len + 2+2);
287}
288
289static uint8_t *add_d6_client_options(uint8_t *ptr)
290{
291 return ptr;
292 //uint8_t c;
293 //int i, end, len;
294
295 /* Add a "param req" option with the list of options we'd like to have
296 * from stubborn DHCP servers. Pull the data from the struct in common.c.
297 * No bounds checking because it goes towards the head of the packet. */
298 //...
299
300 /* Add -x options if any */
301 //...
302}
303
304static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t *end)
305{
306 static const uint8_t FF02__1_2[16] = {
307 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
309 };
310
311 return d6_send_raw_packet(
312 packet, (end - (uint8_t*) packet),
313 /*src*/ NULL, CLIENT_PORT,
314 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT, MAC_BCAST_ADDR,
315 client_config.ifindex
316 );
317}
318
319/* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP.
320 *
321 * RFC 3315 17.1.1. Creation of Solicit Messages
322 *
323 * The client MUST include a Client Identifier option to identify itself
324 * to the server. The client includes IA options for any IAs to which
325 * it wants the server to assign addresses. The client MAY include
326 * addresses in the IAs as a hint to the server about addresses for
327 * which the client has a preference. ...
328 *
329 * The client uses IA_NA options to request the assignment of non-
330 * temporary addresses and uses IA_TA options to request the assignment
331 * of temporary addresses. Either IA_NA or IA_TA options, or a
332 * combination of both, can be included in DHCP messages.
333 *
334 * The client SHOULD include an Option Request option (see section 22.7)
335 * to indicate the options the client is interested in receiving. The
336 * client MAY additionally include instances of those options that are
337 * identified in the Option Request option, with data values as hints to
338 * the server about parameter values the client would like to have
339 * returned.
340 *
341 * The client includes a Reconfigure Accept option (see section 22.20)
342 * if the client is willing to accept Reconfigure messages from the
343 * server.
344 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
345 | OPTION_CLIENTID | option-len |
346 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
347 . .
348 . DUID .
349 . (variable length) .
350 . .
351 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
352
353
354 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
355 | OPTION_IA_NA | option-len |
356 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
357 | IAID (4 octets) |
358 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
359 | T1 |
360 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
361 | T2 |
362 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
363 | |
364 . IA_NA-options .
365 . .
366 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
367
368
369 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
370 | OPTION_IAADDR | option-len |
371 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372 | |
373 | IPv6 address |
374 | |
375 | |
376 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
377 | preferred-lifetime |
378 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
379 | valid-lifetime |
380 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
381 . .
382 . IAaddr-options .
383 . .
384 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
385
386
387 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
388 | OPTION_ORO | option-len |
389 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
390 | requested-option-code-1 | requested-option-code-2 |
391 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
392 | ... |
393 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
394
395
396 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
397 | OPTION_RECONF_ACCEPT | 0 |
398 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
399 */
400/* NOINLINE: limit stack usage in caller */
401static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ipv6)
402{
403 struct d6_packet packet;
404 uint8_t *opt_ptr;
405 unsigned len;
406
407 /* Fill in: msg type, client id */
408 opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT, xid);
409
410 /* Create new IA_NA, optionally with included IAADDR with requested IP */
411 free(client6_data.ia_na);
412 len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4;
413 client6_data.ia_na = xzalloc(len);
414 client6_data.ia_na->code = D6_OPT_IA_NA;
415 client6_data.ia_na->len = len - 4;
416 *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */
417 if (requested_ipv6) {
418 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
419 iaaddr->code = D6_OPT_IAADDR;
420 iaaddr->len = 16+4+4;
421 memcpy(iaaddr->data, requested_ipv6, 16);
422 }
423 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, len);
424
425 /* Add options:
426 * "param req" option according to -O, options specified with -x
427 */
428 opt_ptr = add_d6_client_options(opt_ptr);
429
430 bb_info_msg("Sending discover...");
431 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr);
432}
433
434/* Multicast a DHCPv6 request message
435 *
436 * RFC 3315 18.1.1. Creation and Transmission of Request Messages
437 *
438 * The client uses a Request message to populate IAs with addresses and
439 * obtain other configuration information. The client includes one or
440 * more IA options in the Request message. The server then returns
441 * addresses and other information about the IAs to the client in IA
442 * options in a Reply message.
443 *
444 * The client generates a transaction ID and inserts this value in the
445 * "transaction-id" field.
446 *
447 * The client places the identifier of the destination server in a
448 * Server Identifier option.
449 *
450 * The client MUST include a Client Identifier option to identify itself
451 * to the server. The client adds any other appropriate options,
452 * including one or more IA options (if the client is requesting that
453 * the server assign it some network addresses).
454 *
455 * The client MUST include an Option Request option (see section 22.7)
456 * to indicate the options the client is interested in receiving. The
457 * client MAY include options with data values as hints to the server
458 * about parameter values the client would like to have returned.
459 *
460 * The client includes a Reconfigure Accept option (see section 22.20)
461 * indicating whether or not the client is willing to accept Reconfigure
462 * messages from the server.
463 */
464/* NOINLINE: limit stack usage in caller */
465static NOINLINE int send_d6_select(uint32_t xid)
466{
467 struct d6_packet packet;
468 uint8_t *opt_ptr;
469
470 /* Fill in: msg type, client id */
471 opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid);
472
473 /* server id */
474 opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
475 /* IA NA (contains requested IP) */
476 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
477
478 /* Add options:
479 * "param req" option according to -O, options specified with -x
480 */
481 opt_ptr = add_d6_client_options(opt_ptr);
482
483 bb_info_msg("Sending select...");
484 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr);
485}
486
487/* Unicast or broadcast a DHCP renew message
488 *
489 * RFC 3315 18.1.3. Creation and Transmission of Renew Messages
490 *
491 * To extend the valid and preferred lifetimes for the addresses
492 * associated with an IA, the client sends a Renew message to the server
493 * from which the client obtained the addresses in the IA containing an
494 * IA option for the IA. The client includes IA Address options in the
495 * IA option for the addresses associated with the IA. The server
496 * determines new lifetimes for the addresses in the IA according to the
497 * administrative configuration of the server. The server may also add
498 * new addresses to the IA. The server may remove addresses from the IA
499 * by setting the preferred and valid lifetimes of those addresses to
500 * zero.
501 *
502 * The server controls the time at which the client contacts the server
503 * to extend the lifetimes on assigned addresses through the T1 and T2
504 * parameters assigned to an IA.
505 *
506 * At time T1 for an IA, the client initiates a Renew/Reply message
507 * exchange to extend the lifetimes on any addresses in the IA. The
508 * client includes an IA option with all addresses currently assigned to
509 * the IA in its Renew message.
510 *
511 * If T1 or T2 is set to 0 by the server (for an IA_NA) or there are no
512 * T1 or T2 times (for an IA_TA), the client may send a Renew or Rebind
513 * message, respectively, at the client's discretion.
514 *
515 * The client sets the "msg-type" field to RENEW. The client generates
516 * a transaction ID and inserts this value in the "transaction-id"
517 * field.
518 *
519 * The client places the identifier of the destination server in a
520 * Server Identifier option.
521 *
522 * The client MUST include a Client Identifier option to identify itself
523 * to the server. The client adds any appropriate options, including
524 * one or more IA options. The client MUST include the list of
525 * addresses the client currently has associated with the IAs in the
526 * Renew message.
527 *
528 * The client MUST include an Option Request option (see section 22.7)
529 * to indicate the options the client is interested in receiving. The
530 * client MAY include options with data values as hints to the server
531 * about parameter values the client would like to have returned.
532 */
533/* NOINLINE: limit stack usage in caller */
534static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
535{
536 struct d6_packet packet;
537 uint8_t *opt_ptr;
538
539 /* Fill in: msg type, client id */
540 opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid);
541
542 /* server id */
543 opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
544 /* IA NA (contains requested IP) */
545 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
546
547 /* Add options:
548 * "param req" option according to -O, options specified with -x
549 */
550 opt_ptr = add_d6_client_options(opt_ptr);
551
552 bb_info_msg("Sending renew...");
553 if (server_ipv6)
554 return d6_send_kernel_packet(
555 &packet, (opt_ptr - (uint8_t*) &packet),
556 our_cur_ipv6, CLIENT_PORT,
557 server_ipv6, SERVER_PORT
558 );
559 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr);
560}
561
562/* Unicast a DHCP release message */
563static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
564{
565 struct d6_packet packet;
566 uint8_t *opt_ptr;
567
568 /* Fill in: msg type, client id */
569 opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid());
570 /* server id */
571 opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2);
572 /* IA NA (contains our current IP) */
573 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
574
575 bb_info_msg("Sending release...");
576 return d6_send_kernel_packet(
577 &packet, (opt_ptr - (uint8_t*) &packet),
578 our_cur_ipv6, CLIENT_PORT,
579 server_ipv6, SERVER_PORT
580 );
581}
582
583/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
584/* NOINLINE: limit stack usage in caller */
585static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6
586 UNUSED_PARAM
587 , struct d6_packet *d6_pkt, int fd)
588{
589 int bytes;
590 struct ip6_udp_d6_packet packet;
591
592 bytes = safe_read(fd, &packet, sizeof(packet));
593 if (bytes < 0) {
594 log1("Packet read error, ignoring");
595 /* NB: possible down interface, etc. Caller should pause. */
596 return bytes; /* returns -1 */
597 }
598
599 if (bytes < (int) (sizeof(packet.ip6) + sizeof(packet.udp))) {
600 log1("Packet is too short, ignoring");
601 return -2;
602 }
603
604 if (bytes < sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen)) {
605 /* packet is bigger than sizeof(packet), we did partial read */
606 log1("Oversized packet, ignoring");
607 return -2;
608 }
609
610 /* ignore any extra garbage bytes */
611 bytes = sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen);
612
613 /* make sure its the right packet for us, and that it passes sanity checks */
614 if (packet.ip6.ip6_nxt != IPPROTO_UDP
615 || (packet.ip6.ip6_vfc >> 4) != 6
616 || packet.udp.dest != htons(CLIENT_PORT)
617 /* || bytes > (int) sizeof(packet) - can't happen */
618 || packet.udp.len != packet.ip6.ip6_plen
619 ) {
620 log1("Unrelated/bogus packet, ignoring");
621 return -2;
622 }
623
624//How to do this for ipv6?
625// /* verify UDP checksum. IP header has to be modified for this */
626// memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
627// /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
628// packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
629// check = packet.udp.check;
630// packet.udp.check = 0;
631// if (check && check != inet_cksum((uint16_t *)&packet, bytes)) {
632// log1("Packet with bad UDP checksum received, ignoring");
633// return -2;
634// }
635
636 log1("Received a packet");
637 d6_dump_packet(&packet.data);
638
639 bytes -= sizeof(packet.ip6) + sizeof(packet.udp);
640 memcpy(d6_pkt, &packet.data, bytes);
641 return bytes;
642}
643
644
645/*** Main ***/
646
647static int sockfd = -1;
648
649#define LISTEN_NONE 0
650#define LISTEN_KERNEL 1
651#define LISTEN_RAW 2
652static smallint listen_mode;
653
654/* initial state: (re)start DHCP negotiation */
655#define INIT_SELECTING 0
656/* discover was sent, DHCPOFFER reply received */
657#define REQUESTING 1
658/* select/renew was sent, DHCPACK reply received */
659#define BOUND 2
660/* half of lease passed, want to renew it by sending unicast renew requests */
661#define RENEWING 3
662/* renew requests were not answered, lease is almost over, send broadcast renew */
663#define REBINDING 4
664/* manually requested renew (SIGUSR1) */
665#define RENEW_REQUESTED 5
666/* release, possibly manually requested (SIGUSR2) */
667#define RELEASED 6
668static smallint state;
669
670static int d6_raw_socket(int ifindex)
671{
672 int fd;
673 struct sockaddr_ll sock;
674
675 /*
676 * Comment:
677 *
678 * I've selected not to see LL header, so BPF doesn't see it, too.
679 * The filter may also pass non-IP and non-ARP packets, but we do
680 * a more complete check when receiving the message in userspace.
681 *
682 * and filter shamelessly stolen from:
683 *
684 * http://www.flamewarmaster.de/software/dhcpclient/
685 *
686 * There are a few other interesting ideas on that page (look under
687 * "Motivation"). Use of netlink events is most interesting. Think
688 * of various network servers listening for events and reconfiguring.
689 * That would obsolete sending HUP signals and/or make use of restarts.
690 *
691 * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
692 * License: GPL v2.
693 *
694 * TODO: make conditional?
695 */
696#if 0
697 static const struct sock_filter filter_instr[] = {
698 /* load 9th byte (protocol) */
699 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
700 /* jump to L1 if it is IPPROTO_UDP, else to L4 */
701 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
702 /* L1: load halfword from offset 6 (flags and frag offset) */
703 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
704 /* jump to L4 if any bits in frag offset field are set, else to L2 */
705 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
706 /* L2: skip IP header (load index reg with header len) */
707 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
708 /* load udp destination port from halfword[header_len + 2] */
709 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
710 /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */
711 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
712 /* L3: accept packet */
713 BPF_STMT(BPF_RET|BPF_K, 0xffffffff),
714 /* L4: discard packet */
715 BPF_STMT(BPF_RET|BPF_K, 0),
716 };
717 static const struct sock_fprog filter_prog = {
718 .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
719 /* casting const away: */
720 .filter = (struct sock_filter *) filter_instr,
721 };
722#endif
723
724 log1("Opening raw socket on ifindex %d", ifindex); //log2?
725
726 fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
727 log1("Got raw socket fd %d", fd); //log2?
728
729 sock.sll_family = AF_PACKET;
730 sock.sll_protocol = htons(ETH_P_IPV6);
731 sock.sll_ifindex = ifindex;
732 xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
733
734#if 0
735 if (CLIENT_PORT == 68) {
736 /* Use only if standard port is in use */
737 /* Ignoring error (kernel may lack support for this) */
738 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
739 sizeof(filter_prog)) >= 0)
740 log1("Attached filter to raw socket fd %d", fd); // log?
741 }
742#endif
743
744 log1("Created raw socket");
745
746 return fd;
747}
748
749static void change_listen_mode(int new_mode)
750{
751 log1("Entering listen mode: %s",
752 new_mode != LISTEN_NONE
753 ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw")
754 : "none"
755 );
756
757 listen_mode = new_mode;
758 if (sockfd >= 0) {
759 close(sockfd);
760 sockfd = -1;
761 }
762 if (new_mode == LISTEN_KERNEL)
763 sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);
764 else if (new_mode != LISTEN_NONE)
765 sockfd = d6_raw_socket(client_config.ifindex);
766 /* else LISTEN_NONE: sockfd stays closed */
767}
768
769/* Called only on SIGUSR1 */
770static void perform_renew(void)
771{
772 bb_info_msg("Performing a DHCP renew");
773 switch (state) {
774 case BOUND:
775 change_listen_mode(LISTEN_KERNEL);
776 case RENEWING:
777 case REBINDING:
778 state = RENEW_REQUESTED;
779 break;
780 case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
781 d6_run_script(NULL, "deconfig");
782 case REQUESTING:
783 case RELEASED:
784 change_listen_mode(LISTEN_RAW);
785 state = INIT_SELECTING;
786 break;
787 case INIT_SELECTING:
788 break;
789 }
790}
791
792static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
793{
794 /* send release packet */
795 if (state == BOUND || state == RENEWING || state == REBINDING) {
796 bb_info_msg("Unicasting a release");
797 send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */
798 d6_run_script(NULL, "deconfig");
799 }
800 bb_info_msg("Entering released state");
801
802 change_listen_mode(LISTEN_NONE);
803 state = RELEASED;
804}
805
806///static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
807///{
808/// uint8_t *storage;
809/// int len = strnlen(str, 255);
810/// storage = xzalloc(len + extra + OPT_DATA);
811/// storage[OPT_CODE] = code;
812/// storage[OPT_LEN] = len + extra;
813/// memcpy(storage + extra + OPT_DATA, str, len);
814/// return storage;
815///}
816
817#if BB_MMU
818static void client_background(void)
819{
820 bb_daemonize(0);
821 logmode &= ~LOGMODE_STDIO;
822 /* rewrite pidfile, as our pid is different now */
823 write_pidfile(client_config.pidfile);
824}
825#endif
826
827//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
828//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
829//usage:#else
830//usage:# define IF_UDHCP_VERBOSE(...)
831//usage:#endif
832//usage:#define udhcpc6_trivial_usage
833//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
834//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
835//usage:#define udhcpc6_full_usage "\n"
836//usage: IF_LONG_OPTS(
837//usage: "\n -i,--interface IFACE Interface to use (default eth0)"
838//usage: "\n -p,--pidfile FILE Create pidfile"
839//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
840//usage: "\n -B,--broadcast Request broadcast replies"
841//usage: "\n -t,--retries N Send up to N discover packets"
842//usage: "\n -T,--timeout N Pause between packets (default 3 seconds)"
843//usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)"
844//usage: "\n -f,--foreground Run in foreground"
845//usage: USE_FOR_MMU(
846//usage: "\n -b,--background Background if lease is not obtained"
847//usage: )
848//usage: "\n -n,--now Exit if lease is not obtained"
849//usage: "\n -q,--quit Exit after obtaining lease"
850//usage: "\n -R,--release Release IP on exit"
851//usage: "\n -S,--syslog Log to syslog too"
852//usage: IF_FEATURE_UDHCP_PORT(
853//usage: "\n -P,--client-port N Use port N (default 546)"
854//usage: )
855////usage: IF_FEATURE_UDHCPC_ARPING(
856////usage: "\n -a,--arping Use arping to validate offered address"
857////usage: )
858//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)"
859//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)"
860//usage: "\n -r,--request IP Request this IP address"
861//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
862//usage: "\n Examples of string, numeric, and hex byte opts:"
863//usage: "\n -x hostname:bbox - option 12"
864//usage: "\n -x lease:3600 - option 51 (lease time)"
865//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
866//usage: IF_UDHCP_VERBOSE(
867//usage: "\n -v Verbose"
868//usage: )
869//usage: )
870//usage: IF_NOT_LONG_OPTS(
871//usage: "\n -i IFACE Interface to use (default eth0)"
872//usage: "\n -p FILE Create pidfile"
873//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
874//usage: "\n -B Request broadcast replies"
875//usage: "\n -t N Send up to N discover packets"
876//usage: "\n -T N Pause between packets (default 3 seconds)"
877//usage: "\n -A N Wait N seconds (default 20) after failure"
878//usage: "\n -f Run in foreground"
879//usage: USE_FOR_MMU(
880//usage: "\n -b Background if lease is not obtained"
881//usage: )
882//usage: "\n -n Exit if lease is not obtained"
883//usage: "\n -q Exit after obtaining lease"
884//usage: "\n -R Release IP on exit"
885//usage: "\n -S Log to syslog too"
886//usage: IF_FEATURE_UDHCP_PORT(
887//usage: "\n -P N Use port N (default 546)"
888//usage: )
889////usage: IF_FEATURE_UDHCPC_ARPING(
890////usage: "\n -a Use arping to validate offered address"
891////usage: )
892//usage: "\n -O OPT Request option OPT from server (cumulative)"
893//usage: "\n -o Don't request any options (unless -O is given)"
894//usage: "\n -r IP Request this IP address"
895//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)"
896//usage: "\n Examples of string, numeric, and hex byte opts:"
897//usage: "\n -x hostname:bbox - option 12"
898//usage: "\n -x lease:3600 - option 51 (lease time)"
899//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
900//usage: IF_UDHCP_VERBOSE(
901//usage: "\n -v Verbose"
902//usage: )
903//usage: )
904//usage: "\nSignals:"
905//usage: "\n USR1 Renew lease"
906//usage: "\n USR2 Release lease"
907
908
909int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
910int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
911{
912 const char *str_r;
913 IF_FEATURE_UDHCP_PORT(char *str_P;)
914 void *clientid_mac_ptr;
915 llist_t *list_O = NULL;
916 llist_t *list_x = NULL;
917 int tryagain_timeout = 20;
918 int discover_timeout = 3;
919 int discover_retries = 3;
920 struct in6_addr srv6_buf;
921 struct in6_addr ipv6_buf;
922 struct in6_addr *requested_ipv6;
923 uint32_t xid = 0;
924 int packet_num;
925 int timeout; /* must be signed */
926 unsigned already_waited_sec;
927 unsigned opt;
928 int max_fd;
929 int retval;
930 fd_set rfds;
931
932 /* Default options */
933 IF_FEATURE_UDHCP_PORT(SERVER_PORT = 547;)
934 IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 546;)
935 client_config.interface = "eth0";
936 client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
937
938 /* Parse command line */
939 /* O,x: list; -T,-t,-A take numeric param */
940 opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ;
941 IF_LONG_OPTS(applet_long_options = udhcpc6_longopts;)
942 opt = getopt32(argv, "i:np:qRr:s:T:t:SA:O:ox:f"
943 USE_FOR_MMU("b")
944 ///IF_FEATURE_UDHCPC_ARPING("a")
945 IF_FEATURE_UDHCP_PORT("P:")
946 "v"
947 , &client_config.interface, &client_config.pidfile, &str_r /* i,p */
948 , &client_config.script /* s */
949 , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
950 , &list_O
951 , &list_x
952 IF_FEATURE_UDHCP_PORT(, &str_P)
953 IF_UDHCP_VERBOSE(, &dhcp_verbose)
954 );
955 requested_ipv6 = NULL;
956 if (opt & OPT_r) {
957 if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0)
958 bb_error_msg_and_die("bad IPv6 address '%s'", str_r);
959 requested_ipv6 = &ipv6_buf;
960 }
961#if ENABLE_FEATURE_UDHCP_PORT
962 if (opt & OPT_P) {
963 CLIENT_PORT = xatou16(str_P);
964 SERVER_PORT = CLIENT_PORT - 1;
965 }
966#endif
967 if (opt & OPT_o)
968 client_config.no_default_options = 1;
969 while (list_O) {
970 char *optstr = llist_pop(&list_O);
971 unsigned n = bb_strtou(optstr, NULL, 0);
972 if (errno || n > 254) {
973 n = udhcp_option_idx(optstr);
974 n = dhcp_optflags[n].code;
975 }
976 client_config.opt_mask[n >> 3] |= 1 << (n & 7);
977 }
978 while (list_x) {
979 char *optstr = llist_pop(&list_x);
980 char *colon = strchr(optstr, ':');
981 if (colon)
982 *colon = ' ';
983 /* now it looks similar to udhcpd's config file line:
984 * "optname optval", using the common routine: */
985 udhcp_str2optset(optstr, &client_config.options);
986 }
987
988 if (udhcp_read_interface(client_config.interface,
989 &client_config.ifindex,
990 NULL,
991 client_config.client_mac)
992 ) {
993 return 1;
994 }
995
996 /* Create client ID based on mac, set clientid_mac_ptr */
997 {
998 struct d6_option *clientid;
999 clientid = xzalloc(2+2+2+2+6);
1000 clientid->code = D6_OPT_CLIENTID;
1001 clientid->len = 2+2+6;
1002 clientid->data[1] = 3; /* DUID-LL */
1003 clientid->data[3] = 1; /* ethernet */
1004 clientid_mac_ptr = clientid->data + 2+2;
1005 memcpy(clientid_mac_ptr, client_config.client_mac, 6);
1006 client_config.clientid = (void*)clientid;
1007 }
1008
1009#if !BB_MMU
1010 /* on NOMMU reexec (i.e., background) early */
1011 if (!(opt & OPT_f)) {
1012 bb_daemonize_or_rexec(0 /* flags */, argv);
1013 logmode = LOGMODE_NONE;
1014 }
1015#endif
1016 if (opt & OPT_S) {
1017 openlog(applet_name, LOG_PID, LOG_DAEMON);
1018 logmode |= LOGMODE_SYSLOG;
1019 }
1020
1021 /* Make sure fd 0,1,2 are open */
1022 bb_sanitize_stdio();
1023 /* Equivalent of doing a fflush after every \n */
1024 setlinebuf(stdout);
1025 /* Create pidfile */
1026 write_pidfile(client_config.pidfile);
1027 /* Goes to stdout (unless NOMMU) and possibly syslog */
1028 bb_info_msg("%s (v"BB_VER") started", applet_name);
1029 /* Set up the signal pipe */
1030 udhcp_sp_setup();
1031 /* We want random_xid to be random... */
1032 srand(monotonic_us());
1033
1034 state = INIT_SELECTING;
1035 d6_run_script(NULL, "deconfig");
1036 change_listen_mode(LISTEN_RAW);
1037 packet_num = 0;
1038 timeout = 0;
1039 already_waited_sec = 0;
1040
1041 /* Main event loop. select() waits on signal pipe and possibly
1042 * on sockfd.
1043 * "continue" statements in code below jump to the top of the loop.
1044 */
1045 for (;;) {
1046 struct timeval tv;
1047 struct d6_packet packet;
1048 uint8_t *packet_end;
1049 /* silence "uninitialized!" warning */
1050 unsigned timestamp_before_wait = timestamp_before_wait;
1051
1052 //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode);
1053
1054 /* Was opening raw or udp socket here
1055 * if (listen_mode != LISTEN_NONE && sockfd < 0),
1056 * but on fast network renew responses return faster
1057 * than we open sockets. Thus this code is moved
1058 * to change_listen_mode(). Thus we open listen socket
1059 * BEFORE we send renew request (see "case BOUND:"). */
1060
1061 max_fd = udhcp_sp_fd_set(&rfds, sockfd);
1062
1063 tv.tv_sec = timeout - already_waited_sec;
1064 tv.tv_usec = 0;
1065 retval = 0;
1066 /* If we already timed out, fall through with retval = 0, else... */
1067 if ((int)tv.tv_sec > 0) {
1068 timestamp_before_wait = (unsigned)monotonic_sec();
1069 log1("Waiting on select...");
1070 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
1071 if (retval < 0) {
1072 /* EINTR? A signal was caught, don't panic */
1073 if (errno == EINTR) {
1074 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
1075 continue;
1076 }
1077 /* Else: an error occured, panic! */
1078 bb_perror_msg_and_die("select");
1079 }
1080 }
1081
1082 /* If timeout dropped to zero, time to become active:
1083 * resend discover/renew/whatever
1084 */
1085 if (retval == 0) {
1086 /* When running on a bridge, the ifindex may have changed
1087 * (e.g. if member interfaces were added/removed
1088 * or if the status of the bridge changed).
1089 * Refresh ifindex and client_mac:
1090 */
1091 if (udhcp_read_interface(client_config.interface,
1092 &client_config.ifindex,
1093 NULL,
1094 client_config.client_mac)
1095 ) {
1096 goto ret0; /* iface is gone? */
1097 }
1098 memcpy(clientid_mac_ptr, client_config.client_mac, 6);
1099
1100 /* We will restart the wait in any case */
1101 already_waited_sec = 0;
1102
1103 switch (state) {
1104 case INIT_SELECTING:
1105 if (packet_num < discover_retries) {
1106 if (packet_num == 0)
1107 xid = random_xid();
1108 /* multicast */
1109 send_d6_discover(xid, requested_ipv6);
1110 timeout = discover_timeout;
1111 packet_num++;
1112 continue;
1113 }
1114 leasefail:
1115 d6_run_script(NULL, "leasefail");
1116#if BB_MMU /* -b is not supported on NOMMU */
1117 if (opt & OPT_b) { /* background if no lease */
1118 bb_info_msg("No lease, forking to background");
1119 client_background();
1120 /* do not background again! */
1121 opt = ((opt & ~OPT_b) | OPT_f);
1122 } else
1123#endif
1124 if (opt & OPT_n) { /* abort if no lease */
1125 bb_info_msg("No lease, failing");
1126 retval = 1;
1127 goto ret;
1128 }
1129 /* wait before trying again */
1130 timeout = tryagain_timeout;
1131 packet_num = 0;
1132 continue;
1133 case REQUESTING:
1134 if (packet_num < discover_retries) {
1135 /* send multicast select packet */
1136 send_d6_select(xid);
1137 timeout = discover_timeout;
1138 packet_num++;
1139 continue;
1140 }
1141 /* Timed out, go back to init state.
1142 * "discover...select...discover..." loops
1143 * were seen in the wild. Treat them similarly
1144 * to "no response to discover" case */
1145 change_listen_mode(LISTEN_RAW);
1146 state = INIT_SELECTING;
1147 goto leasefail;
1148 case BOUND:
1149 /* 1/2 lease passed, enter renewing state */
1150 state = RENEWING;
1151 client_config.first_secs = 0; /* make secs field count from 0 */
1152 change_listen_mode(LISTEN_KERNEL);
1153 log1("Entering renew state");
1154 /* fall right through */
1155 case RENEW_REQUESTED: /* manual (SIGUSR1) renew */
1156 case_RENEW_REQUESTED:
1157 case RENEWING:
1158 if (timeout > 60) {
1159 /* send an unicast renew request */
1160 /* Sometimes observed to fail (EADDRNOTAVAIL) to bind
1161 * a new UDP socket for sending inside send_renew.
1162 * I hazard to guess existing listening socket
1163 * is somehow conflicting with it, but why is it
1164 * not deterministic then?! Strange.
1165 * Anyway, it does recover by eventually failing through
1166 * into INIT_SELECTING state.
1167 */
1168 send_d6_renew(xid, &srv6_buf, requested_ipv6);
1169 timeout >>= 1;
1170 continue;
1171 }
1172 /* Timed out, enter rebinding state */
1173 log1("Entering rebinding state");
1174 state = REBINDING;
1175 /* fall right through */
1176 case REBINDING:
1177 /* Switch to bcast receive */
1178 change_listen_mode(LISTEN_RAW);
1179 /* Lease is *really* about to run out,
1180 * try to find DHCP server using broadcast */
1181 if (timeout > 0) {
1182 /* send a broadcast renew request */
1183 send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6);
1184 timeout >>= 1;
1185 continue;
1186 }
1187 /* Timed out, enter init state */
1188 bb_info_msg("Lease lost, entering init state");
1189 d6_run_script(NULL, "deconfig");
1190 state = INIT_SELECTING;
1191 client_config.first_secs = 0; /* make secs field count from 0 */
1192 /*timeout = 0; - already is */
1193 packet_num = 0;
1194 continue;
1195 /* case RELEASED: */
1196 }
1197 /* yah, I know, *you* say it would never happen */
1198 timeout = INT_MAX;
1199 continue; /* back to main loop */
1200 } /* if select timed out */
1201
1202 /* select() didn't timeout, something happened */
1203
1204 /* Is it a signal? */
1205 /* note: udhcp_sp_read checks FD_ISSET before reading */
1206 switch (udhcp_sp_read(&rfds)) {
1207 case SIGUSR1:
1208 client_config.first_secs = 0; /* make secs field count from 0 */
1209 already_waited_sec = 0;
1210 perform_renew();
1211 if (state == RENEW_REQUESTED) {
1212 /* We might be either on the same network
1213 * (in which case renew might work),
1214 * or we might be on a completely different one
1215 * (in which case renew won't ever succeed).
1216 * For the second case, must make sure timeout
1217 * is not too big, or else we can send
1218 * futile renew requests for hours.
1219 * (Ab)use -A TIMEOUT value (usually 20 sec)
1220 * as a cap on the timeout.
1221 */
1222 if (timeout > tryagain_timeout)
1223 timeout = tryagain_timeout;
1224 goto case_RENEW_REQUESTED;
1225 }
1226 /* Start things over */
1227 packet_num = 0;
1228 /* Kill any timeouts, user wants this to hurry along */
1229 timeout = 0;
1230 continue;
1231 case SIGUSR2:
1232 perform_d6_release(&srv6_buf, requested_ipv6);
1233 timeout = INT_MAX;
1234 continue;
1235 case SIGTERM:
1236 bb_info_msg("Received SIGTERM");
1237 goto ret0;
1238 }
1239
1240 /* Is it a packet? */
1241 if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds))
1242 continue; /* no */
1243
1244 {
1245 int len;
1246
1247 /* A packet is ready, read it */
1248 if (listen_mode == LISTEN_KERNEL)
1249 len = d6_recv_kernel_packet(&srv6_buf, &packet, sockfd);
1250 else
1251 len = d6_recv_raw_packet(&srv6_buf, &packet, sockfd);
1252 if (len == -1) {
1253 /* Error is severe, reopen socket */
1254 bb_info_msg("Read error: %s, reopening socket", strerror(errno));
1255 sleep(discover_timeout); /* 3 seconds by default */
1256 change_listen_mode(listen_mode); /* just close and reopen */
1257 }
1258 /* If this packet will turn out to be unrelated/bogus,
1259 * we will go back and wait for next one.
1260 * Be sure timeout is properly decreased. */
1261 already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
1262 if (len < 0)
1263 continue;
1264 packet_end = (uint8_t*)&packet + len;
1265 }
1266
1267 if ((packet.d6_xid32 & htonl(0x00ffffff)) != xid) {
1268 log1("xid %x (our is %x), ignoring packet",
1269 (unsigned)(packet.d6_xid32 & htonl(0x00ffffff)), (unsigned)xid);
1270 continue;
1271 }
1272
1273 switch (state) {
1274 case INIT_SELECTING:
1275 if (packet.d6_msg_type == D6_MSG_ADVERTISE)
1276 goto type_is_ok;
1277 /* DHCPv6 has "Rapid Commit", when instead of Advertise,
1278 * server sends Reply right away.
1279 * Fall through to check for this case.
1280 */
1281 case REQUESTING:
1282 case RENEWING:
1283 case RENEW_REQUESTED:
1284 case REBINDING:
1285 if (packet.d6_msg_type == D6_MSG_REPLY) {
1286 uint32_t lease_seconds;
1287 struct d6_option *option, *iaaddr;
1288 type_is_ok:
1289 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1290 if (option && option->data[4] != 0) {
1291 /* return to init state */
1292 bb_info_msg("Received DHCP NAK (%u)", option->data[4]);
1293 d6_run_script(&packet, "nak");
1294 if (state != REQUESTING)
1295 d6_run_script(NULL, "deconfig");
1296 change_listen_mode(LISTEN_RAW);
1297 sleep(3); /* avoid excessive network traffic */
1298 state = INIT_SELECTING;
1299 client_config.first_secs = 0; /* make secs field count from 0 */
1300 requested_ipv6 = NULL;
1301 timeout = 0;
1302 packet_num = 0;
1303 already_waited_sec = 0;
1304 continue;
1305 }
1306 option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID);
1307 if (!option) {
1308 bb_error_msg("no server ID, ignoring packet");
1309 continue;
1310 /* still selecting - this server looks bad */
1311 }
1312//Note: we do not bother comparing server IDs in Advertise and Reply msgs.
1313//server_id variable is used solely for creation of proper server_id option
1314//in outgoing packets. (why DHCPv6 even introduced it is a mystery).
1315 free(client6_data.server_id);
1316 client6_data.server_id = option;
1317 if (packet.d6_msg_type == D6_MSG_ADVERTISE) {
1318 /* enter requesting state */
1319 state = REQUESTING;
1320 timeout = 0;
1321 packet_num = 0;
1322 already_waited_sec = 0;
1323 continue;
1324 }
1325 /* It's a D6_MSG_REPLY */
1326/*
1327 * RFC 3315 18.1.8. Receipt of Reply Messages
1328 *
1329 * Upon the receipt of a valid Reply message in response to a Solicit
1330 * (with a Rapid Commit option), Request, Confirm, Renew, Rebind or
1331 * Information-request message, the client extracts the configuration
1332 * information contained in the Reply. The client MAY choose to report
1333 * any status code or message from the status code option in the Reply
1334 * message.
1335 *
1336 * The client SHOULD perform duplicate address detection [17] on each of
1337 * the addresses in any IAs it receives in the Reply message before
1338 * using that address for traffic. If any of the addresses are found to
1339 * be in use on the link, the client sends a Decline message to the
1340 * server as described in section 18.1.7.
1341 *
1342 * If the Reply was received in response to a Solicit (with a Rapid
1343 * Commit option), Request, Renew or Rebind message, the client updates
1344 * the information it has recorded about IAs from the IA options
1345 * contained in the Reply message:
1346 *
1347 * - Record T1 and T2 times.
1348 *
1349 * - Add any new addresses in the IA option to the IA as recorded by
1350 * the client.
1351 *
1352 * - Update lifetimes for any addresses in the IA option that the
1353 * client already has recorded in the IA.
1354 *
1355 * - Discard any addresses from the IA, as recorded by the client, that
1356 * have a valid lifetime of 0 in the IA Address option.
1357 *
1358 * - Leave unchanged any information about addresses the client has
1359 * recorded in the IA but that were not included in the IA from the
1360 * server.
1361 *
1362 * Management of the specific configuration information is detailed in
1363 * the definition of each option in section 22.
1364 *
1365 * If the client receives a Reply message with a Status Code containing
1366 * UnspecFail, the server is indicating that it was unable to process
1367 * the message due to an unspecified failure condition. If the client
1368 * retransmits the original message to the same server to retry the
1369 * desired operation, the client MUST limit the rate at which it
1370 * retransmits the message and limit the duration of the time during
1371 * which it retransmits the message.
1372 *
1373 * When the client receives a Reply message with a Status Code option
1374 * with the value UseMulticast, the client records the receipt of the
1375 * message and sends subsequent messages to the server through the
1376 * interface on which the message was received using multicast. The
1377 * client resends the original message using multicast.
1378 *
1379 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1380 * | OPTION_IA_NA | option-len |
1381 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1382 * | IAID (4 octets) |
1383 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1384 * | T1 |
1385 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1386 * | T2 |
1387 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1388 * | |
1389 * . IA_NA-options .
1390 * . .
1391 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1392 *
1393 *
1394 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1395 * | OPTION_IAADDR | option-len |
1396 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1397 * | |
1398 * | IPv6 address |
1399 * | |
1400 * | |
1401 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1402 * | preferred-lifetime |
1403 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1404 * | valid-lifetime |
1405 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1406 * . .
1407 * . IAaddr-options .
1408 * . .
1409 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1410 */
1411 free(client6_data.ia_na);
1412 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA);
1413 if (!client6_data.ia_na) {
1414 bb_error_msg("no %s option, ignoring packet", "IA_NA");
1415 continue;
1416 }
1417 if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) {
1418 bb_error_msg("IA_NA option is too short:%d bytes", client6_data.ia_na->len);
1419 continue;
1420 }
1421 iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4,
1422 client6_data.ia_na->data + client6_data.ia_na->len,
1423 D6_OPT_IAADDR
1424 );
1425 if (!iaaddr) {
1426 bb_error_msg("no %s option, ignoring packet", "IAADDR");
1427 continue;
1428 }
1429 if (iaaddr->len < (16 + 4 + 4)) {
1430 bb_error_msg("IAADDR option is too short:%d bytes", iaaddr->len);
1431 continue;
1432 }
1433 /* Note: the address is sufficiently aligned for cast:
1434 * we _copied_ IA-NA, and copy is always well-aligned.
1435 */
1436 requested_ipv6 = (struct in6_addr*) iaaddr->data;
1437 move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4);
1438 lease_seconds = ntohl(lease_seconds);
1439 /* paranoia: must not be too small and not prone to overflows */
1440 if (lease_seconds < 0x10)
1441 lease_seconds = 0x10;
1442/// TODO: check for 0 lease time?
1443 if (lease_seconds >= 0x10000000)
1444 lease_seconds = 0x0fffffff;
1445 /* enter bound state */
1446 timeout = lease_seconds / 2;
1447 bb_info_msg("Lease obtained, lease time %u",
1448 /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1449 d6_run_script(&packet, state == REQUESTING ? "bound" : "renew");
1450
1451 state = BOUND;
1452 change_listen_mode(LISTEN_NONE);
1453 if (opt & OPT_q) { /* quit after lease */
1454 goto ret0;
1455 }
1456 /* future renew failures should not exit (JM) */
1457 opt &= ~OPT_n;
1458#if BB_MMU /* NOMMU case backgrounded earlier */
1459 if (!(opt & OPT_f)) {
1460 client_background();
1461 /* do not background again! */
1462 opt = ((opt & ~OPT_b) | OPT_f);
1463 }
1464#endif
1465 already_waited_sec = 0;
1466 continue; /* back to main loop */
1467 }
1468 continue;
1469 /* case BOUND: - ignore all packets */
1470 /* case RELEASED: - ignore all packets */
1471 }
1472 /* back to main loop */
1473 } /* for (;;) - main loop ends */
1474
1475 ret0:
1476 if (opt & OPT_R) /* release on quit */
1477 perform_d6_release(&srv6_buf, requested_ipv6);
1478 retval = 0;
1479 ret:
1480 /*if (client_config.pidfile) - remove_pidfile has its own check */
1481 remove_pidfile(client_config.pidfile);
1482 return retval;
1483}
diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c
new file mode 100644
index 000000000..79b2946ef
--- /dev/null
+++ b/networking/udhcp/d6_packet.c
@@ -0,0 +1,172 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2011 Denys Vlasenko.
4 *
5 * Licensed under GPLv2, see file LICENSE in this source tree.
6 */
7#include "common.h"
8#include "d6_common.h"
9#include "dhcpd.h"
10#include <netinet/in.h>
11#include <netinet/if_ether.h>
12#include <netpacket/packet.h>
13
14#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
15void FAST_FUNC d6_dump_packet(struct d6_packet *packet)
16{
17 if (dhcp_verbose < 2)
18 return;
19
20 bb_info_msg(
21 " xid %x"
22 , packet->d6_xid32
23 );
24 //*bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0';
25 //bb_info_msg(" chaddr %s", buf);
26}
27#endif
28
29int FAST_FUNC d6_recv_kernel_packet(struct in6_addr *peer_ipv6
30 UNUSED_PARAM
31 , struct d6_packet *packet, int fd)
32{
33 int bytes;
34
35 memset(packet, 0, sizeof(*packet));
36 bytes = safe_read(fd, packet, sizeof(*packet));
37 if (bytes < 0) {
38 log1("Packet read error, ignoring");
39 return bytes; /* returns -1 */
40 }
41
42 if (bytes < offsetof(struct d6_packet, d6_options)) {
43 bb_info_msg("Packet with bad magic, ignoring");
44 return -2;
45 }
46 log1("Received a packet");
47 d6_dump_packet(packet);
48
49 return bytes;
50}
51
52/* Construct a ipv6+udp header for a packet, send packet */
53int FAST_FUNC d6_send_raw_packet(
54 struct d6_packet *d6_pkt, unsigned d6_pkt_size,
55 struct in6_addr *src_ipv6, int source_port,
56 struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp,
57 int ifindex)
58{
59 struct sockaddr_ll dest_sll;
60 struct ip6_udp_d6_packet packet;
61 int fd;
62 int result = -1;
63 const char *msg;
64
65 fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6));
66 if (fd < 0) {
67 msg = "socket(%s)";
68 goto ret_msg;
69 }
70
71 memset(&dest_sll, 0, sizeof(dest_sll));
72 memset(&packet, 0, offsetof(struct ip6_udp_d6_packet, data));
73 packet.data = *d6_pkt; /* struct copy */
74
75 dest_sll.sll_family = AF_PACKET;
76 dest_sll.sll_protocol = htons(ETH_P_IPV6);
77 dest_sll.sll_ifindex = ifindex;
78 dest_sll.sll_halen = 6;
79 memcpy(dest_sll.sll_addr, dest_arp, 6);
80
81 if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) {
82 msg = "bind(%s)";
83 goto ret_close;
84 }
85
86 packet.ip6.ip6_vfc = (6 << 4); /* 4 bits version, top 4 bits of tclass */
87 if (src_ipv6)
88 packet.ip6.ip6_src = *src_ipv6; /* struct copy */
89 packet.ip6.ip6_dst = *dst_ipv6; /* struct copy */
90 packet.udp.source = htons(source_port);
91 packet.udp.dest = htons(dest_port);
92 /* size, excluding IP header: */
93 packet.udp.len = htons(sizeof(struct udphdr) + d6_pkt_size);
94 packet.ip6.ip6_plen = packet.udp.len;
95 /*
96 * Someone was smoking weed (at least) while inventing UDP checksumming:
97 * UDP checksum skips first four bytes of IPv6 header.
98 * 'next header' field should be summed as if it is one more byte
99 * to the right, therefore we write its value (IPPROTO_UDP)
100 * into ip6_hlim, and its 'real' location remains zero-filled for now.
101 */
102 packet.ip6.ip6_hlim = IPPROTO_UDP;
103 packet.udp.check = inet_cksum(
104 (uint16_t *)&packet + 2,
105 offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size
106 );
107 /* fix 'hop limit' and 'next header' after UDP checksumming */
108 packet.ip6.ip6_hlim = 1; /* observed Windows machines to use hlim=1 */
109 packet.ip6.ip6_nxt = IPPROTO_UDP;
110
111 d6_dump_packet(d6_pkt);
112 result = sendto(fd, &packet, offsetof(struct ip6_udp_d6_packet, data) + d6_pkt_size,
113 /*flags:*/ 0,
114 (struct sockaddr *) &dest_sll, sizeof(dest_sll)
115 );
116 msg = "sendto";
117 ret_close:
118 close(fd);
119 if (result < 0) {
120 ret_msg:
121 bb_perror_msg(msg, "PACKET");
122 }
123 return result;
124}
125
126/* Let the kernel do all the work for packet generation */
127int FAST_FUNC d6_send_kernel_packet(
128 struct d6_packet *d6_pkt, unsigned d6_pkt_size,
129 struct in6_addr *src_ipv6, int source_port,
130 struct in6_addr *dst_ipv6, int dest_port)
131{
132 struct sockaddr_in6 sa;
133 int fd;
134 int result = -1;
135 const char *msg;
136
137 fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
138 if (fd < 0) {
139 msg = "socket(%s)";
140 goto ret_msg;
141 }
142 setsockopt_reuseaddr(fd);
143
144 memset(&sa, 0, sizeof(sa));
145 sa.sin6_family = AF_INET6;
146 sa.sin6_port = htons(source_port);
147 sa.sin6_addr = *src_ipv6; /* struct copy */
148 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
149 msg = "bind(%s)";
150 goto ret_close;
151 }
152
153 memset(&sa, 0, sizeof(sa));
154 sa.sin6_family = AF_INET6;
155 sa.sin6_port = htons(dest_port);
156 sa.sin6_addr = *dst_ipv6; /* struct copy */
157 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
158 msg = "connect";
159 goto ret_close;
160 }
161
162 d6_dump_packet(d6_pkt);
163 result = safe_write(fd, d6_pkt, d6_pkt_size);
164 msg = "write";
165 ret_close:
166 close(fd);
167 if (result < 0) {
168 ret_msg:
169 bb_perror_msg(msg, "UDP");
170 }
171 return result;
172}
diff --git a/networking/udhcp/d6_socket.c b/networking/udhcp/d6_socket.c
new file mode 100644
index 000000000..56f69f6a1
--- /dev/null
+++ b/networking/udhcp/d6_socket.c
@@ -0,0 +1,34 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2011 Denys Vlasenko.
4 *
5 * Licensed under GPLv2, see file LICENSE in this source tree.
6 */
7#include "common.h"
8#include "d6_common.h"
9#include <net/if.h>
10
11int FAST_FUNC d6_listen_socket(int port, const char *inf)
12{
13 int fd;
14 struct sockaddr_in6 addr;
15
16 log1("Opening listen socket on *:%d %s", port, inf);
17 fd = xsocket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
18
19 setsockopt_reuseaddr(fd);
20 if (setsockopt_broadcast(fd) == -1)
21 bb_perror_msg_and_die("SO_BROADCAST");
22
23 /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */
24 if (setsockopt_bindtodevice(fd, inf))
25 xfunc_die(); /* warning is already printed */
26
27 memset(&addr, 0, sizeof(addr));
28 addr.sin6_family = AF_INET6;
29 addr.sin6_port = htons(port);
30 /* addr.sin6_addr is all-zeros */
31 xbind(fd, (struct sockaddr *)&addr, sizeof(addr));
32
33 return fd;
34}
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 3d4c397ff..2f2016cd5 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -29,7 +29,7 @@
29#include <netpacket/packet.h> 29#include <netpacket/packet.h>
30#include <linux/filter.h> 30#include <linux/filter.h>
31 31
32/* struct client_config_t client_config is in bb_common_bufsiz1 */ 32/* "struct client_config_t client_config" is in bb_common_bufsiz1 */
33 33
34 34
35#if ENABLE_LONG_OPTS 35#if ENABLE_LONG_OPTS
@@ -46,7 +46,6 @@ static const char udhcpc_longopts[] ALIGN1 =
46 "request\0" Required_argument "r" 46 "request\0" Required_argument "r"
47 "script\0" Required_argument "s" 47 "script\0" Required_argument "s"
48 "timeout\0" Required_argument "T" 48 "timeout\0" Required_argument "T"
49 "version\0" No_argument "v"
50 "retries\0" Required_argument "t" 49 "retries\0" Required_argument "t"
51 "tryagain\0" Required_argument "A" 50 "tryagain\0" Required_argument "A"
52 "syslog\0" No_argument "S" 51 "syslog\0" No_argument "S"
@@ -124,24 +123,6 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
124 return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); 123 return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
125} 124}
126 125
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
145/* really simple implementation, just count the bits */ 126/* really simple implementation, just count the bits */
146static int mton(uint32_t mask) 127static int mton(uint32_t mask)
147{ 128{
@@ -154,6 +135,63 @@ static int mton(uint32_t mask)
154 return i; 135 return i;
155} 136}
156 137
138/* Check if a given label represents a valid DNS label
139 * Return pointer to the first character after the label upon success,
140 * NULL otherwise.
141 * See RFC1035, 2.3.1
142 */
143/* We don't need to be particularly anal. For example, allowing _, hyphen
144 * at the end, or leading and trailing dots would be ok, since it
145 * can't be used for attacks. (Leading hyphen can be, if someone uses
146 * cmd "$hostname"
147 * in the script: then hostname may be treated as an option)
148 */
149static const char *valid_domain_label(const char *label)
150{
151 unsigned char ch;
152 unsigned pos = 0;
153
154 for (;;) {
155 ch = *label;
156 if ((ch|0x20) < 'a' || (ch|0x20) > 'z') {
157 if (pos == 0) {
158 /* label must begin with letter */
159 return NULL;
160 }
161 if (ch < '0' || ch > '9') {
162 if (ch == '\0' || ch == '.')
163 return label;
164 /* DNS allows only '-', but we are more permissive */
165 if (ch != '-' && ch != '_')
166 return NULL;
167 }
168 }
169 label++;
170 pos++;
171 //Do we want this?
172 //if (pos > 63) /* NS_MAXLABEL; labels must be 63 chars or less */
173 // return NULL;
174 }
175}
176
177/* Check if a given name represents a valid DNS name */
178/* See RFC1035, 2.3.1 */
179static int good_hostname(const char *name)
180{
181 //const char *start = name;
182
183 for (;;) {
184 name = valid_domain_label(name);
185 if (!name)
186 return 0;
187 if (!name[0])
188 return 1;
189 //Do we want this?
190 //return ((name - start) < 1025); /* NS_MAXDNAME */
191 name++;
192 }
193}
194
157/* Create "opt_name=opt_value" string */ 195/* Create "opt_name=opt_value" string */
158static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name) 196static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name)
159{ 197{
@@ -206,8 +244,11 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
206 * the case of list of options. 244 * the case of list of options.
207 */ 245 */
208 case OPTION_STRING: 246 case OPTION_STRING:
247 case OPTION_STRING_HOST:
209 memcpy(dest, option, len); 248 memcpy(dest, option, len);
210 dest[len] = '\0'; 249 dest[len] = '\0';
250 if (type == OPTION_STRING_HOST && !good_hostname(dest))
251 safe_strncpy(dest, "bad", len);
211 return ret; 252 return ret;
212 case OPTION_STATIC_ROUTES: { 253 case OPTION_STATIC_ROUTES: {
213 /* Option binary format: 254 /* Option binary format:
@@ -387,6 +428,7 @@ static char **fill_envp(struct dhcp_packet *packet)
387 /* +1 element for each option, +2 for subnet option: */ 428 /* +1 element for each option, +2 for subnet option: */
388 if (packet) { 429 if (packet) {
389 /* note: do not search for "pad" (0) and "end" (255) options */ 430 /* note: do not search for "pad" (0) and "end" (255) options */
431//TODO: change logic to scan packet _once_
390 for (i = 1; i < 255; i++) { 432 for (i = 1; i < 255; i++) {
391 temp = udhcp_get_option(packet, i); 433 temp = udhcp_get_option(packet, i);
392 if (temp) { 434 if (temp) {
@@ -499,9 +541,6 @@ static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
499 char **envp, **curr; 541 char **envp, **curr;
500 char *argv[3]; 542 char *argv[3];
501 543
502 if (client_config.script == NULL)
503 return;
504
505 envp = fill_envp(packet); 544 envp = fill_envp(packet);
506 545
507 /* call script */ 546 /* call script */
@@ -598,6 +637,12 @@ static void add_client_options(struct dhcp_packet *packet)
598// if (client_config.boot_file) 637// if (client_config.boot_file)
599// strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1); 638// strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1);
600 } 639 }
640
641 // This will be needed if we remove -V VENDOR_STR in favor of
642 // -x vendor:VENDOR_STR
643 //if (!udhcp_find_option(packet.options, DHCP_VENDOR))
644 // /* not set, set the default vendor ID */
645 // ...add (DHCP_VENDOR, "udhcp "BB_VER) opt...
601} 646}
602 647
603/* RFC 2131 648/* RFC 2131
@@ -742,7 +787,7 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
742#if ENABLE_FEATURE_UDHCPC_ARPING 787#if ENABLE_FEATURE_UDHCPC_ARPING
743/* Broadcast a DHCP decline message */ 788/* Broadcast a DHCP decline message */
744/* NOINLINE: limit stack usage in caller */ 789/* NOINLINE: limit stack usage in caller */
745static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t requested) 790static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t requested)
746{ 791{
747 struct dhcp_packet packet; 792 struct dhcp_packet packet;
748 793
@@ -751,12 +796,14 @@ static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t request
751 */ 796 */
752 init_packet(&packet, DHCPDECLINE); 797 init_packet(&packet, DHCPDECLINE);
753 798
799#if 0
754 /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client, 800 /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client,
755 * but in case the server is buggy and wants DHCPDECLINE's xid 801 * but in case the server is buggy and wants DHCPDECLINE's xid
756 * to match the xid which started entire handshake, 802 * to match the xid which started entire handshake,
757 * we use the same xid we used in initial DHCPDISCOVER: 803 * we use the same xid we used in initial DHCPDISCOVER:
758 */ 804 */
759 packet.xid = xid; 805 packet.xid = xid;
806#endif
760 /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ 807 /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */
761 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); 808 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
762 809
@@ -794,7 +841,6 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
794 struct ip_udp_dhcp_packet packet; 841 struct ip_udp_dhcp_packet packet;
795 uint16_t check; 842 uint16_t check;
796 843
797 memset(&packet, 0, sizeof(packet));
798 bytes = safe_read(fd, &packet, sizeof(packet)); 844 bytes = safe_read(fd, &packet, sizeof(packet));
799 if (bytes < 0) { 845 if (bytes < 0) {
800 log1("Packet read error, ignoring"); 846 log1("Packet read error, ignoring");
@@ -852,7 +898,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
852 return -2; 898 return -2;
853 } 899 }
854 900
855 log1("Got valid DHCP packet"); 901 log1("Received a packet");
856 udhcp_dump_packet(&packet.data); 902 udhcp_dump_packet(&packet.data);
857 903
858 bytes -= sizeof(packet.ip) + sizeof(packet.udp); 904 bytes -= sizeof(packet.ip) + sizeof(packet.udp);
@@ -1004,7 +1050,7 @@ static void perform_renew(void)
1004 } 1050 }
1005} 1051}
1006 1052
1007static void perform_release(uint32_t requested_ip, uint32_t server_addr) 1053static void perform_release(uint32_t server_addr, uint32_t requested_ip)
1008{ 1054{
1009 char buffer[sizeof("255.255.255.255")]; 1055 char buffer[sizeof("255.255.255.255")];
1010 struct in_addr temp_addr; 1056 struct in_addr temp_addr;
@@ -1053,7 +1099,7 @@ static void client_background(void)
1053//usage:#endif 1099//usage:#endif
1054//usage:#define udhcpc_trivial_usage 1100//usage:#define udhcpc_trivial_usage
1055//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" 1101//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
1056//usage: " [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") 1102//usage: " [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
1057//usage:#define udhcpc_full_usage "\n" 1103//usage:#define udhcpc_full_usage "\n"
1058//usage: IF_LONG_OPTS( 1104//usage: IF_LONG_OPTS(
1059//usage: "\n -i,--interface IFACE Interface to use (default eth0)" 1105//usage: "\n -i,--interface IFACE Interface to use (default eth0)"
@@ -1086,7 +1132,6 @@ static void client_background(void)
1086//usage: "\n -x lease:3600 - option 51 (lease time)" 1132//usage: "\n -x lease:3600 - option 51 (lease time)"
1087//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" 1133//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
1088//usage: "\n -F,--fqdn NAME Ask server to update DNS mapping for NAME" 1134//usage: "\n -F,--fqdn NAME Ask server to update DNS mapping for NAME"
1089//usage: "\n -H,-h,--hostname NAME Send NAME as client hostname (default none)"
1090//usage: "\n -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')" 1135//usage: "\n -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')"
1091//usage: "\n -C,--clientid-none Don't send MAC as client identifier" 1136//usage: "\n -C,--clientid-none Don't send MAC as client identifier"
1092//usage: IF_UDHCP_VERBOSE( 1137//usage: IF_UDHCP_VERBOSE(
@@ -1124,7 +1169,6 @@ static void client_background(void)
1124//usage: "\n -x lease:3600 - option 51 (lease time)" 1169//usage: "\n -x lease:3600 - option 51 (lease time)"
1125//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" 1170//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
1126//usage: "\n -F NAME Ask server to update DNS mapping for NAME" 1171//usage: "\n -F NAME Ask server to update DNS mapping for NAME"
1127//usage: "\n -H,-h NAME Send NAME as client hostname (default none)"
1128//usage: "\n -V VENDOR Vendor identifier (default 'udhcp VERSION')" 1172//usage: "\n -V VENDOR Vendor identifier (default 'udhcp VERSION')"
1129//usage: "\n -C Don't send MAC as client identifier" 1173//usage: "\n -C Don't send MAC as client identifier"
1130//usage: IF_UDHCP_VERBOSE( 1174//usage: IF_UDHCP_VERBOSE(
@@ -1132,8 +1176,8 @@ static void client_background(void)
1132//usage: ) 1176//usage: )
1133//usage: ) 1177//usage: )
1134//usage: "\nSignals:" 1178//usage: "\nSignals:"
1135//usage: "\n USR1 Renew current lease" 1179//usage: "\n USR1 Renew lease"
1136//usage: "\n USR2 Release current lease" 1180//usage: "\n USR2 Release lease"
1137 1181
1138 1182
1139int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1183int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -1150,16 +1194,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1150 int discover_retries = 3; 1194 int discover_retries = 3;
1151 uint32_t server_addr = server_addr; /* for compiler */ 1195 uint32_t server_addr = server_addr; /* for compiler */
1152 uint32_t requested_ip = 0; 1196 uint32_t requested_ip = 0;
1153 uint32_t xid = 0; 1197 uint32_t xid = xid; /* for compiler */
1154 uint32_t lease_seconds = 0; /* can be given as 32-bit quantity */
1155 int packet_num; 1198 int packet_num;
1156 int timeout; /* must be signed */ 1199 int timeout; /* must be signed */
1157 unsigned already_waited_sec; 1200 unsigned already_waited_sec;
1158 unsigned opt; 1201 unsigned opt;
1159 int max_fd; 1202 int max_fd;
1160 int retval; 1203 int retval;
1161 struct timeval tv;
1162 struct dhcp_packet packet;
1163 fd_set rfds; 1204 fd_set rfds;
1164 1205
1165 /* Default options */ 1206 /* Default options */
@@ -1186,9 +1227,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1186 , &list_x 1227 , &list_x
1187 IF_FEATURE_UDHCP_PORT(, &str_P) 1228 IF_FEATURE_UDHCP_PORT(, &str_P)
1188 IF_UDHCP_VERBOSE(, &dhcp_verbose) 1229 IF_UDHCP_VERBOSE(, &dhcp_verbose)
1189 ); 1230 );
1190 if (opt & (OPT_h|OPT_H)) 1231 if (opt & (OPT_h|OPT_H)) {
1232 //msg added 2011-11
1233 bb_error_msg("option -h NAME is deprecated, use -x hostname:NAME");
1191 client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); 1234 client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
1235 }
1192 if (opt & OPT_F) { 1236 if (opt & OPT_F) {
1193 /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */ 1237 /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */
1194 client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3); 1238 client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
@@ -1249,8 +1293,16 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1249 clientid_mac_ptr = client_config.clientid + OPT_DATA+1; 1293 clientid_mac_ptr = client_config.clientid + OPT_DATA+1;
1250 memcpy(clientid_mac_ptr, client_config.client_mac, 6); 1294 memcpy(clientid_mac_ptr, client_config.client_mac, 6);
1251 } 1295 }
1252 if (str_V[0] != '\0') 1296 if (str_V[0] != '\0') {
1297 // can drop -V, str_V, client_config.vendorclass,
1298 // but need to add "vendor" to the list of recognized
1299 // string opts for this to work;
1300 // and need to tweak add_client_options() too...
1301 // ...so the question is, should we?
1302 //bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR");
1253 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); 1303 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
1304 }
1305
1254#if !BB_MMU 1306#if !BB_MMU
1255 /* on NOMMU reexec (i.e., background) early */ 1307 /* on NOMMU reexec (i.e., background) early */
1256 if (!(opt & OPT_f)) { 1308 if (!(opt & OPT_f)) {
@@ -1288,6 +1340,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1288 * "continue" statements in code below jump to the top of the loop. 1340 * "continue" statements in code below jump to the top of the loop.
1289 */ 1341 */
1290 for (;;) { 1342 for (;;) {
1343 struct timeval tv;
1344 struct dhcp_packet packet;
1291 /* silence "uninitialized!" warning */ 1345 /* silence "uninitialized!" warning */
1292 unsigned timestamp_before_wait = timestamp_before_wait; 1346 unsigned timestamp_before_wait = timestamp_before_wait;
1293 1347
@@ -1335,7 +1389,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1335 NULL, 1389 NULL,
1336 client_config.client_mac) 1390 client_config.client_mac)
1337 ) { 1391 ) {
1338 return 1; /* iface is gone? */ 1392 goto ret0; /* iface is gone? */
1339 } 1393 }
1340 if (clientid_mac_ptr) 1394 if (clientid_mac_ptr)
1341 memcpy(clientid_mac_ptr, client_config.client_mac, 6); 1395 memcpy(clientid_mac_ptr, client_config.client_mac, 6);
@@ -1472,13 +1526,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1472 timeout = 0; 1526 timeout = 0;
1473 continue; 1527 continue;
1474 case SIGUSR2: 1528 case SIGUSR2:
1475 perform_release(requested_ip, server_addr); 1529 perform_release(server_addr, requested_ip);
1476 timeout = INT_MAX; 1530 timeout = INT_MAX;
1477 continue; 1531 continue;
1478 case SIGTERM: 1532 case SIGTERM:
1479 bb_info_msg("Received SIGTERM"); 1533 bb_info_msg("Received SIGTERM");
1480 if (opt & OPT_R) /* release on quit */
1481 perform_release(requested_ip, server_addr);
1482 goto ret0; 1534 goto ret0;
1483 } 1535 }
1484 1536
@@ -1531,7 +1583,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1531 1583
1532 switch (state) { 1584 switch (state) {
1533 case INIT_SELECTING: 1585 case INIT_SELECTING:
1534 /* Must be a DHCPOFFER to one of our xid's */ 1586 /* Must be a DHCPOFFER */
1535 if (*message == DHCPOFFER) { 1587 if (*message == DHCPOFFER) {
1536/* What exactly is server's IP? There are several values. 1588/* What exactly is server's IP? There are several values.
1537 * Example DHCP offer captured with tchdump: 1589 * Example DHCP offer captured with tchdump:
@@ -1575,6 +1627,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1575 case RENEW_REQUESTED: 1627 case RENEW_REQUESTED:
1576 case REBINDING: 1628 case REBINDING:
1577 if (*message == DHCPACK) { 1629 if (*message == DHCPACK) {
1630 uint32_t lease_seconds;
1631 struct in_addr temp_addr;
1632
1578 temp = udhcp_get_option(&packet, DHCP_LEASE_TIME); 1633 temp = udhcp_get_option(&packet, DHCP_LEASE_TIME);
1579 if (!temp) { 1634 if (!temp) {
1580 bb_error_msg("no lease time with ACK, using 1 hour lease"); 1635 bb_error_msg("no lease time with ACK, using 1 hour lease");
@@ -1583,9 +1638,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1583 /* it IS unaligned sometimes, don't "optimize" */ 1638 /* it IS unaligned sometimes, don't "optimize" */
1584 move_from_unaligned32(lease_seconds, temp); 1639 move_from_unaligned32(lease_seconds, temp);
1585 lease_seconds = ntohl(lease_seconds); 1640 lease_seconds = ntohl(lease_seconds);
1586 lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */ 1641 /* paranoia: must not be too small and not prone to overflows */
1587 if (lease_seconds < 10) /* and not too small */ 1642 if (lease_seconds < 0x10)
1588 lease_seconds = 10; 1643 lease_seconds = 0x10;
1644 if (lease_seconds >= 0x10000000)
1645 lease_seconds = 0x0fffffff;
1589 } 1646 }
1590#if ENABLE_FEATURE_UDHCPC_ARPING 1647#if ENABLE_FEATURE_UDHCPC_ARPING
1591 if (opt & OPT_a) { 1648 if (opt & OPT_a) {
@@ -1606,7 +1663,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1606 ) { 1663 ) {
1607 bb_info_msg("Offered address is in use " 1664 bb_info_msg("Offered address is in use "
1608 "(got ARP reply), declining"); 1665 "(got ARP reply), declining");
1609 send_decline(xid, server_addr, packet.yiaddr); 1666 send_decline(/*xid,*/ server_addr, packet.yiaddr);
1610 1667
1611 if (state != REQUESTING) 1668 if (state != REQUESTING)
1612 udhcp_run_script(NULL, "deconfig"); 1669 udhcp_run_script(NULL, "deconfig");
@@ -1623,20 +1680,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1623#endif 1680#endif
1624 /* enter bound state */ 1681 /* enter bound state */
1625 timeout = lease_seconds / 2; 1682 timeout = lease_seconds / 2;
1626 { 1683 temp_addr.s_addr = packet.yiaddr;
1627 struct in_addr temp_addr; 1684 bb_info_msg("Lease of %s obtained, lease time %u",
1628 temp_addr.s_addr = packet.yiaddr; 1685 inet_ntoa(temp_addr), (unsigned)lease_seconds);
1629 bb_info_msg("Lease of %s obtained, lease time %u",
1630 inet_ntoa(temp_addr), (unsigned)lease_seconds);
1631 }
1632 requested_ip = packet.yiaddr; 1686 requested_ip = packet.yiaddr;
1633 udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew"); 1687 udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew");
1634 1688
1635 state = BOUND; 1689 state = BOUND;
1636 change_listen_mode(LISTEN_NONE); 1690 change_listen_mode(LISTEN_NONE);
1637 if (opt & OPT_q) { /* quit after lease */ 1691 if (opt & OPT_q) { /* quit after lease */
1638 if (opt & OPT_R) /* release on quit */
1639 perform_release(requested_ip, server_addr);
1640 goto ret0; 1692 goto ret0;
1641 } 1693 }
1642 /* future renew failures should not exit (JM) */ 1694 /* future renew failures should not exit (JM) */
@@ -1648,6 +1700,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1648 opt = ((opt & ~OPT_b) | OPT_f); 1700 opt = ((opt & ~OPT_b) | OPT_f);
1649 } 1701 }
1650#endif 1702#endif
1703 /* make future renew packets use different xid */
1704 /* xid = random_xid(); ...but why bother? */
1651 already_waited_sec = 0; 1705 already_waited_sec = 0;
1652 continue; /* back to main loop */ 1706 continue; /* back to main loop */
1653 } 1707 }
@@ -1674,6 +1728,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1674 } /* for (;;) - main loop ends */ 1728 } /* for (;;) - main loop ends */
1675 1729
1676 ret0: 1730 ret0:
1731 if (opt & OPT_R) /* release on quit */
1732 perform_release(server_addr, requested_ip);
1677 retval = 0; 1733 retval = 0;
1678 ret: 1734 ret:
1679 /*if (client_config.pidfile) - remove_pidfile has its own check */ 1735 /*if (client_config.pidfile) - remove_pidfile has its own check */
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c
index 4d5ff0676..33c9585cf 100644
--- a/networking/udhcp/packet.c
+++ b/networking/udhcp/packet.c
@@ -81,7 +81,6 @@ void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet)
81int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) 81int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd)
82{ 82{
83 int bytes; 83 int bytes;
84 unsigned char *vendor;
85 84
86 memset(packet, 0, sizeof(*packet)); 85 memset(packet, 0, sizeof(*packet));
87 bytes = safe_read(fd, packet, sizeof(*packet)); 86 bytes = safe_read(fd, packet, sizeof(*packet));
@@ -90,42 +89,15 @@ int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd)
90 return bytes; /* returns -1 */ 89 return bytes; /* returns -1 */
91 } 90 }
92 91
93 if (packet->cookie != htonl(DHCP_MAGIC)) { 92 if (bytes < offsetof(struct dhcp_packet, options)
93 || packet->cookie != htonl(DHCP_MAGIC)
94 ) {
94 bb_info_msg("Packet with bad magic, ignoring"); 95 bb_info_msg("Packet with bad magic, ignoring");
95 return -2; 96 return -2;
96 } 97 }
97 log1("Received a packet"); 98 log1("Received a packet");
98 udhcp_dump_packet(packet); 99 udhcp_dump_packet(packet);
99 100
100 if (packet->op == BOOTREQUEST) {
101 vendor = udhcp_get_option(packet, DHCP_VENDOR);
102 if (vendor) {
103#if 0
104 static const char broken_vendors[][8] = {
105 "MSFT 98",
106 ""
107 };
108 int i;
109 for (i = 0; broken_vendors[i][0]; i++) {
110 if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)strlen(broken_vendors[i])
111 && strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - OPT_DATA]) == 0
112 ) {
113 log1("Broken client (%s), forcing broadcast replies",
114 broken_vendors[i]);
115 packet->flags |= htons(BROADCAST_FLAG);
116 }
117 }
118#else
119 if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)(sizeof("MSFT 98")-1)
120 && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0
121 ) {
122 log1("Broken client (%s), forcing broadcast replies", "MSFT 98");
123 packet->flags |= htons(BROADCAST_FLAG);
124 }
125#endif
126 }
127 }
128
129 return bytes; 101 return bytes;
130} 102}
131 103
@@ -210,7 +182,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
210 uint32_t source_nip, int source_port, 182 uint32_t source_nip, int source_port,
211 uint32_t dest_nip, int dest_port) 183 uint32_t dest_nip, int dest_port)
212{ 184{
213 struct sockaddr_in client; 185 struct sockaddr_in sa;
214 unsigned padding; 186 unsigned padding;
215 int fd; 187 int fd;
216 int result = -1; 188 int result = -1;
@@ -223,26 +195,25 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
223 } 195 }
224 setsockopt_reuseaddr(fd); 196 setsockopt_reuseaddr(fd);
225 197
226 memset(&client, 0, sizeof(client)); 198 memset(&sa, 0, sizeof(sa));
227 client.sin_family = AF_INET; 199 sa.sin_family = AF_INET;
228 client.sin_port = htons(source_port); 200 sa.sin_port = htons(source_port);
229 client.sin_addr.s_addr = source_nip; 201 sa.sin_addr.s_addr = source_nip;
230 if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { 202 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
231 msg = "bind(%s)"; 203 msg = "bind(%s)";
232 goto ret_close; 204 goto ret_close;
233 } 205 }
234 206
235 memset(&client, 0, sizeof(client)); 207 memset(&sa, 0, sizeof(sa));
236 client.sin_family = AF_INET; 208 sa.sin_family = AF_INET;
237 client.sin_port = htons(dest_port); 209 sa.sin_port = htons(dest_port);
238 client.sin_addr.s_addr = dest_nip; 210 sa.sin_addr.s_addr = dest_nip;
239 if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { 211 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
240 msg = "connect"; 212 msg = "connect";
241 goto ret_close; 213 goto ret_close;
242 } 214 }
243 215
244 udhcp_dump_packet(dhcp_pkt); 216 udhcp_dump_packet(dhcp_pkt);
245
246 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options); 217 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options);
247 result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding); 218 result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding);
248 msg = "write"; 219 msg = "write";
diff --git a/networking/vconfig.c b/networking/vconfig.c
index 48b45d9af..924b2f009 100644
--- a/networking/vconfig.c
+++ b/networking/vconfig.c
@@ -13,12 +13,12 @@
13//usage: "COMMAND [OPTIONS]" 13//usage: "COMMAND [OPTIONS]"
14//usage:#define vconfig_full_usage "\n\n" 14//usage:#define vconfig_full_usage "\n\n"
15//usage: "Create and remove virtual ethernet devices\n" 15//usage: "Create and remove virtual ethernet devices\n"
16//usage: "\n add [interface-name] [vlan_id]" 16//usage: "\n add IFACE VLAN_ID"
17//usage: "\n rem [vlan-name]" 17//usage: "\n rem VLAN_NAME"
18//usage: "\n set_flag [interface-name] [flag-num] [0 | 1]" 18//usage: "\n set_flag IFACE 0|1 VLAN_QOS"
19//usage: "\n set_egress_map [vlan-name] [skb_priority] [vlan_qos]" 19//usage: "\n set_egress_map VLAN_NAME SKB_PRIO VLAN_QOS"
20//usage: "\n set_ingress_map [vlan-name] [skb_priority] [vlan_qos]" 20//usage: "\n set_ingress_map VLAN_NAME SKB_PRIO VLAN_QOS"
21//usage: "\n set_name_type [name-type]" 21//usage: "\n set_name_type NAME_TYPE"
22 22
23#include "libbb.h" 23#include "libbb.h"
24#include <net/if.h> 24#include <net/if.h>
@@ -66,58 +66,40 @@ struct vlan_ioctl_args {
66 * The return value is the last data entry for the matching string. */ 66 * The return value is the last data entry for the matching string. */
67static const char *xfind_str(const char *table, const char *str) 67static const char *xfind_str(const char *table, const char *str)
68{ 68{
69 while (strcasecmp(str, table+1) != 0) { 69 while (strcasecmp(str, table + 1) != 0) {
70 table += table[0]; 70 if (!table[0])
71 if (!*table) {
72 bb_show_usage(); 71 bb_show_usage();
73 } 72 table += table[0];
74 } 73 }
75 return table - 1; 74 return table - 1;
76} 75}
77 76
78static const char cmds[] ALIGN1 = { 77static const char cmds[] ALIGN1 = {
79 4, ADD_VLAN_CMD, 7, 78 4, ADD_VLAN_CMD, 7,
80 'a', 'd', 'd', 0, 79 'a','d','d',0,
81 3, DEL_VLAN_CMD, 7, 80 3, DEL_VLAN_CMD, 7,
82 'r', 'e', 'm', 0, 81 'r','e','m',0,
83 3, SET_VLAN_NAME_TYPE_CMD, 17, 82 3, SET_VLAN_NAME_TYPE_CMD, 17,
84 's', 'e', 't', '_', 83 's','e','t','_','n','a','m','e','_','t','y','p','e',0,
85 'n', 'a', 'm', 'e', '_',
86 't', 'y', 'p', 'e', 0,
87 5, SET_VLAN_FLAG_CMD, 12, 84 5, SET_VLAN_FLAG_CMD, 12,
88 's', 'e', 't', '_', 85 's','e','t','_','f','l','a','g',0,
89 'f', 'l', 'a', 'g', 0,
90 5, SET_VLAN_EGRESS_PRIORITY_CMD, 18, 86 5, SET_VLAN_EGRESS_PRIORITY_CMD, 18,
91 's', 'e', 't', '_', 87 's','e','t','_','e','g','r','e','s','s','_','m','a','p',0,
92 'e', 'g', 'r', 'e', 's', 's', '_', 88 5, SET_VLAN_INGRESS_PRIORITY_CMD, 0,
93 'm', 'a', 'p', 0, 89 's','e','t','_','i','n','g','r','e','s','s','_','m','a','p',0,
94 5, SET_VLAN_INGRESS_PRIORITY_CMD, 16,
95 's', 'e', 't', '_',
96 'i', 'n', 'g', 'r', 'e', 's', 's', '_',
97 'm', 'a', 'p', 0,
98}; 90};
99 91
100static const char name_types[] ALIGN1 = { 92static const char name_types[] ALIGN1 = {
101 VLAN_NAME_TYPE_PLUS_VID, 16, 93 VLAN_NAME_TYPE_PLUS_VID, 16,
102 'V', 'L', 'A', 'N', 94 'V','L','A','N','_','P','L','U','S','_','V','I','D',0,
103 '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D',
104 0,
105 VLAN_NAME_TYPE_PLUS_VID_NO_PAD, 22, 95 VLAN_NAME_TYPE_PLUS_VID_NO_PAD, 22,
106 'V', 'L', 'A', 'N', 96 'V','L','A','N','_','P','L','U','S','_','V','I','D','_','N','O','_','P','A','D',0,
107 '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D',
108 '_', 'N', 'O', '_', 'P', 'A', 'D', 0,
109 VLAN_NAME_TYPE_RAW_PLUS_VID, 15, 97 VLAN_NAME_TYPE_RAW_PLUS_VID, 15,
110 'D', 'E', 'V', 98 'D','E','V','_','P','L','U','S','_','V','I','D',0,
111 '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', 99 VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, 0,
112 0, 100 'D','E','V','_','P','L','U','S','_','V','I','D','_','N','O','_','P','A','D',0,
113 VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, 20,
114 'D', 'E', 'V',
115 '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D',
116 '_', 'N', 'O', '_', 'P', 'A', 'D', 0,
117}; 101};
118 102
119static const char conf_file_name[] ALIGN1 = "/proc/net/vlan/config";
120
121int vconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 103int vconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
122int vconfig_main(int argc, char **argv) 104int vconfig_main(int argc, char **argv)
123{ 105{
@@ -125,25 +107,19 @@ int vconfig_main(int argc, char **argv)
125 const char *p; 107 const char *p;
126 int fd; 108 int fd;
127 109
128 if (argc < 3) {
129 bb_show_usage();
130 }
131
132 /* Don't bother closing the filedes. It will be closed on cleanup. */
133 /* Will die if 802.1q is not present */
134 xopen(conf_file_name, O_RDONLY);
135
136 memset(&ifr, 0, sizeof(ifr)); 110 memset(&ifr, 0, sizeof(ifr));
137 111
138 ++argv; 112 ++argv;
139 p = xfind_str(cmds+2, *argv); 113 if (!argv[0])
114 bb_show_usage();
115 p = xfind_str(cmds + 2, argv[0]);
140 ifr.cmd = *p; 116 ifr.cmd = *p;
141 if (argc != p[-1]) { 117 if (argc != p[-1])
142 bb_show_usage(); 118 bb_show_usage();
143 }
144 119
145 if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) { /* set_name_type */ 120 if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) {
146 ifr.u.name_type = *xfind_str(name_types+1, argv[1]); 121 /* set_name_type */
122 ifr.u.name_type = *xfind_str(name_types + 1, argv[1]);
147 } else { 123 } else {
148 strncpy_IFNAMSIZ(ifr.device1, argv[1]); 124 strncpy_IFNAMSIZ(ifr.device1, argv[1]);
149 p = argv[2]; 125 p = argv[2];
@@ -152,22 +128,26 @@ int vconfig_main(int argc, char **argv)
152 * since ifr.u.flag, ifr.u.VID, and ifr.u.skb_priority are all same-sized 128 * since ifr.u.flag, ifr.u.VID, and ifr.u.skb_priority are all same-sized
153 * (unsigned) int members of a unions. But because of the range checking, 129 * (unsigned) int members of a unions. But because of the range checking,
154 * doing so wouldn't save that much space and would also make maintainence 130 * doing so wouldn't save that much space and would also make maintainence
155 * more of a pain. */ 131 * more of a pain.
156 if (ifr.cmd == SET_VLAN_FLAG_CMD) { /* set_flag */ 132 */
157 ifr.u.flag = xatoul_range(p, 0, 1); 133 if (ifr.cmd == SET_VLAN_FLAG_CMD) {
134 /* set_flag */
135 ifr.u.flag = xatou_range(p, 0, 1);
158 /* DM: in order to set reorder header, qos must be set */ 136 /* DM: in order to set reorder header, qos must be set */
159 ifr.vlan_qos = xatoul_range(argv[3], 0, 7); 137 ifr.vlan_qos = xatou_range(argv[3], 0, 7);
160 } else if (ifr.cmd == ADD_VLAN_CMD) { /* add */ 138 } else if (ifr.cmd == ADD_VLAN_CMD) {
161 ifr.u.VID = xatoul_range(p, 0, VLAN_GROUP_ARRAY_LEN-1); 139 /* add */
162 } else if (ifr.cmd != DEL_VLAN_CMD) { /* set_{egress|ingress}_map */ 140 ifr.u.VID = xatou_range(p, 0, VLAN_GROUP_ARRAY_LEN - 1);
141 } else if (ifr.cmd != DEL_VLAN_CMD) {
142 /* set_{egress|ingress}_map */
163 ifr.u.skb_priority = xatou(p); 143 ifr.u.skb_priority = xatou(p);
164 ifr.vlan_qos = xatoul_range(argv[3], 0, 7); 144 ifr.vlan_qos = xatou_range(argv[3], 0, 7);
165 } 145 }
166 } 146 }
167 147
168 fd = xsocket(AF_INET, SOCK_STREAM, 0); 148 fd = xsocket(AF_INET, SOCK_STREAM, 0);
169 ioctl_or_perror_and_die(fd, SIOCSIFVLAN, &ifr, 149 ioctl_or_perror_and_die(fd, SIOCSIFVLAN, &ifr,
170 "ioctl error for %s", *argv); 150 "ioctl error for %s", argv[0]);
171 151
172 return 0; 152 return 0;
173} 153}
diff --git a/networking/wget.c b/networking/wget.c
index 4dd42de9d..ea46d1795 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -557,6 +557,7 @@ static void download_one_url(const char *url)
557 FILE *dfp; /* socket to ftp server (data) */ 557 FILE *dfp; /* socket to ftp server (data) */
558 char *proxy = NULL; 558 char *proxy = NULL;
559 char *fname_out_alloc; 559 char *fname_out_alloc;
560 char *redirected_path = NULL;
560 struct host_info server; 561 struct host_info server;
561 struct host_info target; 562 struct host_info target;
562 563
@@ -793,8 +794,8 @@ However, in real world it was observed that some web servers
793 bb_error_msg_and_die("too many redirections"); 794 bb_error_msg_and_die("too many redirections");
794 fclose(sfp); 795 fclose(sfp);
795 if (str[0] == '/') { 796 if (str[0] == '/') {
796 free(target.allocated); 797 free(redirected_path);
797 target.path = target.allocated = xstrdup(str+1); 798 target.path = redirected_path = xstrdup(str+1);
798 /* lsa stays the same: it's on the same server */ 799 /* lsa stays the same: it's on the same server */
799 } else { 800 } else {
800 parse_url(str, &target); 801 parse_url(str, &target);
@@ -849,6 +850,7 @@ However, in real world it was observed that some web servers
849 free(server.allocated); 850 free(server.allocated);
850 free(target.allocated); 851 free(target.allocated);
851 free(fname_out_alloc); 852 free(fname_out_alloc);
853 free(redirected_path);
852} 854}
853 855
854int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 856int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
diff --git a/procps/kill.c b/procps/kill.c
index 8aa0eb3e2..0b170fa3d 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -167,13 +167,15 @@ int kill_main(int argc, char **argv)
167 /* Stop all processes */ 167 /* Stop all processes */
168 kill(-1, SIGSTOP); 168 kill(-1, SIGSTOP);
169 /* Signal all processes except those in our session */ 169 /* Signal all processes except those in our session */
170 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) { 170 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID)) != NULL) {
171 int i; 171 int i;
172 172
173 if (p->sid == (unsigned)sid 173 if (p->sid == (unsigned)sid
174 || p->pid == (unsigned)pid 174 || p->pid == (unsigned)pid
175 || p->pid == 1) 175 || p->pid == 1
176 ) {
176 continue; 177 continue;
178 }
177 179
178 /* All remaining args must be -o PID options. 180 /* All remaining args must be -o PID options.
179 * Check p->pid against them. */ 181 * Check p->pid against them. */
@@ -257,9 +259,10 @@ int kill_main(int argc, char **argv)
257 pid = bb_strtoi(arg, &end, 10); 259 pid = bb_strtoi(arg, &end, 10);
258 if (errno && (errno != EINVAL || *end != ' ')) { 260 if (errno && (errno != EINVAL || *end != ' ')) {
259 bb_error_msg("invalid number '%s'", arg); 261 bb_error_msg("invalid number '%s'", arg);
260 *end = '\0';
261 errors++; 262 errors++;
262 } else if (kill(pid, signo) != 0) { 263 break;
264 }
265 if (kill(pid, signo) != 0) {
263 bb_perror_msg("can't kill pid %d", (int)pid); 266 bb_perror_msg("can't kill pid %d", (int)pid);
264 errors++; 267 errors++;
265 } 268 }
diff --git a/procps/sysctl.c b/procps/sysctl.c
index cb3b6a25a..5296d0f58 100644
--- a/procps/sysctl.c
+++ b/procps/sysctl.c
@@ -224,7 +224,7 @@ static int sysctl_handle_preload_file(const char *filename)
224 parser = config_open(filename); 224 parser = config_open(filename);
225 /* Must do it _after_ config_open(): */ 225 /* Must do it _after_ config_open(): */
226 xchdir("/proc/sys"); 226 xchdir("/proc/sys");
227 /* xchroot(".") - if you are paranoid */ 227 /* xchroot("/proc/sys") - if you are paranoid */
228 228
229//TODO: ';' is comment char too 229//TODO: ';' is comment char too
230//TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value 230//TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value
@@ -260,7 +260,7 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv)
260 return sysctl_handle_preload_file(*argv ? *argv : "/etc/sysctl.conf"); 260 return sysctl_handle_preload_file(*argv ? *argv : "/etc/sysctl.conf");
261 } 261 }
262 xchdir("/proc/sys"); 262 xchdir("/proc/sys");
263 /* xchroot(".") - if you are paranoid */ 263 /* xchroot("/proc/sys") - if you are paranoid */
264 if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) { 264 if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) {
265 return sysctl_act_recursive("."); 265 return sysctl_act_recursive(".");
266 } 266 }
diff --git a/runit/chpst.c b/runit/chpst.c
index 9b8c99bdd..ac296babf 100644
--- a/runit/chpst.c
+++ b/runit/chpst.c
@@ -417,8 +417,7 @@ int chpst_main(int argc UNUSED_PARAM, char **argv)
417 } 417 }
418 418
419 if (opt & OPT_root) { 419 if (opt & OPT_root) {
420 xchdir(root); 420 xchroot(root);
421 xchroot(".");
422 } 421 }
423 422
424 if (opt & OPT_u) { 423 if (opt & OPT_u) {
diff --git a/scripts/defconfig.tig b/scripts/defconfig.tig
index 2de0d8041..444b31145 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.20.0.git 3# Busybox version: 1.20.0.git
4# Fri Mar 23 10:48:09 2012 4# Fri Mar 23 12:07:27 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
@@ -65,7 +65,10 @@ CONFIG_BUSYBOX_EXEC_PATH=""
65# CONFIG_FEATURE_SHARED_BUSYBOX is not set 65# CONFIG_FEATURE_SHARED_BUSYBOX is not set
66# CONFIG_LFS is not set 66# CONFIG_LFS is not set
67CONFIG_CROSS_COMPILER_PREFIX="i686-pc-mingw32-" 67CONFIG_CROSS_COMPILER_PREFIX="i686-pc-mingw32-"
68CONFIG_SYSROOT=""
68CONFIG_EXTRA_CFLAGS="-g -O0" 69CONFIG_EXTRA_CFLAGS="-g -O0"
70CONFIG_EXTRA_LDFLAGS=""
71CONFIG_EXTRA_LDLIBS=""
69 72
70# 73#
71# Debugging Options 74# Debugging Options
@@ -184,6 +187,7 @@ CONFIG_FEATURE_DATE_COMPAT=y
184CONFIG_TEST=y 187CONFIG_TEST=y
185CONFIG_FEATURE_TEST_64=y 188CONFIG_FEATURE_TEST_64=y
186CONFIG_TOUCH=y 189CONFIG_TOUCH=y
190# CONFIG_FEATURE_TOUCH_SUSV3 is not set
187CONFIG_TR=y 191CONFIG_TR=y
188CONFIG_FEATURE_TR_CLASSES=y 192CONFIG_FEATURE_TR_CLASSES=y
189CONFIG_FEATURE_TR_EQUIV=y 193CONFIG_FEATURE_TR_EQUIV=y
@@ -471,6 +475,7 @@ CONFIG_LAST_SYSTEM_ID=0
471# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set 475# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
472# CONFIG_CRYPTPW is not set 476# CONFIG_CRYPTPW is not set
473# CONFIG_CHPASSWD is not set 477# CONFIG_CHPASSWD is not set
478CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
474# CONFIG_SU is not set 479# CONFIG_SU is not set
475# CONFIG_FEATURE_SU_SYSLOG is not set 480# CONFIG_FEATURE_SU_SYSLOG is not set
476# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set 481# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
@@ -825,6 +830,7 @@ CONFIG_IFUPDOWN_IFSTATE_PATH=""
825# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set 830# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
826# CONFIG_TUNCTL is not set 831# CONFIG_TUNCTL is not set
827# CONFIG_FEATURE_TUNCTL_UG is not set 832# CONFIG_FEATURE_TUNCTL_UG is not set
833# CONFIG_UDHCPC6 is not set
828# CONFIG_UDHCPD is not set 834# CONFIG_UDHCPD is not set
829# CONFIG_DHCPRELAY is not set 835# CONFIG_DHCPRELAY is not set
830# CONFIG_DUMPLEASES is not set 836# CONFIG_DUMPLEASES is not set
diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh
index c42fe9fbb..0989b2fe5 100755
--- a/scripts/gen_build_files.sh
+++ b/scripts/gen_build_files.sh
@@ -52,14 +52,17 @@ sed -n 's@^//applet:@@p' "$srctree"/*/*.c "$srctree"/*/*/*.c \
52# We add line continuation backslash after each line, 52# We add line continuation backslash after each line,
53# and insert empty line before each line which doesn't start 53# and insert empty line before each line which doesn't start
54# with space or tab 54# with space or tab
55sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\@p' "$srctree"/*/*.c "$srctree"/*/*/*.c \ 55sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\@p' \
56 "$srctree"/*/*.c "$srctree"/*/*/*.c \
56| generate \ 57| generate \
57 "$srctree/include/usage.src.h" \ 58 "$srctree/include/usage.src.h" \
58 "include/usage.h" \ 59 "include/usage.h" \
59 "/* DO NOT EDIT. This file is generated from usage.src.h */" 60 "/* DO NOT EDIT. This file is generated from usage.src.h */"
60 61
61# (Re)generate */Kbuild and */Config.in 62# (Re)generate */Kbuild and */Config.in
62{ cd -- "$srctree" && find . -type d; } | while read -r d; do 63# We skip .dotdirs - makes git/svn/etc users happier
64{ cd -- "$srctree" && find . -type d -not '(' -name '.?*' -prune ')'; } \
65| while read -r d; do
63 d="${d#./}" 66 d="${d#./}"
64 67
65 src="$srctree/$d/Kbuild.src" 68 src="$srctree/$d/Kbuild.src"
diff --git a/shell/ash.c b/shell/ash.c
index a79099bc5..065678ea5 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -7794,6 +7794,12 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **
7794 * 7794 *
7795 * That is, do not use $SHELL, user's shell, or /bin/sh; 7795 * That is, do not use $SHELL, user's shell, or /bin/sh;
7796 * just call ourselves. 7796 * just call ourselves.
7797 *
7798 * Note that bash reads ~80 chars of the file, and if it sees
7799 * a zero byte before it sees newline, it doesn't try to
7800 * interpret it, but fails with "cannot execute binary file"
7801 * message and exit code 126. For one, this prevents attempts
7802 * to interpret foreign ELF binaries as shell scripts.
7797 */ 7803 */
7798 char **ap; 7804 char **ap;
7799 char **new; 7805 char **new;
@@ -7824,9 +7830,7 @@ shellexec(char **argv, const char *path, int idx)
7824 int e; 7830 int e;
7825 char **envp; 7831 char **envp;
7826 int exerrno; 7832 int exerrno;
7827#if ENABLE_FEATURE_SH_STANDALONE 7833 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7828 int applet_no = -1;
7829#endif
7830 7834
7831 clearredir(/*drop:*/ 1); 7835 clearredir(/*drop:*/ 1);
7832 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 7836 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
@@ -7836,8 +7840,16 @@ shellexec(char **argv, const char *path, int idx)
7836#endif 7840#endif
7837 ) { 7841 ) {
7838 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp); 7842 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
7843 if (applet_no >= 0) {
7844 /* We tried execing ourself, but it didn't work.
7845 * Maybe /proc/self/exe doesn't exist?
7846 * Try $PATH search.
7847 */
7848 goto try_PATH;
7849 }
7839 e = errno; 7850 e = errno;
7840 } else { 7851 } else {
7852 try_PATH:
7841 e = ENOENT; 7853 e = ENOENT;
7842 while ((cmdname = path_advance(&path, argv[0])) != NULL) { 7854 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
7843 if (--idx < 0 && pathopt == NULL) { 7855 if (--idx < 0 && pathopt == NULL) {
diff --git a/shell/cttyhack.c b/shell/cttyhack.c
index 6ff867413..f9b59c263 100644
--- a/shell/cttyhack.c
+++ b/shell/cttyhack.c
@@ -123,15 +123,22 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv)
123 * TIOCGSERIAL check, which assumes that all 123 * TIOCGSERIAL check, which assumes that all
124 * serial lines follow /dev/ttySn convention - 124 * serial lines follow /dev/ttySn convention -
125 * which is not always the case. 125 * which is not always the case.
126 * Therefore, we use this methos first: 126 * Therefore, we use this method first:
127 */ 127 */
128 int s = open_read_close("/sys/class/tty/console/active", 128 int s = open_read_close("/sys/class/tty/console/active",
129 console + 5, sizeof(console) - 5); 129 console + 5, sizeof(console) - 5);
130 if (s > 0) { 130 if (s > 0) {
131 /* found active console via sysfs (Linux 2.6.38+) 131 char *last;
132 * sysfs string looks like "ttyS0\n" so zap the newline: 132 /* Found active console via sysfs (Linux 2.6.38+).
133 * It looks like "[tty0 ]ttyS0\n" so zap the newline:
133 */ 134 */
134 console[4 + s] = '\0'; 135 console[4 + s] = '\0';
136 /* If there are multiple consoles,
137 * take the last one:
138 */
139 last = strrchr(console + 5, ' ');
140 if (last)
141 overlapping_strcpy(console + 5, last + 1);
135 break; 142 break;
136 } 143 }
137 144
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 4329ca05c..0ffe21e0b 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -138,7 +138,13 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
138 old_tty = tty; 138 old_tty = tty;
139 if (nchars) { 139 if (nchars) {
140 tty.c_lflag &= ~ICANON; 140 tty.c_lflag &= ~ICANON;
141 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255; 141 // Setting it to more than 1 breaks poll():
142 // it blocks even if there's data. !??
143 //tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
144 /* reads would block only if < 1 char is available */
145 tty.c_cc[VMIN] = 1;
146 /* no timeout (reads block forever) */
147 tty.c_cc[VTIME] = 0;
142 } 148 }
143 if (read_flags & BUILTIN_READ_SILENT) { 149 if (read_flags & BUILTIN_READ_SILENT) {
144 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL); 150 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
diff --git a/testsuite/tar.tests b/testsuite/tar.tests
index 39ece5feb..7927020c1 100755
--- a/testsuite/tar.tests
+++ b/testsuite/tar.tests
@@ -170,6 +170,25 @@ Ok
170"" "" 170"" ""
171SKIP= 171SKIP=
172 172
173# Do we detect XZ-compressed data (even w/o .tar.xz or txz extension)?
174# (the uuencoded hello_world.txz contains one empty file named "hello_world")
175optional UUDECODE FEATURE_TAR_AUTODETECT FEATURE_SEAMLESS_XZ
176testing "tar extract txz" "\
177uudecode -o input && tar tf input && echo Ok
178" "\
179hello_world
180Ok
181" \
182"" "\
183begin-base64 644 hello_world.txz
184/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AX/AEldADQZSe6ODIZQ3rSQ8kAJ
185SnMPTX+XWGKW3Yu/Rwqg4Ik5wqgQKgVH97J8yA8IvZ4ahaCQogUNHRkXibr2
186Q615wcb2G7fJU49AhWAAAAAAUA8gu9DyXfAAAWWADAAAAB5FXGCxxGf7AgAA
187AAAEWVo=
188====
189"
190SKIP=
191
173# On extract, everything up to and including last ".." component is stripped 192# On extract, everything up to and including last ".." component is stripped
174optional FEATURE_TAR_CREATE 193optional FEATURE_TAR_CREATE
175testing "tar strips /../ on extract" "\ 194testing "tar strips /../ on extract" "\
diff --git a/util-linux/Config.src b/util-linux/Config.src
index 888bc8f3b..57a52cefb 100644
--- a/util-linux/Config.src
+++ b/util-linux/Config.src
@@ -485,13 +485,18 @@ config FEATURE_MOUNT_LABEL
485 This also enables label or uuid support for swapon. 485 This also enables label or uuid support for swapon.
486 486
487config FEATURE_MOUNT_NFS 487config FEATURE_MOUNT_NFS
488 bool "Support mounting NFS file systems" 488 bool "Support mounting NFS file systems on Linux < 2.6.23"
489 default y 489 default n
490 depends on MOUNT 490 depends on MOUNT
491 select FEATURE_HAVE_RPC 491 select FEATURE_HAVE_RPC
492 select FEATURE_SYSLOG 492 select FEATURE_SYSLOG
493 help 493 help
494 Enable mounting of NFS file systems. 494 Enable mounting of NFS file systems on Linux kernels prior
495 to version 2.6.23. Note that in this case mounting of NFS
496 over IPv6 will not be possible.
497
498 Note that this option links in RPC support from libc,
499 which is rather large (~10 kbytes on uclibc).
495 500
496config FEATURE_MOUNT_CIFS 501config FEATURE_MOUNT_CIFS
497 bool "Support mounting CIFS/SMB file systems" 502 bool "Support mounting CIFS/SMB file systems"
diff --git a/util-linux/acpid.c b/util-linux/acpid.c
index 6e7321b02..1b22f3a01 100644
--- a/util-linux/acpid.c
+++ b/util-linux/acpid.c
@@ -8,13 +8,13 @@
8 */ 8 */
9 9
10//usage:#define acpid_trivial_usage 10//usage:#define acpid_trivial_usage
11//usage: "[-d] [-c CONFDIR] [-l LOGFILE] [-a ACTIONFILE] [-M MAPFILE] [-e PROC_EVENT_FILE] [-p PIDFILE]" 11//usage: "[-df] [-c CONFDIR] [-l LOGFILE] [-a ACTIONFILE] [-M MAPFILE] [-e PROC_EVENT_FILE] [-p PIDFILE]"
12//usage:#define acpid_full_usage "\n\n" 12//usage:#define acpid_full_usage "\n\n"
13//usage: "Listen to ACPI events and spawn specific helpers on event arrival\n" 13//usage: "Listen to ACPI events and spawn specific helpers on event arrival\n"
14//usage: "\n -d Log to stderr, not log file (implies -f)"
15//usage: "\n -f Run in foreground"
14//usage: "\n -c DIR Config directory [/etc/acpi]" 16//usage: "\n -c DIR Config directory [/etc/acpi]"
15//usage: "\n -d Don't daemonize, (implies -f)"
16//usage: "\n -e FILE /proc event file [/proc/acpi/event]" 17//usage: "\n -e FILE /proc event file [/proc/acpi/event]"
17//usage: "\n -f Run in foreground"
18//usage: "\n -l FILE Log file [/var/log/acpid.log]" 18//usage: "\n -l FILE Log file [/var/log/acpid.log]"
19//usage: "\n -p FILE Pid file [/var/run/acpid.pid]" 19//usage: "\n -p FILE Pid file [/var/run/acpid.pid]"
20//usage: "\n -a FILE Action file [/etc/acpid.conf]" 20//usage: "\n -a FILE Action file [/etc/acpid.conf]"
@@ -225,7 +225,6 @@ static void parse_map_file(const char *filename)
225int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 225int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
226int acpid_main(int argc UNUSED_PARAM, char **argv) 226int acpid_main(int argc UNUSED_PARAM, char **argv)
227{ 227{
228 struct input_event ev;
229 int nfd; 228 int nfd;
230 int opts; 229 int opts;
231 struct pollfd *pfd; 230 struct pollfd *pfd;
@@ -248,23 +247,33 @@ int acpid_main(int argc UNUSED_PARAM, char **argv)
248 ); 247 );
249 248
250 if (!(opts & OPT_f)) { 249 if (!(opts & OPT_f)) {
250 /* No -f "Foreground", we go to background */
251 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); 251 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
252 } 252 }
253 253
254 if (!(opts & OPT_d)) { 254 if (!(opts & OPT_d)) {
255 /* No -d "Debug", we log to log file.
256 * This includes any output from children.
257 */
258 xmove_fd(xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
259 xdup2(STDOUT_FILENO, STDERR_FILENO);
260 /* Also, acpid's messages (but not children) will go to syslog too */
255 openlog(applet_name, LOG_PID, LOG_DAEMON); 261 openlog(applet_name, LOG_PID, LOG_DAEMON);
256 logmode = LOGMODE_SYSLOG | LOGMODE_STDIO; 262 logmode = LOGMODE_SYSLOG | LOGMODE_STDIO;
257 } else {
258 xmove_fd(xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
259 } 263 }
264 /* else: -d "Debug", log is not redirected */
260 265
261 parse_conf_file(opt_action); 266 parse_conf_file(opt_action);
262 parse_map_file(opt_map); 267 parse_map_file(opt_map);
263 268
264 xchdir(opt_dir); 269 xchdir(opt_dir);
265 270
271 /* We spawn children but don't wait for them. Prevent zombies: */
266 bb_signals((1 << SIGCHLD), SIG_IGN); 272 bb_signals((1 << SIGCHLD), SIG_IGN);
267 bb_signals(BB_FATAL_SIGS, record_signo); 273 // If you enable this, (1) explain why, (2)
274 // make sure while(poll) loop below is still interruptible
275 // by SIGTERM et al:
276 //bb_signals(BB_FATAL_SIGS, record_signo);
268 277
269 pfd = NULL; 278 pfd = NULL;
270 nfd = 0; 279 nfd = 0;
@@ -272,13 +281,14 @@ int acpid_main(int argc UNUSED_PARAM, char **argv)
272 int fd; 281 int fd;
273 char *dev_event; 282 char *dev_event;
274 283
275 dev_event = xasprintf((option_mask32 & OPT_e) ? "%s" : "%s%u", opt_input, nfd); 284 dev_event = xasprintf((opts & OPT_e) ? "%s" : "%s%u", opt_input, nfd);
276 fd = open(dev_event, O_RDONLY | O_NONBLOCK); 285 fd = open(dev_event, O_RDONLY | O_NONBLOCK);
277 if (fd < 0) { 286 if (fd < 0) {
278 if (nfd == 0) 287 if (nfd == 0)
279 bb_simple_perror_msg_and_die(dev_event); 288 bb_simple_perror_msg_and_die(dev_event);
280 break; 289 break;
281 } 290 }
291 free(dev_event);
282 pfd = xrealloc_vector(pfd, 1, nfd); 292 pfd = xrealloc_vector(pfd, 1, nfd);
283 pfd[nfd].fd = fd; 293 pfd[nfd].fd = fd;
284 pfd[nfd].events = POLLIN; 294 pfd[nfd].events = POLLIN;
@@ -287,16 +297,26 @@ int acpid_main(int argc UNUSED_PARAM, char **argv)
287 297
288 write_pidfile(opt_pidfile); 298 write_pidfile(opt_pidfile);
289 299
290 while (poll(pfd, nfd, -1) > 0) { 300 while (safe_poll(pfd, nfd, -1) > 0) {
291 int i; 301 int i;
292 for (i = 0; i < nfd; i++) { 302 for (i = 0; i < nfd; i++) {
293 const char *event = NULL; 303 const char *event;
294 304
295 memset(&ev, 0, sizeof(ev)); 305 if (!(pfd[i].revents & POLLIN)) {
296 306 if (pfd[i].revents == 0)
297 if (!(pfd[i].revents & POLLIN)) 307 continue; /* this fd has nothing */
298 continue; 308
309 /* Likely POLLERR, POLLHUP, POLLNVAL.
310 * Do not listen on this fd anymore.
311 */
312 close(pfd[i].fd);
313 nfd--;
314 for (; i < nfd; i++)
315 pfd[i].fd = pfd[i + 1].fd;
316 break; /* do poll() again */
317 }
299 318
319 event = NULL;
300 if (option_mask32 & OPT_e) { 320 if (option_mask32 & OPT_e) {
301 char *buf; 321 char *buf;
302 int len; 322 int len;
@@ -307,7 +327,10 @@ int acpid_main(int argc UNUSED_PARAM, char **argv)
307 if (len >= 0) 327 if (len >= 0)
308 buf[len] = '\0'; 328 buf[len] = '\0';
309 event = find_action(NULL, buf); 329 event = find_action(NULL, buf);
330 free(buf);
310 } else { 331 } else {
332 struct input_event ev;
333
311 if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev))) 334 if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev)))
312 continue; 335 continue;
313 336
@@ -318,17 +341,14 @@ int acpid_main(int argc UNUSED_PARAM, char **argv)
318 } 341 }
319 if (!event) 342 if (!event)
320 continue; 343 continue;
321 // spawn event handler 344 /* spawn event handler */
322 process_event(event); 345 process_event(event);
323 } 346 }
324 } 347 }
325 348
326 if (ENABLE_FEATURE_CLEAN_UP) { 349 if (ENABLE_FEATURE_CLEAN_UP) {
327 while (nfd--) { 350 while (nfd--)
328 if (pfd[nfd].fd) { 351 close(pfd[nfd].fd);
329 close(pfd[nfd].fd);
330 }
331 }
332 free(pfd); 352 free(pfd);
333 } 353 }
334 remove_pidfile(opt_pidfile); 354 remove_pidfile(opt_pidfile);
diff --git a/util-linux/blkid.c b/util-linux/blkid.c
index c30360c65..1bbc80311 100644
--- a/util-linux/blkid.c
+++ b/util-linux/blkid.c
@@ -8,23 +8,24 @@
8 */ 8 */
9 9
10//usage:#define blkid_trivial_usage 10//usage:#define blkid_trivial_usage
11//usage: "" 11//usage: "[BLOCKDEV]..."
12//usage:#define blkid_full_usage "\n\n" 12//usage:#define blkid_full_usage "\n\n"
13//usage: "Print UUIDs of all filesystems" 13//usage: "Print UUIDs of all filesystems"
14 14
15#include "libbb.h" 15#include "libbb.h"
16#include "volume_id.h" 16#include "volume_id.h"
17 17
18//TODO: extend to take BLOCKDEV args, and show TYPE="fstype"
19
20int blkid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 18int blkid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
21int blkid_main(int argc UNUSED_PARAM, char **argv) 19int blkid_main(int argc UNUSED_PARAM, char **argv)
22{ 20{
21 int scan_devices = 1;
22
23 while (*++argv) { 23 while (*++argv) {
24 /* Note: bogus device names don't cause any error messages */ 24 /* Note: bogus device names don't cause any error messages */
25 add_to_uuid_cache(*argv); 25 add_to_uuid_cache(*argv);
26 scan_devices = 0;
26 } 27 }
27 28
28 display_uuid_cache(); 29 display_uuid_cache(scan_devices);
29 return 0; 30 return 0;
30} 31}
diff --git a/util-linux/getopt.c b/util-linux/getopt.c
index c45edf8ca..d662c813a 100644
--- a/util-linux/getopt.c
+++ b/util-linux/getopt.c
@@ -32,30 +32,47 @@
32 */ 32 */
33 33
34//usage:#define getopt_trivial_usage 34//usage:#define getopt_trivial_usage
35//usage: "[OPTIONS]" 35//usage: "[OPTIONS] [--] OPTSTRING PARAMS"
36//usage:#define getopt_full_usage "\n\n" 36//usage:#define getopt_full_usage "\n\n"
37//usage: IF_LONG_OPTS( 37//usage: IF_LONG_OPTS(
38//usage: " -a,--alternative Allow long options starting with single -" 38//usage: " -a,--alternative Allow long options starting with single -"
39//usage: "\n -l,--longoptions=longopts Long options to be recognized" 39//usage: "\n -l,--longoptions=LOPT[,...] Long options to be recognized"
40//usage: "\n -n,--name=progname The name under which errors are reported" 40//usage: "\n -n,--name=PROGNAME The name under which errors are reported"
41//usage: "\n -o,--options=optstring Short options to be recognized" 41//usage: "\n -o,--options=OPTSTRING Short options to be recognized"
42//usage: "\n -q,--quiet Disable error reporting by getopt(3)" 42//usage: "\n -q,--quiet Disable error reporting by getopt(3)"
43//usage: "\n -Q,--quiet-output No normal output" 43//usage: "\n -Q,--quiet-output No normal output"
44//usage: "\n -s,--shell=shell Set shell quoting conventions" 44//usage: "\n -s,--shell=SHELL Set shell quoting conventions"
45//usage: "\n -T,--test Test for getopt(1) version" 45//usage: "\n -T,--test Test for getopt(1) version"
46//usage: "\n -u,--unquoted Don't quote the output" 46//usage: "\n -u,--unquoted Don't quote the output"
47//usage: ) 47//usage: )
48//usage: IF_NOT_LONG_OPTS( 48//usage: IF_NOT_LONG_OPTS(
49//usage: " -a Allow long options starting with single -" 49//usage: " -a Allow long options starting with single -"
50//usage: "\n -l longopts Long options to be recognized" 50//usage: "\n -l LOPT[,...] Long options to be recognized"
51//usage: "\n -n progname The name under which errors are reported" 51//usage: "\n -n PROGNAME The name under which errors are reported"
52//usage: "\n -o optstring Short options to be recognized" 52//usage: "\n -o OPTSTRING Short options to be recognized"
53//usage: "\n -q Disable error reporting by getopt(3)" 53//usage: "\n -q Disable error reporting by getopt(3)"
54//usage: "\n -Q No normal output" 54//usage: "\n -Q No normal output"
55//usage: "\n -s shell Set shell quoting conventions" 55//usage: "\n -s SHELL Set shell quoting conventions"
56//usage: "\n -T Test for getopt(1) version" 56//usage: "\n -T Test for getopt(1) version"
57//usage: "\n -u Don't quote the output" 57//usage: "\n -u Don't quote the output"
58//usage: ) 58//usage: )
59//usage: "\n"
60//usage: "\nExample:"
61//usage: "\n"
62//usage: "\nO=`getopt -l bb: -- ab:c:: \"$@\"` || exit 1"
63//usage: "\neval set -- \"$O\""
64//usage: "\nwhile true; do"
65//usage: "\n case \"$1\" in"
66//usage: "\n -a) echo A; shift;;"
67//usage: "\n -b|--bb) echo \"B:'$2'\"; shift 2;;"
68//usage: "\n -c) case \"$2\" in"
69//usage: "\n \"\") echo C; shift 2;;"
70//usage: "\n *) echo \"C:'$2'\"; shift 2;;"
71//usage: "\n esac;;"
72//usage: "\n --) shift; break;;"
73//usage: "\n *) echo Error; exit 1;;"
74//usage: "\n esac"
75//usage: "\ndone"
59//usage: 76//usage:
60//usage:#define getopt_example_usage 77//usage:#define getopt_example_usage
61//usage: "$ cat getopt.test\n" 78//usage: "$ cat getopt.test\n"
@@ -339,6 +356,7 @@ static const char getopt_longopts[] ALIGN1 =
339int getopt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 356int getopt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
340int getopt_main(int argc, char **argv) 357int getopt_main(int argc, char **argv)
341{ 358{
359 int n;
342 char *optstr = NULL; 360 char *optstr = NULL;
343 char *name = NULL; 361 char *name = NULL;
344 unsigned opt; 362 unsigned opt;
@@ -351,7 +369,7 @@ int getopt_main(int argc, char **argv)
351 369
352 compatible = getenv("GETOPT_COMPATIBLE"); /* used as yes/no flag */ 370 compatible = getenv("GETOPT_COMPATIBLE"); /* used as yes/no flag */
353 371
354 if (argc == 1) { 372 if (!argv[1]) {
355 if (compatible) { 373 if (compatible) {
356 /* For some reason, the original getopt gave no error 374 /* For some reason, the original getopt gave no error
357 when there were no arguments. */ 375 when there were no arguments. */
@@ -362,10 +380,10 @@ int getopt_main(int argc, char **argv)
362 } 380 }
363 381
364 if (argv[1][0] != '-' || compatible) { 382 if (argv[1][0] != '-' || compatible) {
365 char *s; 383 char *s = argv[1];
366 384
367 option_mask32 |= OPT_u; /* quoting off */ 385 option_mask32 |= OPT_u; /* quoting off */
368 s = xstrdup(argv[1] + strspn(argv[1], "-+")); 386 s = xstrdup(s + strspn(s, "-+"));
369 argv[1] = argv[0]; 387 argv[1] = argv[0];
370 return generate_output(argv+1, argc-1, s, long_options); 388 return generate_output(argv+1, argc-1, s, long_options);
371 } 389 }
@@ -392,12 +410,13 @@ int getopt_main(int argc, char **argv)
392 } 410 }
393 411
394 /* All options controlling the applet have now been parsed */ 412 /* All options controlling the applet have now been parsed */
413 n = optind - 1;
395 if (!optstr) { 414 if (!optstr) {
396 if (optind >= argc) 415 optstr = argv[++n];
416 if (!optstr)
397 bb_error_msg_and_die("missing optstring argument"); 417 bb_error_msg_and_die("missing optstring argument");
398 optstr = argv[optind++];
399 } 418 }
400 419
401 argv[optind-1] = name ? name : argv[0]; 420 argv[n] = name ? name : argv[0];
402 return generate_output(argv+optind-1, argc-optind+1, optstr, long_options); 421 return generate_output(argv + n, argc - n, optstr, long_options);
403} 422}
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index c6be1b872..67de52d06 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -206,7 +206,8 @@ static void parse_next_rule(void)
206 char *tokens[4]; 206 char *tokens[4];
207 char *val; 207 char *val;
208 208
209 if (!config_read(G.parser, tokens, 4, 3, "# \t", PARSE_NORMAL)) 209 /* No PARSE_EOL_COMMENTS, because command may contain '#' chars */
210 if (!config_read(G.parser, tokens, 4, 3, "# \t", PARSE_NORMAL & ~PARSE_EOL_COMMENTS))
210 break; 211 break;
211 212
212 /* Fields: [-]regex uid:gid mode [alias] [cmd] */ 213 /* Fields: [-]regex uid:gid mode [alias] [cmd] */
@@ -564,8 +565,12 @@ static void make_device(char *path, int delete)
564 chown(node_name, rule->ugid.uid, rule->ugid.gid); 565 chown(node_name, rule->ugid.uid, rule->ugid.gid);
565 } 566 }
566 if (ENABLE_FEATURE_MDEV_RENAME && alias) { 567 if (ENABLE_FEATURE_MDEV_RENAME && alias) {
567 if (aliaslink == '>') 568 if (aliaslink == '>') {
569//TODO: on devtmpfs, device_name already exists and symlink() fails.
570//End result is that instead of symlink, we have two nodes.
571//What should be done?
568 symlink(node_name, device_name); 572 symlink(node_name, device_name);
573 }
569 } 574 }
570 } 575 }
571 576
@@ -782,7 +787,7 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
782 int seqlen; 787 int seqlen;
783 char seqbuf[sizeof(int)*3 + 2]; 788 char seqbuf[sizeof(int)*3 + 2];
784 789
785 seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf-1)); 790 seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf) - 1);
786 if (seqlen < 0) { 791 if (seqlen < 0) {
787 seq = NULL; 792 seq = NULL;
788 break; 793 break;
diff --git a/util-linux/mkfs_ext2.c b/util-linux/mkfs_ext2.c
index f6ccc9c9e..6cbbe0e07 100644
--- a/util-linux/mkfs_ext2.c
+++ b/util-linux/mkfs_ext2.c
@@ -615,7 +615,11 @@ int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
615 615
616 // zero boot sectors 616 // zero boot sectors
617 memset(buf, 0, blocksize); 617 memset(buf, 0, blocksize);
618 PUT(0, buf, 1024); // N.B. 1024 <= blocksize, so buf[0..1023] contains zeros 618 // Disabled: standard mke2fs doesn't do this, and
619 // on SPARC this destroys Sun disklabel.
620 // Users who need/want zeroing can easily do it with dd.
621 //PUT(0, buf, 1024); // N.B. 1024 <= blocksize, so buf[0..1023] contains zeros
622
619 // zero inode tables 623 // zero inode tables
620 for (i = 0; i < ngroups; ++i) 624 for (i = 0; i < ngroups; ++i)
621 for (n = 0; n < inode_table_blocks; ++n) 625 for (n = 0; n < inode_table_blocks; ++n)
diff --git a/util-linux/more.c b/util-linux/more.c
index efceb71ec..359571397 100644
--- a/util-linux/more.c
+++ b/util-linux/more.c
@@ -85,8 +85,7 @@ int more_main(int argc UNUSED_PARAM, char **argv)
85 cin_fileno = fileno(cin); 85 cin_fileno = fileno(cin);
86 getTermSettings(cin_fileno, &initial_settings); 86 getTermSettings(cin_fileno, &initial_settings);
87 new_settings = initial_settings; 87 new_settings = initial_settings;
88 new_settings.c_lflag &= ~ICANON; 88 new_settings.c_lflag &= ~(ICANON | ECHO);
89 new_settings.c_lflag &= ~ECHO;
90 new_settings.c_cc[VMIN] = 1; 89 new_settings.c_cc[VMIN] = 1;
91 new_settings.c_cc[VTIME] = 0; 90 new_settings.c_cc[VTIME] = 0;
92 setTermSettings(cin_fileno, &new_settings); 91 setTermSettings(cin_fileno, &new_settings);
diff --git a/util-linux/mount.c b/util-linux/mount.c
index f94b6e643..807e89747 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -820,31 +820,31 @@ enum {
820 */ 820 */
821 821
822struct nfs2_fh { 822struct nfs2_fh {
823 char data[32]; 823 char data[32];
824}; 824};
825struct nfs3_fh { 825struct nfs3_fh {
826 unsigned short size; 826 unsigned short size;
827 unsigned char data[64]; 827 unsigned char data[64];
828}; 828};
829 829
830struct nfs_mount_data { 830struct nfs_mount_data {
831 int version; /* 1 */ 831 int version; /* 1 */
832 int fd; /* 1 */ 832 int fd; /* 1 */
833 struct nfs2_fh old_root; /* 1 */ 833 struct nfs2_fh old_root; /* 1 */
834 int flags; /* 1 */ 834 int flags; /* 1 */
835 int rsize; /* 1 */ 835 int rsize; /* 1 */
836 int wsize; /* 1 */ 836 int wsize; /* 1 */
837 int timeo; /* 1 */ 837 int timeo; /* 1 */
838 int retrans; /* 1 */ 838 int retrans; /* 1 */
839 int acregmin; /* 1 */ 839 int acregmin; /* 1 */
840 int acregmax; /* 1 */ 840 int acregmax; /* 1 */
841 int acdirmin; /* 1 */ 841 int acdirmin; /* 1 */
842 int acdirmax; /* 1 */ 842 int acdirmax; /* 1 */
843 struct sockaddr_in addr; /* 1 */ 843 struct sockaddr_in addr; /* 1 */
844 char hostname[256]; /* 1 */ 844 char hostname[256]; /* 1 */
845 int namlen; /* 2 */ 845 int namlen; /* 2 */
846 unsigned int bsize; /* 3 */ 846 unsigned int bsize; /* 3 */
847 struct nfs3_fh root; /* 4 */ 847 struct nfs3_fh root; /* 4 */
848}; 848};
849 849
850/* bits in the flags field */ 850/* bits in the flags field */
@@ -859,6 +859,7 @@ enum {
859 NFS_MOUNT_VER3 = 0x0080, /* 3 */ 859 NFS_MOUNT_VER3 = 0x0080, /* 3 */
860 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */ 860 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
861 NFS_MOUNT_NONLM = 0x0200, /* 3 */ 861 NFS_MOUNT_NONLM = 0x0200, /* 3 */
862 NFS_MOUNT_NOACL = 0x0800, /* 4 */
862 NFS_MOUNT_NORDIRPLUS = 0x4000 863 NFS_MOUNT_NORDIRPLUS = 0x4000
863}; 864};
864 865
@@ -1123,6 +1124,7 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
1123 int noac; 1124 int noac;
1124 int nordirplus; 1125 int nordirplus;
1125 int nolock; 1126 int nolock;
1127 int noacl;
1126 1128
1127 find_kernel_nfs_mount_version(); 1129 find_kernel_nfs_mount_version();
1128 1130
@@ -1142,7 +1144,7 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
1142 pathname = s + 1; 1144 pathname = s + 1;
1143 *s = '\0'; 1145 *s = '\0';
1144 /* Ignore all but first hostname in replicated mounts 1146 /* Ignore all but first hostname in replicated mounts
1145 until they can be fully supported. (mack@sgi.com) */ 1147 * until they can be fully supported. (mack@sgi.com) */
1146 s = strchr(hostname, ','); 1148 s = strchr(hostname, ',');
1147 if (s) { 1149 if (s) {
1148 *s = '\0'; 1150 *s = '\0';
@@ -1195,6 +1197,7 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
1195 nolock = 0; 1197 nolock = 0;
1196 noac = 0; 1198 noac = 0;
1197 nordirplus = 0; 1199 nordirplus = 0;
1200 noacl = 0;
1198 retry = 10000; /* 10000 minutes ~ 1 week */ 1201 retry = 10000; /* 10000 minutes ~ 1 week */
1199 tcp = 1; /* nfs-utils uses tcp per default */ 1202 tcp = 1; /* nfs-utils uses tcp per default */
1200 1203
@@ -1333,7 +1336,8 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
1333 "tcp\0" 1336 "tcp\0"
1334 "udp\0" 1337 "udp\0"
1335 "lock\0" 1338 "lock\0"
1336 "rdirplus\0"; 1339 "rdirplus\0"
1340 "acl\0";
1337 int val = 1; 1341 int val = 1;
1338 if (!strncmp(opt, "no", 2)) { 1342 if (!strncmp(opt, "no", 2)) {
1339 val = 0; 1343 val = 0;
@@ -1383,6 +1387,9 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
1383 case 11: //rdirplus 1387 case 11: //rdirplus
1384 nordirplus = !val; 1388 nordirplus = !val;
1385 break; 1389 break;
1390 case 12: // acl
1391 noacl = !val;
1392 break;
1386 default: 1393 default:
1387 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt); 1394 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1388 goto fail; 1395 goto fail;
@@ -1396,7 +1403,8 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
1396 | (posix ? NFS_MOUNT_POSIX : 0) 1403 | (posix ? NFS_MOUNT_POSIX : 0)
1397 | (nocto ? NFS_MOUNT_NOCTO : 0) 1404 | (nocto ? NFS_MOUNT_NOCTO : 0)
1398 | (noac ? NFS_MOUNT_NOAC : 0) 1405 | (noac ? NFS_MOUNT_NOAC : 0)
1399 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0); 1406 | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0)
1407 | (noacl ? NFS_MOUNT_NOACL : 0);
1400 if (nfs_mount_version >= 2) 1408 if (nfs_mount_version >= 2)
1401 data.flags |= (tcp ? NFS_MOUNT_TCP : 0); 1409 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1402 if (nfs_mount_version >= 3) 1410 if (nfs_mount_version >= 3)
@@ -1675,7 +1683,6 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
1675 1683
1676 /* Perform actual mount */ 1684 /* Perform actual mount */
1677 do_mount: 1685 do_mount:
1678 mp->mnt_type = (char*)"nfs";
1679 retval = mount_it_now(mp, vfsflags, (char*)&data); 1686 retval = mount_it_now(mp, vfsflags, (char*)&data);
1680 goto ret; 1687 goto ret;
1681 1688
@@ -1700,8 +1707,43 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
1700 1707
1701#else // !ENABLE_FEATURE_MOUNT_NFS 1708#else // !ENABLE_FEATURE_MOUNT_NFS
1702 1709
1703// Never called. Call should be optimized out. 1710/* Linux 2.6.23+ supports nfs mounts with options passed as a string.
1704int nfsmount(struct mntent *mp, long vfsflags, char *filteropts); 1711 * For older kernels, you must build busybox with ENABLE_FEATURE_MOUNT_NFS.
1712 * (However, note that then you lose any chances that NFS over IPv6 would work).
1713 */
1714static int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
1715{
1716 len_and_sockaddr *lsa;
1717 char *opts;
1718 char *end;
1719 char *dotted;
1720 int ret;
1721
1722# if ENABLE_FEATURE_IPV6
1723 end = strchr(mp->mnt_fsname, ']');
1724 if (end && end[1] == ':')
1725 end++;
1726 else
1727# endif
1728 /* mount_main() guarantees that ':' is there */
1729 end = strchr(mp->mnt_fsname, ':');
1730
1731 *end = '\0';
1732 lsa = xhost2sockaddr(mp->mnt_fsname, /*port:*/ 0);
1733 *end = ':';
1734 dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
1735 if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
1736 opts = xasprintf("%s%saddr=%s",
1737 filteropts ? filteropts : "",
1738 filteropts ? "," : "",
1739 dotted
1740 );
1741 if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
1742 ret = mount_it_now(mp, vfsflags, opts);
1743 if (ENABLE_FEATURE_CLEAN_UP) free(opts);
1744
1745 return ret;
1746}
1705 1747
1706#endif // !ENABLE_FEATURE_MOUNT_NFS 1748#endif // !ENABLE_FEATURE_MOUNT_NFS
1707 1749
@@ -1792,10 +1834,11 @@ static int singlemount(struct mntent *mp, int ignore_busy)
1792 } 1834 }
1793 1835
1794 // Might this be an NFS filesystem? 1836 // Might this be an NFS filesystem?
1795 if (ENABLE_FEATURE_MOUNT_NFS 1837 if ((!mp->mnt_type || strncmp(mp->mnt_type, "nfs", 3) == 0)
1796 && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
1797 && strchr(mp->mnt_fsname, ':') != NULL 1838 && strchr(mp->mnt_fsname, ':') != NULL
1798 ) { 1839 ) {
1840 if (!mp->mnt_type)
1841 mp->mnt_type = (char*)"nfs";
1799 rc = nfsmount(mp, vfsflags, filteropts); 1842 rc = nfsmount(mp, vfsflags, filteropts);
1800 goto report_error; 1843 goto report_error;
1801 } 1844 }
diff --git a/util-linux/rdev.c b/util-linux/rdev.c
index 1212f841e..465281756 100644
--- a/util-linux/rdev.c
+++ b/util-linux/rdev.c
@@ -23,9 +23,9 @@
23int rdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 23int rdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
24int rdev_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 24int rdev_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
25{ 25{
26 char const * const root_device = find_block_device("/"); 26 const char *root_device = find_block_device("/");
27 27
28 if (root_device != NULL) { 28 if (root_device) {
29 printf("%s /\n", root_device); 29 printf("%s /\n", root_device);
30 return EXIT_SUCCESS; 30 return EXIT_SUCCESS;
31 } 31 }
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c
index db6ae3542..a301b365b 100644
--- a/util-linux/switch_root.c
+++ b/util-linux/switch_root.c
@@ -114,7 +114,7 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv)
114 } 114 }
115 xchroot("."); 115 xchroot(".");
116 // The chdir is needed to recalculate "." and ".." links 116 // The chdir is needed to recalculate "." and ".." links
117 xchdir("/"); 117 /*xchdir("/"); - done in xchroot */
118 118
119 // If a new console specified, redirect stdin/stdout/stderr to it 119 // If a new console specified, redirect stdin/stdout/stderr to it
120 if (console) { 120 if (console) {
diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c
index 7c9930543..230102d89 100644
--- a/util-linux/volume_id/get_devname.c
+++ b/util-linux/volume_id/get_devname.c
@@ -114,12 +114,12 @@ uuidcache_check_device(const char *device,
114 return TRUE; 114 return TRUE;
115} 115}
116 116
117static void 117static struct uuidCache_s*
118uuidcache_init(void) 118uuidcache_init(int scan_devices)
119{ 119{
120 dbg("DBG: uuidCache=%x, uuidCache"); 120 dbg("DBG: uuidCache=%x, uuidCache");
121 if (uuidCache) 121 if (uuidCache)
122 return; 122 return uuidCache;
123 123
124 /* We were scanning /proc/partitions 124 /* We were scanning /proc/partitions
125 * and /proc/sys/dev/cdrom/info here. 125 * and /proc/sys/dev/cdrom/info here.
@@ -131,12 +131,14 @@ uuidcache_init(void)
131 * This is unacceptably complex. Let's just scan /dev. 131 * This is unacceptably complex. Let's just scan /dev.
132 * (Maybe add scanning of /sys/block/XXX/dev for devices 132 * (Maybe add scanning of /sys/block/XXX/dev for devices
133 * somehow not having their /dev/XXX entries created?) */ 133 * somehow not having their /dev/XXX entries created?) */
134 134 if (scan_devices)
135 recursive_action("/dev", ACTION_RECURSE, 135 recursive_action("/dev", ACTION_RECURSE,
136 uuidcache_check_device, /* file_action */ 136 uuidcache_check_device, /* file_action */
137 NULL, /* dir_action */ 137 NULL, /* dir_action */
138 NULL, /* userData */ 138 NULL, /* userData */
139 0 /* depth */); 139 0 /* depth */);
140
141 return uuidCache;
140} 142}
141 143
142#define UUID 1 144#define UUID 1
@@ -148,9 +150,7 @@ get_spec_by_x(int n, const char *t, int *majorPtr, int *minorPtr)
148{ 150{
149 struct uuidCache_s *uc; 151 struct uuidCache_s *uc;
150 152
151 uuidcache_init(); 153 uc = uuidcache_init(/*scan_devices:*/ 1);
152 uc = uuidCache;
153
154 while (uc) { 154 while (uc) {
155 switch (n) { 155 switch (n) {
156 case UUID: 156 case UUID:
@@ -215,24 +215,23 @@ get_spec_by_volume_label(const char *s, int *major, int *minor)
215#endif // UNUSED 215#endif // UNUSED
216 216
217/* Used by blkid */ 217/* Used by blkid */
218void display_uuid_cache(void) 218void display_uuid_cache(int scan_devices)
219{ 219{
220 struct uuidCache_s *u; 220 struct uuidCache_s *uc;
221 221
222 uuidcache_init(); 222 uc = uuidcache_init(scan_devices);
223 u = uuidCache; 223 while (uc) {
224 while (u) { 224 printf("%s:", uc->device);
225 printf("%s:", u->device); 225 if (uc->label[0])
226 if (u->label[0]) 226 printf(" LABEL=\"%s\"", uc->label);
227 printf(" LABEL=\"%s\"", u->label); 227 if (uc->uc_uuid[0])
228 if (u->uc_uuid[0]) 228 printf(" UUID=\"%s\"", uc->uc_uuid);
229 printf(" UUID=\"%s\"", u->uc_uuid);
230#if ENABLE_FEATURE_BLKID_TYPE 229#if ENABLE_FEATURE_BLKID_TYPE
231 if (u->type) 230 if (uc->type)
232 printf(" TYPE=\"%s\"", u->type); 231 printf(" TYPE=\"%s\"", uc->type);
233#endif 232#endif
234 bb_putchar('\n'); 233 bb_putchar('\n');
235 u = u->next; 234 uc = uc->next;
236 } 235 }
237} 236}
238 237
@@ -265,8 +264,7 @@ char *get_devname_from_label(const char *spec)
265{ 264{
266 struct uuidCache_s *uc; 265 struct uuidCache_s *uc;
267 266
268 uuidcache_init(); 267 uc = uuidcache_init(/*scan_devices:*/ 1);
269 uc = uuidCache;
270 while (uc) { 268 while (uc) {
271 if (uc->label[0] && strcmp(spec, uc->label) == 0) { 269 if (uc->label[0] && strcmp(spec, uc->label) == 0) {
272 return xstrdup(uc->device); 270 return xstrdup(uc->device);
@@ -280,8 +278,7 @@ char *get_devname_from_uuid(const char *spec)
280{ 278{
281 struct uuidCache_s *uc; 279 struct uuidCache_s *uc;
282 280
283 uuidcache_init(); 281 uc = uuidcache_init(/*scan_devices:*/ 1);
284 uc = uuidCache;
285 while (uc) { 282 while (uc) {
286 /* case of hex numbers doesn't matter */ 283 /* case of hex numbers doesn't matter */
287 if (strcasecmp(spec, uc->uc_uuid) == 0) { 284 if (strcasecmp(spec, uc->uc_uuid) == 0) {