aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2018-07-25 10:41:42 +0100
committerRon Yorston <rmy@pobox.com>2018-07-25 10:41:42 +0100
commit59873514f17cefd6ba3997dad5779f75433fd4e6 (patch)
tree1c9d0a3450ed95f0b820285b9f9fc217c902e652
parent779fd5745ac11bf752f5f4b977a274a39c192f90 (diff)
parent81de30de05beebabfa72f2a01ec4f33e9a1923e3 (diff)
downloadbusybox-w32-59873514f17cefd6ba3997dad5779f75433fd4e6.tar.gz
busybox-w32-59873514f17cefd6ba3997dad5779f75433fd4e6.tar.bz2
busybox-w32-59873514f17cefd6ba3997dad5779f75433fd4e6.zip
Merge branch 'busybox'
-rw-r--r--Config.in2
-rw-r--r--Makefile2
-rw-r--r--archival/Config.src2
-rw-r--r--archival/cpio.c11
-rw-r--r--archival/gzip.c12
-rw-r--r--archival/libarchive/data_extract_all.c16
-rw-r--r--archival/libarchive/decompress_unlzma.c6
-rw-r--r--archival/libarchive/get_header_ar.c2
-rw-r--r--archival/libarchive/unsafe_symlink_target.c21
-rw-r--r--archival/tar.c2
-rw-r--r--archival/unzip.c7
-rw-r--r--console-tools/Config.src2
-rw-r--r--coreutils/Config.src2
-rw-r--r--coreutils/cp.c24
-rw-r--r--coreutils/install.c6
-rw-r--r--coreutils/nproc.c44
-rw-r--r--coreutils/readlink.c2
-rw-r--r--coreutils/realpath.c2
-rw-r--r--coreutils/sort.c47
-rw-r--r--debianutils/Config.src2
-rw-r--r--docs/Kconfig-language.txt255
-rw-r--r--e2fsprogs/Config.src2
-rw-r--r--e2fsprogs/fsck.c17
-rw-r--r--editors/Config.src2
-rw-r--r--editors/vi.c61
-rw-r--r--examples/var_service/dhcp_if/README5
-rwxr-xr-xexamples/var_service/dhcp_if/dhcp_handler10
-rwxr-xr-xexamples/var_service/dhcp_if/finish2
-rwxr-xr-xexamples/var_service/dhcp_if/log/run21
-rwxr-xr-xexamples/var_service/dhcp_if/p_log4
-rwxr-xr-xexamples/var_service/dhcp_if/w_log4
-rw-r--r--examples/var_service/dhcp_if_pinger/README5
-rwxr-xr-xexamples/var_service/dhcp_if_pinger/run16
-rw-r--r--examples/var_service/dhcpd_if/README5
-rwxr-xr-xexamples/var_service/dhcpd_if/log/run21
-rwxr-xr-xexamples/var_service/dhcpd_if/p_log4
-rwxr-xr-xexamples/var_service/dhcpd_if/w_log4
-rwxr-xr-xexamples/var_service/dnsmasq/log/run21
-rwxr-xr-xexamples/var_service/dnsmasq/p_log4
-rwxr-xr-xexamples/var_service/dnsmasq/w_log4
-rw-r--r--examples/var_service/ftpd/README5
-rwxr-xr-xexamples/var_service/ftpd/log/run21
-rwxr-xr-xexamples/var_service/ftpd/p_log4
-rwxr-xr-xexamples/var_service/ftpd/w_log4
-rw-r--r--examples/var_service/fw/README5
-rw-r--r--examples/var_service/fw/etc/dnsmasq_servers.conf2
-rwxr-xr-xexamples/var_service/fw/run2
-rw-r--r--examples/var_service/getty_tty1/README5
-rwxr-xr-xexamples/var_service/getty_tty1/cfg8
-rwxr-xr-xexamples/var_service/getty_tty1/login.sh3
-rw-r--r--examples/var_service/getty_tty1/ru_koi8r.keymap183
-rwxr-xr-xexamples/var_service/getty_tty1/run6
-rw-r--r--examples/var_service/getty_tty1/unicode_cyrillic.keymap200
-rw-r--r--examples/var_service/gpm/README5
-rw-r--r--examples/var_service/httpd/README5
-rwxr-xr-xexamples/var_service/httpd/log/run21
-rwxr-xr-xexamples/var_service/httpd/p_log4
-rwxr-xr-xexamples/var_service/httpd/w_log4
-rw-r--r--examples/var_service/ifplugd_if/README5
-rwxr-xr-xexamples/var_service/ifplugd_if/ifplugd_handler23
-rwxr-xr-xexamples/var_service/ifplugd_if/log/run21
-rwxr-xr-xexamples/var_service/ifplugd_if/p_log4
-rwxr-xr-xexamples/var_service/ifplugd_if/w_log4
-rw-r--r--examples/var_service/inetd/README5
-rwxr-xr-xexamples/var_service/inetd/log/run21
-rwxr-xr-xexamples/var_service/inetd/p_log4
-rwxr-xr-xexamples/var_service/inetd/w_log4
-rw-r--r--examples/var_service/nmeter/README5
-rw-r--r--examples/var_service/ntpd/README5
-rwxr-xr-xexamples/var_service/ntpd/log/run21
-rwxr-xr-xexamples/var_service/ntpd/p_log4
-rwxr-xr-xexamples/var_service/ntpd/run25
-rwxr-xr-xexamples/var_service/ntpd/w_log4
-rwxr-xr-xexamples/var_service/std_service_logger32
-rw-r--r--examples/var_service/supplicant_if/README5
-rwxr-xr-xexamples/var_service/supplicant_if/log/run21
-rwxr-xr-xexamples/var_service/supplicant_if/p_log4
-rwxr-xr-xexamples/var_service/supplicant_if/w_log4
-rwxr-xr-xexamples/var_service/sview19
-rwxr-xr-xexamples/var_service/svpage19
-rw-r--r--examples/var_service/tftpd/README5
-rwxr-xr-xexamples/var_service/tftpd/log/run21
-rwxr-xr-xexamples/var_service/tftpd/p_log4
-rwxr-xr-xexamples/var_service/tftpd/w_log4
-rw-r--r--examples/var_service/zcip_if/README5
-rwxr-xr-xexamples/var_service/zcip_if/finish4
-rwxr-xr-xexamples/var_service/zcip_if/log/run21
-rwxr-xr-xexamples/var_service/zcip_if/p_log4
-rwxr-xr-xexamples/var_service/zcip_if/w_log4
-rwxr-xr-xexamples/var_service/zcip_if/zcip_handler4
-rw-r--r--findutils/Config.src2
-rw-r--r--findutils/find.c56
-rw-r--r--findutils/grep.c11
-rw-r--r--findutils/xargs.c2
-rw-r--r--include/bb_archive.h17
-rw-r--r--include/libbb.h4
-rw-r--r--init/Config.src2
-rw-r--r--klibc-utils/Config.src2
-rw-r--r--libbb/Config.src2
-rw-r--r--libbb/appletlib.c9
-rw-r--r--libbb/copy_file.c19
-rw-r--r--libbb/dump.c14
-rw-r--r--libbb/loop.c4
-rw-r--r--libbb/nuke_str.c2
-rw-r--r--libbb/pw_encrypt.c1
-rw-r--r--libbb/xfuncs_printf.c1
-rw-r--r--libbb/xreadlink.c30
-rw-r--r--loginutils/Config.src2
-rw-r--r--mailutils/popmaildir.c2
-rw-r--r--mailutils/sendmail.c2
-rw-r--r--miscutils/Config.src2
-rw-r--r--miscutils/hexedit.c5
-rw-r--r--modutils/Config.src2
-rw-r--r--networking/Config.src2
-rw-r--r--networking/nc_bloaty.c2
-rw-r--r--networking/nslookup.c2
-rw-r--r--networking/ntpd.c17
-rw-r--r--networking/tls.c20
-rw-r--r--networking/udhcp/Config.src2
-rw-r--r--networking/udhcp/common.c118
-rw-r--r--networking/udhcp/common.h68
-rw-r--r--networking/udhcp/d6_common.h3
-rw-r--r--networking/udhcp/d6_dhcpc.c117
-rw-r--r--networking/udhcp/dhcpc.c15
-rw-r--r--networking/udhcp/dhcpd.c9
-rw-r--r--networking/udhcp/packet.c7
-rw-r--r--networking/wget.c10
-rw-r--r--printutils/Config.src2
-rw-r--r--procps/Config.src2
-rw-r--r--runit/Config.src2
-rwxr-xr-xscripts/bb_release22
-rwxr-xr-xscripts/randomtest7
-rw-r--r--selinux/Config.src2
-rw-r--r--shell/Config.src2
-rw-r--r--shell/ash.c3
-rw-r--r--shell/ash_test/ash-glob/glob_altvalue1.right7
-rwxr-xr-xshell/ash_test/ash-glob/glob_altvalue1.tests13
-rw-r--r--shell/ash_test/ash-heredoc/heredoc.right2
-rw-r--r--shell/ash_test/ash-heredoc/heredocA.right1
-rwxr-xr-xshell/ash_test/ash-heredoc/heredocA.tests4
-rw-r--r--shell/ash_test/ash-heredoc/heredocB.right3
-rwxr-xr-xshell/ash_test/ash-heredoc/heredocB.tests12
-rw-r--r--shell/ash_test/ash-heredoc/heredoc_after_compound1.right2
-rwxr-xr-xshell/ash_test/ash-heredoc/heredoc_after_compound1.tests3
-rw-r--r--shell/ash_test/ash-heredoc/heredoc_bkslash_newline2.right1
-rwxr-xr-xshell/ash_test/ash-heredoc/heredoc_bkslash_newline2.tests4
-rw-r--r--shell/ash_test/ash-heredoc/heredoc_empty3.right2
-rwxr-xr-xshell/ash_test/ash-heredoc/heredoc_empty3.tests4
-rw-r--r--shell/ash_test/ash-quoting/dollar_altvalue1.right16
-rwxr-xr-xshell/ash_test/ash-quoting/dollar_altvalue1.tests16
-rw-r--r--shell/ash_test/ash-quoting/dollar_altvalue2.right69
-rwxr-xr-xshell/ash_test/ash-quoting/dollar_altvalue2.tests33
-rw-r--r--shell/ash_test/ash-quoting/dollar_altvalue9.right26
-rwxr-xr-xshell/ash_test/ash-quoting/dollar_altvalue9.tests17
-rw-r--r--shell/ash_test/ash-quoting/dollar_repl_bash1.right14
-rwxr-xr-xshell/ash_test/ash-quoting/dollar_repl_bash1.tests12
-rw-r--r--shell/ash_test/ash-quoting/squote_in_varexp.right4
-rwxr-xr-xshell/ash_test/ash-quoting/squote_in_varexp.tests4
-rw-r--r--shell/ash_test/ash-quoting/squote_in_varexp2.right2
-rwxr-xr-xshell/ash_test/ash-quoting/squote_in_varexp2.tests2
-rwxr-xr-xshell/ash_test/ash-redir/redir_script.tests4
-rwxr-xr-xshell/ash_test/ash-z_slow/many_ifs.tests4
-rw-r--r--shell/hush.c1320
-rw-r--r--shell/hush_test/hush-glob/glob_altvalue1.right7
-rwxr-xr-xshell/hush_test/hush-glob/glob_altvalue1.tests13
-rw-r--r--shell/hush_test/hush-heredoc/heredoc.right20
-rwxr-xr-xshell/hush_test/hush-heredoc/heredoc.tests97
-rw-r--r--shell/hush_test/hush-heredoc/heredoc9.right1
-rwxr-xr-xshell/hush_test/hush-heredoc/heredoc9.tests9
-rw-r--r--shell/hush_test/hush-heredoc/heredocA.right1
-rwxr-xr-xshell/hush_test/hush-heredoc/heredocA.tests4
-rw-r--r--shell/hush_test/hush-heredoc/heredocB.right3
-rwxr-xr-xshell/hush_test/hush-heredoc/heredocB.tests12
-rw-r--r--shell/hush_test/hush-heredoc/heredoc_after_compound1.right2
-rwxr-xr-xshell/hush_test/hush-heredoc/heredoc_after_compound1.tests3
-rw-r--r--shell/hush_test/hush-heredoc/heredoc_bkslash_newline2.right1
-rwxr-xr-xshell/hush_test/hush-heredoc/heredoc_bkslash_newline2.tests4
-rw-r--r--shell/hush_test/hush-heredoc/heredoc_empty3.right2
-rwxr-xr-xshell/hush_test/hush-heredoc/heredoc_empty3.tests4
-rw-r--r--shell/hush_test/hush-heredoc/heredoc_var_expand1.right4
-rwxr-xr-xshell/hush_test/hush-heredoc/heredoc_var_expand1.tests11
-rw-r--r--shell/hush_test/hush-quoting/dollar_altvalue1.right16
-rwxr-xr-xshell/hush_test/hush-quoting/dollar_altvalue1.tests16
-rw-r--r--shell/hush_test/hush-quoting/dollar_altvalue2.right69
-rwxr-xr-xshell/hush_test/hush-quoting/dollar_altvalue2.tests33
-rw-r--r--shell/hush_test/hush-quoting/dollar_altvalue9.right26
-rwxr-xr-xshell/hush_test/hush-quoting/dollar_altvalue9.tests17
-rw-r--r--shell/hush_test/hush-quoting/dollar_repl_bash1.right14
-rwxr-xr-xshell/hush_test/hush-quoting/dollar_repl_bash1.tests12
-rw-r--r--shell/hush_test/hush-quoting/squote_in_varexp.right4
-rwxr-xr-xshell/hush_test/hush-quoting/squote_in_varexp.tests4
-rw-r--r--shell/hush_test/hush-quoting/squote_in_varexp2.right2
-rwxr-xr-xshell/hush_test/hush-quoting/squote_in_varexp2.tests2
-rwxr-xr-xshell/hush_test/hush-redir/redir_script.tests4
-rwxr-xr-xshell/hush_test/hush-z_slow/many_ifs.tests4
-rw-r--r--shell/random.c12
-rw-r--r--sysklogd/Config.src2
-rwxr-xr-xtestsuite/bzcat.tests15
-rwxr-xr-xtestsuite/cat.tests4
-rwxr-xr-xtestsuite/hexdump.tests18
-rwxr-xr-xtestsuite/mount.tests2
-rwxr-xr-xtestsuite/pidof.tests7
-rwxr-xr-xtestsuite/tar.tests20
-rw-r--r--testsuite/unexpand/unexpand-works-like-GNU4
-rwxr-xr-xtestsuite/unzip.tests19
-rw-r--r--testsuite/unzip_bad_lzma_2.zipbin0 -> 96 bytes
-rw-r--r--util-linux/Config.src2
-rw-r--r--util-linux/fdisk.c6
-rw-r--r--util-linux/fdisk_sgi.c2
-rw-r--r--util-linux/mkfs_vfat.c2
-rw-r--r--util-linux/nsenter.c4
-rw-r--r--util-linux/unshare.c2
-rw-r--r--util-linux/volume_id/Config.src2
213 files changed, 2877 insertions, 1398 deletions
diff --git a/Config.in b/Config.in
index b9df4ca16..43061e9ac 100644
--- a/Config.in
+++ b/Config.in
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6mainmenu "Configuration" 6mainmenu "Configuration"
diff --git a/Makefile b/Makefile
index ee30c1f08..ea40cd14b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
1VERSION = 1 1VERSION = 1
2PATCHLEVEL = 29 2PATCHLEVEL = 30
3SUBLEVEL = 0 3SUBLEVEL = 0
4EXTRAVERSION = .git 4EXTRAVERSION = .git
5NAME = Unnamed 5NAME = Unnamed
diff --git a/archival/Config.src b/archival/Config.src
index 449914565..6f4f30c43 100644
--- a/archival/Config.src
+++ b/archival/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Archival Utilities" 6menu "Archival Utilities"
diff --git a/archival/cpio.c b/archival/cpio.c
index 308ec1b25..9cacf9de6 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -64,15 +64,17 @@
64//usage: "\n -p DIR Copy files to DIR" 64//usage: "\n -p DIR Copy files to DIR"
65//usage: ) 65//usage: )
66//usage: "\nOptions:" 66//usage: "\nOptions:"
67//usage: IF_FEATURE_CPIO_O(
68//usage: "\n -H newc Archive format"
69//usage: )
67//usage: "\n -d Make leading directories" 70//usage: "\n -d Make leading directories"
68//usage: "\n -m Preserve mtime" 71//usage: "\n -m Preserve mtime"
69//usage: "\n -v Verbose" 72//usage: "\n -v Verbose"
70//usage: "\n -u Overwrite" 73//usage: "\n -u Overwrite"
71//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file" 74//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file"
72//usage: "\n -R USER[:GRP] Set owner of created files" 75//usage: "\n -R USER[:GRP] Set owner of created files"
73//usage: IF_FEATURE_CPIO_O( 76//usage: "\n -L Dereference symlinks"
74//usage: "\n -H newc Archive format" 77//usage: "\n -0 Input is separated by NULs"
75//usage: )
76 78
77/* GNU cpio 2.9 --help (abridged): 79/* GNU cpio 2.9 --help (abridged):
78 80
@@ -374,6 +376,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
374#endif 376#endif
375 "owner\0" Required_argument "R" 377 "owner\0" Required_argument "R"
376 "verbose\0" No_argument "v" 378 "verbose\0" No_argument "v"
379 "null\0" No_argument "0"
377 "quiet\0" No_argument "\xff" 380 "quiet\0" No_argument "\xff"
378 "to-stdout\0" No_argument "\xfe" 381 "to-stdout\0" No_argument "\xfe"
379 ; 382 ;
@@ -508,7 +511,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
508 while (get_header_cpio(archive_handle) == EXIT_SUCCESS) 511 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
509 continue; 512 continue;
510 513
511 create_symlinks_from_list(archive_handle->symlink_placeholders); 514 create_links_from_list(archive_handle->link_placeholders);
512 515
513 if (archive_handle->cpio__blocks != (off_t)-1 516 if (archive_handle->cpio__blocks != (off_t)-1
514 && !(opt & OPT_QUIET) 517 && !(opt & OPT_QUIET)
diff --git a/archival/gzip.c b/archival/gzip.c
index c5a1fe9b4..74d5d685f 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -333,12 +333,6 @@ struct globals {
333 /* DECLARE(Pos, head, 1<<HASH_BITS); */ 333 /* DECLARE(Pos, head, 1<<HASH_BITS); */
334#define head (G1.prev + WSIZE) /* hash head (see deflate.c) */ 334#define head (G1.prev + WSIZE) /* hash head (see deflate.c) */
335 335
336/* =========================================================================== */
337/* all members below are zeroed out in pack_gzip() for each next file */
338
339 uint32_t crc; /* shift register contents */
340 /*uint32_t *crc_32_tab;*/
341
342#if ENABLE_FEATURE_GZIP_LEVELS 336#if ENABLE_FEATURE_GZIP_LEVELS
343 unsigned max_chain_length; 337 unsigned max_chain_length;
344 unsigned max_lazy_match; 338 unsigned max_lazy_match;
@@ -350,6 +344,12 @@ struct globals {
350#define nice_match (G1.nice_match) 344#define nice_match (G1.nice_match)
351#endif 345#endif
352 346
347/* =========================================================================== */
348/* all members below are zeroed out in pack_gzip() for each next file */
349
350 uint32_t crc; /* shift register contents */
351 /*uint32_t *crc_32_tab;*/
352
353/* window position at the beginning of the current output block. Gets 353/* window position at the beginning of the current output block. Gets
354 * negative when the window is moved backwards. 354 * negative when the window is moved backwards.
355 */ 355 */
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index 8fa69ffaf..4c95db4a6 100644
--- a/archival/libarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -122,13 +122,10 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
122 122
123 /* Handle hard links separately */ 123 /* Handle hard links separately */
124 if (hard_link) { 124 if (hard_link) {
125 res = link(hard_link, dst_name); 125 create_or_remember_link(&archive_handle->link_placeholders,
126 if (res != 0) { 126 hard_link,
127 /* shared message */ 127 dst_name,
128 bb_perror_msg("can't create %slink '%s' to '%s'", 128 1);
129 "hard", dst_name, hard_link
130 );
131 }
132 /* Hardlinks have no separate mode/ownership, skip chown/chmod */ 129 /* Hardlinks have no separate mode/ownership, skip chown/chmod */
133 goto ret; 130 goto ret;
134 } 131 }
@@ -195,9 +192,10 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
195 * 192 *
196 * Untarring bug.tar would otherwise place evil.py in '/tmp'. 193 * Untarring bug.tar would otherwise place evil.py in '/tmp'.
197 */ 194 */
198 create_or_remember_symlink(&archive_handle->symlink_placeholders, 195 create_or_remember_link(&archive_handle->link_placeholders,
199 file_header->link_target, 196 file_header->link_target,
200 dst_name); 197 dst_name,
198 0);
201 break; 199 break;
202 case S_IFSOCK: 200 case S_IFSOCK:
203 case S_IFBLK: 201 case S_IFBLK:
diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c
index 446319e7b..6886239d0 100644
--- a/archival/libarchive/decompress_unlzma.c
+++ b/archival/libarchive/decompress_unlzma.c
@@ -350,8 +350,12 @@ unpack_lzma_stream(transformer_state_t *xstate)
350 state = state < LZMA_NUM_LIT_STATES ? 9 : 11; 350 state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
351 351
352 pos = buffer_pos - rep0; 352 pos = buffer_pos - rep0;
353 if ((int32_t)pos < 0) 353 if ((int32_t)pos < 0) {
354 pos += header.dict_size; 354 pos += header.dict_size;
355 /* see unzip_bad_lzma_2.zip: */
356 if (pos >= buffer_size)
357 goto bad;
358 }
355 previous_byte = buffer[pos]; 359 previous_byte = buffer[pos];
356 goto one_byte1; 360 goto one_byte1;
357#else 361#else
diff --git a/archival/libarchive/get_header_ar.c b/archival/libarchive/get_header_ar.c
index adcde46d5..7ce9c615c 100644
--- a/archival/libarchive/get_header_ar.c
+++ b/archival/libarchive/get_header_ar.c
@@ -126,7 +126,7 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
126 struct archive_handle_t *sa = archive_handle->dpkg__sub_archive; 126 struct archive_handle_t *sa = archive_handle->dpkg__sub_archive;
127 while (archive_handle->dpkg__action_data_subarchive(sa) == EXIT_SUCCESS) 127 while (archive_handle->dpkg__action_data_subarchive(sa) == EXIT_SUCCESS)
128 continue; 128 continue;
129 create_symlinks_from_list(sa->symlink_placeholders); 129 create_links_from_list(sa->link_placeholders);
130 } else 130 } else
131#endif 131#endif
132 archive_handle->action_data(archive_handle); 132 archive_handle->action_data(archive_handle);
diff --git a/archival/libarchive/unsafe_symlink_target.c b/archival/libarchive/unsafe_symlink_target.c
index 0ad4c9392..f53881f2f 100644
--- a/archival/libarchive/unsafe_symlink_target.c
+++ b/archival/libarchive/unsafe_symlink_target.c
@@ -5,15 +5,16 @@
5#include "libbb.h" 5#include "libbb.h"
6#include "bb_archive.h" 6#include "bb_archive.h"
7 7
8void FAST_FUNC create_or_remember_symlink(llist_t **symlink_placeholders 8void FAST_FUNC create_or_remember_link(llist_t **link_placeholders
9 IF_PLATFORM_MINGW32(UNUSED_PARAM), 9 IF_PLATFORM_MINGW32(UNUSED_PARAM),
10 const char *target, 10 const char *target,
11 const char *linkname) 11 const char *linkname,
12 int hard_link IF_PLATFORM_MINGW32(UNUSED_PARAM))
12{ 13{
13#if !ENABLE_PLATFORM_MINGW32 14#if !ENABLE_PLATFORM_MINGW32
14 if (target[0] == '/' || strstr(target, "..")) { 15 if (hard_link || target[0] == '/' || strstr(target, "..")) {
15 llist_add_to(symlink_placeholders, 16 llist_add_to_end(link_placeholders,
16 xasprintf("%s%c%s", linkname, '\0', target) 17 xasprintf("%c%s%c%s", hard_link, linkname, '\0', target)
17 ); 18 );
18 return; 19 return;
19 } 20 }
@@ -30,17 +31,17 @@ void FAST_FUNC create_or_remember_symlink(llist_t **symlink_placeholders
30} 31}
31 32
32#if !ENABLE_PLATFORM_MINGW32 33#if !ENABLE_PLATFORM_MINGW32
33void FAST_FUNC create_symlinks_from_list(llist_t *list) 34void FAST_FUNC create_links_from_list(llist_t *list)
34{ 35{
35 while (list) { 36 while (list) {
36 char *target; 37 char *target;
37 38
38 target = list->data + strlen(list->data) + 1; 39 target = list->data + 1 + strlen(list->data + 1) + 1;
39 if (symlink(target, list->data)) { 40 if ((*list->data ? link : symlink) (target, list->data + 1)) {
40 /* shared message */ 41 /* shared message */
41 bb_error_msg_and_die("can't create %slink '%s' to '%s'", 42 bb_error_msg_and_die("can't create %slink '%s' to '%s'",
42 "sym", 43 *list->data ? "hard" : "sym",
43 list->data, target 44 list->data + 1, target
44 ); 45 );
45 } 46 }
46 list = list->link; 47 list = list->link;
diff --git a/archival/tar.c b/archival/tar.c
index afd8cfec5..e1af27401 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -1279,7 +1279,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1279 while (get_header_tar(tar_handle) == EXIT_SUCCESS) 1279 while (get_header_tar(tar_handle) == EXIT_SUCCESS)
1280 bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */ 1280 bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */
1281 1281
1282 create_symlinks_from_list(tar_handle->symlink_placeholders); 1282 create_links_from_list(tar_handle->link_placeholders);
1283 1283
1284 /* Check that every file that should have been extracted was */ 1284 /* Check that every file that should have been extracted was */
1285 while (tar_handle->accept) { 1285 while (tar_handle->accept) {
diff --git a/archival/unzip.c b/archival/unzip.c
index 369c6c028..a9b7dc10f 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -375,9 +375,10 @@ static void unzip_extract_symlink(llist_t **symlink_placeholders,
375 target[xstate.mem_output_size] = '\0'; 375 target[xstate.mem_output_size] = '\0';
376#endif 376#endif
377 } 377 }
378 create_or_remember_symlink(symlink_placeholders, 378 create_or_remember_link(symlink_placeholders,
379 target, 379 target,
380 dst_fn); 380 dst_fn,
381 0);
381 free(target); 382 free(target);
382} 383}
383#endif 384#endif
@@ -993,7 +994,7 @@ int unzip_main(int argc, char **argv)
993 } 994 }
994 995
995#if ENABLE_FEATURE_UNZIP_CDF 996#if ENABLE_FEATURE_UNZIP_CDF
996 create_symlinks_from_list(symlink_placeholders); 997 create_links_from_list(symlink_placeholders);
997#endif 998#endif
998 999
999 if ((opts & OPT_l) && quiet <= 1) { 1000 if ((opts & OPT_l) && quiet <= 1) {
diff --git a/console-tools/Config.src b/console-tools/Config.src
index e6587ade4..c30caf0e1 100644
--- a/console-tools/Config.src
+++ b/console-tools/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Console Utilities" 6menu "Console Utilities"
diff --git a/coreutils/Config.src b/coreutils/Config.src
index 7a8a3a634..1bded03a6 100644
--- a/coreutils/Config.src
+++ b/coreutils/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Coreutils" 6menu "Coreutils"
diff --git a/coreutils/cp.c b/coreutils/cp.c
index 455bffbba..ae60623d3 100644
--- a/coreutils/cp.c
+++ b/coreutils/cp.c
@@ -24,6 +24,11 @@
24//config: help 24//config: help
25//config: Enable long options. 25//config: Enable long options.
26//config: Also add support for --parents option. 26//config: Also add support for --parents option.
27//config:
28//config:config FEATURE_CP_REFLINK
29//config: bool "Enable --reflink[=auto]"
30//config: default y
31//config: depends on FEATURE_CP_LONG_OPTIONS
27 32
28//applet:IF_CP(APPLET_NOEXEC(cp, cp, BB_DIR_BIN, BB_SUID_DROP, cp)) 33//applet:IF_CP(APPLET_NOEXEC(cp, cp, BB_DIR_BIN, BB_SUID_DROP, cp))
29/* NOEXEC despite cases when it can be a "runner" (cp -r LARGE_DIR NEW_DIR) */ 34/* NOEXEC despite cases when it can be a "runner" (cp -r LARGE_DIR NEW_DIR) */
@@ -72,10 +77,14 @@ int cp_main(int argc, char **argv)
72#if ENABLE_FEATURE_CP_LONG_OPTIONS 77#if ENABLE_FEATURE_CP_LONG_OPTIONS
73 /*OPT_rmdest = FILEUTILS_RMDEST = 1 << FILEUTILS_CP_OPTNUM */ 78 /*OPT_rmdest = FILEUTILS_RMDEST = 1 << FILEUTILS_CP_OPTNUM */
74 OPT_parents = 1 << (FILEUTILS_CP_OPTNUM+1), 79 OPT_parents = 1 << (FILEUTILS_CP_OPTNUM+1),
80 OPT_reflink = 1 << (FILEUTILS_CP_OPTNUM+2),
75#endif 81#endif
76 }; 82 };
77 83
78#if ENABLE_FEATURE_CP_LONG_OPTIONS 84#if ENABLE_FEATURE_CP_LONG_OPTIONS
85# if ENABLE_FEATURE_CP_REFLINK
86 char *reflink = NULL;
87# endif
79 flags = getopt32long(argv, "^" 88 flags = getopt32long(argv, "^"
80 FILEUTILS_CP_OPTSTR 89 FILEUTILS_CP_OPTSTR
81 "\0" 90 "\0"
@@ -99,7 +108,22 @@ int cp_main(int argc, char **argv)
99 "update\0" No_argument "u" 108 "update\0" No_argument "u"
100 "remove-destination\0" No_argument "\xff" 109 "remove-destination\0" No_argument "\xff"
101 "parents\0" No_argument "\xfe" 110 "parents\0" No_argument "\xfe"
111# if ENABLE_FEATURE_CP_REFLINK
112 "reflink\0" Optional_argument "\xfd"
113 , &reflink
114# endif
102 ); 115 );
116# if ENABLE_FEATURE_CP_REFLINK
117 BUILD_BUG_ON(OPT_reflink != FILEUTILS_REFLINK);
118 if (flags & FILEUTILS_REFLINK) {
119 if (!reflink)
120 flags |= FILEUTILS_REFLINK_ALWAYS;
121 else if (strcmp(reflink, "always") == 0)
122 flags |= FILEUTILS_REFLINK_ALWAYS;
123 else if (strcmp(reflink, "auto") != 0)
124 bb_show_usage();
125 }
126# endif
103#else 127#else
104 flags = getopt32(argv, "^" 128 flags = getopt32(argv, "^"
105 FILEUTILS_CP_OPTSTR 129 FILEUTILS_CP_OPTSTR
diff --git a/coreutils/install.c b/coreutils/install.c
index 2e4dc257f..8270490bd 100644
--- a/coreutils/install.c
+++ b/coreutils/install.c
@@ -214,7 +214,11 @@ int install_main(int argc, char **argv)
214 dest = last; 214 dest = last;
215 if (opts & OPT_MKDIR_LEADING) { 215 if (opts & OPT_MKDIR_LEADING) {
216 char *ddir = xstrdup(dest); 216 char *ddir = xstrdup(dest);
217 bb_make_directory(dirname(ddir), 0755, mkdir_flags); 217 /*
218 * -D -t DIR1/DIR2/F3 FILE: create DIR1/DIR2/F3, copy FILE there
219 * -D FILE DIR1/DIR2/F3: create DIR1/DIR2, copy FILE there as F3
220 */
221 bb_make_directory((opts & OPT_TARGET) ? ddir : dirname(ddir), 0755, mkdir_flags);
218 /* errors are not checked. copy_file 222 /* errors are not checked. copy_file
219 * will fail if dir is not created. 223 * will fail if dir is not created.
220 */ 224 */
diff --git a/coreutils/nproc.c b/coreutils/nproc.c
index 336b176ca..0ea8d1001 100644
--- a/coreutils/nproc.c
+++ b/coreutils/nproc.c
@@ -14,10 +14,14 @@
14//kbuild:lib-$(CONFIG_NPROC) += nproc.o 14//kbuild:lib-$(CONFIG_NPROC) += nproc.o
15 15
16//usage:#define nproc_trivial_usage 16//usage:#define nproc_trivial_usage
17//usage: "" 17//usage: ""IF_LONG_OPTS("--all --ignore=N")
18//TODO: "[--all] [--ignore=N]"
19//usage:#define nproc_full_usage "\n\n" 18//usage:#define nproc_full_usage "\n\n"
20//usage: "Print number of CPUs" 19//usage: "Print number of available CPUs"
20//usage: IF_LONG_OPTS(
21//usage: "\n"
22//usage: "\n --all Number of installed CPUs"
23//usage: "\n --ignore=N Exclude N CPUs"
24//usage: )
21 25
22#include <sched.h> 26#include <sched.h>
23#include "libbb.h" 27#include "libbb.h"
@@ -26,13 +30,30 @@ int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
26int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 30int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
27{ 31{
28 unsigned long mask[1024]; 32 unsigned long mask[1024];
29 unsigned i, count = 0; 33 int count = 0;
30 34#if ENABLE_LONG_OPTS
31 //getopt32(argv, ""); 35 int ignore = 0;
32 36 int opts = getopt32long(argv, "\xfe:+",
33 //if --all, count /sys/devices/system/cpu/cpuN dirs, else: 37 "ignore\0" Required_argument "\xfe"
38 "all\0" No_argument "\xff"
39 , &ignore
40 );
34 41
42 if (opts & (1 << 1)) {
43 DIR *cpusd = opendir("/sys/devices/system/cpu");
44 if (cpusd) {
45 struct dirent *de;
46 while (NULL != (de = readdir(cpusd))) {
47 char *cpuid = strstr(de->d_name, "cpu");
48 if (cpuid && isdigit(cpuid[strlen(cpuid) - 1]))
49 count++;
50 }
51 closedir(cpusd);
52 }
53 } else
54#endif
35 if (sched_getaffinity(0, sizeof(mask), (void*)mask) == 0) { 55 if (sched_getaffinity(0, sizeof(mask), (void*)mask) == 0) {
56 int i;
36 for (i = 0; i < ARRAY_SIZE(mask); i++) { 57 for (i = 0; i < ARRAY_SIZE(mask); i++) {
37 unsigned long m = mask[i]; 58 unsigned long m = mask[i];
38 while (m) { 59 while (m) {
@@ -42,8 +63,11 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
42 } 63 }
43 } 64 }
44 } 65 }
45 if (count == 0) 66
46 count++; 67 IF_LONG_OPTS(count -= ignore;)
68 if (count <= 0)
69 count = 1;
70
47 printf("%u\n", count); 71 printf("%u\n", count);
48 72
49 return 0; 73 return 0;
diff --git a/coreutils/readlink.c b/coreutils/readlink.c
index b8e327d11..49361cea0 100644
--- a/coreutils/readlink.c
+++ b/coreutils/readlink.c
@@ -86,7 +86,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv)
86 86
87 /* NOFORK: only one alloc is allowed; must free */ 87 /* NOFORK: only one alloc is allowed; must free */
88 if (opt & 1) { /* -f */ 88 if (opt & 1) { /* -f */
89 buf = xmalloc_realpath(fname); 89 buf = xmalloc_realpath_coreutils(fname);
90 } else { 90 } else {
91 buf = xmalloc_readlink_or_warn(fname); 91 buf = xmalloc_readlink_or_warn(fname);
92 } 92 }
diff --git a/coreutils/realpath.c b/coreutils/realpath.c
index aa878fcd2..43923681c 100644
--- a/coreutils/realpath.c
+++ b/coreutils/realpath.c
@@ -38,7 +38,7 @@ int realpath_main(int argc UNUSED_PARAM, char **argv)
38 38
39 do { 39 do {
40 /* NOFORK: only one alloc is allowed; must free */ 40 /* NOFORK: only one alloc is allowed; must free */
41 char *resolved_path = xmalloc_realpath(*argv); 41 char *resolved_path = xmalloc_realpath_coreutils(*argv);
42 if (resolved_path != NULL) { 42 if (resolved_path != NULL) {
43 puts(resolved_path); 43 puts(resolved_path);
44 free(resolved_path); 44 free(resolved_path);
diff --git a/coreutils/sort.c b/coreutils/sort.c
index 4d741e76d..05e5c9071 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -60,6 +60,7 @@
60//usage: IF_FEATURE_SORT_BIG( 60//usage: IF_FEATURE_SORT_BIG(
61//usage: "\n -g General numerical sort" 61//usage: "\n -g General numerical sort"
62//usage: "\n -M Sort month" 62//usage: "\n -M Sort month"
63//usage: "\n -V Sort version"
63//usage: "\n -t CHAR Field separator" 64//usage: "\n -t CHAR Field separator"
64//usage: "\n -k N[,M] Sort by Nth field" 65//usage: "\n -k N[,M] Sort by Nth field"
65//usage: ) 66//usage: )
@@ -91,32 +92,33 @@
91 92
92/* These are sort types */ 93/* These are sort types */
93enum { 94enum {
94 FLAG_n = 1, /* Numeric sort */ 95 FLAG_n = 1 << 0, /* Numeric sort */
95 FLAG_g = 2, /* Sort using strtod() */ 96 FLAG_g = 1 << 1, /* Sort using strtod() */
96 FLAG_M = 4, /* Sort date */ 97 FLAG_M = 1 << 2, /* Sort date */
98 FLAG_V = 1 << 3, /* Sort version */
97/* ucsz apply to root level only, not keys. b at root level implies bb */ 99/* ucsz apply to root level only, not keys. b at root level implies bb */
98 FLAG_u = 8, /* Unique */ 100 FLAG_u = 1 << 4, /* Unique */
99 FLAG_c = 0x10, /* Check: no output, exit(!ordered) */ 101 FLAG_c = 1 << 5, /* Check: no output, exit(!ordered) */
100 FLAG_s = 0x20, /* Stable sort, no ascii fallback at end */ 102 FLAG_s = 1 << 6, /* Stable sort, no ascii fallback at end */
101 FLAG_z = 0x40, /* Input and output is NUL terminated, not \n */ 103 FLAG_z = 1 << 7, /* Input and output is NUL terminated, not \n */
102/* These can be applied to search keys, the previous four can't */ 104/* These can be applied to search keys, the previous four can't */
103 FLAG_b = 0x80, /* Ignore leading blanks */ 105 FLAG_b = 1 << 8, /* Ignore leading blanks */
104 FLAG_r = 0x100, /* Reverse */ 106 FLAG_r = 1 << 9, /* Reverse */
105 FLAG_d = 0x200, /* Ignore !(isalnum()|isspace()) */ 107 FLAG_d = 1 << 10, /* Ignore !(isalnum()|isspace()) */
106 FLAG_f = 0x400, /* Force uppercase */ 108 FLAG_f = 1 << 11, /* Force uppercase */
107 FLAG_i = 0x800, /* Ignore !isprint() */ 109 FLAG_i = 1 << 12, /* Ignore !isprint() */
108 FLAG_m = 0x1000, /* ignored: merge already sorted files; do not sort */ 110 FLAG_m = 1 << 13, /* ignored: merge already sorted files; do not sort */
109 FLAG_S = 0x2000, /* ignored: -S, --buffer-size=SIZE */ 111 FLAG_S = 1 << 14, /* ignored: -S, --buffer-size=SIZE */
110 FLAG_T = 0x4000, /* ignored: -T, --temporary-directory=DIR */ 112 FLAG_T = 1 << 15, /* ignored: -T, --temporary-directory=DIR */
111 FLAG_o = 0x8000, 113 FLAG_o = 1 << 16,
112 FLAG_k = 0x10000, 114 FLAG_k = 1 << 17,
113 FLAG_t = 0x20000, 115 FLAG_t = 1 << 18,
114 FLAG_bb = 0x80000000, /* Ignore trailing blanks */ 116 FLAG_bb = 0x80000000, /* Ignore trailing blanks */
115 FLAG_no_tie_break = 0x40000000, 117 FLAG_no_tie_break = 0x40000000,
116}; 118};
117 119
118static const char sort_opt_str[] ALIGN1 = "^" 120static const char sort_opt_str[] ALIGN1 = "^"
119 "ngMucszbrdfimS:T:o:k:*t:" 121 "ngMVucszbrdfimS:T:o:k:*t:"
120 "\0" "o--o:t--t"/*-t, -o: at most one of each*/; 122 "\0" "o--o:t--t"/*-t, -o: at most one of each*/;
121/* 123/*
122 * OPT_STR must not be string literal, needs to have stable address: 124 * OPT_STR must not be string literal, needs to have stable address:
@@ -273,10 +275,15 @@ static int compare_keys(const void *xarg, const void *yarg)
273 y = *(char **)yarg; 275 y = *(char **)yarg;
274#endif 276#endif
275 /* Perform actual comparison */ 277 /* Perform actual comparison */
276 switch (flags & (FLAG_n | FLAG_M | FLAG_g)) { 278 switch (flags & (FLAG_n | FLAG_g | FLAG_M | FLAG_V)) {
277 default: 279 default:
278 bb_error_msg_and_die("unknown sort type"); 280 bb_error_msg_and_die("unknown sort type");
279 break; 281 break;
282#if defined(HAVE_STRVERSCMP) && HAVE_STRVERSCMP == 1
283 case FLAG_V:
284 retval = strverscmp(x, y);
285 break;
286#endif
280 /* Ascii sort */ 287 /* Ascii sort */
281 case 0: 288 case 0:
282#if ENABLE_LOCALE_SUPPORT 289#if ENABLE_LOCALE_SUPPORT
diff --git a/debianutils/Config.src b/debianutils/Config.src
index 61daeb047..17b0d8945 100644
--- a/debianutils/Config.src
+++ b/debianutils/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Debian Utilities" 6menu "Debian Utilities"
diff --git a/docs/Kconfig-language.txt b/docs/Kconfig-language.txt
new file mode 100644
index 000000000..0ba8932ba
--- /dev/null
+++ b/docs/Kconfig-language.txt
@@ -0,0 +1,255 @@
1Introduction
2------------
3
4The configuration database is collection of configuration options
5organized in a tree structure:
6
7 +- Code maturity level options
8 | +- Prompt for development and/or incomplete code/drivers
9 +- General setup
10 | +- Networking support
11 | +- System V IPC
12 | +- BSD Process Accounting
13 | +- Sysctl support
14 +- Loadable module support
15 | +- Enable loadable module support
16 | +- Set version information on all module symbols
17 | +- Kernel module loader
18 +- ...
19
20Every entry has its own dependencies. These dependencies are used
21to determine the visible of an entry. Any child entry is only
22visible if its parent entry is also visible.
23
24Menu entries
25------------
26
27Most entries define a config option, all other entries help to organize
28them. A single configuration option is defined like this:
29
30config MODVERSIONS
31 bool "Set version information on all module symbols"
32 depends MODULES
33 help
34 Usually, modules have to be recompiled whenever you switch to a new
35 kernel. ...
36
37Every line starts with a key word and can be followed by multiple
38arguments. "config" starts a new config entry. The following lines
39define attributes for this config option. Attributes can be the type of
40the config option, input prompt, dependencies, help text and default
41values. A config option can be defined multiple times with the same
42name, but every definition can have only a single input prompt and the
43type must not conflict.
44
45Menu attributes
46---------------
47
48A menu entry can have a number of attributes. Not all of them are
49applicable everywhere (see syntax).
50
51- type definition: "bool"/"tristate"/"string"/"hex"/"integer"
52 Every config option must have a type. There are only two basic types:
53 tristate and string, the other types base on these two. The type
54 definition optionally accepts an input prompt, so these two examples
55 are equivalent:
56
57 bool "Networking support"
58 and
59 bool
60 prompt "Networking support"
61
62- input prompt: "prompt" <prompt> ["if" <expr>]
63 Every menu entry can have at most one prompt, which is used to display
64 to the user. Optionally dependencies only for this prompt can be added
65 with "if".
66
67- default value: "default" <symbol> ["if" <expr>]
68 A config option can have any number of default values. If multiple
69 default values are visible, only the first defined one is active.
70 Default values are not limited to the menu entry, where they are
71 defined, this means the default can be defined somewhere else or be
72 overridden by an earlier definition.
73 The default value is only assigned to the config symbol if no other
74 value was set by the user (via the input prompt above). If an input
75 prompt is visible the default value is presented to the user and can
76 be overridden by him.
77 Optionally dependencies only for this default value can be added with
78 "if".
79
80- dependencies: "depends on"/"requires" <expr>
81 This defines a dependency for this menu entry. If multiple
82 dependencies are defined they are connected with '&&'. Dependencies
83 are applied to all other options within this menu entry (which also
84 accept "if" expression), so these two examples are equivalent:
85
86 bool "foo" if BAR
87 default y if BAR
88 and
89 depends on BAR
90 bool "foo"
91 default y
92
93- help text: "help"
94 This defines a help text. The end of the help text is determined by
95 the level indentation, this means it ends at the first line which has
96 a smaller indentation than the first line of the help text.
97
98
99Menu dependencies
100-----------------
101
102Dependencies define the visibility of a menu entry and can also reduce
103the input range of tristate symbols. The tristate logic used in the
104expressions uses one more state than normal boolean logic to express the
105module state. Dependency expressions have the following syntax:
106
107<expr> ::= <symbol> (1)
108 <symbol> '=' <symbol> (2)
109 <symbol> '!=' <symbol> (3)
110 '(' <expr> ')' (4)
111 '!' <expr> (5)
112 <expr> '||' <expr> (6)
113 <expr> '&&' <expr> (7)
114
115Expressions are listed in decreasing order of precedence.
116
117(1) Convert the symbol into an expression. Boolean and tristate symbols
118 are simply converted into the respective expression values. All
119 other symbol types result in 'n'.
120(2) If the values of both symbols are equal, it returns 'y',
121 otherwise 'n'.
122(3) If the values of both symbols are equal, it returns 'n',
123 otherwise 'y'.
124(4) Returns the value of the expression. Used to override precedence.
125(5) Returns the result of (2-/expr/).
126(6) Returns the result of min(/expr/, /expr/).
127(7) Returns the result of max(/expr/, /expr/).
128
129An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2
130respectively for calculations). A menu entry becomes visible when it's
131expression evaluates to 'm' or 'y'.
132
133There are two type of symbols: constant and nonconstant symbols.
134Nonconstant symbols are the most common ones and are defined with the
135'config' statement. Nonconstant symbols consist entirely of alphanumeric
136characters or underscores.
137Constant symbols are only part of expressions. Constant symbols are
138always surrounded by single or double quotes. Within the quote any
139other character is allowed and the quotes can be escaped using '\'.
140
141Menu structure
142--------------
143
144The position of a menu entry in the tree is determined in two ways. First
145it can be specified explicitely:
146
147menu "Network device support"
148 depends NET
149
150config NETDEVICES
151 ...
152
153endmenu
154
155All entries within the "menu" ... "endmenu" block become a submenu of
156"Network device support". All subentries inherit the dependencies from
157the menu entry, e.g. this means the dependency "NET" is added to the
158dependency list of the config option NETDEVICES.
159
160The other way to generate the menu structure is done by analyzing the
161dependencies. If a menu entry somehow depends on the previous entry, it
162can be made a submenu of it. First the the previous (parent) symbol must
163be part of the dependency list and then one of these two condititions
164must be true:
165- the child entry must become invisible, if the parent is set to 'n'
166- the child entry must only be visible, if the parent is visible
167
168config MODULES
169 bool "Enable loadable module support"
170
171config MODVERSIONS
172 bool "Set version information on all module symbols"
173 depends MODULES
174
175comment "module support disabled"
176 depends !MODULES
177
178MODVERSIONS directly depends on MODULES, this means it's only visible if
179MODULES is different from 'n'. The comment on the other hand is always
180visible when MODULES it's visible (the (empty) dependency of MODULES is
181also part of the comment dependencies).
182
183
184Kconfig syntax
185--------------
186
187The configuration file describes a series of menu entries, where every
188line starts with a keyword (except help texts). The following keywords
189end a menu entry:
190- config
191- choice/endchoice
192- comment
193- menu/endmenu
194- if/endif
195- source
196The first four also start the definition of a menu entry.
197
198config:
199
200 "config" <symbol>
201 <config options>
202
203This defines a config symbol <symbol> and accepts any of above
204attributes as options.
205
206choices:
207
208 "choice"
209 <choice options>
210 <choice block>
211 "endchoice"
212
213This defines a choice group and accepts any of above attributes as
214options. A choice can only be of type bool or tristate, while a boolean
215choice only allows a single config entry to be selected, a tristate
216choice also allows any number of config entries to be set to 'm'. This
217can be used if multiple drivers for a single hardware exists and only a
218single driver can be compiled/loaded into the kernel, but all drivers
219can be compiled as modules.
220A choice accepts another option "optional", which allows to set the
221choice to 'n' and no entry needs to be selected.
222
223comment:
224
225 "comment" <prompt>
226 <comment options>
227
228This defines a comment which is displayed to the user during the
229configuration process and is also echoed to the output files. The only
230possible options are dependencies.
231
232menu:
233
234 "menu" <prompt>
235 <menu options>
236 <menu block>
237 "endmenu"
238
239This defines a menu block, see "Menu structure" above for more
240information. The only possible options are dependencies.
241
242if:
243
244 "if" <expr>
245 <if block>
246 "endif"
247
248This defines an if block. The dependency expression <expr> is appended
249to all enclosed menu entries.
250
251source:
252
253 "source" <prompt>
254
255This reads the specified configuration file. This file is always parsed.
diff --git a/e2fsprogs/Config.src b/e2fsprogs/Config.src
index a20d849e6..ad15f470c 100644
--- a/e2fsprogs/Config.src
+++ b/e2fsprogs/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Linux Ext2 FS Progs" 6menu "Linux Ext2 FS Progs"
diff --git a/e2fsprogs/fsck.c b/e2fsprogs/fsck.c
index 1c285bb92..f5aa3dbe4 100644
--- a/e2fsprogs/fsck.c
+++ b/e2fsprogs/fsck.c
@@ -414,7 +414,7 @@ static void kill_all_if_got_signal(void)
414static int wait_one(int flags) 414static int wait_one(int flags)
415{ 415{
416 int status; 416 int status;
417 int sig; 417 int exitcode;
418 struct fsck_instance *inst, *prev; 418 struct fsck_instance *inst, *prev;
419 pid_t pid; 419 pid_t pid;
420 420
@@ -448,15 +448,16 @@ static int wait_one(int flags)
448 } 448 }
449 child_died: 449 child_died:
450 450
451 status = WEXITSTATUS(status); 451 exitcode = WEXITSTATUS(status);
452 if (WIFSIGNALED(status)) { 452 if (WIFSIGNALED(status)) {
453 unsigned sig;
453 sig = WTERMSIG(status); 454 sig = WTERMSIG(status);
454 status = EXIT_UNCORRECTED; 455 exitcode = EXIT_UNCORRECTED;
455 if (sig != SIGINT) { 456 if (sig != SIGINT) {
456 printf("Warning: %s %s terminated " 457 printf("Warning: %s %s terminated "
457 "by signal %d\n", 458 "by signal %u\n",
458 inst->prog, inst->device, sig); 459 inst->prog, inst->device, sig);
459 status = EXIT_ERROR; 460 exitcode = EXIT_ERROR;
460 } 461 }
461 } 462 }
462 463
@@ -492,12 +493,12 @@ static int wait_one(int flags)
492 else 493 else
493 G.instance_list = inst->next; 494 G.instance_list = inst->next;
494 if (G.verbose > 1) 495 if (G.verbose > 1)
495 printf("Finished with %s (exit status %d)\n", 496 printf("Finished with %s (exit status %u)\n",
496 inst->device, status); 497 inst->device, exitcode);
497 G.num_running--; 498 G.num_running--;
498 free_instance(inst); 499 free_instance(inst);
499 500
500 return status; 501 return exitcode;
501} 502}
502 503
503/* 504/*
diff --git a/editors/Config.src b/editors/Config.src
index 0920bc494..3b2e4a6c0 100644
--- a/editors/Config.src
+++ b/editors/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Editors" 6menu "Editors"
diff --git a/editors/vi.c b/editors/vi.c
index 26487bee6..e79787977 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -752,7 +752,10 @@ static int query_screen_dimensions(void)
752 return err; 752 return err;
753} 753}
754#else 754#else
755# define query_screen_dimensions() (0) 755static ALWAYS_INLINE int query_screen_dimensions(void)
756{
757 return 0;
758}
756#endif 759#endif
757 760
758static void edit_file(char *fn) 761static void edit_file(char *fn)
@@ -1069,10 +1072,13 @@ static void colon(char *buf)
1069 not_implemented(p); 1072 not_implemented(p);
1070#else 1073#else
1071 1074
1072 char c, *orig_buf, *buf1, *q, *r; 1075 char c, *buf1, *q, *r;
1073 char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN]; 1076 char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN];
1074 int i, l, li, b, e; 1077 int i, l, li, b, e;
1075 int useforce; 1078 int useforce;
1079# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
1080 char *orig_buf;
1081# endif
1076 1082
1077 // :3154 // if (-e line 3154) goto it else stay put 1083 // :3154 // if (-e line 3154) goto it else stay put
1078 // :4,33w! foo // write a portion of buffer to file "foo" 1084 // :4,33w! foo // write a portion of buffer to file "foo"
@@ -1104,8 +1110,10 @@ static void colon(char *buf)
1104 // look for optional address(es) :. :1 :1,9 :'q,'a :% 1110 // look for optional address(es) :. :1 :1,9 :'q,'a :%
1105 buf = get_address(buf, &b, &e); 1111 buf = get_address(buf, &b, &e);
1106 1112
1113# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
1107 // remember orig command line 1114 // remember orig command line
1108 orig_buf = buf; 1115 orig_buf = buf;
1116# endif
1109 1117
1110 // get the COMMAND into cmd[] 1118 // get the COMMAND into cmd[]
1111 buf1 = cmd; 1119 buf1 = cmd;
@@ -1149,7 +1157,7 @@ static void colon(char *buf)
1149 dot_skip_over_ws(); 1157 dot_skip_over_ws();
1150 } 1158 }
1151 } 1159 }
1152#if ENABLE_FEATURE_ALLOW_EXEC 1160# if ENABLE_FEATURE_ALLOW_EXEC
1153 else if (cmd[0] == '!') { // run a cmd 1161 else if (cmd[0] == '!') { // run a cmd
1154 int retcode; 1162 int retcode;
1155 // :!ls run the <cmd> 1163 // :!ls run the <cmd>
@@ -1161,7 +1169,7 @@ static void colon(char *buf)
1161 rawmode(); 1169 rawmode();
1162 Hit_Return(); // let user see results 1170 Hit_Return(); // let user see results
1163 } 1171 }
1164#endif 1172# endif
1165 else if (cmd[0] == '=' && !cmd[1]) { // where is the address 1173 else if (cmd[0] == '=' && !cmd[1]) { // where is the address
1166 if (b < 0) { // no addr given- use defaults 1174 if (b < 0) { // no addr given- use defaults
1167 b = e = count_lines(text, dot); 1175 b = e = count_lines(text, dot);
@@ -1196,7 +1204,7 @@ static void colon(char *buf)
1196 1204
1197 size = init_text_buffer(fn); 1205 size = init_text_buffer(fn);
1198 1206
1199#if ENABLE_FEATURE_VI_YANKMARK 1207# if ENABLE_FEATURE_VI_YANKMARK
1200 if (Ureg >= 0 && Ureg < 28) { 1208 if (Ureg >= 0 && Ureg < 28) {
1201 free(reg[Ureg]); // free orig line reg- for 'U' 1209 free(reg[Ureg]); // free orig line reg- for 'U'
1202 reg[Ureg] = NULL; 1210 reg[Ureg] = NULL;
@@ -1205,7 +1213,7 @@ static void colon(char *buf)
1205 free(reg[YDreg]); // free default yank/delete register 1213 free(reg[YDreg]); // free default yank/delete register
1206 reg[YDreg] = NULL; 1214 reg[YDreg] = NULL;
1207 } 1215 }
1208#endif 1216# endif
1209 // how many lines in text[]? 1217 // how many lines in text[]?
1210 li = count_lines(text, end - 1); 1218 li = count_lines(text, end - 1);
1211 status_line("'%s'%s" 1219 status_line("'%s'%s"
@@ -1352,16 +1360,16 @@ static void colon(char *buf)
1352 optind = -1; /* start from 0th file */ 1360 optind = -1; /* start from 0th file */
1353 editing = 0; 1361 editing = 0;
1354 } 1362 }
1355#if ENABLE_FEATURE_VI_SET 1363# if ENABLE_FEATURE_VI_SET
1356 } else if (strncmp(cmd, "set", i) == 0) { // set or clear features 1364 } else if (strncmp(cmd, "set", i) == 0) { // set or clear features
1357#if ENABLE_FEATURE_VI_SETOPTS 1365# if ENABLE_FEATURE_VI_SETOPTS
1358 char *argp; 1366 char *argp;
1359#endif 1367# endif
1360 i = 0; // offset into args 1368 i = 0; // offset into args
1361 // only blank is regarded as args delimiter. What about tab '\t'? 1369 // only blank is regarded as args delimiter. What about tab '\t'?
1362 if (!args[0] || strcasecmp(args, "all") == 0) { 1370 if (!args[0] || strcasecmp(args, "all") == 0) {
1363 // print out values of all options 1371 // print out values of all options
1364#if ENABLE_FEATURE_VI_SETOPTS 1372# if ENABLE_FEATURE_VI_SETOPTS
1365 status_line_bold( 1373 status_line_bold(
1366 "%sautoindent " 1374 "%sautoindent "
1367 "%sflash " 1375 "%sflash "
@@ -1374,10 +1382,10 @@ static void colon(char *buf)
1374 showmatch ? "" : "no", 1382 showmatch ? "" : "no",
1375 tabstop 1383 tabstop
1376 ); 1384 );
1377#endif 1385# endif
1378 goto ret; 1386 goto ret;
1379 } 1387 }
1380#if ENABLE_FEATURE_VI_SETOPTS 1388# if ENABLE_FEATURE_VI_SETOPTS
1381 argp = args; 1389 argp = args;
1382 while (*argp) { 1390 while (*argp) {
1383 if (strncmp(argp, "no", 2) == 0) 1391 if (strncmp(argp, "no", 2) == 0)
@@ -1395,16 +1403,17 @@ static void colon(char *buf)
1395 argp = skip_non_whitespace(argp); 1403 argp = skip_non_whitespace(argp);
1396 argp = skip_whitespace(argp); 1404 argp = skip_whitespace(argp);
1397 } 1405 }
1398#endif /* FEATURE_VI_SETOPTS */ 1406# endif /* FEATURE_VI_SETOPTS */
1399#endif /* FEATURE_VI_SET */ 1407# endif /* FEATURE_VI_SET */
1400#if ENABLE_FEATURE_VI_SEARCH 1408
1409# if ENABLE_FEATURE_VI_SEARCH
1401 } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern 1410 } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern
1402 char *F, *R, *flags; 1411 char *F, *R, *flags;
1403 size_t len_F, len_R; 1412 size_t len_F, len_R;
1404 int gflag; // global replace flag 1413 int gflag; // global replace flag
1405#if ENABLE_FEATURE_VI_UNDO 1414# if ENABLE_FEATURE_VI_UNDO
1406 int dont_chain_first_item = ALLOW_UNDO; 1415 int dont_chain_first_item = ALLOW_UNDO;
1407#endif 1416# endif
1408 1417
1409 // F points to the "find" pattern 1418 // F points to the "find" pattern
1410 // R points to the "replace" pattern 1419 // R points to the "replace" pattern
@@ -1441,9 +1450,9 @@ static void colon(char *buf)
1441 // we found the "find" pattern - delete it 1450 // we found the "find" pattern - delete it
1442 // For undo support, the first item should not be chained 1451 // For undo support, the first item should not be chained
1443 text_hole_delete(found, found + len_F - 1, dont_chain_first_item); 1452 text_hole_delete(found, found + len_F - 1, dont_chain_first_item);
1444#if ENABLE_FEATURE_VI_UNDO 1453# if ENABLE_FEATURE_VI_UNDO
1445 dont_chain_first_item = ALLOW_UNDO_CHAIN; 1454 dont_chain_first_item = ALLOW_UNDO_CHAIN;
1446#endif 1455# endif
1447 // insert the "replace" patern 1456 // insert the "replace" patern
1448 bias = string_insert(found, R, ALLOW_UNDO_CHAIN); 1457 bias = string_insert(found, R, ALLOW_UNDO_CHAIN);
1449 found += bias; 1458 found += bias;
@@ -1459,7 +1468,7 @@ static void colon(char *buf)
1459 } 1468 }
1460 q = next_line(ls); 1469 q = next_line(ls);
1461 } 1470 }
1462#endif /* FEATURE_VI_SEARCH */ 1471# endif /* FEATURE_VI_SEARCH */
1463 } else if (strncmp(cmd, "version", i) == 0) { // show software version 1472 } else if (strncmp(cmd, "version", i) == 0) { // show software version
1464 status_line(BB_VER); 1473 status_line(BB_VER);
1465 } else if (strncmp(cmd, "write", i) == 0 // write text to file 1474 } else if (strncmp(cmd, "write", i) == 0 // write text to file
@@ -1474,12 +1483,12 @@ static void colon(char *buf)
1474 if (args[0]) { 1483 if (args[0]) {
1475 fn = args; 1484 fn = args;
1476 } 1485 }
1477#if ENABLE_FEATURE_VI_READONLY 1486# if ENABLE_FEATURE_VI_READONLY
1478 if (readonly_mode && !useforce) { 1487 if (readonly_mode && !useforce) {
1479 status_line_bold("'%s' is read only", fn); 1488 status_line_bold("'%s' is read only", fn);
1480 goto ret; 1489 goto ret;
1481 } 1490 }
1482#endif 1491# endif
1483 //if (useforce) { 1492 //if (useforce) {
1484 // if "fn" is not write-able, chmod u+w 1493 // if "fn" is not write-able, chmod u+w
1485 // sprintf(syscmd, "chmod u+w %s", fn); 1494 // sprintf(syscmd, "chmod u+w %s", fn);
@@ -1519,7 +1528,7 @@ static void colon(char *buf)
1519 } 1528 }
1520 } 1529 }
1521 } 1530 }
1522#if ENABLE_FEATURE_VI_YANKMARK 1531# if ENABLE_FEATURE_VI_YANKMARK
1523 } else if (strncmp(cmd, "yank", i) == 0) { // yank lines 1532 } else if (strncmp(cmd, "yank", i) == 0) { // yank lines
1524 if (b < 0) { // no addr given- use defaults 1533 if (b < 0) { // no addr given- use defaults
1525 q = begin_line(dot); // assume .,. for the range 1534 q = begin_line(dot); // assume .,. for the range
@@ -1529,7 +1538,7 @@ static void colon(char *buf)
1529 li = count_lines(q, r); 1538 li = count_lines(q, r);
1530 status_line("Yank %d lines (%d chars) into [%c]", 1539 status_line("Yank %d lines (%d chars) into [%c]",
1531 li, strlen(reg[YDreg]), what_reg()); 1540 li, strlen(reg[YDreg]), what_reg());
1532#endif 1541# endif
1533 } else { 1542 } else {
1534 // cmd unknown 1543 // cmd unknown
1535 not_implemented(cmd); 1544 not_implemented(cmd);
@@ -1537,10 +1546,10 @@ static void colon(char *buf)
1537 ret: 1546 ret:
1538 dot = bound_dot(dot); // make sure "dot" is valid 1547 dot = bound_dot(dot); // make sure "dot" is valid
1539 return; 1548 return;
1540#if ENABLE_FEATURE_VI_SEARCH 1549# if ENABLE_FEATURE_VI_SEARCH
1541 colon_s_fail: 1550 colon_s_fail:
1542 status_line(":s expression missing delimiters"); 1551 status_line(":s expression missing delimiters");
1543#endif 1552# endif
1544#endif /* FEATURE_VI_COLON */ 1553#endif /* FEATURE_VI_COLON */
1545} 1554}
1546 1555
diff --git a/examples/var_service/dhcp_if/README b/examples/var_service/dhcp_if/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/dhcp_if/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/dhcp_if/dhcp_handler b/examples/var_service/dhcp_if/dhcp_handler
index 3d44a6022..6a97e8543 100755
--- a/examples/var_service/dhcp_if/dhcp_handler
+++ b/examples/var_service/dhcp_if/dhcp_handler
@@ -52,7 +52,7 @@ if test x"$1" != x"bound" && test x"$1" != x"renew" ; then
52 rm "$file_ntpconf" 52 rm "$file_ntpconf"
53 rm "$dir_ipconf/$file_ipconf" 53 rm "$dir_ipconf/$file_ipconf"
54 rm "$dir_ntpconf/$file_ntpconf" 54 rm "$dir_ntpconf/$file_ntpconf"
55 sv u /var/service/fw 55 svc -u fw
56 exit 56 exit
57fi 57fi
58 58
@@ -67,10 +67,10 @@ if test $? != 0; then
67 echo "Reconfiguring fw" 67 echo "Reconfiguring fw"
68 mkdir -p "$dir_ipconf" 2>/dev/null 68 mkdir -p "$dir_ipconf" 2>/dev/null
69 cp "$file_ipconf" "$dir_ipconf/$file_ipconf" 69 cp "$file_ipconf" "$dir_ipconf/$file_ipconf"
70 sv u /var/service/fw 70 svc -u fw
71fi 71fi
72 72
73if test -d /var/service/ntpd; then 73if test -d ../ntpd; then
74 ./convert2ntpconf "$file_ntpconf" 74 ./convert2ntpconf "$file_ntpconf"
75 # Reconfigure ntp server addresses if needed 75 # Reconfigure ntp server addresses if needed
76 diff --brief "$file_ntpconf" "$dir_ntpconf/$file_ntpconf" >/dev/null 2>&1 76 diff --brief "$file_ntpconf" "$dir_ntpconf/$file_ntpconf" >/dev/null 2>&1
@@ -78,7 +78,7 @@ if test -d /var/service/ntpd; then
78 echo "Reconfiguring ntp" 78 echo "Reconfiguring ntp"
79 mkdir -p "$dir_ntpconf" 2>/dev/null 79 mkdir -p "$dir_ntpconf" 2>/dev/null
80 cp "$file_ntpconf" "$dir_ntpconf/$file_ntpconf" 80 cp "$file_ntpconf" "$dir_ntpconf/$file_ntpconf"
81 sv t /var/service/ntpd 81 svc -t ntpd
82 sv u /var/service/ntpd 82 svc -u ntpd
83 fi 83 fi
84fi 84fi
diff --git a/examples/var_service/dhcp_if/finish b/examples/var_service/dhcp_if/finish
index 5e7667a2d..8ce188336 100755
--- a/examples/var_service/dhcp_if/finish
+++ b/examples/var_service/dhcp_if/finish
@@ -14,4 +14,4 @@ rm "$file_ipconf"
14rm "$file_ntpconf" 14rm "$file_ntpconf"
15rm "$dir_ipconf/$file_ipconf" 15rm "$dir_ipconf/$file_ipconf"
16rm "$dir_ntpconf/$file_ntpconf" 16rm "$dir_ntpconf/$file_ntpconf"
17sv u /var/service/fw 17svc -u fw
diff --git a/examples/var_service/dhcp_if/log/run b/examples/var_service/dhcp_if/log/run
index 69d74b73f..756be4e7e 100755
--- a/examples/var_service/dhcp_if/log/run
+++ b/examples/var_service/dhcp_if/log/run
@@ -1,21 +1,2 @@
1#!/bin/sh 1#!/bin/sh
2 2exec std_service_logger
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/dhcp_if/p_log b/examples/var_service/dhcp_if/p_log
deleted file mode 100755
index a2521be05..000000000
--- a/examples/var_service/dhcp_if/p_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/dhcp_if/w_log b/examples/var_service/dhcp_if/w_log
deleted file mode 100755
index aa36ef13b..000000000
--- a/examples/var_service/dhcp_if/w_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4watch -n2 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b1-$((w-2))'
diff --git a/examples/var_service/dhcp_if_pinger/README b/examples/var_service/dhcp_if_pinger/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/dhcp_if_pinger/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/dhcp_if_pinger/run b/examples/var_service/dhcp_if_pinger/run
index 8aca90c1a..25341243f 100755
--- a/examples/var_service/dhcp_if_pinger/run
+++ b/examples/var_service/dhcp_if_pinger/run
@@ -21,9 +21,9 @@ if test -f "$0.log"; then
21 mv "$0.log.new" "$0.log" 21 mv "$0.log.new" "$0.log"
22fi 22fi
23 23
24test -f "/var/service/dhcp_$if/env.out" || exec env - sleep "$ping_time" 24test -f "../dhcp_$if/env.out" || exec env - sleep "$ping_time"
25 25
26. "/var/service/dhcp_$if/env.out" 26. "../dhcp_$if/env.out"
27test x"$router" != x"" || exec env - sleep "$ping_time" 27test x"$router" != x"" || exec env - sleep "$ping_time"
28 28
29#msg "Pinging $router" 29#msg "Pinging $router"
@@ -36,12 +36,12 @@ while true; do
36 env - sleep "$retry_time" 36 env - sleep "$retry_time"
37done 37done
38 38
39test -d "/var/service/dhcp_$if" && { 39test -d "../dhcp_$if" && {
40 msg "Restarting /var/service/dhcp_$if" 40 msg "Restarting dhcp_$if"
41 sv t "/var/service/dhcp_$if" 41 svc -t "dhcp_$if"
42} 42}
43test -d "/var/service/supplicant_$if" && { 43test -d "../supplicant_$if" && {
44 msg "Restarting /var/service/supplicant_$if" 44 msg "Restarting supplicant_$if"
45 sv t "/var/service/supplicant_$if" 45 svc -t "supplicant_$if"
46} 46}
47exec env - sleep "$ping_time" 47exec env - sleep "$ping_time"
diff --git a/examples/var_service/dhcpd_if/README b/examples/var_service/dhcpd_if/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/dhcpd_if/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/dhcpd_if/log/run b/examples/var_service/dhcpd_if/log/run
index 69d74b73f..756be4e7e 100755
--- a/examples/var_service/dhcpd_if/log/run
+++ b/examples/var_service/dhcpd_if/log/run
@@ -1,21 +1,2 @@
1#!/bin/sh 1#!/bin/sh
2 2exec std_service_logger
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/dhcpd_if/p_log b/examples/var_service/dhcpd_if/p_log
deleted file mode 100755
index a2521be05..000000000
--- a/examples/var_service/dhcpd_if/p_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/dhcpd_if/w_log b/examples/var_service/dhcpd_if/w_log
deleted file mode 100755
index dba76c69b..000000000
--- a/examples/var_service/dhcpd_if/w_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir
4watch -n1 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b0-$((w-2))'
diff --git a/examples/var_service/dnsmasq/log/run b/examples/var_service/dnsmasq/log/run
index 69d74b73f..756be4e7e 100755
--- a/examples/var_service/dnsmasq/log/run
+++ b/examples/var_service/dnsmasq/log/run
@@ -1,21 +1,2 @@
1#!/bin/sh 1#!/bin/sh
2 2exec std_service_logger
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/dnsmasq/p_log b/examples/var_service/dnsmasq/p_log
deleted file mode 100755
index a2521be05..000000000
--- a/examples/var_service/dnsmasq/p_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/dnsmasq/w_log b/examples/var_service/dnsmasq/w_log
deleted file mode 100755
index aa36ef13b..000000000
--- a/examples/var_service/dnsmasq/w_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4watch -n2 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b1-$((w-2))'
diff --git a/examples/var_service/ftpd/README b/examples/var_service/ftpd/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/ftpd/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/ftpd/log/run b/examples/var_service/ftpd/log/run
index 69d74b73f..756be4e7e 100755
--- a/examples/var_service/ftpd/log/run
+++ b/examples/var_service/ftpd/log/run
@@ -1,21 +1,2 @@
1#!/bin/sh 1#!/bin/sh
2 2exec std_service_logger
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/ftpd/p_log b/examples/var_service/ftpd/p_log
deleted file mode 100755
index a2521be05..000000000
--- a/examples/var_service/ftpd/p_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/ftpd/w_log b/examples/var_service/ftpd/w_log
deleted file mode 100755
index aa36ef13b..000000000
--- a/examples/var_service/ftpd/w_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4watch -n2 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b1-$((w-2))'
diff --git a/examples/var_service/fw/README b/examples/var_service/fw/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/fw/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/fw/etc/dnsmasq_servers.conf b/examples/var_service/fw/etc/dnsmasq_servers.conf
index 68313605f..c39fe6e43 100644
--- a/examples/var_service/fw/etc/dnsmasq_servers.conf
+++ b/examples/var_service/fw/etc/dnsmasq_servers.conf
@@ -35,4 +35,4 @@ $empty && echo "server=8.8.8.8"
35$empty && echo "server=8.8.4.4" 35$empty && echo "server=8.8.4.4"
36 36
37# SIGHUP: make dnsmasq reload config 37# SIGHUP: make dnsmasq reload config
38sv h dnsmasq 38svc -h dnsmasq
diff --git a/examples/var_service/fw/run b/examples/var_service/fw/run
index 1fd71cc01..41078d0ab 100755
--- a/examples/var_service/fw/run
+++ b/examples/var_service/fw/run
@@ -8,7 +8,7 @@ extif="if"
8ext_open_tcp="22 80 88" # space-separated 8ext_open_tcp="22 80 88" # space-separated
9 9
10# Make ourself one-shot 10# Make ourself one-shot
11sv o . 11svc -o .
12# Debug 12# Debug
13#date '+%Y-%m-%d %H:%M:%S' >>"$0.log" 13#date '+%Y-%m-%d %H:%M:%S' >>"$0.log"
14 14
diff --git a/examples/var_service/getty_tty1/README b/examples/var_service/getty_tty1/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/getty_tty1/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/getty_tty1/cfg b/examples/var_service/getty_tty1/cfg
index 0f63e5233..ab973f738 100755
--- a/examples/var_service/getty_tty1/cfg
+++ b/examples/var_service/getty_tty1/cfg
@@ -10,7 +10,7 @@ ttyname=`tty`
10ttybase="${ttyname%%[0123456789]*}" # strip numeric tail 10ttybase="${ttyname%%[0123456789]*}" # strip numeric tail
11 11
12if test x"$ttybase" = x"/dev/vc/" -o x"$ttybase" = x"/dev/tty"; then 12if test x"$ttybase" = x"/dev/vc/" -o x"$ttybase" = x"/dev/tty"; then
13 echo "* Activating Cyrillic KOI8-R -> CP866 font map" 13 echo "* Activating font map"
14 echo -ne "\033(K" >"$ttyname" 14 echo -ne "\033(K" >"$ttyname"
15 15
16 echo "* Loading screen font" 16 echo "* Loading screen font"
@@ -18,9 +18,9 @@ if test x"$ttybase" = x"/dev/vc/" -o x"$ttybase" = x"/dev/tty"; then
18 -C "$ttyname" \ 18 -C "$ttyname" \
19 -m "$PWD/koi8r_to_uni.trans" \ 19 -m "$PWD/koi8r_to_uni.trans" \
20 "$PWD/alt08x16+unimap.fnt" \ 20 "$PWD/alt08x16+unimap.fnt" \
21 || echo "! setfont failure" 21 || echo "setfont exit code: $?"
22 22
23 echo "* Loading keymap" 23 echo "* Loading keymap"
24 loadkeys "$PWD/ru_koi8r.keymap" \ 24 loadkeys "$PWD/unicode_cyrillic.keymap" \
25 || echo "! loadkeys failure" 25 || echo "loadkeys exit code: $?"
26fi 26fi
diff --git a/examples/var_service/getty_tty1/login.sh b/examples/var_service/getty_tty1/login.sh
index d69b6fd55..f8b53fc03 100755
--- a/examples/var_service/getty_tty1/login.sh
+++ b/examples/var_service/getty_tty1/login.sh
@@ -6,7 +6,8 @@ ttybase="${ttyname%%[0123456789]*}" # strip numeric tail
6if test "$ttybase" = "/dev/tty"; then 6if test "$ttybase" = "/dev/tty"; then
7 tail="${ttyname:8}" 7 tail="${ttyname:8}"
8 echo "* Setting terminal device's owner to $LOGIN_UID:$LOGIN_GID" 8 echo "* Setting terminal device's owner to $LOGIN_UID:$LOGIN_GID"
9 chown "$LOGIN_UID:$LOGIN_GID" "/dev/vcs$tail" "/dev/vcsa$tail" 9 test -c "/dev/vcs$tail" && chown "$LOGIN_UID:$LOGIN_GID" "/dev/vcs$tail"
10 test -c "/dev/vcsa$tail" && chown "$LOGIN_UID:$LOGIN_GID" "/dev/vcsa$tail"
10fi 11fi
11# We can do this also, but login does it itself 12# We can do this also, but login does it itself
12# chown "$LOGIN_UID:$LOGIN_GID" "$ttyname" 13# chown "$LOGIN_UID:$LOGIN_GID" "$ttyname"
diff --git a/examples/var_service/getty_tty1/ru_koi8r.keymap b/examples/var_service/getty_tty1/ru_koi8r.keymap
deleted file mode 100644
index 6c811539c..000000000
--- a/examples/var_service/getty_tty1/ru_koi8r.keymap
+++ /dev/null
@@ -1,183 +0,0 @@
1keymaps 0,1, 2,3, 4,6, 8,10, 12,14
2#
3# This one is for generating koi8r Russian chars
4# Cyr/Lat switches: RightAlt, Shift+Ctrl, Ctrl+Shift
5# (last one does not work for dark and obscure reasons 8( )
6#
7# plain,shift, plain,shift, ctrl,ctrl alt,alt ctrlalt,ctrlalt
8# lat-------- cyr-------- lat cyr lat cyr lat cyr
9#
10#Shift 1
11#AltGr (cyr) 2
12#Control 4
13#Alt 8
14#ShiftL 16
15#ShiftR 32
16#CtrlL 64
17#CtrlR 128
18#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
19keycode 1 = Escape Escape Escape Escape Escape Escape Meta_Escape Meta_Escape SAK SAK
20keycode 2 = one exclam one exclam exclam exclam Meta_one Meta_one
21keycode 3 = two at two at nul nul Meta_two Meta_two
22keycode 4 = three numbersign three numbersign three three Meta_three Meta_three
23keycode 5 = four dollar four dollar Control_backslash Control_backslash Meta_four Meta_four
24keycode 6 = five percent five percent Control_bracketright Control_bracketright Meta_five Meta_five
25keycode 7 = six asciicircum six asciicircum Control_asciicircum Control_asciicircum Meta_six Meta_six
26keycode 8 = seven ampersand seven ampersand Control_underscore Control_underscore Meta_seven Meta_seven
27keycode 9 = eight asterisk eight asterisk eight eight Meta_eight Meta_eight
28keycode 10 = nine parenleft nine parenleft nine nine Meta_nine Meta_nine
29keycode 11 = zero parenright zero parenright zero zero Meta_zero Meta_zero
30keycode 12 = minus underscore minus underscore Control_underscore Control_underscore Meta_minus Meta_minus
31keycode 13 = equal plus equal plus equal equal Meta_equal Meta_equal
32keycode 14 = Delete Delete Delete Delete BackSpace BackSpace Meta_Delete Meta_Delete
33keycode 15 = Tab Tab Tab Tab Tab Tab Meta_Tab Meta_Tab
34keycode 16 = q Q 202 234 Control_q Control_q Meta_q Meta_q Meta_Control_q Meta_Control_q
35keycode 17 = w W 195 227 Control_w Control_w Meta_w Meta_w Meta_Control_w Meta_Control_w
36keycode 18 = e E 213 245 Control_e Control_e Meta_e Meta_e Meta_Control_e Meta_Control_e
37keycode 19 = r R 203 235 Control_r Control_r Meta_r Meta_r Meta_Control_r Meta_Control_r
38keycode 20 = t T 197 229 Control_t Control_t Meta_t Meta_t Meta_Control_t Meta_Control_t
39#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
40keycode 21 = y Y 206 238 Control_y Control_y Meta_y Meta_y Meta_Control_y Meta_Control_y
41keycode 22 = u U 199 231 Control_u Control_u Meta_u Meta_u Meta_Control_u Meta_Control_u
42keycode 23 = i I 219 251 Control_i Control_i Meta_i Meta_i Meta_Control_i Meta_Control_i
43keycode 24 = o O 221 253 Control_o Control_o Meta_o Meta_o Meta_Control_o Meta_Control_o
44keycode 25 = p P 218 250 Control_p Control_p Meta_p Meta_p Meta_Control_p Meta_Control_p
45keycode 26 = bracketleft braceleft 200 232 Escape Escape Meta_bracketleft Meta_bracketleft
46keycode 27 = bracketright braceright 223 255 Control_bracketright Control_bracketright
47keycode 28 = Return
48# Shift+Ctrl - Cyrillic
49keycode 29 = Control AltGr_Lock Control AltGr_Lock Control Control Control Control Control Control
50keycode 30 = a A 198 230 Control_a Control_a Meta_a Meta_a Meta_Control_a Meta_Control_a
51keycode 31 = s S 217 249 Control_s Control_s Meta_s Meta_s Meta_Control_s Meta_Control_s
52keycode 32 = d D 215 247 Control_d Control_d Meta_d Meta_d Meta_Control_d Meta_Control_d
53keycode 33 = f F 193 225 Control_f Control_f Meta_f Meta_f Meta_Control_f Meta_Control_f
54keycode 34 = g G 208 240 Control_g Control_g Meta_g Meta_g Meta_Control_g Meta_Control_g
55keycode 35 = h H 210 242 Control_h Control_h Meta_h Meta_h Meta_Control_h Meta_Control_h
56keycode 36 = j J 207 239 Control_j Control_j Meta_j Meta_j Meta_Control_j Meta_Control_j
57keycode 37 = k K 204 236 Control_k Control_k Meta_k Meta_k Meta_Control_k Meta_Control_k
58keycode 38 = l L 196 228 Control_l Control_l Meta_l Meta_l Meta_Control_l Meta_Control_l
59keycode 39 = semicolon colon 214 246 semicolon semicolon Meta_semicolon Meta_semicolon
60keycode 40 = apostrophe quotedbl 220 252 Control_g Control_g Meta_apostrophe Meta_apostrophe
61#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
62keycode 41 = grave asciitilde grave asciitilde nul nul Meta_grave Meta_grave
63keycode 42 = Shift
64keycode 43 = backslash bar backslash bar Control_backslash Control_backslash Meta_backslash Meta_backslash
65keycode 44 = z Z 209 241 Control_z Control_z Meta_z Meta_z Meta_Control_z Meta_Control_z
66keycode 45 = x X 222 254 Control_x Control_x Meta_x Meta_x Meta_Control_x Meta_Control_x
67keycode 46 = c C 211 243 Control_c Control_c Meta_c Meta_c Meta_Control_c Meta_Control_c
68keycode 47 = v V 205 237 Control_v Control_v Meta_v Meta_v Meta_Control_v Meta_Control_v
69keycode 48 = b B 201 233 Control_b Control_b Meta_b Meta_b Meta_Control_b Meta_Control_b
70keycode 49 = n N 212 244 Control_n Control_n Meta_n Meta_n Meta_Control_n Meta_Control_n
71keycode 50 = m M 216 248 Control_m Control_m Meta_m Meta_m Meta_Control_m Meta_Control_m
72keycode 51 = comma less 194 226 comma comma Meta_comma Meta_comma
73keycode 52 = period greater 192 224 Compose Compose Meta_period Meta_period
74keycode 53 = slash question slash question Delete Delete Meta_slash Meta_slash Meta_question Meta_question
75# Ctrl+Shift - Cyrillic (not working???)
76keycode 54 = Shift Shift Shift Shift AltGr_Lock AltGr_Lock Shift Shift Shift Shift
77keycode 55 = KP_Multiply
78keycode 56 = Alt
79keycode 57 = space space space space nul nul Meta_space Meta_space
80keycode 58 = Caps_Lock
81keycode 59 = F1 F11 F1 F11 F1 F1 Console_1 Console_1 Console_1 Console_1
82keycode 60 = F2 F12 F2 F12 F2 F2 Console_2 Console_2 Console_2 Console_2
83#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
84keycode 61 = F3 F13 F3 F13 F3 F3 Console_3 Console_3 Console_3 Console_3
85keycode 62 = F4 F14 F4 F14 F4 F4 Console_4 Console_4 Console_4 Console_4
86keycode 63 = F5 F15 F5 F15 F5 F5 Console_5 Console_5 Console_5 Console_5
87keycode 64 = F6 F16 F6 F16 F6 F6 Console_6 Console_6 Console_6 Console_6
88keycode 65 = F7 F17 F7 F17 F7 F7 Console_7 Console_7 Console_7 Console_7
89keycode 66 = F8 F18 F8 F18 F8 F8 Console_8 Console_8 Console_8 Console_8
90keycode 67 = F9 F19 F9 F19 F9 F9 Console_9 Console_9 Console_9 Console_9
91keycode 68 = F10 F20 F10 F20 F10 F10 Console_10 Console_10 Console_10 Console_10
92keycode 69 = Num_Lock Bare_Num_Lock Num_Lock Bare_Num_Lock
93keycode 70 = Scroll_Lock Show_Memory Scroll_Lock Show_Memory Show_State Show_State
94keycode 71 = KP_7 KP_7 KP_7 KP_7 KP_7 KP_7 Ascii_7 Ascii_7
95keycode 72 = KP_8 KP_8 KP_8 KP_8 KP_8 KP_8 Ascii_8 Ascii_8
96keycode 73 = KP_9 KP_9 KP_9 KP_9 KP_9 KP_9 Ascii_9 Ascii_9
97keycode 74 = KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract
98keycode 75 = KP_4 KP_4 KP_4 KP_4 KP_4 KP_4 Ascii_4 Ascii_4
99keycode 76 = KP_5 KP_5 KP_5 KP_5 KP_5 KP_5 Ascii_5 Ascii_5
100keycode 77 = KP_6 KP_6 KP_6 KP_6 KP_6 KP_6 Ascii_6 Ascii_6
101keycode 78 = KP_Add KP_Add KP_Add KP_Add KP_Add KP_Add KP_Add KP_Add
102keycode 79 = KP_1 KP_1 KP_1 KP_1 KP_1 KP_1 Ascii_1 Ascii_1
103keycode 80 = KP_2 KP_2 KP_2 KP_2 KP_2 KP_2 Ascii_2 Ascii_2
104#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
105keycode 81 = KP_3 KP_3 KP_3 KP_3 KP_3 KP_3 Ascii_3 Ascii_3
106keycode 82 = KP_0 KP_0 KP_0 KP_0 KP_0 KP_0 Ascii_0 Ascii_0
107keycode 83 = KP_Period KP_Period KP_Period KP_Period KP_Period KP_Period KP_Period KP_Period Boot Boot
108keycode 84 = Last_Console
109keycode 85 =
110keycode 86 = less greater less greater less less Meta_less Meta_less
111keycode 87 = F11 F11 F11 F11 F11 F11 Console_11 Console_11 Console_11 Console_11
112keycode 88 = F12 F12 F12 F12 F12 F12 Console_12 Console_12 Console_12 Console_12
113keycode 89 =
114keycode 90 =
115keycode 91 =
116keycode 92 =
117keycode 93 =
118keycode 94 =
119keycode 95 =
120keycode 96 = KP_Enter
121keycode 97 = Control
122keycode 98 = KP_Divide
123keycode 99 = Control_backslash
124# Right Alt - Cyrillic
125keycode 100 = AltGr_Lock
126#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
127keycode 101 = Break
128keycode 102 = Find
129keycode 103 = Up
130keycode 104 = Prior Scroll_Backward Prior Scroll_Backward Prior Prior Prior Prior Prior Prior
131keycode 105 = Left Left Left Left Left Left Left Left Decr_Console Decr_Console
132keycode 106 = Right Right Right Right Right Right Right Right Incr_Console Incr_Console
133keycode 107 = Select
134keycode 108 = Down
135keycode 109 = Next Scroll_Forward Next Scroll_Forward Next Next Next Next Next Next
136keycode 110 = Insert
137keycode 111 = Remove Remove Remove Remove Remove Remove Remove Remove Boot Boot
138keycode 112 = Macro
139keycode 113 = F13
140keycode 114 = F14
141keycode 115 = Help
142keycode 116 = Do
143keycode 117 = F17
144keycode 118 = KP_MinPlus
145keycode 119 = Pause
146keycode 120 =
147#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
148keycode 121 =
149keycode 122 =
150keycode 123 =
151keycode 124 =
152keycode 125 =
153keycode 126 =
154keycode 127 =
155
156string F1 = "\033[[A"
157string F2 = "\033[[B"
158string F3 = "\033[[C"
159string F4 = "\033[[D"
160string F5 = "\033[[E"
161string F6 = "\033[17~"
162string F7 = "\033[18~"
163string F8 = "\033[19~"
164string F9 = "\033[20~"
165string F10 = "\033[21~"
166string F11 = "\033[23~"
167string F12 = "\033[24~"
168string F13 = "\033[25~"
169string F14 = "\033[26~"
170string F15 = "\033[28~"
171string F16 = "\033[29~"
172string F17 = "\033[31~"
173string F18 = "\033[32~"
174string F19 = "\033[33~"
175string F20 = "\033[34~"
176string Find = "\033[1~"
177string Insert = "\033[2~"
178string Remove = "\033[3~"
179string Select = "\033[4~"
180string Prior = "\033[5~"
181string Next = "\033[6~"
182string Macro = "\033[M"
183string Pause = "\033[P"
diff --git a/examples/var_service/getty_tty1/run b/examples/var_service/getty_tty1/run
index c7c413ba4..c5b291b4d 100755
--- a/examples/var_service/getty_tty1/run
+++ b/examples/var_service/getty_tty1/run
@@ -1,9 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2 2
3exec >/dev/null
4exec 2>&1
5exec </dev/null
6
7user=root 3user=root
8baud=38400 4baud=38400
9delay=3 5delay=3
@@ -25,6 +21,4 @@ test -x ./cfg && . ./cfg
25 21
26exec \ 22exec \
27env - "TERM=$TERM" PATH="$PATH" LOGIN_PRE_SUID_SCRIPT="$PWD/login.sh" \ 23env - "TERM=$TERM" PATH="$PATH" LOGIN_PRE_SUID_SCRIPT="$PWD/login.sh" \
28softlimit \
29setuidgid "$user" \
30getty "$baud" "$tty" "$TERM" 24getty "$baud" "$tty" "$TERM"
diff --git a/examples/var_service/getty_tty1/unicode_cyrillic.keymap b/examples/var_service/getty_tty1/unicode_cyrillic.keymap
new file mode 100644
index 000000000..49911cd10
--- /dev/null
+++ b/examples/var_service/getty_tty1/unicode_cyrillic.keymap
@@ -0,0 +1,200 @@
1keymaps 0,1, 2,3, 4,6, 8,9, 10,11, 12,14
2#
3# This one is for generating Unicode Curillic chars
4# Cyr/Lat switches: RightAlt, Shift+Ctrl, Ctrl+Shift, Win keys
5#
6# plain,shift, plain,shift, ctrl,ctrl alt,shiftalt alt,shiftalt ctrlalt,ctrlalt
7# lat-------- cyr-------- lat cyr lat--------- cyr--------- lat cyr
8#
9#Shift 1
10#AltGr (cyr) 2
11#Control 4
12#Alt 8
13#ShiftL 16
14#ShiftR 32
15#CtrlL 64
16#CtrlR 128
17
18# L/R Ctrl: Shift+Ctrl - Cyrillic
19keycode 29 = Control AltGr_Lock Control AltGr_Lock Control Control Control Control Control Control Control Control
20keycode 97 = Control AltGr_Lock Control AltGr_Lock Control Control Control Control Control Control Control Control
21# L/R Shift: Ctrl+Shift - Cyrillic
22keycode 42 = Shift Shift Shift Shift AltGr_Lock AltGr_Lock Shift Shift Shift Shift Shift Shift
23keycode 54 = Shift Shift Shift Shift AltGr_Lock AltGr_Lock Shift Shift Shift Shift Shift Shift
24# Right Alt: Cyrillic
25keycode 100 = AltGr_Lock
26# L/R Win: Cyrillic
27keycode 125 = AltGr_Lock
28keycode 126 = AltGr_Lock
29
30#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt shift ============= alt cyr =============== alt shift cur ========= ctrlalt =============== ctrlalt cyr ===========
31keycode 1 = Escape Escape Escape Escape Escape Escape Meta_Escape Meta_Escape Meta_Escape Meta_Escape SAK SAK
32keycode 2 = one exclam one exclam exclam exclam Meta_one Meta_one Meta_one Meta_one
33keycode 3 = two at two at nul nul Meta_two Meta_two Meta_two Meta_two
34keycode 4 = three numbersign three numbersign three three Meta_three Meta_three Meta_three Meta_three
35keycode 5 = four dollar four dollar Control_backslash Control_backslash Meta_four Meta_four Meta_four Meta_four
36keycode 6 = five percent five percent Control_bracketright Control_bracketright Meta_five Meta_five Meta_five Meta_five
37keycode 7 = six asciicircum six asciicircum Control_asciicircum Control_asciicircum Meta_six Meta_six Meta_six Meta_six
38keycode 8 = seven ampersand seven ampersand Control_underscore Control_underscore Meta_seven Meta_seven Meta_seven Meta_seven
39keycode 9 = eight asterisk eight asterisk eight eight Meta_eight Meta_eight Meta_eight Meta_eight
40keycode 10 = nine parenleft nine parenleft nine nine Meta_nine Meta_nine Meta_nine Meta_nine
41keycode 11 = zero parenright zero parenright zero zero Meta_zero Meta_zero Meta_zero Meta_zero
42keycode 12 = minus underscore minus underscore Control_underscore Control_underscore Meta_minus Meta_minus Meta_minus Meta_minus
43keycode 13 = equal plus equal plus equal equal Meta_equal Meta_equal Meta_equal Meta_equal
44keycode 14 = Delete Delete Delete Delete BackSpace BackSpace Meta_Delete Meta_Delete Meta_Delete Meta_Delete
45keycode 15 = Tab Tab Tab Tab Tab Tab Meta_Tab Meta_Tab Meta_Tab Meta_Tab
46keycode 16 = +q +Q +U+0439 +U+0419 Control_q Control_q Meta_q Meta_q Meta_q Meta_q Meta_Control_q Meta_Control_q
47keycode 17 = +w +W +U+0446 +U+0426 Control_w Control_w Meta_w Meta_w Meta_w Meta_w Meta_Control_w Meta_Control_w
48keycode 18 = +e +E +U+0443 +U+0423 Control_e Control_e Meta_e Meta_e Meta_e Meta_e Meta_Control_e Meta_Control_e
49keycode 19 = +r +R +U+043a +U+041a Control_r Control_r Meta_r Meta_r Meta_r Meta_r Meta_Control_r Meta_Control_r
50keycode 20 = +t +T +U+0435 +U+0415 Control_t Control_t Meta_t Meta_t Meta_t Meta_t Meta_Control_t Meta_Control_t
51#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt =================== alt cyr =============== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
52keycode 21 = +y +Y +U+043d +U+041d Control_y Control_y Meta_y Meta_y Meta_y Meta_y Meta_Control_y Meta_Control_y
53keycode 22 = +u +U +U+0433 +U+0413 Control_u Control_u Meta_u Meta_u Meta_u Meta_u Meta_Control_u Meta_Control_u
54keycode 23 = +i +I +U+0448 +U+0428 Control_i Control_i Meta_i Meta_i Meta_i Meta_i Meta_Control_i Meta_Control_i
55keycode 24 = +o +O +U+0449 +U+0429 Control_o Control_o Meta_o Meta_o Meta_o Meta_o Meta_Control_o Meta_Control_o
56keycode 25 = +p +P +U+0437 +U+0417 Control_p Control_p Meta_p Meta_p Meta_p Meta_p Meta_Control_p Meta_Control_p
57keycode 26 = bracketleft braceleft +U+0445 +U+0425 Escape Escape Meta_bracketleft Meta_bracketleft Meta_bracketleft Meta_bracketleft
58keycode 27 = bracketright braceright +U+044a +U+042a Control_bracketright Control_bracketright
59keycode 28 = Return
60# LCtrl
61#keycode 29 =
62keycode 30 = +a +A +U+0444 +U+0424 Control_a Control_a Meta_a Meta_a Meta_a Meta_a Meta_Control_a Meta_Control_a
63keycode 31 = +s +S +U+044b +U+042b Control_s Control_s Meta_s Meta_s Meta_s Meta_s Meta_Control_s Meta_Control_s
64keycode 32 = +d +D +U+0432 +U+0412 Control_d Control_d Meta_d Meta_d Meta_d Meta_d Meta_Control_d Meta_Control_d
65keycode 33 = +f +F +U+0430 +U+0410 Control_f Control_f Meta_f Meta_f Meta_f Meta_f Meta_Control_f Meta_Control_f
66keycode 34 = +g +G +U+043f +U+041f Control_g Control_g Meta_g Meta_g Meta_g Meta_g Meta_Control_g Meta_Control_g
67keycode 35 = +h +H +U+0440 +U+0420 Control_h Control_h Meta_h Meta_h Meta_h Meta_h Meta_Control_h Meta_Control_h
68keycode 36 = +j +J +U+043e +U+041e Control_j Control_j Meta_j Meta_j Meta_j Meta_j Meta_Control_j Meta_Control_j
69keycode 37 = +k +K +U+043b +U+041b Control_k Control_k Meta_k Meta_k Meta_k Meta_k Meta_Control_k Meta_Control_k
70keycode 38 = +l +L +U+0434 +U+0414 Control_l Control_l Meta_l Meta_l Meta_l Meta_l Meta_Control_l Meta_Control_l
71keycode 39 = semicolon colon +U+0436 +U+0416 semicolon semicolon Meta_semicolon Meta_semicolon Meta_semicolon Meta_semicolon
72keycode 40 = apostrophe quotedbl +U+044d +U+042d Control_g Control_g Meta_apostrophe Meta_apostrophe Meta_apostrophe Meta_apostrophe
73#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt =================== alt cyr =============== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
74keycode 41 = grave asciitilde grave asciitilde nul nul Meta_grave Meta_grave Meta_grave Meta_grave
75# LShift
76#keycode 42 =
77keycode 43 = backslash bar backslash bar Control_backslash Control_backslash Meta_backslash Meta_backslash Meta_backslash Meta_backslash
78keycode 44 = +z +Z +U+044f +U+042f Control_z Control_z Meta_z Meta_z Meta_z Meta_z Meta_Control_z Meta_Control_z
79keycode 45 = +x +X +U+0447 +U+0427 Control_x Control_x Meta_x Meta_x Meta_x Meta_x Meta_Control_x Meta_Control_x
80keycode 46 = +c +C +U+0441 +U+0421 Control_c Control_c Meta_c Meta_c Meta_c Meta_c Meta_Control_c Meta_Control_c
81keycode 47 = +v +V +U+043c +U+041c Control_v Control_v Meta_v Meta_v Meta_v Meta_v Meta_Control_v Meta_Control_v
82keycode 48 = +b +B +U+0438 +U+0418 Control_b Control_b Meta_b Meta_b Meta_b Meta_b Meta_Control_b Meta_Control_b
83keycode 49 = +n +N +U+0442 +U+0422 Control_n Control_n Meta_n Meta_n Meta_n Meta_n Meta_Control_n Meta_Control_n
84keycode 50 = +m +M +U+044c +U+042c Control_m Control_m Meta_m Meta_m Meta_m Meta_m Meta_Control_m Meta_Control_m
85keycode 51 = comma less +U+0431 +U+0411 comma comma Meta_comma Meta_comma Meta_comma Meta_comma
86keycode 52 = period greater +U+044e +U+042e Compose Compose Meta_period Meta_period Meta_period Meta_period
87keycode 53 = slash question slash question Delete Delete Meta_slash Meta_question Meta_slash Meta_question Meta_question Meta_question
88# RShift
89#keycode 54 =
90keycode 55 = KP_Multiply
91keycode 56 = Alt
92keycode 57 = space space space space nul nul Meta_space Meta_space Meta_space Meta_space
93keycode 58 = Caps_Lock
94keycode 59 = F1 F11 F1 F11 F1 F1 Console_1 Console_1 Console_1 Console_1 Console_1 Console_1
95keycode 60 = F2 F12 F2 F12 F2 F2 Console_2 Console_2 Console_2 Console_2 Console_2 Console_2
96#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt =================== alt cyr =============== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
97keycode 61 = F3 F13 F3 F13 F3 F3 Console_3 Console_3 Console_3 Console_3 Console_3 Console_3
98keycode 62 = F4 F14 F4 F14 F4 F4 Console_4 Console_4 Console_4 Console_4 Console_4 Console_4
99keycode 63 = F5 F15 F5 F15 F5 F5 Console_5 Console_5 Console_5 Console_5 Console_5 Console_5
100keycode 64 = F6 F16 F6 F16 F6 F6 Console_6 Console_6 Console_6 Console_6 Console_6 Console_6
101keycode 65 = F7 F17 F7 F17 F7 F7 Console_7 Console_7 Console_7 Console_7 Console_7 Console_7
102keycode 66 = F8 F18 F8 F18 F8 F8 Console_8 Console_8 Console_8 Console_8 Console_8 Console_8
103keycode 67 = F9 F19 F9 F19 F9 F9 Console_9 Console_9 Console_9 Console_9 Console_9 Console_9
104keycode 68 = F10 F20 F10 F20 F10 F10 Console_10 Console_10 Console_10 Console_10 Console_10 Console_10
105keycode 69 = Num_Lock Bare_Num_Lock Num_Lock Bare_Num_Lock
106keycode 70 = Scroll_Lock Show_Memory Scroll_Lock Show_Memory Show_State Show_State
107keycode 71 = KP_7 KP_7 KP_7 KP_7 KP_7 KP_7 Ascii_7 Ascii_7 Ascii_7 Ascii_7
108keycode 72 = KP_8 KP_8 KP_8 KP_8 KP_8 KP_8 Ascii_8 Ascii_8 Ascii_8 Ascii_8
109keycode 73 = KP_9 KP_9 KP_9 KP_9 KP_9 KP_9 Ascii_9 Ascii_9 Ascii_9 Ascii_9
110keycode 74 = KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract
111keycode 75 = KP_4 KP_4 KP_4 KP_4 KP_4 KP_4 Ascii_4 Ascii_4 Ascii_4 Ascii_4
112keycode 76 = KP_5 KP_5 KP_5 KP_5 KP_5 KP_5 Ascii_5 Ascii_5 Ascii_5 Ascii_5
113keycode 77 = KP_6 KP_6 KP_6 KP_6 KP_6 KP_6 Ascii_6 Ascii_6 Ascii_6 Ascii_6
114keycode 78 = KP_Add KP_Add KP_Add KP_Add KP_Add KP_Add KP_Add KP_Add KP_Add KP_Add
115keycode 79 = KP_1 KP_1 KP_1 KP_1 KP_1 KP_1 Ascii_1 Ascii_1 Ascii_1 Ascii_1
116keycode 80 = KP_2 KP_2 KP_2 KP_2 KP_2 KP_2 Ascii_2 Ascii_2 Ascii_2 Ascii_2
117#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt =================== alt cyr =============== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
118keycode 81 = KP_3 KP_3 KP_3 KP_3 KP_3 KP_3 Ascii_3 Ascii_3 Ascii_3 Ascii_3
119keycode 82 = KP_0 KP_0 KP_0 KP_0 KP_0 KP_0 Ascii_0 Ascii_0 Ascii_0 Ascii_0
120keycode 83 = KP_Period KP_Period KP_Period KP_Period KP_Period KP_Period KP_Period KP_Period KP_Period KP_Period Boot Boot
121keycode 84 = Last_Console
122keycode 85 =
123keycode 86 = less greater less greater less less Meta_less Meta_less Meta_less Meta_less
124keycode 87 = F11 F11 F11 F11 F11 F11 Console_11 Console_11 Console_11 Console_11 Console_11 Console_11
125keycode 88 = F12 F12 F12 F12 F12 F12 Console_12 Console_12 Console_12 Console_12 Console_12 Console_12
126keycode 89 =
127keycode 90 =
128keycode 91 =
129keycode 92 =
130keycode 93 =
131keycode 94 =
132keycode 95 =
133keycode 96 = KP_Enter
134# RControl
135#keycode 97 =
136keycode 98 = KP_Divide
137keycode 99 = Control_backslash
138# RAlt
139#keycode 100 =
140#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt shift ============= alt cyr =============== alt shift cyr ========= ctrlalt =============== ctrlalt cyr ===========
141keycode 101 = Break
142keycode 102 = Find
143keycode 103 = Up
144keycode 104 = Prior Scroll_Backward Prior Scroll_Backward Prior Prior Prior Prior Prior Prior Prior Prior
145keycode 105 = Left Left Left Left Left Left Left Left Left Left Decr_Console Decr_Console
146keycode 106 = Right Right Right Right Right Right Right Right Right Right Incr_Console Incr_Console
147keycode 107 = Select
148keycode 108 = Down
149keycode 109 = Next Scroll_Forward Next Scroll_Forward Next Next Next Next Next Next Next Next
150keycode 110 = Insert
151keycode 111 = Remove Remove Remove Remove Remove Remove Remove Remove Remove Remove Boot Boot
152keycode 112 = Macro
153keycode 113 = F13
154keycode 114 = F14
155keycode 115 = Help
156keycode 116 = Do
157keycode 117 = F17
158keycode 118 = KP_MinPlus
159keycode 119 = Pause
160keycode 120 =
161#============== plain ========= shift========== plain cyr ===== shift cyr ===== ctrl ================== ctrl cyr ============== alt =================== alt =================== alt cyr =============== alt cyr =============== ctrlalt =============== ctrlalt cyr ===========
162keycode 121 =
163keycode 122 =
164keycode 123 =
165keycode 124 =
166# LWin
167#keycode 125 =
168# RWin
169#keycode 126 =
170# RMenu
171keycode 127 =
172
173string F1 = "\033[[A"
174string F2 = "\033[[B"
175string F3 = "\033[[C"
176string F4 = "\033[[D"
177string F5 = "\033[[E"
178string F6 = "\033[17~"
179string F7 = "\033[18~"
180string F8 = "\033[19~"
181string F9 = "\033[20~"
182string F10 = "\033[21~"
183string F11 = "\033[23~"
184string F12 = "\033[24~"
185string F13 = "\033[25~"
186string F14 = "\033[26~"
187string F15 = "\033[28~"
188string F16 = "\033[29~"
189string F17 = "\033[31~"
190string F18 = "\033[32~"
191string F19 = "\033[33~"
192string F20 = "\033[34~"
193string Find = "\033[1~"
194string Insert = "\033[2~"
195string Remove = "\033[3~"
196string Select = "\033[4~"
197string Prior = "\033[5~"
198string Next = "\033[6~"
199string Macro = "\033[M"
200string Pause = "\033[P"
diff --git a/examples/var_service/gpm/README b/examples/var_service/gpm/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/gpm/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/httpd/README b/examples/var_service/httpd/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/httpd/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/httpd/log/run b/examples/var_service/httpd/log/run
index 69d74b73f..756be4e7e 100755
--- a/examples/var_service/httpd/log/run
+++ b/examples/var_service/httpd/log/run
@@ -1,21 +1,2 @@
1#!/bin/sh 1#!/bin/sh
2 2exec std_service_logger
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/httpd/p_log b/examples/var_service/httpd/p_log
deleted file mode 100755
index a2521be05..000000000
--- a/examples/var_service/httpd/p_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/httpd/w_log b/examples/var_service/httpd/w_log
deleted file mode 100755
index aa36ef13b..000000000
--- a/examples/var_service/httpd/w_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4watch -n2 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b1-$((w-2))'
diff --git a/examples/var_service/ifplugd_if/README b/examples/var_service/ifplugd_if/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/ifplugd_if/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/ifplugd_if/ifplugd_handler b/examples/var_service/ifplugd_if/ifplugd_handler
index 4962fcf98..0749019f1 100755
--- a/examples/var_service/ifplugd_if/ifplugd_handler
+++ b/examples/var_service/ifplugd_if/ifplugd_handler
@@ -3,13 +3,18 @@
3# $1: interface 3# $1: interface
4# $2: state 4# $2: state
5 5
6if test -d "/var/service/dhcp_$1"; then 6if test x"$2" = x"down"; then
7 if test x"$2" = x"down"; then 7 echo "Downing dhcp_$1"
8 echo "Downing /var/service/dhcp_$1" 8 svc -d "dhcp_$1"
9 sv d "/var/service/dhcp_$1" 9 echo "Downing zcip_$1"
10 fi 10 svc -d "zcip_$1"
11 if test x"$2" = x"up"; then
12 echo "Upping /var/service/dhcp_$1"
13 sv u "/var/service/dhcp_$1"
14 fi
15fi 11fi
12if test x"$2" = x"up"; then
13 echo "Upping dhcp_$1"
14 svc -u "dhcp_$1"
15 echo "Upping zcip_$1"
16 svc -u "zcip_$1"
17fi
18# Parent ifplugd exits if we exit with nonzero.
19# Do not startle it:
20exit 0
diff --git a/examples/var_service/ifplugd_if/log/run b/examples/var_service/ifplugd_if/log/run
index 69d74b73f..756be4e7e 100755
--- a/examples/var_service/ifplugd_if/log/run
+++ b/examples/var_service/ifplugd_if/log/run
@@ -1,21 +1,2 @@
1#!/bin/sh 1#!/bin/sh
2 2exec std_service_logger
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/ifplugd_if/p_log b/examples/var_service/ifplugd_if/p_log
deleted file mode 100755
index a2521be05..000000000
--- a/examples/var_service/ifplugd_if/p_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/ifplugd_if/w_log b/examples/var_service/ifplugd_if/w_log
deleted file mode 100755
index aa36ef13b..000000000
--- a/examples/var_service/ifplugd_if/w_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4watch -n2 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b1-$((w-2))'
diff --git a/examples/var_service/inetd/README b/examples/var_service/inetd/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/inetd/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/inetd/log/run b/examples/var_service/inetd/log/run
index 69d74b73f..756be4e7e 100755
--- a/examples/var_service/inetd/log/run
+++ b/examples/var_service/inetd/log/run
@@ -1,21 +1,2 @@
1#!/bin/sh 1#!/bin/sh
2 2exec std_service_logger
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/inetd/p_log b/examples/var_service/inetd/p_log
deleted file mode 100755
index a2521be05..000000000
--- a/examples/var_service/inetd/p_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/inetd/w_log b/examples/var_service/inetd/w_log
deleted file mode 100755
index aa36ef13b..000000000
--- a/examples/var_service/inetd/w_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4watch -n2 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b1-$((w-2))'
diff --git a/examples/var_service/nmeter/README b/examples/var_service/nmeter/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/nmeter/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/ntpd/README b/examples/var_service/ntpd/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/ntpd/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/ntpd/log/run b/examples/var_service/ntpd/log/run
index 69d74b73f..756be4e7e 100755
--- a/examples/var_service/ntpd/log/run
+++ b/examples/var_service/ntpd/log/run
@@ -1,21 +1,2 @@
1#!/bin/sh 1#!/bin/sh
2 2exec std_service_logger
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/ntpd/p_log b/examples/var_service/ntpd/p_log
deleted file mode 100755
index a2521be05..000000000
--- a/examples/var_service/ntpd/p_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/ntpd/run b/examples/var_service/ntpd/run
index 6f2a68188..5c90aad41 100755
--- a/examples/var_service/ntpd/run
+++ b/examples/var_service/ntpd/run
@@ -6,12 +6,22 @@ exec 2>&1
6exec </dev/null 6exec </dev/null
7 7
8user=root 8user=root
9start_delay=15
10net_down_delay=5
9pool="us.pool.ntp.org" # replace "us" with your country code 11pool="us.pool.ntp.org" # replace "us" with your country code
10 12
11service="${PWD##*/}" 13service="${PWD##*/}"
12rundir="/var/run/service/$service" 14rundir="/var/run/service/$service"
13default_p_opt="-p 0.$pool -p 1.$pool -p 2.$pool -p 3.$pool" 15default_p_opt="-p 0.$pool -p 1.$pool -p 2.$pool -p 3.$pool"
14 16
17echo "* Checking network"
18test -f /var/run/service/fw/up || exec sleep $net_down_delay
19
20# With multiple interfaces (e.g. wired+wireless) going up,
21# networking scripts may restart ntpd service several times
22# in quick succession. Do not be too eager to start sending
23# NTP requests:
24sleep $start_delay
15 25
16# Make sure rundir/ exists 26# Make sure rundir/ exists
17mkdir -p "$rundir" 2>/dev/null 27mkdir -p "$rundir" 2>/dev/null
@@ -20,30 +30,25 @@ chmod -R a=rX "$rundir"
20rm -rf rundir 2>/dev/null 30rm -rf rundir 2>/dev/null
21ln -s "$rundir" rundir 31ln -s "$rundir" rundir
22 32
23
24echo "* Checking network"
25test -f /var/run/service/fw/up || exec sleep 7
26sleep 5 # to let it settle
27
28# Grab config from dhcp 33# Grab config from dhcp
29cfg=-1 34cfg=-1
30for f in rundir/*.ntpconf; do 35for f in rundir/*.ntpconf; do
31 test -f "$f" || continue 36 test -f "$f" || continue
32 . "$f" 37 . "$f"
33done 38done
34 39
35# Select peers 40# Select peers
36p_opt="" 41p_opt=""
37cfg=0 42cfg=0
38while test x"${ntpip[$cfg]}" != x""; do 43while test x"${ntpip[$cfg]}" != x""; do
39 p_opt="$p_opt -p ${ntpip[$cfg]}" 44 p_opt="$p_opt -p ${ntpip[$cfg]}"
40 let cfg=cfg+1 45 let cfg=cfg+1
41done 46done
42test x"$p_opt" == x"" && p_opt="$default_p_opt" 47test x"$p_opt" == x"" && p_opt="$default_p_opt"
43 48
44if test x"$p_opt" == x""; then 49if test x"$p_opt" == x""; then
45 echo "* No NTP peers configured, stopping" 50 echo "* No NTP peers configured, stopping"
46 sv o . 51 svc -o .
47 exec sleep 1 52 exec sleep 1
48fi 53fi
49 54
diff --git a/examples/var_service/ntpd/w_log b/examples/var_service/ntpd/w_log
deleted file mode 100755
index aa36ef13b..000000000
--- a/examples/var_service/ntpd/w_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4watch -n2 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b1-$((w-2))'
diff --git a/examples/var_service/std_service_logger b/examples/var_service/std_service_logger
new file mode 100755
index 000000000..ee68ad12b
--- /dev/null
+++ b/examples/var_service/std_service_logger
@@ -0,0 +1,32 @@
1#!/bin/sh
2
3user=logger
4
5exec >/dev/null 2>&1
6
7service="${PWD%/log}"
8service="${service##*/}"
9logdir="/var/log/service/$service"
10
11mkdir -p "$logdir"
12chown -R "$user": "$logdir"
13chmod -R go-rwxst,u+rwX "$logdir"
14# TODO: if "$logdir/config" does not exist,
15# based on service's preferences, write some setup in it:
16# e.g. smaller nNUM directive ("I'm not that important,
17# save 2 rather than default 10 one-megabyte log files")
18
19# Convenience symlink in this log/ directory:
20rm logdir
21ln -s "$logdir" logdir
22
23# Make current dir accessible to logger:
24chmod a+rX .
25
26args=""
27test "$LOG_NOTIMESTAMP" || args="-tt"
28
29exec \
30env - PATH="$PATH" \
31chpst -u "$user" -m $((20 * 1024*1024)) \
32svlogd $args "$logdir"
diff --git a/examples/var_service/supplicant_if/README b/examples/var_service/supplicant_if/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/supplicant_if/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/supplicant_if/log/run b/examples/var_service/supplicant_if/log/run
index 69d74b73f..756be4e7e 100755
--- a/examples/var_service/supplicant_if/log/run
+++ b/examples/var_service/supplicant_if/log/run
@@ -1,21 +1,2 @@
1#!/bin/sh 1#!/bin/sh
2 2exec std_service_logger
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/supplicant_if/p_log b/examples/var_service/supplicant_if/p_log
deleted file mode 100755
index a2521be05..000000000
--- a/examples/var_service/supplicant_if/p_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/supplicant_if/w_log b/examples/var_service/supplicant_if/w_log
deleted file mode 100755
index aa36ef13b..000000000
--- a/examples/var_service/supplicant_if/w_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4watch -n2 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b1-$((w-2))'
diff --git a/examples/var_service/sview b/examples/var_service/sview
new file mode 100755
index 000000000..716c1079c
--- /dev/null
+++ b/examples/var_service/sview
@@ -0,0 +1,19 @@
1#!/bin/sh
2
3test "$1" || {
4 echo "Syntax: ${0##*/} SERVICE"
5 exit 1
6}
7
8test x"$1" = x"${1#*/}" -a x"$1" != x"." && {
9 # has no slashes and is not a "."
10 cd "/var/service/$1" || exit $?
11 set -- "."
12}
13
14test -x "$1/view" && exec "$1/view"
15
16cd "log/logdir" || exit $?
17
18h=`ttysize h`
19exec tail -n $((h-1)) -F current 2>&1
diff --git a/examples/var_service/svpage b/examples/var_service/svpage
new file mode 100755
index 000000000..31c3d6dd7
--- /dev/null
+++ b/examples/var_service/svpage
@@ -0,0 +1,19 @@
1#!/bin/sh
2
3test "$1" || {
4 echo "Syntax: ${0##*/} SERVICE"
5 exit 1
6}
7
8test x"$1" = x"${1#*/}" -a x"$1" != x"." && {
9 # has no slashes and is not a "."
10 cd "/var/service/$1" || exit $?
11 set -- "."
12}
13
14test -x "$1/page" && exec "$1/page"
15
16cd "log/logdir" || exit $?
17
18test "$PAGER" || PAGER=less
19cat @* current | $PAGER
diff --git a/examples/var_service/tftpd/README b/examples/var_service/tftpd/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/tftpd/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/tftpd/log/run b/examples/var_service/tftpd/log/run
index 69d74b73f..756be4e7e 100755
--- a/examples/var_service/tftpd/log/run
+++ b/examples/var_service/tftpd/log/run
@@ -1,21 +1,2 @@
1#!/bin/sh 1#!/bin/sh
2 2exec std_service_logger
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/tftpd/p_log b/examples/var_service/tftpd/p_log
deleted file mode 100755
index a2521be05..000000000
--- a/examples/var_service/tftpd/p_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/tftpd/w_log b/examples/var_service/tftpd/w_log
deleted file mode 100755
index aa36ef13b..000000000
--- a/examples/var_service/tftpd/w_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4watch -n2 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b1-$((w-2))'
diff --git a/examples/var_service/zcip_if/README b/examples/var_service/zcip_if/README
deleted file mode 100644
index 4ddccb22d..000000000
--- a/examples/var_service/zcip_if/README
+++ /dev/null
@@ -1,5 +0,0 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/zcip_if/finish b/examples/var_service/zcip_if/finish
index 95995cf5f..7955cf3b8 100755
--- a/examples/var_service/zcip_if/finish
+++ b/examples/var_service/zcip_if/finish
@@ -1,5 +1,5 @@
1#!/bin/sh 1#!/bin/sh
2# executed when service is taken down ("sv d .") 2# executed when service is taken down
3 3
4service=${PWD##*/} 4service=${PWD##*/}
5file_ipconf="$service.ipconf" 5file_ipconf="$service.ipconf"
@@ -10,4 +10,4 @@ echo "Finish: deconfiguring"
10rm "env.out" 10rm "env.out"
11rm "$file_ipconf" 11rm "$file_ipconf"
12rm "$dir_ipconf/$file_ipconf" 12rm "$dir_ipconf/$file_ipconf"
13sv u /var/service/fw 13svc -u fw
diff --git a/examples/var_service/zcip_if/log/run b/examples/var_service/zcip_if/log/run
index 69d74b73f..756be4e7e 100755
--- a/examples/var_service/zcip_if/log/run
+++ b/examples/var_service/zcip_if/log/run
@@ -1,21 +1,2 @@
1#!/bin/sh 1#!/bin/sh
2 2exec std_service_logger
3user=logger
4
5logdir="/var/log/service/`(cd ..;basename $PWD)`"
6mkdir -p "$logdir" 2>/dev/null
7chown -R "$user": "$logdir"
8chmod -R go-rwxst,u+rwX "$logdir"
9rm -rf logdir
10ln -s "$logdir" logdir
11
12# make this dir accessible to logger
13chmod a+rX .
14
15exec >/dev/null
16exec 2>&1
17exec \
18env - PATH="$PATH" \
19softlimit \
20setuidgid "$user" \
21svlogd -tt "$logdir"
diff --git a/examples/var_service/zcip_if/p_log b/examples/var_service/zcip_if/p_log
deleted file mode 100755
index a2521be05..000000000
--- a/examples/var_service/zcip_if/p_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4cat @* current | $PAGER
diff --git a/examples/var_service/zcip_if/w_log b/examples/var_service/zcip_if/w_log
deleted file mode 100755
index aa36ef13b..000000000
--- a/examples/var_service/zcip_if/w_log
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/sh
2
3cd log/logdir || exit 1
4watch -n2 'w=`ttysize w`; h=`ttysize h`; tail -$((h-3)) current 2>&1 | cut -b1-$((w-2))'
diff --git a/examples/var_service/zcip_if/zcip_handler b/examples/var_service/zcip_if/zcip_handler
index 3c6ca788b..625450f7b 100755
--- a/examples/var_service/zcip_if/zcip_handler
+++ b/examples/var_service/zcip_if/zcip_handler
@@ -28,7 +28,7 @@ if test x"$1" != x"config"; then
28 echo "Deconfiguring" 28 echo "Deconfiguring"
29 rm "$file_ipconf" 29 rm "$file_ipconf"
30 rm "$dir_ipconf/$file_ipconf" 30 rm "$dir_ipconf/$file_ipconf"
31 sv u /var/service/fw 31 svc -u fw
32 exit 32 exit
33fi 33fi
34 34
@@ -43,5 +43,5 @@ if test $? != 0; then
43 echo "Reconfiguring fw" 43 echo "Reconfiguring fw"
44 mkdir -p "$dir_ipconf" 2>/dev/null 44 mkdir -p "$dir_ipconf" 2>/dev/null
45 cp "$file_ipconf" "$dir_ipconf/$file_ipconf" 45 cp "$file_ipconf" "$dir_ipconf/$file_ipconf"
46 sv u /var/service/fw 46 svc -u fw
47fi 47fi
diff --git a/findutils/Config.src b/findutils/Config.src
index 9ee71a845..c28c5844e 100644
--- a/findutils/Config.src
+++ b/findutils/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Finding Utilities" 6menu "Finding Utilities"
diff --git a/findutils/find.c b/findutils/find.c
index 07321c81a..6407c6c5a 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -95,6 +95,11 @@
95//config: Enable searching based on file type (file, 95//config: Enable searching based on file type (file,
96//config: directory, socket, device, etc.). 96//config: directory, socket, device, etc.).
97//config: 97//config:
98//config:config FEATURE_FIND_EXECUTABLE
99//config: bool "Enable -executable: file is executable"
100//config: default y
101//config: depends on FIND
102//config:
98//config:config FEATURE_FIND_XDEV 103//config:config FEATURE_FIND_XDEV
99//config: bool "Enable -xdev: 'stay in filesystem'" 104//config: bool "Enable -xdev: 'stay in filesystem'"
100//config: default y 105//config: default y
@@ -182,6 +187,13 @@
182//config: If the file is a directory, don't descend into it. Useful for 187//config: If the file is a directory, don't descend into it. Useful for
183//config: exclusion .svn and CVS directories. 188//config: exclusion .svn and CVS directories.
184//config: 189//config:
190//config:config FEATURE_FIND_QUIT
191//config: bool "Enable -quit: exit"
192//config: default y
193//config: depends on FIND
194//config: help
195//config: If this action is reached, 'find' exits.
196//config:
185//config:config FEATURE_FIND_DELETE 197//config:config FEATURE_FIND_DELETE
186//config: bool "Enable -delete: delete files/dirs" 198//config: bool "Enable -delete: delete files/dirs"
187//config: default y 199//config: default y
@@ -265,6 +277,9 @@
265//usage: IF_FEATURE_FIND_TYPE( 277//usage: IF_FEATURE_FIND_TYPE(
266//usage: "\n -type X File type is X (one of: f,d,l,b,c,s,p)" 278//usage: "\n -type X File type is X (one of: f,d,l,b,c,s,p)"
267//usage: ) 279//usage: )
280//usage: IF_FEATURE_FIND_EXECUTABLE(
281//usage: "\n -executable File is executable"
282//usage: )
268//usage: IF_FEATURE_FIND_PERM( 283//usage: IF_FEATURE_FIND_PERM(
269//usage: "\n -perm MASK At least one mask bit (+MASK), all bits (-MASK)," 284//usage: "\n -perm MASK At least one mask bit (+MASK), all bits (-MASK),"
270//usage: "\n or exactly MASK bits are set in file's mode" 285//usage: "\n or exactly MASK bits are set in file's mode"
@@ -318,6 +333,9 @@
318//usage: IF_FEATURE_FIND_DELETE( 333//usage: IF_FEATURE_FIND_DELETE(
319//usage: "\n -delete Delete current file/directory. Turns on -depth option" 334//usage: "\n -delete Delete current file/directory. Turns on -depth option"
320//usage: ) 335//usage: )
336//usage: IF_FEATURE_FIND_QUIT(
337//usage: "\n -quit Exit"
338//usage: )
321//usage: 339//usage:
322//usage:#define find_example_usage 340//usage:#define find_example_usage
323//usage: "$ find / -name passwd\n" 341//usage: "$ find / -name passwd\n"
@@ -365,6 +383,7 @@ IF_FEATURE_FIND_PATH( ACTS(path, const char *pattern; bool ipath;))
365IF_FEATURE_FIND_REGEX( ACTS(regex, regex_t compiled_pattern;)) 383IF_FEATURE_FIND_REGEX( ACTS(regex, regex_t compiled_pattern;))
366IF_FEATURE_FIND_PRINT0( ACTS(print0)) 384IF_FEATURE_FIND_PRINT0( ACTS(print0))
367IF_FEATURE_FIND_TYPE( ACTS(type, int type_mask;)) 385IF_FEATURE_FIND_TYPE( ACTS(type, int type_mask;))
386IF_FEATURE_FIND_EXECUTABLE(ACTS(executable))
368IF_FEATURE_FIND_PERM( ACTS(perm, char perm_char; mode_t perm_mask;)) 387IF_FEATURE_FIND_PERM( ACTS(perm, char perm_char; mode_t perm_mask;))
369IF_FEATURE_FIND_MTIME( ACTS(mtime, char mtime_char; unsigned mtime_days;)) 388IF_FEATURE_FIND_MTIME( ACTS(mtime, char mtime_char; unsigned mtime_days;))
370IF_FEATURE_FIND_MMIN( ACTS(mmin, char mmin_char; unsigned mmin_mins;)) 389IF_FEATURE_FIND_MMIN( ACTS(mmin, char mmin_char; unsigned mmin_mins;))
@@ -375,6 +394,7 @@ IF_FEATURE_FIND_SIZE( ACTS(size, char size_char; off_t size;))
375IF_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;)) 394IF_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;))
376IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;)) 395IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;))
377IF_FEATURE_FIND_PRUNE( ACTS(prune)) 396IF_FEATURE_FIND_PRUNE( ACTS(prune))
397IF_FEATURE_FIND_QUIT( ACTS(quit))
378IF_FEATURE_FIND_DELETE( ACTS(delete)) 398IF_FEATURE_FIND_DELETE( ACTS(delete))
379IF_FEATURE_FIND_EXEC( ACTS(exec, 399IF_FEATURE_FIND_EXEC( ACTS(exec,
380 char **exec_argv; /* -exec ARGS */ 400 char **exec_argv; /* -exec ARGS */
@@ -402,6 +422,7 @@ struct globals {
402 action ***actions; 422 action ***actions;
403 smallint need_print; 423 smallint need_print;
404 smallint xdev_on; 424 smallint xdev_on;
425 smalluint exitstatus;
405 recurse_flags_t recurse_flags; 426 recurse_flags_t recurse_flags;
406 IF_FEATURE_FIND_EXEC_PLUS(unsigned max_argv_len;) 427 IF_FEATURE_FIND_EXEC_PLUS(unsigned max_argv_len;)
407} FIX_ALIASING; 428} FIX_ALIASING;
@@ -566,6 +587,12 @@ ACTF(type)
566 return ((statbuf->st_mode & S_IFMT) == ap->type_mask); 587 return ((statbuf->st_mode & S_IFMT) == ap->type_mask);
567} 588}
568#endif 589#endif
590#if ENABLE_FEATURE_FIND_EXECUTABLE
591ACTF(executable)
592{
593 return access(fileName, X_OK) == 0;
594}
595#endif
569#if ENABLE_FEATURE_FIND_PERM 596#if ENABLE_FEATURE_FIND_PERM
570ACTF(perm) 597ACTF(perm)
571{ 598{
@@ -774,6 +801,12 @@ ACTF(prune)
774 return SKIP + TRUE; 801 return SKIP + TRUE;
775} 802}
776#endif 803#endif
804#if ENABLE_FEATURE_FIND_QUIT
805ACTF(quit)
806{
807 exit(G.exitstatus);
808}
809#endif
777#if ENABLE_FEATURE_FIND_DELETE 810#if ENABLE_FEATURE_FIND_DELETE
778ACTF(delete) 811ACTF(delete)
779{ 812{
@@ -954,8 +987,10 @@ static action*** parse_params(char **argv)
954 PARM_print , 987 PARM_print ,
955 IF_FEATURE_FIND_PRINT0( PARM_print0 ,) 988 IF_FEATURE_FIND_PRINT0( PARM_print0 ,)
956 IF_FEATURE_FIND_PRUNE( PARM_prune ,) 989 IF_FEATURE_FIND_PRUNE( PARM_prune ,)
990 IF_FEATURE_FIND_QUIT( PARM_quit ,)
957 IF_FEATURE_FIND_DELETE( PARM_delete ,) 991 IF_FEATURE_FIND_DELETE( PARM_delete ,)
958 IF_FEATURE_FIND_EXEC( PARM_exec ,) 992 IF_FEATURE_FIND_EXEC( PARM_exec ,)
993 IF_FEATURE_FIND_EXECUTABLE(PARM_executable,)
959 IF_FEATURE_FIND_PAREN( PARM_char_brace,) 994 IF_FEATURE_FIND_PAREN( PARM_char_brace,)
960 /* All options/actions starting from here require argument */ 995 /* All options/actions starting from here require argument */
961 PARM_name , 996 PARM_name ,
@@ -997,8 +1032,10 @@ static action*** parse_params(char **argv)
997 "-print\0" 1032 "-print\0"
998 IF_FEATURE_FIND_PRINT0( "-print0\0" ) 1033 IF_FEATURE_FIND_PRINT0( "-print0\0" )
999 IF_FEATURE_FIND_PRUNE( "-prune\0" ) 1034 IF_FEATURE_FIND_PRUNE( "-prune\0" )
1035 IF_FEATURE_FIND_QUIT( "-quit\0" )
1000 IF_FEATURE_FIND_DELETE( "-delete\0" ) 1036 IF_FEATURE_FIND_DELETE( "-delete\0" )
1001 IF_FEATURE_FIND_EXEC( "-exec\0" ) 1037 IF_FEATURE_FIND_EXEC( "-exec\0" )
1038 IF_FEATURE_FIND_EXECUTABLE("-executable\0")
1002 IF_FEATURE_FIND_PAREN( "(\0" ) 1039 IF_FEATURE_FIND_PAREN( "(\0" )
1003 /* All options/actions starting from here require argument */ 1040 /* All options/actions starting from here require argument */
1004 "-name\0" 1041 "-name\0"
@@ -1152,6 +1189,12 @@ static action*** parse_params(char **argv)
1152 (void) ALLOC_ACTION(prune); 1189 (void) ALLOC_ACTION(prune);
1153 } 1190 }
1154#endif 1191#endif
1192#if ENABLE_FEATURE_FIND_QUIT
1193 else if (parm == PARM_quit) {
1194 dbg("%d", __LINE__);
1195 (void) ALLOC_ACTION(quit);
1196 }
1197#endif
1155#if ENABLE_FEATURE_FIND_DELETE 1198#if ENABLE_FEATURE_FIND_DELETE
1156 else if (parm == PARM_delete) { 1199 else if (parm == PARM_delete) {
1157 dbg("%d", __LINE__); 1200 dbg("%d", __LINE__);
@@ -1262,6 +1305,11 @@ static action*** parse_params(char **argv)
1262 dbg("created:type mask:%x", ap->type_mask); 1305 dbg("created:type mask:%x", ap->type_mask);
1263 } 1306 }
1264#endif 1307#endif
1308#if ENABLE_FEATURE_FIND_EXECUTABLE
1309 else if (parm == PARM_executable) {
1310 (void) ALLOC_ACTION(executable);
1311 }
1312#endif
1265#if ENABLE_FEATURE_FIND_PERM 1313#if ENABLE_FEATURE_FIND_PERM
1266/* -perm BITS File's mode bits are exactly BITS (octal or symbolic). 1314/* -perm BITS File's mode bits are exactly BITS (octal or symbolic).
1267 * Symbolic modes use mode 0 as a point of departure. 1315 * Symbolic modes use mode 0 as a point of departure.
@@ -1401,7 +1449,7 @@ static action*** parse_params(char **argv)
1401int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1449int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1402int find_main(int argc UNUSED_PARAM, char **argv) 1450int find_main(int argc UNUSED_PARAM, char **argv)
1403{ 1451{
1404 int i, firstopt, status = EXIT_SUCCESS; 1452 int i, firstopt;
1405 char **past_HLP, *saved; 1453 char **past_HLP, *saved;
1406 1454
1407 INIT_G(); 1455 INIT_G();
@@ -1475,10 +1523,10 @@ int find_main(int argc UNUSED_PARAM, char **argv)
1475 NULL, /* user data */ 1523 NULL, /* user data */
1476 0) /* depth */ 1524 0) /* depth */
1477 ) { 1525 ) {
1478 status |= EXIT_FAILURE; 1526 G.exitstatus |= EXIT_FAILURE;
1479 } 1527 }
1480 } 1528 }
1481 1529
1482 IF_FEATURE_FIND_EXEC_PLUS(status |= flush_exec_plus();) 1530 IF_FEATURE_FIND_EXEC_PLUS(G.exitstatus |= flush_exec_plus();)
1483 return status; 1531 return G.exitstatus;
1484} 1532}
diff --git a/findutils/grep.c b/findutils/grep.c
index 88de0d4ef..3e8ea9239 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -704,10 +704,15 @@ int grep_main(int argc UNUSED_PARAM, char **argv)
704 /* do normal option parsing */ 704 /* do normal option parsing */
705#if ENABLE_FEATURE_GREP_CONTEXT 705#if ENABLE_FEATURE_GREP_CONTEXT
706 /* -H unsets -h; -C unsets -A,-B */ 706 /* -H unsets -h; -C unsets -A,-B */
707 opts = getopt32(argv, 707 opts = getopt32long(argv, "^"
708 "^" OPTSTR_GREP "\0" "H-h:C-AB", 708 OPTSTR_GREP
709 "\0"
710 "H-h:C-AB",
711 "color\0" Optional_argument "\xff",
709 &pattern_head, &fopt, &max_matches, 712 &pattern_head, &fopt, &max_matches,
710 &lines_after, &lines_before, &Copt); 713 &lines_after, &lines_before, &Copt
714 , NULL
715 );
711 716
712 if (opts & OPT_C) { 717 if (opts & OPT_C) {
713 /* -C unsets prev -A and -B, but following -A or -B 718 /* -C unsets prev -A and -B, but following -A or -B
diff --git a/findutils/xargs.c b/findutils/xargs.c
index df2300207..4399783ea 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -606,7 +606,7 @@ static int xargs_ask_confirmation(void)
606//usage: ) 606//usage: )
607//usage: "\n -r Don't run command if input is empty" 607//usage: "\n -r Don't run command if input is empty"
608//usage: IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( 608//usage: IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(
609//usage: "\n -0 Input is separated by NUL characters" 609//usage: "\n -0 Input is separated by NULs"
610//usage: ) 610//usage: )
611//usage: IF_FEATURE_XARGS_SUPPORT_ARGS_FILE( 611//usage: IF_FEATURE_XARGS_SUPPORT_ARGS_FILE(
612//usage: "\n -a FILE Read from FILE instead of stdin" 612//usage: "\n -a FILE Read from FILE instead of stdin"
diff --git a/include/bb_archive.h b/include/bb_archive.h
index 2182fcc3c..ace9c8e23 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -74,8 +74,8 @@ typedef struct archive_handle_t {
74 /* Currently processed file's header */ 74 /* Currently processed file's header */
75 file_header_t *file_header; 75 file_header_t *file_header;
76 76
77 /* List of symlink placeholders */ 77 /* List of link placeholders */
78 llist_t *symlink_placeholders; 78 llist_t *link_placeholders;
79 79
80 /* Process the header component, e.g. tar -t */ 80 /* Process the header component, e.g. tar -t */
81 void FAST_FUNC (*action_header)(const file_header_t *); 81 void FAST_FUNC (*action_header)(const file_header_t *);
@@ -126,10 +126,10 @@ typedef struct archive_handle_t {
126#if ENABLE_FEATURE_AR_CREATE 126#if ENABLE_FEATURE_AR_CREATE
127 const char *ar__name; 127 const char *ar__name;
128 struct archive_handle_t *ar__out; 128 struct archive_handle_t *ar__out;
129# if ENABLE_FEATURE_AR_LONG_FILENAMES 129#endif
130#if ENABLE_FEATURE_AR_LONG_FILENAMES
130 char *ar__long_names; 131 char *ar__long_names;
131 unsigned ar__long_name_size; 132 unsigned ar__long_name_size;
132# endif
133#endif 133#endif
134} archive_handle_t; 134} archive_handle_t;
135/* bits in ah_flags */ 135/* bits in ah_flags */
@@ -213,13 +213,14 @@ void seek_by_jump(int fd, off_t amount) FAST_FUNC;
213void seek_by_read(int fd, off_t amount) FAST_FUNC; 213void seek_by_read(int fd, off_t amount) FAST_FUNC;
214 214
215const char *strip_unsafe_prefix(const char *str) FAST_FUNC; 215const char *strip_unsafe_prefix(const char *str) FAST_FUNC;
216void create_or_remember_symlink(llist_t **symlink_placeholders, 216void create_or_remember_link(llist_t **link_placeholders,
217 const char *target, 217 const char *target,
218 const char *linkname) FAST_FUNC; 218 const char *linkname,
219 int hard_link) FAST_FUNC;
219#if !ENABLE_PLATFORM_MINGW32 220#if !ENABLE_PLATFORM_MINGW32
220void create_symlinks_from_list(llist_t *list) FAST_FUNC; 221void create_links_from_list(llist_t *list) FAST_FUNC;
221#else 222#else
222#define create_symlinks_from_list(l) (void)0 223#define create_links_from_list(l) (void)0
223#endif 224#endif
224 225
225void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC; 226void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC;
diff --git a/include/libbb.h b/include/libbb.h
index fb9167ce3..0264282dd 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -428,6 +428,9 @@ enum { /* cp.c, mv.c, install.c depend on these values. CAREFUL when changing th
428 FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 15, /* -c */ 428 FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 15, /* -c */
429#endif 429#endif
430 FILEUTILS_RMDEST = 1 << (16 - !ENABLE_SELINUX), /* --remove-destination */ 430 FILEUTILS_RMDEST = 1 << (16 - !ENABLE_SELINUX), /* --remove-destination */
431 /* bit 17 skipped for "cp --parents" */
432 FILEUTILS_REFLINK = 1 << (18 - !ENABLE_SELINUX), /* cp --reflink=auto */
433 FILEUTILS_REFLINK_ALWAYS = 1 << (19 - !ENABLE_SELINUX), /* cp --reflink[=always] */
431 /* 434 /*
432 * Hole. cp may have some bits set here, 435 * Hole. cp may have some bits set here,
433 * they should not affect remove_file()/copy_file() 436 * they should not affect remove_file()/copy_file()
@@ -503,6 +506,7 @@ DIR *xopendir(const char *path) FAST_FUNC;
503DIR *warn_opendir(const char *path) FAST_FUNC; 506DIR *warn_opendir(const char *path) FAST_FUNC;
504 507
505char *xmalloc_realpath(const char *path) FAST_FUNC RETURNS_MALLOC; 508char *xmalloc_realpath(const char *path) FAST_FUNC RETURNS_MALLOC;
509char *xmalloc_realpath_coreutils(const char *path) FAST_FUNC RETURNS_MALLOC;
506char *xmalloc_readlink(const char *path) FAST_FUNC RETURNS_MALLOC; 510char *xmalloc_readlink(const char *path) FAST_FUNC RETURNS_MALLOC;
507char *xmalloc_readlink_or_warn(const char *path) FAST_FUNC RETURNS_MALLOC; 511char *xmalloc_readlink_or_warn(const char *path) FAST_FUNC RETURNS_MALLOC;
508/* !RETURNS_MALLOC: it's a realloc-like function */ 512/* !RETURNS_MALLOC: it's a realloc-like function */
diff --git a/init/Config.src b/init/Config.src
index 5767c93f0..b19b0bea1 100644
--- a/init/Config.src
+++ b/init/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Init Utilities" 6menu "Init Utilities"
diff --git a/klibc-utils/Config.src b/klibc-utils/Config.src
index fe7cb1315..cf4552e51 100644
--- a/klibc-utils/Config.src
+++ b/klibc-utils/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "klibc-utils" 6menu "klibc-utils"
diff --git a/libbb/Config.src b/libbb/Config.src
index 16e16480b..312aa1831 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6comment "Library Tuning" 6comment "Library Tuning"
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index f250264d9..7df75c665 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -177,8 +177,11 @@ void FAST_FUNC bb_show_usage(void)
177 else { 177 else {
178 full_write2_str("\nUsage: "); 178 full_write2_str("\nUsage: ");
179 full_write2_str(applet_name); 179 full_write2_str(applet_name);
180 full_write2_str(" "); 180 if (p[0]) {
181 full_write2_str(p); 181 if (p[0] != '\n')
182 full_write2_str(" ");
183 full_write2_str(p);
184 }
182 full_write2_str("\n"); 185 full_write2_str("\n");
183 } 186 }
184 if (ENABLE_FEATURE_CLEAN_UP) 187 if (ENABLE_FEATURE_CLEAN_UP)
@@ -747,7 +750,7 @@ static void install_links(const char *busybox, int use_symbolic_links,
747 * busybox.h::bb_install_loc_t, or else... */ 750 * busybox.h::bb_install_loc_t, or else... */
748 int (*lf)(const char *, const char *); 751 int (*lf)(const char *, const char *);
749 char *fpc; 752 char *fpc;
750 const char *appname = applet_names; 753 const char *appname = applet_names;
751 unsigned i; 754 unsigned i;
752 int rc; 755 int rc;
753 756
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index c60765d95..7cd9cd978 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -343,8 +343,27 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
343 } 343 }
344 } 344 }
345#endif 345#endif
346#if ENABLE_FEATURE_CP_REFLINK
347# undef BTRFS_IOCTL_MAGIC
348# define BTRFS_IOCTL_MAGIC 0x94
349# undef BTRFS_IOC_CLONE
350# define BTRFS_IOC_CLONE _IOW (BTRFS_IOCTL_MAGIC, 9, int)
351 if (flags & FILEUTILS_REFLINK) {
352 retval = ioctl(dst_fd, BTRFS_IOC_CLONE, src_fd);
353 if (retval == 0)
354 goto do_close;
355 /* reflink did not work */
356 if (flags & FILEUTILS_REFLINK_ALWAYS) {
357 bb_perror_msg("failed to clone '%s' from '%s'", dest, source);
358 goto do_close;
359 }
360 /* fall through to standard copy */
361 retval = 0;
362 }
363#endif
346 if (bb_copyfd_eof(src_fd, dst_fd) == -1) 364 if (bb_copyfd_eof(src_fd, dst_fd) == -1)
347 retval = -1; 365 retval = -1;
366 IF_FEATURE_CP_REFLINK(do_close:)
348 /* Careful with writing... */ 367 /* Careful with writing... */
349 if (close(dst_fd) < 0) { 368 if (close(dst_fd) < 0) {
350 bb_perror_msg("error writing to '%s'", dest); 369 bb_perror_msg("error writing to '%s'", dest);
diff --git a/libbb/dump.c b/libbb/dump.c
index 5941ef902..b4b49d709 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -387,7 +387,10 @@ static unsigned char *get(priv_dumper_t *dumper)
387 if (need == blocksize) { 387 if (need == blocksize) {
388 return NULL; 388 return NULL;
389 } 389 }
390 if (dumper->pub.dump_vflag != ALL && !memcmp(dumper->get__curp, dumper->get__savp, nread)) { 390 if (dumper->pub.dump_vflag != ALL /* not "show all"? */
391 && dumper->pub.dump_vflag != FIRST /* not first line? */
392 && memcmp(dumper->get__curp, dumper->get__savp, nread) == 0 /* same data? */
393 ) {
391 if (dumper->pub.dump_vflag != DUP) { 394 if (dumper->pub.dump_vflag != DUP) {
392 puts("*"); 395 puts("*");
393 } 396 }
@@ -399,7 +402,7 @@ static unsigned char *get(priv_dumper_t *dumper)
399 } 402 }
400 n = fread(dumper->get__curp + nread, sizeof(unsigned char), 403 n = fread(dumper->get__curp + nread, sizeof(unsigned char),
401 dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), stdin); 404 dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), stdin);
402 if (!n) { 405 if (n == 0) {
403 if (ferror(stdin)) { 406 if (ferror(stdin)) {
404 bb_simple_perror_msg(dumper->argv[-1]); 407 bb_simple_perror_msg(dumper->argv[-1]);
405 } 408 }
@@ -411,9 +414,10 @@ static unsigned char *get(priv_dumper_t *dumper)
411 dumper->pub.dump_length -= n; 414 dumper->pub.dump_length -= n;
412 } 415 }
413 need -= n; 416 need -= n;
414 if (!need) { 417 if (need == 0) {
415 if (dumper->pub.dump_vflag == ALL || dumper->pub.dump_vflag == FIRST 418 if (dumper->pub.dump_vflag == ALL /* "show all"? */
416 || memcmp(dumper->get__curp, dumper->get__savp, blocksize) 419 || dumper->pub.dump_vflag == FIRST /* first line? */
420 || memcmp(dumper->get__curp, dumper->get__savp, blocksize) != 0 /* not same data? */
417 ) { 421 ) {
418 if (dumper->pub.dump_vflag == DUP || dumper->pub.dump_vflag == FIRST) { 422 if (dumper->pub.dump_vflag == DUP || dumper->pub.dump_vflag == FIRST) {
419 dumper->pub.dump_vflag = WAIT; 423 dumper->pub.dump_vflag = WAIT;
diff --git a/libbb/loop.c b/libbb/loop.c
index f0d4296ae..c78535a20 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -106,6 +106,10 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
106 return -errno; 106 return -errno;
107 } 107 }
108 108
109//TODO: use LOOP_CTL_GET_FREE instead of trying every loopN in sequence? a-la:
110// fd = open("/dev/loop-control", O_RDWR);
111// loopN = ioctl(fd, LOOP_CTL_GET_FREE);
112//
109 /* Find a loop device. */ 113 /* Find a loop device. */
110 try = *device ? *device : dev; 114 try = *device ? *device : dev;
111 /* 1048575 (0xfffff) is a max possible minor number in Linux circa 2010 */ 115 /* 1048575 (0xfffff) is a max possible minor number in Linux circa 2010 */
diff --git a/libbb/nuke_str.c b/libbb/nuke_str.c
index 240e68004..b5385e956 100644
--- a/libbb/nuke_str.c
+++ b/libbb/nuke_str.c
@@ -12,7 +12,7 @@
12 12
13void FAST_FUNC nuke_str(char *str) 13void FAST_FUNC nuke_str(char *str)
14{ 14{
15 if (str) { 15 if (str) {
16 while (*str) 16 while (*str)
17 *str++ = 0; 17 *str++ = 0;
18 /* or: memset(str, 0, strlen(str)); - not as small as above */ 18 /* or: memset(str, 0, strlen(str)); - not as small as above */
diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c
index 1edf4b6f0..86455cd0d 100644
--- a/libbb/pw_encrypt.c
+++ b/libbb/pw_encrypt.c
@@ -6,6 +6,7 @@
6 * 6 *
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#include <crypt.h>
9#include "libbb.h" 10#include "libbb.h"
10 11
11/* static const uint8_t ascii64[] ALIGN1 = 12/* static const uint8_t ascii64[] ALIGN1 =
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 21263ccfe..a0db2b86e 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -222,6 +222,7 @@ void FAST_FUNC xdup2(int from, int to)
222{ 222{
223 if (dup2(from, to) != to) 223 if (dup2(from, to) != to)
224 bb_perror_msg_and_die("can't duplicate file descriptor"); 224 bb_perror_msg_and_die("can't duplicate file descriptor");
225 // " %d to %d", from, to);
225} 226}
226 227
227// "Renumber" opened fd 228// "Renumber" opened fd
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c
index b3118b433..9ae70de99 100644
--- a/libbb/xreadlink.c
+++ b/libbb/xreadlink.c
@@ -122,3 +122,33 @@ char* FAST_FUNC xmalloc_realpath(const char *path)
122 return xstrdup(realpath(path, buf)); 122 return xstrdup(realpath(path, buf));
123#endif 123#endif
124} 124}
125
126char* FAST_FUNC xmalloc_realpath_coreutils(const char *path)
127{
128 char *buf;
129
130 errno = 0;
131 buf = xmalloc_realpath(path);
132 /*
133 * There is one case when "readlink -f" and
134 * "realpath" from coreutils succeed,
135 * even though file does not exist, such as:
136 * /tmp/file_does_not_exist
137 * (the directory must exist).
138 */
139 if (!buf && errno == ENOENT) {
140 char *last_slash = strrchr(path, '/');
141 if (last_slash) {
142 *last_slash++ = '\0';
143 buf = xmalloc_realpath(path);
144 if (buf) {
145 unsigned len = strlen(buf);
146 buf = xrealloc(buf, len + strlen(last_slash) + 2);
147 buf[len++] = '/';
148 strcpy(buf + len, last_slash);
149 }
150 }
151 }
152
153 return buf;
154}
diff --git a/loginutils/Config.src b/loginutils/Config.src
index 680f42118..cbb09646b 100644
--- a/loginutils/Config.src
+++ b/loginutils/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Login/Password Management Utilities" 6menu "Login/Password Management Utilities"
diff --git a/mailutils/popmaildir.c b/mailutils/popmaildir.c
index a4aad3662..589456715 100644
--- a/mailutils/popmaildir.c
+++ b/mailutils/popmaildir.c
@@ -265,7 +265,7 @@ int popmaildir_main(int argc UNUSED_PARAM, char **argv)
265 265
266 // atomically move message to ./new/ 266 // atomically move message to ./new/
267 target = xstrdup(filename); 267 target = xstrdup(filename);
268 strncpy(target, "new", 3); 268 memcpy(target, "new", 3);
269 // ... or just stop receiving on failure 269 // ... or just stop receiving on failure
270 if (rename_or_warn(filename, target)) 270 if (rename_or_warn(filename, target))
271 break; 271 break;
diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c
index 4ca91fad8..0170f2870 100644
--- a/mailutils/sendmail.c
+++ b/mailutils/sendmail.c
@@ -173,7 +173,7 @@ static char *angle_address(char *str)
173 char *s, *e; 173 char *s, *e;
174 174
175 e = trim(str); 175 e = trim(str);
176 if (e != str && e[-1] == '>') { 176 if (e != str && *--e == '>') {
177 s = strrchr(str, '<'); 177 s = strrchr(str, '<');
178 if (s) { 178 if (s) {
179 *e = '\0'; 179 *e = '\0';
diff --git a/miscutils/Config.src b/miscutils/Config.src
index 7325fb8fa..d10b00b28 100644
--- a/miscutils/Config.src
+++ b/miscutils/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Miscellaneous Utilities" 6menu "Miscellaneous Utilities"
diff --git a/miscutils/hexedit.c b/miscutils/hexedit.c
index 95c930d12..298eb8149 100644
--- a/miscutils/hexedit.c
+++ b/miscutils/hexedit.c
@@ -153,7 +153,8 @@ static void redraw(unsigned cursor)
153 i++; 153 i++;
154 } 154 }
155 155
156 printf(ESC"[%u;%uH", 1 + cursor / 16, 1 + pos + (cursor & 0xf) * 3); 156 G.row = cursor / 16;
157 printf(ESC"[%u;%uH", 1 + G.row, 1 + pos + (cursor & 0xf) * 3);
157} 158}
158 159
159static void redraw_cur_line(void) 160static void redraw_cur_line(void)
@@ -367,6 +368,8 @@ int hexedit_main(int argc UNUSED_PARAM, char **argv)
367 if (G.current_byte > G.eof_byte) { 368 if (G.current_byte > G.eof_byte) {
368 /* _after_ eof - don't allow this */ 369 /* _after_ eof - don't allow this */
369 G.current_byte -= 16; 370 G.current_byte -= 16;
371 if (G.current_byte < G.baseaddr)
372 move_mapping_lower();
370 break; 373 break;
371 } 374 }
372 } 375 }
diff --git a/modutils/Config.src b/modutils/Config.src
index e413702bb..188296814 100644
--- a/modutils/Config.src
+++ b/modutils/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Linux Module Utilities" 6menu "Linux Module Utilities"
diff --git a/networking/Config.src b/networking/Config.src
index 492c60da4..2ce5287de 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Networking Utilities" 6menu "Networking Utilities"
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 64098648a..42c84de45 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -791,7 +791,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv)
791 "np:s:uvw:+"/* -w N */ IF_NC_SERVER("lk") 791 "np:s:uvw:+"/* -w N */ IF_NC_SERVER("lk")
792 IF_NC_EXTRA("i:o:z") 792 IF_NC_EXTRA("i:o:z")
793 "\0" 793 "\0"
794 "?2:vv:ll", /* max 2 params; -v and -l are counters */ 794 "?2:vv"IF_NC_SERVER(":ll"), /* max 2 params; -v and -l are counters */
795 &str_p, &str_s, &o_wait 795 &str_p, &str_s, &o_wait
796 IF_NC_EXTRA(, &str_i, &str_o) 796 IF_NC_EXTRA(, &str_i, &str_o)
797 , &o_verbose IF_NC_SERVER(, &cnt_l) 797 , &o_verbose IF_NC_SERVER(, &cnt_l)
diff --git a/networking/nslookup.c b/networking/nslookup.c
index fd241a5ca..3a614b0c6 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -712,11 +712,11 @@ static void add_query(int type, const char *dname)
712static char *make_ptr(const char *addrstr) 712static char *make_ptr(const char *addrstr)
713{ 713{
714 unsigned char addr[16]; 714 unsigned char addr[16];
715 int i;
716 715
717#if ENABLE_FEATURE_IPV6 716#if ENABLE_FEATURE_IPV6
718 if (inet_pton(AF_INET6, addrstr, addr)) { 717 if (inet_pton(AF_INET6, addrstr, addr)) {
719 if (memcmp(addr, v4_mapped, 12) != 0) { 718 if (memcmp(addr, v4_mapped, 12) != 0) {
719 int i;
720 char resbuf[80]; 720 char resbuf[80];
721 char *ptr = resbuf; 721 char *ptr = resbuf;
722 for (i = 0; i < 16; i++) { 722 for (i = 0; i < 16; i++) {
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 6cd497090..7b800369e 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -93,10 +93,10 @@
93 93
94#include "libbb.h" 94#include "libbb.h"
95#include <math.h> 95#include <math.h>
96#include <netinet/ip.h> /* For IPTOS_LOWDELAY definition */ 96#include <netinet/ip.h> /* For IPTOS_DSCP_AF21 definition */
97#include <sys/timex.h> 97#include <sys/timex.h>
98#ifndef IPTOS_LOWDELAY 98#ifndef IPTOS_DSCP_AF21
99# define IPTOS_LOWDELAY 0x10 99# define IPTOS_DSCP_AF21 0x48
100#endif 100#endif
101 101
102 102
@@ -149,6 +149,7 @@
149 */ 149 */
150 150
151#define INITIAL_SAMPLES 4 /* how many samples do we want for init */ 151#define INITIAL_SAMPLES 4 /* how many samples do we want for init */
152#define MIN_FREQHOLD 10 /* adjust offset, but not freq in this many first adjustments */
152#define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this */ 153#define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this */
153 154
154#define RETRY_INTERVAL 32 /* on send/recv error, retry in N secs (need to be power of 2) */ 155#define RETRY_INTERVAL 32 /* on send/recv error, retry in N secs (need to be power of 2) */
@@ -910,7 +911,7 @@ send_query_to_peer(peer_t *p)
910#if ENABLE_FEATURE_IPV6 911#if ENABLE_FEATURE_IPV6
911 if (family == AF_INET) 912 if (family == AF_INET)
912#endif 913#endif
913 setsockopt_int(fd, IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY); 914 setsockopt_int(fd, IPPROTO_IP, IP_TOS, IPTOS_DSCP_AF21);
914 free(local_lsa); 915 free(local_lsa);
915 } 916 }
916 917
@@ -1753,7 +1754,7 @@ update_local_clock(peer_t *p)
1753//15:19:39.114 update from:<IP> offset:+0.327022 delay:0.158384 jitter:0.108538 clock drift:-1.393ppm tc:4 1754//15:19:39.114 update from:<IP> offset:+0.327022 delay:0.158384 jitter:0.108538 clock drift:-1.393ppm tc:4
1754//15:20:12.715 update from:<IP> offset:+0.275596 delay:0.158297 jitter:0.097292 clock drift:-1.393ppm tc:4 1755//15:20:12.715 update from:<IP> offset:+0.275596 delay:0.158297 jitter:0.097292 clock drift:-1.393ppm tc:4
1755//15:20:45.111 update from:<IP> offset:+0.225715 delay:0.158271 jitter:0.087841 clock drift:-1.393ppm tc:4 1756//15:20:45.111 update from:<IP> offset:+0.225715 delay:0.158271 jitter:0.087841 clock drift:-1.393ppm tc:4
1756// If allwed to continue, it would start increasing tmx.freq now. 1757// If allowed to continue, it would start increasing tmx.freq now.
1757// Instead, it was ^Ced, and started anew: 1758// Instead, it was ^Ced, and started anew:
1758//15:21:15.043 no valid datapoints, no peer selected 1759//15:21:15.043 no valid datapoints, no peer selected
1759//15:21:17.408 update from:<IP> offset:+0.175910 delay:0.158314 jitter:0.076683 clock drift:-1.393ppm tc:4 1760//15:21:17.408 update from:<IP> offset:+0.175910 delay:0.158314 jitter:0.076683 clock drift:-1.393ppm tc:4
@@ -1776,9 +1777,9 @@ update_local_clock(peer_t *p)
1776//15:31:53.473 update from:<IP> offset:+0.000007 delay:0.158142 jitter:0.010922 clock drift:+9.343ppm tc:6 1777//15:31:53.473 update from:<IP> offset:+0.000007 delay:0.158142 jitter:0.010922 clock drift:+9.343ppm tc:6
1777//15:32:58.902 update from:<IP> offset:-0.000728 delay:0.158222 jitter:0.009454 clock drift:+9.298ppm tc:6 1778//15:32:58.902 update from:<IP> offset:-0.000728 delay:0.158222 jitter:0.009454 clock drift:+9.298ppm tc:6
1778 /* 1779 /*
1779 * This expression would choose 15 in the above example. 1780 * This expression would choose MIN_FREQHOLD + 7 in the above example.
1780 */ 1781 */
1781 G.FREQHOLD_cnt = 8 + ((unsigned)(abs(tmx.offset)) >> 16); 1782 G.FREQHOLD_cnt = MIN_FREQHOLD + ((unsigned)(abs(tmx.offset)) >> 16);
1782 } 1783 }
1783 G.FREQHOLD_cnt--; 1784 G.FREQHOLD_cnt--;
1784 tmx.status |= STA_FREQHOLD; 1785 tmx.status |= STA_FREQHOLD;
@@ -2320,7 +2321,7 @@ static NOINLINE void ntp_init(char **argv)
2320 xfunc_die(); 2321 xfunc_die();
2321 } 2322 }
2322 socket_want_pktinfo(G_listen_fd); 2323 socket_want_pktinfo(G_listen_fd);
2323 setsockopt_int(G_listen_fd, IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY); 2324 setsockopt_int(G_listen_fd, IPPROTO_IP, IP_TOS, IPTOS_DSCP_AF21);
2324 } 2325 }
2325#endif 2326#endif
2326 /* I hesitate to set -20 prio. -15 should be high enough for timekeeping */ 2327 /* I hesitate to set -20 prio. -15 should be high enough for timekeeping */
diff --git a/networking/tls.c b/networking/tls.c
index ec5a56d57..fce1d0ea6 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -1088,6 +1088,8 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len)
1088 * We need Certificate.tbsCertificate.subjectPublicKeyInfo.publicKey 1088 * We need Certificate.tbsCertificate.subjectPublicKeyInfo.publicKey
1089 */ 1089 */
1090 uint8_t *end = der + len; 1090 uint8_t *end = der + len;
1091 uint8_t tag_class, pc, tag_number;
1092 int version_present;
1091 1093
1092 /* enter "Certificate" item: [der, end) will be only Cert */ 1094 /* enter "Certificate" item: [der, end) will be only Cert */
1093 der = enter_der_item(der, &end); 1095 der = enter_der_item(der, &end);
@@ -1095,8 +1097,24 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len)
1095 /* enter "tbsCertificate" item: [der, end) will be only tbsCert */ 1097 /* enter "tbsCertificate" item: [der, end) will be only tbsCert */
1096 der = enter_der_item(der, &end); 1098 der = enter_der_item(der, &end);
1097 1099
1100 /*
1101 * Skip version field only if it is present. For a v1 certificate, the
1102 * version field won't be present since v1 is the default value for the
1103 * version field and fields with default values should be omitted (see
1104 * RFC 5280 sections 4.1 and 4.1.2.1). If the version field is present
1105 * it will have a tag class of 2 (context-specific), bit 6 as 1
1106 * (constructed), and a tag number of 0 (see ITU-T X.690 sections 8.1.2
1107 * and 8.14).
1108 */
1109 tag_class = der[0] >> 6; /* bits 8-7 */
1110 pc = (der[0] & 32) >> 5; /* bit 6 */
1111 tag_number = der[0] & 31; /* bits 5-1 */
1112 version_present = tag_class == 2 && pc == 1 && tag_number == 0;
1113 if (version_present) {
1114 der = skip_der_item(der, end); /* version */
1115 }
1116
1098 /* skip up to subjectPublicKeyInfo */ 1117 /* skip up to subjectPublicKeyInfo */
1099 der = skip_der_item(der, end); /* version */
1100 der = skip_der_item(der, end); /* serialNumber */ 1118 der = skip_der_item(der, end); /* serialNumber */
1101 der = skip_der_item(der, end); /* signatureAlgo */ 1119 der = skip_der_item(der, end); /* signatureAlgo */
1102 der = skip_der_item(der, end); /* issuer */ 1120 der = skip_der_item(der, end); /* issuer */
diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src
index 50bff2e8c..e5958804b 100644
--- a/networking/udhcp/Config.src
+++ b/networking/udhcp/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6config UDHCPD 6config UDHCPD
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index fbf9c6878..e5fd74f91 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -65,6 +65,7 @@ const struct dhcp_optflag dhcp_optflags[] = {
65#endif 65#endif
66 { OPTION_STRING , 0xd1 }, /* DHCP_PXE_CONF_FILE */ 66 { OPTION_STRING , 0xd1 }, /* DHCP_PXE_CONF_FILE */
67 { OPTION_STRING , 0xd2 }, /* DHCP_PXE_PATH_PREFIX */ 67 { OPTION_STRING , 0xd2 }, /* DHCP_PXE_PATH_PREFIX */
68 { OPTION_U32 , 0xd3 }, /* DHCP_REBOOT_TIME */
68 { OPTION_6RD , 0xd4 }, /* DHCP_6RD */ 69 { OPTION_6RD , 0xd4 }, /* DHCP_6RD */
69 { OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ 70 { OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
70 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ 71 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */
@@ -92,50 +93,51 @@ const struct dhcp_optflag dhcp_optflags[] = {
92 */ 93 */
93/* Must match dhcp_optflags[] order */ 94/* Must match dhcp_optflags[] order */
94const char dhcp_option_strings[] ALIGN1 = 95const char dhcp_option_strings[] ALIGN1 =
95 "subnet" "\0" /* DHCP_SUBNET */ 96 "subnet" "\0" /* DHCP_SUBNET */
96 "timezone" "\0" /* DHCP_TIME_OFFSET */ 97 "timezone" "\0" /* DHCP_TIME_OFFSET */
97 "router" "\0" /* DHCP_ROUTER */ 98 "router" "\0" /* DHCP_ROUTER */
98// "timesrv" "\0" /* DHCP_TIME_SERVER */ 99// "timesrv" "\0" /* DHCP_TIME_SERVER */
99// "namesrv" "\0" /* DHCP_NAME_SERVER */ 100// "namesrv" "\0" /* DHCP_NAME_SERVER */
100 "dns" "\0" /* DHCP_DNS_SERVER */ 101 "dns" "\0" /* DHCP_DNS_SERVER */
101// "logsrv" "\0" /* DHCP_LOG_SERVER */ 102// "logsrv" "\0" /* DHCP_LOG_SERVER */
102// "cookiesrv" "\0" /* DHCP_COOKIE_SERVER */ 103// "cookiesrv" "\0" /* DHCP_COOKIE_SERVER */
103 "lprsrv" "\0" /* DHCP_LPR_SERVER */ 104 "lprsrv" "\0" /* DHCP_LPR_SERVER */
104 "hostname" "\0" /* DHCP_HOST_NAME */ 105 "hostname" "\0" /* DHCP_HOST_NAME */
105 "bootsize" "\0" /* DHCP_BOOT_SIZE */ 106 "bootsize" "\0" /* DHCP_BOOT_SIZE */
106 "domain" "\0" /* DHCP_DOMAIN_NAME */ 107 "domain" "\0" /* DHCP_DOMAIN_NAME */
107 "swapsrv" "\0" /* DHCP_SWAP_SERVER */ 108 "swapsrv" "\0" /* DHCP_SWAP_SERVER */
108 "rootpath" "\0" /* DHCP_ROOT_PATH */ 109 "rootpath" "\0" /* DHCP_ROOT_PATH */
109 "ipttl" "\0" /* DHCP_IP_TTL */ 110 "ipttl" "\0" /* DHCP_IP_TTL */
110 "mtu" "\0" /* DHCP_MTU */ 111 "mtu" "\0" /* DHCP_MTU */
111 "broadcast" "\0" /* DHCP_BROADCAST */ 112 "broadcast" "\0" /* DHCP_BROADCAST */
112 "routes" "\0" /* DHCP_ROUTES */ 113 "routes" "\0" /* DHCP_ROUTES */
113 "nisdomain" "\0" /* DHCP_NIS_DOMAIN */ 114 "nisdomain" "\0" /* DHCP_NIS_DOMAIN */
114 "nissrv" "\0" /* DHCP_NIS_SERVER */ 115 "nissrv" "\0" /* DHCP_NIS_SERVER */
115 "ntpsrv" "\0" /* DHCP_NTP_SERVER */ 116 "ntpsrv" "\0" /* DHCP_NTP_SERVER */
116 "wins" "\0" /* DHCP_WINS_SERVER */ 117 "wins" "\0" /* DHCP_WINS_SERVER */
117 "lease" "\0" /* DHCP_LEASE_TIME */ 118 "lease" "\0" /* DHCP_LEASE_TIME */
118 "serverid" "\0" /* DHCP_SERVER_ID */ 119 "serverid" "\0" /* DHCP_SERVER_ID */
119 "message" "\0" /* DHCP_ERR_MESSAGE */ 120 "message" "\0" /* DHCP_ERR_MESSAGE */
120 "tftp" "\0" /* DHCP_TFTP_SERVER_NAME */ 121 "tftp" "\0" /* DHCP_TFTP_SERVER_NAME*/
121 "bootfile" "\0" /* DHCP_BOOT_FILE */ 122 "bootfile" "\0" /* DHCP_BOOT_FILE */
122// "userclass" "\0" /* DHCP_USER_CLASS */ 123// "userclass" "\0" /* DHCP_USER_CLASS */
123#if ENABLE_FEATURE_UDHCP_RFC3397 124#if ENABLE_FEATURE_UDHCP_RFC3397
124 "search" "\0" /* DHCP_DOMAIN_SEARCH */ 125 "search" "\0" /* DHCP_DOMAIN_SEARCH */
125// doesn't work in udhcpd.conf since OPTION_SIP_SERVERS 126// doesn't work in udhcpd.conf since OPTION_SIP_SERVERS
126// is not handled yet by "string->option" conversion code: 127// is not handled yet by "string->option" conversion code:
127 "sipsrv" "\0" /* DHCP_SIP_SERVERS */ 128 "sipsrv" "\0" /* DHCP_SIP_SERVERS */
128#endif 129#endif
129 "staticroutes" "\0"/* DHCP_STATIC_ROUTES */ 130 "staticroutes" "\0" /* DHCP_STATIC_ROUTES */
130#if ENABLE_FEATURE_UDHCP_8021Q 131#if ENABLE_FEATURE_UDHCP_8021Q
131 "vlanid" "\0" /* DHCP_VLAN_ID */ 132 "vlanid" "\0" /* DHCP_VLAN_ID */
132 "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */ 133 "vlanpriority" "\0" /* DHCP_VLAN_PRIORITY */
133#endif 134#endif
134 "pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */ 135 "pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */
135 "pxepathprefix" "\0" /* DHCP_PXE_PATH_PREFIX */ 136 "pxepathprefix" "\0" /* DHCP_PXE_PATH_PREFIX */
136 "ip6rd" "\0" /* DHCP_6RD */ 137 "reboottime" "\0" /* DHCP_REBOOT_TIME */
137 "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ 138 "ip6rd" "\0" /* DHCP_6RD */
138 "wpad" "\0" /* DHCP_WPAD */ 139 "msstaticroutes" "\0" /* DHCP_MS_STATIC_ROUTES*/
140 "wpad" "\0" /* DHCP_WPAD */
139 ; 141 ;
140#endif 142#endif
141 143
@@ -379,12 +381,18 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg)
379 * and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives. 381 * and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives.
380 */ 382 */
381/* helper: add an option to the opt_list */ 383/* helper: add an option to the opt_list */
384#if !ENABLE_UDHCPC6
385#define attach_option(opt_list, optflag, buffer, length, dhcpv6) \
386 attach_option(opt_list, optflag, buffer, length)
387#endif
382static NOINLINE void attach_option( 388static NOINLINE void attach_option(
383 struct option_set **opt_list, 389 struct option_set **opt_list,
384 const struct dhcp_optflag *optflag, 390 const struct dhcp_optflag *optflag,
385 char *buffer, 391 char *buffer,
386 int length) 392 int length,
393 bool dhcpv6)
387{ 394{
395 IF_NOT_UDHCPC6(bool dhcpv6 = 0;)
388 struct option_set *existing; 396 struct option_set *existing;
389 char *allocated = NULL; 397 char *allocated = NULL;
390 398
@@ -410,10 +418,21 @@ static NOINLINE void attach_option(
410 /* make a new option */ 418 /* make a new option */
411 log2("attaching option %02x to list", optflag->code); 419 log2("attaching option %02x to list", optflag->code);
412 new = xmalloc(sizeof(*new)); 420 new = xmalloc(sizeof(*new));
413 new->data = xmalloc(length + OPT_DATA); 421 if (!dhcpv6) {
414 new->data[OPT_CODE] = optflag->code; 422 new->data = xmalloc(length + OPT_DATA);
415 new->data[OPT_LEN] = length; 423 new->data[OPT_CODE] = optflag->code;
416 memcpy(new->data + OPT_DATA, (allocated ? allocated : buffer), length); 424 new->data[OPT_LEN] = length;
425 memcpy(new->data + OPT_DATA, (allocated ? allocated : buffer),
426 length);
427 } else {
428 new->data = xmalloc(length + D6_OPT_DATA);
429 new->data[D6_OPT_CODE] = optflag->code >> 8;
430 new->data[D6_OPT_CODE + 1] = optflag->code & 0xff;
431 new->data[D6_OPT_LEN] = length >> 8;
432 new->data[D6_OPT_LEN + 1] = length & 0xff;
433 memcpy(new->data + D6_OPT_DATA, (allocated ? allocated : buffer),
434 length);
435 }
417 436
418 curr = opt_list; 437 curr = opt_list;
419 while (*curr && (*curr)->data[OPT_CODE] < optflag->code) 438 while (*curr && (*curr)->data[OPT_CODE] < optflag->code)
@@ -450,7 +469,9 @@ static NOINLINE void attach_option(
450 free(allocated); 469 free(allocated);
451} 470}
452 471
453int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dhcp_optflag *optflags, const char *option_strings) 472int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg,
473 const struct dhcp_optflag *optflags, const char *option_strings,
474 bool dhcpv6)
454{ 475{
455 struct option_set **opt_list = arg; 476 struct option_set **opt_list = arg;
456 char *opt; 477 char *opt;
@@ -489,9 +510,10 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dh
489 int length; 510 int length;
490 char *val; 511 char *val;
491 512
492 if (optflag->flags == OPTION_BIN) 513 if (optflag->flags == OPTION_BIN) {
493 val = trim(strtok(NULL, "")); /* do not split "'q w e'" */ 514 val = strtok(NULL, ""); /* do not split "'q w e'" */
494 else 515 trim(val);
516 } else
495 val = strtok(NULL, ", \t"); 517 val = strtok(NULL, ", \t");
496 if (!val) 518 if (!val)
497 break; 519 break;
@@ -601,7 +623,7 @@ case_OPTION_STRING:
601 } 623 }
602 624
603 if (retval) 625 if (retval)
604 attach_option(opt_list, optflag, opt, length); 626 attach_option(opt_list, optflag, opt, length, dhcpv6);
605 } while (retval && (optflag->flags & OPTION_LIST)); 627 } while (retval && (optflag->flags & OPTION_LIST));
606 628
607 return retval; 629 return retval;
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 13059f106..7ad603d33 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -122,9 +122,9 @@ enum {
122//#define DHCP_LOG_SERVER 0x07 /* port 704 UDP log (not syslog) 122//#define DHCP_LOG_SERVER 0x07 /* port 704 UDP log (not syslog)
123//#define DHCP_COOKIE_SERVER 0x08 /* "quote of the day" server */ 123//#define DHCP_COOKIE_SERVER 0x08 /* "quote of the day" server */
124//#define DHCP_LPR_SERVER 0x09 124//#define DHCP_LPR_SERVER 0x09
125#define DHCP_HOST_NAME 0x0c /* either client informs server or server gives name to client */ 125#define DHCP_HOST_NAME 0x0c /* 12: either client informs server or server gives name to client */
126//#define DHCP_BOOT_SIZE 0x0d 126//#define DHCP_BOOT_SIZE 0x0d
127//#define DHCP_DOMAIN_NAME 0x0f /* server gives domain suffix */ 127//#define DHCP_DOMAIN_NAME 0x0f /* 15: server gives domain suffix */
128//#define DHCP_SWAP_SERVER 0x10 128//#define DHCP_SWAP_SERVER 0x10
129//#define DHCP_ROOT_PATH 0x11 129//#define DHCP_ROOT_PATH 0x11
130//#define DHCP_IP_TTL 0x17 130//#define DHCP_IP_TTL 0x17
@@ -135,35 +135,40 @@ enum {
135//#define DHCP_NIS_SERVER 0x29 135//#define DHCP_NIS_SERVER 0x29
136//#define DHCP_NTP_SERVER 0x2a 136//#define DHCP_NTP_SERVER 0x2a
137//#define DHCP_WINS_SERVER 0x2c 137//#define DHCP_WINS_SERVER 0x2c
138#define DHCP_REQUESTED_IP 0x32 /* sent by client if specific IP is wanted */ 138#define DHCP_REQUESTED_IP 0x32 /* 50: sent by client if specific IP is wanted */
139#define DHCP_LEASE_TIME 0x33 139#define DHCP_LEASE_TIME 0x33 /* 51: */
140#define DHCP_OPTION_OVERLOAD 0x34 140#define DHCP_OPTION_OVERLOAD 0x34 /* 52: */
141#define DHCP_MESSAGE_TYPE 0x35 141#define DHCP_MESSAGE_TYPE 0x35 /* 53: */
142#define DHCP_SERVER_ID 0x36 /* by default server's IP */ 142#define DHCP_SERVER_ID 0x36 /* 54: server's IP */
143#define DHCP_PARAM_REQ 0x37 /* list of options client wants */ 143#define DHCP_PARAM_REQ 0x37 /* 55: list of options client wants */
144//#define DHCP_ERR_MESSAGE 0x38 /* error message when sending NAK etc */ 144//#define DHCP_ERR_MESSAGE 0x38 /* 56: error message when sending NAK etc */
145#define DHCP_MAX_SIZE 0x39 145#define DHCP_MAX_SIZE 0x39 /* 57: */
146#define DHCP_VENDOR 0x3c /* client's vendor (a string) */ 146#define DHCP_VENDOR 0x3c /* 60: client's vendor (a string) */
147#define DHCP_CLIENT_ID 0x3d /* by default client's MAC addr, but may be arbitrarily long */ 147#define DHCP_CLIENT_ID 0x3d /* 61: by default client's MAC addr, but may be arbitrarily long */
148//#define DHCP_TFTP_SERVER_NAME 0x42 /* same as 'sname' field */ 148//#define DHCP_TFTP_SERVER_NAME 0x42 /* 66: same as 'sname' field */
149//#define DHCP_BOOT_FILE 0x43 /* same as 'file' field */ 149//#define DHCP_BOOT_FILE 0x43 /* 67: same as 'file' field */
150//#define DHCP_USER_CLASS 0x4d /* RFC 3004. set of LASCII strings. "I am a printer" etc */ 150//#define DHCP_USER_CLASS 0x4d /* 77: RFC 3004. set of LASCII strings. "I am a printer" etc */
151#define DHCP_FQDN 0x51 /* client asks to update DNS to map its FQDN to its new IP */ 151#define DHCP_FQDN 0x51 /* 81: client asks to update DNS to map its FQDN to its new IP */
152//#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */ 152//#define DHCP_DOMAIN_SEARCH 0x77 /* 119: RFC 3397. set of ASCIZ string, DNS-style compressed */
153//#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */ 153//#define DHCP_SIP_SERVERS 0x78 /* 120: RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */
154//#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */ 154//#define DHCP_STATIC_ROUTES 0x79 /* 121: RFC 3442. (mask,ip,router) tuples */
155//#define DHCP_VLAN_ID 0x84 /* 802.1P VLAN ID */ 155//#define DHCP_VLAN_ID 0x84 /* 132: 802.1P VLAN ID */
156//#define DHCP_VLAN_PRIORITY 0x85 /* 802.1Q VLAN priority */ 156//#define DHCP_VLAN_PRIORITY 0x85 /* 133: 802.1Q VLAN priority */
157//#define DHCP_PXE_CONF_FILE 0xd1 /* RFC 5071 Configuration File */ 157//#define DHCP_PXE_CONF_FILE 0xd1 /* 209: RFC 5071 Configuration File */
158//#define DHCP_PXE_PATH_PREFIX 0xd2 /* RFC 5071 Configuration File */ 158//#define DHCP_PXE_PATH_PREFIX 0xd2 /* 210: RFC 5071 Configuration File */
159//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */ 159//#define DHCP_REBOOT_TIME 0xd3 /* 211: RFC 5071 Reboot time */
160//#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */ 160//#define DHCP_MS_STATIC_ROUTES 0xf9 /* 249: Microsoft's pre-RFC 3442 code for 0x79? */
161#define DHCP_END 0xff 161//#define DHCP_WPAD 0xfc /* 252: MSIE's Web Proxy Autodiscovery Protocol */
162#define DHCP_END 0xff /* 255: */
162 163
163/* Offsets in option byte sequence */ 164/* Offsets in option byte sequence */
164#define OPT_CODE 0 165#define OPT_CODE 0
165#define OPT_LEN 1 166#define OPT_LEN 1
166#define OPT_DATA 2 167#define OPT_DATA 2
168/* Offsets in option byte sequence for DHCPv6 */
169#define D6_OPT_CODE 0
170#define D6_OPT_LEN 2
171#define D6_OPT_DATA 4
167/* Bits in "overload" option */ 172/* Bits in "overload" option */
168#define OPTION_FIELD 0 173#define OPTION_FIELD 0
169#define FILE_FIELD 1 174#define FILE_FIELD 1
@@ -290,10 +295,15 @@ void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC;
290/* 2nd param is "uint32_t*" */ 295/* 2nd param is "uint32_t*" */
291int FAST_FUNC udhcp_str2nip(const char *str, void *arg); 296int FAST_FUNC udhcp_str2nip(const char *str, void *arg);
292/* 2nd param is "struct option_set**" */ 297/* 2nd param is "struct option_set**" */
298#if !ENABLE_UDHCPC6
299#define udhcp_str2optset(str, arg, optflags, option_strings, dhcpv6) \
300 udhcp_str2optset(str, arg, optflags, option_strings)
301#endif
293int FAST_FUNC udhcp_str2optset(const char *str, 302int FAST_FUNC udhcp_str2optset(const char *str,
294 void *arg, 303 void *arg,
295 const struct dhcp_optflag *optflags, 304 const struct dhcp_optflag *optflags,
296 const char *option_strings); 305 const char *option_strings,
306 bool dhcpv6);
297 307
298#if ENABLE_UDHCPC || ENABLE_UDHCPD 308#if ENABLE_UDHCPC || ENABLE_UDHCPD
299void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; 309void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC;
@@ -308,9 +318,7 @@ int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
308 318
309int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 319int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
310 uint32_t source_nip, int source_port, 320 uint32_t source_nip, int source_port,
311 uint32_t dest_nip, int dest_port, 321 uint32_t dest_nip, int dest_port) FAST_FUNC;
312 int send_flags
313) FAST_FUNC;
314 322
315void udhcp_sp_setup(void) FAST_FUNC; 323void udhcp_sp_setup(void) FAST_FUNC;
316void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC; 324void udhcp_sp_fd_set(struct pollfd *pfds, int extra_fd) FAST_FUNC;
diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h
index e9c0397ae..d0506e2bb 100644
--- a/networking/udhcp/d6_common.h
+++ b/networking/udhcp/d6_common.h
@@ -128,6 +128,9 @@ struct d6_option {
128#define D6_OPT_TZ_POSIX 41 128#define D6_OPT_TZ_POSIX 41
129#define D6_OPT_TZ_NAME 42 129#define D6_OPT_TZ_NAME 42
130 130
131#define D6_OPT_BOOT_URL 59
132#define D6_OPT_BOOT_PARAM 60
133
131/*** Other shared functions ***/ 134/*** Other shared functions ***/
132 135
133struct client6_data_t { 136struct client6_data_t {
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 85d9da724..ed2255ef3 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -38,6 +38,14 @@
38//config: help 38//config: help
39//config: You can request POSIX timezone with "-O tz" and timezone name 39//config: You can request POSIX timezone with "-O tz" and timezone name
40//config: with "-O timezone". 40//config: with "-O timezone".
41//config:
42//config:config FEATURE_UDHCPC6_RFC5970
43//config: bool "Support RFC 5970 (Network Boot)"
44//config: default y
45//config: depends on UDHCPC6
46//config: help
47//config: You can request bootfile-url with "-O bootfile_url" and
48//config: bootfile-params with "-O bootfile_params".
41 49
42//applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP)) 50//applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP))
43 51
@@ -71,6 +79,12 @@ static const struct dhcp_optflag d6_optflags[] = {
71 { OPTION_STRING, D6_OPT_TZ_POSIX }, 79 { OPTION_STRING, D6_OPT_TZ_POSIX },
72 { OPTION_STRING, D6_OPT_TZ_NAME }, 80 { OPTION_STRING, D6_OPT_TZ_NAME },
73#endif 81#endif
82#if ENABLE_FEATURE_UDHCPC6_RFC5970
83 { OPTION_STRING, D6_OPT_BOOT_URL },
84 { OPTION_STRING, D6_OPT_BOOT_PARAM },
85#endif
86 { OPTION_STRING, 0xd1 }, /* DHCP_PXE_CONF_FILE */
87 { OPTION_STRING, 0xd2 }, /* DHCP_PXE_PATH_PREFIX */
74 { 0, 0 } 88 { 0, 0 }
75}; 89};
76/* Must match d6_optflags[] order */ 90/* Must match d6_optflags[] order */
@@ -86,6 +100,12 @@ static const char d6_option_strings[] ALIGN1 =
86 "tz" "\0" /* D6_OPT_TZ_POSIX */ 100 "tz" "\0" /* D6_OPT_TZ_POSIX */
87 "timezone" "\0" /* D6_OPT_TZ_NAME */ 101 "timezone" "\0" /* D6_OPT_TZ_NAME */
88#endif 102#endif
103#if ENABLE_FEATURE_UDHCPC6_RFC5970
104 "bootfile_url" "\0" /* D6_OPT_BOOT_URL */
105 "bootfile_param" "\0" /* D6_OPT_BOOT_PARAM */
106#endif
107 "pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */
108 "pxepathprefix" "\0" /* DHCP_PXE_PATH_PREFIX */
89 "\0"; 109 "\0";
90 110
91#if ENABLE_LONG_OPTS 111#if ENABLE_LONG_OPTS
@@ -195,8 +215,37 @@ static char** new_env(void)
195 return &client6_data.env_ptr[client6_data.env_idx++]; 215 return &client6_data.env_ptr[client6_data.env_idx++];
196} 216}
197 217
218static char *string_option_to_env(const uint8_t *option,
219 const uint8_t *option_end)
220{
221 const char *ptr, *name = NULL;
222 unsigned val_len;
223 int i;
224
225 ptr = d6_option_strings;
226 i = 0;
227 while (*ptr) {
228 if (d6_optflags[i].code == option[1]) {
229 name = ptr;
230 goto found;
231 }
232 ptr += strlen(ptr) + 1;
233 i++;
234 }
235 bb_error_msg("can't find option name for 0x%x, skipping", option[1]);
236 return NULL;
237
238 found:
239 val_len = (option[2] << 8) | option[3];
240 if (val_len + &option[D6_OPT_DATA] > option_end) {
241 bb_error_msg("option data exceeds option length");
242 return NULL;
243 }
244 return xasprintf("%s=%.*s", name, val_len, (char*)option + 4);
245}
246
198/* put all the parameters into the environment */ 247/* put all the parameters into the environment */
199static void option_to_env(uint8_t *option, uint8_t *option_end) 248static void option_to_env(const uint8_t *option, const uint8_t *option_end)
200{ 249{
201#if ENABLE_FEATURE_UDHCPC6_RFC3646 250#if ENABLE_FEATURE_UDHCPC6_RFC3646
202 int addrs, option_offset; 251 int addrs, option_offset;
@@ -239,6 +288,10 @@ static void option_to_env(uint8_t *option, uint8_t *option_end)
239 * | valid-lifetime | 288 * | valid-lifetime |
240 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 289 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
241 */ 290 */
291 /* Make sure payload contains an address */
292 if (option[3] < 24)
293 break;
294
242 sprint_nip6(ipv6str, option + 4); 295 sprint_nip6(ipv6str, option + 4);
243 *new_env() = xasprintf("ipv6=%s", ipv6str); 296 *new_env() = xasprintf("ipv6=%s", ipv6str);
244 297
@@ -354,13 +407,23 @@ static void option_to_env(uint8_t *option, uint8_t *option_end)
354 *new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4); 407 *new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4);
355 break; 408 break;
356#endif 409#endif
410 case D6_OPT_BOOT_URL:
411 case D6_OPT_BOOT_PARAM:
412 case 0xd1: /* DHCP_PXE_CONF_FILE */
413 case 0xd2: /* DHCP_PXE_PATH_PREFIX */
414 {
415 char *tmp = string_option_to_env(option, option_end);
416 if (tmp)
417 *new_env() = tmp;
418 break;
419 }
357 } 420 }
358 len_m4 -= 4 + option[3]; 421 len_m4 -= 4 + option[3];
359 option += 4 + option[3]; 422 option += 4 + option[3];
360 } 423 }
361} 424}
362 425
363static char **fill_envp(struct d6_packet *packet) 426static char **fill_envp(const uint8_t *option, const uint8_t *option_end)
364{ 427{
365 char **envp, **curr; 428 char **envp, **curr;
366 429
@@ -369,8 +432,8 @@ static char **fill_envp(struct d6_packet *packet)
369 432
370 *new_env() = xasprintf("interface=%s", client_config.interface); 433 *new_env() = xasprintf("interface=%s", client_config.interface);
371 434
372 if (packet) 435 if (option)
373 option_to_env(packet->d6_options, packet->d6_options + sizeof(packet->d6_options)); 436 option_to_env(option, option_end);
374 437
375 envp = curr = client6_data.env_ptr; 438 envp = curr = client6_data.env_ptr;
376 while (*curr) 439 while (*curr)
@@ -380,12 +443,13 @@ static char **fill_envp(struct d6_packet *packet)
380} 443}
381 444
382/* Call a script with a par file and env vars */ 445/* Call a script with a par file and env vars */
383static void d6_run_script(struct d6_packet *packet, const char *name) 446static void d6_run_script(const uint8_t *option, const uint8_t *option_end,
447 const char *name)
384{ 448{
385 char **envp, **curr; 449 char **envp, **curr;
386 char *argv[3]; 450 char *argv[3];
387 451
388 envp = fill_envp(packet); 452 envp = fill_envp(option, option_end);
389 453
390 /* call script */ 454 /* call script */
391 log1("executing %s %s", client_config.script, name); 455 log1("executing %s %s", client_config.script, name);
@@ -401,6 +465,11 @@ static void d6_run_script(struct d6_packet *packet, const char *name)
401 free(envp); 465 free(envp);
402} 466}
403 467
468/* Call a script with a par file and no env var */
469static void d6_run_script_no_option(const char *name)
470{
471 d6_run_script(NULL, NULL, name);
472}
404 473
405/*** Sending/receiving packets ***/ 474/*** Sending/receiving packets ***/
406 475
@@ -426,8 +495,10 @@ static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid
426 495
427static uint8_t *add_d6_client_options(uint8_t *ptr) 496static uint8_t *add_d6_client_options(uint8_t *ptr)
428{ 497{
498 struct option_set *curr;
429 uint8_t *start = ptr; 499 uint8_t *start = ptr;
430 unsigned option; 500 unsigned option;
501 uint16_t len;
431 502
432 ptr += 4; 503 ptr += 4;
433 for (option = 1; option < 256; option++) { 504 for (option = 1; option < 256; option++) {
@@ -450,7 +521,12 @@ static uint8_t *add_d6_client_options(uint8_t *ptr)
450 ptr = mempcpy(ptr, &opt_fqdn_req, sizeof(opt_fqdn_req)); 521 ptr = mempcpy(ptr, &opt_fqdn_req, sizeof(opt_fqdn_req));
451#endif 522#endif
452 /* Add -x options if any */ 523 /* Add -x options if any */
453 //... 524 curr = client_config.options;
525 while (curr) {
526 len = (curr->data[D6_OPT_LEN] << 8) | curr->data[D6_OPT_LEN + 1];
527 ptr = mempcpy(ptr, curr->data, D6_OPT_DATA + len);
528 curr = curr->next;
529 }
454 530
455 return ptr; 531 return ptr;
456} 532}
@@ -727,15 +803,13 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st
727 opt_ptr = add_d6_client_options(opt_ptr); 803 opt_ptr = add_d6_client_options(opt_ptr);
728 804
729 bb_error_msg("sending %s", "renew"); 805 bb_error_msg("sending %s", "renew");
730 if (server_ipv6) { 806 if (server_ipv6)
731 return d6_send_kernel_packet( 807 return d6_send_kernel_packet(
732 &packet, (opt_ptr - (uint8_t*) &packet), 808 &packet, (opt_ptr - (uint8_t*) &packet),
733 our_cur_ipv6, CLIENT_PORT6, 809 our_cur_ipv6, CLIENT_PORT6,
734 server_ipv6, SERVER_PORT6, 810 server_ipv6, SERVER_PORT6,
735 client_config.ifindex 811 client_config.ifindex
736 /* TODO? send_flags: MSG_DONTROUTE (see IPv4 code for reason why) */
737 ); 812 );
738 }
739 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); 813 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr);
740} 814}
741 815
@@ -969,7 +1043,7 @@ static void perform_renew(void)
969 state = RENEW_REQUESTED; 1043 state = RENEW_REQUESTED;
970 break; 1044 break;
971 case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ 1045 case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
972 d6_run_script(NULL, "deconfig"); 1046 d6_run_script_no_option("deconfig");
973 case REQUESTING: 1047 case REQUESTING:
974 case RELEASED: 1048 case RELEASED:
975 change_listen_mode(LISTEN_RAW); 1049 change_listen_mode(LISTEN_RAW);
@@ -998,7 +1072,7 @@ static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *ou
998 * Users requested to be notified in all cases, even if not in one 1072 * Users requested to be notified in all cases, even if not in one
999 * of the states above. 1073 * of the states above.
1000 */ 1074 */
1001 d6_run_script(NULL, "deconfig"); 1075 d6_run_script_no_option("deconfig");
1002 change_listen_mode(LISTEN_NONE); 1076 change_listen_mode(LISTEN_NONE);
1003 state = RELEASED; 1077 state = RELEASED;
1004} 1078}
@@ -1157,7 +1231,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1157 } 1231 }
1158 while (list_x) { 1232 while (list_x) {
1159 char *optstr = xstrdup(llist_pop(&list_x)); 1233 char *optstr = xstrdup(llist_pop(&list_x));
1160 udhcp_str2optset(optstr, &client_config.options, d6_optflags, d6_option_strings); 1234 udhcp_str2optset(optstr, &client_config.options,
1235 d6_optflags, d6_option_strings,
1236 /*dhcpv6:*/ 1
1237 );
1161 free(optstr); 1238 free(optstr);
1162 } 1239 }
1163 1240
@@ -1204,7 +1281,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1204 udhcp_sp_setup(); 1281 udhcp_sp_setup();
1205 1282
1206 state = INIT_SELECTING; 1283 state = INIT_SELECTING;
1207 d6_run_script(NULL, "deconfig"); 1284 d6_run_script_no_option("deconfig");
1208 change_listen_mode(LISTEN_RAW); 1285 change_listen_mode(LISTEN_RAW);
1209 packet_num = 0; 1286 packet_num = 0;
1210 timeout = 0; 1287 timeout = 0;
@@ -1285,7 +1362,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1285 continue; 1362 continue;
1286 } 1363 }
1287 leasefail: 1364 leasefail:
1288 d6_run_script(NULL, "leasefail"); 1365 d6_run_script_no_option("leasefail");
1289#if BB_MMU /* -b is not supported on NOMMU */ 1366#if BB_MMU /* -b is not supported on NOMMU */
1290 if (opt & OPT_b) { /* background if no lease */ 1367 if (opt & OPT_b) { /* background if no lease */
1291 bb_error_msg("no lease, forking to background"); 1368 bb_error_msg("no lease, forking to background");
@@ -1359,7 +1436,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1359 } 1436 }
1360 /* Timed out, enter init state */ 1437 /* Timed out, enter init state */
1361 bb_error_msg("lease lost, entering init state"); 1438 bb_error_msg("lease lost, entering init state");
1362 d6_run_script(NULL, "deconfig"); 1439 d6_run_script_no_option("deconfig");
1363 state = INIT_SELECTING; 1440 state = INIT_SELECTING;
1364 client_config.first_secs = 0; /* make secs field count from 0 */ 1441 client_config.first_secs = 0; /* make secs field count from 0 */
1365 /*timeout = 0; - already is */ 1442 /*timeout = 0; - already is */
@@ -1466,9 +1543,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1466 if (option && (option->data[0] | option->data[1]) != 0) { 1543 if (option && (option->data[0] | option->data[1]) != 0) {
1467 /* return to init state */ 1544 /* return to init state */
1468 bb_error_msg("received DHCP NAK (%u)", option->data[4]); 1545 bb_error_msg("received DHCP NAK (%u)", option->data[4]);
1469 d6_run_script(&packet, "nak"); 1546 d6_run_script(packet.d6_options,
1547 packet_end, "nak");
1470 if (state != REQUESTING) 1548 if (state != REQUESTING)
1471 d6_run_script(NULL, "deconfig"); 1549 d6_run_script_no_option("deconfig");
1472 change_listen_mode(LISTEN_RAW); 1550 change_listen_mode(LISTEN_RAW);
1473 sleep(3); /* avoid excessive network traffic */ 1551 sleep(3); /* avoid excessive network traffic */
1474 state = INIT_SELECTING; 1552 state = INIT_SELECTING;
@@ -1665,7 +1743,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1665 if (timeout < 0x10) 1743 if (timeout < 0x10)
1666 timeout = 0x10; 1744 timeout = 0x10;
1667 /* enter bound state */ 1745 /* enter bound state */
1668 d6_run_script(&packet, state == REQUESTING ? "bound" : "renew"); 1746 d6_run_script(packet.d6_options, packet_end,
1747 (state == REQUESTING ? "bound" : "renew"));
1669 1748
1670 state = BOUND; 1749 state = BOUND;
1671 change_listen_mode(LISTEN_NONE); 1750 change_listen_mode(LISTEN_NONE);
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index bd9e8fdc2..c2805a009 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -693,16 +693,10 @@ static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet, uint
693 693
694static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t server) 694static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t server)
695{ 695{
696 if (server) { 696 if (server)
697 /* Without MSG_DONTROUTE, the packet was seen routed over
698 * _other interface_ if server ID is bogus (example: 1.1.1.1).
699 */
700 return udhcp_send_kernel_packet(packet, 697 return udhcp_send_kernel_packet(packet,
701 ciaddr, CLIENT_PORT, 698 ciaddr, CLIENT_PORT,
702 server, SERVER_PORT, 699 server, SERVER_PORT);
703 /*send_flags: "to hosts only on directly connected networks" */ MSG_DONTROUTE
704 );
705 }
706 return raw_bcast_from_client_config_ifindex(packet, ciaddr); 700 return raw_bcast_from_client_config_ifindex(packet, ciaddr);
707} 701}
708 702
@@ -1337,7 +1331,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1337 } 1331 }
1338 while (list_x) { 1332 while (list_x) {
1339 char *optstr = xstrdup(llist_pop(&list_x)); 1333 char *optstr = xstrdup(llist_pop(&list_x));
1340 udhcp_str2optset(optstr, &client_config.options, dhcp_optflags, dhcp_option_strings); 1334 udhcp_str2optset(optstr, &client_config.options,
1335 dhcp_optflags, dhcp_option_strings,
1336 /*dhcpv6:*/ 0
1337 );
1341 free(optstr); 1338 free(optstr);
1342 } 1339 }
1343 1340
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 19f94a2d7..a8cd3f03b 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -362,7 +362,10 @@ static int FAST_FUNC read_staticlease(const char *const_line, void *arg)
362} 362}
363 363
364static int FAST_FUNC read_optset(const char *line, void *arg) { 364static int FAST_FUNC read_optset(const char *line, void *arg) {
365 return udhcp_str2optset(line, arg, dhcp_optflags, dhcp_option_strings); 365 return udhcp_str2optset(line, arg,
366 dhcp_optflags, dhcp_option_strings,
367 /*dhcpv6:*/ 0
368 );
366} 369}
367 370
368struct config_keyword { 371struct config_keyword {
@@ -588,9 +591,7 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
588 591
589 udhcp_send_kernel_packet(dhcp_pkt, 592 udhcp_send_kernel_packet(dhcp_pkt,
590 server_config.server_nip, SERVER_PORT, 593 server_config.server_nip, SERVER_PORT,
591 dhcp_pkt->gateway_nip, SERVER_PORT, 594 dhcp_pkt->gateway_nip, SERVER_PORT);
592 /*send_flags:*/ 0
593 );
594} 595}
595 596
596static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) 597static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c
index fc2bb5416..ff16904f7 100644
--- a/networking/udhcp/packet.c
+++ b/networking/udhcp/packet.c
@@ -189,8 +189,7 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
189/* Let the kernel do all the work for packet generation */ 189/* Let the kernel do all the work for packet generation */
190int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 190int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
191 uint32_t source_nip, int source_port, 191 uint32_t source_nip, int source_port,
192 uint32_t dest_nip, int dest_port, 192 uint32_t dest_nip, int dest_port)
193 int send_flags)
194{ 193{
195 struct sockaddr_in sa; 194 struct sockaddr_in sa;
196 unsigned padding; 195 unsigned padding;
@@ -227,8 +226,8 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
227 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options); 226 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options);
228 if (padding > DHCP_SIZE - 300) 227 if (padding > DHCP_SIZE - 300)
229 padding = DHCP_SIZE - 300; 228 padding = DHCP_SIZE - 300;
230 result = send(fd, dhcp_pkt, DHCP_SIZE - padding, send_flags); 229 result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding);
231 msg = "send"; 230 msg = "write";
232 ret_close: 231 ret_close:
233 close(fd); 232 close(fd);
234 if (result < 0) { 233 if (result < 0) {
diff --git a/networking/wget.c b/networking/wget.c
index 85eae061b..bd2f4edcf 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -137,6 +137,7 @@
137//usage: "Retrieve files via HTTP or FTP\n" 137//usage: "Retrieve files via HTTP or FTP\n"
138//usage: IF_FEATURE_WGET_LONG_OPTIONS( 138//usage: IF_FEATURE_WGET_LONG_OPTIONS(
139//usage: "\n --spider Only check URL existence: $? is 0 if exists" 139//usage: "\n --spider Only check URL existence: $? is 0 if exists"
140///////: "\n --no-check-certificate Don't validate the server's certificate"
140//usage: ) 141//usage: )
141//usage: "\n -c Continue retrieval of aborted transfer" 142//usage: "\n -c Continue retrieval of aborted transfer"
142//usage: "\n -q Quiet" 143//usage: "\n -q Quiet"
@@ -271,6 +272,7 @@ enum {
271 WGET_OPT_HEADER = (1 << 10) * ENABLE_FEATURE_WGET_LONG_OPTIONS, 272 WGET_OPT_HEADER = (1 << 10) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
272 WGET_OPT_POST_DATA = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS, 273 WGET_OPT_POST_DATA = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
273 WGET_OPT_SPIDER = (1 << 12) * ENABLE_FEATURE_WGET_LONG_OPTIONS, 274 WGET_OPT_SPIDER = (1 << 12) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
275 WGET_OPT_NO_CHECK_CERT = (1 << 13) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
274}; 276};
275 277
276enum { 278enum {
@@ -721,6 +723,9 @@ static void spawn_ssl_client(const char *host, int network_fd, int flags)
721 int pid; 723 int pid;
722 char *servername, *p; 724 char *servername, *p;
723 725
726 if (!(option_mask32 & WGET_OPT_NO_CHECK_CERT))
727 bb_error_msg("note: TLS certificate validation not implemented");
728
724 servername = xstrdup(host); 729 servername = xstrdup(host);
725 p = strrchr(servername, ':'); 730 p = strrchr(servername, ':');
726 if (p) *p = '\0'; 731 if (p) *p = '\0';
@@ -1362,6 +1367,7 @@ However, in real world it was observed that some web servers
1362 /* server.user remains untouched */ 1367 /* server.user remains untouched */
1363 free(server.allocated); 1368 free(server.allocated);
1364 server.allocated = NULL; 1369 server.allocated = NULL;
1370 server.protocol = target.protocol;
1365 server.host = target.host; 1371 server.host = target.host;
1366 /* strip_ipv6_scope_id(target.host); - no! */ 1372 /* strip_ipv6_scope_id(target.host); - no! */
1367 /* we assume remote never gives us IPv6 addr with scope id */ 1373 /* we assume remote never gives us IPv6 addr with scope id */
@@ -1434,10 +1440,9 @@ IF_DESKTOP( "tries\0" Required_argument "t")
1434 "header\0" Required_argument "\xff" 1440 "header\0" Required_argument "\xff"
1435 "post-data\0" Required_argument "\xfe" 1441 "post-data\0" Required_argument "\xfe"
1436 "spider\0" No_argument "\xfd" 1442 "spider\0" No_argument "\xfd"
1443 "no-check-certificate\0" No_argument "\xfc"
1437 /* Ignored (we always use PASV): */ 1444 /* Ignored (we always use PASV): */
1438IF_DESKTOP( "passive-ftp\0" No_argument "\xf0") 1445IF_DESKTOP( "passive-ftp\0" No_argument "\xf0")
1439 /* Ignored (we don't do ssl) */
1440IF_DESKTOP( "no-check-certificate\0" No_argument "\xf0")
1441 /* Ignored (we don't support caching) */ 1446 /* Ignored (we don't support caching) */
1442IF_DESKTOP( "no-cache\0" No_argument "\xf0") 1447IF_DESKTOP( "no-cache\0" No_argument "\xf0")
1443IF_DESKTOP( "no-verbose\0" No_argument "\xf0") 1448IF_DESKTOP( "no-verbose\0" No_argument "\xf0")
@@ -1497,6 +1502,7 @@ IF_DESKTOP( "no-parent\0" No_argument "\xf0")
1497 if (option_mask32 & WGET_OPT_HEADER) bb_error_msg("--header"); 1502 if (option_mask32 & WGET_OPT_HEADER) bb_error_msg("--header");
1498 if (option_mask32 & WGET_OPT_POST_DATA) bb_error_msg("--post-data"); 1503 if (option_mask32 & WGET_OPT_POST_DATA) bb_error_msg("--post-data");
1499 if (option_mask32 & WGET_OPT_SPIDER) bb_error_msg("--spider"); 1504 if (option_mask32 & WGET_OPT_SPIDER) bb_error_msg("--spider");
1505 if (option_mask32 & WGET_OPT_NO_CHECK_CERT) bb_error_msg("--no-check-certificate");
1500 exit(0); 1506 exit(0);
1501#endif 1507#endif
1502 argv += optind; 1508 argv += optind;
diff --git a/printutils/Config.src b/printutils/Config.src
index e53b9d093..5f1d65f6c 100644
--- a/printutils/Config.src
+++ b/printutils/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Print Utilities" 6menu "Print Utilities"
diff --git a/procps/Config.src b/procps/Config.src
index 515d79938..2b1b8ab11 100644
--- a/procps/Config.src
+++ b/procps/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Process Utilities" 6menu "Process Utilities"
diff --git a/runit/Config.src b/runit/Config.src
index 8cde89680..403ec8724 100644
--- a/runit/Config.src
+++ b/runit/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Runit Utilities" 6menu "Runit Utilities"
diff --git a/scripts/bb_release b/scripts/bb_release
index 8aa380438..2e146bf84 100755
--- a/scripts/bb_release
+++ b/scripts/bb_release
@@ -15,20 +15,8 @@ VERSION=`ls busybox-*.tar.gz | sed 's/busybox-\(.*\)\.tar\.gz/\1/'`
15 15
16zcat busybox-$VERSION.tar.gz | bzip2 > busybox-$VERSION.tar.bz2 16zcat busybox-$VERSION.tar.gz | bzip2 > busybox-$VERSION.tar.bz2
17 17
18test -f busybox-$VERSION.tar.gz || { echo "no busybox-$VERSION.tar.gz"; exit 1; } 18for releasefile in busybox-$VERSION.tar.gz busybox-$VERSION.tar.bz2; do
19test -f busybox-$VERSION.tar.bz2 || { echo "no busybox-$VERSION.tar.bz2"; exit 1; } 19 test -f $releasefile || { echo "no $releasefile"; exit 1; }
20 20 gpg --detach-sign $releasefile
21signit() 21 sha256sum $releasefile > $releasefile.sha256
22{ 22done
23echo "$1 released `date -r $1 -R`
24
25MD5: `md5sum $1`
26SHA1: `sha1sum $1`
27
28To verify this signature, you can obtain my public key
29from http://busybox.net/~vda/vda_pubkey.gpg
30" | gpg --clearsign > "$1.sign"
31}
32
33signit busybox-$VERSION.tar.gz
34signit busybox-$VERSION.tar.bz2
diff --git a/scripts/randomtest b/scripts/randomtest
index 635978338..94709a99f 100755
--- a/scripts/randomtest
+++ b/scripts/randomtest
@@ -57,6 +57,8 @@ if test x"$LIBC" = x"glibc"; then
57 | grep -v CONFIG_FEATURE_2_4_MODULES \ 57 | grep -v CONFIG_FEATURE_2_4_MODULES \
58 | grep -v CONFIG_FEATURE_USE_BSS_TAIL \ 58 | grep -v CONFIG_FEATURE_USE_BSS_TAIL \
59 | grep -v CONFIG_DEBUG_SANITIZE \ 59 | grep -v CONFIG_DEBUG_SANITIZE \
60 | grep -v CONFIG_FEATURE_MOUNT_NFS \
61 | grep -v CONFIG_FEATURE_INETD_RPC \
60 >.config.new 62 >.config.new
61 mv .config.new .config 63 mv .config.new .config
62 echo '# CONFIG_STATIC is not set' >>.config 64 echo '# CONFIG_STATIC is not set' >>.config
@@ -66,6 +68,9 @@ if test x"$LIBC" = x"glibc"; then
66 echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config 68 echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config
67 echo '# CONFIG_FEATURE_USE_BSS_TAIL is not set' >>.config 69 echo '# CONFIG_FEATURE_USE_BSS_TAIL is not set' >>.config
68 echo '# CONFIG_DEBUG_SANITIZE is not set' >>.config 70 echo '# CONFIG_DEBUG_SANITIZE is not set' >>.config
71 # 2018: current glibc versions no longer include rpc/rpc.h
72 echo '# CONFIG_FEATURE_MOUNT_NFS is not set' >>.config
73 echo '# CONFIG_FEATURE_INETD_RPC is not set' >>.config
69fi 74fi
70 75
71# If uclibc, build static, and remove some things 76# If uclibc, build static, and remove some things
@@ -86,6 +91,7 @@ if test x"$LIBC" = x"uclibc"; then
86 | grep -v CONFIG_UNSHARE \ 91 | grep -v CONFIG_UNSHARE \
87 | grep -v CONFIG_FALLOCATE \ 92 | grep -v CONFIG_FALLOCATE \
88 | grep -v CONFIG_UDHCPC6 \ 93 | grep -v CONFIG_UDHCPC6 \
94 | grep -v CONFIG_NSLOOKUP \
89 | grep -v CONFIG_ASH_INTERNAL_GLOB \ 95 | grep -v CONFIG_ASH_INTERNAL_GLOB \
90 >.config.new 96 >.config.new
91 mv .config.new .config 97 mv .config.new .config
@@ -103,6 +109,7 @@ if test x"$LIBC" = x"uclibc"; then
103 echo '# CONFIG_UNSHARE is not set' >>.config 109 echo '# CONFIG_UNSHARE is not set' >>.config
104 echo '# CONFIG_FALLOCATE is not set' >>.config 110 echo '# CONFIG_FALLOCATE is not set' >>.config
105 echo '# CONFIG_UDHCPC6 is not set' >>.config 111 echo '# CONFIG_UDHCPC6 is not set' >>.config
112 echo '# CONFIG_NSLOOKUP is not set' >>.config
106 echo 'CONFIG_ASH_INTERNAL_GLOB=y' >>.config 113 echo 'CONFIG_ASH_INTERNAL_GLOB=y' >>.config
107fi 114fi
108 115
diff --git a/selinux/Config.src b/selinux/Config.src
index 9cb755a0f..f8fcdadf9 100644
--- a/selinux/Config.src
+++ b/selinux/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "SELinux Utilities" 6menu "SELinux Utilities"
diff --git a/shell/Config.src b/shell/Config.src
index 81c4ec874..959d3cb42 100644
--- a/shell/Config.src
+++ b/shell/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Shells" 6menu "Shells"
diff --git a/shell/ash.c b/shell/ash.c
index 7fa9dae21..4bd1c2c9d 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -8929,7 +8929,8 @@ describe_command(char *command, const char *path, int describe_command_verbose)
8929 8929
8930 case CMDFUNCTION: 8930 case CMDFUNCTION:
8931 if (describe_command_verbose) { 8931 if (describe_command_verbose) {
8932 out1str(" is a shell function"); 8932 /*out1str(" is a shell function");*/
8933 out1str(" is a function"); /* bash says this */
8933 } else { 8934 } else {
8934 out1str(command); 8935 out1str(command);
8935 } 8936 }
diff --git a/shell/ash_test/ash-glob/glob_altvalue1.right b/shell/ash_test/ash-glob/glob_altvalue1.right
new file mode 100644
index 000000000..bd3592229
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob_altvalue1.right
@@ -0,0 +1,7 @@
11u: glob_altvalue1.tests
22u: glob_altvalue1.t*
33u: glob_altvalue1.t*
44u: glob_altvalue1.t*
51q: glob_altvalue1.t*
62q: 'glob_altvalue1.t*'
73q: glob_altvalue1.t*
diff --git a/shell/ash_test/ash-glob/glob_altvalue1.tests b/shell/ash_test/ash-glob/glob_altvalue1.tests
new file mode 100755
index 000000000..5483d63e6
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob_altvalue1.tests
@@ -0,0 +1,13 @@
1x=x
2
3echo 1u: ${x:+glob_altvalue1.t*}
4echo 2u: ${x:+'glob_altvalue1.t*'}
5echo 3u: ${x:+"glob_altvalue1.t*"}
6echo 4u: ${x:+glob_altvalue1.t\*}
7##echo 5u: ${x:+"glob_altvalue1.t\*"}
8
9echo 1q: "${x:+glob_altvalue1.t*}"
10echo 2q: "${x:+'glob_altvalue1.t*'}"
11echo 3q: "${x:+"glob_altvalue1.t*"}"
12##echo 4q: "${x:+glob_altvalue1.t\*}"
13##echo 5q: "${x:+"glob_altvalue1.t\*"}"
diff --git a/shell/ash_test/ash-heredoc/heredoc.right b/shell/ash_test/ash-heredoc/heredoc.right
index baf115166..85d36dae9 100644
--- a/shell/ash_test/ash-heredoc/heredoc.right
+++ b/shell/ash_test/ash-heredoc/heredoc.right
@@ -16,6 +16,6 @@ tab 3
16abc 16abc
17def ghi 17def ghi
18jkl mno 18jkl mno
19fff is a shell function 19fff is a function
20hi 20hi
21there 21there
diff --git a/shell/ash_test/ash-heredoc/heredocA.right b/shell/ash_test/ash-heredoc/heredocA.right
new file mode 100644
index 000000000..7326d9603
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredocA.right
@@ -0,0 +1 @@
Ok
diff --git a/shell/ash_test/ash-heredoc/heredocA.tests b/shell/ash_test/ash-heredoc/heredocA.tests
new file mode 100755
index 000000000..440aaf906
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredocA.tests
@@ -0,0 +1,4 @@
1{ cat <<EOF ;
2Ok
3EOF
4}
diff --git a/shell/ash_test/ash-heredoc/heredocB.right b/shell/ash_test/ash-heredoc/heredocB.right
new file mode 100644
index 000000000..43ba0b4f9
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredocB.right
@@ -0,0 +1,3 @@
1one - alpha
2two - beta
3three - gamma
diff --git a/shell/ash_test/ash-heredoc/heredocB.tests b/shell/ash_test/ash-heredoc/heredocB.tests
new file mode 100755
index 000000000..45ea4687f
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredocB.tests
@@ -0,0 +1,12 @@
1while read line1; do
2 read line2 <&3
3 echo $line1 - $line2
4done <<EOF1 3<<EOF2
5one
6two
7three
8EOF1
9alpha
10beta
11gamma
12EOF2
diff --git a/shell/ash_test/ash-heredoc/heredoc_after_compound1.right b/shell/ash_test/ash-heredoc/heredoc_after_compound1.right
new file mode 100644
index 000000000..9052f7d1f
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_after_compound1.right
@@ -0,0 +1,2 @@
1Ok1
2Ok2
diff --git a/shell/ash_test/ash-heredoc/heredoc_after_compound1.tests b/shell/ash_test/ash-heredoc/heredoc_after_compound1.tests
new file mode 100755
index 000000000..e7cfb5be1
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_after_compound1.tests
@@ -0,0 +1,3 @@
1{ cat <<EOF; }; echo Ok2
2Ok1
3EOF
diff --git a/shell/ash_test/ash-heredoc/heredoc_bkslash_newline2.right b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline2.right
new file mode 100644
index 000000000..3d79316d7
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline2.right
@@ -0,0 +1 @@
Ok1
diff --git a/shell/ash_test/ash-heredoc/heredoc_bkslash_newline2.tests b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline2.tests
new file mode 100755
index 000000000..1d2a26504
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_bkslash_newline2.tests
@@ -0,0 +1,4 @@
1cat <<EOF
2Ok1
3EO\
4F
diff --git a/shell/ash_test/ash-heredoc/heredoc_empty3.right b/shell/ash_test/ash-heredoc/heredoc_empty3.right
new file mode 100644
index 000000000..0b54a9c93
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_empty3.right
@@ -0,0 +1,2 @@
1
2Ok
diff --git a/shell/ash_test/ash-heredoc/heredoc_empty3.tests b/shell/ash_test/ash-heredoc/heredoc_empty3.tests
new file mode 100755
index 000000000..828c2dd89
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_empty3.tests
@@ -0,0 +1,4 @@
1cat <<EOF
2
3Ok
4EOF
diff --git a/shell/ash_test/ash-quoting/dollar_altvalue1.right b/shell/ash_test/ash-quoting/dollar_altvalue1.right
new file mode 100644
index 000000000..5cd495d3b
--- /dev/null
+++ b/shell/ash_test/ash-quoting/dollar_altvalue1.right
@@ -0,0 +1,16 @@
1Unquoted b c d
2|b|
3|c|
4|d|
5Unquoted 'b c' d
6|b c|
7|d|
8Unquoted "b c" d
9|b c|
10|d|
11Quoted b c d
12|b c d|
13Quoted 'b c' d
14|'b c' d|
15Quoted "b c" d
16|b c d|
diff --git a/shell/ash_test/ash-quoting/dollar_altvalue1.tests b/shell/ash_test/ash-quoting/dollar_altvalue1.tests
new file mode 100755
index 000000000..f4dc8caec
--- /dev/null
+++ b/shell/ash_test/ash-quoting/dollar_altvalue1.tests
@@ -0,0 +1,16 @@
1f() { for i; do echo "|$i|"; done; }
2x=a
3
4echo Unquoted b c d
5f ${x:+b c d}
6echo Unquoted "'b c' d"
7f ${x:+'b c' d}
8echo Unquoted '"b c" d'
9f ${x:+"b c" d}
10
11echo Quoted b c d
12f "${x:+b c d}"
13echo Quoted "'b c' d"
14f "${x:+'b c' d}"
15echo Quoted '"b c" d'
16f "${x:+"b c" d}"
diff --git a/shell/ash_test/ash-quoting/dollar_altvalue2.right b/shell/ash_test/ash-quoting/dollar_altvalue2.right
new file mode 100644
index 000000000..7cf37e379
--- /dev/null
+++ b/shell/ash_test/ash-quoting/dollar_altvalue2.right
@@ -0,0 +1,69 @@
1Unquoted '':
2start:
3||
4end
5start:
6||
7end
8start:
9||
10end
11start:
12||
13end
14start:
15||
16||
17end
18
19Unquoted "":
20start:
21||
22end
23start:
24||
25end
26start:
27||
28end
29start:
30||
31end
32start:
33||
34||
35end
36
37Quoted '':
38start:
39|''|
40end
41start:
42|'' |
43end
44start:
45| ''|
46end
47start:
48| '' |
49end
50start:
51|'' ''|
52end
53
54Quoted "":
55start:
56||
57end
58start:
59| |
60end
61start:
62| |
63end
64start:
65| |
66end
67start:
68| |
69end
diff --git a/shell/ash_test/ash-quoting/dollar_altvalue2.tests b/shell/ash_test/ash-quoting/dollar_altvalue2.tests
new file mode 100755
index 000000000..3377eb27f
--- /dev/null
+++ b/shell/ash_test/ash-quoting/dollar_altvalue2.tests
@@ -0,0 +1,33 @@
1f() { echo start:; for i; do echo "|$i|"; done; echo end; }
2x=a
3
4echo "Unquoted '':"
5f ${x:+''}
6f ${x:+'' }
7f ${x:+ ''}
8f ${x:+ '' }
9f ${x:+'' ''}
10
11echo
12echo 'Unquoted "":'
13f ${x:+""}
14f ${x:+"" }
15f ${x:+ ""}
16f ${x:+ "" }
17f ${x:+"" ""}
18
19echo
20echo "Quoted '':"
21f "${x:+''}"
22f "${x:+'' }"
23f "${x:+ ''}"
24f "${x:+ '' }"
25f "${x:+'' ''}"
26
27echo
28echo 'Quoted "":'
29f "${x:+""}"
30f "${x:+"" }"
31f "${x:+ ""}"
32f "${x:+ "" }"
33f "${x:+"" ""}"
diff --git a/shell/ash_test/ash-quoting/dollar_altvalue9.right b/shell/ash_test/ash-quoting/dollar_altvalue9.right
new file mode 100644
index 000000000..39342fe7c
--- /dev/null
+++ b/shell/ash_test/ash-quoting/dollar_altvalue9.right
@@ -0,0 +1,26 @@
1Unquoted 1:
2|a|
3|x y|
4|1|
5|2|
6||
7|1 2|
8|A|
9|B|
10|C D|
11|zb|
12Quoted 1:
13|a 'x y' 1 2 '' 1 2 A B C D zb|
14Unquoted 2:
15|ax y|
16|1|
17|2|
18||
19|1 2|
20|A|
21|B|
22|C D|
23|z|
24|b|
25Quoted 2:
26|a 'x y' 1 2 '' 1 2 A B C D z b|
diff --git a/shell/ash_test/ash-quoting/dollar_altvalue9.tests b/shell/ash_test/ash-quoting/dollar_altvalue9.tests
new file mode 100755
index 000000000..27a6f4f3c
--- /dev/null
+++ b/shell/ash_test/ash-quoting/dollar_altvalue9.tests
@@ -0,0 +1,17 @@
1f() { for i; do echo "|$i|"; done; }
2
3echo Unquoted 1:
4x='1 2'; f a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z}b
5echo Quoted 1:
6x='1 2'; f "a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z}b"
7
8echo Unquoted 2:
9x='1 2'; f a${x:+'x y' $x '' "$x" `echo A B` "`echo C D`" z }b
10echo Quoted 2:
11x='1 2'; f "a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z }b"
12
13#echo Unquoted 3:
14#e=
15#x='1 2'; f a${x:+'x y' $x '' "$x" $e $e "$e" $e `echo A B` "`echo C D`" z }b
16#echo Quoted 3:
17#x='1 2'; f "a${x:+ 'x y' $x '' "$x" $e $e "$e" $e `echo A B` "`echo C D`" z }b"
diff --git a/shell/ash_test/ash-quoting/dollar_repl_bash1.right b/shell/ash_test/ash-quoting/dollar_repl_bash1.right
new file mode 100644
index 000000000..f5e9309f4
--- /dev/null
+++ b/shell/ash_test/ash-quoting/dollar_repl_bash1.right
@@ -0,0 +1,14 @@
1|y|
2|zx|
3|y|
4|zx|
5|y zx|
6|y zx|
7|y|
8|zy|
9|z|
10|y|
11|zy|
12|z|
13|y zy z|
14|y zy z|
diff --git a/shell/ash_test/ash-quoting/dollar_repl_bash1.tests b/shell/ash_test/ash-quoting/dollar_repl_bash1.tests
new file mode 100755
index 000000000..912635925
--- /dev/null
+++ b/shell/ash_test/ash-quoting/dollar_repl_bash1.tests
@@ -0,0 +1,12 @@
1f() { for i; do echo "|$i|"; done; }
2v=xx
3
4f ${v/'x'/"y z"}
5f ${v/"x"/'y z'}
6f "${v/'x'/"y z"}"
7f "${v/"x"/'y z'}"
8
9f ${v//'x'/"y z"}
10f ${v//"x"/'y z'}
11f "${v//'x'/"y z"}"
12f "${v//"x"/'y z'}"
diff --git a/shell/ash_test/ash-quoting/squote_in_varexp.right b/shell/ash_test/ash-quoting/squote_in_varexp.right
index a75c0bfd6..4a457021b 100644
--- a/shell/ash_test/ash-quoting/squote_in_varexp.right
+++ b/shell/ash_test/ash-quoting/squote_in_varexp.right
@@ -1,5 +1,9 @@
1z 1z
2z 2z
3z
4z
5y
6y
3y 7y
4y 8y
5Ok:0 9Ok:0
diff --git a/shell/ash_test/ash-quoting/squote_in_varexp.tests b/shell/ash_test/ash-quoting/squote_in_varexp.tests
index a2d05a246..4afc52107 100755
--- a/shell/ash_test/ash-quoting/squote_in_varexp.tests
+++ b/shell/ash_test/ash-quoting/squote_in_varexp.tests
@@ -1,6 +1,10 @@
1x=yz 1x=yz
2echo ${x#'y'} 2echo ${x#'y'}
3echo "${x#'y'}" 3echo "${x#'y'}"
4echo ${x#"y"}
5echo "${x#"y"}"
4echo ${x%'z'} 6echo ${x%'z'}
5echo "${x%'z'}" 7echo "${x%'z'}"
8echo ${x%"z"}
9echo "${x%"z"}"
6echo Ok:$? 10echo Ok:$?
diff --git a/shell/ash_test/ash-quoting/squote_in_varexp2.right b/shell/ash_test/ash-quoting/squote_in_varexp2.right
index 9d0add3c5..d03047024 100644
--- a/shell/ash_test/ash-quoting/squote_in_varexp2.right
+++ b/shell/ash_test/ash-quoting/squote_in_varexp2.right
@@ -1,3 +1,5 @@
1Nothing: 1Nothing:
2Nothing: 2Nothing:
3Nothing:
4Nothing:
3Ok:0 5Ok:0
diff --git a/shell/ash_test/ash-quoting/squote_in_varexp2.tests b/shell/ash_test/ash-quoting/squote_in_varexp2.tests
index 806ad12b9..2797725cc 100755
--- a/shell/ash_test/ash-quoting/squote_in_varexp2.tests
+++ b/shell/ash_test/ash-quoting/squote_in_varexp2.tests
@@ -1,4 +1,6 @@
1x='\\\\' 1x='\\\\'
2printf Nothing:'%s\n' ${x#'\\\\'} 2printf Nothing:'%s\n' ${x#'\\\\'}
3printf Nothing:'%s\n' "${x#'\\\\'}" 3printf Nothing:'%s\n' "${x#'\\\\'}"
4printf Nothing:'%s\n' ${x#"\\\\\\\\"}
5printf Nothing:'%s\n' "${x#"\\\\\\\\"}"
4echo Ok:$? 6echo Ok:$?
diff --git a/shell/ash_test/ash-redir/redir_script.tests b/shell/ash_test/ash-redir/redir_script.tests
index 740daa461..a8d93ce4f 100755
--- a/shell/ash_test/ash-redir/redir_script.tests
+++ b/shell/ash_test/ash-redir/redir_script.tests
@@ -27,6 +27,10 @@ test x"$fds1" = x"$fds" \
27test x"$fds1" = x" 10>&- 3>&-" && \ 27test x"$fds1" = x" 10>&- 3>&-" && \
28test x"$fds" = x" 11>&- 3>&-" \ 28test x"$fds" = x" 11>&- 3>&-" \
29&& { echo "Ok: script fd is not closed"; exit 0; } 29&& { echo "Ok: script fd is not closed"; exit 0; }
30# or we see that fd 3 moved to fd 10:
31test x"$fds1" = x" 3>&- 4>&-" && \
32test x"$fds" = x" 10>&- 3>&-" \
33&& { echo "Ok: script fd is not closed"; exit 0; }
30 34
31echo "Bug: script fd is closed" 35echo "Bug: script fd is closed"
32echo "fds1:$fds1" 36echo "fds1:$fds1"
diff --git a/shell/ash_test/ash-z_slow/many_ifs.tests b/shell/ash_test/ash-z_slow/many_ifs.tests
index 1f5b1b3a6..cf9a89874 100755
--- a/shell/ash_test/ash-z_slow/many_ifs.tests
+++ b/shell/ash_test/ash-z_slow/many_ifs.tests
@@ -229,8 +229,8 @@ do
229 '') split "$d0$f1$d1$f2$d2$f3$d3" "[2]($f1)($f2)" "($f1)($f2)" ;; 229 '') split "$d0$f1$d1$f2$d2$f3$d3" "[2]($f1)($f2)" "($f1)($f2)" ;;
230 ' ') ;; 230 ' ') ;;
231 *) x=$f2$d2$f3$d3 231 *) x=$f2$d2$f3$d3
232 x=${x# } #was x=${x#' '} hush needs fixing for this to work 232 x=${x#' '}
233 x=${x% } #was x=${x%' '} 233 x=${x%' '}
234 split "$d0$f1$d1$f2$d2$f3$d3" "[3]($f1)($f2)($f3)" "($f1)($x)" 234 split "$d0$f1$d1$f2$d2$f3$d3" "[3]($f1)($f2)($f3)" "($f1)($x)"
235 ;; 235 ;;
236 esac 236 esac
diff --git a/shell/hush.c b/shell/hush.c
index c77700175..e3c6e2de9 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -357,6 +357,9 @@
357#else 357#else
358# define CLEAR_RANDOM_T(rnd) ((void)0) 358# define CLEAR_RANDOM_T(rnd) ((void)0)
359#endif 359#endif
360#ifndef O_CLOEXEC
361# define O_CLOEXEC 0
362#endif
360#ifndef F_DUPFD_CLOEXEC 363#ifndef F_DUPFD_CLOEXEC
361# define F_DUPFD_CLOEXEC F_DUPFD 364# define F_DUPFD_CLOEXEC F_DUPFD
362#endif 365#endif
@@ -439,21 +442,22 @@
439 442
440/* If you comment out one of these below, it will be #defined later 443/* If you comment out one of these below, it will be #defined later
441 * to perform debug printfs to stderr: */ 444 * to perform debug printfs to stderr: */
442#define debug_printf(...) do {} while (0) 445#define debug_printf(...) do {} while (0)
443/* Finer-grained debug switches */ 446/* Finer-grained debug switches */
444#define debug_printf_parse(...) do {} while (0) 447#define debug_printf_parse(...) do {} while (0)
445#define debug_print_tree(a, b) do {} while (0) 448#define debug_printf_heredoc(...) do {} while (0)
446#define debug_printf_exec(...) do {} while (0) 449#define debug_print_tree(a, b) do {} while (0)
447#define debug_printf_env(...) do {} while (0) 450#define debug_printf_exec(...) do {} while (0)
448#define debug_printf_jobs(...) do {} while (0) 451#define debug_printf_env(...) do {} while (0)
449#define debug_printf_expand(...) do {} while (0) 452#define debug_printf_jobs(...) do {} while (0)
450#define debug_printf_varexp(...) do {} while (0) 453#define debug_printf_expand(...) do {} while (0)
451#define debug_printf_glob(...) do {} while (0) 454#define debug_printf_varexp(...) do {} while (0)
452#define debug_printf_redir(...) do {} while (0) 455#define debug_printf_glob(...) do {} while (0)
453#define debug_printf_list(...) do {} while (0) 456#define debug_printf_redir(...) do {} while (0)
454#define debug_printf_subst(...) do {} while (0) 457#define debug_printf_list(...) do {} while (0)
455#define debug_printf_prompt(...) do {} while (0) 458#define debug_printf_subst(...) do {} while (0)
456#define debug_printf_clean(...) do {} while (0) 459#define debug_printf_prompt(...) do {} while (0)
460#define debug_printf_clean(...) do {} while (0)
457 461
458#define ERR_PTR ((void*)(long)1) 462#define ERR_PTR ((void*)(long)1)
459 463
@@ -534,6 +538,7 @@ typedef struct o_string {
534 * possibly empty one: word"", wo''rd etc. */ 538 * possibly empty one: word"", wo''rd etc. */
535 smallint has_quoted_part; 539 smallint has_quoted_part;
536 smallint has_empty_slot; 540 smallint has_empty_slot;
541 smallint ended_in_ifs;
537} o_string; 542} o_string;
538enum { 543enum {
539 EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */ 544 EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */
@@ -554,11 +559,27 @@ static const char *const assignment_flag[] = {
554}; 559};
555#endif 560#endif
556 561
562/* We almost can use standard FILE api, but we need an ability to move
563 * its fd when redirects coincide with it. No api exists for that
564 * (RFE for it at https://sourceware.org/bugzilla/show_bug.cgi?id=21902).
565 * HFILE is our internal alternative. Only supports reading.
566 * Since we now can, we incorporate linked list of all opened HFILEs
567 * into the struct (used to be a separate mini-list).
568 */
569typedef struct HFILE {
570 char *cur;
571 char *end;
572 struct HFILE *next_hfile;
573 int is_stdin;
574 int fd;
575 char buf[1024];
576} HFILE;
577
557typedef struct in_str { 578typedef struct in_str {
558 const char *p; 579 const char *p;
559 int peek_buf[2]; 580 int peek_buf[2];
560 int last_char; 581 int last_char;
561 FILE *file; 582 HFILE *file;
562} in_str; 583} in_str;
563 584
564/* The descrip member of this structure is only used to make 585/* The descrip member of this structure is only used to make
@@ -812,14 +833,6 @@ enum {
812 NUM_OPT_O 833 NUM_OPT_O
813}; 834};
814 835
815
816struct FILE_list {
817 struct FILE_list *next;
818 FILE *fp;
819 int fd;
820};
821
822
823/* "Globals" within this file */ 836/* "Globals" within this file */
824/* Sorted roughly by size (smaller offsets == smaller code) */ 837/* Sorted roughly by size (smaller offsets == smaller code) */
825struct globals { 838struct globals {
@@ -952,7 +965,7 @@ struct globals {
952 unsigned lineno; 965 unsigned lineno;
953 char *lineno_var; 966 char *lineno_var;
954#endif 967#endif
955 struct FILE_list *FILE_list; 968 HFILE *HFILE_list;
956 /* Which signals have non-DFL handler (even with no traps set)? 969 /* Which signals have non-DFL handler (even with no traps set)?
957 * Set at the start to: 970 * Set at the start to:
958 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) 971 * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS)
@@ -1218,6 +1231,10 @@ static const struct built_in_command bltins2[] = {
1218# define debug_printf_parse(...) (indent(), fdprintf(2, __VA_ARGS__)) 1231# define debug_printf_parse(...) (indent(), fdprintf(2, __VA_ARGS__))
1219#endif 1232#endif
1220 1233
1234#ifndef debug_printf_heredoc
1235# define debug_printf_heredoc(...) (indent(), fdprintf(2, __VA_ARGS__))
1236#endif
1237
1221#ifndef debug_printf_exec 1238#ifndef debug_printf_exec
1222#define debug_printf_exec(...) (indent(), fdprintf(2, __VA_ARGS__)) 1239#define debug_printf_exec(...) (indent(), fdprintf(2, __VA_ARGS__))
1223#endif 1240#endif
@@ -1557,83 +1574,115 @@ static int xdup_CLOEXEC_and_close(int fd, int avoid_fd)
1557} 1574}
1558 1575
1559 1576
1560/* Manipulating the list of open FILEs */ 1577/* Manipulating HFILEs */
1561static FILE *remember_FILE(FILE *fp) 1578static HFILE *hfopen(const char *name)
1562{ 1579{
1563 if (fp) { 1580 HFILE *fp;
1564 struct FILE_list *n = xmalloc(sizeof(*n)); 1581 int fd;
1565 n->next = G.FILE_list; 1582
1566 G.FILE_list = n; 1583 fd = STDIN_FILENO;
1567 n->fp = fp; 1584 if (name) {
1568 n->fd = fileno(fp); 1585 fd = open(name, O_RDONLY | O_CLOEXEC);
1569 close_on_exec_on(n->fd); 1586 if (fd < 0)
1587 return NULL;
1588 if (O_CLOEXEC == 0) /* ancient libc */
1589 close_on_exec_on(fd);
1570 } 1590 }
1591
1592 fp = xmalloc(sizeof(*fp));
1593 fp->is_stdin = (name == NULL);
1594 fp->fd = fd;
1595 fp->cur = fp->end = fp->buf;
1596 fp->next_hfile = G.HFILE_list;
1597 G.HFILE_list = fp;
1571 return fp; 1598 return fp;
1572} 1599}
1573static void fclose_and_forget(FILE *fp) 1600static void hfclose(HFILE *fp)
1574{ 1601{
1575 struct FILE_list **pp = &G.FILE_list; 1602 HFILE **pp = &G.HFILE_list;
1576 while (*pp) { 1603 while (*pp) {
1577 struct FILE_list *cur = *pp; 1604 HFILE *cur = *pp;
1578 if (cur->fp == fp) { 1605 if (cur == fp) {
1579 *pp = cur->next; 1606 *pp = cur->next_hfile;
1580 free(cur);
1581 break; 1607 break;
1582 } 1608 }
1583 pp = &cur->next; 1609 pp = &cur->next_hfile;
1584 } 1610 }
1585 fclose(fp); 1611 if (fp->fd >= 0)
1612 close(fp->fd);
1613 free(fp);
1586} 1614}
1587static int save_FILEs_on_redirect(int fd, int avoid_fd) 1615static int refill_HFILE_and_getc(HFILE *fp)
1588{ 1616{
1589 struct FILE_list *fl = G.FILE_list; 1617 int n;
1618
1619 if (fp->fd < 0) {
1620 /* Already saw EOF */
1621 return EOF;
1622 }
1623 /* Try to buffer more input */
1624 fp->cur = fp->buf;
1625 n = safe_read(fp->fd, fp->buf, sizeof(fp->buf));
1626 if (n < 0) {
1627 bb_perror_msg("read error");
1628 n = 0;
1629 }
1630 fp->end = fp->buf + n;
1631 if (n == 0) {
1632 /* EOF/error */
1633 close(fp->fd);
1634 fp->fd = -1;
1635 return EOF;
1636 }
1637 return (unsigned char)(*fp->cur++);
1638}
1639/* Inlined for common case of non-empty buffer.
1640 */
1641static ALWAYS_INLINE int hfgetc(HFILE *fp)
1642{
1643 if (fp->cur < fp->end)
1644 return (unsigned char)(*fp->cur++);
1645 /* Buffer empty */
1646 return refill_HFILE_and_getc(fp);
1647}
1648static int move_HFILEs_on_redirect(int fd, int avoid_fd)
1649{
1650 HFILE *fl = G.HFILE_list;
1590 while (fl) { 1651 while (fl) {
1591 if (fd == fl->fd) { 1652 if (fd == fl->fd) {
1592 /* We use it only on script files, they are all CLOEXEC */ 1653 /* We use it only on script files, they are all CLOEXEC */
1593 fl->fd = xdup_CLOEXEC_and_close(fd, avoid_fd); 1654 fl->fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
1594 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd); 1655 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd);
1595 return 1; 1656 return 1; /* "found and moved" */
1596 } 1657 }
1597 fl = fl->next; 1658 fl = fl->next_hfile;
1598 }
1599 return 0;
1600}
1601static void restore_redirected_FILEs(void)
1602{
1603 struct FILE_list *fl = G.FILE_list;
1604 while (fl) {
1605 int should_be = fileno(fl->fp);
1606 if (fl->fd != should_be) {
1607 debug_printf_redir("restoring script fd from %d to %d\n", fl->fd, should_be);
1608 xmove_fd(fl->fd, should_be);
1609 fl->fd = should_be;
1610 }
1611 fl = fl->next;
1612 } 1659 }
1660 return 0; /* "not in the list" */
1613} 1661}
1614#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU 1662#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
1615static void close_all_FILE_list(void) 1663static void close_all_HFILE_list(void)
1616{ 1664{
1617 struct FILE_list *fl = G.FILE_list; 1665 HFILE *fl = G.HFILE_list;
1618 while (fl) { 1666 while (fl) {
1619 /* fclose would also free FILE object. 1667 /* hfclose would also free HFILE object.
1620 * It is disastrous if we share memory with a vforked parent. 1668 * It is disastrous if we share memory with a vforked parent.
1621 * I'm not sure we never come here after vfork. 1669 * I'm not sure we never come here after vfork.
1622 * Therefore just close fd, nothing more. 1670 * Therefore just close fd, nothing more.
1623 */ 1671 */
1624 /*fclose(fl->fp); - unsafe */ 1672 /*hfclose(fl); - unsafe */
1625 close(fl->fd); 1673 if (fl->fd >= 0)
1626 fl = fl->next; 1674 close(fl->fd);
1675 fl = fl->next_hfile;
1627 } 1676 }
1628} 1677}
1629#endif 1678#endif
1630static int fd_in_FILEs(int fd) 1679static int fd_in_HFILEs(int fd)
1631{ 1680{
1632 struct FILE_list *fl = G.FILE_list; 1681 HFILE *fl = G.HFILE_list;
1633 while (fl) { 1682 while (fl) {
1634 if (fl->fd == fd) 1683 if (fl->fd == fd)
1635 return 1; 1684 return 1;
1636 fl = fl->next; 1685 fl = fl->next_hfile;
1637 } 1686 }
1638 return 0; 1687 return 0;
1639} 1688}
@@ -2333,6 +2382,7 @@ static void set_pwd_var(unsigned flag)
2333 set_local_var(xasprintf("PWD=%s", get_cwd(/*force:*/ 1)), flag); 2382 set_local_var(xasprintf("PWD=%s", get_cwd(/*force:*/ 1)), flag);
2334} 2383}
2335 2384
2385#if ENABLE_HUSH_UNSET || ENABLE_HUSH_GETOPTS
2336static int unset_local_var_len(const char *name, int name_len) 2386static int unset_local_var_len(const char *name, int name_len)
2337{ 2387{
2338 struct variable *cur; 2388 struct variable *cur;
@@ -2366,14 +2416,14 @@ static int unset_local_var_len(const char *name, int name_len)
2366 return EXIT_SUCCESS; 2416 return EXIT_SUCCESS;
2367} 2417}
2368 2418
2369#if ENABLE_HUSH_UNSET || ENABLE_HUSH_GETOPTS
2370static int unset_local_var(const char *name) 2419static int unset_local_var(const char *name)
2371{ 2420{
2372 return unset_local_var_len(name, strlen(name)); 2421 return unset_local_var_len(name, strlen(name));
2373} 2422}
2374#endif 2423#endif
2375 2424
2376#if BASH_HOSTNAME_VAR || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_READ || ENABLE_HUSH_GETOPTS 2425#if BASH_HOSTNAME_VAR || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_READ || ENABLE_HUSH_GETOPTS \
2426 || (ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT)
2377static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) 2427static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val)
2378{ 2428{
2379 char *var = xasprintf("%s=%s", name, val); 2429 char *var = xasprintf("%s=%s", name, val);
@@ -2422,35 +2472,33 @@ static void set_vars_and_save_old(char **strings)
2422 char *eq; 2472 char *eq;
2423 2473
2424 eq = strchr(*s, '='); 2474 eq = strchr(*s, '=');
2425 if (eq) { 2475 if (HUSH_DEBUG && !eq)
2426 var_pp = get_ptr_to_local_var(*s, eq - *s);
2427 if (var_pp) {
2428 var_p = *var_pp;
2429 if (var_p->flg_read_only) {
2430 char **p;
2431 bb_error_msg("%s: readonly variable", *s);
2432 /*
2433 * "VAR=V BLTIN" unsets VARs after BLTIN completes.
2434 * If VAR is readonly, leaving it in the list
2435 * after asssignment error (msg above)
2436 * causes doubled error message later, on unset.
2437 */
2438 debug_printf_env("removing/freeing '%s' element\n", *s);
2439 free(*s);
2440 p = s;
2441 do { *p = p[1]; p++; } while (*p);
2442 goto next;
2443 }
2444 /* below, set_local_var() with nest level will
2445 * "shadow" (remove) this variable from
2446 * global linked list.
2447 */
2448 }
2449 debug_printf_env("%s: env override '%s'/%u\n", __func__, *s, G.var_nest_level);
2450 set_local_var(*s, (G.var_nest_level << SETFLAG_VARLVL_SHIFT) | SETFLAG_EXPORT);
2451 } else if (HUSH_DEBUG) {
2452 bb_error_msg_and_die("BUG in varexp4"); 2476 bb_error_msg_and_die("BUG in varexp4");
2477 var_pp = get_ptr_to_local_var(*s, eq - *s);
2478 if (var_pp) {
2479 var_p = *var_pp;
2480 if (var_p->flg_read_only) {
2481 char **p;
2482 bb_error_msg("%s: readonly variable", *s);
2483 /*
2484 * "VAR=V BLTIN" unsets VARs after BLTIN completes.
2485 * If VAR is readonly, leaving it in the list
2486 * after asssignment error (msg above)
2487 * causes doubled error message later, on unset.
2488 */
2489 debug_printf_env("removing/freeing '%s' element\n", *s);
2490 free(*s);
2491 p = s;
2492 do { *p = p[1]; p++; } while (*p);
2493 goto next;
2494 }
2495 /* below, set_local_var() with nest level will
2496 * "shadow" (remove) this variable from
2497 * global linked list.
2498 */
2453 } 2499 }
2500 debug_printf_env("%s: env override '%s'/%u\n", __func__, *s, G.var_nest_level);
2501 set_local_var(*s, (G.var_nest_level << SETFLAG_VARLVL_SHIFT) | SETFLAG_EXPORT);
2454 s++; 2502 s++;
2455 next: ; 2503 next: ;
2456 } 2504 }
@@ -2469,7 +2517,7 @@ static void reinit_unicode_for_hush(void)
2469 */ 2517 */
2470 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV 2518 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2471 || ENABLE_UNICODE_USING_LOCALE 2519 || ENABLE_UNICODE_USING_LOCALE
2472 ) { 2520 ) {
2473 const char *s = get_local_var_value("LC_ALL"); 2521 const char *s = get_local_var_value("LC_ALL");
2474 if (!s) s = get_local_var_value("LC_CTYPE"); 2522 if (!s) s = get_local_var_value("LC_CTYPE");
2475 if (!s) s = get_local_var_value("LANG"); 2523 if (!s) s = get_local_var_value("LANG");
@@ -2575,7 +2623,7 @@ static int get_user_input(struct in_str *i)
2575 } 2623 }
2576 fflush_all(); 2624 fflush_all();
2577//FIXME: here ^C or SIGINT will have effect only after <Enter> 2625//FIXME: here ^C or SIGINT will have effect only after <Enter>
2578 r = fgetc(i->file); 2626 r = hfgetc(i->file);
2579 /* In !ENABLE_FEATURE_EDITING we don't use read_line_input, 2627 /* In !ENABLE_FEATURE_EDITING we don't use read_line_input,
2580 * no ^C masking happens during fgetc, no special code for ^C: 2628 * no ^C masking happens during fgetc, no special code for ^C:
2581 * it generates SIGINT as usual. 2629 * it generates SIGINT as usual.
@@ -2595,22 +2643,22 @@ static int fgetc_interactive(struct in_str *i)
2595{ 2643{
2596 int ch; 2644 int ch;
2597 /* If it's interactive stdin, get new line. */ 2645 /* If it's interactive stdin, get new line. */
2598 if (G_interactive_fd && i->file == stdin) { 2646 if (G_interactive_fd && i->file->is_stdin) {
2599 /* Returns first char (or EOF), the rest is in i->p[] */ 2647 /* Returns first char (or EOF), the rest is in i->p[] */
2600 ch = get_user_input(i); 2648 ch = get_user_input(i);
2601 G.promptmode = 1; /* PS2 */ 2649 G.promptmode = 1; /* PS2 */
2602 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode); 2650 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
2603 } else { 2651 } else {
2604 /* Not stdin: script file, sourced file, etc */ 2652 /* Not stdin: script file, sourced file, etc */
2605 do ch = fgetc(i->file); while (ch == '\0'); 2653 do ch = hfgetc(i->file); while (ch == '\0');
2606 } 2654 }
2607 return ch; 2655 return ch;
2608} 2656}
2609#else 2657#else
2610static inline int fgetc_interactive(struct in_str *i) 2658static ALWAYS_INLINE int fgetc_interactive(struct in_str *i)
2611{ 2659{
2612 int ch; 2660 int ch;
2613 do ch = fgetc(i->file); while (ch == '\0'); 2661 do ch = hfgetc(i->file); while (ch == '\0');
2614 return ch; 2662 return ch;
2615} 2663}
2616#endif /* INTERACTIVE */ 2664#endif /* INTERACTIVE */
@@ -2725,7 +2773,7 @@ static int i_peek2(struct in_str *i)
2725 ch = i->peek_buf[1]; 2773 ch = i->peek_buf[1];
2726 if (ch == 0) { 2774 if (ch == 0) {
2727 /* We did not read it yet, get it now */ 2775 /* We did not read it yet, get it now */
2728 do ch = fgetc(i->file); while (ch == '\0'); 2776 do ch = hfgetc(i->file); while (ch == '\0');
2729 i->peek_buf[1] = ch; 2777 i->peek_buf[1] = ch;
2730 } 2778 }
2731 2779
@@ -2769,10 +2817,10 @@ static int i_peek_and_eat_bkslash_nl(struct in_str *input)
2769 } 2817 }
2770} 2818}
2771 2819
2772static void setup_file_in_str(struct in_str *i, FILE *f) 2820static void setup_file_in_str(struct in_str *i, HFILE *fp)
2773{ 2821{
2774 memset(i, 0, sizeof(*i)); 2822 memset(i, 0, sizeof(*i));
2775 i->file = f; 2823 i->file = fp;
2776 /* i->p = NULL; */ 2824 /* i->p = NULL; */
2777} 2825}
2778 2826
@@ -2797,13 +2845,13 @@ static void o_reset_to_empty_unquoted(o_string *o)
2797 o->data[0] = '\0'; 2845 o->data[0] = '\0';
2798} 2846}
2799 2847
2800static void o_free(o_string *o) 2848static void o_free_and_set_NULL(o_string *o)
2801{ 2849{
2802 free(o->data); 2850 free(o->data);
2803 memset(o, 0, sizeof(*o)); 2851 memset(o, 0, sizeof(*o));
2804} 2852}
2805 2853
2806static ALWAYS_INLINE void o_free_unsafe(o_string *o) 2854static ALWAYS_INLINE void o_free(o_string *o)
2807{ 2855{
2808 free(o->data); 2856 free(o->data);
2809} 2857}
@@ -3342,7 +3390,6 @@ static char **o_finalize_list(o_string *o, int n)
3342 char **list; 3390 char **list;
3343 int string_start; 3391 int string_start;
3344 3392
3345 n = o_save_ptr(o, n); /* force growth for list[n] if necessary */
3346 if (DEBUG_EXPAND) 3393 if (DEBUG_EXPAND)
3347 debug_print_list("finalized", o, n); 3394 debug_print_list("finalized", o, n);
3348 debug_printf_expand("finalized n:%d\n", n); 3395 debug_printf_expand("finalized n:%d\n", n);
@@ -3530,6 +3577,8 @@ static void debug_print_tree(struct pipe *pi, int lvl)
3530 fdprintf(2, " '%s'", *argv); 3577 fdprintf(2, " '%s'", *argv);
3531 argv++; 3578 argv++;
3532 } 3579 }
3580 if (command->redirects)
3581 fdprintf(2, " {redir}");
3533 fdprintf(2, "\n"); 3582 fdprintf(2, "\n");
3534 prn++; 3583 prn++;
3535 } 3584 }
@@ -3853,7 +3902,7 @@ static const struct reserved_combo* reserved_word(struct parse_context *ctx)
3853 int len = old->as_string.length; 3902 int len = old->as_string.length;
3854 /* Concatenate halves */ 3903 /* Concatenate halves */
3855 o_addstr(&old->as_string, ctx->as_string.data); 3904 o_addstr(&old->as_string, ctx->as_string.data);
3856 o_free_unsafe(&ctx->as_string); 3905 o_free(&ctx->as_string);
3857 /* Find where leading keyword starts in first half */ 3906 /* Find where leading keyword starts in first half */
3858 str = old->as_string.data + len; 3907 str = old->as_string.data + len;
3859 if (str > old->as_string.data) 3908 if (str > old->as_string.data)
@@ -4227,6 +4276,14 @@ static char *fetch_till_str(o_string *as_string,
4227 int prev = 0; /* not \ */ 4276 int prev = 0; /* not \ */
4228 int ch; 4277 int ch;
4229 4278
4279 /* Starting with "" is necessary for this case:
4280 * cat <<EOF
4281 *
4282 * xxx
4283 * EOF
4284 */
4285 heredoc.data = xzalloc(1); /* start as "", not as NULL */
4286
4230 goto jump_in; 4287 goto jump_in;
4231 4288
4232 while (1) { 4289 while (1) {
@@ -4236,9 +4293,10 @@ static char *fetch_till_str(o_string *as_string,
4236 if (ch == '\n' || ch == EOF) { 4293 if (ch == '\n' || ch == EOF) {
4237 check_heredoc_end: 4294 check_heredoc_end:
4238 if ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\') { 4295 if ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\') {
4296 /* End-of-line, and not a line continuation */
4239 if (strcmp(heredoc.data + past_EOL, word) == 0) { 4297 if (strcmp(heredoc.data + past_EOL, word) == 0) {
4240 heredoc.data[past_EOL] = '\0'; 4298 heredoc.data[past_EOL] = '\0';
4241 debug_printf_parse("parsed heredoc '%s'\n", heredoc.data); 4299 debug_printf_heredoc("parsed '%s' heredoc '%s'\n", word, heredoc.data);
4242 return heredoc.data; 4300 return heredoc.data;
4243 } 4301 }
4244 if (ch == '\n') { 4302 if (ch == '\n') {
@@ -4261,17 +4319,32 @@ static char *fetch_till_str(o_string *as_string,
4261 if (ch == '\n') 4319 if (ch == '\n')
4262 goto check_heredoc_end; 4320 goto check_heredoc_end;
4263 } 4321 }
4322 } else {
4323 /* Backslash-line continuation in an unquoted
4324 * heredoc. This does not need special handling
4325 * for heredoc body (unquoted heredocs are
4326 * expanded on "execution" and that would take
4327 * care of this case too), but not the case
4328 * of line continuation *in terminator*:
4329 * cat <<EOF
4330 * Ok1
4331 * EO\
4332 * F
4333 */
4334 heredoc.data[--heredoc.length] = '\0';
4335 prev = 0; /* not '\' */
4336 continue;
4264 } 4337 }
4265 } 4338 }
4266 if (ch == EOF) { 4339 if (ch == EOF) {
4267 o_free_unsafe(&heredoc); 4340 o_free(&heredoc);
4268 return NULL; 4341 return NULL; /* error */
4269 } 4342 }
4270 o_addchr(&heredoc, ch); 4343 o_addchr(&heredoc, ch);
4271 nommu_addchr(as_string, ch); 4344 nommu_addchr(as_string, ch);
4272 if (prev == '\\' && ch == '\\') 4345 if (prev == '\\' && ch == '\\')
4273 /* Correctly handle foo\\<eol> (not a line cont.) */ 4346 /* Correctly handle foo\\<eol> (not a line cont.) */
4274 prev = 0; /* not \ */ 4347 prev = 0; /* not '\' */
4275 else 4348 else
4276 prev = ch; 4349 prev = ch;
4277 } 4350 }
@@ -4280,21 +4353,24 @@ static char *fetch_till_str(o_string *as_string,
4280/* Look at entire parse tree for not-yet-loaded REDIRECT_HEREDOCs 4353/* Look at entire parse tree for not-yet-loaded REDIRECT_HEREDOCs
4281 * and load them all. There should be exactly heredoc_cnt of them. 4354 * and load them all. There should be exactly heredoc_cnt of them.
4282 */ 4355 */
4283static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_str *input) 4356#if BB_MMU
4357#define fetch_heredocs(as_string, pi, heredoc_cnt, input) \
4358 fetch_heredocs(pi, heredoc_cnt, input)
4359#endif
4360static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt, struct in_str *input)
4284{ 4361{
4285 struct pipe *pi = ctx->list_head;
4286
4287 while (pi && heredoc_cnt) { 4362 while (pi && heredoc_cnt) {
4288 int i; 4363 int i;
4289 struct command *cmd = pi->cmds; 4364 struct command *cmd = pi->cmds;
4290 4365
4291 debug_printf_parse("fetch_heredocs: num_cmds:%d cmd argv0:'%s'\n", 4366 debug_printf_heredoc("fetch_heredocs: num_cmds:%d cmd argv0:'%s'\n",
4292 pi->num_cmds, 4367 pi->num_cmds,
4293 cmd->argv ? cmd->argv[0] : "NONE"); 4368 cmd->argv ? cmd->argv[0] : "NONE"
4369 );
4294 for (i = 0; i < pi->num_cmds; i++) { 4370 for (i = 0; i < pi->num_cmds; i++) {
4295 struct redir_struct *redir = cmd->redirects; 4371 struct redir_struct *redir = cmd->redirects;
4296 4372
4297 debug_printf_parse("fetch_heredocs: %d cmd argv0:'%s'\n", 4373 debug_printf_heredoc("fetch_heredocs: %d cmd argv0:'%s'\n",
4298 i, cmd->argv ? cmd->argv[0] : "NONE"); 4374 i, cmd->argv ? cmd->argv[0] : "NONE");
4299 while (redir) { 4375 while (redir) {
4300 if (redir->rd_type == REDIRECT_HEREDOC) { 4376 if (redir->rd_type == REDIRECT_HEREDOC) {
@@ -4302,11 +4378,11 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_
4302 4378
4303 redir->rd_type = REDIRECT_HEREDOC2; 4379 redir->rd_type = REDIRECT_HEREDOC2;
4304 /* redir->rd_dup is (ab)used to indicate <<- */ 4380 /* redir->rd_dup is (ab)used to indicate <<- */
4305 p = fetch_till_str(&ctx->as_string, input, 4381 p = fetch_till_str(as_string, input,
4306 redir->rd_filename, redir->rd_dup); 4382 redir->rd_filename, redir->rd_dup);
4307 if (!p) { 4383 if (!p) {
4308 syntax_error("unexpected EOF in here document"); 4384 syntax_error("unexpected EOF in here document");
4309 return 1; 4385 return -1;
4310 } 4386 }
4311 free(redir->rd_filename); 4387 free(redir->rd_filename);
4312 redir->rd_filename = p; 4388 redir->rd_filename = p;
@@ -4314,31 +4390,36 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_
4314 } 4390 }
4315 redir = redir->next; 4391 redir = redir->next;
4316 } 4392 }
4393 if (cmd->group) {
4394 //bb_error_msg("%s:%u heredoc_cnt:%d", __func__, __LINE__, heredoc_cnt);
4395 heredoc_cnt = fetch_heredocs(as_string, cmd->group, heredoc_cnt, input);
4396 //bb_error_msg("%s:%u heredoc_cnt:%d", __func__, __LINE__, heredoc_cnt);
4397 if (heredoc_cnt < 0)
4398 return heredoc_cnt; /* error */
4399 }
4317 cmd++; 4400 cmd++;
4318 } 4401 }
4319 pi = pi->next; 4402 pi = pi->next;
4320 } 4403 }
4321#if 0 4404 return heredoc_cnt;
4322 /* Should be 0. If it isn't, it's a parse error */
4323 if (heredoc_cnt)
4324 bb_error_msg_and_die("heredoc BUG 2");
4325#endif
4326 return 0;
4327} 4405}
4328 4406
4329 4407
4330static int run_list(struct pipe *pi); 4408static int run_list(struct pipe *pi);
4331#if BB_MMU 4409#if BB_MMU
4332#define parse_stream(pstring, input, end_trigger) \ 4410#define parse_stream(pstring, heredoc_cnt_ptr, input, end_trigger) \
4333 parse_stream(input, end_trigger) 4411 parse_stream(heredoc_cnt_ptr, input, end_trigger)
4334#endif 4412#endif
4335static struct pipe *parse_stream(char **pstring, 4413static struct pipe *parse_stream(char **pstring,
4414 int *heredoc_cnt_ptr,
4336 struct in_str *input, 4415 struct in_str *input,
4337 int end_trigger); 4416 int end_trigger);
4338 4417
4339 4418/* Returns number of heredocs not yet consumed,
4419 * or -1 on error.
4420 */
4340static int parse_group(struct parse_context *ctx, 4421static int parse_group(struct parse_context *ctx,
4341 struct in_str *input, int ch) 4422 struct in_str *input, int ch)
4342{ 4423{
4343 /* ctx->word contains characters seen prior to ( or {. 4424 /* ctx->word contains characters seen prior to ( or {.
4344 * Typically it's empty, but for function defs, 4425 * Typically it's empty, but for function defs,
@@ -4349,6 +4430,7 @@ static int parse_group(struct parse_context *ctx,
4349 char *as_string = NULL; 4430 char *as_string = NULL;
4350#endif 4431#endif
4351 struct pipe *pipe_list; 4432 struct pipe *pipe_list;
4433 int heredoc_cnt = 0;
4352 int endch; 4434 int endch;
4353 struct command *command = ctx->command; 4435 struct command *command = ctx->command;
4354 4436
@@ -4357,12 +4439,12 @@ static int parse_group(struct parse_context *ctx,
4357 if (ch == '(' && !ctx->word.has_quoted_part) { 4439 if (ch == '(' && !ctx->word.has_quoted_part) {
4358 if (ctx->word.length) 4440 if (ctx->word.length)
4359 if (done_word(ctx)) 4441 if (done_word(ctx))
4360 return 1; 4442 return -1;
4361 if (!command->argv) 4443 if (!command->argv)
4362 goto skip; /* (... */ 4444 goto skip; /* (... */
4363 if (command->argv[1]) { /* word word ... (... */ 4445 if (command->argv[1]) { /* word word ... (... */
4364 syntax_error_unexpected_ch('('); 4446 syntax_error_unexpected_ch('(');
4365 return 1; 4447 return -1;
4366 } 4448 }
4367 /* it is "word(..." or "word (..." */ 4449 /* it is "word(..." or "word (..." */
4368 do 4450 do
@@ -4370,7 +4452,7 @@ static int parse_group(struct parse_context *ctx,
4370 while (ch == ' ' || ch == '\t'); 4452 while (ch == ' ' || ch == '\t');
4371 if (ch != ')') { 4453 if (ch != ')') {
4372 syntax_error_unexpected_ch(ch); 4454 syntax_error_unexpected_ch(ch);
4373 return 1; 4455 return -1;
4374 } 4456 }
4375 nommu_addchr(&ctx->as_string, ch); 4457 nommu_addchr(&ctx->as_string, ch);
4376 do 4458 do
@@ -4378,7 +4460,7 @@ static int parse_group(struct parse_context *ctx,
4378 while (ch == ' ' || ch == '\t' || ch == '\n'); 4460 while (ch == ' ' || ch == '\t' || ch == '\n');
4379 if (ch != '{' && ch != '(') { 4461 if (ch != '{' && ch != '(') {
4380 syntax_error_unexpected_ch(ch); 4462 syntax_error_unexpected_ch(ch);
4381 return 1; 4463 return -1;
4382 } 4464 }
4383 nommu_addchr(&ctx->as_string, ch); 4465 nommu_addchr(&ctx->as_string, ch);
4384 command->cmd_type = CMD_FUNCDEF; 4466 command->cmd_type = CMD_FUNCDEF;
@@ -4392,9 +4474,9 @@ static int parse_group(struct parse_context *ctx,
4392 || ctx->word.has_quoted_part /* ""{... */ 4474 || ctx->word.has_quoted_part /* ""{... */
4393 ) { 4475 ) {
4394 syntax_error(NULL); 4476 syntax_error(NULL);
4395 debug_printf_parse("parse_group return 1: " 4477 debug_printf_parse("parse_group return -1: "
4396 "syntax error, groups and arglists don't mix\n"); 4478 "syntax error, groups and arglists don't mix\n");
4397 return 1; 4479 return -1;
4398 } 4480 }
4399#endif 4481#endif
4400 4482
@@ -4412,7 +4494,7 @@ static int parse_group(struct parse_context *ctx,
4412 && ch != '(' /* but "{(..." is allowed (without whitespace) */ 4494 && ch != '(' /* but "{(..." is allowed (without whitespace) */
4413 ) { 4495 ) {
4414 syntax_error_unexpected_ch(ch); 4496 syntax_error_unexpected_ch(ch);
4415 return 1; 4497 return -1;
4416 } 4498 }
4417 if (ch != '(') { 4499 if (ch != '(') {
4418 ch = i_getch(input); 4500 ch = i_getch(input);
@@ -4420,7 +4502,9 @@ static int parse_group(struct parse_context *ctx,
4420 } 4502 }
4421 } 4503 }
4422 4504
4423 pipe_list = parse_stream(&as_string, input, endch); 4505 debug_printf_heredoc("calling parse_stream, heredoc_cnt:%d\n", heredoc_cnt);
4506 pipe_list = parse_stream(&as_string, &heredoc_cnt, input, endch);
4507 debug_printf_heredoc("parse_stream returned: heredoc_cnt:%d\n", heredoc_cnt);
4424#if !BB_MMU 4508#if !BB_MMU
4425 if (as_string) 4509 if (as_string)
4426 o_addstr(&ctx->as_string, as_string); 4510 o_addstr(&ctx->as_string, as_string);
@@ -4431,9 +4515,9 @@ static int parse_group(struct parse_context *ctx,
4431 /* parse_stream already emitted error msg */ 4515 /* parse_stream already emitted error msg */
4432 if (!BB_MMU) 4516 if (!BB_MMU)
4433 free(as_string); 4517 free(as_string);
4434 debug_printf_parse("parse_group return 1: " 4518 debug_printf_parse("parse_group return -1: "
4435 "parse_stream returned %p\n", pipe_list); 4519 "parse_stream returned %p\n", pipe_list);
4436 return 1; 4520 return -1;
4437 } 4521 }
4438#if !BB_MMU 4522#if !BB_MMU
4439 as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */ 4523 as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */
@@ -4464,15 +4548,14 @@ static int parse_group(struct parse_context *ctx,
4464 4548
4465 command->group = pipe_list; 4549 command->group = pipe_list;
4466 4550
4467 debug_printf_parse("parse_group return 0\n"); 4551 debug_printf_parse("parse_group return %d\n", heredoc_cnt);
4468 return 0; 4552 return heredoc_cnt;
4469 /* command remains "open", available for possible redirects */ 4553 /* command remains "open", available for possible redirects */
4470#undef as_string 4554#undef as_string
4471} 4555}
4472 4556
4473#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS 4557#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS
4474/* Subroutines for copying $(...) and `...` things */ 4558/* Subroutines for copying $(...) and `...` things */
4475static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
4476/* '...' */ 4559/* '...' */
4477static int add_till_single_quote(o_string *dest, struct in_str *input) 4560static int add_till_single_quote(o_string *dest, struct in_str *input)
4478{ 4561{
@@ -4487,7 +4570,21 @@ static int add_till_single_quote(o_string *dest, struct in_str *input)
4487 o_addchr(dest, ch); 4570 o_addchr(dest, ch);
4488 } 4571 }
4489} 4572}
4573static int add_till_single_quote_dquoted(o_string *dest, struct in_str *input)
4574{
4575 while (1) {
4576 int ch = i_getch(input);
4577 if (ch == EOF) {
4578 syntax_error_unterm_ch('\'');
4579 return 0;
4580 }
4581 if (ch == '\'')
4582 return 1;
4583 o_addqchr(dest, ch);
4584 }
4585}
4490/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ 4586/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */
4587static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
4491static int add_till_double_quote(o_string *dest, struct in_str *input) 4588static int add_till_double_quote(o_string *dest, struct in_str *input)
4492{ 4589{
4493 while (1) { 4590 while (1) {
@@ -4577,7 +4674,9 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
4577# endif 4674# endif
4578 end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); 4675 end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1);
4579 4676
4677#if ENABLE_HUSH_INTERACTIVE
4580 G.promptmode = 1; /* PS2 */ 4678 G.promptmode = 1; /* PS2 */
4679#endif
4581 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode); 4680 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
4582 4681
4583 while (1) { 4682 while (1) {
@@ -4885,34 +4984,15 @@ static int parse_dollar(o_string *as_string,
4885} 4984}
4886 4985
4887#if BB_MMU 4986#if BB_MMU
4888# if BASH_PATTERN_SUBST 4987#define encode_string(as_string, dest, input, dquote_end) \
4889#define encode_string(as_string, dest, input, dquote_end, process_bkslash) \
4890 encode_string(dest, input, dquote_end, process_bkslash)
4891# else
4892/* only ${var/pattern/repl} (its pattern part) needs additional mode */
4893#define encode_string(as_string, dest, input, dquote_end, process_bkslash) \
4894 encode_string(dest, input, dquote_end) 4988 encode_string(dest, input, dquote_end)
4895# endif
4896#define as_string NULL 4989#define as_string NULL
4897
4898#else /* !MMU */
4899
4900# if BASH_PATTERN_SUBST
4901/* all parameters are needed, no macro tricks */
4902# else
4903#define encode_string(as_string, dest, input, dquote_end, process_bkslash) \
4904 encode_string(as_string, dest, input, dquote_end)
4905# endif
4906#endif 4990#endif
4907static int encode_string(o_string *as_string, 4991static int encode_string(o_string *as_string,
4908 o_string *dest, 4992 o_string *dest,
4909 struct in_str *input, 4993 struct in_str *input,
4910 int dquote_end, 4994 int dquote_end)
4911 int process_bkslash)
4912{ 4995{
4913#if !BASH_PATTERN_SUBST
4914 const int process_bkslash = 1;
4915#endif
4916 int ch; 4996 int ch;
4917 int next; 4997 int next;
4918 4998
@@ -4935,7 +5015,7 @@ static int encode_string(o_string *as_string,
4935 } 5015 }
4936 debug_printf_parse("\" ch=%c (%d) escape=%d\n", 5016 debug_printf_parse("\" ch=%c (%d) escape=%d\n",
4937 ch, ch, !!(dest->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); 5017 ch, ch, !!(dest->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
4938 if (process_bkslash && ch == '\\') { 5018 if (ch == '\\') {
4939 if (next == EOF) { 5019 if (next == EOF) {
4940 /* Testcase: in interactive shell a file with 5020 /* Testcase: in interactive shell a file with
4941 * echo "unterminated string\<eof> 5021 * echo "unterminated string\<eof>
@@ -4995,6 +5075,7 @@ static int encode_string(o_string *as_string,
4995 * or return ERR_PTR. 5075 * or return ERR_PTR.
4996 */ 5076 */
4997static struct pipe *parse_stream(char **pstring, 5077static struct pipe *parse_stream(char **pstring,
5078 int *heredoc_cnt_ptr,
4998 struct in_str *input, 5079 struct in_str *input,
4999 int end_trigger) 5080 int end_trigger)
5000{ 5081{
@@ -5013,8 +5094,7 @@ static struct pipe *parse_stream(char **pstring,
5013 /* If very first arg is "" or '', ctx.word.data may end up NULL. 5094 /* If very first arg is "" or '', ctx.word.data may end up NULL.
5014 * Preventing this: 5095 * Preventing this:
5015 */ 5096 */
5016 o_addchr(&ctx.word, '\0'); 5097 ctx.word.data = xzalloc(1); /* start as "", not as NULL */
5017 ctx.word.length = 0;
5018 5098
5019 /* We used to separate words on $IFS here. This was wrong. 5099 /* We used to separate words on $IFS here. This was wrong.
5020 * $IFS is used only for word splitting when $var is expanded, 5100 * $IFS is used only for word splitting when $var is expanded,
@@ -5052,7 +5132,7 @@ static struct pipe *parse_stream(char **pstring,
5052 if (done_word(&ctx)) { 5132 if (done_word(&ctx)) {
5053 goto parse_error; 5133 goto parse_error;
5054 } 5134 }
5055 o_free(&ctx.word); 5135 o_free_and_set_NULL(&ctx.word);
5056 done_pipe(&ctx, PIPE_SEQ); 5136 done_pipe(&ctx, PIPE_SEQ);
5057 pi = ctx.list_head; 5137 pi = ctx.list_head;
5058 /* If we got nothing... */ 5138 /* If we got nothing... */
@@ -5069,9 +5149,13 @@ static struct pipe *parse_stream(char **pstring,
5069 if (pstring) 5149 if (pstring)
5070 *pstring = ctx.as_string.data; 5150 *pstring = ctx.as_string.data;
5071 else 5151 else
5072 o_free_unsafe(&ctx.as_string); 5152 o_free(&ctx.as_string);
5073#endif 5153#endif
5154 // heredoc_cnt must be 0 here anyway
5155 //if (heredoc_cnt_ptr)
5156 // *heredoc_cnt_ptr = heredoc_cnt;
5074 debug_leave(); 5157 debug_leave();
5158 debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
5075 debug_printf_parse("parse_stream return %p\n", pi); 5159 debug_printf_parse("parse_stream return %p\n", pi);
5076 return pi; 5160 return pi;
5077 } 5161 }
@@ -5198,7 +5282,9 @@ static struct pipe *parse_stream(char **pstring,
5198 * "case ... in <newline> word) ..." 5282 * "case ... in <newline> word) ..."
5199 */ 5283 */
5200 if (IS_NULL_CMD(ctx.command) 5284 if (IS_NULL_CMD(ctx.command)
5201 && ctx.word.length == 0 && !ctx.word.has_quoted_part 5285 && ctx.word.length == 0
5286 && !ctx.word.has_quoted_part
5287 && heredoc_cnt == 0
5202 ) { 5288 ) {
5203 /* This newline can be ignored. But... 5289 /* This newline can be ignored. But...
5204 * Without check #1, interactive shell 5290 * Without check #1, interactive shell
@@ -5226,12 +5312,11 @@ static struct pipe *parse_stream(char **pstring,
5226 } 5312 }
5227 /* Treat newline as a command separator. */ 5313 /* Treat newline as a command separator. */
5228 done_pipe(&ctx, PIPE_SEQ); 5314 done_pipe(&ctx, PIPE_SEQ);
5229 debug_printf_parse("heredoc_cnt:%d\n", heredoc_cnt); 5315 debug_printf_heredoc("heredoc_cnt:%d\n", heredoc_cnt);
5230 if (heredoc_cnt) { 5316 if (heredoc_cnt) {
5231 if (fetch_heredocs(heredoc_cnt, &ctx, input)) { 5317 heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input);
5318 if (heredoc_cnt != 0)
5232 goto parse_error; 5319 goto parse_error;
5233 }
5234 heredoc_cnt = 0;
5235 } 5320 }
5236 ctx.is_assignment = MAYBE_ASSIGNMENT; 5321 ctx.is_assignment = MAYBE_ASSIGNMENT;
5237 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); 5322 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
@@ -5280,19 +5365,6 @@ static struct pipe *parse_stream(char **pstring,
5280 ) 5365 )
5281#endif 5366#endif
5282 ) { 5367 ) {
5283 if (heredoc_cnt) {
5284 /* This is technically valid:
5285 * { cat <<HERE; }; echo Ok
5286 * heredoc
5287 * heredoc
5288 * HERE
5289 * but we don't support this.
5290 * We require heredoc to be in enclosing {}/(),
5291 * if any.
5292 */
5293 syntax_error_unterm_str("here document");
5294 goto parse_error;
5295 }
5296 if (done_word(&ctx)) { 5368 if (done_word(&ctx)) {
5297 goto parse_error; 5369 goto parse_error;
5298 } 5370 }
@@ -5303,13 +5375,13 @@ static struct pipe *parse_stream(char **pstring,
5303 if (!HAS_KEYWORDS 5375 if (!HAS_KEYWORDS
5304 IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) 5376 IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0))
5305 ) { 5377 ) {
5306 o_free(&ctx.word); 5378 o_free_and_set_NULL(&ctx.word);
5307#if !BB_MMU 5379#if !BB_MMU
5308 debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data); 5380 debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data);
5309 if (pstring) 5381 if (pstring)
5310 *pstring = ctx.as_string.data; 5382 *pstring = ctx.as_string.data;
5311 else 5383 else
5312 o_free_unsafe(&ctx.as_string); 5384 o_free(&ctx.as_string);
5313#endif 5385#endif
5314 if (ch != ';' && IS_NULL_PIPE(ctx.list_head)) { 5386 if (ch != ';' && IS_NULL_PIPE(ctx.list_head)) {
5315 /* Example: bare "{ }", "()" */ 5387 /* Example: bare "{ }", "()" */
@@ -5317,6 +5389,9 @@ static struct pipe *parse_stream(char **pstring,
5317 syntax_error_unexpected_ch(ch); 5389 syntax_error_unexpected_ch(ch);
5318 goto parse_error2; 5390 goto parse_error2;
5319 } 5391 }
5392 if (heredoc_cnt_ptr)
5393 *heredoc_cnt_ptr = heredoc_cnt;
5394 debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
5320 debug_printf_parse("parse_stream return %p: " 5395 debug_printf_parse("parse_stream return %p: "
5321 "end_trigger char found\n", 5396 "end_trigger char found\n",
5322 ctx.list_head); 5397 ctx.list_head);
@@ -5360,7 +5435,7 @@ static struct pipe *parse_stream(char **pstring,
5360 if (next == '<') { 5435 if (next == '<') {
5361 redir_style = REDIRECT_HEREDOC; 5436 redir_style = REDIRECT_HEREDOC;
5362 heredoc_cnt++; 5437 heredoc_cnt++;
5363 debug_printf_parse("++heredoc_cnt=%d\n", heredoc_cnt); 5438 debug_printf_heredoc("++heredoc_cnt=%d\n", heredoc_cnt);
5364 ch = i_getch(input); 5439 ch = i_getch(input);
5365 nommu_addchr(&ctx.as_string, ch); 5440 nommu_addchr(&ctx.as_string, ch);
5366 } else if (next == '>') { 5441 } else if (next == '>') {
@@ -5444,7 +5519,7 @@ static struct pipe *parse_stream(char **pstring,
5444 } 5519 }
5445 if (ctx.is_assignment == NOT_ASSIGNMENT) 5520 if (ctx.is_assignment == NOT_ASSIGNMENT)
5446 ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; 5521 ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS;
5447 if (!encode_string(&ctx.as_string, &ctx.word, input, '"', /*process_bkslash:*/ 1)) 5522 if (!encode_string(&ctx.as_string, &ctx.word, input, '"'))
5448 goto parse_error; 5523 goto parse_error;
5449 ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; 5524 ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS;
5450 continue; /* get next char */ 5525 continue; /* get next char */
@@ -5538,16 +5613,22 @@ static struct pipe *parse_stream(char **pstring,
5538 continue; /* get next char */ 5613 continue; /* get next char */
5539 } 5614 }
5540#endif 5615#endif
5541 case '{': 5616 /* fall through */
5542 if (parse_group(&ctx, input, ch) != 0) { 5617 case '{': {
5618 int n = parse_group(&ctx, input, ch);
5619 if (n < 0) {
5543 goto parse_error; 5620 goto parse_error;
5544 } 5621 }
5622 debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n);
5623 heredoc_cnt += n;
5545 goto new_cmd; 5624 goto new_cmd;
5625 }
5546 case ')': 5626 case ')':
5547#if ENABLE_HUSH_CASE 5627#if ENABLE_HUSH_CASE
5548 if (ctx.ctx_res_w == RES_MATCH) 5628 if (ctx.ctx_res_w == RES_MATCH)
5549 goto case_semi; 5629 goto case_semi;
5550#endif 5630#endif
5631
5551 case '}': 5632 case '}':
5552 /* proper use of this character is caught by end_trigger: 5633 /* proper use of this character is caught by end_trigger:
5553 * if we see {, we call parse_group(..., end_trigger='}') 5634 * if we see {, we call parse_group(..., end_trigger='}')
@@ -5587,7 +5668,7 @@ static struct pipe *parse_stream(char **pstring,
5587 free_pipe_list(pctx->list_head); 5668 free_pipe_list(pctx->list_head);
5588 debug_printf_clean("freed list %p\n", pctx->list_head); 5669 debug_printf_clean("freed list %p\n", pctx->list_head);
5589#if !BB_MMU 5670#if !BB_MMU
5590 o_free_unsafe(&pctx->as_string); 5671 o_free(&pctx->as_string);
5591#endif 5672#endif
5592 IF_HAS_KEYWORDS(p2 = pctx->stack;) 5673 IF_HAS_KEYWORDS(p2 = pctx->stack;)
5593 if (pctx != &ctx) { 5674 if (pctx != &ctx) {
@@ -5618,6 +5699,7 @@ static char *expand_string_to_string(const char *str, int EXP_flags, int do_unba
5618#if ENABLE_HUSH_TICK 5699#if ENABLE_HUSH_TICK
5619static int process_command_subs(o_string *dest, const char *s); 5700static int process_command_subs(o_string *dest, const char *s);
5620#endif 5701#endif
5702static int expand_vars_to_list(o_string *output, int n, char *arg);
5621 5703
5622/* expand_strvec_to_strvec() takes a list of strings, expands 5704/* expand_strvec_to_strvec() takes a list of strings, expands
5623 * all variable references within and returns a pointer to 5705 * all variable references within and returns a pointer to
@@ -5662,10 +5744,10 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len
5662/* Store given string, finalizing the word and starting new one whenever 5744/* Store given string, finalizing the word and starting new one whenever
5663 * we encounter IFS char(s). This is used for expanding variable values. 5745 * we encounter IFS char(s). This is used for expanding variable values.
5664 * End-of-string does NOT finalize word: think about 'echo -$VAR-'. 5746 * End-of-string does NOT finalize word: think about 'echo -$VAR-'.
5665 * Return in *ended_with_ifs: 5747 * Return in output->ended_in_ifs:
5666 * 1 - ended with IFS char, else 0 (this includes case of empty str). 5748 * 1 - ended with IFS char, else 0 (this includes case of empty str).
5667 */ 5749 */
5668static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const char *str) 5750static int expand_on_ifs(o_string *output, int n, const char *str)
5669{ 5751{
5670 int last_is_ifs = 0; 5752 int last_is_ifs = 0;
5671 5753
@@ -5728,8 +5810,7 @@ static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const cha
5728 } 5810 }
5729 } 5811 }
5730 5812
5731 if (ended_with_ifs) 5813 output->ended_in_ifs = last_is_ifs;
5732 *ended_with_ifs = last_is_ifs;
5733 debug_print_list("expand_on_ifs[1]", output, n); 5814 debug_print_list("expand_on_ifs[1]", output, n);
5734 return n; 5815 return n;
5735} 5816}
@@ -5741,45 +5822,288 @@ static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const cha
5741 * Returns malloced string. 5822 * Returns malloced string.
5742 * As an optimization, we return NULL if expansion is not needed. 5823 * As an optimization, we return NULL if expansion is not needed.
5743 */ 5824 */
5744#if !BASH_PATTERN_SUBST 5825static char *encode_then_expand_string(const char *str)
5745/* only ${var/pattern/repl} (its pattern part) needs additional mode */
5746#define encode_then_expand_string(str, process_bkslash, do_unbackslash) \
5747 encode_then_expand_string(str)
5748#endif
5749static char *encode_then_expand_string(const char *str, int process_bkslash, int do_unbackslash)
5750{ 5826{
5751#if !BASH_PATTERN_SUBST
5752 enum { do_unbackslash = 1 };
5753#endif
5754 char *exp_str; 5827 char *exp_str;
5755 struct in_str input; 5828 struct in_str input;
5756 o_string dest = NULL_O_STRING; 5829 o_string dest = NULL_O_STRING;
5830 const char *cp;
5757 5831
5758 if (!strchr(str, '$') 5832 cp = str;
5759 && !strchr(str, '\\') 5833 for (;;) {
5834 if (!*cp) return NULL; /* string has no special chars */
5835 if (*cp == '$') break;
5836 if (*cp == '\\') break;
5760#if ENABLE_HUSH_TICK 5837#if ENABLE_HUSH_TICK
5761 && !strchr(str, '`') 5838 if (*cp == '`') break;
5762#endif 5839#endif
5763 ) { 5840 cp++;
5764 return NULL;
5765 } 5841 }
5766 5842
5767 /* We need to expand. Example: 5843 /* We need to expand. Example:
5768 * echo $(($a + `echo 1`)) $((1 + $((2)) )) 5844 * echo $(($a + `echo 1`)) $((1 + $((2)) ))
5769 */ 5845 */
5770 setup_string_in_str(&input, str); 5846 setup_string_in_str(&input, str);
5771 encode_string(NULL, &dest, &input, EOF, process_bkslash); 5847 encode_string(NULL, &dest, &input, EOF);
5772//TODO: error check (encode_string returns 0 on error)? 5848//TODO: error check (encode_string returns 0 on error)?
5773 //bb_error_msg("'%s' -> '%s'", str, dest.data); 5849 //bb_error_msg("'%s' -> '%s'", str, dest.data);
5774 exp_str = expand_string_to_string(dest.data, 5850 exp_str = expand_string_to_string(dest.data,
5851 EXP_FLAG_ESC_GLOB_CHARS,
5852 /*unbackslash:*/ 1
5853 );
5854 //bb_error_msg("'%s' -> '%s'", dest.data, exp_str);
5855 o_free(&dest);
5856 return exp_str;
5857}
5858
5859/* Expanding ARG in ${var#ARG}, ${var%ARG}, or ${var/ARG/ARG}.
5860 * These can contain single- and double-quoted strings,
5861 * and treated as if the ARG string is initially unquoted. IOW:
5862 * ${var#ARG} and "${var#ARG}" treat ARG the same (ARG can even be
5863 * a dquoted string: "${var#"zz"}"), the difference only comes later
5864 * (word splitting and globbing of the ${var...} result).
5865 */
5866#if !BASH_PATTERN_SUBST
5867#define encode_then_expand_vararg(str, handle_squotes, do_unbackslash) \
5868 encode_then_expand_vararg(str, handle_squotes)
5869#endif
5870static char *encode_then_expand_vararg(const char *str, int handle_squotes, int do_unbackslash)
5871{
5872#if !BASH_PATTERN_SUBST
5873 const int do_unbackslash = 0;
5874#endif
5875 char *exp_str;
5876 struct in_str input;
5877 o_string dest = NULL_O_STRING;
5878 const char *cp;
5879
5880 cp = str;
5881 for (;;) {
5882 if (!*cp) return NULL; /* string has no special chars */
5883 if (*cp == '$') break;
5884 if (*cp == '\\') break;
5885 if (*cp == '\'') break;
5886 if (*cp == '"') break;
5887#if ENABLE_HUSH_TICK
5888 if (*cp == '`') break;
5889#endif
5890 cp++;
5891 }
5892
5893 setup_string_in_str(&input, str);
5894 dest.data = xzalloc(1); /* start as "", not as NULL */
5895 exp_str = NULL;
5896
5897 for (;;) {
5898 int ch;
5899
5900 ch = i_getch(&input);
5901 debug_printf_parse("%s: ch=%c (%d) escape=%d\n",
5902 __func__, ch, ch, !!dest.o_expflags);
5903
5904 if (!dest.o_expflags) {
5905 if (ch == EOF)
5906 break;
5907 if (handle_squotes && ch == '\'') {
5908 if (!add_till_single_quote_dquoted(&dest, &input))
5909 goto ret; /* error */
5910 continue;
5911 }
5912 }
5913 if (ch == EOF) {
5914 syntax_error_unterm_ch('"');
5915 goto ret; /* error */
5916 }
5917 if (ch == '"') {
5918 dest.o_expflags ^= EXP_FLAG_ESC_GLOB_CHARS;
5919 continue;
5920 }
5921 if (ch == '\\') {
5922 ch = i_getch(&input);
5923 if (ch == EOF) {
5924//example? error message? syntax_error_unterm_ch('"');
5925 debug_printf_parse("%s: error: \\<eof>\n", __func__);
5926 goto ret;
5927 }
5928 o_addqchr(&dest, ch);
5929 continue;
5930 }
5931 if (ch == '$') {
5932 if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ 0x80)) {
5933 debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__);
5934 goto ret;
5935 }
5936 continue;
5937 }
5938#if ENABLE_HUSH_TICK
5939 if (ch == '`') {
5940 //unsigned pos = dest->length;
5941 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
5942 o_addchr(&dest, 0x80 | '`');
5943 if (!add_till_backquote(&dest, &input,
5944 /*in_dquote:*/ dest.o_expflags /* nonzero if EXP_FLAG_ESC_GLOB_CHARS set */
5945 )
5946 ) {
5947 goto ret; /* error */
5948 }
5949 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
5950 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
5951 continue;
5952 }
5953#endif
5954 o_addQchr(&dest, ch);
5955 } /* for (;;) */
5956
5957 debug_printf_parse("encode: '%s' -> '%s'\n", str, dest.data);
5958 exp_str = expand_string_to_string(dest.data,
5775 do_unbackslash ? EXP_FLAG_ESC_GLOB_CHARS : 0, 5959 do_unbackslash ? EXP_FLAG_ESC_GLOB_CHARS : 0,
5776 do_unbackslash 5960 do_unbackslash
5777 ); 5961 );
5778 //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); 5962 ret:
5779 o_free_unsafe(&dest); 5963 debug_printf_parse("expand: '%s' -> '%s'\n", dest.data, exp_str);
5964 o_free(&dest);
5780 return exp_str; 5965 return exp_str;
5781} 5966}
5782 5967
5968/* Expanding ARG in ${var+ARG}, ${var-ARG}
5969 */
5970static int encode_then_append_var_plusminus(o_string *output, int n,
5971 const char *str, int dquoted)
5972{
5973 struct in_str input;
5974 o_string dest = NULL_O_STRING;
5975
5976#if 0 //todo?
5977 const char *cp;
5978 cp = str;
5979 for (;;) {
5980 if (!*cp) return NULL; /* string has no special chars */
5981 if (*cp == '$') break;
5982 if (*cp == '\\') break;
5983 if (*cp == '\'') break;
5984 if (*cp == '"') break;
5985#if ENABLE_HUSH_TICK
5986 if (*cp == '`') break;
5987#endif
5988 cp++;
5989 }
5990#endif
5991
5992 setup_string_in_str(&input, str);
5993
5994 for (;;) {
5995 int ch;
5996
5997 ch = i_getch(&input);
5998 debug_printf_parse("%s: ch=%c (%d) escape=%x\n",
5999 __func__, ch, ch, dest.o_expflags);
6000
6001 if (!dest.o_expflags) {
6002 if (ch == EOF)
6003 break;
6004 if (!dquoted && strchr(G.ifs, ch)) {
6005 /* PREFIX${x:d${e}f ...} and we met space: expand "d${e}f" and start new word.
6006 * do not assume we are at the start of the word (PREFIX above).
6007 */
6008 if (dest.data) {
6009 n = expand_vars_to_list(output, n, dest.data);
6010 o_free_and_set_NULL(&dest);
6011 o_addchr(output, '\0');
6012 n = o_save_ptr(output, n); /* create next word */
6013 } else
6014 if (output->length != o_get_last_ptr(output, n)
6015 || output->has_quoted_part
6016 ) {
6017 /* For these cases:
6018 * f() { for i; do echo "|$i|"; done; }; x=x
6019 * f a${x:+ }b # 1st condition
6020 * |a|
6021 * |b|
6022 * f ""${x:+ }b # 2nd condition
6023 * ||
6024 * |b|
6025 */
6026 o_addchr(output, '\0');
6027 n = o_save_ptr(output, n); /* create next word */
6028 }
6029 continue;
6030 }
6031 if (!dquoted && ch == '\'') {
6032 if (!add_till_single_quote_dquoted(&dest, &input))
6033 goto ret; /* error */
6034 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6035 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6036 continue;
6037 }
6038 }
6039 if (ch == EOF) {
6040 syntax_error_unterm_ch('"');
6041 goto ret; /* error */
6042 }
6043 if (ch == '"') {
6044 dest.o_expflags ^= EXP_FLAG_ESC_GLOB_CHARS;
6045 if (dest.o_expflags) {
6046 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6047 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6048 }
6049 continue;
6050 }
6051 if (ch == '\\') {
6052 ch = i_getch(&input);
6053 if (ch == EOF) {
6054//example? error message? syntax_error_unterm_ch('"');
6055 debug_printf_parse("%s: error: \\<eof>\n", __func__);
6056 goto ret;
6057 }
6058 o_addqchr(&dest, ch);
6059 continue;
6060 }
6061 if (ch == '$') {
6062 if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ (dest.o_expflags || dquoted) ? 0x80 : 0)) {
6063 debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__);
6064 goto ret;
6065 }
6066 continue;
6067 }
6068#if ENABLE_HUSH_TICK
6069 if (ch == '`') {
6070 //unsigned pos = dest->length;
6071 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6072 o_addchr(&dest, (dest.o_expflags || dquoted) ? 0x80 | '`' : '`');
6073 if (!add_till_backquote(&dest, &input,
6074 /*in_dquote:*/ dest.o_expflags /* nonzero if EXP_FLAG_ESC_GLOB_CHARS set */
6075 )
6076 ) {
6077 goto ret; /* error */
6078 }
6079 o_addchr(&dest, SPECIAL_VAR_SYMBOL);
6080 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
6081 continue;
6082 }
6083#endif
6084 if (dquoted) {
6085 /* Always glob-protect if in dquotes:
6086 * x=x; echo "${x:+/bin/c*}" - prints: /bin/c*
6087 * x=x; echo "${x:+"/bin/c*"}" - prints: /bin/c*
6088 */
6089 o_addqchr(&dest, ch);
6090 } else {
6091 /* Glob-protect only if char is quoted:
6092 * x=x; echo ${x:+/bin/c*} - prints many filenames
6093 * x=x; echo ${x:+"/bin/c*"} - prints: /bin/c*
6094 */
6095 o_addQchr(&dest, ch);
6096 }
6097 } /* for (;;) */
6098
6099 if (dest.data) {
6100 n = expand_vars_to_list(output, n, dest.data);
6101 }
6102 ret:
6103 o_free(&dest);
6104 return n;
6105}
6106
5783#if ENABLE_FEATURE_SH_MATH 6107#if ENABLE_FEATURE_SH_MATH
5784static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p) 6108static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
5785{ 6109{
@@ -5790,7 +6114,7 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
5790 math_state.lookupvar = get_local_var_value; 6114 math_state.lookupvar = get_local_var_value;
5791 math_state.setvar = set_local_var_from_halves; 6115 math_state.setvar = set_local_var_from_halves;
5792 //math_state.endofname = endofname; 6116 //math_state.endofname = endofname;
5793 exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); 6117 exp_str = encode_then_expand_string(arg);
5794 res = arith(&math_state, exp_str ? exp_str : arg); 6118 res = arith(&math_state, exp_str ? exp_str : arg);
5795 free(exp_str); 6119 free(exp_str);
5796 if (errmsg_p) 6120 if (errmsg_p)
@@ -5857,16 +6181,33 @@ static char *replace_pattern(char *val, const char *pattern, const char *repl, c
5857} 6181}
5858#endif /* BASH_PATTERN_SUBST */ 6182#endif /* BASH_PATTERN_SUBST */
5859 6183
5860/* Helper: 6184static int append_str_maybe_ifs_split(o_string *output, int n,
5861 * Handles <SPECIAL_VAR_SYMBOL>varname...<SPECIAL_VAR_SYMBOL> construct. 6185 int first_ch, const char *val)
6186{
6187 if (!(first_ch & 0x80)) { /* unquoted $VAR */
6188 debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val,
6189 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
6190 if (val && val[0])
6191 n = expand_on_ifs(output, n, val);
6192 } else { /* quoted "$VAR" */
6193 output->has_quoted_part = 1;
6194 debug_printf_expand("quoted '%s', output->o_escape:%d\n", val,
6195 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
6196 if (val && val[0])
6197 o_addQstr(output, val);
6198 }
6199 return n;
6200}
6201
6202/* Handle <SPECIAL_VAR_SYMBOL>varname...<SPECIAL_VAR_SYMBOL> construct.
5862 */ 6203 */
5863static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, char **pp) 6204static NOINLINE int expand_one_var(o_string *output, int n,
6205 int first_ch, char *arg, char **pp)
5864{ 6206{
5865 const char *val; 6207 const char *val;
5866 char *to_be_freed; 6208 char *to_be_freed;
5867 char *p; 6209 char *p;
5868 char *var; 6210 char *var;
5869 char first_char;
5870 char exp_op; 6211 char exp_op;
5871 char exp_save = exp_save; /* for compiler */ 6212 char exp_save = exp_save; /* for compiler */
5872 char *exp_saveptr; /* points to expansion operator */ 6213 char *exp_saveptr; /* points to expansion operator */
@@ -5880,10 +6221,10 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5880 var = arg; 6221 var = arg;
5881 exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL; 6222 exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL;
5882 arg0 = arg[0]; 6223 arg0 = arg[0];
5883 first_char = arg[0] = arg0 & 0x7f; 6224 arg[0] = (arg0 & 0x7f);
5884 exp_op = 0; 6225 exp_op = 0;
5885 6226
5886 if (first_char == '#' && arg[1] /* ${#...} but not ${#} */ 6227 if (arg[0] == '#' && arg[1] /* ${#...} but not ${#} */
5887 && (!exp_saveptr /* and ( not(${#<op_char>...}) */ 6228 && (!exp_saveptr /* and ( not(${#<op_char>...}) */
5888 || (arg[2] == '\0' && strchr(SPECIAL_VARS_STR, arg[1])) /* or ${#C} "len of $C" ) */ 6229 || (arg[2] == '\0' && strchr(SPECIAL_VARS_STR, arg[1])) /* or ${#C} "len of $C" ) */
5889 ) /* NB: skipping ^^^specvar check mishandles ${#::2} */ 6230 ) /* NB: skipping ^^^specvar check mishandles ${#::2} */
@@ -5894,7 +6235,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5894 } else { 6235 } else {
5895 /* Maybe handle parameter expansion */ 6236 /* Maybe handle parameter expansion */
5896 if (exp_saveptr /* if 2nd char is one of expansion operators */ 6237 if (exp_saveptr /* if 2nd char is one of expansion operators */
5897 && strchr(NUMERIC_SPECVARS_STR, first_char) /* 1st char is special variable */ 6238 && strchr(NUMERIC_SPECVARS_STR, arg[0]) /* 1st char is special variable */
5898 ) { 6239 ) {
5899 /* ${?:0}, ${#[:]%0} etc */ 6240 /* ${?:0}, ${#[:]%0} etc */
5900 exp_saveptr = var + 1; 6241 exp_saveptr = var + 1;
@@ -5923,9 +6264,9 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5923 /* Look up the variable in question */ 6264 /* Look up the variable in question */
5924 if (isdigit(var[0])) { 6265 if (isdigit(var[0])) {
5925 /* parse_dollar should have vetted var for us */ 6266 /* parse_dollar should have vetted var for us */
5926 int n = xatoi_positive(var); 6267 int nn = xatoi_positive(var);
5927 if (n < G.global_argc) 6268 if (nn < G.global_argc)
5928 val = G.global_argv[n]; 6269 val = G.global_argv[nn];
5929 /* else val remains NULL: $N with too big N */ 6270 /* else val remains NULL: $N with too big N */
5930 } else { 6271 } else {
5931 switch (var[0]) { 6272 switch (var[0]) {
@@ -5963,6 +6304,9 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5963 * Word is expanded to produce a glob pattern. 6304 * Word is expanded to produce a glob pattern.
5964 * Then var's value is matched to it and matching part removed. 6305 * Then var's value is matched to it and matching part removed.
5965 */ 6306 */
6307//FIXME: ${x#...${...}...}
6308//should evaluate inner ${...} even if x is "" and no shrinking of it is possible -
6309//inner ${...} may have side effects!
5966 if (val && val[0]) { 6310 if (val && val[0]) {
5967 char *t; 6311 char *t;
5968 char *exp_exp_word; 6312 char *exp_exp_word;
@@ -5971,20 +6315,16 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
5971 if (exp_op == *exp_word) /* ## or %% */ 6315 if (exp_op == *exp_word) /* ## or %% */
5972 exp_word++; 6316 exp_word++;
5973 debug_printf_expand("expand: exp_word:'%s'\n", exp_word); 6317 debug_printf_expand("expand: exp_word:'%s'\n", exp_word);
5974 /* 6318 exp_exp_word = encode_then_expand_vararg(exp_word, /*handle_squotes:*/ 1, /*unbackslash:*/ 0);
5975 * process_bkslash:1 unbackslash:1 breaks this:
5976 * a='a\\'; echo ${a%\\\\} # correct output is: a
5977 * process_bkslash:1 unbackslash:0 breaks this:
5978 * a='a}'; echo ${a%\}} # correct output is: a
5979 */
5980 exp_exp_word = encode_then_expand_string(exp_word, /*process_bkslash:*/ 0, /*unbackslash:*/ 0);
5981 if (exp_exp_word) 6319 if (exp_exp_word)
5982 exp_word = exp_exp_word; 6320 exp_word = exp_exp_word;
5983 debug_printf_expand("expand: exp_exp_word:'%s'\n", exp_word); 6321 debug_printf_expand("expand: exp_word:'%s'\n", exp_word);
5984 /* HACK ALERT. We depend here on the fact that 6322 /*
6323 * HACK ALERT. We depend here on the fact that
5985 * G.global_argv and results of utoa and get_local_var_value 6324 * G.global_argv and results of utoa and get_local_var_value
5986 * are actually in writable memory: 6325 * are actually in writable memory:
5987 * scan_and_match momentarily stores NULs there. */ 6326 * scan_and_match momentarily stores NULs there.
6327 */
5988 t = (char*)val; 6328 t = (char*)val;
5989 loc = scan_and_match(t, exp_word, scan_flags); 6329 loc = scan_and_match(t, exp_word, scan_flags);
5990 debug_printf_expand("op:%c str:'%s' pat:'%s' res:'%s'\n", exp_op, t, exp_word, loc); 6330 debug_printf_expand("op:%c str:'%s' pat:'%s' res:'%s'\n", exp_op, t, exp_word, loc);
@@ -6017,7 +6357,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
6017 * (note that a*z _pattern_ is never globbed!) 6357 * (note that a*z _pattern_ is never globbed!)
6018 */ 6358 */
6019 char *pattern, *repl, *t; 6359 char *pattern, *repl, *t;
6020 pattern = encode_then_expand_string(exp_word, /*process_bkslash:*/ 0, /*unbackslash:*/ 0); 6360 pattern = encode_then_expand_vararg(exp_word, /*handle_squotes:*/ 1, /*unbackslash:*/ 0);
6021 if (!pattern) 6361 if (!pattern)
6022 pattern = xstrdup(exp_word); 6362 pattern = xstrdup(exp_word);
6023 debug_printf_varexp("pattern:'%s'->'%s'\n", exp_word, pattern); 6363 debug_printf_varexp("pattern:'%s'->'%s'\n", exp_word, pattern);
@@ -6025,7 +6365,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
6025 exp_word = p; 6365 exp_word = p;
6026 p = strchr(p, SPECIAL_VAR_SYMBOL); 6366 p = strchr(p, SPECIAL_VAR_SYMBOL);
6027 *p = '\0'; 6367 *p = '\0';
6028 repl = encode_then_expand_string(exp_word, /*process_bkslash:*/ 0, /*unbackslash:*/ 1); 6368 repl = encode_then_expand_vararg(exp_word, /*handle_squotes:*/ 1, /*unbackslash:*/ 1);
6029 debug_printf_varexp("repl:'%s'->'%s'\n", exp_word, repl); 6369 debug_printf_varexp("repl:'%s'->'%s'\n", exp_word, repl);
6030 /* HACK ALERT. We depend here on the fact that 6370 /* HACK ALERT. We depend here on the fact that
6031 * G.global_argv and results of utoa and get_local_var_value 6371 * G.global_argv and results of utoa and get_local_var_value
@@ -6121,6 +6461,34 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
6121 * 6461 *
6122 * Colon forms (${var:-word}, ${var:=word} etc) do the same, 6462 * Colon forms (${var:-word}, ${var:=word} etc) do the same,
6123 * but also treat null var as if it is unset. 6463 * but also treat null var as if it is unset.
6464 *
6465 * Word-splitting and single quote behavior:
6466 *
6467 * $ f() { for i; do echo "|$i|"; done; };
6468 *
6469 * $ x=; f ${x:?'x y' z}
6470 * bash: x: x y z #BUG: does not abort, ${} results in empty expansion
6471 * $ x=; f "${x:?'x y' z}"
6472 * bash: x: x y z # dash prints: dash: x: 'x y' z #BUG: does not abort, ${} results in ""
6473 *
6474 * $ x=; f ${x:='x y' z}
6475 * |x|
6476 * |y|
6477 * |z|
6478 * $ x=; f "${x:='x y' z}"
6479 * |'x y' z|
6480 *
6481 * $ x=x; f ${x:+'x y' z}
6482 * |x y|
6483 * |z|
6484 * $ x=x; f "${x:+'x y' z}"
6485 * |'x y' z|
6486 *
6487 * $ x=; f ${x:-'x y' z}
6488 * |x y|
6489 * |z|
6490 * $ x=; f "${x:-'x y' z}"
6491 * |'x y' z|
6124 */ 6492 */
6125 int use_word = (!val || ((exp_save == ':') && !val[0])); 6493 int use_word = (!val || ((exp_save == ':') && !val[0]));
6126 if (exp_op == '+') 6494 if (exp_op == '+')
@@ -6128,33 +6496,51 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
6128 debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op, 6496 debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op,
6129 (exp_save == ':') ? "true" : "false", use_word); 6497 (exp_save == ':') ? "true" : "false", use_word);
6130 if (use_word) { 6498 if (use_word) {
6131 to_be_freed = encode_then_expand_string(exp_word, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); 6499 if (exp_op == '+' || exp_op == '-') {
6132 if (to_be_freed) 6500 /* ${var+word} - use alternative value */
6133 exp_word = to_be_freed; 6501 /* ${var-word} - use default value */
6134 if (exp_op == '?') { 6502 n = encode_then_append_var_plusminus(output, n, exp_word,
6135 /* mimic bash message */ 6503 /*dquoted:*/ (arg0 & 0x80)
6136 msg_and_die_if_script("%s: %s",
6137 var,
6138 exp_word[0]
6139 ? exp_word
6140 : "parameter null or not set"
6141 /* ash has more specific messages, a-la: */
6142 /*: (exp_save == ':' ? "parameter null or not set" : "parameter not set")*/
6143 ); 6504 );
6144//TODO: how interactive bash aborts expansion mid-command? 6505 val = NULL;
6145 } else { 6506 } else {
6146 val = exp_word; 6507 /* ${var?word} - indicate error if unset */
6147 } 6508 /* ${var=word} - assign and use default value */
6148 6509 to_be_freed = encode_then_expand_vararg(exp_word,
6149 if (exp_op == '=') { 6510 /*handle_squotes:*/ !(arg0 & 0x80),
6150 /* ${var=[word]} or ${var:=[word]} */ 6511 /*unbackslash:*/ 0
6151 if (isdigit(var[0]) || var[0] == '#') { 6512 );
6513 if (to_be_freed)
6514 exp_word = to_be_freed;
6515 if (exp_op == '?') {
6152 /* mimic bash message */ 6516 /* mimic bash message */
6153 msg_and_die_if_script("$%s: cannot assign in this way", var); 6517 msg_and_die_if_script("%s: %s",
6154 val = NULL; 6518 var,
6519 exp_word[0]
6520 ? exp_word
6521 : "parameter null or not set"
6522 /* ash has more specific messages, a-la: */
6523 /*: (exp_save == ':' ? "parameter null or not set" : "parameter not set")*/
6524 );
6525//TODO: how interactive bash aborts expansion mid-command?
6526//It aborts the entire line, returns to prompt:
6527// $ f() { for i; do echo "|$i|"; done; }; x=; f "${x:?'x y' z}"; echo YO
6528// bash: x: x y z
6529// $
6530// ("echo YO" is not executed, neither the f function call)
6155 } else { 6531 } else {
6156 char *new_var = xasprintf("%s=%s", var, val); 6532 val = exp_word;
6157 set_local_var(new_var, /*flag:*/ 0); 6533 }
6534 if (exp_op == '=') {
6535 /* ${var=[word]} or ${var:=[word]} */
6536 if (isdigit(var[0]) || var[0] == '#') {
6537 /* mimic bash message */
6538 msg_and_die_if_script("$%s: cannot assign in this way", var);
6539 val = NULL;
6540 } else {
6541 char *new_var = xasprintf("%s=%s", var, val);
6542 set_local_var(new_var, /*flag:*/ 0);
6543 }
6158 } 6544 }
6159 } 6545 }
6160 } 6546 }
@@ -6164,10 +6550,12 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
6164 } /* if (exp_op) */ 6550 } /* if (exp_op) */
6165 6551
6166 arg[0] = arg0; 6552 arg[0] = arg0;
6167
6168 *pp = p; 6553 *pp = p;
6169 *to_be_freed_pp = to_be_freed; 6554
6170 return val; 6555 n = append_str_maybe_ifs_split(output, n, first_ch, val);
6556
6557 free(to_be_freed);
6558 return n;
6171} 6559}
6172 6560
6173/* Expand all variable references in given string, adding words to list[] 6561/* Expand all variable references in given string, adding words to list[]
@@ -6181,30 +6569,22 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
6181 * expansion of right-hand side of assignment == 1-element expand. 6569 * expansion of right-hand side of assignment == 1-element expand.
6182 */ 6570 */
6183 char cant_be_null = 0; /* only bit 0x80 matters */ 6571 char cant_be_null = 0; /* only bit 0x80 matters */
6184 int ended_in_ifs = 0; /* did last unquoted expansion end with IFS chars? */
6185 char *p; 6572 char *p;
6186 6573
6187 debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg, 6574 debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg,
6188 !!(output->o_expflags & EXP_FLAG_SINGLEWORD)); 6575 !!(output->o_expflags & EXP_FLAG_SINGLEWORD));
6189 debug_print_list("expand_vars_to_list", output, n);
6190 n = o_save_ptr(output, n);
6191 debug_print_list("expand_vars_to_list[0]", output, n); 6576 debug_print_list("expand_vars_to_list[0]", output, n);
6192 6577
6193 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) { 6578 while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) {
6194 char first_ch; 6579 char first_ch;
6195 char *to_be_freed = NULL;
6196 const char *val = NULL;
6197#if ENABLE_HUSH_TICK
6198 o_string subst_result = NULL_O_STRING;
6199#endif
6200#if ENABLE_FEATURE_SH_MATH 6580#if ENABLE_FEATURE_SH_MATH
6201 char arith_buf[sizeof(arith_t)*3 + 2]; 6581 char arith_buf[sizeof(arith_t)*3 + 2];
6202#endif 6582#endif
6203 6583
6204 if (ended_in_ifs) { 6584 if (output->ended_in_ifs) {
6205 o_addchr(output, '\0'); 6585 o_addchr(output, '\0');
6206 n = o_save_ptr(output, n); 6586 n = o_save_ptr(output, n);
6207 ended_in_ifs = 0; 6587 output->ended_in_ifs = 0;
6208 } 6588 }
6209 6589
6210 o_addblock(output, arg, p - arg); 6590 o_addblock(output, arg, p - arg);
@@ -6235,7 +6615,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
6235 cant_be_null |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ 6615 cant_be_null |= first_ch; /* do it for "$@" _now_, when we know it's not empty */
6236 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ 6616 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
6237 while (G.global_argv[i]) { 6617 while (G.global_argv[i]) {
6238 n = expand_on_ifs(NULL, output, n, G.global_argv[i]); 6618 n = expand_on_ifs(output, n, G.global_argv[i]);
6239 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); 6619 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1);
6240 if (G.global_argv[i++][0] && G.global_argv[i]) { 6620 if (G.global_argv[i++][0] && G.global_argv[i]) {
6241 /* this argv[] is not empty and not last: 6621 /* this argv[] is not empty and not last:
@@ -6272,19 +6652,25 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
6272 } 6652 }
6273 break; 6653 break;
6274 } 6654 }
6275 case SPECIAL_VAR_SYMBOL: /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */ 6655 case SPECIAL_VAR_SYMBOL: {
6656 /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_SYMBOL> */
6276 /* "Empty variable", used to make "" etc to not disappear */ 6657 /* "Empty variable", used to make "" etc to not disappear */
6277 output->has_quoted_part = 1; 6658 output->has_quoted_part = 1;
6278 arg++;
6279 cant_be_null = 0x80; 6659 cant_be_null = 0x80;
6660 arg++;
6280 break; 6661 break;
6662 }
6281 case SPECIAL_VAR_QUOTED_SVS: 6663 case SPECIAL_VAR_QUOTED_SVS:
6282 /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_QUOTED_SVS><SPECIAL_VAR_SYMBOL> */ 6664 /* <SPECIAL_VAR_SYMBOL><SPECIAL_VAR_QUOTED_SVS><SPECIAL_VAR_SYMBOL> */
6665 /* "^C variable", represents literal ^C char (possible in scripts) */
6666 o_addchr(output, SPECIAL_VAR_SYMBOL);
6283 arg++; 6667 arg++;
6284 val = SPECIAL_VAR_SYMBOL_STR;
6285 break; 6668 break;
6286#if ENABLE_HUSH_TICK 6669#if ENABLE_HUSH_TICK
6287 case '`': /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */ 6670 case '`': {
6671 /* <SPECIAL_VAR_SYMBOL>`cmd<SPECIAL_VAR_SYMBOL> */
6672 o_string subst_result = NULL_O_STRING;
6673
6288 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */ 6674 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */
6289 arg++; 6675 arg++;
6290 /* Can't just stuff it into output o_string, 6676 /* Can't just stuff it into output o_string,
@@ -6294,11 +6680,14 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
6294 G.last_exitcode = process_command_subs(&subst_result, arg); 6680 G.last_exitcode = process_command_subs(&subst_result, arg);
6295 G.expand_exitcode = G.last_exitcode; 6681 G.expand_exitcode = G.last_exitcode;
6296 debug_printf_subst("SUBST RES:%d '%s'\n", G.last_exitcode, subst_result.data); 6682 debug_printf_subst("SUBST RES:%d '%s'\n", G.last_exitcode, subst_result.data);
6297 val = subst_result.data; 6683 n = append_str_maybe_ifs_split(output, n, first_ch, subst_result.data);
6298 goto store_val; 6684 o_free(&subst_result);
6685 break;
6686 }
6299#endif 6687#endif
6300#if ENABLE_FEATURE_SH_MATH 6688#if ENABLE_FEATURE_SH_MATH
6301 case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */ 6689 case '+': {
6690 /* <SPECIAL_VAR_SYMBOL>+arith<SPECIAL_VAR_SYMBOL> */
6302 arith_t res; 6691 arith_t res;
6303 6692
6304 arg++; /* skip '+' */ 6693 arg++; /* skip '+' */
@@ -6307,62 +6696,43 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
6307 res = expand_and_evaluate_arith(arg, NULL); 6696 res = expand_and_evaluate_arith(arg, NULL);
6308 debug_printf_subst("ARITH RES '"ARITH_FMT"'\n", res); 6697 debug_printf_subst("ARITH RES '"ARITH_FMT"'\n", res);
6309 sprintf(arith_buf, ARITH_FMT, res); 6698 sprintf(arith_buf, ARITH_FMT, res);
6310 val = arith_buf; 6699 o_addstr(output, arith_buf);
6311 break; 6700 break;
6312 } 6701 }
6313#endif 6702#endif
6314 default: 6703 default:
6315 val = expand_one_var(&to_be_freed, arg, &p); 6704 /* <SPECIAL_VAR_SYMBOL>varname[ops]<SPECIAL_VAR_SYMBOL> */
6316 IF_HUSH_TICK(store_val:) 6705 n = expand_one_var(output, n, first_ch, arg, &p);
6317 if (!(first_ch & 0x80)) { /* unquoted $VAR */
6318 debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val,
6319 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
6320 if (val && val[0]) {
6321 n = expand_on_ifs(&ended_in_ifs, output, n, val);
6322 val = NULL;
6323 }
6324 } else { /* quoted $VAR, val will be appended below */
6325 output->has_quoted_part = 1;
6326 debug_printf_expand("quoted '%s', output->o_escape:%d\n", val,
6327 !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
6328 }
6329 break; 6706 break;
6330 } /* switch (char after <SPECIAL_VAR_SYMBOL>) */ 6707 } /* switch (char after <SPECIAL_VAR_SYMBOL>) */
6331 6708
6332 if (val && val[0]) {
6333 o_addQstr(output, val);
6334 }
6335 free(to_be_freed);
6336
6337 /* Restore NULL'ed SPECIAL_VAR_SYMBOL. 6709 /* Restore NULL'ed SPECIAL_VAR_SYMBOL.
6338 * Do the check to avoid writing to a const string. */ 6710 * Do the check to avoid writing to a const string. */
6339 if (*p != SPECIAL_VAR_SYMBOL) 6711 if (*p != SPECIAL_VAR_SYMBOL)
6340 *p = SPECIAL_VAR_SYMBOL; 6712 *p = SPECIAL_VAR_SYMBOL;
6341
6342#if ENABLE_HUSH_TICK
6343 o_free(&subst_result);
6344#endif
6345 arg = ++p; 6713 arg = ++p;
6346 } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ 6714 } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */
6347 6715
6348 if (arg[0]) { 6716 if (*arg) {
6349 if (ended_in_ifs) { 6717 /* handle trailing string */
6718 if (output->ended_in_ifs) {
6350 o_addchr(output, '\0'); 6719 o_addchr(output, '\0');
6351 n = o_save_ptr(output, n); 6720 n = o_save_ptr(output, n);
6352 } 6721 }
6353 debug_print_list("expand_vars_to_list[a]", output, n); 6722 debug_print_list("expand_vars_to_list[a]", output, n);
6354 /* this part is literal, and it was already pre-quoted 6723 /* this part is literal, and it was already pre-quoted
6355 * if needed (much earlier), do not use o_addQstr here! */ 6724 * if needed (much earlier), do not use o_addQstr here!
6356 o_addstr_with_NUL(output, arg); 6725 */
6726 o_addstr(output, arg);
6357 debug_print_list("expand_vars_to_list[b]", output, n); 6727 debug_print_list("expand_vars_to_list[b]", output, n);
6358 } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ 6728 } else
6359 && !(cant_be_null & 0x80) /* and all vars were not quoted. */ 6729 if (output->length == o_get_last_ptr(output, n) /* expansion is empty */
6730 && !(cant_be_null & 0x80) /* and all vars were not quoted */
6731 && !output->has_quoted_part
6360 ) { 6732 ) {
6361 n--; 6733 n--;
6362 /* allow to reuse list[n] later without re-growth */ 6734 /* allow to reuse list[n] later without re-growth */
6363 output->has_empty_slot = 1; 6735 output->has_empty_slot = 1;
6364 } else {
6365 o_addchr(output, '\0');
6366 } 6736 }
6367 6737
6368 return n; 6738 return n;
@@ -6377,9 +6747,18 @@ static char **expand_variables(char **argv, unsigned expflags)
6377 output.o_expflags = expflags; 6747 output.o_expflags = expflags;
6378 6748
6379 n = 0; 6749 n = 0;
6380 while (*argv) { 6750 for (;;) {
6381 n = expand_vars_to_list(&output, n, *argv); 6751 /* go to next list[n] */
6382 argv++; 6752 output.ended_in_ifs = 0;
6753 n = o_save_ptr(&output, n);
6754
6755 if (!*argv)
6756 break;
6757
6758 /* expand argv[i] */
6759 n = expand_vars_to_list(&output, n, *argv++);
6760 /* if (!output->has_empty_slot) -- need this?? */
6761 o_addchr(&output, '\0');
6383 } 6762 }
6384 debug_print_list("expand_variables", &output, n); 6763 debug_print_list("expand_variables", &output, n);
6385 6764
@@ -6429,13 +6808,20 @@ static char *expand_string_to_string(const char *str, int EXP_flags, int do_unba
6429 argv[0] = (char*)str; 6808 argv[0] = (char*)str;
6430 argv[1] = NULL; 6809 argv[1] = NULL;
6431 list = expand_variables(argv, EXP_flags | EXP_FLAG_SINGLEWORD); 6810 list = expand_variables(argv, EXP_flags | EXP_FLAG_SINGLEWORD);
6432 if (HUSH_DEBUG) 6811 if (!list[0]) {
6433 if (!list[0] || list[1]) 6812 /* Example where it happens:
6434 bb_error_msg_and_die("BUG in varexp2"); 6813 * x=; echo ${x:-"$@"}
6435 /* actually, just move string 2*sizeof(char*) bytes back */ 6814 */
6436 overlapping_strcpy((char*)list, list[0]); 6815 ((char*)list)[0] = '\0';
6437 if (do_unbackslash) 6816 } else {
6438 unbackslash((char*)list); 6817 if (HUSH_DEBUG)
6818 if (list[1])
6819 bb_error_msg_and_die("BUG in varexp2");
6820 /* actually, just move string 2*sizeof(char*) bytes back */
6821 overlapping_strcpy((char*)list, list[0]);
6822 if (do_unbackslash)
6823 unbackslash((char*)list);
6824 }
6439 debug_printf_expand("string_to_string=>'%s'\n", (char*)list); 6825 debug_printf_expand("string_to_string=>'%s'\n", (char*)list);
6440 return (char*)list; 6826 return (char*)list;
6441} 6827}
@@ -6722,7 +7108,7 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger)
6722 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode); 7108 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
6723 } 7109 }
6724#endif 7110#endif
6725 pipe_list = parse_stream(NULL, inp, end_trigger); 7111 pipe_list = parse_stream(NULL, NULL, inp, end_trigger);
6726 if (!pipe_list || pipe_list == ERR_PTR) { /* EOF/error */ 7112 if (!pipe_list || pipe_list == ERR_PTR) { /* EOF/error */
6727 /* If we are in "big" script 7113 /* If we are in "big" script
6728 * (not in `cmd` or something similar)... 7114 * (not in `cmd` or something similar)...
@@ -6763,19 +7149,19 @@ static void parse_and_run_string(const char *s)
6763 //IF_HUSH_LINENO_VAR(G.lineno = sv;) 7149 //IF_HUSH_LINENO_VAR(G.lineno = sv;)
6764} 7150}
6765 7151
6766static void parse_and_run_file(FILE *f) 7152static void parse_and_run_file(HFILE *fp)
6767{ 7153{
6768 struct in_str input; 7154 struct in_str input;
6769 IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;) 7155 IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;)
6770 7156
6771 IF_HUSH_LINENO_VAR(G.lineno = 1;) 7157 IF_HUSH_LINENO_VAR(G.lineno = 1;)
6772 setup_file_in_str(&input, f); 7158 setup_file_in_str(&input, fp);
6773 parse_and_run_stream(&input, ';'); 7159 parse_and_run_stream(&input, ';');
6774 IF_HUSH_LINENO_VAR(G.lineno = sv;) 7160 IF_HUSH_LINENO_VAR(G.lineno = sv;)
6775} 7161}
6776 7162
6777#if ENABLE_HUSH_TICK 7163#if ENABLE_HUSH_TICK
6778static FILE *generate_stream_from_string(const char *s, pid_t *pid_p) 7164static int generate_stream_from_string(const char *s, pid_t *pid_p)
6779{ 7165{
6780 pid_t pid; 7166 pid_t pid;
6781 int channel[2]; 7167 int channel[2];
@@ -6877,7 +7263,7 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p)
6877 free(to_free); 7263 free(to_free);
6878# endif 7264# endif
6879 close(channel[1]); 7265 close(channel[1]);
6880 return remember_FILE(xfdopen_for_read(channel[0])); 7266 return channel[0];
6881} 7267}
6882 7268
6883/* Return code is exit status of the process that is run. */ 7269/* Return code is exit status of the process that is run. */
@@ -6887,7 +7273,7 @@ static int process_command_subs(o_string *dest, const char *s)
6887 pid_t pid; 7273 pid_t pid;
6888 int status, ch, eol_cnt; 7274 int status, ch, eol_cnt;
6889 7275
6890 fp = generate_stream_from_string(s, &pid); 7276 fp = xfdopen_for_read(generate_stream_from_string(s, &pid));
6891 7277
6892 /* Now send results of command back into original context */ 7278 /* Now send results of command back into original context */
6893 eol_cnt = 0; 7279 eol_cnt = 0;
@@ -6906,7 +7292,7 @@ static int process_command_subs(o_string *dest, const char *s)
6906 } 7292 }
6907 7293
6908 debug_printf("done reading from `cmd` pipe, closing it\n"); 7294 debug_printf("done reading from `cmd` pipe, closing it\n");
6909 fclose_and_forget(fp); 7295 fclose(fp);
6910 /* We need to extract exitcode. Test case 7296 /* We need to extract exitcode. Test case
6911 * "true; echo `sleep 1; false` $?" 7297 * "true; echo `sleep 1; false` $?"
6912 * should print 1 */ 7298 * should print 1 */
@@ -6931,7 +7317,7 @@ static void setup_heredoc(struct redir_struct *redir)
6931 7317
6932 expanded = NULL; 7318 expanded = NULL;
6933 if (!(redir->rd_dup & HEREDOC_QUOTED)) { 7319 if (!(redir->rd_dup & HEREDOC_QUOTED)) {
6934 expanded = encode_then_expand_string(heredoc, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); 7320 expanded = encode_then_expand_string(heredoc);
6935 if (expanded) 7321 if (expanded)
6936 heredoc = expanded; 7322 heredoc = expanded;
6937 } 7323 }
@@ -7084,19 +7470,54 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
7084 return 1; /* "we closed fd" */ 7470 return 1; /* "we closed fd" */
7085 } 7471 }
7086#endif 7472#endif
7087 /* Are we called from setup_redirects(squirrel==NULL)? Two cases: 7473 /* Are we called from setup_redirects(squirrel==NULL)
7088 * (1) Redirect in a forked child. No need to save FILEs' fds, 7474 * in redirect in a [v]forked child?
7089 * we aren't going to use them anymore, ok to trash.
7090 * (2) "exec 3>FILE". Bummer. We can save script FILEs' fds,
7091 * but how are we doing to restore them?
7092 * "fileno(fd) = new_fd" can't be done.
7093 */ 7475 */
7094 if (!sqp) 7476 if (sqp == NULL) {
7477 /* No need to move script fds.
7478 * For NOMMU case, it's actively wrong: we'd change ->fd
7479 * fields in memory for the parent, but parent's fds
7480 * aren't be moved, it would use wrong fd!
7481 * Reproducer: "cmd 3>FILE" in script.
7482 * If we would call move_HFILEs_on_redirect(), child would:
7483 * fcntl64(3, F_DUPFD_CLOEXEC, 10) = 10
7484 * close(3) = 0
7485 * and change ->fd to 10 if fd#3 is a script fd. WRONG.
7486 */
7487 //bb_error_msg("sqp == NULL: [v]forked child");
7095 return 0; 7488 return 0;
7489 }
7096 7490
7097 /* If this one of script's fds? */ 7491 /* If this one of script's fds? */
7098 if (save_FILEs_on_redirect(fd, avoid_fd)) 7492 if (move_HFILEs_on_redirect(fd, avoid_fd))
7099 return 1; /* yes. "we closed fd" */ 7493 return 1; /* yes. "we closed fd" (actually moved it) */
7494
7495 /* Are we called for "exec 3>FILE"? Came through
7496 * redirect_and_varexp_helper(squirrel=ERR_PTR) -> setup_redirects(ERR_PTR)
7497 * This case used to fail for this script:
7498 * exec 3>FILE
7499 * echo Ok
7500 * ...100000 more lines...
7501 * echo Ok
7502 * as follows:
7503 * read(3, "exec 3>FILE\necho Ok\necho Ok"..., 1024) = 1024
7504 * open("FILE", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 4
7505 * dup2(4, 3) = 3
7506 * ^^^^^^^^ oops, we lost fd#3 opened to our script!
7507 * close(4) = 0
7508 * write(1, "Ok\n", 3) = 3
7509 * ... = 3
7510 * write(1, "Ok\n", 3) = 3
7511 * read(3, 0x94fbc08, 1024) = -1 EBADF (Bad file descriptor)
7512 * ^^^^^^^^ oops, wrong fd!!!
7513 * With this case separate from sqp == NULL and *after* move_HFILEs,
7514 * it now works:
7515 */
7516 if (sqp == ERR_PTR) {
7517 /* Don't preserve redirected fds: exec is _meant_ to change these */
7518 //bb_error_msg("sqp == ERR_PTR: exec >FILE");
7519 return 0;
7520 }
7100 7521
7101 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */ 7522 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
7102 *sqp = add_squirrel(*sqp, fd, avoid_fd); 7523 *sqp = add_squirrel(*sqp, fd, avoid_fd);
@@ -7122,8 +7543,6 @@ static void restore_redirects(struct squirrel *sq)
7122 } 7543 }
7123 7544
7124 /* If moved, G.interactive_fd stays on new fd, not restoring it */ 7545 /* If moved, G.interactive_fd stays on new fd, not restoring it */
7125
7126 restore_redirected_FILEs();
7127} 7546}
7128 7547
7129#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU 7548#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
@@ -7131,7 +7550,7 @@ static void close_saved_fds_and_FILE_fds(void)
7131{ 7550{
7132 if (G_interactive_fd) 7551 if (G_interactive_fd)
7133 close(G_interactive_fd); 7552 close(G_interactive_fd);
7134 close_all_FILE_list(); 7553 close_all_HFILE_list();
7135} 7554}
7136#endif 7555#endif
7137 7556
@@ -7144,7 +7563,7 @@ static int internally_opened_fd(int fd, struct squirrel *sq)
7144 return 1; 7563 return 1;
7145#endif 7564#endif
7146 /* If this one of script's fds? */ 7565 /* If this one of script's fds? */
7147 if (fd_in_FILEs(fd)) 7566 if (fd_in_HFILEs(fd))
7148 return 1; 7567 return 1;
7149 7568
7150 if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) { 7569 if (sq) for (i = 0; sq[i].orig_fd >= 0; i++) {
@@ -7169,7 +7588,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
7169 save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp); 7588 save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp);
7170 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ 7589 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_
7171 * of the heredoc */ 7590 * of the heredoc */
7172 debug_printf_parse("set heredoc '%s'\n", 7591 debug_printf_redir("set heredoc '%s'\n",
7173 redir->rd_filename); 7592 redir->rd_filename);
7174 setup_heredoc(redir); 7593 setup_heredoc(redir);
7175 continue; 7594 continue;
@@ -7181,8 +7600,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
7181 int mode; 7600 int mode;
7182 7601
7183 if (redir->rd_filename == NULL) { 7602 if (redir->rd_filename == NULL) {
7184 /* 7603 /* Examples:
7185 * Examples:
7186 * "cmd >" (no filename) 7604 * "cmd >" (no filename)
7187 * "cmd > <file" (2nd redirect starts too early) 7605 * "cmd > <file" (2nd redirect starts too early)
7188 */ 7606 */
@@ -7238,7 +7656,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
7238 */ 7656 */
7239 } else { 7657 } else {
7240 /* if newfd is a script fd or saved fd, simulate EBADF */ 7658 /* if newfd is a script fd or saved fd, simulate EBADF */
7241 if (internally_opened_fd(newfd, sqp ? *sqp : NULL)) { 7659 if (internally_opened_fd(newfd, sqp && sqp != ERR_PTR ? *sqp : NULL)) {
7242 //errno = EBADF; 7660 //errno = EBADF;
7243 //bb_perror_msg_and_die("can't duplicate file descriptor"); 7661 //bb_perror_msg_and_die("can't duplicate file descriptor");
7244 newfd = -1; /* same effect as code above */ 7662 newfd = -1; /* same effect as code above */
@@ -7312,6 +7730,58 @@ static const struct built_in_command *find_builtin(const char *name)
7312 return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); 7730 return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]);
7313} 7731}
7314 7732
7733static void remove_nested_vars(void)
7734{
7735 struct variable *cur;
7736 struct variable **cur_pp;
7737
7738 cur_pp = &G.top_var;
7739 while ((cur = *cur_pp) != NULL) {
7740 if (cur->var_nest_level <= G.var_nest_level) {
7741 cur_pp = &cur->next;
7742 continue;
7743 }
7744 /* Unexport */
7745 if (cur->flg_export) {
7746 debug_printf_env("unexporting nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
7747 bb_unsetenv(cur->varstr);
7748 }
7749 /* Remove from global list */
7750 *cur_pp = cur->next;
7751 /* Free */
7752 if (!cur->max_len) {
7753 debug_printf_env("freeing nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
7754 free(cur->varstr);
7755 }
7756 free(cur);
7757 }
7758}
7759
7760static void enter_var_nest_level(void)
7761{
7762 G.var_nest_level++;
7763 debug_printf_env("var_nest_level++ %u\n", G.var_nest_level);
7764
7765 /* Try: f() { echo -n .; f; }; f
7766 * struct variable::var_nest_level is uint16_t,
7767 * thus limiting recursion to < 2^16.
7768 * In any case, with 8 Mbyte stack SEGV happens
7769 * not too long after 2^16 recursions anyway.
7770 */
7771 if (G.var_nest_level > 0xff00)
7772 bb_error_msg_and_die("fatal recursion (depth %u)", G.var_nest_level);
7773}
7774
7775static void leave_var_nest_level(void)
7776{
7777 G.var_nest_level--;
7778 debug_printf_env("var_nest_level-- %u\n", G.var_nest_level);
7779 if (HUSH_DEBUG && (int)G.var_nest_level < 0)
7780 bb_error_msg_and_die("BUG: nesting underflow");
7781
7782 remove_nested_vars();
7783}
7784
7315#if ENABLE_HUSH_FUNCTIONS 7785#if ENABLE_HUSH_FUNCTIONS
7316static struct function **find_function_slot(const char *name) 7786static struct function **find_function_slot(const char *name)
7317{ 7787{
@@ -7398,58 +7868,6 @@ static void unset_func(const char *name)
7398} 7868}
7399# endif 7869# endif
7400 7870
7401static void remove_nested_vars(void)
7402{
7403 struct variable *cur;
7404 struct variable **cur_pp;
7405
7406 cur_pp = &G.top_var;
7407 while ((cur = *cur_pp) != NULL) {
7408 if (cur->var_nest_level <= G.var_nest_level) {
7409 cur_pp = &cur->next;
7410 continue;
7411 }
7412 /* Unexport */
7413 if (cur->flg_export) {
7414 debug_printf_env("unexporting nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
7415 bb_unsetenv(cur->varstr);
7416 }
7417 /* Remove from global list */
7418 *cur_pp = cur->next;
7419 /* Free */
7420 if (!cur->max_len) {
7421 debug_printf_env("freeing nested '%s'/%u\n", cur->varstr, cur->var_nest_level);
7422 free(cur->varstr);
7423 }
7424 free(cur);
7425 }
7426}
7427
7428static void enter_var_nest_level(void)
7429{
7430 G.var_nest_level++;
7431 debug_printf_env("var_nest_level++ %u\n", G.var_nest_level);
7432
7433 /* Try: f() { echo -n .; f; }; f
7434 * struct variable::var_nest_level is uint16_t,
7435 * thus limiting recursion to < 2^16.
7436 * In any case, with 8 Mbyte stack SEGV happens
7437 * not too long after 2^16 recursions anyway.
7438 */
7439 if (G.var_nest_level > 0xff00)
7440 bb_error_msg_and_die("fatal recursion (depth %u)", G.var_nest_level);
7441}
7442
7443static void leave_var_nest_level(void)
7444{
7445 G.var_nest_level--;
7446 debug_printf_env("var_nest_level-- %u\n", G.var_nest_level);
7447 if (HUSH_DEBUG && (int)G.var_nest_level < 0)
7448 bb_error_msg_and_die("BUG: nesting underflow");
7449
7450 remove_nested_vars();
7451}
7452
7453# if BB_MMU 7871# if BB_MMU
7454#define exec_function(to_free, funcp, argv) \ 7872#define exec_function(to_free, funcp, argv) \
7455 exec_function(funcp, argv) 7873 exec_function(funcp, argv)
@@ -8253,8 +8671,8 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe)
8253 * subshell: ( list ) [&] 8671 * subshell: ( list ) [&]
8254 */ 8672 */
8255#if !ENABLE_HUSH_MODE_X 8673#if !ENABLE_HUSH_MODE_X
8256#define redirect_and_varexp_helper(old_vars_p, command, squirrel, argv_expanded) \ 8674#define redirect_and_varexp_helper(command, sqp, argv_expanded) \
8257 redirect_and_varexp_helper(old_vars_p, command, squirrel) 8675 redirect_and_varexp_helper(command, sqp)
8258#endif 8676#endif
8259static int redirect_and_varexp_helper( 8677static int redirect_and_varexp_helper(
8260 struct command *command, 8678 struct command *command,
@@ -8271,10 +8689,6 @@ static int redirect_and_varexp_helper(
8271 /* this takes ownership of new_env[i] elements, and frees new_env: */ 8689 /* this takes ownership of new_env[i] elements, and frees new_env: */
8272 set_vars_and_save_old(new_env); 8690 set_vars_and_save_old(new_env);
8273 8691
8274 /* setup_redirects acts on file descriptors, not FILEs.
8275 * This is perfect for work that comes after exec().
8276 * Is it really safe for inline use? Experimentally,
8277 * things seem to work. */
8278 return setup_redirects(command, sqp); 8692 return setup_redirects(command, sqp);
8279} 8693}
8280static NOINLINE int run_pipe(struct pipe *pi) 8694static NOINLINE int run_pipe(struct pipe *pi)
@@ -8363,7 +8777,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
8363 } 8777 }
8364#endif 8778#endif
8365 /* { list } */ 8779 /* { list } */
8366 debug_printf("non-subshell group\n"); 8780 debug_printf_exec("non-subshell group\n");
8367 rcode = 1; /* exitcode if redir failed */ 8781 rcode = 1; /* exitcode if redir failed */
8368 if (setup_redirects(command, &squirrel) == 0) { 8782 if (setup_redirects(command, &squirrel) == 0) {
8369 debug_printf_exec(": run_list\n"); 8783 debug_printf_exec(": run_list\n");
@@ -8475,7 +8889,10 @@ static NOINLINE int run_pipe(struct pipe *pi)
8475 */ 8889 */
8476 enter_var_nest_level(); 8890 enter_var_nest_level();
8477 G.shadowed_vars_pp = &old_vars; 8891 G.shadowed_vars_pp = &old_vars;
8478 rcode = redirect_and_varexp_helper(command, /*squirrel:*/ NULL, argv_expanded); 8892 rcode = redirect_and_varexp_helper(command,
8893 /*squirrel:*/ ERR_PTR,
8894 argv_expanded
8895 );
8479 G.shadowed_vars_pp = sv_shadowed; 8896 G.shadowed_vars_pp = sv_shadowed;
8480 /* rcode=1 can be if redir file can't be opened */ 8897 /* rcode=1 can be if redir file can't be opened */
8481 8898
@@ -9528,14 +9945,13 @@ int hush_main(int argc, char **argv)
9528 9945
9529 /* If we are login shell... */ 9946 /* If we are login shell... */
9530 if (flags & OPT_login) { 9947 if (flags & OPT_login) {
9531 FILE *input; 9948 HFILE *input;
9532 debug_printf("sourcing /etc/profile\n"); 9949 debug_printf("sourcing /etc/profile\n");
9533 input = fopen_for_read("/etc/profile"); 9950 input = hfopen("/etc/profile");
9534 if (input != NULL) { 9951 if (input != NULL) {
9535 remember_FILE(input);
9536 install_special_sighandlers(); 9952 install_special_sighandlers();
9537 parse_and_run_file(input); 9953 parse_and_run_file(input);
9538 fclose_and_forget(input); 9954 hfclose(input);
9539 } 9955 }
9540 /* bash: after sourcing /etc/profile, 9956 /* bash: after sourcing /etc/profile,
9541 * tries to source (in the given order): 9957 * tries to source (in the given order):
@@ -9548,7 +9964,7 @@ int hush_main(int argc, char **argv)
9548 9964
9549 /* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */ 9965 /* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */
9550 if (!(flags & OPT_s) && G.global_argv[1]) { 9966 if (!(flags & OPT_s) && G.global_argv[1]) {
9551 FILE *input; 9967 HFILE *input;
9552 /* 9968 /*
9553 * "bash <script>" (which is never interactive (unless -i?)) 9969 * "bash <script>" (which is never interactive (unless -i?))
9554 * sources $BASH_ENV here (without scanning $PATH). 9970 * sources $BASH_ENV here (without scanning $PATH).
@@ -9559,13 +9975,15 @@ int hush_main(int argc, char **argv)
9559 G.global_argv++; 9975 G.global_argv++;
9560 debug_printf("running script '%s'\n", G.global_argv[0]); 9976 debug_printf("running script '%s'\n", G.global_argv[0]);
9561 xfunc_error_retval = 127; /* for "hush /does/not/exist" case */ 9977 xfunc_error_retval = 127; /* for "hush /does/not/exist" case */
9562 input = xfopen_for_read(G.global_argv[0]); 9978 input = hfopen(G.global_argv[0]);
9979 if (!input) {
9980 bb_simple_perror_msg_and_die(G.global_argv[0]);
9981 }
9563 xfunc_error_retval = 1; 9982 xfunc_error_retval = 1;
9564 remember_FILE(input);
9565 install_special_sighandlers(); 9983 install_special_sighandlers();
9566 parse_and_run_file(input); 9984 parse_and_run_file(input);
9567#if ENABLE_FEATURE_CLEAN_UP 9985#if ENABLE_FEATURE_CLEAN_UP
9568 fclose_and_forget(input); 9986 hfclose(input);
9569#endif 9987#endif
9570 goto final_return; 9988 goto final_return;
9571 } 9989 }
@@ -9666,7 +10084,7 @@ int hush_main(int argc, char **argv)
9666 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); 10084 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
9667 if (G_interactive_fd < 0) { 10085 if (G_interactive_fd < 0) {
9668 /* try to dup to any fd */ 10086 /* try to dup to any fd */
9669 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO); 10087 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1);
9670 if (G_interactive_fd < 0) 10088 if (G_interactive_fd < 0)
9671 /* give up */ 10089 /* give up */
9672 G_interactive_fd = 0; 10090 G_interactive_fd = 0;
@@ -9695,7 +10113,7 @@ int hush_main(int argc, char **argv)
9695 ); 10113 );
9696 } 10114 }
9697 10115
9698 parse_and_run_file(stdin); 10116 parse_and_run_file(hfopen(NULL)); /* stdin */
9699 10117
9700 final_return: 10118 final_return:
9701 hush_exit(G.last_exitcode); 10119 hush_exit(G.last_exitcode);
@@ -9803,41 +10221,41 @@ static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM)
9803 10221
9804static int FAST_FUNC builtin_eval(char **argv) 10222static int FAST_FUNC builtin_eval(char **argv)
9805{ 10223{
9806 int rcode = EXIT_SUCCESS;
9807
9808 argv = skip_dash_dash(argv); 10224 argv = skip_dash_dash(argv);
9809 if (argv[0]) {
9810 char *str = NULL;
9811 10225
9812 if (argv[1]) { 10226 if (!argv[0])
9813 /* "The eval utility shall construct a command by 10227 return EXIT_SUCCESS;
9814 * concatenating arguments together, separating
9815 * each with a <space> character."
9816 */
9817 char *p;
9818 unsigned len = 0;
9819 char **pp = argv;
9820 do
9821 len += strlen(*pp) + 1;
9822 while (*++pp);
9823 str = p = xmalloc(len);
9824 pp = argv;
9825 do {
9826 p = stpcpy(p, *pp);
9827 *p++ = ' ';
9828 } while (*++pp);
9829 p[-1] = '\0';
9830 }
9831 10228
10229 if (!argv[1]) {
9832 /* bash: 10230 /* bash:
9833 * eval "echo Hi; done" ("done" is syntax error): 10231 * eval "echo Hi; done" ("done" is syntax error):
9834 * "echo Hi" will not execute too. 10232 * "echo Hi" will not execute too.
9835 */ 10233 */
9836 parse_and_run_string(str ? str : argv[0]); 10234 parse_and_run_string(argv[0]);
10235 } else {
10236 /* "The eval utility shall construct a command by
10237 * concatenating arguments together, separating
10238 * each with a <space> character."
10239 */
10240 char *str, *p;
10241 unsigned len = 0;
10242 char **pp = argv;
10243 do
10244 len += strlen(*pp) + 1;
10245 while (*++pp);
10246 str = p = xmalloc(len);
10247 pp = argv;
10248 for (;;) {
10249 p = stpcpy(p, *pp);
10250 pp++;
10251 if (!*pp)
10252 break;
10253 *p++ = ' ';
10254 }
10255 parse_and_run_string(str);
9837 free(str); 10256 free(str);
9838 rcode = G.last_exitcode;
9839 } 10257 }
9840 return rcode; 10258 return G.last_exitcode;
9841} 10259}
9842 10260
9843static int FAST_FUNC builtin_exec(char **argv) 10261static int FAST_FUNC builtin_exec(char **argv)
@@ -10506,7 +10924,7 @@ Test that VAR is a valid variable name?
10506static int FAST_FUNC builtin_source(char **argv) 10924static int FAST_FUNC builtin_source(char **argv)
10507{ 10925{
10508 char *arg_path, *filename; 10926 char *arg_path, *filename;
10509 FILE *input; 10927 HFILE *input;
10510 save_arg_t sv; 10928 save_arg_t sv;
10511 char *args_need_save; 10929 char *args_need_save;
10512#if ENABLE_HUSH_FUNCTIONS 10930#if ENABLE_HUSH_FUNCTIONS
@@ -10530,10 +10948,10 @@ static int FAST_FUNC builtin_source(char **argv)
10530 return EXIT_FAILURE; 10948 return EXIT_FAILURE;
10531 } 10949 }
10532 } 10950 }
10533 input = remember_FILE(fopen_or_warn(filename, "r")); 10951 input = hfopen(filename);
10534 free(arg_path); 10952 free(arg_path);
10535 if (!input) { 10953 if (!input) {
10536 /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ 10954 bb_perror_msg("%s", filename);
10537 /* POSIX: non-interactive shell should abort here, 10955 /* POSIX: non-interactive shell should abort here,
10538 * not merely fail. So far no one complained :) 10956 * not merely fail. So far no one complained :)
10539 */ 10957 */
@@ -10552,7 +10970,7 @@ static int FAST_FUNC builtin_source(char **argv)
10552 /* "false; . ./empty_line; echo Zero:$?" should print 0 */ 10970 /* "false; . ./empty_line; echo Zero:$?" should print 0 */
10553 G.last_exitcode = 0; 10971 G.last_exitcode = 0;
10554 parse_and_run_file(input); 10972 parse_and_run_file(input);
10555 fclose_and_forget(input); 10973 hfclose(input);
10556 10974
10557 if (args_need_save) /* can't use argv[1] instead: "shift" can mangle it */ 10975 if (args_need_save) /* can't use argv[1] instead: "shift" can mangle it */
10558 restore_G_args(&sv, argv); 10976 restore_G_args(&sv, argv);
diff --git a/shell/hush_test/hush-glob/glob_altvalue1.right b/shell/hush_test/hush-glob/glob_altvalue1.right
new file mode 100644
index 000000000..bd3592229
--- /dev/null
+++ b/shell/hush_test/hush-glob/glob_altvalue1.right
@@ -0,0 +1,7 @@
11u: glob_altvalue1.tests
22u: glob_altvalue1.t*
33u: glob_altvalue1.t*
44u: glob_altvalue1.t*
51q: glob_altvalue1.t*
62q: 'glob_altvalue1.t*'
73q: glob_altvalue1.t*
diff --git a/shell/hush_test/hush-glob/glob_altvalue1.tests b/shell/hush_test/hush-glob/glob_altvalue1.tests
new file mode 100755
index 000000000..5483d63e6
--- /dev/null
+++ b/shell/hush_test/hush-glob/glob_altvalue1.tests
@@ -0,0 +1,13 @@
1x=x
2
3echo 1u: ${x:+glob_altvalue1.t*}
4echo 2u: ${x:+'glob_altvalue1.t*'}
5echo 3u: ${x:+"glob_altvalue1.t*"}
6echo 4u: ${x:+glob_altvalue1.t\*}
7##echo 5u: ${x:+"glob_altvalue1.t\*"}
8
9echo 1q: "${x:+glob_altvalue1.t*}"
10echo 2q: "${x:+'glob_altvalue1.t*'}"
11echo 3q: "${x:+"glob_altvalue1.t*"}"
12##echo 4q: "${x:+glob_altvalue1.t\*}"
13##echo 5q: "${x:+"glob_altvalue1.t\*"}"
diff --git a/shell/hush_test/hush-heredoc/heredoc.right b/shell/hush_test/hush-heredoc/heredoc.right
new file mode 100644
index 000000000..9b9e2aae9
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc.right
@@ -0,0 +1,20 @@
1there
2one - alpha
3two - beta
4three - gamma
5hi\
6there$a
7stuff
8hi\
9there
10EO\
11F
12hi
13hi
14tab 1
15tab 2
16tab 3
17abc
18def ghi
19jkl mno
20fff is a function
diff --git a/shell/hush_test/hush-heredoc/heredoc.tests b/shell/hush_test/hush-heredoc/heredoc.tests
new file mode 100755
index 000000000..39345c51b
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc.tests
@@ -0,0 +1,97 @@
1# check order and content of multiple here docs
2
3cat << EOF1 << EOF2
4hi
5EOF1
6there
7EOF2
8
9while read line1; do
10 read line2 <&3
11 echo $line1 - $line2
12done <<EOF1 3<<EOF2
13one
14two
15three
16EOF1
17alpha
18beta
19gamma
20EOF2
21
22
23# check quoted here-doc is protected
24
25a=foo
26cat << 'EOF'
27hi\
28there$a
29stuff
30EOF
31
32# check that quoted here-documents don't have \newline processing done
33
34cat << 'EOF'
35hi\
36there
37EO\
38F
39EOF
40true
41
42# check that \newline is removed at start of here-doc
43cat << EO\
44F
45hi
46EOF
47
48# check that \newline removal works for here-doc delimiter
49cat << EOF
50hi
51EO\
52F
53
54# check operation of tab removal in here documents
55cat <<- EOF
56 tab 1
57 tab 2
58 tab 3
59 EOF
60
61# check appending of text to file from here document
62rm -f /tmp/bash-zzz
63cat > /tmp/bash-zzz << EOF
64abc
65EOF
66cat >> /tmp/bash-zzz << EOF
67def ghi
68jkl mno
69EOF
70cat /tmp/bash-zzz
71rm -f /tmp/bash-zzz
72
73# make sure command printing puts the here-document as the last redirection
74# on the line, and the function export code preserves syntactic correctness
75fff()
76{
77 ed /tmp/foo <<ENDOFINPUT >/dev/null
78/^name/d
79w
80q
81ENDOFINPUT
82aa=1
83}
84
85type fff
86#ash# export -f fff
87#ash# ${THIS_SH} -c 'type fff'
88
89#hush# bash warns: "here-document at line N delimited by end-of-file",
90#hush# ash allows it,
91#hush# hush errors out for now:
92#hush# # check that end of file delimits a here-document
93#hush# # THIS MUST BE LAST!
94#hush#
95#hush# cat << EOF
96#hush# hi
97#hush# there
diff --git a/shell/hush_test/hush-heredoc/heredoc9.right b/shell/hush_test/hush-heredoc/heredoc9.right
new file mode 100644
index 000000000..ce0136250
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc9.right
@@ -0,0 +1 @@
hello
diff --git a/shell/hush_test/hush-heredoc/heredoc9.tests b/shell/hush_test/hush-heredoc/heredoc9.tests
new file mode 100755
index 000000000..96c227cc1
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc9.tests
@@ -0,0 +1,9 @@
1echo hello >greeting
2cat <<EOF &&
3$(cat greeting)
4EOF
5{
6 echo $?
7 cat greeting
8} >/dev/null
9rm greeting
diff --git a/shell/hush_test/hush-heredoc/heredocA.right b/shell/hush_test/hush-heredoc/heredocA.right
new file mode 100644
index 000000000..7326d9603
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredocA.right
@@ -0,0 +1 @@
Ok
diff --git a/shell/hush_test/hush-heredoc/heredocA.tests b/shell/hush_test/hush-heredoc/heredocA.tests
new file mode 100755
index 000000000..440aaf906
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredocA.tests
@@ -0,0 +1,4 @@
1{ cat <<EOF ;
2Ok
3EOF
4}
diff --git a/shell/hush_test/hush-heredoc/heredocB.right b/shell/hush_test/hush-heredoc/heredocB.right
new file mode 100644
index 000000000..43ba0b4f9
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredocB.right
@@ -0,0 +1,3 @@
1one - alpha
2two - beta
3three - gamma
diff --git a/shell/hush_test/hush-heredoc/heredocB.tests b/shell/hush_test/hush-heredoc/heredocB.tests
new file mode 100755
index 000000000..45ea4687f
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredocB.tests
@@ -0,0 +1,12 @@
1while read line1; do
2 read line2 <&3
3 echo $line1 - $line2
4done <<EOF1 3<<EOF2
5one
6two
7three
8EOF1
9alpha
10beta
11gamma
12EOF2
diff --git a/shell/hush_test/hush-heredoc/heredoc_after_compound1.right b/shell/hush_test/hush-heredoc/heredoc_after_compound1.right
new file mode 100644
index 000000000..9052f7d1f
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_after_compound1.right
@@ -0,0 +1,2 @@
1Ok1
2Ok2
diff --git a/shell/hush_test/hush-heredoc/heredoc_after_compound1.tests b/shell/hush_test/hush-heredoc/heredoc_after_compound1.tests
new file mode 100755
index 000000000..e7cfb5be1
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_after_compound1.tests
@@ -0,0 +1,3 @@
1{ cat <<EOF; }; echo Ok2
2Ok1
3EOF
diff --git a/shell/hush_test/hush-heredoc/heredoc_bkslash_newline2.right b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline2.right
new file mode 100644
index 000000000..3d79316d7
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline2.right
@@ -0,0 +1 @@
Ok1
diff --git a/shell/hush_test/hush-heredoc/heredoc_bkslash_newline2.tests b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline2.tests
new file mode 100755
index 000000000..1d2a26504
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_bkslash_newline2.tests
@@ -0,0 +1,4 @@
1cat <<EOF
2Ok1
3EO\
4F
diff --git a/shell/hush_test/hush-heredoc/heredoc_empty3.right b/shell/hush_test/hush-heredoc/heredoc_empty3.right
new file mode 100644
index 000000000..0b54a9c93
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_empty3.right
@@ -0,0 +1,2 @@
1
2Ok
diff --git a/shell/hush_test/hush-heredoc/heredoc_empty3.tests b/shell/hush_test/hush-heredoc/heredoc_empty3.tests
new file mode 100755
index 000000000..828c2dd89
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_empty3.tests
@@ -0,0 +1,4 @@
1cat <<EOF
2
3Ok
4EOF
diff --git a/shell/hush_test/hush-heredoc/heredoc_var_expand1.right b/shell/hush_test/hush-heredoc/heredoc_var_expand1.right
new file mode 100644
index 000000000..eb221832d
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_var_expand1.right
@@ -0,0 +1,4 @@
1
2Ok1:0
3
4Ok2:0
diff --git a/shell/hush_test/hush-heredoc/heredoc_var_expand1.tests b/shell/hush_test/hush-heredoc/heredoc_var_expand1.tests
new file mode 100755
index 000000000..3b00bab7b
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_var_expand1.tests
@@ -0,0 +1,11 @@
1x='*'
2
3cat <<- EOF
4 ${x#'*'}
5EOF
6echo Ok1:$?
7
8cat <<EOF
9${x#'*'}
10EOF
11echo Ok2:$?
diff --git a/shell/hush_test/hush-quoting/dollar_altvalue1.right b/shell/hush_test/hush-quoting/dollar_altvalue1.right
new file mode 100644
index 000000000..5cd495d3b
--- /dev/null
+++ b/shell/hush_test/hush-quoting/dollar_altvalue1.right
@@ -0,0 +1,16 @@
1Unquoted b c d
2|b|
3|c|
4|d|
5Unquoted 'b c' d
6|b c|
7|d|
8Unquoted "b c" d
9|b c|
10|d|
11Quoted b c d
12|b c d|
13Quoted 'b c' d
14|'b c' d|
15Quoted "b c" d
16|b c d|
diff --git a/shell/hush_test/hush-quoting/dollar_altvalue1.tests b/shell/hush_test/hush-quoting/dollar_altvalue1.tests
new file mode 100755
index 000000000..f4dc8caec
--- /dev/null
+++ b/shell/hush_test/hush-quoting/dollar_altvalue1.tests
@@ -0,0 +1,16 @@
1f() { for i; do echo "|$i|"; done; }
2x=a
3
4echo Unquoted b c d
5f ${x:+b c d}
6echo Unquoted "'b c' d"
7f ${x:+'b c' d}
8echo Unquoted '"b c" d'
9f ${x:+"b c" d}
10
11echo Quoted b c d
12f "${x:+b c d}"
13echo Quoted "'b c' d"
14f "${x:+'b c' d}"
15echo Quoted '"b c" d'
16f "${x:+"b c" d}"
diff --git a/shell/hush_test/hush-quoting/dollar_altvalue2.right b/shell/hush_test/hush-quoting/dollar_altvalue2.right
new file mode 100644
index 000000000..7cf37e379
--- /dev/null
+++ b/shell/hush_test/hush-quoting/dollar_altvalue2.right
@@ -0,0 +1,69 @@
1Unquoted '':
2start:
3||
4end
5start:
6||
7end
8start:
9||
10end
11start:
12||
13end
14start:
15||
16||
17end
18
19Unquoted "":
20start:
21||
22end
23start:
24||
25end
26start:
27||
28end
29start:
30||
31end
32start:
33||
34||
35end
36
37Quoted '':
38start:
39|''|
40end
41start:
42|'' |
43end
44start:
45| ''|
46end
47start:
48| '' |
49end
50start:
51|'' ''|
52end
53
54Quoted "":
55start:
56||
57end
58start:
59| |
60end
61start:
62| |
63end
64start:
65| |
66end
67start:
68| |
69end
diff --git a/shell/hush_test/hush-quoting/dollar_altvalue2.tests b/shell/hush_test/hush-quoting/dollar_altvalue2.tests
new file mode 100755
index 000000000..3377eb27f
--- /dev/null
+++ b/shell/hush_test/hush-quoting/dollar_altvalue2.tests
@@ -0,0 +1,33 @@
1f() { echo start:; for i; do echo "|$i|"; done; echo end; }
2x=a
3
4echo "Unquoted '':"
5f ${x:+''}
6f ${x:+'' }
7f ${x:+ ''}
8f ${x:+ '' }
9f ${x:+'' ''}
10
11echo
12echo 'Unquoted "":'
13f ${x:+""}
14f ${x:+"" }
15f ${x:+ ""}
16f ${x:+ "" }
17f ${x:+"" ""}
18
19echo
20echo "Quoted '':"
21f "${x:+''}"
22f "${x:+'' }"
23f "${x:+ ''}"
24f "${x:+ '' }"
25f "${x:+'' ''}"
26
27echo
28echo 'Quoted "":'
29f "${x:+""}"
30f "${x:+"" }"
31f "${x:+ ""}"
32f "${x:+ "" }"
33f "${x:+"" ""}"
diff --git a/shell/hush_test/hush-quoting/dollar_altvalue9.right b/shell/hush_test/hush-quoting/dollar_altvalue9.right
new file mode 100644
index 000000000..39342fe7c
--- /dev/null
+++ b/shell/hush_test/hush-quoting/dollar_altvalue9.right
@@ -0,0 +1,26 @@
1Unquoted 1:
2|a|
3|x y|
4|1|
5|2|
6||
7|1 2|
8|A|
9|B|
10|C D|
11|zb|
12Quoted 1:
13|a 'x y' 1 2 '' 1 2 A B C D zb|
14Unquoted 2:
15|ax y|
16|1|
17|2|
18||
19|1 2|
20|A|
21|B|
22|C D|
23|z|
24|b|
25Quoted 2:
26|a 'x y' 1 2 '' 1 2 A B C D z b|
diff --git a/shell/hush_test/hush-quoting/dollar_altvalue9.tests b/shell/hush_test/hush-quoting/dollar_altvalue9.tests
new file mode 100755
index 000000000..27a6f4f3c
--- /dev/null
+++ b/shell/hush_test/hush-quoting/dollar_altvalue9.tests
@@ -0,0 +1,17 @@
1f() { for i; do echo "|$i|"; done; }
2
3echo Unquoted 1:
4x='1 2'; f a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z}b
5echo Quoted 1:
6x='1 2'; f "a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z}b"
7
8echo Unquoted 2:
9x='1 2'; f a${x:+'x y' $x '' "$x" `echo A B` "`echo C D`" z }b
10echo Quoted 2:
11x='1 2'; f "a${x:+ 'x y' $x '' "$x" `echo A B` "`echo C D`" z }b"
12
13#echo Unquoted 3:
14#e=
15#x='1 2'; f a${x:+'x y' $x '' "$x" $e $e "$e" $e `echo A B` "`echo C D`" z }b
16#echo Quoted 3:
17#x='1 2'; f "a${x:+ 'x y' $x '' "$x" $e $e "$e" $e `echo A B` "`echo C D`" z }b"
diff --git a/shell/hush_test/hush-quoting/dollar_repl_bash1.right b/shell/hush_test/hush-quoting/dollar_repl_bash1.right
new file mode 100644
index 000000000..f5e9309f4
--- /dev/null
+++ b/shell/hush_test/hush-quoting/dollar_repl_bash1.right
@@ -0,0 +1,14 @@
1|y|
2|zx|
3|y|
4|zx|
5|y zx|
6|y zx|
7|y|
8|zy|
9|z|
10|y|
11|zy|
12|z|
13|y zy z|
14|y zy z|
diff --git a/shell/hush_test/hush-quoting/dollar_repl_bash1.tests b/shell/hush_test/hush-quoting/dollar_repl_bash1.tests
new file mode 100755
index 000000000..912635925
--- /dev/null
+++ b/shell/hush_test/hush-quoting/dollar_repl_bash1.tests
@@ -0,0 +1,12 @@
1f() { for i; do echo "|$i|"; done; }
2v=xx
3
4f ${v/'x'/"y z"}
5f ${v/"x"/'y z'}
6f "${v/'x'/"y z"}"
7f "${v/"x"/'y z'}"
8
9f ${v//'x'/"y z"}
10f ${v//"x"/'y z'}
11f "${v//'x'/"y z"}"
12f "${v//"x"/'y z'}"
diff --git a/shell/hush_test/hush-quoting/squote_in_varexp.right b/shell/hush_test/hush-quoting/squote_in_varexp.right
index a75c0bfd6..4a457021b 100644
--- a/shell/hush_test/hush-quoting/squote_in_varexp.right
+++ b/shell/hush_test/hush-quoting/squote_in_varexp.right
@@ -1,5 +1,9 @@
1z 1z
2z 2z
3z
4z
5y
6y
3y 7y
4y 8y
5Ok:0 9Ok:0
diff --git a/shell/hush_test/hush-quoting/squote_in_varexp.tests b/shell/hush_test/hush-quoting/squote_in_varexp.tests
index a2d05a246..4afc52107 100755
--- a/shell/hush_test/hush-quoting/squote_in_varexp.tests
+++ b/shell/hush_test/hush-quoting/squote_in_varexp.tests
@@ -1,6 +1,10 @@
1x=yz 1x=yz
2echo ${x#'y'} 2echo ${x#'y'}
3echo "${x#'y'}" 3echo "${x#'y'}"
4echo ${x#"y"}
5echo "${x#"y"}"
4echo ${x%'z'} 6echo ${x%'z'}
5echo "${x%'z'}" 7echo "${x%'z'}"
8echo ${x%"z"}
9echo "${x%"z"}"
6echo Ok:$? 10echo Ok:$?
diff --git a/shell/hush_test/hush-quoting/squote_in_varexp2.right b/shell/hush_test/hush-quoting/squote_in_varexp2.right
index 9d0add3c5..d03047024 100644
--- a/shell/hush_test/hush-quoting/squote_in_varexp2.right
+++ b/shell/hush_test/hush-quoting/squote_in_varexp2.right
@@ -1,3 +1,5 @@
1Nothing: 1Nothing:
2Nothing: 2Nothing:
3Nothing:
4Nothing:
3Ok:0 5Ok:0
diff --git a/shell/hush_test/hush-quoting/squote_in_varexp2.tests b/shell/hush_test/hush-quoting/squote_in_varexp2.tests
index 806ad12b9..2797725cc 100755
--- a/shell/hush_test/hush-quoting/squote_in_varexp2.tests
+++ b/shell/hush_test/hush-quoting/squote_in_varexp2.tests
@@ -1,4 +1,6 @@
1x='\\\\' 1x='\\\\'
2printf Nothing:'%s\n' ${x#'\\\\'} 2printf Nothing:'%s\n' ${x#'\\\\'}
3printf Nothing:'%s\n' "${x#'\\\\'}" 3printf Nothing:'%s\n' "${x#'\\\\'}"
4printf Nothing:'%s\n' ${x#"\\\\\\\\"}
5printf Nothing:'%s\n' "${x#"\\\\\\\\"}"
4echo Ok:$? 6echo Ok:$?
diff --git a/shell/hush_test/hush-redir/redir_script.tests b/shell/hush_test/hush-redir/redir_script.tests
index 740daa461..a8d93ce4f 100755
--- a/shell/hush_test/hush-redir/redir_script.tests
+++ b/shell/hush_test/hush-redir/redir_script.tests
@@ -27,6 +27,10 @@ test x"$fds1" = x"$fds" \
27test x"$fds1" = x" 10>&- 3>&-" && \ 27test x"$fds1" = x" 10>&- 3>&-" && \
28test x"$fds" = x" 11>&- 3>&-" \ 28test x"$fds" = x" 11>&- 3>&-" \
29&& { echo "Ok: script fd is not closed"; exit 0; } 29&& { echo "Ok: script fd is not closed"; exit 0; }
30# or we see that fd 3 moved to fd 10:
31test x"$fds1" = x" 3>&- 4>&-" && \
32test x"$fds" = x" 10>&- 3>&-" \
33&& { echo "Ok: script fd is not closed"; exit 0; }
30 34
31echo "Bug: script fd is closed" 35echo "Bug: script fd is closed"
32echo "fds1:$fds1" 36echo "fds1:$fds1"
diff --git a/shell/hush_test/hush-z_slow/many_ifs.tests b/shell/hush_test/hush-z_slow/many_ifs.tests
index 1f5b1b3a6..cf9a89874 100755
--- a/shell/hush_test/hush-z_slow/many_ifs.tests
+++ b/shell/hush_test/hush-z_slow/many_ifs.tests
@@ -229,8 +229,8 @@ do
229 '') split "$d0$f1$d1$f2$d2$f3$d3" "[2]($f1)($f2)" "($f1)($f2)" ;; 229 '') split "$d0$f1$d1$f2$d2$f3$d3" "[2]($f1)($f2)" "($f1)($f2)" ;;
230 ' ') ;; 230 ' ') ;;
231 *) x=$f2$d2$f3$d3 231 *) x=$f2$d2$f3$d3
232 x=${x# } #was x=${x#' '} hush needs fixing for this to work 232 x=${x#' '}
233 x=${x% } #was x=${x%' '} 233 x=${x%' '}
234 split "$d0$f1$d1$f2$d2$f3$d3" "[3]($f1)($f2)($f3)" "($f1)($x)" 234 split "$d0$f1$d1$f2$d2$f3$d3" "[3]($f1)($f2)($f3)" "($f1)($x)"
235 ;; 235 ;;
236 esac 236 esac
diff --git a/shell/random.c b/shell/random.c
index 614172279..ffe0cc937 100644
--- a/shell/random.c
+++ b/shell/random.c
@@ -57,11 +57,11 @@ next_random(random_t *rnd)
57 * Choices for a,b,c: 10,13,10; 8,9,22; 2,7,3; 23,3,24 57 * Choices for a,b,c: 10,13,10; 8,9,22; 2,7,3; 23,3,24
58 * (given by algorithm author) 58 * (given by algorithm author)
59 */ 59 */
60 enum { 60 enum {
61 a = 2, 61 a = 2,
62 b = 7, 62 b = 7,
63 c = 3, 63 c = 3,
64 }; 64 };
65 65
66 uint32_t t; 66 uint32_t t;
67 67
@@ -165,7 +165,7 @@ int main(int argc, char **argv)
165 write(1, buf, sizeof(buf)); 165 write(1, buf, sizeof(buf));
166 } 166 }
167 167
168 return 0; 168 return 0;
169} 169}
170 170
171#endif 171#endif
diff --git a/sysklogd/Config.src b/sysklogd/Config.src
index 684e7d414..321be0117 100644
--- a/sysklogd/Config.src
+++ b/sysklogd/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "System Logging Utilities" 6menu "System Logging Utilities"
diff --git a/testsuite/bzcat.tests b/testsuite/bzcat.tests
index 32c1c5d7f..ad05dcb2c 100755
--- a/testsuite/bzcat.tests
+++ b/testsuite/bzcat.tests
@@ -30,10 +30,11 @@ hello_bz2() {
30 $ECHO -ne "\x17\x72\x45\x38\x50\x90\x5b\xb8\xe8\xa3" 30 $ECHO -ne "\x17\x72\x45\x38\x50\x90\x5b\xb8\xe8\xa3"
31} 31}
32 32
33test x"$CONFIG_ZCAT" = x"y" && \
33for ext in \ 34for ext in \
34 `test x"$CONFIG_GUNZIP" = x"y" && echo gz` \ 35 `test x"$CONFIG_FEATURE_SEAMLESS_GZ" = x"y" && echo gz` \
35 `test x"$CONFIG_BUNZIP2" = x"y" && echo bz2` \ 36 `test x"$CONFIG_FEATURE_SEAMLESS_BZ2" = x"y" && echo bz2` \
36 `test x"$CONFIG_UNCOMPRESS" = x"y" && echo Z` 37 `test x"$CONFIG_FEATURE_SEAMLESS_Z" = x"y" && echo Z`
37do 38do
38 prep() { 39 prep() {
39 rm -f t1.$ext t2.$ext t_actual 40 rm -f t1.$ext t2.$ext t_actual
@@ -47,6 +48,8 @@ do
47 echo "PASS: $1" 48 echo "PASS: $1"
48 else 49 else
49 echo "FAIL: $1" 50 echo "FAIL: $1"
51 #echo "t_actual:"
52 #cat t_actual
50 FAILCOUNT=$((FAILCOUNT + 1)) 53 FAILCOUNT=$((FAILCOUNT + 1))
51 fi 54 fi
52 } 55 }
@@ -95,7 +98,8 @@ testing "bzcat can handle compressed zero-length bzip2 files" \
95## compress algorithm 98## compress algorithm
96 99
97# "input" file is compressed (.Z) file with "a\n" data 100# "input" file is compressed (.Z) file with "a\n" data
98test x"$CONFIG_UNCOMPRESS" = x"y" && \ 101test x"$CONFIG_ZCAT" = x"y" && \
102test x"$CONFIG_FEATURE_SEAMLESS_Z" = x"y" && \
99testing "zcat can print many files" \ 103testing "zcat can print many files" \
100"zcat input input; echo \$?" \ 104"zcat input input; echo \$?" \
101"\ 105"\
@@ -107,7 +111,8 @@ a
107" "" 111" ""
108 112
109# "input" file is compressed (.Z) zero byte file 113# "input" file is compressed (.Z) zero byte file
110test x"$CONFIG_UNCOMPRESS" = x"y" && \ 114test x"$CONFIG_ZCAT" = x"y" && \
115test x"$CONFIG_FEATURE_SEAMLESS_Z" = x"y" && \
111testing "zcat can handle compressed zero-length (.Z) files" \ 116testing "zcat can handle compressed zero-length (.Z) files" \
112"zcat input input; echo \$?" \ 117"zcat input input; echo \$?" \
113"0\n" \ 118"0\n" \
diff --git a/testsuite/cat.tests b/testsuite/cat.tests
index 404ebedeb..10970dc90 100755
--- a/testsuite/cat.tests
+++ b/testsuite/cat.tests
@@ -6,16 +6,20 @@
6. ./testing.sh 6. ./testing.sh
7 7
8# testing "description" "command" "result" "infile" "stdin" 8# testing "description" "command" "result" "infile" "stdin"
9optional FEATURE_CATV
9testing 'cat -e' \ 10testing 'cat -e' \
10 'cat -e' \ 11 'cat -e' \
11 'foo$\n' \ 12 'foo$\n' \
12 '' \ 13 '' \
13 'foo\n' 14 'foo\n'
15SKIP=
14 16
17optional FEATURE_CATV
15testing 'cat -v' \ 18testing 'cat -v' \
16 'cat -v' \ 19 'cat -v' \
17 'foo\n' \ 20 'foo\n' \
18 '' \ 21 '' \
19 'foo\n' 22 'foo\n'
23SKIP=
20 24
21exit $FAILCOUNT 25exit $FAILCOUNT
diff --git a/testsuite/hexdump.tests b/testsuite/hexdump.tests
new file mode 100755
index 000000000..45a0c1300
--- /dev/null
+++ b/testsuite/hexdump.tests
@@ -0,0 +1,18 @@
1#!/bin/sh
2
3# Copyright 2018 by Denys Vlasenko <vda.linux@googlemail.com>
4# Licensed under GPLv2, see file LICENSE in this source tree.
5
6. ./testing.sh
7
8# testing "description" "command" "result" "infile" "stdin"
9testing 'hexdump -C with four NULs' \
10 'hexdump -C' \
11 "\
1200000000 00 00 00 00 |....|
1300000004
14" \
15 '' \
16 '\0\0\0\0'
17
18exit $FAILCOUNT
diff --git a/testsuite/mount.tests b/testsuite/mount.tests
index a0bc50888..91c2e8b42 100755
--- a/testsuite/mount.tests
+++ b/testsuite/mount.tests
@@ -10,9 +10,11 @@ test "`id -u`" = 0 || {
10 exit 0 10 exit 0
11} 11}
12 12
13# Without MOUNT_LOOP_CREATE, the test will fail if /dev/loopN's do not exist
13if test x"$CONFIG_MKFS_MINIX" != x"y" \ 14if test x"$CONFIG_MKFS_MINIX" != x"y" \
14|| test x"$CONFIG_FEATURE_MINIX2" != x"y" \ 15|| test x"$CONFIG_FEATURE_MINIX2" != x"y" \
15|| test x"$CONFIG_FEATURE_MOUNT_LOOP" != x"y" \ 16|| test x"$CONFIG_FEATURE_MOUNT_LOOP" != x"y" \
17|| test x"$CONFIG_FEATURE_MOUNT_LOOP_CREATE" != x"y" \
16|| test x"$CONFIG_FEATURE_MOUNT_FLAGS" != x"y" \ 18|| test x"$CONFIG_FEATURE_MOUNT_FLAGS" != x"y" \
17|| test x"$CONFIG_FEATURE_DEVFS" = x"y" \ 19|| test x"$CONFIG_FEATURE_DEVFS" = x"y" \
18; then 20; then
diff --git a/testsuite/pidof.tests b/testsuite/pidof.tests
index 2a06d2b1c..cd10de4e0 100755
--- a/testsuite/pidof.tests
+++ b/testsuite/pidof.tests
@@ -18,15 +18,22 @@ testing "pidof (exit with success)" "pidof pidof > /dev/null; echo \$?" \
18 18
19testing "pidof this" "pidof pidof.tests | grep -o -w $$" "$$\n" "" "" 19testing "pidof this" "pidof pidof.tests | grep -o -w $$" "$$\n" "" ""
20 20
21test x"`cat /proc/1/comm`" = x"init" && {
21optional FEATURE_PIDOF_SINGLE 22optional FEATURE_PIDOF_SINGLE
22testing "pidof -s" "pidof -s init" "1\n" "" "" 23testing "pidof -s" "pidof -s init" "1\n" "" ""
23SKIP= 24SKIP=
25}
24 26
27test x"`cat /proc/1/comm`" = x"init" && {
25optional FEATURE_PIDOF_OMIT FEATURE_PIDOF_SINGLE 28optional FEATURE_PIDOF_OMIT FEATURE_PIDOF_SINGLE
26# This test fails now because process name matching logic has changed, 29# This test fails now because process name matching logic has changed,
27# but new logic is not "wrong" either... see find_pid_by_name.c comments 30# but new logic is not "wrong" either... see find_pid_by_name.c comments
28#testing "pidof -o %PPID" "pidof -o %PPID pidof.tests | grep -o -w $$" "" "" "" 31#testing "pidof -o %PPID" "pidof -o %PPID pidof.tests | grep -o -w $$" "" "" ""
29testing "pidof -o %PPID NOP" "pidof -o %PPID -s init" "1\n" "" "" 32testing "pidof -o %PPID NOP" "pidof -o %PPID -s init" "1\n" "" ""
33SKIP=
34}
35
36optional FEATURE_PIDOF_OMIT
30testing "pidof -o init" "pidof -o 1 init | grep -o -w 1" "" "" "" 37testing "pidof -o init" "pidof -o 1 init | grep -o -w 1" "" "" ""
31SKIP= 38SKIP=
32 39
diff --git a/testsuite/tar.tests b/testsuite/tar.tests
index 1675b07b1..d71a34910 100755
--- a/testsuite/tar.tests
+++ b/testsuite/tar.tests
@@ -336,7 +336,7 @@ SKIP=
336cd .. || exit 1; rm -rf tar.tempdir 2>/dev/null 336cd .. || exit 1; rm -rf tar.tempdir 2>/dev/null
337 337
338mkdir tar.tempdir && cd tar.tempdir || exit 1 338mkdir tar.tempdir && cd tar.tempdir || exit 1
339optional FEATURE_SEAMLESS_BZ2 FEATURE_TAR_AUTODETECT 339optional FEATURE_SEAMLESS_BZ2 FEATURE_TAR_AUTODETECT LS
340testing "Symlink attack: create symlink and then write through it" '\ 340testing "Symlink attack: create symlink and then write through it" '\
341exec 2>&1 341exec 2>&1
342uudecode -o input && tar xvf input; echo $? 342uudecode -o input && tar xvf input; echo $?
@@ -365,4 +365,22 @@ n8fYaKlioCTzL2oXYczyUUIP4u5IpwoSEwWdtoA=
365SKIP= 365SKIP=
366cd .. || exit 1; rm -rf tar.tempdir 2>/dev/null 366cd .. || exit 1; rm -rf tar.tempdir 2>/dev/null
367 367
368mkdir tar.tempdir && cd tar.tempdir || exit 1
369optional FEATURE_TAR_CREATE
370testing "Symlinks and hardlinks coexist" '\
371mkdir dir
372>dir/a
373ln -s ../dir/a dir/b
374ln dir/b dir/c
375mkdir new
376tar cf - dir/* | tar -C new -xvf - 2>&1
377' "\
378dir/a
379dir/b
380dir/c
381" \
382"" ""
383SKIP=
384cd .. || exit 1; rm -rf tar.tempdir 2>/dev/null
385
368exit $FAILCOUNT 386exit $FAILCOUNT
diff --git a/testsuite/unexpand/unexpand-works-like-GNU b/testsuite/unexpand/unexpand-works-like-GNU
index a5258363f..111b277b5 100644
--- a/testsuite/unexpand/unexpand-works-like-GNU
+++ b/testsuite/unexpand/unexpand-works-like-GNU
@@ -1,3 +1,7 @@
1# coreutils 8.25 often says "input line is too long"
2# on ELF executables. In this case, do not run the test:
3unexpand ../../busybox >/dev/null || exit 0
4
1rm -f foo bar 5rm -f foo bar
2echo " y" | unexpand ../../busybox > foo 6echo " y" | unexpand ../../busybox > foo
3echo " y" | busybox unexpand ../../busybox > bar 7echo " y" | busybox unexpand ../../busybox > bar
diff --git a/testsuite/unzip.tests b/testsuite/unzip.tests
index 6bcb6b3a2..af53de9df 100755
--- a/testsuite/unzip.tests
+++ b/testsuite/unzip.tests
@@ -14,7 +14,7 @@
14# Create a scratch directory 14# Create a scratch directory
15 15
16mkdir temp 16mkdir temp
17cd temp || exit 90 17cd temp || exit $?
18 18
19# Create test file to work with. 19# Create test file to work with.
20 20
@@ -54,9 +54,22 @@ SKIP=
54 54
55rm -f * 55rm -f *
56 56
57optional CONFIG_FEATURE_UNZIP_LZMA 57optional FEATURE_UNZIP_LZMA
58testing "unzip (archive with corrupted lzma)" "unzip -p ../unzip_bad_lzma_1.zip 2>&1; echo \$?" \ 58testing "unzip (archive with corrupted lzma 1)" "unzip -p ../unzip_bad_lzma_1.zip 2>&1; echo \$?" \
59"unzip: removing leading '/' from member names 59"unzip: removing leading '/' from member names
60unzip: corrupted data
61unzip: inflate error
621
63" \
64"" ""
65SKIP=
66
67rm -f *
68
69optional FEATURE_UNZIP_LZMA
70testing "unzip (archive with corrupted lzma 2)" "unzip -p ../unzip_bad_lzma_2.zip 2>&1; echo \$?" \
71"unzip: removing leading '/' from member names
72unzip: corrupted data
60unzip: inflate error 73unzip: inflate error
611 741
62" \ 75" \
diff --git a/testsuite/unzip_bad_lzma_2.zip b/testsuite/unzip_bad_lzma_2.zip
new file mode 100644
index 000000000..cdb917088
--- /dev/null
+++ b/testsuite/unzip_bad_lzma_2.zip
Binary files differ
diff --git a/util-linux/Config.src b/util-linux/Config.src
index 68fcc266f..0fad3e5c0 100644
--- a/util-linux/Config.src
+++ b/util-linux/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6menu "Linux System Utilities" 6menu "Linux System Utilities"
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c
index 7275535e6..cdcba0a03 100644
--- a/util-linux/fdisk.c
+++ b/util-linux/fdisk.c
@@ -2004,12 +2004,6 @@ check_consistency(const struct partition *p, int partition)
2004 printf(" phys=(%u,%u,%u) ", pec, peh, pes); 2004 printf(" phys=(%u,%u,%u) ", pec, peh, pes);
2005 printf("logical=(%u,%u,%u)\n", lec, leh, les); 2005 printf("logical=(%u,%u,%u)\n", lec, leh, les);
2006 } 2006 }
2007
2008/* Ending on cylinder boundary? */
2009 if (peh != (g_heads - 1) || pes != g_sectors) {
2010 printf("Partition %u does not end on cylinder boundary\n",
2011 partition + 1);
2012 }
2013} 2007}
2014 2008
2015static void 2009static void
diff --git a/util-linux/fdisk_sgi.c b/util-linux/fdisk_sgi.c
index 30def09c6..1cf0af5cc 100644
--- a/util-linux/fdisk_sgi.c
+++ b/util-linux/fdisk_sgi.c
@@ -425,7 +425,7 @@ create_sgiinfo(void)
425 /* I keep SGI's habit to write the sgilabel to the second block */ 425 /* I keep SGI's habit to write the sgilabel to the second block */
426 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2); 426 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
427 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo)); 427 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
428 strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8); 428 memcpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
429} 429}
430 430
431static sgiinfo *fill_sgiinfo(void); 431static sgiinfo *fill_sgiinfo(void);
diff --git a/util-linux/mkfs_vfat.c b/util-linux/mkfs_vfat.c
index 26a919536..92f0e3b1a 100644
--- a/util-linux/mkfs_vfat.c
+++ b/util-linux/mkfs_vfat.c
@@ -522,7 +522,7 @@ int mkfs_vfat_main(int argc UNUSED_PARAM, char **argv)
522 //STORE_LE(boot_blk->reserved2[3], 0,0,0); 522 //STORE_LE(boot_blk->reserved2[3], 0,0,0);
523 STORE_LE(boot_blk->vi.ext_boot_sign, 0x29); 523 STORE_LE(boot_blk->vi.ext_boot_sign, 0x29);
524 STORE_LE(boot_blk->vi.volume_id32, volume_id); 524 STORE_LE(boot_blk->vi.volume_id32, volume_id);
525 strncpy(boot_blk->vi.fs_type, "FAT32 ", sizeof(boot_blk->vi.fs_type)); 525 memcpy(boot_blk->vi.fs_type, "FAT32 ", sizeof(boot_blk->vi.fs_type));
526 strncpy(boot_blk->vi.volume_label, volume_label, sizeof(boot_blk->vi.volume_label)); 526 strncpy(boot_blk->vi.volume_label, volume_label, sizeof(boot_blk->vi.volume_label));
527 memcpy(boot_blk->boot_code, boot_code, sizeof(boot_code)); 527 memcpy(boot_blk->boot_code, boot_code, sizeof(boot_code));
528 STORE_LE(boot_blk->boot_sign, BOOT_SIGN); 528 STORE_LE(boot_blk->boot_sign, BOOT_SIGN);
diff --git a/util-linux/nsenter.c b/util-linux/nsenter.c
index c6933c8d5..ae8103a52 100644
--- a/util-linux/nsenter.c
+++ b/util-linux/nsenter.c
@@ -105,14 +105,14 @@ static const struct namespace_descr ns_list[] = {
105/* 105/*
106 * Upstream nsenter doesn't support the short option for --preserve-credentials 106 * Upstream nsenter doesn't support the short option for --preserve-credentials
107 */ 107 */
108static const char opt_str[] ALIGN1 = "U::i::u::n::p::m::""t+S+G+r::w::F"; 108static const char opt_str[] ALIGN1 = "U::i::u::n::p::m::""t:+S:+G:+r::w::F";
109 109
110#if ENABLE_LONG_OPTS 110#if ENABLE_LONG_OPTS
111static const char nsenter_longopts[] ALIGN1 = 111static const char nsenter_longopts[] ALIGN1 =
112 "user\0" Optional_argument "U" 112 "user\0" Optional_argument "U"
113 "ipc\0" Optional_argument "i" 113 "ipc\0" Optional_argument "i"
114 "uts\0" Optional_argument "u" 114 "uts\0" Optional_argument "u"
115 "network\0" Optional_argument "n" 115 "net\0" Optional_argument "n"
116 "pid\0" Optional_argument "p" 116 "pid\0" Optional_argument "p"
117 "mount\0" Optional_argument "m" 117 "mount\0" Optional_argument "m"
118 "target\0" Required_argument "t" 118 "target\0" Required_argument "t"
diff --git a/util-linux/unshare.c b/util-linux/unshare.c
index 7c295da1f..fffee28a0 100644
--- a/util-linux/unshare.c
+++ b/util-linux/unshare.c
@@ -73,7 +73,7 @@
73#include "libbb.h" 73#include "libbb.h"
74 74
75static void mount_or_die(const char *source, const char *target, 75static void mount_or_die(const char *source, const char *target,
76 const char *fstype, unsigned long mountflags) 76 const char *fstype, unsigned long mountflags)
77{ 77{
78 if (mount(source, target, fstype, mountflags, NULL)) { 78 if (mount(source, target, fstype, mountflags, NULL)) {
79 bb_perror_msg_and_die("can't mount %s on %s (flags:0x%lx)", 79 bb_perror_msg_and_die("can't mount %s on %s (flags:0x%lx)",
diff --git a/util-linux/volume_id/Config.src b/util-linux/volume_id/Config.src
index ac208c9cc..fe3b14a71 100644
--- a/util-linux/volume_id/Config.src
+++ b/util-linux/volume_id/Config.src
@@ -1,6 +1,6 @@
1# 1#
2# For a description of the syntax of this configuration file, 2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt. 3# see docs/Kconfig-language.txt.
4# 4#
5 5
6config VOLUMEID 6config VOLUMEID