diff options
author | Ron Yorston <rmy@pobox.com> | 2012-03-23 12:12:03 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2012-03-23 12:12:03 +0000 |
commit | b0f54743e36af163ae2530c381c485bb29df13dc (patch) | |
tree | cda4cfeaae6e47fe4f14c1b566092be4da9affc4 | |
parent | 40514a0309939f2446f0d4ed9600cad5de396e7f (diff) | |
parent | ba88826c66411affc1da3614742b454654f7298a (diff) | |
download | busybox-w32-b0f54743e36af163ae2530c381c485bb29df13dc.tar.gz busybox-w32-b0f54743e36af163ae2530c381c485bb29df13dc.tar.bz2 busybox-w32-b0f54743e36af163ae2530c381c485bb29df13dc.zip |
Merge branch 'busybox' into merge
Conflicts:
Makefile.flags
129 files changed, 4967 insertions, 1458 deletions
@@ -106,20 +106,21 @@ config FEATURE_BUFFERS_GO_IN_BSS | |||
106 | endchoice | 106 | endchoice |
107 | 107 | ||
108 | config SHOW_USAGE | 108 | config 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 | ||
117 | config FEATURE_VERBOSE_USAGE | 118 | config 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 | ||
626 | config 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 | |||
625 | config EXTRA_CFLAGS | 641 | config 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 | ||
647 | config EXTRA_LDFLAGS | ||
648 | string "Additional LDFLAGS" | ||
649 | default "" | ||
650 | help | ||
651 | Additional LDFLAGS to pass to the linker verbatim. | ||
652 | |||
653 | config EXTRA_LDLIBS | ||
654 | string "Additional LDLIBS" | ||
655 | default "" | ||
656 | help | ||
657 | Additional LDLIBS to pass to the linker with -l. | ||
658 | |||
631 | endmenu | 659 | endmenu |
632 | 660 | ||
633 | menu 'Debugging Options' | 661 | menu '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 | #")) |
98 | endif | 98 | endif |
99 | 99 | ||
100 | # Note: both "" (string consisting of two quote chars) and empty string | ||
101 | # are possible, and should be skipped below. | ||
102 | ifneq ($(subst "",,$(CONFIG_SYSROOT)),) | ||
103 | CFLAGS += --sysroot=$(CONFIG_SYSROOT) | ||
104 | export SYSROOT=$(CONFIG_SYSROOT) | ||
105 | endif | ||
106 | |||
100 | ifeq ($(CONFIG_PLATFORM_MINGW32),y) | 107 | ifeq ($(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 |
102 | CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy | 109 | CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy |
@@ -104,17 +111,25 @@ EXEEXT = .exe | |||
104 | ifeq ($(CONFIG_WIN32_NET),y) | 111 | ifeq ($(CONFIG_WIN32_NET),y) |
105 | LDLIBS += ws2_32 | 112 | LDLIBS += ws2_32 |
106 | endif | 113 | endif |
107 | else | 114 | endif |
108 | ifneq ($(CONFIG_CROSS_COMPILER_PREFIX),"arm-linux-androideabi-") | 115 | |
116 | # Android has no separate crypt library | ||
117 | CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) -lcrypt -o /dev/null -xc - >/dev/null 2>&1 && echo "y") | ||
118 | ifeq ($(CRYPT_AVAILABLE),y) | ||
109 | LDLIBS += m crypt | 119 | LDLIBS += m crypt |
110 | else | 120 | else |
111 | # Android libc has no crypt. TODO: make a generic CONFIG_LINK_WITH_CRYPT option? | ||
112 | LDLIBS += m | 121 | LDLIBS += m |
113 | endif | 122 | endif |
114 | endif | ||
115 | 123 | ||
116 | ifeq ($(CONFIG_PAM),y) | 124 | ifeq ($(CONFIG_PAM),y) |
117 | LDLIBS += 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.) | ||
132 | LDLIBS += pam pam_misc pthread | ||
118 | endif | 133 | endif |
119 | 134 | ||
120 | ifeq ($(CONFIG_SELINUX),y) | 135 | ifeq ($(CONFIG_SELINUX),y) |
@@ -139,6 +154,16 @@ ifneq (,$(findstring $(W_ELF2FLT),$(LDFLAGS) $(CFLAGS_busybox))) | |||
139 | SKIP_STRIP = y | 154 | SKIP_STRIP = y |
140 | endif | 155 | endif |
141 | 156 | ||
157 | ifneq ($(CONFIG_EXTRA_LDFLAGS),) | ||
158 | EXTRA_LDFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_LDFLAGS))) | ||
159 | #")) | ||
160 | endif | ||
161 | |||
162 | ifneq ($(CONFIG_EXTRA_LDLIBS),) | ||
163 | LDLIBS += $(strip $(subst ",,$(CONFIG_EXTRA_LDLIBS))) | ||
164 | #")) | ||
165 | endif | ||
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 @@ | |||
1 | This directory contains examples of applets implemented as shell scripts. | ||
2 | |||
3 | So far these scripts are not hooked to the build system and are not | ||
4 | installed by "make install". If you want to use them, | ||
5 | you 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 | ||
5 | sed $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 | ||
2 | cat /etc/nologin.txt 2>/dev/null || echo "This account is not available" | ||
3 | sleep 5 | ||
4 | exit 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 | ||
4 | for i in "$@" | ||
5 | do | ||
6 | sed -e '1!G;h;$!d' "$i" | ||
7 | done | ||
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 | ||
5 | sed $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 | ||
34 | config FEATURE_SEAMLESS_Z | 34 | config 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 | ||
40 | config AR | 40 | config 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 | ||
35 | int FAST_FUNC bbunpack(char **argv, | 35 | int 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 |
186 | static | 186 | static |
187 | IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(unpack_info_t *info UNUSED_PARAM) | 187 | IF_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 | } |
198 | int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 191 | int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
199 | int uncompress_main(int argc UNUSED_PARAM, char **argv) | 192 | int 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 | } |
283 | static | 276 | static |
284 | IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(unpack_info_t *info) | 277 | IF_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 |
356 | static | 327 | static |
357 | IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(unpack_info_t *info UNUSED_PARAM) | 328 | IF_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 | } |
361 | int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 332 | int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
362 | int bunzip2_main(int argc UNUSED_PARAM, char **argv) | 333 | int 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 |
424 | static | 395 | static |
425 | IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(unpack_info_t *info UNUSED_PARAM) | 396 | IF_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 | } |
429 | int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 400 | int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
430 | int unlzma_main(int argc UNUSED_PARAM, char **argv) | 401 | int 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 |
449 | static | 420 | static |
450 | IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM) | 421 | IF_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 | } |
463 | int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 425 | int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
464 | int unxz_main(int argc UNUSED_PARAM, char **argv) | 426 | int 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 | ||
113 | static | 113 | static |
114 | IF_DESKTOP(long long) int FAST_FUNC compressStream(unpack_info_t *info UNUSED_PARAM) | 114 | IF_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 | /* ======================================================================== */ |
2017 | static | 2017 | static |
2018 | IF_DESKTOP(long long) int FAST_FUNC pack_gzip(unpack_info_t *info UNUSED_PARAM) | 2018 | IF_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 | ||
30 | DPKG_FILES:= \ | 30 | DPKG_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 | ||
36 | INSERT | 39 | INSERT |
37 | 40 | ||
@@ -42,18 +45,18 @@ lib-$(CONFIG_UNXZ) += decompress_unxz.o | |||
42 | lib-$(CONFIG_CPIO) += get_header_cpio.o | 45 | lib-$(CONFIG_CPIO) += get_header_cpio.o |
43 | lib-$(CONFIG_DPKG) += $(DPKG_FILES) | 46 | lib-$(CONFIG_DPKG) += $(DPKG_FILES) |
44 | lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) | 47 | lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) |
45 | lib-$(CONFIG_GUNZIP) += decompress_unzip.o | 48 | lib-$(CONFIG_GUNZIP) += decompress_gunzip.o |
46 | lib-$(CONFIG_RPM2CPIO) += decompress_unzip.o get_header_cpio.o | 49 | lib-$(CONFIG_RPM2CPIO) += decompress_gunzip.o get_header_cpio.o |
47 | lib-$(CONFIG_RPM) += open_transformer.o decompress_unzip.o get_header_cpio.o | 50 | lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o |
48 | lib-$(CONFIG_TAR) += get_header_tar.o | 51 | lib-$(CONFIG_TAR) += get_header_tar.o |
49 | lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o | 52 | lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o |
50 | lib-$(CONFIG_UNZIP) += decompress_unzip.o | 53 | lib-$(CONFIG_UNZIP) += decompress_gunzip.o |
51 | lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o | 54 | lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o |
52 | lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o | 55 | lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o |
53 | lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o | 56 | lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o |
54 | lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_unzip.o get_header_tar_gz.o | 57 | lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_gunzip.o |
55 | lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o | 58 | lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o |
56 | lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o | 59 | lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o |
57 | lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o | 60 | lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o |
58 | lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o | 61 | lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o |
59 | lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += decompress_bunzip2.o | 62 | lib-$(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. */ |
723 | IF_DESKTOP(long long) int FAST_FUNC | 723 | IF_DESKTOP(long long) int FAST_FUNC |
724 | unpack_bz2_stream(int src_fd, int dst_fd) | 724 | unpack_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 | ||
797 | IF_DESKTOP(long long) int FAST_FUNC | ||
798 | unpack_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 | ||
810 | static char *const bunzip_errors[] = { | 802 | static 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 | ||
1036 | IF_DESKTOP(long long) int FAST_FUNC | 1036 | IF_DESKTOP(long long) int FAST_FUNC |
1037 | inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out) | 1037 | inflate_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 | ||
1110 | static int check_header_gzip(STATE_PARAM unpack_info_t *info) | 1110 | static 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 | ||
1184 | IF_DESKTOP(long long) int FAST_FUNC | 1184 | IF_DESKTOP(long long) int FAST_FUNC |
1185 | unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) | 1185 | unpack_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 | |||
1248 | IF_DESKTOP(long long) int FAST_FUNC | ||
1249 | unpack_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 | ||
75 | IF_DESKTOP(long long) int FAST_FUNC | 75 | IF_DESKTOP(long long) int FAST_FUNC |
76 | unpack_Z_stream(int fd_in, int fd_out) | 76 | unpack_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 | ||
215 | IF_DESKTOP(long long) int FAST_FUNC | 215 | IF_DESKTOP(long long) int FAST_FUNC |
216 | unpack_lzma_stream(int src_fd, int dst_fd) | 216 | unpack_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 | ||
40 | IF_DESKTOP(long long) int FAST_FUNC | 40 | IF_DESKTOP(long long) int FAST_FUNC |
41 | unpack_xz_stream(int src_fd, int dst_fd) | 41 | unpack_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. | 94 | static 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" | ||
98 | static 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 | ||
150 | char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) | 161 | char 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 | ||
9 | char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) | 9 | char 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 | ||
9 | void FAST_FUNC init_transformer_aux_data(transformer_aux_data_t *aux) | ||
10 | { | ||
11 | memset(aux, 0, sizeof(*aux)); | ||
12 | } | ||
13 | |||
14 | int 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 | ||
31 | void 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 | */ | ||
14 | void FAST_FUNC open_transformer(int fd, | 60 | void 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 | ||
65 | void 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 | */ | ||
117 | int 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 | |||
179 | int 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 | |||
208 | void* 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 | ||
1079 | static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(unpack_info_t *info UNUSED_PARAM) | 1080 | static 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 | ||
696 | static 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 */ | ||
723 | static int child_error; | ||
724 | |||
725 | static 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 |
850 | static const char tar_longopts[] ALIGN1 = | 804 | static const char tar_longopts[] ALIGN1 = |
@@ -903,7 +857,6 @@ static const char tar_longopts[] ALIGN1 = | |||
903 | int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 857 | int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
904 | int tar_main(int argc UNUSED_PARAM, char **argv) | 858 | int 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 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_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 |
63 | CONFIG_LFS=y | 63 | # CONFIG_LFS is not set |
64 | CONFIG_CROSS_COMPILER_PREFIX="arm-eabi-" | 64 | CONFIG_CROSS_COMPILER_PREFIX="arm-eabi-" |
65 | # | 65 | # |
66 | # Removed: | 66 | # Removed: |
@@ -199,6 +199,7 @@ CONFIG_CAT=y | |||
199 | CONFIG_TEST=y | 199 | CONFIG_TEST=y |
200 | CONFIG_FEATURE_TEST_64=y | 200 | CONFIG_FEATURE_TEST_64=y |
201 | CONFIG_TOUCH=y | 201 | CONFIG_TOUCH=y |
202 | CONFIG_FEATURE_TOUCH_SUSV3=y | ||
202 | CONFIG_TR=y | 203 | CONFIG_TR=y |
203 | CONFIG_FEATURE_TR_CLASSES=y | 204 | CONFIG_FEATURE_TR_CLASSES=y |
204 | CONFIG_FEATURE_TR_EQUIV=y | 205 | CONFIG_FEATURE_TR_EQUIV=y |
@@ -554,7 +555,7 @@ CONFIG_FEATURE_FBSET_READMODE=y | |||
554 | CONFIG_FDFLUSH=y | 555 | CONFIG_FDFLUSH=y |
555 | CONFIG_FDFORMAT=y | 556 | CONFIG_FDFORMAT=y |
556 | CONFIG_FDISK=y | 557 | CONFIG_FDISK=y |
557 | # CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set | 558 | CONFIG_FDISK_SUPPORT_LARGE_DISKS=y |
558 | CONFIG_FEATURE_FDISK_WRITABLE=y | 559 | CONFIG_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 | |||
790 | CONFIG_FEATURE_IFUPDOWN_IPV4=y | 791 | CONFIG_FEATURE_IFUPDOWN_IPV4=y |
791 | # CONFIG_FEATURE_IFUPDOWN_IPV6 is not set | 792 | # CONFIG_FEATURE_IFUPDOWN_IPV6 is not set |
792 | CONFIG_FEATURE_IFUPDOWN_MAPPING=y | 793 | CONFIG_FEATURE_IFUPDOWN_MAPPING=y |
793 | # CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set | 794 | CONFIG_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 | |||
841 | CONFIG_FEATURE_TFTP_BLOCKSIZE=y | 842 | CONFIG_FEATURE_TFTP_BLOCKSIZE=y |
842 | CONFIG_FEATURE_TFTP_PROGRESS_BAR=y | 843 | CONFIG_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 | 845 | CONFIG_TRACEROUTE=y |
845 | # CONFIG_TRACEROUTE6 is not set | 846 | # CONFIG_TRACEROUTE6 is not set |
846 | # CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set | 847 | CONFIG_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 |
849 | CONFIG_TUNCTL=y | 850 | CONFIG_TUNCTL=y |
850 | CONFIG_FEATURE_TUNCTL_UG=y | 851 | CONFIG_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 | |||
856 | CONFIG_DHCPD_LEASES_FILE="" | 858 | CONFIG_DHCPD_LEASES_FILE="" |
857 | CONFIG_UDHCPC=y | 859 | CONFIG_UDHCPC=y |
858 | CONFIG_FEATURE_UDHCPC_ARPING=y | 860 | CONFIG_FEATURE_UDHCPC_ARPING=y |
859 | # CONFIG_FEATURE_UDHCP_PORT is not set | 861 | CONFIG_FEATURE_UDHCP_PORT=y |
860 | CONFIG_UDHCP_DEBUG=9 | 862 | CONFIG_UDHCP_DEBUG=9 |
861 | CONFIG_FEATURE_UDHCP_RFC3397=y | 863 | CONFIG_FEATURE_UDHCP_RFC3397=y |
862 | CONFIG_FEATURE_UDHCP_8021Q=y | 864 | CONFIG_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 | # | ||
6 | CONFIG_HAVE_DOT_CONFIG=y | ||
7 | |||
8 | # | ||
9 | # Busybox Settings | ||
10 | # | ||
11 | |||
12 | # | ||
13 | # General Configuration | ||
14 | # | ||
15 | CONFIG_DESKTOP=y | ||
16 | # CONFIG_EXTRA_COMPAT is not set | ||
17 | # CONFIG_INCLUDE_SUSv2 is not set | ||
18 | # CONFIG_USE_PORTABLE_CODE is not set | ||
19 | CONFIG_PLATFORM_LINUX=y | ||
20 | CONFIG_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 | ||
32 | CONFIG_SUBST_WCHAR=0 | ||
33 | CONFIG_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 | ||
50 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" | ||
51 | CONFIG_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 | ||
64 | CONFIG_CROSS_COMPILER_PREFIX="arm-linux-androideabi-" | ||
65 | CONFIG_SYSROOT="/opt/android-ndk/platforms/android-9/arch-arm" | ||
66 | CONFIG_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" | ||
67 | CONFIG_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" | ||
68 | CONFIG_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 | ||
77 | CONFIG_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 | # | ||
84 | CONFIG_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 | ||
91 | CONFIG_PREFIX="./_install" | ||
92 | |||
93 | # | ||
94 | # Busybox Library Tuning | ||
95 | # | ||
96 | # CONFIG_FEATURE_SYSTEMD is not set | ||
97 | # CONFIG_FEATURE_RTMINMAX is not set | ||
98 | CONFIG_PASSWORD_MINLEN=6 | ||
99 | CONFIG_MD5_SMALL=1 | ||
100 | # CONFIG_FEATURE_FAST_TOP is not set | ||
101 | # CONFIG_FEATURE_ETC_NETWORKS is not set | ||
102 | CONFIG_FEATURE_USE_TERMIOS=y | ||
103 | # CONFIG_FEATURE_EDITING is not set | ||
104 | CONFIG_FEATURE_EDITING_MAX_LEN=0 | ||
105 | # CONFIG_FEATURE_EDITING_VI is not set | ||
106 | CONFIG_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 | ||
116 | CONFIG_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 | # | ||
129 | CONFIG_FEATURE_SEAMLESS_XZ=y | ||
130 | CONFIG_FEATURE_SEAMLESS_LZMA=y | ||
131 | CONFIG_FEATURE_SEAMLESS_BZ2=y | ||
132 | CONFIG_FEATURE_SEAMLESS_GZ=y | ||
133 | CONFIG_FEATURE_SEAMLESS_Z=y | ||
134 | CONFIG_AR=y | ||
135 | CONFIG_FEATURE_AR_LONG_FILENAMES=y | ||
136 | CONFIG_FEATURE_AR_CREATE=y | ||
137 | CONFIG_BUNZIP2=y | ||
138 | CONFIG_BZIP2=y | ||
139 | CONFIG_CPIO=y | ||
140 | CONFIG_FEATURE_CPIO_O=y | ||
141 | CONFIG_FEATURE_CPIO_P=y | ||
142 | CONFIG_DPKG=y | ||
143 | CONFIG_DPKG_DEB=y | ||
144 | # CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set | ||
145 | CONFIG_GUNZIP=y | ||
146 | CONFIG_GZIP=y | ||
147 | # CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set | ||
148 | CONFIG_GZIP_FAST=0 | ||
149 | CONFIG_LZOP=y | ||
150 | CONFIG_LZOP_COMPR_HIGH=y | ||
151 | CONFIG_RPM2CPIO=y | ||
152 | CONFIG_RPM=y | ||
153 | CONFIG_TAR=y | ||
154 | CONFIG_FEATURE_TAR_CREATE=y | ||
155 | CONFIG_FEATURE_TAR_AUTODETECT=y | ||
156 | CONFIG_FEATURE_TAR_FROM=y | ||
157 | CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y | ||
158 | CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y | ||
159 | CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y | ||
160 | # CONFIG_FEATURE_TAR_LONG_OPTIONS is not set | ||
161 | # CONFIG_FEATURE_TAR_TO_COMMAND is not set | ||
162 | CONFIG_FEATURE_TAR_UNAME_GNAME=y | ||
163 | CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y | ||
164 | # CONFIG_FEATURE_TAR_SELINUX is not set | ||
165 | CONFIG_UNCOMPRESS=y | ||
166 | CONFIG_UNLZMA=y | ||
167 | CONFIG_FEATURE_LZMA_FAST=y | ||
168 | CONFIG_LZMA=y | ||
169 | CONFIG_UNXZ=y | ||
170 | CONFIG_XZ=y | ||
171 | CONFIG_UNZIP=y | ||
172 | |||
173 | # | ||
174 | # Coreutils | ||
175 | # | ||
176 | CONFIG_BASENAME=y | ||
177 | CONFIG_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 | ||
185 | CONFIG_TEST=y | ||
186 | CONFIG_FEATURE_TEST_64=y | ||
187 | CONFIG_TOUCH=y | ||
188 | CONFIG_FEATURE_TOUCH_SUSV3=y | ||
189 | CONFIG_TR=y | ||
190 | CONFIG_FEATURE_TR_CLASSES=y | ||
191 | CONFIG_FEATURE_TR_EQUIV=y | ||
192 | CONFIG_BASE64=y | ||
193 | # CONFIG_WHO is not set | ||
194 | # CONFIG_USERS is not set | ||
195 | CONFIG_CAL=y | ||
196 | CONFIG_CATV=y | ||
197 | CONFIG_CHGRP=y | ||
198 | CONFIG_CHMOD=y | ||
199 | CONFIG_CHOWN=y | ||
200 | # CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set | ||
201 | CONFIG_CHROOT=y | ||
202 | CONFIG_CKSUM=y | ||
203 | CONFIG_COMM=y | ||
204 | CONFIG_CP=y | ||
205 | # CONFIG_FEATURE_CP_LONG_OPTIONS is not set | ||
206 | CONFIG_CUT=y | ||
207 | CONFIG_DD=y | ||
208 | CONFIG_FEATURE_DD_SIGNAL_HANDLING=y | ||
209 | CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y | ||
210 | CONFIG_FEATURE_DD_IBS_OBS=y | ||
211 | # CONFIG_DF is not set | ||
212 | # CONFIG_FEATURE_DF_FANCY is not set | ||
213 | CONFIG_DIRNAME=y | ||
214 | CONFIG_DOS2UNIX=y | ||
215 | CONFIG_UNIX2DOS=y | ||
216 | CONFIG_DU=y | ||
217 | CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y | ||
218 | CONFIG_ECHO=y | ||
219 | CONFIG_FEATURE_FANCY_ECHO=y | ||
220 | CONFIG_ENV=y | ||
221 | # CONFIG_FEATURE_ENV_LONG_OPTIONS is not set | ||
222 | CONFIG_EXPAND=y | ||
223 | # CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set | ||
224 | CONFIG_EXPR=y | ||
225 | CONFIG_EXPR_MATH_SUPPORT_64=y | ||
226 | CONFIG_FALSE=y | ||
227 | CONFIG_FOLD=y | ||
228 | CONFIG_FSYNC=y | ||
229 | CONFIG_HEAD=y | ||
230 | CONFIG_FEATURE_FANCY_HEAD=y | ||
231 | CONFIG_INSTALL=y | ||
232 | # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set | ||
233 | CONFIG_LN=y | ||
234 | # CONFIG_LOGNAME is not set | ||
235 | CONFIG_LS=y | ||
236 | CONFIG_FEATURE_LS_FILETYPES=y | ||
237 | CONFIG_FEATURE_LS_FOLLOWLINKS=y | ||
238 | CONFIG_FEATURE_LS_RECURSIVE=y | ||
239 | CONFIG_FEATURE_LS_SORTFILES=y | ||
240 | CONFIG_FEATURE_LS_TIMESTAMPS=y | ||
241 | CONFIG_FEATURE_LS_USERNAME=y | ||
242 | # CONFIG_FEATURE_LS_COLOR is not set | ||
243 | # CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set | ||
244 | CONFIG_MD5SUM=y | ||
245 | CONFIG_MKDIR=y | ||
246 | # CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set | ||
247 | CONFIG_MKFIFO=y | ||
248 | CONFIG_MKNOD=y | ||
249 | CONFIG_MV=y | ||
250 | # CONFIG_FEATURE_MV_LONG_OPTIONS is not set | ||
251 | CONFIG_NICE=y | ||
252 | CONFIG_NOHUP=y | ||
253 | CONFIG_OD=y | ||
254 | CONFIG_PRINTENV=y | ||
255 | CONFIG_PRINTF=y | ||
256 | CONFIG_PWD=y | ||
257 | CONFIG_READLINK=y | ||
258 | CONFIG_FEATURE_READLINK_FOLLOW=y | ||
259 | CONFIG_REALPATH=y | ||
260 | CONFIG_RM=y | ||
261 | CONFIG_RMDIR=y | ||
262 | # CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set | ||
263 | CONFIG_SEQ=y | ||
264 | CONFIG_SHA1SUM=y | ||
265 | CONFIG_SHA256SUM=y | ||
266 | CONFIG_SHA512SUM=y | ||
267 | CONFIG_SLEEP=y | ||
268 | CONFIG_FEATURE_FANCY_SLEEP=y | ||
269 | CONFIG_FEATURE_FLOAT_SLEEP=y | ||
270 | CONFIG_SORT=y | ||
271 | CONFIG_FEATURE_SORT_BIG=y | ||
272 | CONFIG_SPLIT=y | ||
273 | CONFIG_FEATURE_SPLIT_FANCY=y | ||
274 | # CONFIG_STAT is not set | ||
275 | # CONFIG_FEATURE_STAT_FORMAT is not set | ||
276 | CONFIG_STTY=y | ||
277 | CONFIG_SUM=y | ||
278 | CONFIG_SYNC=y | ||
279 | CONFIG_TAC=y | ||
280 | CONFIG_TAIL=y | ||
281 | CONFIG_FEATURE_FANCY_TAIL=y | ||
282 | CONFIG_TEE=y | ||
283 | CONFIG_FEATURE_TEE_USE_BLOCK_IO=y | ||
284 | CONFIG_TRUE=y | ||
285 | # CONFIG_TTY is not set | ||
286 | CONFIG_UNAME=y | ||
287 | CONFIG_UNEXPAND=y | ||
288 | # CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set | ||
289 | CONFIG_UNIQ=y | ||
290 | CONFIG_USLEEP=y | ||
291 | CONFIG_UUDECODE=y | ||
292 | CONFIG_UUENCODE=y | ||
293 | CONFIG_WC=y | ||
294 | CONFIG_FEATURE_WC_LARGE=y | ||
295 | CONFIG_WHOAMI=y | ||
296 | CONFIG_YES=y | ||
297 | |||
298 | # | ||
299 | # Common options for cp and mv | ||
300 | # | ||
301 | CONFIG_FEATURE_PRESERVE_HARDLINKS=y | ||
302 | |||
303 | # | ||
304 | # Common options for ls, more and telnet | ||
305 | # | ||
306 | CONFIG_FEATURE_AUTOWIDTH=y | ||
307 | |||
308 | # | ||
309 | # Common options for df, du, ls | ||
310 | # | ||
311 | CONFIG_FEATURE_HUMAN_READABLE=y | ||
312 | |||
313 | # | ||
314 | # Common options for md5sum, sha1sum, sha256sum, sha512sum | ||
315 | # | ||
316 | CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y | ||
317 | |||
318 | # | ||
319 | # Console Utilities | ||
320 | # | ||
321 | CONFIG_CHVT=y | ||
322 | CONFIG_FGCONSOLE=y | ||
323 | CONFIG_CLEAR=y | ||
324 | CONFIG_DEALLOCVT=y | ||
325 | CONFIG_DUMPKMAP=y | ||
326 | # CONFIG_KBD_MODE is not set | ||
327 | # CONFIG_LOADFONT is not set | ||
328 | CONFIG_LOADKMAP=y | ||
329 | CONFIG_OPENVT=y | ||
330 | CONFIG_RESET=y | ||
331 | CONFIG_RESIZE=y | ||
332 | CONFIG_FEATURE_RESIZE_PRINT=y | ||
333 | CONFIG_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 | ||
337 | CONFIG_DEFAULT_SETFONT_DIR="" | ||
338 | CONFIG_SETKEYCODES=y | ||
339 | CONFIG_SETLOGCONS=y | ||
340 | CONFIG_SHOWKEY=y | ||
341 | # CONFIG_FEATURE_LOADFONT_PSF2 is not set | ||
342 | # CONFIG_FEATURE_LOADFONT_RAW is not set | ||
343 | |||
344 | # | ||
345 | # Debian Utilities | ||
346 | # | ||
347 | CONFIG_MKTEMP=y | ||
348 | CONFIG_PIPE_PROGRESS=y | ||
349 | CONFIG_RUN_PARTS=y | ||
350 | # CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set | ||
351 | CONFIG_FEATURE_RUN_PARTS_FANCY=y | ||
352 | CONFIG_START_STOP_DAEMON=y | ||
353 | CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y | ||
354 | # CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set | ||
355 | CONFIG_WHICH=y | ||
356 | |||
357 | # | ||
358 | # Editors | ||
359 | # | ||
360 | CONFIG_PATCH=y | ||
361 | CONFIG_VI=y | ||
362 | CONFIG_FEATURE_VI_MAX_LEN=4096 | ||
363 | CONFIG_FEATURE_VI_8BIT=y | ||
364 | CONFIG_FEATURE_VI_COLON=y | ||
365 | CONFIG_FEATURE_VI_YANKMARK=y | ||
366 | CONFIG_FEATURE_VI_SEARCH=y | ||
367 | # CONFIG_FEATURE_VI_REGEX_SEARCH is not set | ||
368 | CONFIG_FEATURE_VI_USE_SIGNALS=y | ||
369 | CONFIG_FEATURE_VI_DOT_CMD=y | ||
370 | CONFIG_FEATURE_VI_READONLY=y | ||
371 | CONFIG_FEATURE_VI_SETOPTS=y | ||
372 | CONFIG_FEATURE_VI_SET=y | ||
373 | CONFIG_FEATURE_VI_WIN_RESIZE=y | ||
374 | CONFIG_FEATURE_VI_ASK_TERMINAL=y | ||
375 | CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y | ||
376 | CONFIG_AWK=y | ||
377 | CONFIG_FEATURE_AWK_LIBM=y | ||
378 | CONFIG_CMP=y | ||
379 | CONFIG_DIFF=y | ||
380 | # CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set | ||
381 | CONFIG_FEATURE_DIFF_DIR=y | ||
382 | CONFIG_ED=y | ||
383 | CONFIG_SED=y | ||
384 | CONFIG_FEATURE_ALLOW_EXEC=y | ||
385 | |||
386 | # | ||
387 | # Finding Utilities | ||
388 | # | ||
389 | CONFIG_FIND=y | ||
390 | CONFIG_FEATURE_FIND_PRINT0=y | ||
391 | CONFIG_FEATURE_FIND_MTIME=y | ||
392 | CONFIG_FEATURE_FIND_MMIN=y | ||
393 | CONFIG_FEATURE_FIND_PERM=y | ||
394 | CONFIG_FEATURE_FIND_TYPE=y | ||
395 | CONFIG_FEATURE_FIND_XDEV=y | ||
396 | CONFIG_FEATURE_FIND_MAXDEPTH=y | ||
397 | CONFIG_FEATURE_FIND_NEWER=y | ||
398 | CONFIG_FEATURE_FIND_INUM=y | ||
399 | CONFIG_FEATURE_FIND_EXEC=y | ||
400 | CONFIG_FEATURE_FIND_USER=y | ||
401 | CONFIG_FEATURE_FIND_GROUP=y | ||
402 | CONFIG_FEATURE_FIND_NOT=y | ||
403 | CONFIG_FEATURE_FIND_DEPTH=y | ||
404 | CONFIG_FEATURE_FIND_PAREN=y | ||
405 | CONFIG_FEATURE_FIND_SIZE=y | ||
406 | CONFIG_FEATURE_FIND_PRUNE=y | ||
407 | CONFIG_FEATURE_FIND_DELETE=y | ||
408 | CONFIG_FEATURE_FIND_PATH=y | ||
409 | CONFIG_FEATURE_FIND_REGEX=y | ||
410 | # CONFIG_FEATURE_FIND_CONTEXT is not set | ||
411 | CONFIG_FEATURE_FIND_LINKS=y | ||
412 | CONFIG_GREP=y | ||
413 | CONFIG_FEATURE_GREP_EGREP_ALIAS=y | ||
414 | CONFIG_FEATURE_GREP_FGREP_ALIAS=y | ||
415 | CONFIG_FEATURE_GREP_CONTEXT=y | ||
416 | CONFIG_XARGS=y | ||
417 | CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y | ||
418 | CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y | ||
419 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y | ||
420 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y | ||
421 | |||
422 | # | ||
423 | # Init Utilities | ||
424 | # | ||
425 | CONFIG_BOOTCHARTD=y | ||
426 | CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y | ||
427 | CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y | ||
428 | CONFIG_HALT=y | ||
429 | # CONFIG_FEATURE_CALL_TELINIT is not set | ||
430 | CONFIG_TELINIT_PATH="" | ||
431 | CONFIG_INIT=y | ||
432 | CONFIG_FEATURE_USE_INITTAB=y | ||
433 | # CONFIG_FEATURE_KILL_REMOVED is not set | ||
434 | CONFIG_FEATURE_KILL_DELAY=0 | ||
435 | CONFIG_FEATURE_INIT_SCTTY=y | ||
436 | CONFIG_FEATURE_INIT_SYSLOG=y | ||
437 | CONFIG_FEATURE_EXTRA_QUIET=y | ||
438 | CONFIG_FEATURE_INIT_COREDUMPS=y | ||
439 | CONFIG_FEATURE_INITRD=y | ||
440 | CONFIG_INIT_TERMINAL_TYPE="linux" | ||
441 | CONFIG_MESG=y | ||
442 | CONFIG_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 | ||
457 | CONFIG_FIRST_SYSTEM_ID=0 | ||
458 | CONFIG_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 | ||
476 | CONFIG_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 | # | ||
486 | CONFIG_CHATTR=y | ||
487 | # CONFIG_FSCK is not set | ||
488 | CONFIG_LSATTR=y | ||
489 | CONFIG_TUNE2FS=y | ||
490 | |||
491 | # | ||
492 | # Linux Module Utilities | ||
493 | # | ||
494 | CONFIG_MODINFO=y | ||
495 | CONFIG_MODPROBE_SMALL=y | ||
496 | CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y | ||
497 | CONFIG_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 | ||
519 | CONFIG_DEFAULT_MODULES_DIR="/lib/modules" | ||
520 | CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" | ||
521 | |||
522 | # | ||
523 | # Linux System Utilities | ||
524 | # | ||
525 | CONFIG_BLOCKDEV=y | ||
526 | CONFIG_MDEV=y | ||
527 | CONFIG_FEATURE_MDEV_CONF=y | ||
528 | CONFIG_FEATURE_MDEV_RENAME=y | ||
529 | CONFIG_FEATURE_MDEV_RENAME_REGEXP=y | ||
530 | CONFIG_FEATURE_MDEV_EXEC=y | ||
531 | CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y | ||
532 | CONFIG_REV=y | ||
533 | # CONFIG_ACPID is not set | ||
534 | # CONFIG_FEATURE_ACPID_COMPAT is not set | ||
535 | CONFIG_BLKID=y | ||
536 | CONFIG_FEATURE_BLKID_TYPE=y | ||
537 | CONFIG_DMESG=y | ||
538 | CONFIG_FEATURE_DMESG_PRETTY=y | ||
539 | CONFIG_FBSET=y | ||
540 | CONFIG_FEATURE_FBSET_FANCY=y | ||
541 | CONFIG_FEATURE_FBSET_READMODE=y | ||
542 | CONFIG_FDFLUSH=y | ||
543 | CONFIG_FDFORMAT=y | ||
544 | CONFIG_FDISK=y | ||
545 | CONFIG_FDISK_SUPPORT_LARGE_DISKS=y | ||
546 | CONFIG_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 | ||
552 | CONFIG_FEATURE_FDISK_ADVANCED=y | ||
553 | CONFIG_FINDFS=y | ||
554 | CONFIG_FLOCK=y | ||
555 | CONFIG_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 | ||
562 | CONFIG_GETOPT=y | ||
563 | CONFIG_FEATURE_GETOPT_LONG=y | ||
564 | CONFIG_HEXDUMP=y | ||
565 | CONFIG_FEATURE_HEXDUMP_REVERSE=y | ||
566 | CONFIG_HD=y | ||
567 | CONFIG_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 | ||
572 | CONFIG_LOSETUP=y | ||
573 | CONFIG_LSPCI=y | ||
574 | CONFIG_LSUSB=y | ||
575 | CONFIG_MKSWAP=y | ||
576 | CONFIG_FEATURE_MKSWAP_UUID=y | ||
577 | CONFIG_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 | ||
589 | CONFIG_RDEV=y | ||
590 | CONFIG_READPROFILE=y | ||
591 | CONFIG_RTCWAKE=y | ||
592 | CONFIG_SCRIPT=y | ||
593 | CONFIG_SCRIPTREPLAY=y | ||
594 | # CONFIG_SETARCH is not set | ||
595 | # CONFIG_SWAPONOFF is not set | ||
596 | # CONFIG_FEATURE_SWAPON_PRI is not set | ||
597 | CONFIG_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 | ||
603 | CONFIG_VOLUMEID=y | ||
604 | |||
605 | # | ||
606 | # Filesystem/Volume identification | ||
607 | # | ||
608 | CONFIG_FEATURE_VOLUMEID_EXT=y | ||
609 | CONFIG_FEATURE_VOLUMEID_BTRFS=y | ||
610 | CONFIG_FEATURE_VOLUMEID_REISERFS=y | ||
611 | CONFIG_FEATURE_VOLUMEID_FAT=y | ||
612 | CONFIG_FEATURE_VOLUMEID_HFS=y | ||
613 | CONFIG_FEATURE_VOLUMEID_JFS=y | ||
614 | CONFIG_FEATURE_VOLUMEID_XFS=y | ||
615 | CONFIG_FEATURE_VOLUMEID_NTFS=y | ||
616 | CONFIG_FEATURE_VOLUMEID_ISO9660=y | ||
617 | CONFIG_FEATURE_VOLUMEID_UDF=y | ||
618 | CONFIG_FEATURE_VOLUMEID_LUKS=y | ||
619 | CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y | ||
620 | CONFIG_FEATURE_VOLUMEID_CRAMFS=y | ||
621 | CONFIG_FEATURE_VOLUMEID_ROMFS=y | ||
622 | CONFIG_FEATURE_VOLUMEID_SYSV=y | ||
623 | CONFIG_FEATURE_VOLUMEID_OCFS2=y | ||
624 | CONFIG_FEATURE_VOLUMEID_LINUXRAID=y | ||
625 | |||
626 | # | ||
627 | # Miscellaneous Utilities | ||
628 | # | ||
629 | # CONFIG_CONSPY is not set | ||
630 | CONFIG_LESS=y | ||
631 | CONFIG_FEATURE_LESS_MAXLINES=9999999 | ||
632 | CONFIG_FEATURE_LESS_BRACKETS=y | ||
633 | CONFIG_FEATURE_LESS_FLAGS=y | ||
634 | CONFIG_FEATURE_LESS_MARKS=y | ||
635 | CONFIG_FEATURE_LESS_REGEXP=y | ||
636 | CONFIG_FEATURE_LESS_WINCH=y | ||
637 | CONFIG_FEATURE_LESS_ASK_TERMINAL=y | ||
638 | CONFIG_FEATURE_LESS_DASHCMD=y | ||
639 | CONFIG_FEATURE_LESS_LINENUMS=y | ||
640 | # CONFIG_NANDWRITE is not set | ||
641 | CONFIG_NANDDUMP=y | ||
642 | CONFIG_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 | ||
652 | CONFIG_BEEP=y | ||
653 | CONFIG_FEATURE_BEEP_FREQ=4000 | ||
654 | CONFIG_FEATURE_BEEP_LENGTH_MS=30 | ||
655 | CONFIG_CHAT=y | ||
656 | CONFIG_FEATURE_CHAT_NOFAIL=y | ||
657 | # CONFIG_FEATURE_CHAT_TTY_HIFI is not set | ||
658 | CONFIG_FEATURE_CHAT_IMPLICIT_CR=y | ||
659 | CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y | ||
660 | CONFIG_FEATURE_CHAT_SEND_ESCAPES=y | ||
661 | CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y | ||
662 | CONFIG_FEATURE_CHAT_CLR_ABORT=y | ||
663 | CONFIG_CHRT=y | ||
664 | CONFIG_CROND=y | ||
665 | CONFIG_FEATURE_CROND_D=y | ||
666 | CONFIG_FEATURE_CROND_CALL_SENDMAIL=y | ||
667 | CONFIG_FEATURE_CROND_DIR="/var/spool/cron" | ||
668 | CONFIG_CRONTAB=y | ||
669 | CONFIG_DC=y | ||
670 | CONFIG_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 | ||
676 | CONFIG_DEVMEM=y | ||
677 | # CONFIG_EJECT is not set | ||
678 | # CONFIG_FEATURE_EJECT_SCSI is not set | ||
679 | CONFIG_FBSPLASH=y | ||
680 | CONFIG_FLASHCP=y | ||
681 | CONFIG_FLASH_LOCK=y | ||
682 | CONFIG_FLASH_UNLOCK=y | ||
683 | # CONFIG_FLASH_ERASEALL is not set | ||
684 | # CONFIG_IONICE is not set | ||
685 | CONFIG_INOTIFYD=y | ||
686 | # CONFIG_LAST is not set | ||
687 | # CONFIG_FEATURE_LAST_SMALL is not set | ||
688 | # CONFIG_FEATURE_LAST_FANCY is not set | ||
689 | CONFIG_HDPARM=y | ||
690 | CONFIG_FEATURE_HDPARM_GET_IDENTITY=y | ||
691 | CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y | ||
692 | CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y | ||
693 | CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y | ||
694 | CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y | ||
695 | CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y | ||
696 | CONFIG_MAKEDEVS=y | ||
697 | # CONFIG_FEATURE_MAKEDEVS_LEAF is not set | ||
698 | CONFIG_FEATURE_MAKEDEVS_TABLE=y | ||
699 | CONFIG_MAN=y | ||
700 | # CONFIG_MICROCOM is not set | ||
701 | # CONFIG_MOUNTPOINT is not set | ||
702 | # CONFIG_MT is not set | ||
703 | CONFIG_RAIDAUTORUN=y | ||
704 | # CONFIG_READAHEAD is not set | ||
705 | # CONFIG_RFKILL is not set | ||
706 | # CONFIG_RUNLEVEL is not set | ||
707 | CONFIG_RX=y | ||
708 | CONFIG_SETSID=y | ||
709 | CONFIG_STRINGS=y | ||
710 | # CONFIG_TASKSET is not set | ||
711 | # CONFIG_FEATURE_TASKSET_FANCY is not set | ||
712 | CONFIG_TIME=y | ||
713 | CONFIG_TIMEOUT=y | ||
714 | CONFIG_TTYSIZE=y | ||
715 | CONFIG_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 | ||
724 | CONFIG_NBDCLIENT=y | ||
725 | CONFIG_NC=y | ||
726 | CONFIG_NC_SERVER=y | ||
727 | CONFIG_NC_EXTRA=y | ||
728 | # CONFIG_NC_110_COMPAT is not set | ||
729 | CONFIG_PING=y | ||
730 | # CONFIG_PING6 is not set | ||
731 | CONFIG_FEATURE_FANCY_PING=y | ||
732 | CONFIG_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 | ||
737 | CONFIG_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 | ||
742 | CONFIG_DNSD=y | ||
743 | # CONFIG_ETHER_WAKE is not set | ||
744 | CONFIG_FAKEIDENTD=y | ||
745 | CONFIG_FTPD=y | ||
746 | CONFIG_FEATURE_FTP_WRITE=y | ||
747 | CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y | ||
748 | CONFIG_FTPGET=y | ||
749 | CONFIG_FTPPUT=y | ||
750 | # CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set | ||
751 | # CONFIG_HOSTNAME is not set | ||
752 | CONFIG_HTTPD=y | ||
753 | CONFIG_FEATURE_HTTPD_RANGES=y | ||
754 | CONFIG_FEATURE_HTTPD_USE_SENDFILE=y | ||
755 | CONFIG_FEATURE_HTTPD_SETUID=y | ||
756 | CONFIG_FEATURE_HTTPD_BASIC_AUTH=y | ||
757 | # CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set | ||
758 | CONFIG_FEATURE_HTTPD_CGI=y | ||
759 | CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y | ||
760 | CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y | ||
761 | CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y | ||
762 | CONFIG_FEATURE_HTTPD_ERROR_PAGES=y | ||
763 | CONFIG_FEATURE_HTTPD_PROXY=y | ||
764 | CONFIG_FEATURE_HTTPD_GZIP=y | ||
765 | CONFIG_IFCONFIG=y | ||
766 | CONFIG_FEATURE_IFCONFIG_STATUS=y | ||
767 | # CONFIG_FEATURE_IFCONFIG_SLIP is not set | ||
768 | CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y | ||
769 | CONFIG_FEATURE_IFCONFIG_HW=y | ||
770 | CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y | ||
771 | # CONFIG_IFENSLAVE is not set | ||
772 | # CONFIG_IFPLUGD is not set | ||
773 | CONFIG_IFUPDOWN=y | ||
774 | CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" | ||
775 | CONFIG_FEATURE_IFUPDOWN_IP=y | ||
776 | CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y | ||
777 | # CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set | ||
778 | CONFIG_FEATURE_IFUPDOWN_IPV4=y | ||
779 | # CONFIG_FEATURE_IFUPDOWN_IPV6 is not set | ||
780 | CONFIG_FEATURE_IFUPDOWN_MAPPING=y | ||
781 | CONFIG_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 | ||
789 | CONFIG_IP=y | ||
790 | CONFIG_FEATURE_IP_ADDRESS=y | ||
791 | CONFIG_FEATURE_IP_LINK=y | ||
792 | CONFIG_FEATURE_IP_ROUTE=y | ||
793 | CONFIG_FEATURE_IP_TUNNEL=y | ||
794 | CONFIG_FEATURE_IP_RULE=y | ||
795 | CONFIG_FEATURE_IP_SHORT_FORMS=y | ||
796 | # CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set | ||
797 | CONFIG_IPADDR=y | ||
798 | CONFIG_IPLINK=y | ||
799 | CONFIG_IPROUTE=y | ||
800 | CONFIG_IPTUNNEL=y | ||
801 | CONFIG_IPRULE=y | ||
802 | CONFIG_IPCALC=y | ||
803 | CONFIG_FEATURE_IPCALC_FANCY=y | ||
804 | # CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set | ||
805 | CONFIG_NETSTAT=y | ||
806 | CONFIG_FEATURE_NETSTAT_WIDE=y | ||
807 | CONFIG_FEATURE_NETSTAT_PRG=y | ||
808 | # CONFIG_NSLOOKUP is not set | ||
809 | # CONFIG_NTPD is not set | ||
810 | # CONFIG_FEATURE_NTPD_SERVER is not set | ||
811 | CONFIG_PSCAN=y | ||
812 | CONFIG_ROUTE=y | ||
813 | # CONFIG_SLATTACH is not set | ||
814 | CONFIG_TCPSVD=y | ||
815 | CONFIG_TELNET=y | ||
816 | CONFIG_FEATURE_TELNET_TTYPE=y | ||
817 | CONFIG_FEATURE_TELNET_AUTOLOGIN=y | ||
818 | CONFIG_TELNETD=y | ||
819 | CONFIG_FEATURE_TELNETD_STANDALONE=y | ||
820 | CONFIG_FEATURE_TELNETD_INETD_WAIT=y | ||
821 | CONFIG_TFTP=y | ||
822 | CONFIG_TFTPD=y | ||
823 | |||
824 | # | ||
825 | # Common options for tftp/tftpd | ||
826 | # | ||
827 | CONFIG_FEATURE_TFTP_GET=y | ||
828 | CONFIG_FEATURE_TFTP_PUT=y | ||
829 | CONFIG_FEATURE_TFTP_BLOCKSIZE=y | ||
830 | CONFIG_FEATURE_TFTP_PROGRESS_BAR=y | ||
831 | # CONFIG_TFTP_DEBUG is not set | ||
832 | CONFIG_TRACEROUTE=y | ||
833 | # CONFIG_TRACEROUTE6 is not set | ||
834 | CONFIG_FEATURE_TRACEROUTE_VERBOSE=y | ||
835 | # CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set | ||
836 | # CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set | ||
837 | CONFIG_TUNCTL=y | ||
838 | CONFIG_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 | ||
845 | CONFIG_DHCPD_LEASES_FILE="" | ||
846 | CONFIG_UDHCPC=y | ||
847 | CONFIG_FEATURE_UDHCPC_ARPING=y | ||
848 | CONFIG_FEATURE_UDHCP_PORT=y | ||
849 | CONFIG_UDHCP_DEBUG=9 | ||
850 | CONFIG_FEATURE_UDHCP_RFC3397=y | ||
851 | CONFIG_FEATURE_UDHCP_8021Q=y | ||
852 | CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" | ||
853 | CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 | ||
854 | CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" | ||
855 | CONFIG_UDPSVD=y | ||
856 | CONFIG_VCONFIG=y | ||
857 | CONFIG_WGET=y | ||
858 | CONFIG_FEATURE_WGET_STATUSBAR=y | ||
859 | CONFIG_FEATURE_WGET_AUTHENTICATION=y | ||
860 | # CONFIG_FEATURE_WGET_LONG_OPTIONS is not set | ||
861 | CONFIG_FEATURE_WGET_TIMEOUT=y | ||
862 | # CONFIG_ZCIP is not set | ||
863 | |||
864 | # | ||
865 | # Print Utilities | ||
866 | # | ||
867 | CONFIG_LPD=y | ||
868 | CONFIG_LPR=y | ||
869 | CONFIG_LPQ=y | ||
870 | |||
871 | # | ||
872 | # Mail Utilities | ||
873 | # | ||
874 | CONFIG_MAKEMIME=y | ||
875 | CONFIG_FEATURE_MIME_CHARSET="us-ascii" | ||
876 | CONFIG_POPMAILDIR=y | ||
877 | CONFIG_FEATURE_POPMAILDIR_DELIVERY=y | ||
878 | CONFIG_REFORMIME=y | ||
879 | CONFIG_FEATURE_REFORMIME_COMPAT=y | ||
880 | CONFIG_SENDMAIL=y | ||
881 | |||
882 | # | ||
883 | # Process Utilities | ||
884 | # | ||
885 | CONFIG_IOSTAT=y | ||
886 | CONFIG_MPSTAT=y | ||
887 | CONFIG_NMETER=y | ||
888 | CONFIG_PMAP=y | ||
889 | CONFIG_POWERTOP=y | ||
890 | CONFIG_PSTREE=y | ||
891 | CONFIG_PWDX=y | ||
892 | CONFIG_SMEMCAP=y | ||
893 | CONFIG_UPTIME=y | ||
894 | # CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set | ||
895 | CONFIG_FREE=y | ||
896 | CONFIG_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 | ||
901 | CONFIG_PIDOF=y | ||
902 | CONFIG_FEATURE_PIDOF_SINGLE=y | ||
903 | CONFIG_FEATURE_PIDOF_OMIT=y | ||
904 | # CONFIG_PKILL is not set | ||
905 | CONFIG_PS=y | ||
906 | # CONFIG_FEATURE_PS_WIDE is not set | ||
907 | # CONFIG_FEATURE_PS_LONG is not set | ||
908 | CONFIG_FEATURE_PS_TIME=y | ||
909 | CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y | ||
910 | # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set | ||
911 | CONFIG_RENICE=y | ||
912 | CONFIG_BB_SYSCTL=y | ||
913 | CONFIG_TOP=y | ||
914 | CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y | ||
915 | CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y | ||
916 | CONFIG_FEATURE_TOP_SMP_CPU=y | ||
917 | CONFIG_FEATURE_TOP_DECIMALS=y | ||
918 | CONFIG_FEATURE_TOP_SMP_PROCESS=y | ||
919 | CONFIG_FEATURE_TOPMEM=y | ||
920 | CONFIG_FEATURE_SHOW_THREADS=y | ||
921 | CONFIG_WATCH=y | ||
922 | |||
923 | # | ||
924 | # Runit Utilities | ||
925 | # | ||
926 | CONFIG_RUNSV=y | ||
927 | CONFIG_RUNSVDIR=y | ||
928 | # CONFIG_FEATURE_RUNSVDIR_LOG is not set | ||
929 | CONFIG_SV=y | ||
930 | CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" | ||
931 | CONFIG_SVLOGD=y | ||
932 | CONFIG_CHPST=y | ||
933 | CONFIG_SETUIDGID=y | ||
934 | CONFIG_ENVUIDGID=y | ||
935 | CONFIG_ENVDIR=y | ||
936 | CONFIG_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 | ||
970 | CONFIG_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 | ||
990 | CONFIG_FEATURE_SH_IS_NONE=y | ||
991 | # CONFIG_FEATURE_BASH_IS_ASH is not set | ||
992 | # CONFIG_FEATURE_BASH_IS_HUSH is not set | ||
993 | CONFIG_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 | ||
1009 | CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 | ||
1010 | # CONFIG_FEATURE_IPC_SYSLOG is not set | ||
1011 | CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 | ||
1012 | # CONFIG_LOGREAD is not set | ||
1013 | # CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set | ||
1014 | CONFIG_KLOGD=y | ||
1015 | CONFIG_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 | ||
94 | static void print(unsigned long size, const char *filename) | 92 | static 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 */ |
113 | static unsigned long du(const char *filename) | 111 | static 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) | |||
190 | int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 188 | int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
191 | int du_main(int argc UNUSED_PARAM, char **argv) | 189 | int 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 = | |||
54 | int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 54 | int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
55 | int mkdir_main(int argc UNUSED_PARAM, char **argv) | 55 | int 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 */ | ||
135 | static void print_esc_string(const char *str) | 135 | static 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 |
32 | with /proc/$PID/exe or argv[0] (comm can't be matched, it never contains path)] | 32 | with /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) | |||
282 | static int parse_regex_delim(const char *cmdstr, char **match, char **replace) | 282 | static 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 | |||
68 | option dns 129.219.13.81 # appended to above DNS servers for a total of 3 | 68 | option dns 129.219.13.81 # appended to above DNS servers for a total of 3 |
69 | option domain local | 69 | option domain local |
70 | option lease 864000 # default: 10 days | 70 | option lease 864000 # default: 10 days |
71 | option msstaticroutes 10.0.0.0/8 10.127.0.1 # single static route | ||
72 | option 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: |
72 | option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" | 74 | option 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 */ | ||
159 | typedef struct unpack_info_t { | ||
160 | time_t mtime; | ||
161 | } unpack_info_t; | ||
162 | |||
163 | archive_handle_t *init_handle(void) FAST_FUNC; | 159 | archive_handle_t *init_handle(void) FAST_FUNC; |
164 | 160 | ||
165 | char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC; | 161 | char 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_ | |||
202 | int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; | 198 | int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; |
203 | void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; | 199 | void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; |
204 | 200 | ||
205 | typedef struct inflate_unzip_result { | 201 | /* Meaning and direction (input/output) of the fields are transformer-specific */ |
206 | off_t bytes_out; | 202 | typedef 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 */ | |
210 | IF_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 */ |
212 | IF_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 | |
214 | IF_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; | 210 | void init_transformer_aux_data(transformer_aux_data_t *aux) FAST_FUNC; |
215 | /* the rest wants 2 first bytes already skipped by the caller */ | 211 | int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) FAST_FUNC; |
216 | IF_DESKTOP(long long) int unpack_bz2_stream(int src_fd, int dst_fd) FAST_FUNC; | 212 | |
217 | IF_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd) FAST_FUNC; | 213 | IF_DESKTOP(long long) int inflate_unzip(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; |
218 | IF_DESKTOP(long long) int unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) FAST_FUNC; | 214 | IF_DESKTOP(long long) int unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; |
219 | IF_DESKTOP(long long) int unpack_Z_stream(int src_fd, int dst_fd) FAST_FUNC; | 215 | IF_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" */ | 216 | IF_DESKTOP(long long) int unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; |
221 | IF_DESKTOP(long long) int unpack_bz2_stream_prime(int src_fd, int dst_fd) FAST_FUNC; | 217 | IF_DESKTOP(long long) int unpack_lzma_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; |
218 | IF_DESKTOP(long long) int unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; | ||
222 | 219 | ||
223 | char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; | 220 | char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; |
224 | int bbunpack(char **argv, | 221 | int 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 | ||
227 | void check_errors_in_children(int signo); | ||
230 | #if BB_MMU | 228 | #if BB_MMU |
231 | void open_transformer(int fd, | 229 | void 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 |
235 | void open_transformer(int src_fd, const char *transform_prog) FAST_FUNC; | 236 | void 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 | |||
239 | POP_SAVED_FUNCTION_VISIBILITY | 242 | POP_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 */ |
226 | typedef unsigned long uoff_t; | 230 | typedef 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" */ |
235 | typedef unsigned long long uoff_t; | 239 | typedef 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 |
252 | typedef unsigned long uoff_t; | 256 | typedef 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 | */ | ||
268 | struct 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)? |
323 | extern const char *bb_mode_string(mode_t mode) FAST_FUNC; | 333 | extern const char *bb_mode_string(mode_t mode) FAST_FUNC; |
324 | extern int is_directory(const char *name, int followLinks, struct stat *statBuf) FAST_FUNC; | 334 | extern int is_directory(const char *name, int followLinks) FAST_FUNC; |
325 | enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */ | 335 | enum { /* 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 | ||
575 | int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC; | 584 | int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC; |
576 | #else | ||
577 | int 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 | ||
580 | int xsocket_stream(len_and_sockaddr **lsap) FAST_FUNC; | 585 | int 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; | |||
721 | extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; | 726 | extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; |
722 | /* Never returns NULL */ | 727 | /* Never returns NULL */ |
723 | extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; | 728 | extern 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) |
729 | extern 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 | 739 | extern int setup_unzip_on_fd(int fd, int fail_if_not_detected) FAST_FUNC; |
733 | /* Autodetects .gz etc */ | 740 | /* Autodetects .gz etc */ |
734 | extern int open_zipped(const char *fname) FAST_FUNC; | 741 | extern 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 | ||
735 | extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; | 746 | extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; |
736 | 747 | ||
737 | extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC; | 748 | extern 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 | }; |
1208 | typedef struct parser_t { | 1224 | typedef 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 | ||
21 | char *get_devname_from_label(const char *spec); | 21 | char *get_devname_from_label(const char *spec); |
22 | char *get_devname_from_uuid(const char *spec); | 22 | char *get_devname_from_uuid(const char *spec); |
23 | void display_uuid_cache(void); | 23 | void 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 | } |
171 | static ALWAYS_INLINE | ||
172 | int32_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 | ||
211 | static void do_logging(unsigned sample_period_us) | 211 | static 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 | ||
260 | static void finalize(char *tempdir, const char *prog) | 257 | static 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 | ||
972 | static | ||
973 | void 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 | |||
957 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 998 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
958 | int init_main(int argc UNUSED_PARAM, char **argv) | 999 | int 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 | ||
39 | static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr) | 39 | static 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 | ||
70 | long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base) | 73 | long 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 | ||
98 | long FAST_FUNC bb_strtol(const char *arg, char **endp, int base) | 108 | long 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 | ||
125 | int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base) | 142 | int 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) | |||
99 | static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) | 100 | static 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 | */ |
18 | int FAST_FUNC is_directory(const char *fileName, int followLinks, struct stat *statBuf) | 18 | int 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 */ |
145 | static unsigned long fast_strtoul_10(char **endptr) | 146 | static 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 | ||
252 | void 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 | |||
329 | int 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 | |||
360 | void* 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 | 325 | int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, int family, int sock_type) |
326 | int 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 | ||
358 | int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap) | 360 | int 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 | ||
363 | static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type) | 365 | static 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 | ||
50 | struct statics { | 48 | struct 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 | ||
94 | static struct statics *ptr_to_statics; | 70 | static struct statics *ptr_to_statics; |
@@ -182,22 +158,22 @@ int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf, | |||
182 | struct passwd *fgetpwent(FILE *stream) | 158 | struct 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 | ||
193 | struct group *fgetgrent(FILE *stream) | 169 | struct 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) | |||
207 | struct spwd *fgetspent(FILE *stream) | 183 | struct 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, | |||
299 | struct passwd *getpwuid(uid_t uid) | 275 | struct 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) | |||
311 | struct group *getgrgid(gid_t gid) | 287 | struct 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, | |||
346 | struct spwd *getspuid(uid_t uid) | 322 | struct 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) | |||
359 | struct passwd *getpwnam(const char *name) | 335 | struct 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) | |||
371 | struct group *getgrnam(const char *name) | 347 | struct 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) | |||
383 | struct spwd *getspnam(const char *name) | 359 | struct 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 | ||
286 | config 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 | |||
286 | config SU | 293 | config 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 |
24 | static const char chpasswd_longopts[] ALIGN1 = | 26 | static 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) | |||
119 | void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol) | 119 | void 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 | |||
144 | int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 166 | int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
145 | int makemime_main(int argc UNUSED_PARAM, char **argv) | 167 | int 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 | |||
43 | static int show_manpage(const char *pager, char *man_filename, int man, int level); | 33 | static int show_manpage(const char *pager, char *man_filename, int man, int level); |
44 | 34 | ||
45 | static int run_pipe(const char *pager, char *man_filename, int man, int level) | 35 | static 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" */ |
128 | static int show_manpage(const char *pager, char *man_filename, int man, int level) | 118 | static 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 | */ |
160 | enum { | 169 | enum { |
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" |
111 | enum { | 114 | enum { |
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 | ||
203 | config FEATURE_HTTPD_AUTH_MD5 | 205 | config 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 | ||
211 | config FEATURE_HTTPD_CGI | 219 | config 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 | ||
230 | config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV | 238 | config 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 |
340 | enum { | 350 | enum { |
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 | */ |
1262 | static void send_cgi_and_exit( | 1274 | static 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; |
1268 | static void send_cgi_and_exit( | 1281 | static 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 | ||
1680 | struct pam_userinfo { | ||
1681 | const char *name; | ||
1682 | const char *pw; | ||
1683 | }; | ||
1684 | |||
1685 | static 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 | */ |
1670 | static int check_user_passwd(const char *path, const char *user_and_passwd) | 1737 | static 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! */ |
161 | enum { | 161 | enum { |
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); | |||
263 | static int doexec(char **proggie) NORETURN; | 262 | static int doexec(char **proggie) NORETURN; |
264 | static int doexec(char **proggie) | 263 | static 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 | ||
210 | typedef struct { | 214 | typedef 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 | ||
261 | struct globals { | 265 | struct 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 | |||
500 | filter_datapoints(peer_t *p) | 517 | filter_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( | |||
434 | int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) | 436 | int 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 */ | ||
567 | int 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 */ | ||
315 | int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) FAST_FUNC; | ||
316 | |||
311 | POP_SAVED_FUNCTION_VISIBILITY | 317 | POP_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 | |||
12 | PUSH_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 | |||
32 | struct 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 | |||
43 | struct ip6_udp_d6_packet { | ||
44 | struct ip6_hdr ip6; | ||
45 | struct udphdr udp; | ||
46 | struct d6_packet data; | ||
47 | } PACKED; | ||
48 | |||
49 | struct udp_d6_packet { | ||
50 | struct udphdr udp; | ||
51 | struct d6_packet data; | ||
52 | } PACKED; | ||
53 | |||
54 | /*** Options ***/ | ||
55 | |||
56 | struct 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 | |||
89 | struct 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 | |||
98 | int FAST_FUNC d6_listen_socket(int port, const char *inf); | ||
99 | |||
100 | int FAST_FUNC d6_recv_kernel_packet( | ||
101 | struct in6_addr *peer_ipv6, | ||
102 | struct d6_packet *packet, int fd | ||
103 | ); | ||
104 | |||
105 | int 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 | |||
112 | int 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 | |||
118 | void FAST_FUNC d6_dump_packet(struct d6_packet *packet); | ||
119 | |||
120 | |||
121 | POP_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 | ||
41 | static 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 */ | ||
62 | enum { | ||
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 | |||
91 | static 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 | |||
115 | static 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 | |||
123 | static 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 | |||
132 | static 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 */ | ||
139 | static 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 | |||
225 | static 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 */ | ||
245 | static 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 | |||
269 | static 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 */ | ||
276 | static 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 | |||
289 | static 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 | |||
304 | static 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 */ | ||
401 | static 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 */ | ||
465 | static 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 */ | ||
534 | static 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 */ | ||
563 | static 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 */ | ||
585 | static 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 | |||
647 | static int sockfd = -1; | ||
648 | |||
649 | #define LISTEN_NONE 0 | ||
650 | #define LISTEN_KERNEL 1 | ||
651 | #define LISTEN_RAW 2 | ||
652 | static 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 | ||
668 | static smallint state; | ||
669 | |||
670 | static 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 | |||
749 | static 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 */ | ||
770 | static 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 | |||
792 | static 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 | ||
818 | static 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 | |||
909 | int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
910 | int 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 | ||
15 | void 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 | |||
29 | int 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 */ | ||
53 | int 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 */ | ||
127 | int 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 | |||
11 | int 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 | ||
127 | static 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 */ |
146 | static int mton(uint32_t mask) | 127 | static 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 | */ | ||
149 | static 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 */ | ||
179 | static 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 */ |
158 | static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name) | 196 | static 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 */ |
745 | static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t requested) | 790 | static 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 | ||
1007 | static void perform_release(uint32_t requested_ip, uint32_t server_addr) | 1053 | static 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 | ||
1139 | int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1183 | int 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) | |||
81 | int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) | 81 | int 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. */ |
67 | static const char *xfind_str(const char *table, const char *str) | 67 | static 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 | ||
78 | static const char cmds[] ALIGN1 = { | 77 | static 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 | ||
100 | static const char name_types[] ALIGN1 = { | 92 | static 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 | ||
119 | static const char conf_file_name[] ALIGN1 = "/proc/net/vlan/config"; | ||
120 | |||
121 | int vconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 103 | int vconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
122 | int vconfig_main(int argc, char **argv) | 104 | int 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 | ||
854 | int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 856 | int 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 | # |
6 | CONFIG_HAVE_DOT_CONFIG=y | 6 | CONFIG_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 |
67 | CONFIG_CROSS_COMPILER_PREFIX="i686-pc-mingw32-" | 67 | CONFIG_CROSS_COMPILER_PREFIX="i686-pc-mingw32-" |
68 | CONFIG_SYSROOT="" | ||
68 | CONFIG_EXTRA_CFLAGS="-g -O0" | 69 | CONFIG_EXTRA_CFLAGS="-g -O0" |
70 | CONFIG_EXTRA_LDFLAGS="" | ||
71 | CONFIG_EXTRA_LDLIBS="" | ||
69 | 72 | ||
70 | # | 73 | # |
71 | # Debugging Options | 74 | # Debugging Options |
@@ -184,6 +187,7 @@ CONFIG_FEATURE_DATE_COMPAT=y | |||
184 | CONFIG_TEST=y | 187 | CONFIG_TEST=y |
185 | CONFIG_FEATURE_TEST_64=y | 188 | CONFIG_FEATURE_TEST_64=y |
186 | CONFIG_TOUCH=y | 189 | CONFIG_TOUCH=y |
190 | # CONFIG_FEATURE_TOUCH_SUSV3 is not set | ||
187 | CONFIG_TR=y | 191 | CONFIG_TR=y |
188 | CONFIG_FEATURE_TR_CLASSES=y | 192 | CONFIG_FEATURE_TR_CLASSES=y |
189 | CONFIG_FEATURE_TR_EQUIV=y | 193 | CONFIG_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 |
478 | CONFIG_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 |
55 | sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\@p' "$srctree"/*/*.c "$srctree"/*/*/*.c \ | 55 | sed -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 | "" "" |
171 | SKIP= | 171 | SKIP= |
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") | ||
175 | optional UUDECODE FEATURE_TAR_AUTODETECT FEATURE_SEAMLESS_XZ | ||
176 | testing "tar extract txz" "\ | ||
177 | uudecode -o input && tar tf input && echo Ok | ||
178 | " "\ | ||
179 | hello_world | ||
180 | Ok | ||
181 | " \ | ||
182 | "" "\ | ||
183 | begin-base64 644 hello_world.txz | ||
184 | /Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AX/AEldADQZSe6ODIZQ3rSQ8kAJ | ||
185 | SnMPTX+XWGKW3Yu/Rwqg4Ik5wqgQKgVH97J8yA8IvZ4ahaCQogUNHRkXibr2 | ||
186 | Q615wcb2G7fJU49AhWAAAAAAUA8gu9DyXfAAAWWADAAAAB5FXGCxxGf7AgAA | ||
187 | AAAEWVo= | ||
188 | ==== | ||
189 | " | ||
190 | SKIP= | ||
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 |
174 | optional FEATURE_TAR_CREATE | 193 | optional FEATURE_TAR_CREATE |
175 | testing "tar strips /../ on extract" "\ | 194 | testing "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 | ||
487 | config FEATURE_MOUNT_NFS | 487 | config 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 | ||
496 | config FEATURE_MOUNT_CIFS | 501 | config 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) | |||
225 | int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 225 | int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
226 | int acpid_main(int argc UNUSED_PARAM, char **argv) | 226 | int 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 | |||
20 | int blkid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 18 | int blkid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
21 | int blkid_main(int argc UNUSED_PARAM, char **argv) | 19 | int 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 = | |||
339 | int getopt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 356 | int getopt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
340 | int getopt_main(int argc, char **argv) | 357 | int 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 | ||
822 | struct nfs2_fh { | 822 | struct nfs2_fh { |
823 | char data[32]; | 823 | char data[32]; |
824 | }; | 824 | }; |
825 | struct nfs3_fh { | 825 | struct nfs3_fh { |
826 | unsigned short size; | 826 | unsigned short size; |
827 | unsigned char data[64]; | 827 | unsigned char data[64]; |
828 | }; | 828 | }; |
829 | 829 | ||
830 | struct nfs_mount_data { | 830 | struct 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. |
1704 | int 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 | */ | ||
1714 | static 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 @@ | |||
23 | int rdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 23 | int rdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
24 | int rdev_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 24 | int 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 | ||
117 | static void | 117 | static struct uuidCache_s* |
118 | uuidcache_init(void) | 118 | uuidcache_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 */ |
218 | void display_uuid_cache(void) | 218 | void 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) { |