aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 11:41:16 +1000
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-14 11:41:16 +1000
commit743d85e7d1c2a721baf020b9d79f45f0df2420a9 (patch)
tree9e551b726ac2bf9fd8eafb2764e7237f352bb429
parent87911f4fcd86f7abc0aefba8e9cbec2ac9d127e4 (diff)
parentc7f95d23f6bc7e17a3b79decf83eb362b389e53a (diff)
downloadbusybox-w32-743d85e7d1c2a721baf020b9d79f45f0df2420a9.tar.gz
busybox-w32-743d85e7d1c2a721baf020b9d79f45f0df2420a9.tar.bz2
busybox-w32-743d85e7d1c2a721baf020b9d79f45f0df2420a9.zip
Merge branch 'origin/master' (early part)
-rw-r--r--Config.in11
-rw-r--r--Makefile11
-rw-r--r--archival/cpio.c3
-rw-r--r--archival/libunarchive/get_header_tar.c111
-rw-r--r--archival/rpm.c115
-rw-r--r--archival/rpm.h38
-rw-r--r--archival/rpm2cpio.c69
-rw-r--r--console-tools/clear.c3
-rw-r--r--console-tools/reset.c10
-rw-r--r--coreutils/Kbuild1
-rw-r--r--debianutils/run_parts.c1
-rw-r--r--e2fsprogs/Config.in12
-rw-r--r--e2fsprogs/Kbuild3
-rw-r--r--e2fsprogs/tune2fs.c (renamed from util-linux/tune2fs.c)7
-rw-r--r--editors/Config.in12
-rw-r--r--editors/cmp.c26
-rw-r--r--editors/sed.c26
-rw-r--r--editors/vi.c41
-rw-r--r--findutils/.gitignore3
-rw-r--r--findutils/Config.in253
-rw-r--r--findutils/Config.src10
-rw-r--r--findutils/Kbuild.src (renamed from findutils/Kbuild)5
-rw-r--r--findutils/find.c184
-rw-r--r--findutils/grep.c47
-rw-r--r--findutils/xargs.c41
-rw-r--r--include/applets.h8
-rw-r--r--include/libbb.h9
-rw-r--r--include/unicode.h18
-rw-r--r--include/usage.h77
-rw-r--r--init/Config.in14
-rw-r--r--init/Kbuild7
-rw-r--r--init/bootchartd.c356
-rw-r--r--libbb/appletlib.c73
-rw-r--r--libbb/lineedit.c320
-rw-r--r--libbb/read.c103
-rw-r--r--libbb/read_key.c2
-rw-r--r--libbb/time.c10
-rw-r--r--libbb/unicode.c40
-rw-r--r--libbb/xfuncs.c54
-rw-r--r--miscutils/Config.in11
-rw-r--r--miscutils/Kbuild1
-rw-r--r--miscutils/fbsplash.c4
-rw-r--r--miscutils/less.c10
-rw-r--r--miscutils/rfkill.c120
-rw-r--r--miscutils/setsid.c21
-rw-r--r--networking/Config.in4
-rw-r--r--networking/dnsd.c11
-rw-r--r--networking/ftpd.c4
-rw-r--r--networking/ifplugd.c103
-rw-r--r--networking/ifupdown.c6
-rw-r--r--networking/route.c2
-rw-r--r--networking/telnet.c17
-rw-r--r--networking/telnetd.c2
-rw-r--r--networking/udhcp/leases.c2
-rw-r--r--procps/ps.c2
-rw-r--r--procps/top.c8
-rw-r--r--procps/watch.c3
-rw-r--r--scripts/Makefile.clean2
-rwxr-xr-xscripts/gen_build_files.sh59
-rwxr-xr-xscripts/randomtest130
-rwxr-xr-xscripts/randomtest.loop36
-rw-r--r--shell/Config.in15
-rw-r--r--shell/README190
-rw-r--r--shell/ash.c111
-rw-r--r--shell/ash_test/ash-misc/source2.right1
-rwxr-xr-xshell/ash_test/ash-misc/source2.tests3
-rwxr-xr-xshell/ash_test/ash-redir/redir3.tests2
-rwxr-xr-xshell/ash_test/ash-redir/redir7.tests2
-rwxr-xr-xshell/ash_test/ash-redir/redir8.tests2
-rw-r--r--shell/ash_test/ash-signals/signal5.right12
-rwxr-xr-xshell/ash_test/ash-signals/signal5.tests14
-rw-r--r--shell/ash_test/ash-signals/signal6.right2
-rwxr-xr-xshell/ash_test/ash-signals/signal6.tests2
-rw-r--r--shell/ash_test/ash-vars/var_leak.right3
-rwxr-xr-xshell/ash_test/ash-vars/var_leak.tests19
-rw-r--r--shell/cttyhack.c43
-rw-r--r--shell/hush.c58
-rw-r--r--shell/hush_test/hush-parsing/group2.right2
-rwxr-xr-xshell/hush_test/hush-parsing/group2.tests3
-rwxr-xr-xtestsuite/ar.tests4
-rwxr-xr-xtestsuite/ash.tests30
-rwxr-xr-xtestsuite/awk.tests8
-rwxr-xr-xtestsuite/busybox.tests7
-rwxr-xr-xtestsuite/cpio.tests14
-rw-r--r--testsuite/cut/cut-cuts-a-field2
-rw-r--r--testsuite/date/date-R-works9
-rwxr-xr-xtestsuite/diff.tests10
-rw-r--r--testsuite/du/du-h-works8
-rw-r--r--testsuite/du/du-k-works8
-rw-r--r--testsuite/du/du-l-works12
-rw-r--r--testsuite/du/du-m-works8
-rw-r--r--testsuite/du/du-s-works6
-rw-r--r--testsuite/du/du-works6
-rw-r--r--testsuite/echo/echo-does-not-print-newline2
-rw-r--r--testsuite/echo/echo-prints-slash-zero2
-rwxr-xr-xtestsuite/expand.tests7
-rw-r--r--testsuite/expand/expand-works-like-GNU10
-rw-r--r--testsuite/find/find-supports-minus-xdev2
-rwxr-xr-xtestsuite/fold.tests4
-rwxr-xr-xtestsuite/grep.tests2
-rw-r--r--testsuite/hostid/hostid-works10
-rw-r--r--testsuite/hostname/hostname-d-works5
-rw-r--r--testsuite/ls/ls-1-works2
-rw-r--r--testsuite/ls/ls-h-works2
-rwxr-xr-xtestsuite/makedevs.tests2
-rw-r--r--testsuite/md5sum/md5sum-verifies-non-binary-file2
-rwxr-xr-xtestsuite/mdev.tests22
-rwxr-xr-xtestsuite/mount.tests19
-rwxr-xr-xtestsuite/od.tests2
-rwxr-xr-xtestsuite/patch.tests2
-rwxr-xr-xtestsuite/pidof.tests4
-rwxr-xr-xtestsuite/rx.tests4
-rwxr-xr-xtestsuite/sed.tests28
-rwxr-xr-xtestsuite/sort.tests2
-rw-r--r--testsuite/tail/tail-works2
-rwxr-xr-xtestsuite/tar.tests10
-rw-r--r--testsuite/tar/tar_with_link_with_size2
-rw-r--r--testsuite/tar/tar_with_prefix_fields3
-rw-r--r--[-rwxr-xr-x]testsuite/testing.sh18
-rwxr-xr-xtestsuite/tr.tests6
-rw-r--r--testsuite/tr/tr-d-alnum-works2
-rw-r--r--testsuite/tr/tr-rejects-wrong-class2
-rw-r--r--testsuite/tr/tr-works4
-rwxr-xr-xtestsuite/unexpand.tests4
-rw-r--r--util-linux/Kbuild1
-rw-r--r--util-linux/mkfs_ext2.c7
-rw-r--r--util-linux/mkfs_reiser.c7
-rw-r--r--util-linux/mkfs_vfat.c7
-rw-r--r--util-linux/swaponoff.c17
129 files changed, 2290 insertions, 1245 deletions
diff --git a/Config.in b/Config.in
index 25010cf84..5339b4ab7 100644
--- a/Config.in
+++ b/Config.in
@@ -237,6 +237,17 @@ config UNICODE_NEUTRAL_TABLE
237 With this option on, more extensive (and bigger) table 237 With this option on, more extensive (and bigger) table
238 of neutral chars will be used. 238 of neutral chars will be used.
239 239
240config UNICODE_PRESERVE_BROKEN
241 bool "Make it possible to enter sequences of chars which are not Unicode"
242 default n
243 depends on UNICODE_SUPPORT
244 help
245 With this option on, invalid UTF-8 bytes are not substituted
246 with the selected substitution character.
247 For example, this means that entering 'l', 's', ' ', 0xff, [Enter]
248 at shell prompt will list file named 0xff (single char name
249 with char value 255), not file named '?'.
250
240config LONG_OPTS 251config LONG_OPTS
241 bool "Support for --long-options" 252 bool "Support for --long-options"
242 default y 253 default y
diff --git a/Makefile b/Makefile
index c637d6d45..547c7166e 100644
--- a/Makefile
+++ b/Makefile
@@ -378,6 +378,11 @@ ifneq ($(KBUILD_SRC),)
378 $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) 378 $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
379endif 379endif
380 380
381# This target generates Kbuild's and Config.in's from *.c files
382PHONY += gen_build_files
383gen_build_files:
384 $(Q)$(srctree)/scripts/gen_build_files.sh $(srctree) $(objtree)
385
381# To make sure we do not include .config for any of the *config targets 386# To make sure we do not include .config for any of the *config targets
382# catch them early, and hand them over to scripts/kconfig/Makefile 387# catch them early, and hand them over to scripts/kconfig/Makefile
383# It is allowed to specify more targets when calling make, including 388# It is allowed to specify more targets when calling make, including
@@ -429,7 +434,7 @@ ifeq ($(config-targets),1)
429-include $(srctree)/arch/$(ARCH)/Makefile 434-include $(srctree)/arch/$(ARCH)/Makefile
430export KBUILD_DEFCONFIG 435export KBUILD_DEFCONFIG
431 436
432config %config: scripts_basic outputmakefile FORCE 437config %config: scripts_basic outputmakefile gen_build_files FORCE
433 $(Q)mkdir -p include 438 $(Q)mkdir -p include
434 $(Q)$(MAKE) $(build)=scripts/kconfig $@ 439 $(Q)$(MAKE) $(build)=scripts/kconfig $@
435 $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= .kernelrelease 440 $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= .kernelrelease
@@ -444,7 +449,7 @@ ifeq ($(KBUILD_EXTMOD),)
444# Carefully list dependencies so we do not try to build scripts twice 449# Carefully list dependencies so we do not try to build scripts twice
445# in parrallel 450# in parrallel
446PHONY += scripts 451PHONY += scripts
447scripts: scripts_basic include/config/MARKER 452scripts: gen_build_files scripts_basic include/config/MARKER
448 $(Q)$(MAKE) $(build)=$(@) 453 $(Q)$(MAKE) $(build)=$(@)
449 454
450scripts_basic: include/autoconf.h 455scripts_basic: include/autoconf.h
@@ -998,6 +1003,8 @@ $(mrproper-dirs):
998mrproper: clean archmrproper $(mrproper-dirs) 1003mrproper: clean archmrproper $(mrproper-dirs)
999 $(call cmd,rmdirs) 1004 $(call cmd,rmdirs)
1000 $(call cmd,rmfiles) 1005 $(call cmd,rmfiles)
1006 @find -name Config.src | sed 's/.src$/.in/' | xargs -r rm -f
1007 @find -name Kbuild.src | sed 's/.src$//' | xargs -r rm -f
1001 1008
1002# distclean 1009# distclean
1003# 1010#
diff --git a/archival/cpio.c b/archival/cpio.c
index 858e59b30..e0ca7fa5c 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -311,6 +311,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
311 /* no parameters */ 311 /* no parameters */
312 opt_complementary = "=0"; 312 opt_complementary = "=0";
313 opt = getopt32(argv, OPTION_STR, &cpio_filename); 313 opt = getopt32(argv, OPTION_STR, &cpio_filename);
314 argv += optind;
314 if (opt & CPIO_OPT_FILE) { /* -F */ 315 if (opt & CPIO_OPT_FILE) { /* -F */
315 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); 316 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
316 } 317 }
@@ -424,7 +425,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
424 if (archive_handle->cpio__blocks != (off_t)-1 425 if (archive_handle->cpio__blocks != (off_t)-1
425 && !(opt & CPIO_OPT_QUIET) 426 && !(opt & CPIO_OPT_QUIET)
426 ) { 427 ) {
427 printf("%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks); 428 fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
428 } 429 }
429 430
430 return EXIT_SUCCESS; 431 return EXIT_SUCCESS;
diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c
index adb4c157b..fcddcb834 100644
--- a/archival/libunarchive/get_header_tar.c
+++ b/archival/libunarchive/get_header_tar.c
@@ -18,87 +18,45 @@ typedef uint32_t aliased_uint32_t FIX_ALIASING;
18typedef off_t aliased_off_t FIX_ALIASING; 18typedef off_t aliased_off_t FIX_ALIASING;
19 19
20 20
21/*
22 * GNU tar uses "base-256 encoding" for very large numbers (>8 billion).
23 * Encoding is binary, with highest bit always set as a marker
24 * and sign in next-highest bit:
25 * 80 00 .. 00 - zero
26 * bf ff .. ff - largest positive number
27 * ff ff .. ff - minus 1
28 * c0 00 .. 00 - smallest negative number
29 *
30 * We expect it only in size field, where negative numbers don't make sense.
31 */
32static off_t getBase256_len12(const char *str)
33{
34 off_t value;
35 int len;
36
37 /* if (*str & 0x40) error; - caller prevents this */
38
39 if (sizeof(off_t) >= 12) {
40 /* Probably 128-bit (16 byte) off_t. Can be optimized. */
41 len = 12;
42 value = *str++ & 0x3f;
43 while (--len)
44 value = (value << 8) + (unsigned char) *str++;
45 return value;
46 }
47
48#ifdef CHECK_FOR_OVERFLOW
49 /* Can be optimized to eat 32-bit chunks */
50 char c = *str++ & 0x3f;
51 len = 12;
52 while (1) {
53 if (c)
54 bb_error_msg_and_die("overflow in base-256 encoded file size");
55 if (--len == sizeof(off_t))
56 break;
57 c = *str++;
58 }
59#else
60 str += (12 - sizeof(off_t));
61#endif
62
63/* Now str points to sizeof(off_t) least significant bytes.
64 *
65 * Example of tar file with 8914993153 (0x213600001) byte file.
66 * Field starts at offset 7c:
67 * 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....|
68 * 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336|
69 *
70 * str is at offset 80 or 84 now (64-bit or 32-bit off_t).
71 * We (ab)use the fact that value happens to be aligned,
72 * and fetch it in one go:
73 */
74 if (sizeof(off_t) == 8) {
75 value = *(aliased_off_t*)str;
76 value = SWAP_BE64(value);
77 } else if (sizeof(off_t) == 4) {
78 value = *(aliased_off_t*)str;
79 value = SWAP_BE32(value);
80 } else {
81 value = 0;
82 len = sizeof(off_t);
83 while (--len)
84 value = (value << 8) + (unsigned char) *str++;
85 }
86 return value;
87}
88
89/* NB: _DESTROYS_ str[len] character! */ 21/* NB: _DESTROYS_ str[len] character! */
90static unsigned long long getOctal(char *str, int len) 22static unsigned long long getOctal(char *str, int len)
91{ 23{
92 unsigned long long v; 24 unsigned long long v;
25 char *end;
93 /* NB: leading spaces are allowed. Using strtoull to handle that. 26 /* NB: leading spaces are allowed. Using strtoull to handle that.
94 * The downside is that we accept e.g. "-123" too :( 27 * The downside is that we accept e.g. "-123" too :(
95 */ 28 */
96 str[len] = '\0'; 29 str[len] = '\0';
97 v = strtoull(str, &str, 8); 30 v = strtoull(str, &end, 8);
98 /* std: "Each numeric field is terminated by one or more 31 /* std: "Each numeric field is terminated by one or more
99 * <space> or NUL characters". We must support ' '! */ 32 * <space> or NUL characters". We must support ' '! */
100 if (*str != '\0' && *str != ' ') 33 if (*end != '\0' && *end != ' ') {
101 bb_error_msg_and_die("corrupted octal value in tar header"); 34 int8_t first = str[0];
35 if (!(first & 0x80))
36 bb_error_msg_and_die("corrupted octal value in tar header");
37 /*
38 * GNU tar uses "base-256 encoding" for very large numbers.
39 * Encoding is binary, with highest bit always set as a marker
40 * and sign in next-highest bit:
41 * 80 00 .. 00 - zero
42 * bf ff .. ff - largest positive number
43 * ff ff .. ff - minus 1
44 * c0 00 .. 00 - smallest negative number
45 *
46 * Example of tar file with 8914993153 (0x213600001) byte file.
47 * Field starts at offset 7c:
48 * 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....|
49 * 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336|
50 *
51 * NB: tarballs with NEGATIVE unix times encoded that way were seen!
52 */
53 v = first;
54 /* Sign-extend using 6th bit: */
55 v <<= sizeof(unsigned long long)*8 - 7;
56 v = (long long)v >> (sizeof(unsigned long long)*8 - 7);
57 while (--len != 0)
58 v = (v << 8) + (unsigned char) *str++;
59 }
102 return v; 60 return v;
103} 61}
104#define GET_OCTAL(a) getOctal((a), sizeof(a)) 62#define GET_OCTAL(a) getOctal((a), sizeof(a))
@@ -358,15 +316,8 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
358 file_header->tar__uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL; 316 file_header->tar__uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL;
359 file_header->tar__gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL; 317 file_header->tar__gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL;
360#endif 318#endif
361 /* mtime: rudimentally handle GNU tar's "base256 encoding" 319 file_header->mtime = GET_OCTAL(tar.mtime);
362 * People report tarballs with NEGATIVE unix times encoded that way */ 320 file_header->size = GET_OCTAL(tar.size);
363 file_header->mtime = (tar.mtime[0] & 0x80) /* base256? */
364 ? 0 /* bogus */
365 : GET_OCTAL(tar.mtime);
366 /* size: handle GNU tar's "base256 encoding" */
367 file_header->size = (tar.size[0] & 0xc0) == 0x80 /* positive base256? */
368 ? getBase256_len12(tar.size)
369 : GET_OCTAL(tar.size);
370 file_header->gid = GET_OCTAL(tar.gid); 321 file_header->gid = GET_OCTAL(tar.gid);
371 file_header->uid = GET_OCTAL(tar.uid); 322 file_header->uid = GET_OCTAL(tar.uid);
372 /* Set bits 0-11 of the files mode */ 323 /* Set bits 0-11 of the files mode */
diff --git a/archival/rpm.c b/archival/rpm.c
index 6c1e341cd..38ec20ef5 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -9,8 +9,8 @@
9 9
10#include "libbb.h" 10#include "libbb.h"
11#include "unarchive.h" 11#include "unarchive.h"
12#include "rpm.h"
12 13
13#define RPM_HEADER_MAGIC "\216\255\350"
14#define RPM_CHAR_TYPE 1 14#define RPM_CHAR_TYPE 1
15#define RPM_INT8_TYPE 2 15#define RPM_INT8_TYPE 2
16#define RPM_INT16_TYPE 3 16#define RPM_INT16_TYPE 3
@@ -46,6 +46,7 @@
46#define TAG_DIRINDEXES 1116 46#define TAG_DIRINDEXES 1116
47#define TAG_BASENAMES 1117 47#define TAG_BASENAMES 1117
48#define TAG_DIRNAMES 1118 48#define TAG_DIRNAMES 1118
49
49#define RPMFILE_CONFIG (1 << 0) 50#define RPMFILE_CONFIG (1 << 0)
50#define RPMFILE_DOC (1 << 1) 51#define RPMFILE_DOC (1 << 1)
51 52
@@ -70,7 +71,7 @@ static void *map;
70static rpm_index **mytags; 71static rpm_index **mytags;
71static int tagcount; 72static int tagcount;
72 73
73static void extract_cpio_gz(int fd); 74static void extract_cpio(int fd, const char *source_rpm);
74static rpm_index **rpm_gettags(int fd, int *num_tags); 75static rpm_index **rpm_gettags(int fd, int *num_tags);
75static int bsearch_rpmtag(const void *key, const void *item); 76static int bsearch_rpmtag(const void *key, const void *item);
76static char *rpm_getstr(int tag, int itemindex); 77static char *rpm_getstr(int tag, int itemindex);
@@ -121,6 +122,8 @@ int rpm_main(int argc, char **argv)
121 } 122 }
122 123
123 while (*argv) { 124 while (*argv) {
125 const char *source_rpm;
126
124 rpm_fd = xopen(*argv++, O_RDONLY); 127 rpm_fd = xopen(*argv++, O_RDONLY);
125 mytags = rpm_gettags(rpm_fd, &tagcount); 128 mytags = rpm_gettags(rpm_fd, &tagcount);
126 if (!mytags) 129 if (!mytags)
@@ -129,11 +132,13 @@ int rpm_main(int argc, char **argv)
129 /* Mimimum is one page */ 132 /* Mimimum is one page */
130 map = mmap(0, offset > pagesize ? (offset + offset % pagesize) : pagesize, PROT_READ, MAP_PRIVATE, rpm_fd, 0); 133 map = mmap(0, offset > pagesize ? (offset + offset % pagesize) : pagesize, PROT_READ, MAP_PRIVATE, rpm_fd, 0);
131 134
135 source_rpm = rpm_getstr(TAG_SOURCERPM, 0);
136
132 if (func & rpm_install) { 137 if (func & rpm_install) {
133 /* Backup any config files */ 138 /* Backup any config files */
134 loop_through_files(TAG_BASENAMES, fileaction_dobackup); 139 loop_through_files(TAG_BASENAMES, fileaction_dobackup);
135 /* Extact the archive */ 140 /* Extact the archive */
136 extract_cpio_gz(rpm_fd); 141 extract_cpio(rpm_fd, source_rpm);
137 /* Set the correct file uid/gid's */ 142 /* Set the correct file uid/gid's */
138 loop_through_files(TAG_BASENAMES, fileaction_setowngrp); 143 loop_through_files(TAG_BASENAMES, fileaction_setowngrp);
139 } 144 }
@@ -147,14 +152,20 @@ int rpm_main(int argc, char **argv)
147 time_t bdate_time; 152 time_t bdate_time;
148 struct tm *bdate_ptm; 153 struct tm *bdate_ptm;
149 char bdatestring[50]; 154 char bdatestring[50];
150 printf("Name : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_PREFIXS, 0) ? rpm_getstr(TAG_PREFIXS, 0) : "(not relocateable)"); 155 const char *p;
151 printf("Version : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_VENDOR, 0) ? rpm_getstr(TAG_VENDOR, 0) : "(none)"); 156
157 p = rpm_getstr(TAG_PREFIXS, 0);
158 if (!p) p = "(not relocateable)";
159 printf("Name : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), p);
160 p = rpm_getstr(TAG_VENDOR, 0);
161 if (!p) p = "(none)";
162 printf("Version : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), p);
152 bdate_time = rpm_getint(TAG_BUILDTIME, 0); 163 bdate_time = rpm_getint(TAG_BUILDTIME, 0);
153 bdate_ptm = localtime(&bdate_time); 164 bdate_ptm = localtime(&bdate_time);
154 strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); 165 strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm);
155 printf("Release : %-30sBuild Date: %s\n", rpm_getstr(TAG_RELEASE, 0), bdatestring); 166 printf("Release : %-30sBuild Date: %s\n", rpm_getstr(TAG_RELEASE, 0), bdatestring);
156 printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstr(TAG_BUILDHOST, 0)); 167 printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstr(TAG_BUILDHOST, 0));
157 printf("Group : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), rpm_getstr(TAG_SOURCERPM, 0)); 168 printf("Group : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), source_rpm);
158 printf("Size : %-33dLicense: %s\n", rpm_getint(TAG_SIZE, 0), rpm_getstr(TAG_LICENSE, 0)); 169 printf("Size : %-33dLicense: %s\n", rpm_getint(TAG_SIZE, 0), rpm_getstr(TAG_LICENSE, 0));
159 printf("URL : %s\n", rpm_getstr(TAG_URL, 0)); 170 printf("URL : %s\n", rpm_getstr(TAG_URL, 0));
160 printf("Summary : %s\n", rpm_getstr(TAG_SUMMARY, 0)); 171 printf("Summary : %s\n", rpm_getstr(TAG_SUMMARY, 0));
@@ -187,23 +198,23 @@ int rpm_main(int argc, char **argv)
187 return 0; 198 return 0;
188} 199}
189 200
190static void extract_cpio_gz(int fd) 201static void extract_cpio(int fd, const char *source_rpm)
191{ 202{
192 archive_handle_t *archive_handle; 203 archive_handle_t *archive_handle;
193 unsigned char magic[2]; 204
194#if BB_MMU 205 if (source_rpm != NULL) {
195 IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); 206 /* Binary rpm (it was built from some SRPM), install to root */
196 enum { xformer_prog = 0 }; 207 xchdir("/");
197#else 208 } /* else: SRPM, install to current dir */
198 enum { xformer = 0 };
199 const char *xformer_prog;
200#endif
201 209
202 /* Initialize */ 210 /* Initialize */
203 archive_handle = init_handle(); 211 archive_handle = init_handle();
204 archive_handle->seek = seek_by_read; 212 archive_handle->seek = seek_by_read;
205 //archive_handle->action_header = header_list;
206 archive_handle->action_data = data_extract_all; 213 archive_handle->action_data = data_extract_all;
214#if 0 /* For testing (rpm -i only lists the files in internal cpio): */
215 archive_handle->action_header = header_list;
216 archive_handle->action_data = data_skip;
217#endif
207 archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS 218 archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS
208 /* compat: overwrite existing files. 219 /* compat: overwrite existing files.
209 * try "rpm -i foo.src.rpm" few times in a row - 220 * try "rpm -i foo.src.rpm" few times in a row -
@@ -213,46 +224,14 @@ static void extract_cpio_gz(int fd)
213 archive_handle->src_fd = fd; 224 archive_handle->src_fd = fd;
214 /*archive_handle->offset = 0; - init_handle() did it */ 225 /*archive_handle->offset = 0; - init_handle() did it */
215 226
216// TODO: open_zipped does the same 227 setup_unzip_on_fd(archive_handle->src_fd /*, fail_if_not_detected: 1*/);
217
218 xread(archive_handle->src_fd, &magic, 2);
219#if BB_MMU
220 xformer = unpack_gz_stream;
221#else
222 xformer_prog = "gunzip";
223#endif
224 if (magic[0] != 0x1f || magic[1] != 0x8b) {
225 if (!ENABLE_FEATURE_SEAMLESS_BZ2
226 || magic[0] != 'B' || magic[1] != 'Z'
227 ) {
228 bb_error_msg_and_die("no gzip"
229 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
230 " magic");
231 }
232#if BB_MMU
233 xformer = unpack_bz2_stream;
234#else
235 xformer_prog = "bunzip2";
236#endif
237 } else {
238#if !BB_MMU
239 /* NOMMU version of open_transformer execs an external unzipper that should
240 * have the file position at the start of the file */
241 xlseek(archive_handle->src_fd, 0, SEEK_SET);
242#endif
243 }
244
245 xchdir("/"); /* Install RPM's to root */
246 open_transformer(archive_handle->src_fd, xformer, xformer_prog);
247 archive_handle->offset = 0;
248 while (get_header_cpio(archive_handle) == EXIT_SUCCESS) 228 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
249 continue; 229 continue;
250} 230}
251 231
252
253static rpm_index **rpm_gettags(int fd, int *num_tags) 232static rpm_index **rpm_gettags(int fd, int *num_tags)
254{ 233{
255 /* We should never need mode than 200, and realloc later */ 234 /* We should never need more than 200 (shrink via realloc later) */
256 rpm_index **tags = xzalloc(200 * sizeof(tags[0])); 235 rpm_index **tags = xzalloc(200 * sizeof(tags[0]));
257 int pass, tagindex = 0; 236 int pass, tagindex = 0;
258 237
@@ -260,27 +239,16 @@ static rpm_index **rpm_gettags(int fd, int *num_tags)
260 239
261 /* 1st pass is the signature headers, 2nd is the main stuff */ 240 /* 1st pass is the signature headers, 2nd is the main stuff */
262 for (pass = 0; pass < 2; pass++) { 241 for (pass = 0; pass < 2; pass++) {
263 struct { 242 struct rpm_header header;
264 char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */
265 uint8_t version; /* 1 byte version number */
266 uint32_t reserved; /* 4 bytes reserved */
267 uint32_t entries; /* Number of entries in header (4 bytes) */
268 uint32_t size; /* Size of store (4 bytes) */
269 } header;
270 struct BUG_header {
271 char BUG_header[sizeof(header) == 16 ? 1 : -1];
272 };
273 rpm_index *tmpindex; 243 rpm_index *tmpindex;
274 int storepos; 244 int storepos;
275 245
276 xread(fd, &header, sizeof(header)); 246 xread(fd, &header, sizeof(header));
277 if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) 247 if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER))
278 return NULL; /* Invalid magic */ 248 return NULL; /* Invalid magic, or not version 1 */
279 if (header.version != 1)
280 return NULL; /* This program only supports v1 headers */
281 header.size = ntohl(header.size); 249 header.size = ntohl(header.size);
282 header.entries = ntohl(header.entries); 250 header.entries = ntohl(header.entries);
283 storepos = xlseek(fd,0,SEEK_CUR) + header.entries * 16; 251 storepos = xlseek(fd, 0, SEEK_CUR) + header.entries * 16;
284 252
285 while (header.entries--) { 253 while (header.entries--) {
286 tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex)); 254 tmpindex = tags[tagindex++] = xmalloc(sizeof(*tmpindex));
@@ -292,14 +260,16 @@ static rpm_index **rpm_gettags(int fd, int *num_tags)
292 if (pass == 0) 260 if (pass == 0)
293 tmpindex->tag -= 743; 261 tmpindex->tag -= 743;
294 } 262 }
295 xlseek(fd, header.size, SEEK_CUR); /* Seek past store */ 263 storepos = xlseek(fd, header.size, SEEK_CUR); /* Seek past store */
296 /* Skip padding to 8 byte boundary after reading signature headers */ 264 /* Skip padding to 8 byte boundary after reading signature headers */
297 if (pass == 0) 265 if (pass == 0)
298 xlseek(fd, (8 - (xlseek(fd,0,SEEK_CUR) % 8)) % 8, SEEK_CUR); 266 xlseek(fd, (-storepos) & 0x7, SEEK_CUR);
299 } 267 }
300 tags = xrealloc(tags, tagindex * sizeof(tags[0])); /* realloc tags to save space */ 268 /* realloc tags to save space */
269 tags = xrealloc(tags, tagindex * sizeof(tags[0]));
301 *num_tags = tagindex; 270 *num_tags = tagindex;
302 return tags; /* All done, leave the file at the start of the gzipped cpio archive */ 271 /* All done, leave the file at the start of the gzipped cpio archive */
272 return tags;
303} 273}
304 274
305static int bsearch_rpmtag(const void *key, const void *item) 275static int bsearch_rpmtag(const void *key, const void *item)
@@ -324,10 +294,13 @@ static char *rpm_getstr(int tag, int itemindex)
324 found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); 294 found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
325 if (!found || itemindex >= found[0]->count) 295 if (!found || itemindex >= found[0]->count)
326 return NULL; 296 return NULL;
327 if (found[0]->type == RPM_STRING_TYPE || found[0]->type == RPM_I18NSTRING_TYPE || found[0]->type == RPM_STRING_ARRAY_TYPE) { 297 if (found[0]->type == RPM_STRING_TYPE
298 || found[0]->type == RPM_I18NSTRING_TYPE
299 || found[0]->type == RPM_STRING_ARRAY_TYPE
300 ) {
328 int n; 301 int n;
329 char *tmpstr = (char *) map + found[0]->offset; 302 char *tmpstr = (char *) map + found[0]->offset;
330 for (n=0; n < itemindex; n++) 303 for (n = 0; n < itemindex; n++)
331 tmpstr = tmpstr + strlen(tmpstr) + 1; 304 tmpstr = tmpstr + strlen(tmpstr) + 1;
332 return tmpstr; 305 return tmpstr;
333 } 306 }
diff --git a/archival/rpm.h b/archival/rpm.h
new file mode 100644
index 000000000..f7c6fc2fa
--- /dev/null
+++ b/archival/rpm.h
@@ -0,0 +1,38 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * RPM structs and consts
4 *
5 * Copyright (C) 2001 by Laurence Anderson
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10/* RPM file starts with this struct: */
11struct rpm_lead {
12 uint32_t magic;
13 uint8_t major, minor;
14 uint16_t type;
15 uint16_t archnum;
16 char name[66];
17 uint16_t osnum;
18 uint16_t signature_type;
19 char reserved[16];
20};
21struct BUG_rpm_lead {
22 char bug[sizeof(struct rpm_lead) == 96 ? 1 : -1];
23};
24#define RPM_LEAD_MAGIC 0xedabeedb
25#define RPM_LEAD_MAGIC_STR "\355\253\356\333"
26
27/* Then follows the header: */
28struct rpm_header {
29 uint32_t magic_and_ver; /* 3 byte magic: 0x8e 0xad 0xe8; 1 byte version: 0x01 */
30 uint32_t reserved; /* 4 bytes reserved */
31 uint32_t entries; /* Number of entries in header (4 bytes) */
32 uint32_t size; /* Size of store (4 bytes) */
33};
34struct BUG_rpm_header {
35 char bug[sizeof(struct rpm_header) == 16 ? 1 : -1];
36};
37#define RPM_HEADER_MAGICnVER 0x8eade801
38#define RPM_HEADER_MAGIC_STR "\216\255\350"
diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c
index 5403aee02..4ed5b023b 100644
--- a/archival/rpm2cpio.c
+++ b/archival/rpm2cpio.c
@@ -8,30 +8,7 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10#include "unarchive.h" 10#include "unarchive.h"
11 11#include "rpm.h"
12#define RPM_MAGIC 0xedabeedb
13#define RPM_MAGIC_STR "\355\253\356\333"
14
15struct rpm_lead {
16 uint32_t magic;
17 uint8_t major, minor;
18 uint16_t type;
19 uint16_t archnum;
20 char name[66];
21 uint16_t osnum;
22 uint16_t signature_type;
23 char reserved[16];
24};
25
26#define RPM_HEADER_MAGICnVER 0x8eade801
27#define RPM_HEADER_MAGIC_STR "\216\255\350"
28
29struct rpm_header {
30 uint32_t magic_and_ver; /* 3 byte magic: 0x8e 0xad 0xe8; 1 byte version */
31 uint32_t reserved; /* 4 bytes reserved */
32 uint32_t entries; /* Number of entries in header (4 bytes) */
33 uint32_t size; /* Size of store (4 bytes) */
34};
35 12
36enum { rpm_fd = STDIN_FILENO }; 13enum { rpm_fd = STDIN_FILENO };
37 14
@@ -65,8 +42,6 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
65{ 42{
66 struct rpm_lead lead; 43 struct rpm_lead lead;
67 unsigned pos; 44 unsigned pos;
68 unsigned char magic[2];
69 IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd);
70 45
71 if (argv[1]) { 46 if (argv[1]) {
72 xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd); 47 xmove_fd(xopen(argv[1], O_RDONLY), rpm_fd);
@@ -74,33 +49,45 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
74 xread(rpm_fd, &lead, sizeof(lead)); 49 xread(rpm_fd, &lead, sizeof(lead));
75 50
76 /* Just check the magic, the rest is irrelevant */ 51 /* Just check the magic, the rest is irrelevant */
77 if (lead.magic != htonl(RPM_MAGIC)) { 52 if (lead.magic != htonl(RPM_LEAD_MAGIC)) {
78 bb_error_msg_and_die("invalid RPM magic"); 53 bb_error_msg_and_die("invalid RPM magic");
79 } 54 }
80 55
81 /* Skip the signature header, align to 8 bytes */ 56 /* Skip the signature header, align to 8 bytes */
82 pos = skip_header(); 57 pos = skip_header();
83 seek_by_jump(rpm_fd, (8 - pos) & 7); 58 seek_by_jump(rpm_fd, (-(int)pos) & 7);
84 59
85 /* Skip the main header */ 60 /* Skip the main header */
86 skip_header(); 61 skip_header();
87 62
88 xread(rpm_fd, &magic, 2); 63#if 0
89 unpack = unpack_gz_stream; 64 /* This works, but doesn't report uncompress errors (they happen in child) */
90 if (magic[0] != 0x1f || magic[1] != 0x8b) { 65 setup_unzip_on_fd(rpm_fd /*fail_if_not_detected: 1*/);
91 if (!ENABLE_FEATURE_SEAMLESS_BZ2 66 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
92 || magic[0] != 'B' || magic[1] != 'Z' 67 bb_error_msg_and_die("error unpacking");
93 ) { 68#else
94 bb_error_msg_and_die("invalid gzip" 69 /* BLOAT */
95 IF_FEATURE_SEAMLESS_BZ2("/bzip2") 70 {
96 " magic"); 71 unsigned char magic[2];
72 IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd);
73
74 xread(rpm_fd, &magic, 2);
75 unpack = unpack_gz_stream;
76 if (magic[0] != 0x1f || magic[1] != 0x8b) {
77 if (!ENABLE_FEATURE_SEAMLESS_BZ2
78 || magic[0] != 'B' || magic[1] != 'Z'
79 ) {
80 bb_error_msg_and_die("invalid gzip"
81 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
82 " magic");
83 }
84 unpack = unpack_bz2_stream;
97 } 85 }
98 unpack = unpack_bz2_stream;
99 }
100 86
101 if (unpack(rpm_fd, STDOUT_FILENO) < 0) { 87 if (unpack(rpm_fd, STDOUT_FILENO) < 0)
102 bb_error_msg_and_die("error unpacking"); 88 bb_error_msg_and_die("error unpacking");
103 } 89 }
90#endif
104 91
105 if (ENABLE_FEATURE_CLEAN_UP) { 92 if (ENABLE_FEATURE_CLEAN_UP) {
106 close(rpm_fd); 93 close(rpm_fd);
diff --git a/console-tools/clear.c b/console-tools/clear.c
index 8b727b39b..b0c6d65d2 100644
--- a/console-tools/clear.c
+++ b/console-tools/clear.c
@@ -15,5 +15,6 @@
15int clear_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 15int clear_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
16int clear_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 16int clear_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
17{ 17{
18 return printf("\033[H\033[J") != 6; 18 /* home; clear to the end of screen */
19 return printf("\033[H""\033[J") != 6;
19} 20}
diff --git a/console-tools/reset.c b/console-tools/reset.c
index 6917eda42..f0ea5cb20 100644
--- a/console-tools/reset.c
+++ b/console-tools/reset.c
@@ -28,11 +28,11 @@ int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
28 28
29 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 29 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
30 /* See 'man 4 console_codes' for details: 30 /* See 'man 4 console_codes' for details:
31 * "ESC c" -- Reset 31 * "ESC c" -- Reset
32 * "ESC ( K" -- Select user mapping 32 * "ESC ( K" -- Select user mapping
33 * "ESC [ J" -- Erase display 33 * "ESC [ J" -- Erase to the end of screen
34 * "ESC [ 0 m" -- Reset all display attributes 34 * "ESC [ 0 m" -- Reset all display attributes
35 * "ESC [ ? 25 h" -- Make cursor visible. 35 * "ESC [ ? 25 h" -- Make cursor visible
36 */ 36 */
37 printf("\033c\033(K\033[J\033[0m\033[?25h"); 37 printf("\033c\033(K\033[J\033[0m\033[?25h");
38 /* http://bugs.busybox.net/view.php?id=1414: 38 /* http://bugs.busybox.net/view.php?id=1414:
diff --git a/coreutils/Kbuild b/coreutils/Kbuild
index 460d62d3f..ee22a3f7b 100644
--- a/coreutils/Kbuild
+++ b/coreutils/Kbuild
@@ -17,6 +17,7 @@ lib-$(CONFIG_CATV) += catv.o
17lib-$(CONFIG_CHGRP) += chgrp.o chown.o 17lib-$(CONFIG_CHGRP) += chgrp.o chown.o
18lib-$(CONFIG_CHMOD) += chmod.o 18lib-$(CONFIG_CHMOD) += chmod.o
19lib-$(CONFIG_CHOWN) += chown.o 19lib-$(CONFIG_CHOWN) += chown.o
20lib-$(CONFIG_ADDUSER) += chown.o # used by adduser
20lib-$(CONFIG_ADDGROUP) += chown.o # used by adduser 21lib-$(CONFIG_ADDGROUP) += chown.o # used by adduser
21lib-$(CONFIG_CHROOT) += chroot.o 22lib-$(CONFIG_CHROOT) += chroot.o
22lib-$(CONFIG_CKSUM) += cksum.o 23lib-$(CONFIG_CKSUM) += cksum.o
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c
index 37e8487e1..ba05897f9 100644
--- a/debianutils/run_parts.c
+++ b/debianutils/run_parts.c
@@ -122,7 +122,6 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv)
122 applet_long_options = runparts_longopts; 122 applet_long_options = runparts_longopts;
123#endif 123#endif
124 /* We require exactly one argument: the directory name */ 124 /* We require exactly one argument: the directory name */
125 /* We require exactly one argument: the directory name */
126 opt_complementary = "=1:a::"; 125 opt_complementary = "=1:a::";
127 getopt32(argv, "ra:u:t"IF_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p); 126 getopt32(argv, "ra:u:t"IF_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p);
128 127
diff --git a/e2fsprogs/Config.in b/e2fsprogs/Config.in
index 9a0088ab5..964d08e4c 100644
--- a/e2fsprogs/Config.in
+++ b/e2fsprogs/Config.in
@@ -41,12 +41,12 @@ config LSATTR
41### mke2fs is used to create an ext2/ext3 filesystem. The normal compat 41### mke2fs is used to create an ext2/ext3 filesystem. The normal compat
42### symlinks 'mkfs.ext2' and 'mkfs.ext3' are also provided. 42### symlinks 'mkfs.ext2' and 'mkfs.ext3' are also provided.
43 43
44### config TUNE2FS 44config TUNE2FS
45### bool "tune2fs" 45 bool "tune2fs"
46### default n 46 default n
47### help 47 help
48### tune2fs allows the system administrator to adjust various tunable 48 tune2fs allows the system administrator to adjust various tunable
49### filesystem parameters on Linux ext2/ext3 filesystems. 49 filesystem parameters on Linux ext2/ext3 filesystems.
50 50
51### config E2LABEL 51### config E2LABEL
52### bool "e2label" 52### bool "e2label"
diff --git a/e2fsprogs/Kbuild b/e2fsprogs/Kbuild
index 9f58ce092..0fdc9d215 100644
--- a/e2fsprogs/Kbuild
+++ b/e2fsprogs/Kbuild
@@ -9,4 +9,5 @@ lib-y:=
9lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o 9lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o
10lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o 10lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o
11 11
12lib-$(CONFIG_FSCK) += fsck.o 12lib-$(CONFIG_FSCK) += fsck.o
13lib-$(CONFIG_TUNE2FS) += tune2fs.o
diff --git a/util-linux/tune2fs.c b/e2fsprogs/tune2fs.c
index 3b8f3d8ef..00ede4f1e 100644
--- a/util-linux/tune2fs.c
+++ b/e2fsprogs/tune2fs.c
@@ -9,16 +9,15 @@
9#include "libbb.h" 9#include "libbb.h"
10#include <linux/fs.h> 10#include <linux/fs.h>
11#include <linux/ext2_fs.h> 11#include <linux/ext2_fs.h>
12#include "volume_id/volume_id_internal.h"
13 12
14// storage helpers 13// storage helpers
15char BUG_wrong_field_size(void); 14char BUG_wrong_field_size(void);
16#define STORE_LE(field, value) \ 15#define STORE_LE(field, value) \
17do { \ 16do { \
18 if (sizeof(field) == 4) \ 17 if (sizeof(field) == 4) \
19 field = cpu_to_le32(value); \ 18 field = SWAP_LE32(value); \
20 else if (sizeof(field) == 2) \ 19 else if (sizeof(field) == 2) \
21 field = cpu_to_le16(value); \ 20 field = SWAP_LE16(value); \
22 else if (sizeof(field) == 1) \ 21 else if (sizeof(field) == 1) \
23 field = (value); \ 22 field = (value); \
24 else \ 23 else \
@@ -26,7 +25,7 @@ do { \
26} while (0) 25} while (0)
27 26
28#define FETCH_LE32(field) \ 27#define FETCH_LE32(field) \
29 (sizeof(field) == 4 ? cpu_to_le32(field) : BUG_wrong_field_size()) 28 (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size())
30 29
31enum { 30enum {
32 OPT_L = 1 << 0, // label 31 OPT_L = 1 << 0, // label
diff --git a/editors/Config.in b/editors/Config.in
index e4fdd0f38..5f9566f0a 100644
--- a/editors/Config.in
+++ b/editors/Config.in
@@ -168,6 +168,18 @@ config FEATURE_VI_WIN_RESIZE
168 help 168 help
169 Make busybox vi behave nicely with terminals that get resized. 169 Make busybox vi behave nicely with terminals that get resized.
170 170
171config FEATURE_VI_ASK_TERMINAL
172 bool "Use 'tell me cursor position' ESC sequence to measure window"
173 default n
174 depends on VI
175 help
176 If terminal size can't be retrieved and $LINES/$COLUMNS are not set,
177 this option makes vi perform a last-ditch effort to find it:
178 vi positions cursor to 999,999 and asks terminal to report real
179 cursor position using "ESC [ 6 n" escape sequence, then reads stdin.
180
181 This is not clean but helps a lot on serial lines and such.
182
171config FEATURE_VI_OPTIMIZE_CURSOR 183config FEATURE_VI_OPTIMIZE_CURSOR
172 bool "Optimize cursor movement" 184 bool "Optimize cursor movement"
173 default y 185 default y
diff --git a/editors/cmp.c b/editors/cmp.c
index 0cb80f21e..dbfa4be35 100644
--- a/editors/cmp.c
+++ b/editors/cmp.c
@@ -10,17 +10,6 @@
10/* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */ 10/* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */
11/* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */ 11/* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */
12 12
13/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
14 *
15 * Original version majorly reworked for SUSv3 compliance, bug fixes, and
16 * size optimizations. Changes include:
17 * 1) Now correctly distinguishes between errors and actual file differences.
18 * 2) Proper handling of '-' args.
19 * 3) Actual error checking of i/o.
20 * 4) Accept SUSv3 -l option. Note that we use the slightly nicer gnu format
21 * in the '-l' case.
22 */
23
24#include "libbb.h" 13#include "libbb.h"
25 14
26static const char fmt_eof[] ALIGN1 = "cmp: EOF on %s\n"; 15static const char fmt_eof[] ALIGN1 = "cmp: EOF on %s\n";
@@ -37,8 +26,7 @@ int cmp_main(int argc UNUSED_PARAM, char **argv)
37{ 26{
38 FILE *fp1, *fp2, *outfile = stdout; 27 FILE *fp1, *fp2, *outfile = stdout;
39 const char *filename1, *filename2 = "-"; 28 const char *filename1, *filename2 = "-";
40 IF_DESKTOP(off_t skip1 = 0, skip2 = 0;) 29 off_t skip1 = 0, skip2 = 0, char_pos = 0;
41 off_t char_pos = 0;
42 int line_pos = 1; /* Hopefully won't overflow... */ 30 int line_pos = 1; /* Hopefully won't overflow... */
43 const char *fmt; 31 const char *fmt;
44 int c1, c2; 32 int c1, c2;
@@ -59,14 +47,12 @@ int cmp_main(int argc UNUSED_PARAM, char **argv)
59 47
60 if (*++argv) { 48 if (*++argv) {
61 filename2 = *argv; 49 filename2 = *argv;
62#if ENABLE_DESKTOP 50 if (ENABLE_DESKTOP && *++argv) {
63 if (*++argv) {
64 skip1 = XATOOFF(*argv); 51 skip1 = XATOOFF(*argv);
65 if (*++argv) { 52 if (*++argv) {
66 skip2 = XATOOFF(*argv); 53 skip2 = XATOOFF(*argv);
67 } 54 }
68 } 55 }
69#endif
70 } 56 }
71 57
72 fp2 = xfopen_stdin(filename2); 58 fp2 = xfopen_stdin(filename2);
@@ -83,10 +69,10 @@ int cmp_main(int argc UNUSED_PARAM, char **argv)
83 else 69 else
84 fmt = fmt_differ; 70 fmt = fmt_differ;
85 71
86#if ENABLE_DESKTOP 72 if (ENABLE_DESKTOP) {
87 while (skip1) { getc(fp1); skip1--; } 73 while (skip1) { getc(fp1); skip1--; }
88 while (skip2) { getc(fp2); skip2--; } 74 while (skip2) { getc(fp2); skip2--; }
89#endif 75 }
90 do { 76 do {
91 c1 = getc(fp1); 77 c1 = getc(fp1);
92 c2 = getc(fp2); 78 c2 = getc(fp2);
diff --git a/editors/sed.c b/editors/sed.c
index e5e187725..4bd6e0168 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -487,7 +487,7 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr)
487static void add_cmd(const char *cmdstr) 487static void add_cmd(const char *cmdstr)
488{ 488{
489 sed_cmd_t *sed_cmd; 489 sed_cmd_t *sed_cmd;
490 int temp; 490 unsigned len, n;
491 491
492 /* Append this line to any unfinished line from last time. */ 492 /* Append this line to any unfinished line from last time. */
493 if (G.add_cmd_line) { 493 if (G.add_cmd_line) {
@@ -496,12 +496,14 @@ static void add_cmd(const char *cmdstr)
496 cmdstr = G.add_cmd_line = tp; 496 cmdstr = G.add_cmd_line = tp;
497 } 497 }
498 498
499 /* If this line ends with backslash, request next line. */ 499 /* If this line ends with unescaped backslash, request next line. */
500 temp = strlen(cmdstr); 500 n = len = strlen(cmdstr);
501 if (temp && cmdstr[--temp] == '\\') { 501 while (n && cmdstr[n-1] == '\\')
502 n--;
503 if ((len - n) & 1) { /* if odd number of trailing backslashes */
502 if (!G.add_cmd_line) 504 if (!G.add_cmd_line)
503 G.add_cmd_line = xstrdup(cmdstr); 505 G.add_cmd_line = xstrdup(cmdstr);
504 G.add_cmd_line[temp] = '\0'; 506 G.add_cmd_line[len-1] = '\0';
505 return; 507 return;
506 } 508 }
507 509
@@ -560,7 +562,7 @@ static void add_cmd(const char *cmdstr)
560 /* last part (mandatory) will be a command */ 562 /* last part (mandatory) will be a command */
561 if (!*cmdstr) 563 if (!*cmdstr)
562 bb_error_msg_and_die("missing command"); 564 bb_error_msg_and_die("missing command");
563 sed_cmd->cmd = *(cmdstr++); 565 sed_cmd->cmd = *cmdstr++;
564 cmdstr = parse_cmd_args(sed_cmd, cmdstr); 566 cmdstr = parse_cmd_args(sed_cmd, cmdstr);
565 567
566 /* Add the command to the command array */ 568 /* Add the command to the command array */
@@ -936,7 +938,15 @@ static void process_files(void)
936 /* Skip blocks of commands we didn't match */ 938 /* Skip blocks of commands we didn't match */
937 if (sed_cmd->cmd == '{') { 939 if (sed_cmd->cmd == '{') {
938 if (sed_cmd->invert ? matched : !matched) { 940 if (sed_cmd->invert ? matched : !matched) {
939 while (sed_cmd->cmd != '}') { 941 unsigned nest_cnt = 0;
942 while (1) {
943 if (sed_cmd->cmd == '{')
944 nest_cnt++;
945 if (sed_cmd->cmd == '}') {
946 nest_cnt--;
947 if (nest_cnt == 0)
948 break;
949 }
940 sed_cmd = sed_cmd->next; 950 sed_cmd = sed_cmd->next;
941 if (!sed_cmd) 951 if (!sed_cmd)
942 bb_error_msg_and_die("unterminated {"); 952 bb_error_msg_and_die("unterminated {");
@@ -1031,7 +1041,7 @@ static void process_files(void)
1031 case 'c': 1041 case 'c':
1032 /* Only triggers on last line of a matching range. */ 1042 /* Only triggers on last line of a matching range. */
1033 if (!sed_cmd->in_match) 1043 if (!sed_cmd->in_match)
1034 sed_puts(sed_cmd->string, NO_EOL_CHAR); 1044 sed_puts(sed_cmd->string, '\n');
1035 goto discard_line; 1045 goto discard_line;
1036 1046
1037 /* Read file, append contents to output */ 1047 /* Read file, append contents to output */
diff --git a/editors/vi.c b/editors/vi.c
index 28612508f..d9124fd76 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -60,18 +60,18 @@ enum {
60 60
61/* vt102 typical ESC sequence */ 61/* vt102 typical ESC sequence */
62/* terminal standout start/normal ESC sequence */ 62/* terminal standout start/normal ESC sequence */
63static const char SOs[] ALIGN1 = "\033[7m"; 63#define SOs "\033[7m"
64static const char SOn[] ALIGN1 = "\033[0m"; 64#define SOn "\033[0m"
65/* terminal bell sequence */ 65/* terminal bell sequence */
66static const char bell[] ALIGN1 = "\007"; 66#define bell "\007"
67/* Clear-end-of-line and Clear-end-of-screen ESC sequence */ 67/* Clear-end-of-line and Clear-end-of-screen ESC sequence */
68static const char Ceol[] ALIGN1 = "\033[0K"; 68#define Ceol "\033[K"
69static const char Ceos[] ALIGN1 = "\033[0J"; 69#define Ceos "\033[J"
70/* Cursor motion arbitrary destination ESC sequence */ 70/* Cursor motion arbitrary destination ESC sequence */
71static const char CMrc[] ALIGN1 = "\033[%d;%dH"; 71#define CMrc "\033[%u;%uH"
72/* Cursor motion up and down ESC sequence */ 72/* Cursor motion up and down ESC sequence */
73static const char CMup[] ALIGN1 = "\033[A"; 73#define CMup "\033[A"
74static const char CMdown[] ALIGN1 = "\n"; 74#define CMdown "\n"
75 75
76#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK 76#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK
77// cmds modifying text[] 77// cmds modifying text[]
@@ -138,6 +138,9 @@ struct globals {
138 int save_argc; // how many file names on cmd line 138 int save_argc; // how many file names on cmd line
139 int cmdcnt; // repetition count 139 int cmdcnt; // repetition count
140 unsigned rows, columns; // the terminal screen is this size 140 unsigned rows, columns; // the terminal screen is this size
141#if ENABLE_FEATURE_VI_ASK_TERMINAL
142 int get_rowcol_error;
143#endif
141 int crow, ccol; // cursor is on Crow x Ccol 144 int crow, ccol; // cursor is on Crow x Ccol
142 int offset; // chars scrolled off the screen to the left 145 int offset; // chars scrolled off the screen to the left
143 int have_status_msg; // is default edit status needed? 146 int have_status_msg; // is default edit status needed?
@@ -503,7 +506,11 @@ static int init_text_buffer(char *fn)
503#if ENABLE_FEATURE_VI_WIN_RESIZE 506#if ENABLE_FEATURE_VI_WIN_RESIZE
504static void query_screen_dimensions(void) 507static void query_screen_dimensions(void)
505{ 508{
506 get_terminal_width_height(STDIN_FILENO, &columns, &rows); 509# if ENABLE_FEATURE_VI_ASK_TERMINAL
510 if (!G.get_rowcol_error)
511 G.get_rowcol_error =
512# endif
513 get_terminal_width_height(STDIN_FILENO, &columns, &rows);
507 if (rows > MAX_SCR_ROWS) 514 if (rows > MAX_SCR_ROWS)
508 rows = MAX_SCR_ROWS; 515 rows = MAX_SCR_ROWS;
509 if (columns > MAX_SCR_COLS) 516 if (columns > MAX_SCR_COLS)
@@ -530,6 +537,20 @@ static void edit_file(char *fn)
530 columns = 80; 537 columns = 80;
531 size = 0; 538 size = 0;
532 query_screen_dimensions(); 539 query_screen_dimensions();
540#if ENABLE_FEATURE_VI_ASK_TERMINAL
541 if (G.get_rowcol_error /* TODO? && no input on stdin */) {
542 uint64_t k;
543 write1("\033[999;999H" "\033[6n");
544 fflush_all();
545 k = read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100);
546 if ((int32_t)k == KEYCODE_CURSOR_POS) {
547 uint32_t rc = (k >> 32);
548 columns = (rc & 0x7fff);
549 rows = ((rc >> 16) & 0x7fff);
550 }
551 query_screen_dimensions();
552 }
553#endif
533 new_screen(rows, columns); // get memory for virtual screen 554 new_screen(rows, columns); // get memory for virtual screen
534 init_text_buffer(fn); 555 init_text_buffer(fn);
535 556
@@ -2306,7 +2327,7 @@ static int file_size(const char *fn) // what is the byte size of "fn"
2306 int cnt; 2327 int cnt;
2307 2328
2308 cnt = -1; 2329 cnt = -1;
2309 if (fn && fn[0] && stat(fn, &st_buf) == 0) // see if file exists 2330 if (fn && stat(fn, &st_buf) == 0) // see if file exists
2310 cnt = (int) st_buf.st_size; 2331 cnt = (int) st_buf.st_size;
2311 return cnt; 2332 return cnt;
2312} 2333}
diff --git a/findutils/.gitignore b/findutils/.gitignore
new file mode 100644
index 000000000..7a30caf5c
--- /dev/null
+++ b/findutils/.gitignore
@@ -0,0 +1,3 @@
1# Config.in and Kbuild are auto-generated
2Config.in
3Kbuild
diff --git a/findutils/Config.in b/findutils/Config.in
deleted file mode 100644
index 8582d6446..000000000
--- a/findutils/Config.in
+++ /dev/null
@@ -1,253 +0,0 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6menu "Finding Utilities"
7
8config FIND
9 bool "find"
10 default n
11 help
12 find is used to search your system to find specified files.
13
14config FEATURE_FIND_PRINT0
15 bool "Enable -print0: NUL-terminated output"
16 default y
17 depends on FIND
18 help
19 Causes output names to be separated by a NUL character
20 rather than a newline. This allows names that contain
21 newlines and other whitespace to be more easily
22 interpreted by other programs.
23
24config FEATURE_FIND_MTIME
25 bool "Enable -mtime: modified time matching"
26 default y
27 depends on FIND
28 help
29 Allow searching based on the modification time of
30 files, in days.
31
32config FEATURE_FIND_MMIN
33 bool "Enable -mmin: modified time matching by minutes"
34 default y
35 depends on FIND
36 help
37 Allow searching based on the modification time of
38 files, in minutes.
39
40config FEATURE_FIND_PERM
41 bool "Enable -perm: permissions matching"
42 default y
43 depends on FIND
44 help
45 Enable searching based on file permissions.
46
47config FEATURE_FIND_TYPE
48 bool "Enable -type: file type matching (file/dir/link/...)"
49 default y
50 depends on FIND
51 help
52 Enable searching based on file type (file,
53 directory, socket, device, etc.).
54
55config FEATURE_FIND_XDEV
56 bool "Enable -xdev: 'stay in filesystem'"
57 default y
58 depends on FIND
59 help
60 This option allows find to restrict searches to a single filesystem.
61
62config FEATURE_FIND_MAXDEPTH
63 bool "Enable -maxdepth N"
64 default y
65 depends on FIND
66 help
67 This option enables -maxdepth N option.
68
69config FEATURE_FIND_NEWER
70 bool "Enable -newer: compare file modification times"
71 default y
72 depends on FIND
73 help
74 Support the 'find -newer' option for finding any files which have
75 a modified time that is more recent than the specified FILE.
76
77config FEATURE_FIND_INUM
78 bool "Enable -inum: inode number matching"
79 default y
80 depends on FIND
81 help
82 Support the 'find -inum' option for searching by inode number.
83
84config FEATURE_FIND_EXEC
85 bool "Enable -exec: execute commands"
86 default y
87 depends on FIND
88 help
89 Support the 'find -exec' option for executing commands based upon
90 the files matched.
91
92config FEATURE_FIND_USER
93 bool "Enable -user: username/uid matching"
94 default y
95 depends on FIND
96 help
97 Support the 'find -user' option for searching by username or uid.
98
99config FEATURE_FIND_GROUP
100 bool "Enable -group: group/gid matching"
101 default y
102 depends on FIND
103 help
104 Support the 'find -group' option for searching by group name or gid.
105
106config FEATURE_FIND_NOT
107 bool "Enable the 'not' (!) operator"
108 default y
109 depends on FIND
110 help
111 Support the '!' operator to invert the test results.
112 If 'Enable full-blown desktop' is enabled, then will also support
113 the non-POSIX notation '-not'.
114
115config FEATURE_FIND_DEPTH
116 bool "Enable -depth"
117 default y
118 depends on FIND
119 help
120 Process each directory's contents before the directory itself.
121
122config FEATURE_FIND_PAREN
123 bool "Enable parens in options"
124 default y
125 depends on FIND
126 help
127 Enable usage of parens '(' to specify logical order of arguments.
128
129config FEATURE_FIND_SIZE
130 bool "Enable -size: file size matching"
131 default y
132 depends on FIND
133 help
134 Support the 'find -size' option for searching by file size.
135
136config FEATURE_FIND_PRUNE
137 bool "Enable -prune: exclude subdirectories"
138 default y
139 depends on FIND
140 help
141 If the file is a directory, dont descend into it. Useful for
142 exclusion .svn and CVS directories.
143
144config FEATURE_FIND_DELETE
145 bool "Enable -delete: delete files/dirs"
146 default n
147 depends on FIND && FEATURE_FIND_DEPTH
148 help
149 Support the 'find -delete' option for deleting files and directories.
150 WARNING: This option can do much harm if used wrong. Busybox will not
151 try to protect the user from doing stupid things. Use with care.
152
153config FEATURE_FIND_PATH
154 bool "Enable -path: match pathname with shell pattern"
155 default y
156 depends on FIND
157 help
158 The -path option matches whole pathname instead of just filename.
159
160config FEATURE_FIND_REGEX
161 bool "Enable -regex: match pathname with regex"
162 default y
163 depends on FIND
164 help
165 The -regex option matches whole pathname against regular expression.
166
167config FEATURE_FIND_CONTEXT
168 bool "Enable -context: security context matching"
169 default n
170 depends on FIND && SELINUX
171 help
172 Support the 'find -context' option for matching security context.
173
174config FEATURE_FIND_LINKS
175 bool "Enable -links: link count matching"
176 default n
177 depends on FIND
178 help
179 Support the 'find -links' option for matching number of links.
180
181config GREP
182 bool "grep"
183 default n
184 help
185 grep is used to search files for a specified pattern.
186
187config FEATURE_GREP_EGREP_ALIAS
188 bool "Enable extended regular expressions (egrep & grep -E)"
189 default y
190 depends on GREP
191 help
192 Enabled support for extended regular expressions. Extended
193 regular expressions allow for alternation (foo|bar), grouping,
194 and various repetition operators.
195
196config FEATURE_GREP_FGREP_ALIAS
197 bool "Alias fgrep to grep -F"
198 default y
199 depends on GREP
200 help
201 fgrep sees the search pattern as a normal string rather than
202 regular expressions.
203 grep -F always works, this just creates the fgrep alias.
204
205config FEATURE_GREP_CONTEXT
206 bool "Enable before and after context flags (-A, -B and -C)"
207 default y
208 depends on GREP
209 help
210 Print the specified number of leading (-B) and/or trailing (-A)
211 context surrounding our matching lines.
212 Print the specified number of context lines (-C).
213
214config XARGS
215 bool "xargs"
216 default n
217 help
218 xargs is used to execute a specified command for
219 every item from standard input.
220
221config FEATURE_XARGS_SUPPORT_CONFIRMATION
222 bool "Enable -p: prompt and confirmation"
223 default n
224 depends on XARGS
225 help
226 Support -p: prompt the user whether to run each command
227 line and read a line from the terminal.
228
229config FEATURE_XARGS_SUPPORT_QUOTES
230 bool "Enable single and double quotes and backslash"
231 default n
232 depends on XARGS
233 help
234 Support quoting in the input.
235
236config FEATURE_XARGS_SUPPORT_TERMOPT
237 bool "Enable -x: exit if -s or -n is exceeded"
238 default n
239 depends on XARGS
240 help
241 Support -x: exit if the command size (see the -s or -n option)
242 is exceeded.
243
244config FEATURE_XARGS_SUPPORT_ZERO_TERM
245 bool "Enable -0: NUL-terminated input"
246 default n
247 depends on XARGS
248 help
249 Support -0: input items are terminated by a NUL character
250 instead of whitespace, and the quotes and backslash
251 are not special.
252
253endmenu
diff --git a/findutils/Config.src b/findutils/Config.src
new file mode 100644
index 000000000..9ee71a845
--- /dev/null
+++ b/findutils/Config.src
@@ -0,0 +1,10 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6menu "Finding Utilities"
7
8INSERT
9
10endmenu
diff --git a/findutils/Kbuild b/findutils/Kbuild.src
index 7b504bacf..771789ff5 100644
--- a/findutils/Kbuild
+++ b/findutils/Kbuild.src
@@ -5,6 +5,5 @@
5# Licensed under the GPL v2, see the file LICENSE in this tarball. 5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6 6
7lib-y:= 7lib-y:=
8lib-$(CONFIG_FIND) += find.o 8
9lib-$(CONFIG_GREP) += grep.o 9INSERT
10lib-$(CONFIG_XARGS) += xargs.o
diff --git a/findutils/find.c b/findutils/find.c
index 0b06938da..9022867a2 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -53,6 +53,181 @@
53 * diff -u /tmp/std_find /tmp/bb_find && echo Identical 53 * diff -u /tmp/std_find /tmp/bb_find && echo Identical
54 */ 54 */
55 55
56//kbuild:lib-$(CONFIG_FIND) += find.o
57//config:
58//config:config FIND
59//config: bool "find"
60//config: default n
61//config: help
62//config: find is used to search your system to find specified files.
63//config:
64//config:config FEATURE_FIND_PRINT0
65//config: bool "Enable -print0: NUL-terminated output"
66//config: default y
67//config: depends on FIND
68//config: help
69//config: Causes output names to be separated by a NUL character
70//config: rather than a newline. This allows names that contain
71//config: newlines and other whitespace to be more easily
72//config: interpreted by other programs.
73//config:
74//config:config FEATURE_FIND_MTIME
75//config: bool "Enable -mtime: modified time matching"
76//config: default y
77//config: depends on FIND
78//config: help
79//config: Allow searching based on the modification time of
80//config: files, in days.
81//config:
82//config:config FEATURE_FIND_MMIN
83//config: bool "Enable -mmin: modified time matching by minutes"
84//config: default y
85//config: depends on FIND
86//config: help
87//config: Allow searching based on the modification time of
88//config: files, in minutes.
89//config:
90//config:config FEATURE_FIND_PERM
91//config: bool "Enable -perm: permissions matching"
92//config: default y
93//config: depends on FIND
94//config: help
95//config: Enable searching based on file permissions.
96//config:
97//config:config FEATURE_FIND_TYPE
98//config: bool "Enable -type: file type matching (file/dir/link/...)"
99//config: default y
100//config: depends on FIND
101//config: help
102//config: Enable searching based on file type (file,
103//config: directory, socket, device, etc.).
104//config:
105//config:config FEATURE_FIND_XDEV
106//config: bool "Enable -xdev: 'stay in filesystem'"
107//config: default y
108//config: depends on FIND
109//config: help
110//config: This option allows find to restrict searches to a single filesystem.
111//config:
112//config:config FEATURE_FIND_MAXDEPTH
113//config: bool "Enable -maxdepth N"
114//config: default y
115//config: depends on FIND
116//config: help
117//config: This option enables -maxdepth N option.
118//config:
119//config:config FEATURE_FIND_NEWER
120//config: bool "Enable -newer: compare file modification times"
121//config: default y
122//config: depends on FIND
123//config: help
124//config: Support the 'find -newer' option for finding any files which have
125//config: a modified time that is more recent than the specified FILE.
126//config:
127//config:config FEATURE_FIND_INUM
128//config: bool "Enable -inum: inode number matching"
129//config: default y
130//config: depends on FIND
131//config: help
132//config: Support the 'find -inum' option for searching by inode number.
133//config:
134//config:config FEATURE_FIND_EXEC
135//config: bool "Enable -exec: execute commands"
136//config: default y
137//config: depends on FIND
138//config: help
139//config: Support the 'find -exec' option for executing commands based upon
140//config: the files matched.
141//config:
142//config:config FEATURE_FIND_USER
143//config: bool "Enable -user: username/uid matching"
144//config: default y
145//config: depends on FIND
146//config: help
147//config: Support the 'find -user' option for searching by username or uid.
148//config:
149//config:config FEATURE_FIND_GROUP
150//config: bool "Enable -group: group/gid matching"
151//config: default y
152//config: depends on FIND
153//config: help
154//config: Support the 'find -group' option for searching by group name or gid.
155//config:
156//config:config FEATURE_FIND_NOT
157//config: bool "Enable the 'not' (!) operator"
158//config: default y
159//config: depends on FIND
160//config: help
161//config: Support the '!' operator to invert the test results.
162//config: If 'Enable full-blown desktop' is enabled, then will also support
163//config: the non-POSIX notation '-not'.
164//config:
165//config:config FEATURE_FIND_DEPTH
166//config: bool "Enable -depth"
167//config: default y
168//config: depends on FIND
169//config: help
170//config: Process each directory's contents before the directory itself.
171//config:
172//config:config FEATURE_FIND_PAREN
173//config: bool "Enable parens in options"
174//config: default y
175//config: depends on FIND
176//config: help
177//config: Enable usage of parens '(' to specify logical order of arguments.
178//config:
179//config:config FEATURE_FIND_SIZE
180//config: bool "Enable -size: file size matching"
181//config: default y
182//config: depends on FIND
183//config: help
184//config: Support the 'find -size' option for searching by file size.
185//config:
186//config:config FEATURE_FIND_PRUNE
187//config: bool "Enable -prune: exclude subdirectories"
188//config: default y
189//config: depends on FIND
190//config: help
191//config: If the file is a directory, dont descend into it. Useful for
192//config: exclusion .svn and CVS directories.
193//config:
194//config:config FEATURE_FIND_DELETE
195//config: bool "Enable -delete: delete files/dirs"
196//config: default n
197//config: depends on FIND && FEATURE_FIND_DEPTH
198//config: help
199//config: Support the 'find -delete' option for deleting files and directories.
200//config: WARNING: This option can do much harm if used wrong. Busybox will not
201//config: try to protect the user from doing stupid things. Use with care.
202//config:
203//config:config FEATURE_FIND_PATH
204//config: bool "Enable -path: match pathname with shell pattern"
205//config: default y
206//config: depends on FIND
207//config: help
208//config: The -path option matches whole pathname instead of just filename.
209//config:
210//config:config FEATURE_FIND_REGEX
211//config: bool "Enable -regex: match pathname with regex"
212//config: default y
213//config: depends on FIND
214//config: help
215//config: The -regex option matches whole pathname against regular expression.
216//config:
217//config:config FEATURE_FIND_CONTEXT
218//config: bool "Enable -context: security context matching"
219//config: default n
220//config: depends on FIND && SELINUX
221//config: help
222//config: Support the 'find -context' option for matching security context.
223//config:
224//config:config FEATURE_FIND_LINKS
225//config: bool "Enable -links: link count matching"
226//config: default n
227//config: depends on FIND
228//config: help
229//config: Support the 'find -links' option for matching number of links.
230
56#include <fnmatch.h> 231#include <fnmatch.h>
57#include "libbb.h" 232#include "libbb.h"
58#if ENABLE_FEATURE_FIND_REGEX 233#if ENABLE_FEATURE_FIND_REGEX
@@ -198,14 +373,19 @@ static int exec_actions(action ***appp, const char *fileName, const struct stat
198ACTF(name) 373ACTF(name)
199{ 374{
200 const char *tmp = bb_basename(fileName); 375 const char *tmp = bb_basename(fileName);
201 if (tmp != fileName && !*tmp) { /* "foo/bar/". Oh no... go back to 'b' */ 376 if (tmp != fileName && *tmp == '\0') {
377 /* "foo/bar/". Oh no... go back to 'b' */
202 tmp--; 378 tmp--;
203 while (tmp != fileName && *--tmp != '/') 379 while (tmp != fileName && *--tmp != '/')
204 continue; 380 continue;
205 if (*tmp == '/') 381 if (*tmp == '/')
206 tmp++; 382 tmp++;
207 } 383 }
208 return fnmatch(ap->pattern, tmp, FNM_PERIOD | (ap->iname ? FNM_CASEFOLD : 0)) == 0; 384 /* Was using FNM_PERIOD flag too,
385 * but somewhere between 4.1.20 and 4.4.0 GNU find stopped using it.
386 * find -name '*foo' should match .foo too:
387 */
388 return fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)) == 0;
209} 389}
210 390
211#if ENABLE_FEATURE_FIND_PATH 391#if ENABLE_FEATURE_FIND_PATH
diff --git a/findutils/grep.c b/findutils/grep.c
index 318fb4b2f..d5fe10320 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -19,15 +19,49 @@
19 * (C) 2006 Jac Goudsmit added -o option 19 * (C) 2006 Jac Goudsmit added -o option
20 */ 20 */
21 21
22//kbuild:lib-$(CONFIG_GREP) += grep.o
23//config:
24//config:config GREP
25//config: bool "grep"
26//config: default n
27//config: help
28//config: grep is used to search files for a specified pattern.
29//config:
30//config:config FEATURE_GREP_EGREP_ALIAS
31//config: bool "Enable extended regular expressions (egrep & grep -E)"
32//config: default y
33//config: depends on GREP
34//config: help
35//config: Enabled support for extended regular expressions. Extended
36//config: regular expressions allow for alternation (foo|bar), grouping,
37//config: and various repetition operators.
38//config:
39//config:config FEATURE_GREP_FGREP_ALIAS
40//config: bool "Alias fgrep to grep -F"
41//config: default y
42//config: depends on GREP
43//config: help
44//config: fgrep sees the search pattern as a normal string rather than
45//config: regular expressions.
46//config: grep -F always works, this just creates the fgrep alias.
47//config:
48//config:config FEATURE_GREP_CONTEXT
49//config: bool "Enable before and after context flags (-A, -B and -C)"
50//config: default y
51//config: depends on GREP
52//config: help
53//config: Print the specified number of leading (-B) and/or trailing (-A)
54//config: context surrounding our matching lines.
55//config: Print the specified number of context lines (-C).
56
22#include "libbb.h" 57#include "libbb.h"
23#include "xregex.h" 58#include "xregex.h"
24 59
25/* options */ 60/* options */
26#define OPTSTR_GREP \ 61#define OPTSTR_GREP \
27 "lnqvscFiHhe:f:Lorm:" \ 62 "lnqvscFiHhe:f:Lorm:w" \
28 IF_FEATURE_GREP_CONTEXT("A:B:C:") \ 63 IF_FEATURE_GREP_CONTEXT("A:B:C:") \
29 IF_FEATURE_GREP_EGREP_ALIAS("E") \ 64 IF_FEATURE_GREP_EGREP_ALIAS("E") \
30 IF_DESKTOP("w") \
31 IF_EXTRA_COMPAT("z") \ 65 IF_EXTRA_COMPAT("z") \
32 "aI" 66 "aI"
33 67
@@ -51,11 +85,11 @@ enum {
51 OPTBIT_o, /* show only matching parts of lines */ 85 OPTBIT_o, /* show only matching parts of lines */
52 OPTBIT_r, /* recurse dirs */ 86 OPTBIT_r, /* recurse dirs */
53 OPTBIT_m, /* -m MAX_MATCHES */ 87 OPTBIT_m, /* -m MAX_MATCHES */
88 OPTBIT_w, /* -w whole word match */
54 IF_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */ 89 IF_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */
55 IF_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */ 90 IF_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */
56 IF_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */ 91 IF_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */
57 IF_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */ 92 IF_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */
58 IF_DESKTOP( OPTBIT_w ,) /* whole word match */
59 IF_EXTRA_COMPAT( OPTBIT_z ,) /* input is NUL terminated */ 93 IF_EXTRA_COMPAT( OPTBIT_z ,) /* input is NUL terminated */
60 OPT_l = 1 << OPTBIT_l, 94 OPT_l = 1 << OPTBIT_l,
61 OPT_n = 1 << OPTBIT_n, 95 OPT_n = 1 << OPTBIT_n,
@@ -73,11 +107,11 @@ enum {
73 OPT_o = 1 << OPTBIT_o, 107 OPT_o = 1 << OPTBIT_o,
74 OPT_r = 1 << OPTBIT_r, 108 OPT_r = 1 << OPTBIT_r,
75 OPT_m = 1 << OPTBIT_m, 109 OPT_m = 1 << OPTBIT_m,
110 OPT_w = 1 << OPTBIT_w,
76 OPT_A = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0, 111 OPT_A = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0,
77 OPT_B = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0, 112 OPT_B = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0,
78 OPT_C = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0, 113 OPT_C = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0,
79 OPT_E = IF_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0, 114 OPT_E = IF_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0,
80 OPT_w = IF_DESKTOP( (1 << OPTBIT_w)) + 0,
81 OPT_z = IF_EXTRA_COMPAT( (1 << OPTBIT_z)) + 0, 115 OPT_z = IF_EXTRA_COMPAT( (1 << OPTBIT_z)) + 0,
82}; 116};
83 117
@@ -263,7 +297,10 @@ static int grep_file(FILE *file)
263 while (pattern_ptr) { 297 while (pattern_ptr) {
264 gl = (grep_list_data_t *)pattern_ptr->data; 298 gl = (grep_list_data_t *)pattern_ptr->data;
265 if (FGREP_FLAG) { 299 if (FGREP_FLAG) {
266 found |= (strstr(line, gl->pattern) != NULL); 300 found |= (((option_mask32 & OPT_i)
301 ? strcasestr(line, gl->pattern)
302 : strstr(line, gl->pattern)
303 ) != NULL);
267 } else { 304 } else {
268 if (!(gl->flg_mem_alocated_compiled & COMPILED)) { 305 if (!(gl->flg_mem_alocated_compiled & COMPILED)) {
269 gl->flg_mem_alocated_compiled |= COMPILED; 306 gl->flg_mem_alocated_compiled |= COMPILED;
diff --git a/findutils/xargs.c b/findutils/xargs.c
index 3785f1ec0..c55ac5724 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -17,6 +17,47 @@
17 * 17 *
18 */ 18 */
19 19
20//kbuild:lib-$(CONFIG_XARGS) += xargs.o
21//config:
22//config:config XARGS
23//config: bool "xargs"
24//config: default n
25//config: help
26//config: xargs is used to execute a specified command for
27//config: every item from standard input.
28//config:
29//config:config FEATURE_XARGS_SUPPORT_CONFIRMATION
30//config: bool "Enable -p: prompt and confirmation"
31//config: default n
32//config: depends on XARGS
33//config: help
34//config: Support -p: prompt the user whether to run each command
35//config: line and read a line from the terminal.
36//config:
37//config:config FEATURE_XARGS_SUPPORT_QUOTES
38//config: bool "Enable single and double quotes and backslash"
39//config: default n
40//config: depends on XARGS
41//config: help
42//config: Support quoting in the input.
43//config:
44//config:config FEATURE_XARGS_SUPPORT_TERMOPT
45//config: bool "Enable -x: exit if -s or -n is exceeded"
46//config: default n
47//config: depends on XARGS
48//config: help
49//config: Support -x: exit if the command size (see the -s or -n option)
50//config: is exceeded.
51//config:
52//config:config FEATURE_XARGS_SUPPORT_ZERO_TERM
53//config: bool "Enable -0: NUL-terminated input"
54//config: default n
55//config: depends on XARGS
56//config: help
57//config: Support -0: input items are terminated by a NUL character
58//config: instead of whitespace, and the quotes and backslash
59//config: are not special.
60
20#include "libbb.h" 61#include "libbb.h"
21 62
22/* This is a NOEXEC applet. Be very careful! */ 63/* This is a NOEXEC applet. Be very careful! */
diff --git a/include/applets.h b/include/applets.h
index 83c1792ac..36b24856a 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -83,6 +83,7 @@ IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_DROP))
83//IF_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_DROP)) 83//IF_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_DROP))
84IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 84IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP))
85IF_BLKID(APPLET(blkid, _BB_DIR_SBIN, _BB_SUID_DROP)) 85IF_BLKID(APPLET(blkid, _BB_DIR_SBIN, _BB_SUID_DROP))
86IF_BOOTCHARTD(APPLET(bootchartd, _BB_DIR_SBIN, _BB_SUID_DROP))
86IF_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 87IF_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
87IF_BUNZIP2(APPLET(bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 88IF_BUNZIP2(APPLET(bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP))
88IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP, bzcat)) 89IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP, bzcat))
@@ -247,8 +248,8 @@ IF_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_DROP, ls))
247IF_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_DROP)) 248IF_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_DROP))
248IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_DROP)) 249IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_DROP))
249IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe)) 250IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe))
250IF_LSPCI(APPLET(lspci, _BB_DIR_SBIN, _BB_SUID_DROP)) 251IF_LSPCI(APPLET(lspci, _BB_DIR_USR_BIN, _BB_SUID_DROP))
251IF_LSUSB(APPLET(lsusb, _BB_DIR_SBIN, _BB_SUID_DROP)) 252IF_LSUSB(APPLET(lsusb, _BB_DIR_USR_BIN, _BB_SUID_DROP))
252IF_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzmacat)) 253IF_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzmacat))
253IF_LZOP(APPLET(lzop, _BB_DIR_BIN, _BB_SUID_DROP)) 254IF_LZOP(APPLET(lzop, _BB_DIR_BIN, _BB_SUID_DROP))
254IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzopcat)) 255IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzopcat))
@@ -321,6 +322,7 @@ IF_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_DROP))
321IF_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 322IF_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_DROP))
322IF_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 323IF_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_DROP))
323IF_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, _BB_DIR_SBIN, _BB_SUID_DROP, restorecon)) 324IF_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, _BB_DIR_SBIN, _BB_SUID_DROP, restorecon))
325IF_RFKILL(APPLET(rfkill, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
324IF_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_DROP, rm)) 326IF_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_DROP, rm))
325IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_DROP, rmdir)) 327IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_DROP, rmdir))
326IF_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_DROP)) 328IF_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_DROP))
@@ -403,7 +405,7 @@ IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true))
403IF_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 405IF_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_DROP))
404IF_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 406IF_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_DROP))
405IF_TUNCTL(APPLET(tunctl, _BB_DIR_SBIN, _BB_SUID_DROP)) 407IF_TUNCTL(APPLET(tunctl, _BB_DIR_SBIN, _BB_SUID_DROP))
406IF_MKFS_EXT2(APPLET(tune2fs, _BB_DIR_SBIN, _BB_SUID_DROP)) 408IF_TUNE2FS(APPLET(tune2fs, _BB_DIR_SBIN, _BB_SUID_DROP))
407IF_UDHCPC(APPLET(udhcpc, _BB_DIR_SBIN, _BB_SUID_DROP)) 409IF_UDHCPC(APPLET(udhcpc, _BB_DIR_SBIN, _BB_SUID_DROP))
408IF_UDHCPD(APPLET(udhcpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 410IF_UDHCPD(APPLET(udhcpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
409IF_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_DROP, udpsvd)) 411IF_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_DROP, udpsvd))
diff --git a/include/libbb.h b/include/libbb.h
index 11d7f27d3..58a5968c5 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -664,6 +664,15 @@ extern char *xmalloc_reads(int fd, char *pfx, size_t *maxsz_p) FAST_FUNC;
664extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 664extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
665/* Returns NULL if file can't be opened (default max size: INT_MAX - 4095) */ 665/* Returns NULL if file can't be opened (default max size: INT_MAX - 4095) */
666extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 666extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
667/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */
668#if ENABLE_FEATURE_SEAMLESS_LZMA \
669 || ENABLE_FEATURE_SEAMLESS_BZ2 \
670 || ENABLE_FEATURE_SEAMLESS_GZ \
671 /* || ENABLE_FEATURE_SEAMLESS_Z */
672extern int setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) FAST_FUNC;
673#else
674# define setup_unzip_on_fd(...) ((void)0)
675#endif
667/* Autodetects .gz etc */ 676/* Autodetects .gz etc */
668extern int open_zipped(const char *fname) FAST_FUNC; 677extern int open_zipped(const char *fname) FAST_FUNC;
669extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 678extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
diff --git a/include/unicode.h b/include/unicode.h
index 4e2927297..eaf67c833 100644
--- a/include/unicode.h
+++ b/include/unicode.h
@@ -30,12 +30,21 @@ enum {
30#else 30#else
31 31
32# if CONFIG_LAST_SUPPORTED_WCHAR < 126 || CONFIG_LAST_SUPPORTED_WCHAR >= 0x30000 32# if CONFIG_LAST_SUPPORTED_WCHAR < 126 || CONFIG_LAST_SUPPORTED_WCHAR >= 0x30000
33# define LAST_SUPPORTED_WCHAR 0x2ffff 33# undef CONFIG_LAST_SUPPORTED_WCHAR
34# else 34# define CONFIG_LAST_SUPPORTED_WCHAR 0x2ffff
35# define LAST_SUPPORTED_WCHAR CONFIG_LAST_SUPPORTED_WCHAR 35# endif
36
37# if CONFIG_LAST_SUPPORTED_WCHAR < 0x300
38# undef ENABLE_UNICODE_COMBINING_WCHARS
39# define ENABLE_UNICODE_COMBINING_WCHARS 0
40# endif
41
42# if CONFIG_LAST_SUPPORTED_WCHAR < 0x1100
43# undef ENABLE_UNICODE_WIDE_WCHARS
44# define ENABLE_UNICODE_WIDE_WCHARS 0
36# endif 45# endif
37 46
38# if LAST_SUPPORTED_WCHAR < 0x590 47# if CONFIG_LAST_SUPPORTED_WCHAR < 0x590
39# undef ENABLE_UNICODE_BIDI_SUPPORT 48# undef ENABLE_UNICODE_BIDI_SUPPORT
40# define ENABLE_UNICODE_BIDI_SUPPORT 0 49# define ENABLE_UNICODE_BIDI_SUPPORT 0
41# endif 50# endif
@@ -92,6 +101,7 @@ size_t wcrtomb(char *s, wchar_t wc, mbstate_t *ps) FAST_FUNC;
92int iswspace(wint_t wc) FAST_FUNC; 101int iswspace(wint_t wc) FAST_FUNC;
93int iswalnum(wint_t wc) FAST_FUNC; 102int iswalnum(wint_t wc) FAST_FUNC;
94int iswpunct(wint_t wc) FAST_FUNC; 103int iswpunct(wint_t wc) FAST_FUNC;
104int wcwidth(unsigned ucs) FAST_FUNC;
95# if ENABLE_UNICODE_BIDI_SUPPORT 105# if ENABLE_UNICODE_BIDI_SUPPORT
96# undef unicode_bidi_isrtl 106# undef unicode_bidi_isrtl
97int unicode_bidi_isrtl(wint_t wc) FAST_FUNC; 107int unicode_bidi_isrtl(wint_t wc) FAST_FUNC;
diff --git a/include/usage.h b/include/usage.h
index 4568fac9f..3fce939bb 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -154,18 +154,15 @@
154 "\n -r Repetitions" \ 154 "\n -r Repetitions" \
155 "\n -n Start new tone" \ 155 "\n -n Start new tone" \
156 156
157#define fbsplash_trivial_usage \ 157#define bootchartd_trivial_usage \
158 "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]" 158 "start [PROG ARGS]|stop|init"
159#define fbsplash_full_usage "\n\n" \ 159#define bootchartd_full_usage "\n\n" \
160 "Options:" \ 160 "Create /var/log/bootchart.tgz with boot chart data\n" \
161 "\n -s Image" \ 161 "\nOptions:" \
162 "\n -c Hide cursor" \ 162 "\nstart: start background logging; with PROG, run PROG, then kill logging with USR1" \
163 "\n -d Framebuffer device (default /dev/fb0)" \ 163 "\nstop: send USR1 to all bootchartd processes" \
164 "\n -i Config file (var=value):" \ 164 "\ninit: start background logging; stop when getty/xdm is seen (for init scripts)" \
165 "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" \ 165 "\nUnder PID 1: as init, then exec $bootchart_init, /init, /sbin/init" \
166 "\n BAR_R,BAR_G,BAR_B" \
167 "\n -f Control pipe (else exit after drawing image)" \
168 "\n commands: 'NN' (% for progress bar) or 'exit'" \
169 166
170#define brctl_trivial_usage \ 167#define brctl_trivial_usage \
171 "COMMAND [BRIDGE [INTERFACE]]" 168 "COMMAND [BRIDGE [INTERFACE]]"
@@ -504,9 +501,9 @@
504 "Clear screen" 501 "Clear screen"
505 502
506#define cmp_trivial_usage \ 503#define cmp_trivial_usage \
507 "[-l] [-s] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]") "]]" 504 "[-l] [-s] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]"
508#define cmp_full_usage "\n\n" \ 505#define cmp_full_usage "\n\n" \
509 "Compares FILE1 vs stdin if FILE2 is not specified\n" \ 506 "Compare FILE1 with FILE2 (or stdin)\n" \
510 "\nOptions:" \ 507 "\nOptions:" \
511 "\n -l Write the byte numbers (decimal) and values (octal)" \ 508 "\n -l Write the byte numbers (decimal) and values (octal)" \
512 "\n for all differing bytes" \ 509 "\n for all differing bytes" \
@@ -515,7 +512,7 @@
515#define comm_trivial_usage \ 512#define comm_trivial_usage \
516 "[-123] FILE1 FILE2" 513 "[-123] FILE1 FILE2"
517#define comm_full_usage "\n\n" \ 514#define comm_full_usage "\n\n" \
518 "Compare FILE1 to FILE2, or to stdin if - is specified\n" \ 515 "Compare FILE1 with FILE2\n" \
519 "\nOptions:" \ 516 "\nOptions:" \
520 "\n -1 Suppress lines unique to FILE1" \ 517 "\n -1 Suppress lines unique to FILE1" \
521 "\n -2 Suppress lines unique to FILE2" \ 518 "\n -2 Suppress lines unique to FILE2" \
@@ -652,8 +649,16 @@
652 "\n -S SALT" \ 649 "\n -S SALT" \
653 ) \ 650 ) \
654 651
655#define cttyhack_trivial_usage NOUSAGE_STR 652#define cttyhack_trivial_usage \
656#define cttyhack_full_usage "" 653 "PROG ARGS"
654#define cttyhack_full_usage "\n\n" \
655 "Give PROG a controlling tty if possible." \
656 "\nExample for /etc/inittab (for busybox init):" \
657 "\n ::respawn:/bin/cttyhack /bin/sh" \
658 "\nGiving controlling tty to shell running with PID 1:" \
659 "\n $ exec cttyhack sh" \
660 "\nStarting interactive shell from boot shell script:" \
661 "\n setsid cttyhack sh" \
657 662
658#define cut_trivial_usage \ 663#define cut_trivial_usage \
659 "[OPTIONS] [FILE]..." 664 "[OPTIONS] [FILE]..."
@@ -1174,6 +1179,19 @@
1174 "$ echo $?\n" \ 1179 "$ echo $?\n" \
1175 "1\n" 1180 "1\n"
1176 1181
1182#define fbsplash_trivial_usage \
1183 "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]"
1184#define fbsplash_full_usage "\n\n" \
1185 "Options:" \
1186 "\n -s Image" \
1187 "\n -c Hide cursor" \
1188 "\n -d Framebuffer device (default /dev/fb0)" \
1189 "\n -i Config file (var=value):" \
1190 "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" \
1191 "\n BAR_R,BAR_G,BAR_B" \
1192 "\n -f Control pipe (else exit after drawing image)" \
1193 "\n commands: 'NN' (% for progress bar) or 'exit'" \
1194
1177#define fbset_trivial_usage \ 1195#define fbset_trivial_usage \
1178 "[OPTIONS] [MODE]" 1196 "[OPTIONS] [MODE]"
1179#define fbset_full_usage "\n\n" \ 1197#define fbset_full_usage "\n\n" \
@@ -1531,8 +1549,7 @@
1531 "\n -H HOST Log HOST into the utmp file as the hostname" \ 1549 "\n -H HOST Log HOST into the utmp file as the hostname" \
1532 1550
1533#define grep_trivial_usage \ 1551#define grep_trivial_usage \
1534 "[-HhnlLoqvsri" \ 1552 "[-HhnlLoqvsriw" \
1535 IF_DESKTOP("w") \
1536 "F" \ 1553 "F" \
1537 IF_FEATURE_GREP_EGREP_ALIAS("E") \ 1554 IF_FEATURE_GREP_EGREP_ALIAS("E") \
1538 IF_EXTRA_COMPAT("z") \ 1555 IF_EXTRA_COMPAT("z") \
@@ -1554,9 +1571,7 @@
1554 "\n -s Suppress open and read errors" \ 1571 "\n -s Suppress open and read errors" \
1555 "\n -r Recurse" \ 1572 "\n -r Recurse" \
1556 "\n -i Ignore case" \ 1573 "\n -i Ignore case" \
1557 IF_DESKTOP( \
1558 "\n -w Match whole words only" \ 1574 "\n -w Match whole words only" \
1559 ) \
1560 "\n -F PATTERN is a literal (not regexp)" \ 1575 "\n -F PATTERN is a literal (not regexp)" \
1561 IF_FEATURE_GREP_EGREP_ALIAS( \ 1576 IF_FEATURE_GREP_EGREP_ALIAS( \
1562 "\n -E PATTERN is an extended regexp" \ 1577 "\n -E PATTERN is an extended regexp" \
@@ -3741,6 +3756,18 @@
3741 "\n for customizable files, or the user section," \ 3756 "\n for customizable files, or the user section," \
3742 "\n if it has changed" \ 3757 "\n if it has changed" \
3743 3758
3759#define rfkill_trivial_usage \
3760 "COMMAND [INDEX|TYPE]"
3761#define rfkill_full_usage "\n\n" \
3762 "Enable/disable wireless devices\n" \
3763 "\nCommands:" \
3764 "\n list [INDEX|TYPE] List current state" \
3765 "\n block INDEX|TYPE Disable device" \
3766 "\n unblock INDEX|TYPE Enable device" \
3767 "\n" \
3768 "\n TYPE: all, wlan(wifi), bluetooth, uwb(ultrawideband)," \
3769 "\n wimax, wwan, gps, fm" \
3770
3744#define rm_trivial_usage \ 3771#define rm_trivial_usage \
3745 "[OPTIONS] FILE..." 3772 "[OPTIONS] FILE..."
3746#define rm_full_usage "\n\n" \ 3773#define rm_full_usage "\n\n" \
@@ -3791,13 +3818,13 @@
3791 "\n -A inet" IF_FEATURE_IPV6("{6}") " Select address family" \ 3818 "\n -A inet" IF_FEATURE_IPV6("{6}") " Select address family" \
3792 3819
3793#define rpm_trivial_usage \ 3820#define rpm_trivial_usage \
3794 "-i -q[ildc]p PACKAGE.rpm" 3821 "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm"
3795#define rpm_full_usage "\n\n" \ 3822#define rpm_full_usage "\n\n" \
3796 "Manipulate RPM packages\n" \ 3823 "Manipulate RPM packages\n" \
3797 "\nOptions:" \ 3824 "\nCommands:" \
3798 "\n -i Install package" \ 3825 "\n -i Install package" \
3799 "\n -q Query package" \ 3826 "\n -qp Query package" \
3800 "\n -p Query uninstalled package" \ 3827 "\nOptions:" \
3801 "\n -i Show information" \ 3828 "\n -i Show information" \
3802 "\n -l List contents" \ 3829 "\n -l List contents" \
3803 "\n -d List documents" \ 3830 "\n -d List documents" \
diff --git a/init/Config.in b/init/Config.in
index 3d99d4792..76d509207 100644
--- a/init/Config.in
+++ b/init/Config.in
@@ -120,4 +120,18 @@ config MESG
120 Mesg controls access to your terminal by others. It is typically 120 Mesg controls access to your terminal by others. It is typically
121 used to allow or disallow other users to write to your terminal 121 used to allow or disallow other users to write to your terminal
122 122
123config BOOTCHARTD
124 bool "bootchartd"
125 default n
126 help
127 bootchartd is commonly used to profile the boot process
128 for the purpose of speeding it up. In this case, it is started
129 by the kernel as the init process. This is configured by adding
130 the init=/sbin/bootchartd option to the kernel command line.
131
132 It can also be used to monitor the resource usage of a specific
133 application or the running system in general. In this case,
134 bootchartd is started interactively by running bootchartd start
135 and stopped using bootchartd stop.
136
123endmenu 137endmenu
diff --git a/init/Kbuild b/init/Kbuild
index c060f3af4..ce3f30256 100644
--- a/init/Kbuild
+++ b/init/Kbuild
@@ -5,6 +5,7 @@
5# Licensed under the GPL v2, see the file LICENSE in this tarball. 5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6 6
7lib-y:= 7lib-y:=
8lib-$(CONFIG_HALT) += halt.o 8lib-$(CONFIG_HALT) += halt.o
9lib-$(CONFIG_INIT) += init.o 9lib-$(CONFIG_INIT) += init.o
10lib-$(CONFIG_MESG) += mesg.o 10lib-$(CONFIG_MESG) += mesg.o
11lib-$(CONFIG_BOOTCHARTD) += bootchartd.o
diff --git a/init/bootchartd.c b/init/bootchartd.c
new file mode 100644
index 000000000..d1f9ed30e
--- /dev/null
+++ b/init/bootchartd.c
@@ -0,0 +1,356 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
4 */
5#include "libbb.h"
6#include <sys/mount.h>
7#ifndef MS_SILENT
8# define MS_SILENT (1 << 15)
9#endif
10#ifndef MNT_DETACH
11# define MNT_DETACH 0x00000002
12#endif
13
14#define BC_VERSION_STR "0.8"
15
16/* For debugging, set to 0:
17 * strace won't work with DO_SIGNAL_SYNC set to 1.
18 */
19#define DO_SIGNAL_SYNC 1
20
21
22//Not supported: $PWD/bootchartd.conf and /etc/bootchartd.conf
23
24//# tmpfs size
25//# (32 MB should suffice for ~20 minutes worth of log data, but YMMV)
26//TMPFS_SIZE=32m
27//
28//# Sampling period (in seconds)
29//SAMPLE_PERIOD=0.2
30//
31//# Whether to enable and store BSD process accounting information. The
32//# kernel needs to be configured to enable v3 accounting
33//# (CONFIG_BSD_PROCESS_ACCT_V3). accton from the GNU accounting utilities
34//# is also required.
35//PROCESS_ACCOUNTING="no"
36//
37//# Tarball for the various boot log files
38//BOOTLOG_DEST=/var/log/bootchart.tgz
39//
40//# Whether to automatically stop logging as the boot process completes.
41//# The logger will look for known processes that indicate bootup completion
42//# at a specific runlevel (e.g. gdm-binary, mingetty, etc.).
43//AUTO_STOP_LOGGER="yes"
44//
45//# Whether to automatically generate the boot chart once the boot logger
46//# completes. The boot chart will be generated in $AUTO_RENDER_DIR.
47//# Note that the bootchart package must be installed.
48//AUTO_RENDER="no"
49//
50//# Image format to use for the auto-generated boot chart
51//# (choose between png, svg and eps).
52//AUTO_RENDER_FORMAT="png"
53//
54//# Output directory for auto-generated boot charts
55//AUTO_RENDER_DIR="/var/log"
56
57
58/* Globals */
59struct globals {
60 char jiffy_line[COMMON_BUFSIZE];
61} FIX_ALIASING;
62#define G (*(struct globals*)&bb_common_bufsiz1)
63#define INIT_G() do { } while (0)
64
65static void dump_file(FILE *fp, const char *filename)
66{
67 int fd = open(filename, O_RDONLY);
68 if (fd >= 0) {
69 fputs(G.jiffy_line, fp);
70 fflush(fp);
71 bb_copyfd_eof(fd, fileno(fp));
72 close(fd);
73 fputc('\n', fp);
74 }
75}
76
77static int dump_procs(FILE *fp, int look_for_login_process)
78{
79 struct dirent *entry;
80 DIR *dir = opendir("/proc");
81 int found_login_process = 0;
82
83 fputs(G.jiffy_line, fp);
84 while ((entry = readdir(dir)) != NULL) {
85 char name[sizeof("/proc/%u/cmdline") + sizeof(int)*3];
86 int stat_fd;
87 unsigned pid = bb_strtou(entry->d_name, NULL, 10);
88 if (errno)
89 continue;
90
91 /* Android's version reads /proc/PID/cmdline and extracts
92 * non-truncated process name. Do we want to do that? */
93
94 sprintf(name, "/proc/%u/stat", pid);
95 stat_fd = open(name, O_RDONLY);
96 if (stat_fd >= 0) {
97 char *p;
98 char stat_line[4*1024];
99 int rd = safe_read(stat_fd, stat_line, sizeof(stat_line)-2);
100
101 close(stat_fd);
102 if (rd < 0)
103 continue;
104 stat_line[rd] = '\0';
105 p = strchrnul(stat_line, '\n');
106 *p++ = '\n';
107 *p = '\0';
108 fputs(stat_line, fp);
109 if (!look_for_login_process)
110 continue;
111 p = strchr(stat_line, '(');
112 if (!p)
113 continue;
114 p++;
115 strchrnul(p, ')')[0] = '\0';
116 /* If is gdm, kdm or a getty? */
117 if (((p[0] == 'g' || p[0] == 'k' || p[0] == 'x') && p[1] == 'd' && p[2] == 'm')
118 || strstr(p, "getty")
119 ) {
120 found_login_process = 1;
121 }
122 }
123 }
124 closedir(dir);
125 fputc('\n', fp);
126 return found_login_process;
127}
128
129static char *make_tempdir(const char *prog)
130{
131 char template[] = "/tmp/bootchart.XXXXXX";
132 char *tempdir = xstrdup(mkdtemp(template));
133 if (!tempdir) {
134 /* /tmp is not writable (happens when we are used as init).
135 * Try to mount a tmpfs, them cd and lazily unmount it.
136 * Since we unmount it at once, we can mount it anywhere.
137 * Try a few locations which are likely ti exist.
138 */
139 static const char dirs[] = "/mnt\0""/tmp\0""/boot\0""/proc\0";
140 const char *try_dir = dirs;
141 while (mount("none", try_dir, "tmpfs", MS_SILENT, "size=16m") != 0) {
142 try_dir += strlen(try_dir) + 1;
143 if (!try_dir[0])
144 bb_perror_msg_and_die("can't %smount tmpfs", "");
145 }
146 //bb_error_msg("mounted tmpfs on %s", try_dir);
147 xchdir(try_dir);
148 if (umount2(try_dir, MNT_DETACH) != 0) {
149 bb_perror_msg_and_die("can't %smount tmpfs", "un");
150 }
151 } else {
152 xchdir(tempdir);
153 }
154 {
155 FILE *header_fp = xfopen("header", "w");
156 if (prog)
157 fprintf(header_fp, "profile.process = %s\n", prog);
158 fputs("version = "BC_VERSION_STR"\n", header_fp);
159 fclose(header_fp);
160 }
161
162 return tempdir;
163}
164
165static void do_logging(void)
166{
167 //# Enable process accounting if configured
168 //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then
169 // [ -e kernel_pacct ] || : > kernel_pacct
170 // accton kernel_pacct
171 //fi
172
173 FILE *proc_stat = xfopen("proc_stat.log", "w");
174 FILE *proc_diskstats = xfopen("proc_diskstats.log", "w");
175 //FILE *proc_netdev = xfopen("proc_netdev.log", "w");
176 FILE *proc_ps = xfopen("proc_ps.log", "w");
177 int look_for_login_process = (getppid() == 1);
178 unsigned count = 60*1000*1000 / (200*1000); /* ~1 minute */
179
180 while (--count && !bb_got_signal) {
181 char *p;
182 int len = open_read_close("/proc/uptime", G.jiffy_line, sizeof(G.jiffy_line)-2);
183 if (len < 0)
184 goto wait_more;
185 /* /proc/uptime has format "NNNNNN.MM NNNNNNN.MM" */
186 /* we convert it to "NNNNNNMM\n" (using first value) */
187 G.jiffy_line[len] = '\0';
188 p = strchr(G.jiffy_line, '.');
189 if (!p)
190 goto wait_more;
191 while (isdigit(*++p))
192 p[-1] = *p;
193 p[-1] = '\n';
194 p[0] = '\0';
195
196 dump_file(proc_stat, "/proc/stat");
197 dump_file(proc_diskstats, "/proc/diskstats");
198 //dump_file(proc_netdev, "/proc/net/dev");
199 if (dump_procs(proc_ps, look_for_login_process)) {
200 /* dump_procs saw a getty or {g,k,x}dm
201 * stop logging in 2 seconds:
202 */
203 if (count > 2*1000*1000 / (200*1000))
204 count = 2*1000*1000 / (200*1000);
205 }
206 fflush_all();
207 wait_more:
208 usleep(200*1000);
209 }
210
211 // [ -e kernel_pacct ] && accton off
212}
213
214static void finalize(char *tempdir)
215{
216 //# Stop process accounting if configured
217 //local pacct=
218 //[ -e kernel_pacct ] && pacct=kernel_pacct
219
220 //(
221 // echo "version = $VERSION"
222 // echo "title = Boot chart for $( hostname | sed q ) ($( date ))"
223 // echo "system.uname = $( uname -srvm | sed q )"
224 // echo "system.release = $( sed q /etc/SuSE-release )"
225 // echo "system.cpu = $( grep '^model name' /proc/cpuinfo | sed q ) ($cpucount)"
226 // echo "system.kernel.options = $( sed q /proc/cmdline )"
227 //) >> header
228
229 /* Package log files */
230 system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct
231 /* Clean up (if we are not in detached tmpfs) */
232 if (tempdir) {
233 unlink("header");
234 unlink("proc_stat.log");
235 unlink("proc_diskstats.log");
236 //unlink("proc_netdev.log");
237 unlink("proc_ps.log");
238 rmdir(tempdir);
239 }
240
241 /* shell-based bootchartd tries to run /usr/bin/bootchart if $AUTO_RENDER=yes:
242 * /usr/bin/bootchart -o "$AUTO_RENDER_DIR" -f $AUTO_RENDER_FORMAT "$BOOTLOG_DEST"
243 */
244}
245
246/* Usage:
247 * bootchartd start [PROG ARGS]: start logging in background, USR1 stops it.
248 * With PROG, runs PROG, then kills background logging.
249 * bootchartd stop: same as "killall -USR1 bootchartd"
250 * bootchartd init: start logging in background
251 * Stop when getty/gdm is seen (if AUTO_STOP_LOGGER = yes).
252 * Meant to be used from init scripts.
253 * bootchartd (pid==1): as init, but then execs $bootchart_init, /init, /sbin/init
254 * Meant to be used as kernel's init process.
255 */
256int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
257int bootchartd_main(int argc UNUSED_PARAM, char **argv)
258{
259 pid_t parent_pid, logger_pid;
260 smallint cmd;
261 enum {
262 CMD_STOP = 0,
263 CMD_START,
264 CMD_INIT,
265 CMD_PID1, /* used to mark pid 1 case */
266 };
267
268 INIT_G();
269
270 parent_pid = getpid();
271 if (argv[1]) {
272 cmd = index_in_strings("stop\0""start\0""init\0", argv[1]);
273 if (cmd < 0)
274 bb_show_usage();
275 if (cmd == CMD_STOP) {
276 pid_t *pidList = find_pid_by_name("bootchartd");
277 while (*pidList != 0) {
278 if (*pidList != parent_pid)
279 kill(*pidList, SIGUSR1);
280 pidList++;
281 }
282 return EXIT_SUCCESS;
283 }
284 } else {
285 if (parent_pid != 1)
286 bb_show_usage();
287 cmd = CMD_PID1;
288 }
289
290 /* Here we are in START or INIT state. Create logger child: */
291 logger_pid = fork_or_rexec(argv);
292
293 if (logger_pid == 0) { /* child */
294 char *tempdir;
295
296 bb_signals(0
297 + (1 << SIGUSR1)
298 + (1 << SIGUSR2)
299 + (1 << SIGTERM)
300 + (1 << SIGQUIT)
301 + (1 << SIGINT)
302 + (1 << SIGHUP)
303 , record_signo);
304
305 if (DO_SIGNAL_SYNC)
306 /* Inform parent that we are ready */
307 raise(SIGSTOP);
308
309 /* If we are started by kernel, PATH might be unset.
310 * In order to find "tar", let's set some sane PATH:
311 */
312 if (cmd == CMD_PID1 && !getenv("PATH"))
313 putenv((char*)bb_PATH_root_path);
314
315 tempdir = make_tempdir(cmd == CMD_START ? argv[2] : NULL);
316 do_logging();
317 finalize(tempdir);
318 return EXIT_SUCCESS;
319 }
320
321 /* parent */
322
323 if (DO_SIGNAL_SYNC) {
324 /* Wait for logger child to set handlers, then unpause it.
325 * Otherwise with short-lived PROG (e.g. "bootchartd start true")
326 * we might send SIGUSR1 before logger sets its handler.
327 */
328 waitpid(logger_pid, NULL, WUNTRACED);
329 kill(logger_pid, SIGCONT);
330 }
331
332 if (cmd == CMD_PID1) {
333 char *bootchart_init = getenv("bootchart_init");
334 if (bootchart_init)
335 execl(bootchart_init, bootchart_init, NULL);
336 execl("/init", "init", NULL);
337 execl("/sbin/init", "init", NULL);
338 bb_perror_msg_and_die("can't exec '%s'", "/sbin/init");
339 }
340
341 if (cmd == CMD_START && argv[2]) { /* "start PROG ARGS" */
342 pid_t pid = vfork();
343 if (pid < 0)
344 bb_perror_msg_and_die("vfork");
345 if (pid == 0) { /* child */
346 argv += 2;
347 execvp(argv[0], argv);
348 bb_perror_msg_and_die("can't exec '%s'", argv[0]);
349 }
350 /* parent */
351 waitpid(pid, NULL, 0);
352 kill(logger_pid, SIGUSR1);
353 }
354
355 return EXIT_SUCCESS;
356}
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index f287e4522..f6dc1f171 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -105,7 +105,9 @@ static const char *unpack_usage_messages(void)
105 105
106static void full_write2_str(const char *str) 106static void full_write2_str(const char *str)
107{ 107{
108 xwrite_str(STDERR_FILENO, str); 108 // This uses stdio:
109 //xwrite_str(STDERR_FILENO, str);
110 write(STDERR_FILENO, str, strlen(str));
109} 111}
110 112
111void FAST_FUNC bb_show_usage(void) 113void FAST_FUNC bb_show_usage(void)
@@ -593,6 +595,17 @@ static void check_suid(int applet_no)
593 595
594 596
595#if ENABLE_FEATURE_INSTALLER 597#if ENABLE_FEATURE_INSTALLER
598static const char usr_bin [] ALIGN1 = "/usr/bin/";
599static const char usr_sbin[] ALIGN1 = "/usr/sbin/";
600static const char *const install_dir[] = {
601 &usr_bin [8], /* "/" */
602 &usr_bin [4], /* "/bin/" */
603 &usr_sbin[4], /* "/sbin/" */
604 usr_bin,
605 usr_sbin
606};
607
608
596/* create (sym)links for each applet */ 609/* create (sym)links for each applet */
597static void install_links(const char *busybox, int use_symbolic_links, 610static void install_links(const char *busybox, int use_symbolic_links,
598 char *custom_install_dir) 611 char *custom_install_dir)
@@ -600,16 +613,6 @@ static void install_links(const char *busybox, int use_symbolic_links,
600 /* directory table 613 /* directory table
601 * this should be consistent w/ the enum, 614 * this should be consistent w/ the enum,
602 * busybox.h::bb_install_loc_t, or else... */ 615 * busybox.h::bb_install_loc_t, or else... */
603 static const char usr_bin [] ALIGN1 = "/usr/bin";
604 static const char usr_sbin[] ALIGN1 = "/usr/sbin";
605 static const char *const install_dir[] = {
606 &usr_bin [8], /* "", equivalent to "/" for concat_path_file() */
607 &usr_bin [4], /* "/bin" */
608 &usr_sbin[4], /* "/sbin" */
609 usr_bin,
610 usr_sbin
611 };
612
613 int (*lf)(const char *, const char *); 616 int (*lf)(const char *, const char *);
614 char *fpc; 617 char *fpc;
615 unsigned i; 618 unsigned i;
@@ -633,8 +636,8 @@ static void install_links(const char *busybox, int use_symbolic_links,
633 } 636 }
634} 637}
635#else 638#else
636#define install_links(x,y,z) ((void)0) 639# define install_links(x,y,z) ((void)0)
637#endif /* FEATURE_INSTALLER */ 640#endif
638 641
639/* If we were called as "busybox..." */ 642/* If we were called as "busybox..." */
640static int busybox_main(char **argv) 643static int busybox_main(char **argv)
@@ -655,19 +658,20 @@ static int busybox_main(char **argv)
655 full_write2_str(bb_banner); /* reuse const string */ 658 full_write2_str(bb_banner); /* reuse const string */
656 full_write2_str(" multi-call binary.\n"); /* reuse */ 659 full_write2_str(" multi-call binary.\n"); /* reuse */
657 full_write2_str( 660 full_write2_str(
658 "Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko\n" 661 "Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko\n"
659 "and others. Licensed under GPLv2.\n" 662 "and others. Licensed under GPLv2.\n"
660 "See source distribution for full notice.\n" 663 "See source distribution for full notice.\n"
661 "\n" 664 "\n"
662 "Usage: busybox [function] [arguments]...\n" 665 "Usage: busybox [function] [arguments]...\n"
663 " or: function [arguments]...\n" 666 " or: function [arguments]...\n"
664 "\n" 667 "\n"
665 "\tBusyBox is a multi-call binary that combines many common Unix\n" 668 "\tBusyBox is a multi-call binary that combines many common Unix\n"
666 "\tutilities into a single executable. Most people will create a\n" 669 "\tutilities into a single executable. Most people will create a\n"
667 "\tlink to busybox for each function they wish to use and BusyBox\n" 670 "\tlink to busybox for each function they wish to use and BusyBox\n"
668 "\twill act like whatever it was invoked as.\n" 671 "\twill act like whatever it was invoked as.\n"
669 "\n" 672 "\n"
670 "Currently defined functions:\n"); 673 "Currently defined functions:\n"
674 );
671 col = 0; 675 col = 0;
672 a = applet_names; 676 a = applet_names;
673 /* prevent last comma to be in the very last pos */ 677 /* prevent last comma to be in the very last pos */
@@ -692,6 +696,23 @@ static int busybox_main(char **argv)
692 return 0; 696 return 0;
693 } 697 }
694 698
699 if (strncmp(argv[1], "--list", 6) == 0) {
700 unsigned i = 0;
701 const char *a = applet_names;
702 dup2(1, 2);
703 while (*a) {
704#if ENABLE_FEATURE_INSTALLER
705 if (argv[1][6]) /* --list-path? */
706 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
707#endif
708 full_write2_str(a);
709 full_write2_str("\n");
710 i++;
711 a += strlen(a) + 1;
712 }
713 return 0;
714 }
715
695 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { 716 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
696 int use_symbolic_links; 717 int use_symbolic_links;
697 const char *busybox; 718 const char *busybox;
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 9a04c38bf..f7faf4639 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -42,14 +42,10 @@
42#include "libbb.h" 42#include "libbb.h"
43#include "unicode.h" 43#include "unicode.h"
44 44
45/* FIXME: obsolete CONFIG item? */
46#define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
47
48#ifdef TEST 45#ifdef TEST
49# define ENABLE_FEATURE_EDITING 0 46# define ENABLE_FEATURE_EDITING 0
50# define ENABLE_FEATURE_TAB_COMPLETION 0 47# define ENABLE_FEATURE_TAB_COMPLETION 0
51# define ENABLE_FEATURE_USERNAME_COMPLETION 0 48# define ENABLE_FEATURE_USERNAME_COMPLETION 0
52# define ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 0
53#endif 49#endif
54 50
55 51
@@ -66,9 +62,13 @@
66#endif 62#endif
67 63
68 64
65#define SEQ_CLEAR_TILL_END_OF_SCREEN "\033[J"
66//#define SEQ_CLEAR_TILL_END_OF_LINE "\033[K"
67
68
69#undef CHAR_T 69#undef CHAR_T
70#if ENABLE_UNICODE_SUPPORT 70#if ENABLE_UNICODE_SUPPORT
71# define BB_NUL L'\0' 71# define BB_NUL ((wchar_t)0)
72# define CHAR_T wchar_t 72# define CHAR_T wchar_t
73static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); } 73static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); }
74# if ENABLE_FEATURE_EDITING_VI 74# if ENABLE_FEATURE_EDITING_VI
@@ -92,6 +92,14 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
92#endif 92#endif
93 93
94 94
95# if ENABLE_UNICODE_PRESERVE_BROKEN
96# define unicode_mark_raw_byte(wc) ((wc) | 0x20000000)
97# define unicode_is_raw_byte(wc) ((wc) & 0x20000000)
98# else
99# define unicode_is_raw_byte(wc) 0
100# endif
101
102
95enum { 103enum {
96 /* We use int16_t for positions, need to limit line len */ 104 /* We use int16_t for positions, need to limit line len */
97 MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0 105 MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0
@@ -208,42 +216,107 @@ static size_t load_string(const char *src, int maxsize)
208 ssize_t len = mbstowcs(command_ps, src, maxsize - 1); 216 ssize_t len = mbstowcs(command_ps, src, maxsize - 1);
209 if (len < 0) 217 if (len < 0)
210 len = 0; 218 len = 0;
211 command_ps[len] = L'\0'; 219 command_ps[len] = 0;
212 return len; 220 return len;
213} 221}
214static size_t save_string(char *dst, int maxsize) 222static unsigned save_string(char *dst, unsigned maxsize)
215{ 223{
224# if !ENABLE_UNICODE_PRESERVE_BROKEN
216 ssize_t len = wcstombs(dst, command_ps, maxsize - 1); 225 ssize_t len = wcstombs(dst, command_ps, maxsize - 1);
217 if (len < 0) 226 if (len < 0)
218 len = 0; 227 len = 0;
219 dst[len] = '\0'; 228 dst[len] = '\0';
220 return len; 229 return len;
230# else
231 unsigned dstpos = 0;
232 unsigned srcpos = 0;
233
234 maxsize--;
235 while (dstpos < maxsize) {
236 wchar_t wc;
237 int n = srcpos;
238 while ((wc = command_ps[srcpos]) != 0
239 && !unicode_is_raw_byte(wc)
240 ) {
241 srcpos++;
242 }
243 command_ps[srcpos] = 0;
244 n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos);
245 if (n < 0) /* should not happen */
246 break;
247 dstpos += n;
248 if (wc == 0) /* usually is */
249 break;
250 /* We do have invalid byte here! */
251 command_ps[srcpos] = wc; /* restore it */
252 srcpos++;
253 if (dstpos == maxsize)
254 break;
255 dst[dstpos++] = (char) wc;
256 }
257 dst[dstpos] = '\0';
258 return dstpos;
259# endif
221} 260}
222/* I thought just fputwc(c, stdout) would work. But no... */ 261/* I thought just fputwc(c, stdout) would work. But no... */
223static void BB_PUTCHAR(wchar_t c) 262static void BB_PUTCHAR(wchar_t c)
224{ 263{
225 char buf[MB_CUR_MAX + 1]; 264 char buf[MB_CUR_MAX + 1];
226 mbstate_t mbst = { 0 }; 265 mbstate_t mbst = { 0 };
227 ssize_t len = wcrtomb(buf, c, &mbst); 266 ssize_t len;
228 267
268 len = wcrtomb(buf, c, &mbst);
229 if (len > 0) { 269 if (len > 0) {
230 buf[len] = '\0'; 270 buf[len] = '\0';
231 fputs(buf, stdout); 271 fputs(buf, stdout);
232 } 272 }
233} 273}
234#else 274# if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS
275static wchar_t adjust_width_and_validate_wc(unsigned *width_adj, wchar_t wc)
276# else
277static wchar_t adjust_width_and_validate_wc(wchar_t wc)
278# define adjust_width_and_validate_wc(width_adj, wc) \
279 ((*(width_adj))++, adjust_width_and_validate_wc(wc))
280# endif
281{
282 int w = 1;
283
284 if (unicode_status == UNICODE_ON) {
285 if (wc > CONFIG_LAST_SUPPORTED_WCHAR) {
286 /* note: also true for unicode_is_raw_byte(wc) */
287 goto subst;
288 }
289 w = wcwidth(wc);
290 if ((ENABLE_UNICODE_COMBINING_WCHARS && w < 0)
291 || (!ENABLE_UNICODE_COMBINING_WCHARS && w <= 0)
292 || (!ENABLE_UNICODE_WIDE_WCHARS && w > 1)
293 ) {
294 subst:
295 w = 1;
296 wc = CONFIG_SUBST_WCHAR;
297 }
298 }
299
300# if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS
301 *width_adj += w;
302#endif
303 return wc;
304}
305#else /* !UNICODE */
235static size_t load_string(const char *src, int maxsize) 306static size_t load_string(const char *src, int maxsize)
236{ 307{
237 safe_strncpy(command_ps, src, maxsize); 308 safe_strncpy(command_ps, src, maxsize);
238 return strlen(command_ps); 309 return strlen(command_ps);
239} 310}
240# if ENABLE_FEATURE_TAB_COMPLETION 311# if ENABLE_FEATURE_TAB_COMPLETION
241static void save_string(char *dst, int maxsize) 312static void save_string(char *dst, unsigned maxsize)
242{ 313{
243 safe_strncpy(dst, command_ps, maxsize); 314 safe_strncpy(dst, command_ps, maxsize);
244} 315}
245# endif 316# endif
246# define BB_PUTCHAR(c) bb_putchar(c) 317# define BB_PUTCHAR(c) bb_putchar(c)
318/* Should never be called: */
319int adjust_width_and_validate_wc(unsigned *width_adj, int wc);
247#endif 320#endif
248 321
249 322
@@ -251,38 +324,35 @@ static void save_string(char *dst, int maxsize)
251 * Advance cursor on screen. If we reached right margin, scroll text up 324 * Advance cursor on screen. If we reached right margin, scroll text up
252 * and remove terminal margin effect by printing 'next_char' */ 325 * and remove terminal margin effect by printing 'next_char' */
253#define HACK_FOR_WRONG_WIDTH 1 326#define HACK_FOR_WRONG_WIDTH 1
254#if HACK_FOR_WRONG_WIDTH 327static void put_cur_glyph_and_inc_cursor(void)
255static void cmdedit_set_out_char(void)
256#define cmdedit_set_out_char(next_char) cmdedit_set_out_char()
257#else
258static void cmdedit_set_out_char(int next_char)
259#endif
260{ 328{
261 CHAR_T c = command_ps[cursor]; 329 CHAR_T c = command_ps[cursor];
330 unsigned width = 0;
331 int ofs_to_right;
262 332
263 if (c == BB_NUL) { 333 if (c == BB_NUL) {
264 /* erase character after end of input string */ 334 /* erase character after end of input string */
265 c = ' '; 335 c = ' ';
336 } else {
337 /* advance cursor only if we aren't at the end yet */
338 cursor++;
339 if (unicode_status == UNICODE_ON) {
340 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;)
341 c = adjust_width_and_validate_wc(&cmdedit_x, c);
342 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;)
343 } else {
344 cmdedit_x++;
345 }
266 } 346 }
267#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 347
268 /* Display non-printable characters in reverse */ 348 ofs_to_right = cmdedit_x - cmdedit_termw;
269 if (!BB_isprint(c)) { 349 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) {
270 if (c >= 128) 350 /* c fits on this line */
271 c -= 128;
272 if (c < ' ')
273 c += '@';
274 if (c == 127)
275 c = '?';
276 printf("\033[7m%c\033[0m", c);
277 } else
278#endif
279 {
280 BB_PUTCHAR(c); 351 BB_PUTCHAR(c);
281 } 352 }
282 if (++cmdedit_x >= cmdedit_termw) { 353
283 /* terminal is scrolled down */ 354 if (ofs_to_right >= 0) {
284 cmdedit_y++; 355 /* we go to the next line */
285 cmdedit_x = 0;
286#if HACK_FOR_WRONG_WIDTH 356#if HACK_FOR_WRONG_WIDTH
287 /* This works better if our idea of term width is wrong 357 /* This works better if our idea of term width is wrong
288 * and it is actually wider (often happens on serial lines). 358 * and it is actually wider (often happens on serial lines).
@@ -293,55 +363,83 @@ static void cmdedit_set_out_char(int next_char)
293 * this will break things: there will be one extra empty line */ 363 * this will break things: there will be one extra empty line */
294 puts("\r"); /* + implicit '\n' */ 364 puts("\r"); /* + implicit '\n' */
295#else 365#else
296 /* Works ok only if cmdedit_termw is correct */ 366 /* VT-10x terminals don't wrap cursor to next line when last char
297 /* destroy "(auto)margin" */ 367 * on the line is printed - cursor stays "over" this char.
298 bb_putchar(next_char); 368 * Need to print _next_ char too (first one to appear on next line)
369 * to make cursor move down to next line.
370 */
371 /* Works ok only if cmdedit_termw is correct. */
372 c = command_ps[cursor];
373 if (c == BB_NUL)
374 c = ' ';
375 BB_PUTCHAR(c);
299 bb_putchar('\b'); 376 bb_putchar('\b');
300#endif 377#endif
378 cmdedit_y++;
379 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) {
380 width = 0;
381 } else { /* ofs_to_right > 0 */
382 /* wide char c didn't fit on prev line */
383 BB_PUTCHAR(c);
384 }
385 cmdedit_x = width;
301 } 386 }
302// Huh? What if command_ps[cursor] == BB_NUL (we are at the end already?)
303 cursor++;
304} 387}
305 388
306/* Move to end of line (by printing all chars till the end) */ 389/* Move to end of line (by printing all chars till the end) */
307static void input_end(void) 390static void put_till_end_and_adv_cursor(void)
308{ 391{
309 while (cursor < command_len) 392 while (cursor < command_len)
310 cmdedit_set_out_char(' '); 393 put_cur_glyph_and_inc_cursor();
311} 394}
312 395
313/* Go to the next line */ 396/* Go to the next line */
314static void goto_new_line(void) 397static void goto_new_line(void)
315{ 398{
316 input_end(); 399 put_till_end_and_adv_cursor();
317 if (cmdedit_x) 400 if (cmdedit_x != 0)
318 bb_putchar('\n'); 401 bb_putchar('\n');
319} 402}
320 403
321 404static void beep(void)
322static void out1str(const char *s)
323{ 405{
324 if (s) 406 bb_putchar('\007');
325 fputs(s, stdout);
326} 407}
327 408
328static void beep(void) 409static void put_prompt(void)
329{ 410{
330 bb_putchar('\007'); 411 unsigned w;
412
413 fputs(cmdedit_prompt, stdout);
414 fflush_all();
415 cursor = 0;
416 w = cmdedit_termw; /* read volatile var once */
417 cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */
418 cmdedit_x = cmdedit_prmt_len % w;
331} 419}
332 420
333/* Move back one character */ 421/* Move back one character */
334/* (optimized for slow terminals) */ 422/* (optimized for slow terminals) */
335static void input_backward(unsigned num) 423static void input_backward(unsigned num)
336{ 424{
337 int count_y;
338
339 if (num > cursor) 425 if (num > cursor)
340 num = cursor; 426 num = cursor;
341 if (!num) 427 if (num == 0)
342 return; 428 return;
343 cursor -= num; 429 cursor -= num;
344 430
431 if ((ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS)
432 && unicode_status == UNICODE_ON
433 ) {
434 /* correct NUM to be equal to _screen_ width */
435 int n = num;
436 num = 0;
437 while (--n >= 0)
438 adjust_width_and_validate_wc(&num, command_ps[cursor + n]);
439 if (num == 0)
440 return;
441 }
442
345 if (cmdedit_x >= num) { 443 if (cmdedit_x >= num) {
346 cmdedit_x -= num; 444 cmdedit_x -= num;
347 if (num <= 4) { 445 if (num <= 4) {
@@ -361,38 +459,61 @@ static void input_backward(unsigned num)
361 } 459 }
362 460
363 /* Need to go one or more lines up */ 461 /* Need to go one or more lines up */
364 num -= cmdedit_x; 462 if (ENABLE_UNICODE_WIDE_WCHARS) {
365 { 463 /* With wide chars, it is hard to "backtrack"
366 unsigned w = cmdedit_termw; /* volatile var */ 464 * and reliably figure out where to put cursor.
367 count_y = 1 + (num / w); 465 * Example (<> is a wide char; # is an ordinary char, _ cursor):
368 cmdedit_y -= count_y; 466 * |prompt: <><> |
369 cmdedit_x = w * count_y - num; 467 * |<><><><><><> |
468 * |_ |
469 * and user presses left arrow. num = 1, cmdedit_x = 0,
470 * We need to go up one line, and then - how do we know that
471 * we need to go *10* positions to the right? Because
472 * |prompt: <>#<>|
473 * |<><><>#<><><>|
474 * |_ |
475 * in this situation we need to go *11* positions to the right.
476 *
477 * A simpler thing to do is to redraw everything from the start
478 * up to new cursor position (which is already known):
479 */
480 unsigned sv_cursor;
481 /* go to 1st column; go up to first line */
482 printf("\r" "\033[%uA", cmdedit_y);
483 cmdedit_y = 0;
484 sv_cursor = cursor;
485 put_prompt(); /* sets cursor to 0 */
486 while (cursor < sv_cursor)
487 put_cur_glyph_and_inc_cursor();
488 } else {
489 int lines_up;
490 unsigned width;
491 /* num = chars to go back from the beginning of current line: */
492 num -= cmdedit_x;
493 width = cmdedit_termw; /* read volatile var once */
494 /* num=1...w: one line up, w+1...2w: two, etc: */
495 lines_up = 1 + (num - 1) / width;
496 cmdedit_x = (width * cmdedit_y - num) % width;
497 cmdedit_y -= lines_up;
498 /* go to 1st column; go up */
499 printf("\r" "\033[%uA", lines_up);
500 /* go to correct column.
501 * xterm, konsole, Linux VT interpret 0 as 1 below! wow.
502 * need to *make sure* we skip it if cmdedit_x == 0 */
503 if (cmdedit_x)
504 printf("\033[%uC", cmdedit_x);
370 } 505 }
371 /* go to 1st column; go up; go to correct column */
372 printf("\r" "\033[%dA" "\033[%dC", count_y, cmdedit_x);
373}
374
375static void put_prompt(void)
376{
377 unsigned w;
378
379 out1str(cmdedit_prompt);
380 fflush_all();
381 cursor = 0;
382 w = cmdedit_termw; /* read volatile var once */
383 cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */
384 cmdedit_x = cmdedit_prmt_len % w;
385} 506}
386 507
387/* draw prompt, editor line, and clear tail */ 508/* draw prompt, editor line, and clear tail */
388static void redraw(int y, int back_cursor) 509static void redraw(int y, int back_cursor)
389{ 510{
390 if (y > 0) /* up to start y */ 511 if (y > 0) /* up y lines */
391 printf("\033[%uA", y); 512 printf("\033[%uA", y);
392 bb_putchar('\r'); 513 bb_putchar('\r');
393 put_prompt(); 514 put_prompt();
394 input_end(); /* rewrite */ 515 put_till_end_and_adv_cursor();
395 printf("\033[J"); /* erase after cursor */ 516 printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
396 input_backward(back_cursor); 517 input_backward(back_cursor);
397} 518}
398 519
@@ -426,8 +547,9 @@ static void input_delete(int save)
426 * simplified into (command_len - j) */ 547 * simplified into (command_len - j) */
427 (command_len - j) * sizeof(command_ps[0])); 548 (command_len - j) * sizeof(command_ps[0]));
428 command_len--; 549 command_len--;
429 input_end(); /* rewrite new line */ 550 put_till_end_and_adv_cursor();
430 cmdedit_set_out_char(' '); /* erase char */ 551 /* Last char is still visible, erase it (and more) */
552 printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
431 input_backward(cursor - j); /* back to old pos cursor */ 553 input_backward(cursor - j); /* back to old pos cursor */
432} 554}
433 555
@@ -445,7 +567,7 @@ static void put(void)
445 (command_len - cursor + 1) * sizeof(command_ps[0])); 567 (command_len - cursor + 1) * sizeof(command_ps[0]));
446 memcpy(command_ps + cursor, delbuf, j * sizeof(command_ps[0])); 568 memcpy(command_ps + cursor, delbuf, j * sizeof(command_ps[0]));
447 command_len += j; 569 command_len += j;
448 input_end(); /* rewrite new line */ 570 put_till_end_and_adv_cursor();
449 input_backward(cursor - ocursor - j + 1); /* at end of new text */ 571 input_backward(cursor - ocursor - j + 1); /* at end of new text */
450} 572}
451#endif 573#endif
@@ -463,7 +585,7 @@ static void input_backspace(void)
463static void input_forward(void) 585static void input_forward(void)
464{ 586{
465 if (cursor < command_len) 587 if (cursor < command_len)
466 cmdedit_set_out_char(command_ps[cursor + 1]); 588 put_cur_glyph_and_inc_cursor();
467} 589}
468 590
469#if ENABLE_FEATURE_TAB_COMPLETION 591#if ENABLE_FEATURE_TAB_COMPLETION
@@ -721,21 +843,13 @@ static NOINLINE int find_match(char *matchBuf, int *len_with_quotes)
721 } 843 }
722 844
723 /* mask \+symbol and convert '\t' to ' ' */ 845 /* mask \+symbol and convert '\t' to ' ' */
724 for (i = j = 0; matchBuf[i]; i++, j++) 846 for (i = j = 0; matchBuf[i]; i++, j++) {
725 if (matchBuf[i] == '\\') { 847 if (matchBuf[i] == '\\') {
726 collapse_pos(j, j + 1); 848 collapse_pos(j, j + 1);
727 int_buf[j] |= QUOT; 849 int_buf[j] |= QUOT;
728 i++; 850 i++;
729#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
730 if (matchBuf[i] == '\t') /* algorithm equivalent */
731 int_buf[j] = ' ' | QUOT;
732#endif
733 } 851 }
734#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT 852 }
735 else if (matchBuf[i] == '\t')
736 int_buf[j] = ' ';
737#endif
738
739 /* mask "symbols" or 'symbols' */ 853 /* mask "symbols" or 'symbols' */
740 c2 = 0; 854 c2 = 0;
741 for (i = 0; int_buf[i]; i++) { 855 for (i = 0; int_buf[i]; i++) {
@@ -1509,7 +1623,7 @@ static void ask_terminal(void)
1509 pfd.events = POLLIN; 1623 pfd.events = POLLIN;
1510 if (safe_poll(&pfd, 1, 0) == 0) { 1624 if (safe_poll(&pfd, 1, 0) == 0) {
1511 S.sent_ESC_br6n = 1; 1625 S.sent_ESC_br6n = 1;
1512 out1str("\033" "[6n"); 1626 fputs("\033" "[6n", stdout);
1513 fflush_all(); /* make terminal see it ASAP! */ 1627 fflush_all(); /* make terminal see it ASAP! */
1514 } 1628 }
1515} 1629}
@@ -1727,13 +1841,11 @@ static int lineedit_read_key(char *read_key_buffer)
1727 pushback: 1841 pushback:
1728 /* Invalid sequence. Save all "bad bytes" except first */ 1842 /* Invalid sequence. Save all "bad bytes" except first */
1729 read_key_ungets(read_key_buffer, unicode_buf + 1, unicode_idx - 1); 1843 read_key_ungets(read_key_buffer, unicode_buf + 1, unicode_idx - 1);
1730 /* 1844# if !ENABLE_UNICODE_PRESERVE_BROKEN
1731 * ic = unicode_buf[0] sounds even better, but currently
1732 * this does not work: wchar_t[] -> char[] conversion
1733 * when lineedit finishes mangles such "raw bytes"
1734 * (by misinterpreting them as unicode chars):
1735 */
1736 ic = CONFIG_SUBST_WCHAR; 1845 ic = CONFIG_SUBST_WCHAR;
1846# else
1847 ic = unicode_mark_raw_byte(unicode_buf[0]);
1848# endif
1737 } else { 1849 } else {
1738 /* Valid unicode char, return its code */ 1850 /* Valid unicode char, return its code */
1739 ic = wc; 1851 ic = wc;
@@ -1925,7 +2037,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1925 case CTRL('E'): 2037 case CTRL('E'):
1926 vi_case('$'|VI_CMDMODE_BIT:) 2038 vi_case('$'|VI_CMDMODE_BIT:)
1927 /* Control-e -- End of line */ 2039 /* Control-e -- End of line */
1928 input_end(); 2040 put_till_end_and_adv_cursor();
1929 break; 2041 break;
1930 case CTRL('F'): 2042 case CTRL('F'):
1931 vi_case('l'|VI_CMDMODE_BIT:) 2043 vi_case('l'|VI_CMDMODE_BIT:)
@@ -1954,12 +2066,12 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1954 /* Control-k -- clear to end of line */ 2066 /* Control-k -- clear to end of line */
1955 command_ps[cursor] = BB_NUL; 2067 command_ps[cursor] = BB_NUL;
1956 command_len = cursor; 2068 command_len = cursor;
1957 printf("\033[J"); 2069 printf(SEQ_CLEAR_TILL_END_OF_SCREEN);
1958 break; 2070 break;
1959 case CTRL('L'): 2071 case CTRL('L'):
1960 vi_case(CTRL('L')|VI_CMDMODE_BIT:) 2072 vi_case(CTRL('L')|VI_CMDMODE_BIT:)
1961 /* Control-l -- clear screen */ 2073 /* Control-l -- clear screen */
1962 printf("\033[H"); 2074 printf("\033[H"); /* cursor to top,left */
1963 redraw(0, command_len - cursor); 2075 redraw(0, command_len - cursor);
1964 break; 2076 break;
1965#if MAX_HISTORY > 0 2077#if MAX_HISTORY > 0
@@ -2010,7 +2122,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2010 vi_cmdmode = 0; 2122 vi_cmdmode = 0;
2011 break; 2123 break;
2012 case 'A'|VI_CMDMODE_BIT: 2124 case 'A'|VI_CMDMODE_BIT:
2013 input_end(); 2125 put_till_end_and_adv_cursor();
2014 vi_cmdmode = 0; 2126 vi_cmdmode = 0;
2015 break; 2127 break;
2016 case 'x'|VI_CMDMODE_BIT: 2128 case 'x'|VI_CMDMODE_BIT:
@@ -2170,7 +2282,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2170 input_backward(cursor); 2282 input_backward(cursor);
2171 break; 2283 break;
2172 case KEYCODE_END: 2284 case KEYCODE_END:
2173 input_end(); 2285 put_till_end_and_adv_cursor();
2174 break; 2286 break;
2175 2287
2176 default: 2288 default:
@@ -2230,7 +2342,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2230 /* We are at the end, append */ 2342 /* We are at the end, append */
2231 command_ps[cursor] = ic; 2343 command_ps[cursor] = ic;
2232 command_ps[cursor + 1] = BB_NUL; 2344 command_ps[cursor + 1] = BB_NUL;
2233 cmdedit_set_out_char(' '); 2345 put_cur_glyph_and_inc_cursor();
2234 if (unicode_bidi_isrtl(ic)) 2346 if (unicode_bidi_isrtl(ic))
2235 input_backward(1); 2347 input_backward(1);
2236 } else { 2348 } else {
@@ -2243,8 +2355,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2243 /* is right-to-left char, or neutral one (e.g. comma) was just added to rtl text? */ 2355 /* is right-to-left char, or neutral one (e.g. comma) was just added to rtl text? */
2244 if (!isrtl_str()) 2356 if (!isrtl_str())
2245 sc++; /* no */ 2357 sc++; /* no */
2246 /* rewrite from cursor */ 2358 put_till_end_and_adv_cursor();
2247 input_end();
2248 /* to prev x pos + 1 */ 2359 /* to prev x pos + 1 */
2249 input_backward(cursor - sc); 2360 input_backward(cursor - sc);
2250 } 2361 }
@@ -2345,9 +2456,6 @@ int main(int argc, char **argv)
2345 "% "; 2456 "% ";
2346#endif 2457#endif
2347 2458
2348#if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT
2349 setlocale(LC_ALL, "");
2350#endif
2351 while (1) { 2459 while (1) {
2352 int l; 2460 int l;
2353 l = read_line_input(prompt, buff); 2461 l = read_line_input(prompt, buff);
diff --git a/libbb/read.c b/libbb/read.c
index 06ce29718..f3af144f0 100644
--- a/libbb/read.c
+++ b/libbb/read.c
@@ -6,7 +6,6 @@
6 * 6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */ 8 */
9
10#include "libbb.h" 9#include "libbb.h"
11 10
12#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ 11#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \
@@ -16,7 +15,7 @@
16) 15)
17 16
18#if ZIPPED 17#if ZIPPED
19#include "unarchive.h" 18# include "unarchive.h"
20#endif 19#endif
21 20
22ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count) 21ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count)
@@ -306,14 +305,11 @@ void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p)
306 return buf; 305 return buf;
307} 306}
308 307
309int FAST_FUNC open_zipped(const char *fname) 308#if ZIPPED
309int FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/)
310{ 310{
311#if !ZIPPED 311 const int fail_if_not_detected = 1;
312 return open(fname, O_RDONLY);
313#else
314 unsigned char magic[2]; 312 unsigned char magic[2];
315 char *sfx;
316 int fd;
317#if BB_MMU 313#if BB_MMU
318 IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); 314 IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd);
319 enum { xformer_prog = 0 }; 315 enum { xformer_prog = 0 };
@@ -322,6 +318,62 @@ int FAST_FUNC open_zipped(const char *fname)
322 const char *xformer_prog; 318 const char *xformer_prog;
323#endif 319#endif
324 320
321 /* .gz and .bz2 both have 2-byte signature, and their
322 * unpack_XXX_stream wants this header skipped. */
323 xread(fd, &magic, 2);
324 if (ENABLE_FEATURE_SEAMLESS_GZ
325 && magic[0] == 0x1f && magic[1] == 0x8b
326 ) {
327# if BB_MMU
328 xformer = unpack_gz_stream;
329# else
330 xformer_prog = "gunzip";
331# endif
332 goto found_magic;
333 }
334 if (ENABLE_FEATURE_SEAMLESS_BZ2
335 && magic[0] == 'B' && magic[1] == 'Z'
336 ) {
337# if BB_MMU
338 xformer = unpack_bz2_stream;
339# else
340 xformer_prog = "bunzip2";
341# endif
342 goto found_magic;
343 }
344// TODO: xz format support. rpm adopted it, "rpm -i FILE.rpm" badly needs this.
345// Signature: 0xFD, '7', 'z', 'X', 'Z', 0x00
346// More info at: http://tukaani.org/xz/xz-file-format.txt
347
348 /* No known magic seen */
349 if (fail_if_not_detected)
350 bb_error_msg_and_die("no gzip"
351 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
352 " magic");
353 xlseek(fd, -2, SEEK_CUR);
354 return fd;
355
356 found_magic:
357# if !BB_MMU
358 /* NOMMU version of open_transformer execs
359 * an external unzipper that wants
360 * file position at the start of the file */
361 xlseek(fd, -2, SEEK_CUR);
362# endif
363 open_transformer(fd, xformer, xformer_prog);
364
365 return fd;
366}
367#endif /* ZIPPED */
368
369int FAST_FUNC open_zipped(const char *fname)
370{
371#if !ZIPPED
372 return open(fname, O_RDONLY);
373#else
374 char *sfx;
375 int fd;
376
325 fd = open(fname, O_RDONLY); 377 fd = open(fname, O_RDONLY);
326 if (fd < 0) 378 if (fd < 0)
327 return fd; 379 return fd;
@@ -335,40 +387,7 @@ int FAST_FUNC open_zipped(const char *fname)
335 if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, ".gz") == 0) 387 if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, ".gz") == 0)
336 || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, ".bz2") == 0) 388 || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, ".bz2") == 0)
337 ) { 389 ) {
338 /* .gz and .bz2 both have 2-byte signature, and their 390 setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/);
339 * unpack_XXX_stream wants this header skipped. */
340 xread(fd, &magic, 2);
341#if ENABLE_FEATURE_SEAMLESS_GZ
342#if BB_MMU
343 xformer = unpack_gz_stream;
344#else
345 xformer_prog = "gunzip";
346#endif
347#endif
348 if (!ENABLE_FEATURE_SEAMLESS_GZ
349 || magic[0] != 0x1f || magic[1] != 0x8b
350 ) {
351 if (!ENABLE_FEATURE_SEAMLESS_BZ2
352 || magic[0] != 'B' || magic[1] != 'Z'
353 ) {
354 bb_error_msg_and_die("no gzip"
355 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
356 " magic");
357 }
358#if BB_MMU
359 xformer = unpack_bz2_stream;
360#else
361 xformer_prog = "bunzip2";
362#endif
363 } else {
364#if !BB_MMU
365 /* NOMMU version of open_transformer execs
366 * an external unzipper that wants
367 * file position at the start of the file */
368 xlseek(fd, 0, SEEK_SET);
369#endif
370 }
371 open_transformer(fd, xformer, xformer_prog);
372 } 391 }
373 } 392 }
374 393
diff --git a/libbb/read_key.c b/libbb/read_key.c
index 8422976c9..64557ab14 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -214,7 +214,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
214 } 214 }
215 n++; 215 n++;
216 /* Try to decipher "ESC [ NNN ; NNN R" sequence */ 216 /* Try to decipher "ESC [ NNN ; NNN R" sequence */
217 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL 217 if ((ENABLE_FEATURE_EDITING_ASK_TERMINAL || ENABLE_FEATURE_VI_ASK_TERMINAL)
218 && n >= 5 218 && n >= 5
219 && buffer[0] == '[' 219 && buffer[0] == '['
220 && buffer[n-1] == 'R' 220 && buffer[n-1] == 'R'
diff --git a/libbb/time.c b/libbb/time.c
index 5cd04268c..8d176e52e 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -68,6 +68,16 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
68 end = '\0'; 68 end = '\0';
69 /* else end != NUL and we error out */ 69 /* else end != NUL and we error out */
70 } 70 }
71 } else if (date_str[0] == '@') {
72 time_t t = bb_strtol(date_str + 1, NULL, 10);
73 if (!errno) {
74 struct tm *lt = localtime(&t);
75 if (lt) {
76 *ptm = *lt;
77 return;
78 }
79 }
80 end = '1';
71 } else { 81 } else {
72 /* Googled the following on an old date manpage: 82 /* Googled the following on an old date manpage:
73 * 83 *
diff --git a/libbb/unicode.c b/libbb/unicode.c
index 83e70b412..b2c28239b 100644
--- a/libbb/unicode.c
+++ b/libbb/unicode.c
@@ -240,7 +240,7 @@ int FAST_FUNC iswpunct(wint_t wc)
240} 240}
241 241
242 242
243# if LAST_SUPPORTED_WCHAR >= 0x300 243# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300
244struct interval { 244struct interval {
245 uint16_t first; 245 uint16_t first;
246 uint16_t last; 246 uint16_t last;
@@ -418,12 +418,11 @@ static int in_uint16_table(unsigned ucs, const uint16_t *table, unsigned max)
418 * This implementation assumes that wchar_t characters are encoded 418 * This implementation assumes that wchar_t characters are encoded
419 * in ISO 10646. 419 * in ISO 10646.
420 */ 420 */
421static int wcwidth(unsigned ucs) 421int FAST_FUNC wcwidth(unsigned ucs)
422{ 422{
423# if LAST_SUPPORTED_WCHAR >= 0x300 423# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300
424 /* sorted list of non-overlapping intervals of non-spacing characters */ 424 /* sorted list of non-overlapping intervals of non-spacing characters */
425 /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ 425 /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
426 static const struct interval combining[] = {
427# define BIG_(a,b) { a, b }, 426# define BIG_(a,b) { a, b },
428# define PAIR(a,b) 427# define PAIR(a,b)
429# define ARRAY /* PAIR if < 0x4000 and no more than 4 chars big */ \ 428# define ARRAY /* PAIR if < 0x4000 and no more than 4 chars big */ \
@@ -557,10 +556,9 @@ static int wcwidth(unsigned ucs)
557 BIG_(0xFE20, 0xFE23) \ 556 BIG_(0xFE20, 0xFE23) \
558 BIG_(0xFEFF, 0xFEFF) \ 557 BIG_(0xFEFF, 0xFEFF) \
559 BIG_(0xFFF9, 0xFFFB) 558 BIG_(0xFFF9, 0xFFFB)
560 ARRAY 559 static const struct interval combining[] = { ARRAY };
561# undef BIG_ 560# undef BIG_
562# undef PAIR 561# undef PAIR
563 };
564# define BIG_(a,b) 562# define BIG_(a,b)
565# define PAIR(a,b) (a << 2) | (b-a), 563# define PAIR(a,b) (a << 2) | (b-a),
566 static const uint16_t combining1[] = { ARRAY }; 564 static const uint16_t combining1[] = { ARRAY };
@@ -581,14 +579,14 @@ static int wcwidth(unsigned ucs)
581 if ((ucs & ~0x80) < 0x20 || ucs == 0x7f) 579 if ((ucs & ~0x80) < 0x20 || ucs == 0x7f)
582 return -1; 580 return -1;
583 /* Quick abort if it is an obviously invalid char */ 581 /* Quick abort if it is an obviously invalid char */
584 if (ucs > LAST_SUPPORTED_WCHAR) 582 if (ucs > CONFIG_LAST_SUPPORTED_WCHAR)
585 return -1; 583 return -1;
586 584
587 /* Optimization: no combining chars below 0x300 */ 585 /* Optimization: no combining chars below 0x300 */
588 if (LAST_SUPPORTED_WCHAR < 0x300 || ucs < 0x300) 586 if (CONFIG_LAST_SUPPORTED_WCHAR < 0x300 || ucs < 0x300)
589 return 1; 587 return 1;
590 588
591# if LAST_SUPPORTED_WCHAR >= 0x300 589# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300
592 /* Binary search in table of non-spacing characters */ 590 /* Binary search in table of non-spacing characters */
593 if (in_interval_table(ucs, combining, ARRAY_SIZE(combining) - 1)) 591 if (in_interval_table(ucs, combining, ARRAY_SIZE(combining) - 1))
594 return 0; 592 return 0;
@@ -596,25 +594,25 @@ static int wcwidth(unsigned ucs)
596 return 0; 594 return 0;
597 595
598 /* Optimization: all chars below 0x1100 are not double-width */ 596 /* Optimization: all chars below 0x1100 are not double-width */
599 if (LAST_SUPPORTED_WCHAR < 0x1100 || ucs < 0x1100) 597 if (CONFIG_LAST_SUPPORTED_WCHAR < 0x1100 || ucs < 0x1100)
600 return 1; 598 return 1;
601 599
602# if LAST_SUPPORTED_WCHAR >= 0x1100 600# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x1100
603 /* Invalid code points: */ 601 /* Invalid code points: */
604 /* High (d800..dbff) and low (dc00..dfff) surrogates (valid only in UTF16) */ 602 /* High (d800..dbff) and low (dc00..dfff) surrogates (valid only in UTF16) */
605 /* Private Use Area (e000..f8ff) */ 603 /* Private Use Area (e000..f8ff) */
606 /* Noncharacters fdd0..fdef */ 604 /* Noncharacters fdd0..fdef */
607 if ((LAST_SUPPORTED_WCHAR >= 0xd800 && ucs >= 0xd800 && ucs <= 0xf8ff) 605 if ((CONFIG_LAST_SUPPORTED_WCHAR >= 0xd800 && ucs >= 0xd800 && ucs <= 0xf8ff)
608 || (LAST_SUPPORTED_WCHAR >= 0xfdd0 && ucs >= 0xfdd0 && ucs <= 0xfdef) 606 || (CONFIG_LAST_SUPPORTED_WCHAR >= 0xfdd0 && ucs >= 0xfdd0 && ucs <= 0xfdef)
609 ) { 607 ) {
610 return -1; 608 return -1;
611 } 609 }
612 /* 0xfffe and 0xffff in every plane are invalid */ 610 /* 0xfffe and 0xffff in every plane are invalid */
613 if (LAST_SUPPORTED_WCHAR >= 0xfffe && ((ucs & 0xfffe) == 0xfffe)) { 611 if (CONFIG_LAST_SUPPORTED_WCHAR >= 0xfffe && ((ucs & 0xfffe) == 0xfffe)) {
614 return -1; 612 return -1;
615 } 613 }
616 614
617# if LAST_SUPPORTED_WCHAR >= 0x10000 615# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x10000
618 if (ucs >= 0x10000) { 616 if (ucs >= 0x10000) {
619 /* Combining chars in Supplementary Multilingual Plane 0x1xxxx */ 617 /* Combining chars in Supplementary Multilingual Plane 0x1xxxx */
620 static const struct interval combining0x10000[] = { 618 static const struct interval combining0x10000[] = {
@@ -627,7 +625,7 @@ static int wcwidth(unsigned ucs)
627 if (in_interval_table(ucs ^ 0x10000, combining0x10000, ARRAY_SIZE(combining0x10000) - 1)) 625 if (in_interval_table(ucs ^ 0x10000, combining0x10000, ARRAY_SIZE(combining0x10000) - 1))
628 return 0; 626 return 0;
629 /* Check a few non-spacing chars in Supplementary Special-purpose Plane 0xExxxx */ 627 /* Check a few non-spacing chars in Supplementary Special-purpose Plane 0xExxxx */
630 if (LAST_SUPPORTED_WCHAR >= 0xE0001 628 if (CONFIG_LAST_SUPPORTED_WCHAR >= 0xE0001
631 && ( ucs == 0xE0001 629 && ( ucs == 0xE0001
632 || (ucs >= 0xE0020 && ucs <= 0xE007F) 630 || (ucs >= 0xE0020 && ucs <= 0xE007F)
633 || (ucs >= 0xE0100 && ucs <= 0xE01EF) 631 || (ucs >= 0xE0100 && ucs <= 0xE01EF)
@@ -646,7 +644,7 @@ static int wcwidth(unsigned ucs)
646 || ucs == 0x2329 /* left-pointing angle bracket; also CJK punct. char */ 644 || ucs == 0x2329 /* left-pointing angle bracket; also CJK punct. char */
647 || ucs == 0x232a /* right-pointing angle bracket; also CJK punct. char */ 645 || ucs == 0x232a /* right-pointing angle bracket; also CJK punct. char */
648 || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) /* CJK ... Yi */ 646 || (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) /* CJK ... Yi */
649# if LAST_SUPPORTED_WCHAR >= 0xac00 647# if CONFIG_LAST_SUPPORTED_WCHAR >= 0xac00
650 || (ucs >= 0xac00 && ucs <= 0xd7a3) /* Hangul Syllables */ 648 || (ucs >= 0xac00 && ucs <= 0xd7a3) /* Hangul Syllables */
651 || (ucs >= 0xf900 && ucs <= 0xfaff) /* CJK Compatibility Ideographs */ 649 || (ucs >= 0xf900 && ucs <= 0xfaff) /* CJK Compatibility Ideographs */
652 || (ucs >= 0xfe10 && ucs <= 0xfe19) /* Vertical forms */ 650 || (ucs >= 0xfe10 && ucs <= 0xfe19) /* Vertical forms */
@@ -668,7 +666,6 @@ int FAST_FUNC unicode_bidi_isrtl(wint_t wc)
668 * http://www.unicode.org/Public/5.2.0/ucd/extracted/DerivedBidiClass.txt 666 * http://www.unicode.org/Public/5.2.0/ucd/extracted/DerivedBidiClass.txt
669 * Bidi_Class=Left_To_Right | Bidi_Class=Arabic_Letter 667 * Bidi_Class=Left_To_Right | Bidi_Class=Arabic_Letter
670 */ 668 */
671 static const struct interval rtl_b[] = {
672# define BIG_(a,b) { a, b }, 669# define BIG_(a,b) { a, b },
673# define PAIR(a,b) 670# define PAIR(a,b)
674# define ARRAY \ 671# define ARRAY \
@@ -723,10 +720,9 @@ int FAST_FUNC unicode_bidi_isrtl(wint_t wc)
723 {0x10E7F, 0x10FFF}, 720 {0x10E7F, 0x10FFF},
724 {0x1E800, 0x1EFFF} 721 {0x1E800, 0x1EFFF}
725 */ 722 */
726 ARRAY 723 static const struct interval rtl_b[] = { ARRAY };
727# undef BIG_ 724# undef BIG_
728# undef PAIR 725# undef PAIR
729 };
730# define BIG_(a,b) 726# define BIG_(a,b)
731# define PAIR(a,b) (a << 2) | (b-a), 727# define PAIR(a,b) (a << 2) | (b-a),
732 static const uint16_t rtl_p[] = { ARRAY }; 728 static const uint16_t rtl_p[] = { ARRAY };
@@ -755,7 +751,6 @@ int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc)
755 * White_Space, Other_Neutral, European_Number, European_Separator, 751 * White_Space, Other_Neutral, European_Number, European_Separator,
756 * European_Terminator, Arabic_Number, Common_Separator 752 * European_Terminator, Arabic_Number, Common_Separator
757 */ 753 */
758 static const struct interval neutral_b[] = {
759# define BIG_(a,b) { a, b }, 754# define BIG_(a,b) { a, b },
760# define PAIR(a,b) 755# define PAIR(a,b)
761# define ARRAY \ 756# define ARRAY \
@@ -929,10 +924,9 @@ int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc)
929 {0x1F030, 0x1F093}, 924 {0x1F030, 0x1F093},
930 {0x1F100, 0x1F10A} 925 {0x1F100, 0x1F10A}
931 */ 926 */
932 ARRAY 927 static const struct interval neutral_b[] = { ARRAY };
933# undef BIG_ 928# undef BIG_
934# undef PAIR 929# undef PAIR
935 };
936# define BIG_(a,b) 930# define BIG_(a,b)
937# define PAIR(a,b) (a << 2) | (b-a), 931# define PAIR(a,b) (a << 2) | (b-a),
938 static const uint16_t neutral_p[] = { ARRAY }; 932 static const uint16_t neutral_p[] = { ARRAY };
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index aec165f06..d93dd2af9 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -210,34 +210,40 @@ char* FAST_FUNC xmalloc_ttyname(int fd)
210 return buf; 210 return buf;
211} 211}
212 212
213/* It is perfectly ok to pass in a NULL for either width or for 213static int wh_helper(int value, int def_val, const char *env_name, int *err)
214 * height, in which case that value will not be set. */
215int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height)
216{ 214{
217 struct winsize win = { 0, 0, 0, 0 }; 215 if (value == 0) {
218 int ret = ioctl(fd, TIOCGWINSZ, &win); 216 char *s = getenv(env_name);
219 217 if (s) {
220 if (height) { 218 value = atoi(s);
221 if (!win.ws_row) { 219 /* If LINES/COLUMNS are set, pretent that there is
222 char *s = getenv("LINES"); 220 * no error getting w/h, this prevents some ugly
223 if (s) win.ws_row = atoi(s); 221 * cursor tricks by our callers */
224 } 222 *err = 0;
225 if (win.ws_row <= 1 || win.ws_row >= 30000)
226 win.ws_row = 24;
227 *height = (int) win.ws_row;
228 }
229
230 if (width) {
231 if (!win.ws_col) {
232 char *s = getenv("COLUMNS");
233 if (s) win.ws_col = atoi(s);
234 } 223 }
235 if (win.ws_col <= 1 || win.ws_col >= 30000)
236 win.ws_col = 80;
237 *width = (int) win.ws_col;
238 } 224 }
225 if (value <= 1 || value >= 30000)
226 value = def_val;
227 return value;
228}
239 229
240 return ret; 230/* It is perfectly ok to pass in a NULL for either width or for
231 * height, in which case that value will not be set. */
232int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height)
233{
234 struct winsize win;
235 int err;
236
237 win.ws_row = 0;
238 win.ws_col = 0;
239 /* I've seen ioctl returning 0, but row/col is (still?) 0.
240 * We treat that as an error too. */
241 err = ioctl(fd, TIOCGWINSZ, &win) != 0 || win.ws_row == 0;
242 if (height)
243 *height = wh_helper(win.ws_row, 24, "LINES", &err);
244 if (width)
245 *width = wh_helper(win.ws_col, 80, "COLUMNS", &err);
246 return err;
241} 247}
242 248
243int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) 249int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp)
diff --git a/miscutils/Config.in b/miscutils/Config.in
index 0469b6399..7a69dd10f 100644
--- a/miscutils/Config.in
+++ b/miscutils/Config.in
@@ -545,6 +545,17 @@ config READAHEAD
545 As readahead(2) blocks until each file has been read, it is best to 545 As readahead(2) blocks until each file has been read, it is best to
546 run this applet as a background job. 546 run this applet as a background job.
547 547
548config RFKILL
549 bool "rfkill"
550 default n
551 help
552 Enable/disable wireless devices.
553
554 rfkill list : list all wireless devices
555 rfkill list bluetooth : list all bluetooth devices
556 rfkill list 1 : list device corresponding to the given index
557 rfkill block|unblock wlan : block/unblock all wlan(wifi) devices
558
548config RUNLEVEL 559config RUNLEVEL
549 bool "runlevel" 560 bool "runlevel"
550 default n 561 default n
diff --git a/miscutils/Kbuild b/miscutils/Kbuild
index bbfa93dc7..3c8ce42ba 100644
--- a/miscutils/Kbuild
+++ b/miscutils/Kbuild
@@ -34,6 +34,7 @@ lib-$(CONFIG_MOUNTPOINT) += mountpoint.o
34lib-$(CONFIG_MT) += mt.o 34lib-$(CONFIG_MT) += mt.o
35lib-$(CONFIG_RAIDAUTORUN) += raidautorun.o 35lib-$(CONFIG_RAIDAUTORUN) += raidautorun.o
36lib-$(CONFIG_READAHEAD) += readahead.o 36lib-$(CONFIG_READAHEAD) += readahead.o
37lib-$(CONFIG_RFKILL) += rfkill.o
37lib-$(CONFIG_RUNLEVEL) += runlevel.o 38lib-$(CONFIG_RUNLEVEL) += runlevel.o
38lib-$(CONFIG_RX) += rx.o 39lib-$(CONFIG_RX) += rx.o
39lib-$(CONFIG_SETSID) += setsid.o 40lib-$(CONFIG_SETSID) += setsid.o
diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c
index 5974006bb..e370d207b 100644
--- a/miscutils/fbsplash.c
+++ b/miscutils/fbsplash.c
@@ -359,7 +359,7 @@ int fbsplash_main(int argc UNUSED_PARAM, char **argv)
359 359
360 if (fifo_filename && bCursorOff) { 360 if (fifo_filename && bCursorOff) {
361 // hide cursor (BEFORE any fb ops) 361 // hide cursor (BEFORE any fb ops)
362 full_write(STDOUT_FILENO, "\x1b" "[?25l", 6); 362 full_write(STDOUT_FILENO, "\033[?25l", 6);
363 } 363 }
364 364
365 fb_drawimage(); 365 fb_drawimage();
@@ -404,7 +404,7 @@ int fbsplash_main(int argc UNUSED_PARAM, char **argv)
404 } 404 }
405 405
406 if (bCursorOff) // restore cursor 406 if (bCursorOff) // restore cursor
407 full_write(STDOUT_FILENO, "\x1b" "[?25h", 6); 407 full_write(STDOUT_FILENO, "\033[?25h", 6);
408 408
409 return EXIT_SUCCESS; 409 return EXIT_SUCCESS;
410} 410}
diff --git a/miscutils/less.c b/miscutils/less.c
index e4f8ab979..848266212 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -29,11 +29,11 @@
29#endif 29#endif
30 30
31/* The escape codes for highlighted and normal text */ 31/* The escape codes for highlighted and normal text */
32#define HIGHLIGHT "\033[7m" 32#define HIGHLIGHT "\033[7m"
33#define NORMAL "\033[0m" 33#define NORMAL "\033[0m"
34/* The escape code to clear the screen */ 34/* The escape code to home and clear to the end of screen */
35#define CLEAR "\033[H\033[J" 35#define CLEAR "\033[H\033[J"
36/* The escape code to clear to end of line */ 36/* The escape code to clear to the end of line */
37#define CLEAR_2_EOL "\033[K" 37#define CLEAR_2_EOL "\033[K"
38 38
39enum { 39enum {
diff --git a/miscutils/rfkill.c b/miscutils/rfkill.c
new file mode 100644
index 000000000..0f5817b76
--- /dev/null
+++ b/miscutils/rfkill.c
@@ -0,0 +1,120 @@
1/* vi: set sw=4 ts=4: */
2/*
3* rfkill implementation for busybox
4*
5* Copyright (C) 2010 Malek Degachi <malek-degachi@laposte.net>
6*
7* Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
8*/
9#include "libbb.h"
10#include <linux/rfkill.h>
11
12enum {
13 OPT_b = (1 << 0), /* must be = 1 */
14 OPT_u = (1 << 1),
15 OPT_l = (1 << 2),
16};
17
18int rfkill_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
19int rfkill_main(int argc UNUSED_PARAM, char **argv)
20{
21 struct rfkill_event event;
22 const char *rf_name;
23 int rf_fd;
24 int mode;
25 int rf_type;
26 int rf_idx;
27 unsigned rf_opt = 0;
28
29 argv++;
30 /* Must have one or two params */
31 if (!argv[0] || (argv[1] && argv[2]))
32 bb_show_usage();
33
34 mode = O_RDWR | O_NONBLOCK;
35 rf_name = argv[1];
36 if (strcmp(argv[0], "list") == 0) {
37 rf_opt |= OPT_l;
38 mode = O_RDONLY | O_NONBLOCK;
39 } else if (strcmp(argv[0], "block") == 0 && rf_name) {
40 rf_opt |= OPT_b;
41 } else if (strcmp(argv[0], "unblock") == 0 && rf_name) {
42 rf_opt |= OPT_u;
43 } else
44 bb_show_usage();
45
46 rf_type = RFKILL_TYPE_ALL;
47 rf_idx = -1;
48 if (rf_name) {
49 static const char rfkill_types[] ALIGN1 = "all\0wlan\0bluetooth\0uwb\0wimax\0wwan\0gps\0fm\0";
50 if (strcmp(rf_name, "wifi") == 0)
51 rf_name = "wlan";
52 if (strcmp(rf_name, "ultrawideband") == 0)
53 rf_name = "uwb";
54 rf_type = index_in_strings(rfkill_types, rf_name);
55 if (rf_type < 0) {
56 rf_idx = xatoi_u(rf_name);
57 }
58 }
59
60 rf_fd = device_open("/dev/rfkill", mode);
61 if (rf_fd < 0)
62 bb_perror_msg_and_die("/dev/rfkill");
63
64 if (rf_opt & OPT_l) {
65 while (full_read(rf_fd, &event, sizeof(event)) == RFKILL_EVENT_SIZE_V1) {
66 parser_t *parser;
67 char *tokens[2];
68 char rf_sysfs[sizeof("/sys/class/rfkill/rfkill%u/uevent") + sizeof(int)*3];
69 char *name, *type;
70
71 if (rf_type && rf_type != event.type && rf_idx < 0) {
72 continue;
73 }
74
75 if (rf_idx >= 0 && event.idx != rf_idx) {
76 continue;
77 }
78
79 name = NULL;
80 type = NULL;
81 sprintf(rf_sysfs, "/sys/class/rfkill/rfkill%u/uevent", event.idx);
82 parser = config_open2(rf_sysfs, fopen_for_read);
83 while (config_read(parser, tokens, 2, 2, "\n=", PARSE_NORMAL)) {
84 if (strcmp(tokens[0], "RFKILL_NAME") == 0) {
85 name = xstrdup(tokens[1]);
86 continue;
87 }
88 if (strcmp(tokens[0], "RFKILL_TYPE") == 0) {
89 type = xstrdup(tokens[1]);
90 continue;
91 }
92 }
93 config_close(parser);
94
95 printf("%u: %s: %s\n", event.idx, name, type);
96 printf("\tSoft blocked: %s\n", event.soft ? "yes" : "no");
97 printf("\tHard blocked: %s\n", event.hard ? "yes" : "no");
98 free(name);
99 free(type);
100 }
101 } else {
102 memset(&event, 0, sizeof(event));
103 if (rf_type >= 0) {
104 event.type = rf_type;
105 event.op = RFKILL_OP_CHANGE_ALL;
106 }
107
108 if (rf_idx >= 0) {
109 event.idx = rf_idx;
110 event.op = RFKILL_OP_CHANGE;
111 }
112
113 /* Note: OPT_b == 1 */
114 event.soft = (rf_opt & OPT_b);
115
116 xwrite(rf_fd, &event, sizeof(event));
117 }
118
119 return EXIT_SUCCESS;
120}
diff --git a/miscutils/setsid.c b/miscutils/setsid.c
index d7de1f149..fd3283e30 100644
--- a/miscutils/setsid.c
+++ b/miscutils/setsid.c
@@ -25,11 +25,24 @@ int setsid_main(int argc UNUSED_PARAM, char **argv)
25 /* setsid() is allowed only when we are not a process group leader. 25 /* setsid() is allowed only when we are not a process group leader.
26 * Otherwise our PID serves as PGID of some existing process group 26 * Otherwise our PID serves as PGID of some existing process group
27 * and cannot be used as PGID of a new process group. */ 27 * and cannot be used as PGID of a new process group. */
28 if (getpgrp() == getpid()) 28 if (setsid() < 0) {
29 if (fork_or_rexec(argv)) 29 pid_t pid = fork_or_rexec(argv);
30 exit(EXIT_SUCCESS); /* parent */ 30 if (pid != 0) {
31 /* parent */
32 /* TODO:
33 * we can waitpid(pid, &status, 0) and then even
34 * emulate exitcode, making the behavior consistent
35 * in both forked and non forked cases.
36 * However, the code is larger and upstream
37 * does not do such trick.
38 */
39 exit(EXIT_SUCCESS);
40 }
31 41
32 setsid(); /* no error possible */ 42 /* child */
43 /* now there should be no error: */
44 setsid();
45 }
33 46
34 BB_EXECVP(argv[1], argv + 1); 47 BB_EXECVP(argv[1], argv + 1);
35 bb_simple_perror_msg_and_die(argv[1]); 48 bb_simple_perror_msg_and_die(argv[1]);
diff --git a/networking/Config.in b/networking/Config.in
index 61e59b244..ce7166f98 100644
--- a/networking/Config.in
+++ b/networking/Config.in
@@ -122,8 +122,8 @@ config FEATURE_FTPD_ACCEPT_BROKEN_LIST
122 default y 122 default y
123 depends on FTPD 123 depends on FTPD
124 help 124 help
125 Some ftp-clients (among them KDE's Konqueror) issue illegal 125 Some ftp clients (among them KDE's Konqueror) issue illegal
126 "LIST -la" requests. This option works around those problems. 126 "LIST -l" requests. This option works around such problems.
127 It might prevent you from listing files starting with "-" and 127 It might prevent you from listing files starting with "-" and
128 it increases the code size by ~40 bytes. 128 it increases the code size by ~40 bytes.
129 Most other ftp servers seem to behave similar to this. 129 Most other ftp servers seem to behave similar to this.
diff --git a/networking/dnsd.c b/networking/dnsd.c
index c76a54f9e..1a99040ac 100644
--- a/networking/dnsd.c
+++ b/networking/dnsd.c
@@ -44,10 +44,15 @@ struct dns_head {
44 uint16_t nauth; 44 uint16_t nauth;
45 uint16_t nadd; 45 uint16_t nadd;
46}; 46};
47/* Structure used to access type and class fields.
48 * They are totally unaligned, but gcc 4.3.4 thinks that pointer of type uint16_t*
49 * is 16-bit aligned and replaces 16-bit memcpy (in move_from_unaligned16 macro)
50 * with aligned halfword access on arm920t!
51 * Oh well. Slapping PACKED everywhere seems to help: */
47struct type_and_class { 52struct type_and_class {
48 uint16_t type; 53 uint16_t type PACKED;
49 uint16_t class; 54 uint16_t class PACKED;
50}; 55} PACKED;
51/* element of known name, ip address and reversed ip address */ 56/* element of known name, ip address and reversed ip address */
52struct dns_entry { 57struct dns_entry {
53 struct dns_entry *next; 58 struct dns_entry *next;
diff --git a/networking/ftpd.c b/networking/ftpd.c
index 9d43ea3a2..c63b9319e 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -618,10 +618,10 @@ popen_ls(const char *opt)
618 argv[4] = NULL; 618 argv[4] = NULL;
619 619
620 /* Improve compatibility with non-RFC conforming FTP clients 620 /* Improve compatibility with non-RFC conforming FTP clients
621 * which send e.g. "LIST -l", "LIST -la". 621 * which send e.g. "LIST -l", "LIST -la", "LIST -aL".
622 * See https://bugs.kde.org/show_bug.cgi?id=195578 */ 622 * See https://bugs.kde.org/show_bug.cgi?id=195578 */
623 if (ENABLE_FEATURE_FTPD_ACCEPT_BROKEN_LIST 623 if (ENABLE_FEATURE_FTPD_ACCEPT_BROKEN_LIST
624 && G.ftp_arg && G.ftp_arg[0] == '-' && G.ftp_arg[1] == 'l' 624 && G.ftp_arg && G.ftp_arg[0] == '-'
625 ) { 625 ) {
626 const char *tmp = strchr(G.ftp_arg, ' '); 626 const char *tmp = strchr(G.ftp_arg, ' ');
627 if (tmp) /* skip the space */ 627 if (tmp) /* skip the space */
diff --git a/networking/ifplugd.c b/networking/ifplugd.c
index 41b04c4ed..8cb07db5d 100644
--- a/networking/ifplugd.c
+++ b/networking/ifplugd.c
@@ -93,6 +93,7 @@ enum { // constant fds
93 93
94struct globals { 94struct globals {
95 smallint iface_last_status; 95 smallint iface_last_status;
96 smallint iface_prev_status;
96 smallint iface_exists; 97 smallint iface_exists;
97 98
98 /* Used in getopt32, must have sizeof == sizeof(int) */ 99 /* Used in getopt32, must have sizeof == sizeof(int) */
@@ -121,97 +122,42 @@ struct globals {
121} while (0) 122} while (0)
122 123
123 124
125static const char *strstatus(int status)
126{
127 if (status == IFSTATUS_ERR)
128 return "error";
129 return "down\0up" + (status * 5);
130}
131
124static int run_script(const char *action) 132static int run_script(const char *action)
125{ 133{
134 char *env_PREVIOUS, *env_CURRENT;
126 char *argv[5]; 135 char *argv[5];
127 int r; 136 int r;
128 137
129 bb_error_msg("executing '%s %s %s'", G.script_name, G.iface, action); 138 bb_error_msg("executing '%s %s %s'", G.script_name, G.iface, action);
130 139
131#if 1
132
133 argv[0] = (char*) G.script_name; 140 argv[0] = (char*) G.script_name;
134 argv[1] = (char*) G.iface; 141 argv[1] = (char*) G.iface;
135 argv[2] = (char*) action; 142 argv[2] = (char*) action;
136 argv[3] = (char*) G.extra_arg; 143 argv[3] = (char*) G.extra_arg;
137 argv[4] = NULL; 144 argv[4] = NULL;
138 145
146 env_PREVIOUS = xasprintf("%s=%s", IFPLUGD_ENV_PREVIOUS, strstatus(G.iface_prev_status));
147 putenv(env_PREVIOUS);
148 env_CURRENT = xasprintf("%s=%s", IFPLUGD_ENV_CURRENT, strstatus(G.iface_last_status));
149 putenv(env_CURRENT);
150
139 /* r < 0 - can't exec, 0 <= r < 0x180 - exited, >=0x180 - killed by sig (r-0x180) */ 151 /* r < 0 - can't exec, 0 <= r < 0x180 - exited, >=0x180 - killed by sig (r-0x180) */
140 r = spawn_and_wait(argv); 152 r = spawn_and_wait(argv);
141 153
154 unsetenv(IFPLUGD_ENV_PREVIOUS);
155 unsetenv(IFPLUGD_ENV_CURRENT);
156 free(env_PREVIOUS);
157 free(env_CURRENT);
158
142 bb_error_msg("exit code: %d", r & 0xff); 159 bb_error_msg("exit code: %d", r & 0xff);
143 return (option_mask32 & FLAG_IGNORE_RETVAL) ? 0 : r; 160 return (option_mask32 & FLAG_IGNORE_RETVAL) ? 0 : r;
144
145#else /* insanity */
146
147 struct fd_pair pipe_pair;
148 char buf[256];
149 int i = 0;
150
151 xpiped_pair(pipe_pair);
152
153 pid = vfork();
154 if (pid < 0) {
155 bb_perror_msg("fork");
156 return -1;
157 }
158
159 /* child */
160 if (pid == 0) {
161 xmove_fd(pipe_pair.wr, 1);
162 xdup2(1, 2);
163 if (pipe_pair.rd > 2)
164 close(pipe_pair.rd);
165
166 // umask(0022); // Set up a sane umask
167
168 execlp(G.script_name, G.script_name, G.iface, action, G.extra_arg, NULL);
169 _exit(EXIT_FAILURE);
170 }
171
172 /* parent */
173 close(pipe_pair.wr);
174
175 while (1) {
176 if (bb_got_signal && bb_got_signal != SIGCHLD) {
177 bb_error_msg("killing child");
178 kill(pid, SIGTERM);
179 bb_got_signal = 0;
180 break;
181 }
182
183 r = read(pipe_pair.rd, &buf[i], 1);
184
185 if (buf[i] == '\n' || i == sizeof(buf)-2 || r != 1) {
186 if (r == 1 && buf[i] != '\n')
187 i++;
188
189 buf[i] = '\0';
190
191 if (i > 0)
192 bb_error_msg("client: %s", buf);
193
194 i = 0;
195 } else {
196 i++;
197 }
198
199 if (r != 1)
200 break;
201 }
202
203 close(pipe_pair.rd);
204
205 wait(&r);
206
207 if (!WIFEXITED(r) || WEXITSTATUS(r) != 0) {
208 bb_error_msg("program execution failed, return value is %i",
209 WEXITSTATUS(r));
210 return option_mask32 & FLAG_IGNORE_RETVAL ? 0 : WEXITSTATUS(r);
211 }
212 bb_error_msg("program executed successfully");
213 return 0;
214#endif
215} 161}
216 162
217static int network_ioctl(int request, void* data, const char *errmsg) 163static int network_ioctl(int request, void* data, const char *errmsg)
@@ -228,13 +174,6 @@ static void set_ifreq_to_ifname(struct ifreq *ifreq)
228 strncpy_IFNAMSIZ(ifreq->ifr_name, G.iface); 174 strncpy_IFNAMSIZ(ifreq->ifr_name, G.iface);
229} 175}
230 176
231static const char *strstatus(int status)
232{
233 if (status == IFSTATUS_ERR)
234 return "error";
235 return "down\0up" + (status * 5);
236}
237
238static void up_iface(void) 177static void up_iface(void)
239{ 178{
240 struct ifreq ifrequest; 179 struct ifreq ifrequest;
@@ -474,9 +413,7 @@ static smallint detect_link(void)
474 } 413 }
475 414
476 if (status != G.iface_last_status) { 415 if (status != G.iface_last_status) {
477//TODO: is it safe to repeatedly do this? 416 G.iface_prev_status = G.iface_last_status;
478 setenv(IFPLUGD_ENV_PREVIOUS, strstatus(G.iface_last_status), 1);
479 setenv(IFPLUGD_ENV_CURRENT, strstatus(status), 1);
480 G.iface_last_status = status; 417 G.iface_last_status = status;
481 } 418 }
482 419
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index bf88b1c19..2f3dd1d7b 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -573,8 +573,10 @@ static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
573static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) 573static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
574{ 574{
575 int result; 575 int result;
576 result = execute("kill " 576 result = execute(
577 "`cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec); 577 "test -f /var/run/udhcpc.%iface%.pid && "
578 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
579 ifd, exec);
578 /* Also bring the hardware interface down since 580 /* Also bring the hardware interface down since
579 killing the dhcp client alone doesn't do it. 581 killing the dhcp client alone doesn't do it.
580 This enables consecutive ifup->ifdown->ifup */ 582 This enables consecutive ifup->ifdown->ifup */
diff --git a/networking/route.c b/networking/route.c
index 241be8e09..a3199621a 100644
--- a/networking/route.c
+++ b/networking/route.c
@@ -178,7 +178,7 @@ static NOINLINE void INET_setroute(int action, char **args)
178 int prefix_len; 178 int prefix_len;
179 179
180 prefix_len = xatoul_range(prefix+1, 0, 32); 180 prefix_len = xatoul_range(prefix+1, 0, 32);
181 mask_in_addr(rt) = htonl( ~ (0xffffffffUL >> prefix_len)); 181 mask_in_addr(rt) = htonl( ~(0xffffffffUL >> prefix_len));
182 *prefix = '\0'; 182 *prefix = '\0';
183#if HAVE_NEW_ADDRT 183#if HAVE_NEW_ADDRT
184 rt.rt_genmask.sa_family = AF_INET; 184 rt.rt_genmask.sa_family = AF_INET;
diff --git a/networking/telnet.c b/networking/telnet.c
index 09f75cc84..ec3db0c5e 100644
--- a/networking/telnet.c
+++ b/networking/telnet.c
@@ -299,7 +299,7 @@ static void put_iac_subopt(byte c, char *str)
299static void put_iac_subopt_autologin(void) 299static void put_iac_subopt_autologin(void)
300{ 300{
301 int len = strlen(G.autologin) + 6; // (2 + 1 + 1 + strlen + 2) 301 int len = strlen(G.autologin) + 6; // (2 + 1 + 1 + strlen + 2)
302 const char *user = "USER"; 302 const char *p = "USER";
303 303
304 if (G.iaclen + len > IACBUFSIZE) 304 if (G.iaclen + len > IACBUFSIZE)
305 iac_flush(); 305 iac_flush();
@@ -310,13 +310,14 @@ static void put_iac_subopt_autologin(void)
310 put_iac(TELQUAL_IS); 310 put_iac(TELQUAL_IS);
311 put_iac(NEW_ENV_VAR); 311 put_iac(NEW_ENV_VAR);
312 312
313 while (*user) 313 while (*p)
314 put_iac(*user++); 314 put_iac(*p++);
315 315
316 put_iac(NEW_ENV_VALUE); 316 put_iac(NEW_ENV_VALUE);
317 317
318 while (*G.autologin) 318 p = G.autologin;
319 put_iac(*G.autologin++); 319 while (*p)
320 put_iac(*p++);
320 321
321 put_iac(IAC); 322 put_iac(IAC);
322 put_iac(SE); 323 put_iac(SE);
@@ -441,7 +442,6 @@ static void to_sga(void)
441static void to_ttype(void) 442static void to_ttype(void)
442{ 443{
443 /* Tell server we will (or won't) do TTYPE */ 444 /* Tell server we will (or won't) do TTYPE */
444
445 if (G.ttype) 445 if (G.ttype)
446 put_iac2(WILL, TELOPT_TTYPE); 446 put_iac2(WILL, TELOPT_TTYPE);
447 else 447 else
@@ -453,7 +453,6 @@ static void to_ttype(void)
453static void to_new_environ(void) 453static void to_new_environ(void)
454{ 454{
455 /* Tell server we will (or will not) do AUTOLOGIN */ 455 /* Tell server we will (or will not) do AUTOLOGIN */
456
457 if (G.autologin) 456 if (G.autologin)
458 put_iac2(WILL, TELOPT_NEW_ENVIRON); 457 put_iac2(WILL, TELOPT_NEW_ENVIRON);
459 else 458 else
@@ -505,12 +504,12 @@ static int subneg(byte c)
505 G.telstate = TS_SUB2; 504 G.telstate = TS_SUB2;
506#if ENABLE_FEATURE_TELNET_TTYPE 505#if ENABLE_FEATURE_TELNET_TTYPE
507 else 506 else
508 if (c == TELOPT_TTYPE) 507 if (c == TELOPT_TTYPE && G.ttype)
509 put_iac_subopt(TELOPT_TTYPE, G.ttype); 508 put_iac_subopt(TELOPT_TTYPE, G.ttype);
510#endif 509#endif
511#if ENABLE_FEATURE_TELNET_AUTOLOGIN 510#if ENABLE_FEATURE_TELNET_AUTOLOGIN
512 else 511 else
513 if (c == TELOPT_NEW_ENVIRON) 512 if (c == TELOPT_NEW_ENVIRON && G.autologin)
514 put_iac_subopt_autologin(); 513 put_iac_subopt_autologin();
515#endif 514#endif
516 break; 515 break;
diff --git a/networking/telnetd.c b/networking/telnetd.c
index a8c86b62f..ea66a25c0 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -227,7 +227,7 @@ make_new_session(
227 IF_NOT_FEATURE_TELNETD_STANDALONE(void) 227 IF_NOT_FEATURE_TELNETD_STANDALONE(void)
228) { 228) {
229#if !ENABLE_FEATURE_TELNETD_STANDALONE 229#if !ENABLE_FEATURE_TELNETD_STANDALONE
230 enum { sock = 0 ); 230 enum { sock = 0 };
231#endif 231#endif
232 const char *login_argv[2]; 232 const char *login_argv[2];
233 struct termios termbuf; 233 struct termios termbuf;
diff --git a/networking/udhcp/leases.c b/networking/udhcp/leases.c
index 4999d8079..fad71ec6c 100644
--- a/networking/udhcp/leases.c
+++ b/networking/udhcp/leases.c
@@ -60,6 +60,8 @@ struct dyn_lease* FAST_FUNC add_lease(
60 memset(oldest, 0, sizeof(*oldest)); 60 memset(oldest, 0, sizeof(*oldest));
61 if (hostname) { 61 if (hostname) {
62 char *p; 62 char *p;
63
64 hostname_len++; /* include NUL */
63 if (hostname_len > sizeof(oldest->hostname)) 65 if (hostname_len > sizeof(oldest->hostname))
64 hostname_len = sizeof(oldest->hostname); 66 hostname_len = sizeof(oldest->hostname);
65 p = safe_strncpy(oldest->hostname, hostname, hostname_len); 67 p = safe_strncpy(oldest->hostname, hostname, hostname_len);
diff --git a/procps/ps.c b/procps/ps.c
index b82c126d2..c3b200866 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -142,7 +142,7 @@ static unsigned get_kernel_HZ(void)
142 if (kernel_HZ == (unsigned)-1) 142 if (kernel_HZ == (unsigned)-1)
143 kernel_HZ = get_HZ_by_waiting(); 143 kernel_HZ = get_HZ_by_waiting();
144 144
145 //if (open_read_close("/proc/uptime", buf, sizeof(buf) <= 0) 145 //if (open_read_close("/proc/uptime", buf, sizeof(buf)) <= 0)
146 // bb_perror_msg_and_die("can't read %s", "/proc/uptime"); 146 // bb_perror_msg_and_die("can't read %s", "/proc/uptime");
147 //buf[sizeof(buf)-1] = '\0'; 147 //buf[sizeof(buf)-1] = '\0';
148 ///sscanf(buf, "%llu", &seconds_since_boot); 148 ///sscanf(buf, "%llu", &seconds_since_boot);
diff --git a/procps/top.c b/procps/top.c
index f5c0a123f..e4afafc4c 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -478,8 +478,8 @@ static unsigned long display_header(int scr_width, int *lines_rem_p)
478 snprintf(scrbuf, scr_width, 478 snprintf(scrbuf, scr_width,
479 "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached", 479 "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached",
480 used, mfree, shared, buffers, cached); 480 used, mfree, shared, buffers, cached);
481 /* clear screen & go to top */ 481 /* go to top & clear to the end of screen */
482 printf(OPT_BATCH_MODE ? "%s\n" : "\e[H\e[J%s\n", scrbuf); 482 printf(OPT_BATCH_MODE ? "%s\n" : "\033[H\033[J%s\n", scrbuf);
483 (*lines_rem_p)--; 483 (*lines_rem_p)--;
484 484
485 /* Display CPU time split as percentage of total time 485 /* Display CPU time split as percentage of total time
@@ -518,7 +518,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width)
518#endif 518#endif
519 519
520 /* what info of the processes is shown */ 520 /* what info of the processes is shown */
521 printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, 521 printf(OPT_BATCH_MODE ? "%.*s" : "\033[7m%.*s\033[0m", scr_width,
522 " PID PPID USER STAT VSZ %MEM" 522 " PID PPID USER STAT VSZ %MEM"
523 IF_FEATURE_TOP_SMP_PROCESS(" CPU") 523 IF_FEATURE_TOP_SMP_PROCESS(" CPU")
524 IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU") 524 IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU")
@@ -772,7 +772,7 @@ static void display_topmem_header(int scr_width, int *lines_rem_p)
772 snprintf(linebuf, sizeof(linebuf), 772 snprintf(linebuf, sizeof(linebuf),
773 "Mem total:%s anon:%s map:%s free:%s", 773 "Mem total:%s anon:%s map:%s free:%s",
774 S(total), S(anon), S(map), S(mfree)); 774 S(total), S(anon), S(map), S(mfree));
775 printf(OPT_BATCH_MODE ? "%.*s\n" : "\e[H\e[J%.*s\n", scr_width, linebuf); 775 printf(OPT_BATCH_MODE ? "%.*s\n" : "\033[H\033[J%.*s\n", scr_width, linebuf);
776 776
777 snprintf(linebuf, sizeof(linebuf), 777 snprintf(linebuf, sizeof(linebuf),
778 " slab:%s buf:%s cache:%s dirty:%s write:%s", 778 " slab:%s buf:%s cache:%s dirty:%s write:%s",
diff --git a/procps/watch.c b/procps/watch.c
index 126945c40..a1cde9ea0 100644
--- a/procps/watch.c
+++ b/procps/watch.c
@@ -52,7 +52,8 @@ int watch_main(int argc UNUSED_PARAM, char **argv)
52 width = (unsigned)-1; // make sure first time new_width != width 52 width = (unsigned)-1; // make sure first time new_width != width
53 header = NULL; 53 header = NULL;
54 while (1) { 54 while (1) {
55 printf("\033[H\033[J"); 55 /* home; clear to the end of screen */
56 printf("\033[H""\033[J");
56 if (!(opt & 0x2)) { // no -t 57 if (!(opt & 0x2)) { // no -t
57 const unsigned time_len = sizeof("1234-67-90 23:56:89"); 58 const unsigned time_len = sizeof("1234-67-90 23:56:89");
58 time_t t; 59 time_t t;
diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
index cff33498f..03e397f42 100644
--- a/scripts/Makefile.clean
+++ b/scripts/Makefile.clean
@@ -14,7 +14,7 @@ clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
14 14
15# The filename Kbuild has precedence over Makefile 15# The filename Kbuild has precedence over Makefile
16kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) 16kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
17include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile) 17-include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
18 18
19# Figure out what we need to build from the various variables 19# Figure out what we need to build from the various variables
20# ========================================================================== 20# ==========================================================================
diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh
new file mode 100755
index 000000000..d2db907f3
--- /dev/null
+++ b/scripts/gen_build_files.sh
@@ -0,0 +1,59 @@
1#!/bin/sh
2
3test $# -ge 2 || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; }
4
5# cd to objtree
6cd -- "$2" || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; }
7
8srctree="$1"
9
10find -type d | while read -r d; do
11 src="$srctree/$d/Kbuild.src"
12 dst="$d/Kbuild"
13 if test -f "$src"; then
14 echo " CHK $dst"
15
16 s=`sed -n 's@^//kbuild:@@p' -- "$srctree/$d"/*.c`
17 echo "# DO NOT EDIT. This file is generated from Kbuild.src" >"$dst.$$.tmp"
18
19 # Why "IFS='' read -r REPLY"??
20 # This atrocity is needed to read lines without mangling.
21 # IFS='' prevents whitespace trimming,
22 # -r suppresses backslash handling.
23 while IFS='' read -r REPLY; do
24 test x"$REPLY" = x"INSERT" && REPLY="$s"
25 printf "%s\n" "$REPLY"
26 done <"$src" >>"$dst.$$.tmp"
27
28 if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then
29 rm -- "$dst.$$.tmp"
30 else
31 echo " GEN $dst"
32 mv -- "$dst.$$.tmp" "$dst"
33 fi
34 fi
35
36 src="$srctree/$d/Config.src"
37 dst="$d/Config.in"
38 if test -f "$src"; then
39 echo " CHK $dst"
40
41 s=`sed -n 's@^//config:@@p' -- "$srctree/$d"/*.c`
42 echo "# DO NOT EDIT. This file is generated from Config.src" >"$dst.$$.tmp"
43
44 while IFS='' read -r REPLY; do
45 test x"$REPLY" = x"INSERT" && REPLY="$s"
46 printf "%s\n" "$REPLY"
47 done <"$src" >>"$dst.$$.tmp"
48
49 if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then
50 rm -- "$dst.$$.tmp"
51 else
52 echo " GEN $dst"
53 mv -- "$dst.$$.tmp" "$dst"
54 fi
55 fi
56done
57
58# Last read failed. This is normal. Don't exit with its error code:
59exit 0
diff --git a/scripts/randomtest b/scripts/randomtest
index 6b7db9239..8d0d79e64 100755
--- a/scripts/randomtest
+++ b/scripts/randomtest
@@ -1,86 +1,88 @@
1#!/bin/sh 1#!/bin/sh
2 2
3# Select which libc to build against 3# If not specified in environment...
4libc="glibc" # assumed native 4if ! test "$LIBC"; then
5# static, cross-compilation 5 # Select which libc to build against
6libc="uclibc" 6 LIBC="glibc"
7 LIBC="uclibc"
8fi
7# x86 32-bit: 9# x86 32-bit:
8uclibc_cross="i486-linux-uclibc-" 10#CROSS_COMPILER_PREFIX="i486-linux-uclibc-"
9# My system has strange prefix for x86 64-bit uclibc: 11# My system has strange prefix for x86 64-bit uclibc:
10#uclibc_cross="x86_64-pc-linux-gnu-" 12#CROSS_COMPILER_PREFIX="x86_64-pc-linux-gnu-"
11 13
12test -d tree || exit 1 14if test $# -lt 2 || ! test -d "$1" || test -e "$2"; then
15 echo "Usage: $0 SRC_DIR TMP_DIR"
16 echo
17 echo "SRC_DIR will be copied to TMP_DIR directory."
18 echo "Then a random build will be performed."
19 echo
20 echo "Useful variables:"
21 echo "\$LIBC, \$CROSS_COMPILER_PREFIX, \$MAKEOPTS"
22 exit 1
23fi
13 24
14dir=test.$$ 25cp -dpr -- "$1" "$2" || { echo "copy error"; exit 1; }
15while test -e "$dir" -o -e failed."$dir"; do 26cd -- "$2" || { echo "cd $dir error"; exit 1; }
16 dir=test."$RANDOM"
17done
18 27
19cp -dpr tree "$dir" || exit 1 28# Generate random config
20cd "$dir" || exit 1 29make randconfig >/dev/null || { echo "randconfig error"; exit 1; }
21
22echo "Running randconfig test in $dir..." >&2
23
24make randconfig >/dev/null || exit 1
25 30
31# Tweak resulting config
26cat .config \ 32cat .config \
27| grep -v ^CONFIG_DEBUG_PESSIMIZE= \ 33| grep -v CONFIG_DEBUG_PESSIMIZE \
28| grep -v CONFIG_WERROR \ 34| grep -v CONFIG_WERROR \
29| cat >.config.new 35| grep -v CONFIG_CROSS_COMPILER_PREFIX \
30mv .config.new .config
31#echo CONFIG_WERROR=y >>.config
32echo '# CONFIG_WERROR is not set' >>.config
33
34test "$libc" = glibc && {
35cat .config \
36| grep -v CONFIG_STATIC \
37| grep -v CONFIG_SELINUX \ 36| grep -v CONFIG_SELINUX \
38| grep -v CONFIG_EFENCE \ 37| grep -v CONFIG_EFENCE \
39| grep -v CONFIG_DMALLOC \ 38| grep -v CONFIG_DMALLOC \
40| cat >.config.new 39\
40| grep -v CONFIG_RFKILL \
41>.config.new
41mv .config.new .config 42mv .config.new .config
42echo '# CONFIG_STATIC is not set' >>.config 43echo '# CONFIG_DEBUG_PESSIMIZE is not set' >>.config
43} 44echo '# CONFIG_WERROR is not set' >>.config
45echo "CONFIG_CROSS_COMPILER_PREFIX=\"${CROSS_COMPILER_PREFIX}\"" >>.config
44 46
45test "$libc" = uclibc && { 47# If glibc, don't build static
46cat .config \ 48if test x"$LIBC" = x"glibc"; then
47| grep -v ^CONFIG_SELINUX= \ 49 cat .config \
48| grep -v ^CONFIG_EFENCE= \ 50 | grep -v CONFIG_STATIC \
49| grep -v ^CONFIG_DMALLOC= \ 51 >.config.new
50| grep -v ^CONFIG_BUILD_LIBBUSYBOX= \ 52 mv .config.new .config
51| grep -v ^CONFIG_PAM= \ 53 echo '# CONFIG_STATIC is not set' >>.config
52| grep -v ^CONFIG_TASKSET= \ 54fi
53| grep -v ^CONFIG_UNICODE_SUPPORT= \ 55
54| grep -v ^CONFIG_PIE= \ 56# If glibc, build static, and remove some things
55| grep -v CONFIG_STATIC \ 57# likely to not work on uclibc.
56| grep -v CONFIG_CROSS_COMPILER_PREFIX \ 58if test x"$LIBC" = x"uclibc"; then
57| cat >.config.new 59 cat .config \
58mv .config.new .config 60 | grep -v CONFIG_STATIC \
59echo 'CONFIG_CROSS_COMPILER_PREFIX="'"$uclibc_cross"'"' >>.config 61 | grep -v CONFIG_BUILD_LIBBUSYBOX \
60echo 'CONFIG_STATIC=y' >>.config 62 | grep -v CONFIG_TASKSET \
61} 63 | grep -v CONFIG_UNICODE_SUPPORT \
64 | grep -v CONFIG_PIE \
65 >.config.new
66 mv .config.new .config
67 echo 'CONFIG_STATIC=y' >>.config
68fi
62 69
63# If STATIC, remove some things 70# If STATIC, remove some things.
64# PAM with static linking is probably pointless 71# PAM with static linking is probably pointless
65# (but I need to try - now I don't have libpam.a on my system, only libpam.so) 72# (but I need to try - now I don't have libpam.a on my system, only libpam.so)
66grep -q ^CONFIG_STATIC= .config && { 73if grep -q "^CONFIG_STATIC=y" .config; then
67cat .config \ 74 cat .config \
68| grep -v ^CONFIG_PAM= \ 75 | grep -v CONFIG_PAM \
69| cat >.config.new 76 >.config.new
70mv .config.new .config 77 mv .config.new .config
71} 78fi
72 79
73# Regenerate .config with default answers for yanked-off options 80# Regenerate .config with default answers for yanked-off options
74{ yes "" | make oldconfig >/dev/null; } || exit 1 81# (most of default answers are "no").
75 82{ yes "" | make oldconfig >/dev/null; } || { echo "oldconfig error"; exit 1; }
76nice -n 10 make $MAKEOPTS 2>&1 | tee -a make.log
77 83
78test -x busybox && { 84# Build!
79 cd .. 85nice -n 10 make $MAKEOPTS 2>&1 | tee make.log
80 rm -rf "$dir"
81 exit 0
82}
83 86
84cd .. 87# Return exitcode 1 if busybox executable does not exist
85mv "$dir" "failed.$dir" 88test -x busybox
86exit 1
diff --git a/scripts/randomtest.loop b/scripts/randomtest.loop
index 28edb6732..311536df8 100755
--- a/scripts/randomtest.loop
+++ b/scripts/randomtest.loop
@@ -1,10 +1,38 @@
1#!/bin/sh 1#!/bin/sh
2 2
3test -d "$1" || { echo "'$1' is not a directory"; exit 1; }
4test -x "$1/scripts/randomtest" || { echo "No scripts/randomtest in '$1'"; exit 1; }
5
6export LIBC="uclibc"
7export CROSS_COMPILER_PREFIX="i486-linux-uclibc-"
8export MAKEOPTS="-j9"
9
3cnt=0 10cnt=0
4fail=0 11fail=0
5
6while sleep 1; do 12while sleep 1; do
7 echo "Passes: $cnt Failures: $fail" 13 echo "Passes: $cnt Failures: $fail"
8 ./randomtest >/dev/null || exit #let fail++ 14 dir="test.$$"
9 let cnt++ 15 while test -e "$dir" -o -e "failed.$dir"; do
16 dir="test.$$.$RANDOM"
17 done
18 echo "Running randconfig test in $dir..."
19 if ! "$1/scripts/randomtest" "$1" "$dir" >/dev/null; then
20 mv -- "$dir" "failed.$dir"
21 echo "Failed build in: failed.$dir"
22 exit 1 # you may comment this out...
23 let fail++
24 else
25 (
26 cd -- "$dir/testsuite" || exit 1
27 echo "Running testsuite in $dir..."
28 SKIP_KNOWN_BUGS=1 SKIP_INTERNET_TESTS=1 ./runtest -v >runtest.log 2>&1
29 )
30 if test $? != 0; then
31 echo "Failed runtest in $dir"
32 exit 1
33 fi
34 tail -n10 -- "$dir/testsuite/runtest.log"
35 rm -rf -- "$dir"
36 fi
37 let cnt++
10done 38done
diff --git a/shell/Config.in b/shell/Config.in
index 3b1650615..cf599dff4 100644
--- a/shell/Config.in
+++ b/shell/Config.in
@@ -354,9 +354,20 @@ config CTTYHACK
354 It analyzes stdin with various ioctls, trying to determine whether 354 It analyzes stdin with various ioctls, trying to determine whether
355 it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). 355 it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line).
356 If it detects one, it closes stdin/out/err and reopens that device. 356 If it detects one, it closes stdin/out/err and reopens that device.
357 Then it executes given program. Usage example for /etc/inittab 357 Then it executes given program. Opening the device will make
358 (for busybox init): 358 that device a controlling tty. This may require cttyhack
359 to be a session leader.
360
361 Example for /etc/inittab (for busybox init):
359 362
360 ::respawn:/bin/cttyhack /bin/sh 363 ::respawn:/bin/cttyhack /bin/sh
361 364
365 Giving controlling tty to shell running with PID 1:
366
367 $ exec cttyhack sh
368
369 Starting an interactive shell from boot shell script:
370
371 setsid cttyhack sh
372
362endmenu 373endmenu
diff --git a/shell/README b/shell/README
index 59efe499f..550c712d3 100644
--- a/shell/README
+++ b/shell/README
@@ -1,108 +1,82 @@
1Various bits of what is known about busybox shells, in no particular order. 1http://www.opengroup.org/onlinepubs/9699919799/
2 2Open Group Base Specifications Issue 7
32008-02-14 3
4ash: does not restore tty pgrp if killed by HUP. Symptom: Midnight Commander 4
5is backgrounded if you started ash under it, and then killed it with HUP. 5http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html
6 6Shell & Utilities
72007-11-23 7
8hush: fixed bogus glob handling; fixed exec <"$1"; added test and echo builtins 8It says that any of the standard utilities may be implemented
9 9as a regular shell built-in. It gives a list of utilities which
102007-06-13 10are usually implemented that way (and some of them can only
11hush: exec <"$1" doesn't do parameter subst 11be implemented as built-ins, like "alias"):
12 12
132007-05-24 13alias
14hush: environment-related memory leak plugged, with net code size 14bg
15decrease. 15cd
16 16command
172007-05-24 17false
18hush: '( echo ${name )' will show syntax error message, but prompt 18fc
19doesn't return (need to press <enter>). Pressing Ctrl-C, <enter>, 19fg
20'( echo ${name )' again, Ctrl-C segfaults. 20getopts
21 21jobs
222007-05-21 22kill
23hush: environment cannot be handled by libc routines as they are leaky 23newgrp
24(by API design and thus unfixable): hush will leak memory in this script, 24pwd
25bash does not: 25read
26pid=$$ 26true
27while true; do 27umask
28 unset t; 28unalias
29 t=111111111111111111111111111111111111111111111111111111111111111111111111 29wait
30 export t 30
31 ps -o vsz,pid,comm | grep " $pid " 31
32done 32http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
33The fix is to not use setenv/putenv/unsetenv but manipulate env ourself. TODO. 33Shell Command Language
34hush: meanwhile, first three command subst bugs mentioned below are fixed. :) 34
35 35It says that shell must implement special built-ins. Special built-ins
362007-05-06 36differ from regular ones by the fact that variable assignments
37hush: more bugs spotted. Comparison with bash: 37done on special builtin is *PRESERVED*. That is,
38bash-3.2# echo "TEST`date;echo;echo`BEST" 38
39TESTSun May 6 09:21:05 CEST 2007BEST [we dont strip eols] 39VAR=VAL special_builtin; echo $VAR
40bash-3.2# echo "TEST`echo '$(echo ZZ)'`BEST" 40
41TEST$(echo ZZ)BEST [we execute inner echo] 41should print VAL.
42bash-3.2# echo "TEST`echo "'"`BEST" 42
43TEST'BEST [we totally mess up this one] 43(Another distinction is that an error in special built-in should
44bash-3.2# echo `sleep 5` 44abort the shell, but this is not such a critical difference,
45[Ctrl-C should work, Ctrl-Z should do nothing][we totally mess up this one] 45and moreover, at least bash's "set" does not follow this rule,
46bash-3.2# if true; then 46which is even codified in autoconf now...).
47> [Ctrl-C] 47
48bash-3.2# [we re-issue "> "] 48List of special builtins:
49bash-3.2# if echo `sleep 5`; then 49
50> true; fi [we execute sleep before "> "] 50. file
51 51: [argument...]
522007-05-04 52break [n]
53hush: made ctrl-Z/C work correctly for "while true; do true; done" 53continue [n]
54(namely, it backgrounds/interrupts entire "while") 54eval [argument...]
55 55exec [command [argument...]]
562007-05-03 56exit [n]
57hush: new bug spotted: Ctrl-C on "while true; do true; done" doesn't 57export name[=word]...
58work right: 58export -p
59# while true; do true; done 59readonly name[=word]...
60[1] 0 true <-- pressing Ctrl-C several times... 60readonly -p
61[2] 0 true 61return [n]
62[3] 0 true 62set [-abCefhmnuvx] [-o option] [argument...]
63Segmentation fault 63set [+abCefhmnuvx] [+o option] [argument...]
64 64set -- [argument...]
652007-05-03 65set -o
66hush: update on "sleep 1 | exit 3; echo $?" bug. 66set +o
67parse_stream_outer() repeatedly calls parse_stream(). 67shift [n]
68parse_stream() is now fixed to stop on ';' in this example, 68times
69fixing it (parse_stream_outer() will call parse_stream() 1st time, 69trap n [condition...]
70execute the parse tree, call parse_stream() 2nd time and execute the tree). 70trap [action condition...]
71But it's not the end of story. 71unset [-fv] name...
72In more complex situations we _must_ parse way farther before executing. 72
73Example #2: "{ sleep 1 | exit 3; echo $?; ...few_lines... } >file". 73In practice, no one uses this obscure feature - none of these builtins
74Because of redirection, we cannot execute 1st pipe before we parse it all. 74gives any special reasons to play such dirty tricks.
75We probably need to learn to store $var expressions in parse tree. 75
76Debug printing of parse tree would be nice too. 76However. This section says that *function invocation* should act
77 77similar to special built-in. That is, variable assignments
782007-04-28 78done on function invocation should be preserved after function invocation.
79hush: Ctrl-C and Ctrl-Z for single NOFORK commands are working. 79
80Memory and other resource leaks (opendir) are not addressed 80This is significant: it is not unthinkable to want to run a function
81(testcase is "rm -i" interrupted by ctrl-c). 81with some variables set to special values. But because of the above,
82 82it does not work: variable will "leak" out of the function.
832007-04-21
84hush: "sleep 5 | sleep 6" + Ctrl-Z + fg seems to work.
85"rm -i" + Ctrl-C, "sleep 5" + Ctrl-Z still doesn't work
86for SH_STANDALONE case :(
87
882007-04-21
89hush: fixed non-backgrounding of "sleep 1 &" and totally broken
90"sleep 1 | sleep 2 &". Noticed a bug where successive jobs
91get numbers 1,2,3 even when job #1 has exited before job# 2 is started.
92(bash reuses #1 in this case)
93
942007-04-21
95hush: "sleep 1 | exit 3; echo $?" prints 0 because $? is substituted
96_before_ pipe gets executed!! run_list_real() already has "pipe;echo"
97parsed and handed to it for execution, so it sees "pipe"; "echo 0".
98
992007-04-21
100hush: removed setsid() and made job control sort-of-sometimes-work.
101Ctrl-C in "rm -i" works now except for SH_STANDALONE case.
102"sleep 1 | exit 3" + "echo $?" works, "sleep 1 | exit 3; echo $?"
103shows exitcode 0 (should be 3). "sleep 1 | sleep 2 &" fails horribly.
104
1052007-04-14
106lash, hush: both do setsid() and as a result don't have ctty!
107Ctrl-C doesn't work for any child (try rm -i), etc...
108lash: bare ">file" doesn't create a file (hush works)
diff --git a/shell/ash.c b/shell/ash.c
index 5d8415a79..16a331bb0 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -257,6 +257,7 @@ struct globals_misc {
257 257
258 /* indicates specified signal received */ 258 /* indicates specified signal received */
259 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ 259 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
260 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
260 char *trap[NSIG]; 261 char *trap[NSIG];
261 char **trap_ptr; /* used only by "trap hack" */ 262 char **trap_ptr; /* used only by "trap hack" */
262 263
@@ -285,6 +286,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
285#define optlist (G_misc.optlist ) 286#define optlist (G_misc.optlist )
286#define sigmode (G_misc.sigmode ) 287#define sigmode (G_misc.sigmode )
287#define gotsig (G_misc.gotsig ) 288#define gotsig (G_misc.gotsig )
289#define may_have_traps (G_misc.may_have_traps )
288#define trap (G_misc.trap ) 290#define trap (G_misc.trap )
289#define trap_ptr (G_misc.trap_ptr ) 291#define trap_ptr (G_misc.trap_ptr )
290#define random_gen (G_misc.random_gen ) 292#define random_gen (G_misc.random_gen )
@@ -382,7 +384,7 @@ raise_interrupt(void)
382 /* Signal is not automatically unmasked after it is raised, 384 /* Signal is not automatically unmasked after it is raised,
383 * do it ourself - unmask all signals */ 385 * do it ourself - unmask all signals */
384 sigprocmask_allsigs(SIG_UNBLOCK); 386 sigprocmask_allsigs(SIG_UNBLOCK);
385 /* pending_sig = 0; - now done in onsig() */ 387 /* pending_sig = 0; - now done in signal_handler() */
386 388
387 ex_type = EXSIG; 389 ex_type = EXSIG;
388 if (gotsig[SIGINT - 1] && !trap[SIGINT]) { 390 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
@@ -2743,9 +2745,7 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2743/* ============ ... */ 2745/* ============ ... */
2744 2746
2745 2747
2746#define IBUFSIZ COMMON_BUFSIZE 2748#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
2747/* buffer for top level input file */
2748#define basebuf bb_common_bufsiz1
2749 2749
2750/* Syntax classes */ 2750/* Syntax classes */
2751#define CWORD 0 /* character is nothing special */ 2751#define CWORD 0 /* character is nothing special */
@@ -3424,10 +3424,10 @@ ignoresig(int signo)
3424} 3424}
3425 3425
3426/* 3426/*
3427 * Signal handler. Only one usage site - in setsignal() 3427 * Only one usage site - in setsignal()
3428 */ 3428 */
3429static void 3429static void
3430onsig(int signo) 3430signal_handler(int signo)
3431{ 3431{
3432 gotsig[signo - 1] = 1; 3432 gotsig[signo - 1] = 1;
3433 3433
@@ -3524,7 +3524,7 @@ setsignal(int signo)
3524 act.sa_handler = SIG_DFL; 3524 act.sa_handler = SIG_DFL;
3525 switch (new_act) { 3525 switch (new_act) {
3526 case S_CATCH: 3526 case S_CATCH:
3527 act.sa_handler = onsig; 3527 act.sa_handler = signal_handler;
3528 act.sa_flags = 0; /* matters only if !DFL and !IGN */ 3528 act.sa_flags = 0; /* matters only if !DFL and !IGN */
3529 sigfillset(&act.sa_mask); /* ditto */ 3529 sigfillset(&act.sa_mask); /* ditto */
3530 break; 3530 break;
@@ -4083,9 +4083,9 @@ dowait(int wait_flags, struct job *job)
4083} 4083}
4084 4084
4085static int 4085static int
4086blocking_wait_with_raise_on_sig(struct job *job) 4086blocking_wait_with_raise_on_sig(void)
4087{ 4087{
4088 pid_t pid = dowait(DOWAIT_BLOCK, job); 4088 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
4089 if (pid <= 0 && pending_sig) 4089 if (pid <= 0 && pending_sig)
4090 raise_exception(EXSIG); 4090 raise_exception(EXSIG);
4091 return pid; 4091 return pid;
@@ -4281,14 +4281,21 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4281 jp->waited = 1; 4281 jp->waited = 1;
4282 jp = jp->prev_job; 4282 jp = jp->prev_job;
4283 } 4283 }
4284 blocking_wait_with_raise_on_sig();
4284 /* man bash: 4285 /* man bash:
4285 * "When bash is waiting for an asynchronous command via 4286 * "When bash is waiting for an asynchronous command via
4286 * the wait builtin, the reception of a signal for which a trap 4287 * the wait builtin, the reception of a signal for which a trap
4287 * has been set will cause the wait builtin to return immediately 4288 * has been set will cause the wait builtin to return immediately
4288 * with an exit status greater than 128, immediately after which 4289 * with an exit status greater than 128, immediately after which
4289 * the trap is executed." 4290 * the trap is executed."
4290 * Do we do it that way? */ 4291 *
4291 blocking_wait_with_raise_on_sig(NULL); 4292 * blocking_wait_with_raise_on_sig raises signal handlers
4293 * if it gets no pid (pid < 0). However,
4294 * if child sends us a signal *and immediately exits*,
4295 * blocking_wait_with_raise_on_sig gets pid > 0
4296 * and does not handle pending_sig. Check this case: */
4297 if (pending_sig)
4298 raise_exception(EXSIG);
4292 } 4299 }
4293 } 4300 }
4294 4301
@@ -4308,7 +4315,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4308 job = getjob(*argv, 0); 4315 job = getjob(*argv, 0);
4309 /* loop until process terminated or stopped */ 4316 /* loop until process terminated or stopped */
4310 while (job->state == JOBRUNNING) 4317 while (job->state == JOBRUNNING)
4311 blocking_wait_with_raise_on_sig(NULL); 4318 blocking_wait_with_raise_on_sig();
4312 job->waited = 1; 4319 job->waited = 1;
4313 retval = getstatus(job); 4320 retval = getstatus(job);
4314 repeat: ; 4321 repeat: ;
@@ -5715,7 +5722,11 @@ rmescapes(char *str, int flag)
5715 size_t fulllen = len + strlen(p) + 1; 5722 size_t fulllen = len + strlen(p) + 1;
5716 5723
5717 if (flag & RMESCAPE_GROW) { 5724 if (flag & RMESCAPE_GROW) {
5725 int strloc = str - (char *)stackblock();
5718 r = makestrspace(fulllen, expdest); 5726 r = makestrspace(fulllen, expdest);
5727 /* p and str may be invalidated by makestrspace */
5728 str = (char *)stackblock() + strloc;
5729 p = str + len;
5719 } else if (flag & RMESCAPE_HEAP) { 5730 } else if (flag & RMESCAPE_HEAP) {
5720 r = ckmalloc(fulllen); 5731 r = ckmalloc(fulllen);
5721 } else { 5732 } else {
@@ -8819,7 +8830,7 @@ evalsubshell(union node *n, int flags)
8819 int status; 8830 int status;
8820 8831
8821 expredir(n->nredir.redirect); 8832 expredir(n->nredir.redirect);
8822 if (!backgnd && flags & EV_EXIT && !trap[0]) 8833 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
8823 goto nofork; 8834 goto nofork;
8824 INT_OFF; 8835 INT_OFF;
8825 jp = makejob(/*n,*/ 1); 8836 jp = makejob(/*n,*/ 1);
@@ -8832,10 +8843,11 @@ evalsubshell(union node *n, int flags)
8832 ash_msg_and_raise_error("unable to spawn shell"); 8843 ash_msg_and_raise_error("unable to spawn shell");
8833#endif 8844#endif
8834 if (forkshell(jp, n, backgnd) == 0) { 8845 if (forkshell(jp, n, backgnd) == 0) {
8846 /* child */
8835 INT_ON; 8847 INT_ON;
8836 flags |= EV_EXIT; 8848 flags |= EV_EXIT;
8837 if (backgnd) 8849 if (backgnd)
8838 flags &=~ EV_TESTED; 8850 flags &= ~EV_TESTED;
8839 nofork: 8851 nofork:
8840 redirect(n->nredir.redirect, 0); 8852 redirect(n->nredir.redirect, 0);
8841 evaltreenr(n->nredir.n, flags); 8853 evaltreenr(n->nredir.n, flags);
@@ -9365,7 +9377,9 @@ static const struct builtincmd builtintab[] = {
9365 { BUILTIN_SPEC_REG "return" , returncmd }, 9377 { BUILTIN_SPEC_REG "return" , returncmd },
9366 { BUILTIN_SPEC_REG "set" , setcmd }, 9378 { BUILTIN_SPEC_REG "set" , setcmd },
9367 { BUILTIN_SPEC_REG "shift" , shiftcmd }, 9379 { BUILTIN_SPEC_REG "shift" , shiftcmd },
9380#if ENABLE_ASH_BASH_COMPAT
9368 { BUILTIN_SPEC_REG "source" , dotcmd }, 9381 { BUILTIN_SPEC_REG "source" , dotcmd },
9382#endif
9369#if ENABLE_ASH_BUILTIN_TEST 9383#if ENABLE_ASH_BUILTIN_TEST
9370 { BUILTIN_REGULAR "test" , testcmd }, 9384 { BUILTIN_REGULAR "test" , testcmd },
9371#endif 9385#endif
@@ -9646,16 +9660,19 @@ evalcommand(union node *cmd, int flags)
9646 /* goes through to shellexec() */ 9660 /* goes through to shellexec() */
9647#endif 9661#endif
9648 /* Fork off a child process if necessary. */ 9662 /* Fork off a child process if necessary. */
9649 if (!(flags & EV_EXIT) || trap[0]) { 9663 if (!(flags & EV_EXIT) || may_have_traps) {
9650 INT_OFF; 9664 INT_OFF;
9651 jp = makejob(/*cmd,*/ 1); 9665 jp = makejob(/*cmd,*/ 1);
9652 if (forkshell(jp, cmd, FORK_FG) != 0) { 9666 if (forkshell(jp, cmd, FORK_FG) != 0) {
9667 /* parent */
9653 exitstatus = waitforjob(jp); 9668 exitstatus = waitforjob(jp);
9654 INT_ON; 9669 INT_ON;
9655 TRACE(("forked child exited with %d\n", exitstatus)); 9670 TRACE(("forked child exited with %d\n", exitstatus));
9656 break; 9671 break;
9657 } 9672 }
9673 /* child */
9658 FORCE_INT_ON; 9674 FORCE_INT_ON;
9675 /* fall through to exec'ing external program */
9659 } 9676 }
9660 listsetvar(varlist.list, VEXPORT|VSTACK); 9677 listsetvar(varlist.list, VEXPORT|VSTACK);
9661 shellexec(argv, path, cmdentry.u.index); 9678 shellexec(argv, path, cmdentry.u.index);
@@ -9900,12 +9917,12 @@ preadfd(void)
9900#if ENABLE_FEATURE_EDITING 9917#if ENABLE_FEATURE_EDITING
9901 retry: 9918 retry:
9902 if (!iflag || g_parsefile->fd != STDIN_FILENO) 9919 if (!iflag || g_parsefile->fd != STDIN_FILENO)
9903 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1); 9920 nr = nonblock_safe_read(g_parsefile->fd, buf, IBUFSIZ - 1);
9904 else { 9921 else {
9905#if ENABLE_FEATURE_TAB_COMPLETION 9922#if ENABLE_FEATURE_TAB_COMPLETION
9906 line_input_state->path_lookup = pathval(); 9923 line_input_state->path_lookup = pathval();
9907#endif 9924#endif
9908 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state); 9925 nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state);
9909 if (nr == 0) { 9926 if (nr == 0) {
9910 /* Ctrl+C pressed */ 9927 /* Ctrl+C pressed */
9911 if (trap[SIGINT]) { 9928 if (trap[SIGINT]) {
@@ -9922,7 +9939,7 @@ preadfd(void)
9922 } 9939 }
9923 } 9940 }
9924#else 9941#else
9925 nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1); 9942 nr = nonblock_safe_read(g_parsefile->fd, buf, IBUFSIZ - 1);
9926#endif 9943#endif
9927 9944
9928#if 0 9945#if 0
@@ -12484,36 +12501,43 @@ find_dot_file(char *name)
12484static int FAST_FUNC 12501static int FAST_FUNC
12485dotcmd(int argc, char **argv) 12502dotcmd(int argc, char **argv)
12486{ 12503{
12504 char *fullname;
12487 struct strlist *sp; 12505 struct strlist *sp;
12488 volatile struct shparam saveparam; 12506 volatile struct shparam saveparam;
12489 int status = 0;
12490 12507
12491 for (sp = cmdenviron; sp; sp = sp->next) 12508 for (sp = cmdenviron; sp; sp = sp->next)
12492 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED); 12509 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
12493 12510
12494 if (argv[1]) { /* That's what SVR2 does */ 12511 if (!argv[1]) {
12495 char *fullname = find_dot_file(argv[1]); 12512 /* bash says: "bash: .: filename argument required" */
12496 argv += 2; 12513 return 2; /* bash compat */
12497 argc -= 2;
12498 if (argc) { /* argc > 0, argv[0] != NULL */
12499 saveparam = shellparam;
12500 shellparam.malloced = 0;
12501 shellparam.nparam = argc;
12502 shellparam.p = argv;
12503 };
12504
12505 setinputfile(fullname, INPUT_PUSH_FILE);
12506 commandname = fullname;
12507 cmdloop(0);
12508 popfile();
12509
12510 if (argc) {
12511 freeparam(&shellparam);
12512 shellparam = saveparam;
12513 };
12514 status = exitstatus;
12515 } 12514 }
12516 return status; 12515
12516 /* "false; . empty_file; echo $?" should print 0, not 1: */
12517 exitstatus = 0;
12518
12519 fullname = find_dot_file(argv[1]);
12520
12521 argv += 2;
12522 argc -= 2;
12523 if (argc) { /* argc > 0, argv[0] != NULL */
12524 saveparam = shellparam;
12525 shellparam.malloced = 0;
12526 shellparam.nparam = argc;
12527 shellparam.p = argv;
12528 };
12529
12530 setinputfile(fullname, INPUT_PUSH_FILE);
12531 commandname = fullname;
12532 cmdloop(0);
12533 popfile();
12534
12535 if (argc) {
12536 freeparam(&shellparam);
12537 shellparam = saveparam;
12538 };
12539
12540 return exitstatus;
12517} 12541}
12518 12542
12519static int FAST_FUNC 12543static int FAST_FUNC
@@ -12824,6 +12848,8 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12824 action = ckstrdup(action); 12848 action = ckstrdup(action);
12825 } 12849 }
12826 free(trap[signo]); 12850 free(trap[signo]);
12851 if (action)
12852 may_have_traps = 1;
12827 trap[signo] = action; 12853 trap[signo] = action;
12828 if (signo != 0) 12854 if (signo != 0)
12829 setsignal(signo); 12855 setsignal(signo);
@@ -13219,7 +13245,8 @@ static void
13219init(void) 13245init(void)
13220{ 13246{
13221 /* from input.c: */ 13247 /* from input.c: */
13222 basepf.next_to_pgetc = basepf.buf = basebuf; 13248 /* we will never free this */
13249 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
13223 13250
13224 /* from trap.c: */ 13251 /* from trap.c: */
13225 signal(SIGCHLD, SIG_DFL); 13252 signal(SIGCHLD, SIG_DFL);
diff --git a/shell/ash_test/ash-misc/source2.right b/shell/ash_test/ash-misc/source2.right
new file mode 100644
index 000000000..ce7171c87
--- /dev/null
+++ b/shell/ash_test/ash-misc/source2.right
@@ -0,0 +1 @@
Done: 0
diff --git a/shell/ash_test/ash-misc/source2.tests b/shell/ash_test/ash-misc/source2.tests
new file mode 100755
index 000000000..1870cdf7e
--- /dev/null
+++ b/shell/ash_test/ash-misc/source2.tests
@@ -0,0 +1,3 @@
1false
2. /dev/null
3echo Done: $?
diff --git a/shell/ash_test/ash-redir/redir3.tests b/shell/ash_test/ash-redir/redir3.tests
index f50a7674c..e37d5e45a 100755
--- a/shell/ash_test/ash-redir/redir3.tests
+++ b/shell/ash_test/ash-redir/redir3.tests
@@ -1,4 +1,4 @@
1# redirects to closed descriptors should not leave these descriptors" 1# redirects to closed descriptors should not leave these descriptors
2# open afterwards 2# open afterwards
3echo TEST 9>/dev/null 3echo TEST 9>/dev/null
4echo MUST ERROR OUT >&9 4echo MUST ERROR OUT >&9
diff --git a/shell/ash_test/ash-redir/redir7.tests b/shell/ash_test/ash-redir/redir7.tests
index 17d1040e0..ca3979a81 100755
--- a/shell/ash_test/ash-redir/redir7.tests
+++ b/shell/ash_test/ash-redir/redir7.tests
@@ -7,6 +7,6 @@
7echo -e 'echo Ok >uni\x81code' >>unicode.sh 7echo -e 'echo Ok >uni\x81code' >>unicode.sh
8echo -e 'cat uni\x81code' >>unicode.sh 8echo -e 'cat uni\x81code' >>unicode.sh
9echo -e 'cat uni?code' >>unicode.sh 9echo -e 'cat uni?code' >>unicode.sh
10. unicode.sh 10. ./unicode.sh
11rm uni*code* 11rm uni*code*
12echo Done 12echo Done
diff --git a/shell/ash_test/ash-redir/redir8.tests b/shell/ash_test/ash-redir/redir8.tests
index 32ab607b8..8cb42c0d3 100755
--- a/shell/ash_test/ash-redir/redir8.tests
+++ b/shell/ash_test/ash-redir/redir8.tests
@@ -10,6 +10,6 @@ echo -e 'v=uni\x81code' >>unicode.sh
10echo -e 'echo Ok >"$v"' >>unicode.sh 10echo -e 'echo Ok >"$v"' >>unicode.sh
11echo -e 'cat uni\x81code' >>unicode.sh 11echo -e 'cat uni\x81code' >>unicode.sh
12echo -e 'cat uni?code' >>unicode.sh 12echo -e 'cat uni?code' >>unicode.sh
13. unicode.sh 13. ./unicode.sh
14rm uni*code* 14rm uni*code*
15echo Done 15echo Done
diff --git a/shell/ash_test/ash-signals/signal5.right b/shell/ash_test/ash-signals/signal5.right
new file mode 100644
index 000000000..162f56bbc
--- /dev/null
+++ b/shell/ash_test/ash-signals/signal5.right
@@ -0,0 +1,12 @@
1sleeping for 3 sec
2sleeping for 2 sec
3Waiting
42 sec passed, sending USR1 to parent
5USR1 received
6Wait exit code: 138
7Waiting
83 sec passed, sending USR1 to parent
9USR1 received
10Wait exit code: 138
11Waiting
12Wait returned 0
diff --git a/shell/ash_test/ash-signals/signal5.tests b/shell/ash_test/ash-signals/signal5.tests
new file mode 100755
index 000000000..371120e95
--- /dev/null
+++ b/shell/ash_test/ash-signals/signal5.tests
@@ -0,0 +1,14 @@
1trap "echo USR1 received" USR1
2stub() {
3 echo "sleeping for $1 sec"
4 sleep $1
5 echo "$1 sec passed, sending USR1 to parent"
6 kill -USR1 $$
7}
8stub 3 &
9stub 2 &
10sleep 1
11until { echo "Waiting"; wait; } do
12 echo "Wait exit code: $?"
13done
14echo "Wait returned 0"
diff --git a/shell/ash_test/ash-signals/signal6.right b/shell/ash_test/ash-signals/signal6.right
new file mode 100644
index 000000000..df4d9306a
--- /dev/null
+++ b/shell/ash_test/ash-signals/signal6.right
@@ -0,0 +1,2 @@
1got TERM
2Done: 0
diff --git a/shell/ash_test/ash-signals/signal6.tests b/shell/ash_test/ash-signals/signal6.tests
new file mode 100755
index 000000000..3ce151060
--- /dev/null
+++ b/shell/ash_test/ash-signals/signal6.tests
@@ -0,0 +1,2 @@
1{ trap "echo got TERM" TERM; sleep 3; }& sleep 1; kill $!; wait
2echo Done: $?
diff --git a/shell/ash_test/ash-vars/var_leak.right b/shell/ash_test/ash-vars/var_leak.right
index 45c5458dd..be78112c8 100644
--- a/shell/ash_test/ash-vars/var_leak.right
+++ b/shell/ash_test/ash-vars/var_leak.right
@@ -1,2 +1,3 @@
1should be empty: '' 1should be empty: ''
2should be empty: '' 2should be not empty: 'val2'
3should be not empty: 'val3'
diff --git a/shell/ash_test/ash-vars/var_leak.tests b/shell/ash_test/ash-vars/var_leak.tests
index 1b1123fb7..032059295 100755
--- a/shell/ash_test/ash-vars/var_leak.tests
+++ b/shell/ash_test/ash-vars/var_leak.tests
@@ -1,9 +1,18 @@
1# This currently fails with CONFIG_FEATURE_SH_NOFORK=y 1# true is a regular builtin, varibale should not leak out of it
2# this currently fails with CONFIG_FEATURE_SH_NOFORK=y
2VAR='' 3VAR=''
3VAR=qwe true 4VAR=val1 true
4echo "should be empty: '$VAR'" 5echo "should be empty: '$VAR'"
5 6
6# This fails (always) 7# ash follows the "special builtin leaks variables" rule here:
8# exec is a special builtin. (bash does not do it)
7VAR='' 9VAR=''
8VAR=qwe exec 2>&1 10VAR=val2 exec 2>&1
9echo "should be empty: '$VAR'" 11echo "should be not empty: '$VAR'"
12
13# ash follows the "function call is a special builtin" rule here
14# (bash does not do it)
15f() { true; }
16VAR=''
17VAR=val3 f
18echo "should be not empty: '$VAR'"
diff --git a/shell/cttyhack.c b/shell/cttyhack.c
index 572a3af03..bde2acdc9 100644
--- a/shell/cttyhack.c
+++ b/shell/cttyhack.c
@@ -53,23 +53,32 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv)
53 } 53 }
54 54
55 strcpy(console, "/dev/tty"); 55 strcpy(console, "/dev/tty");
56 if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { 56 fd = open(console, O_RDWR);
57 /* this is a serial console */ 57 if (fd >= 0) {
58 sprintf(console + 8, "S%d", u.sr.line); 58 /* We already have ctty, nothing to do */
59 } else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { 59 close(fd);
60 /* this is linux virtual tty */ 60 } else {
61 sprintf(console + 8, "S%d" + 1, u.vt.v_active); 61 /* We don't have ctty (or don't have "/dev/tty" node...) */
62 } 62 if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) {
63 63 /* this is a serial console */
64 if (console[8]) { 64 sprintf(console + 8, "S%d", u.sr.line);
65 fd = xopen(console, O_RDWR); 65 } else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) {
66 //bb_error_msg("switching to '%s'", console); 66 /* this is linux virtual tty */
67 dup2(fd, 0); 67 sprintf(console + 8, "S%d" + 1, u.vt.v_active);
68 dup2(fd, 1); 68 }
69 dup2(fd, 2); 69 if (console[8]) {
70 while (fd > 2) close(fd--); 70 fd = xopen(console, O_RDWR);
71 /* Some other session may have it as ctty. Steal it from them */ 71 //bb_error_msg("switching to '%s'", console);
72 ioctl(0, TIOCSCTTY, 1); 72 dup2(fd, 0);
73 dup2(fd, 1);
74 dup2(fd, 2);
75 while (fd > 2)
76 close(fd--);
77 /* Some other session may have it as ctty,
78 * steal it from them:
79 */
80 ioctl(0, TIOCSCTTY, 1);
81 }
73 } 82 }
74 83
75 BB_EXECVP(argv[0], argv); 84 BB_EXECVP(argv[0], argv);
diff --git a/shell/hush.c b/shell/hush.c
index 9b15efb30..8baccf246 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -39,25 +39,28 @@
39 * 39 *
40 * POSIX syntax not implemented: 40 * POSIX syntax not implemented:
41 * aliases 41 * aliases
42 * <(list) and >(list) Process Substitution
43 * Tilde Expansion 42 * Tilde Expansion
44 * 43 *
45 * Bash stuff (optionally enabled): 44 * Bash compat TODO:
46 * &> and >& redirection of stdout+stderr 45 * redirection of stdout+stderr: &> and >&
47 * Brace Expansion 46 * brace expansion: one/{two,three,four}
48 * reserved words: [[ ]] function select 47 * reserved words: function select
49 * substrings ${var:1:5} 48 * advanced test: [[ ]]
49 * substrings: ${var:1:5}
50 * process substitution: <(list) and >(list)
51 * =~: regex operator
50 * let EXPR [EXPR...] 52 * let EXPR [EXPR...]
51 * Each EXPR is an arithmetic expression (ARITHMETIC EVALUATION) 53 * Each EXPR is an arithmetic expression (ARITHMETIC EVALUATION)
52 * If the last arg evaluates to 0, let returns 1; 0 otherwise. 54 * If the last arg evaluates to 0, let returns 1; 0 otherwise.
53 * NB: let `echo 'a=a + 1'` - error (IOW: multi-word expansion is used) 55 * NB: let `echo 'a=a + 1'` - error (IOW: multi-word expansion is used)
54 * ((EXPR)) 56 * ((EXPR))
55 * The EXPR is evaluated according to ARITHMETIC EVALUATION. 57 * The EXPR is evaluated according to ARITHMETIC EVALUATION.
56 * This is exactly equivalent to let "expression". 58 * This is exactly equivalent to let "EXPR".
59 * $[EXPR]: synonym for $((EXPR))
57 * 60 *
58 * TODOs: 61 * TODOs:
59 * grep for "TODO" and fix (some of them are easy) 62 * grep for "TODO" and fix (some of them are easy)
60 * special variables (done: PWD) 63 * special variables (done: PWD, PPID, RANDOM)
61 * follow IFS rules more precisely, including update semantics 64 * follow IFS rules more precisely, including update semantics
62 * export builtin should be special, its arguments are assignments 65 * export builtin should be special, its arguments are assignments
63 * and therefore expansion of them should be "one-word" expansion: 66 * and therefore expansion of them should be "one-word" expansion:
@@ -673,6 +676,9 @@ static const struct built_in_command bltins1[] = {
673#endif 676#endif
674 BLTIN("set" , builtin_set , "Set/unset positional parameters"), 677 BLTIN("set" , builtin_set , "Set/unset positional parameters"),
675 BLTIN("shift" , builtin_shift , "Shift positional parameters"), 678 BLTIN("shift" , builtin_shift , "Shift positional parameters"),
679#if ENABLE_HUSH_BASH_COMPAT
680 BLTIN("source" , builtin_source , "Run commands in a file"),
681#endif
676 BLTIN("trap" , builtin_trap , "Trap signals"), 682 BLTIN("trap" , builtin_trap , "Trap signals"),
677 BLTIN("type" , builtin_type , "Show command type"), 683 BLTIN("type" , builtin_type , "Show command type"),
678 BLTIN("ulimit" , shell_builtin_ulimit , "Control resource limits"), 684 BLTIN("ulimit" , shell_builtin_ulimit , "Control resource limits"),
@@ -6232,10 +6238,15 @@ static struct pipe *parse_stream(char **pstring,
6232 is_special = "{}<>;&|()#'" /* special outside of "str" */ 6238 is_special = "{}<>;&|()#'" /* special outside of "str" */
6233 "\\$\"" IF_HUSH_TICK("`"); /* always special */ 6239 "\\$\"" IF_HUSH_TICK("`"); /* always special */
6234 /* Are { and } special here? */ 6240 /* Are { and } special here? */
6235 if (ctx.command->argv /* word [word]{... */ 6241 if (ctx.command->argv /* word [word]{... - non-special */
6236 || dest.length /* word{... */ 6242 || dest.length /* word{... - non-special */
6237 || dest.o_quoted /* ""{... */ 6243 || dest.o_quoted /* ""{... - non-special */
6238 || (next != ';' && next != ')' && !strchr(G.ifs, next)) /* {word */ 6244 || (next != ';' /* }; - special */
6245 && next != ')' /* }) - special */
6246 && next != '&' /* }& and }&& ... - special */
6247 && next != '|' /* }|| ... - special */
6248 && !strchr(G.ifs, next) /* {word - non-special */
6249 )
6239 ) { 6250 ) {
6240 /* They are not special, skip "{}" */ 6251 /* They are not special, skip "{}" */
6241 is_special += 2; 6252 is_special += 2;
@@ -7859,21 +7870,26 @@ static int FAST_FUNC builtin_shift(char **argv)
7859 7870
7860static int FAST_FUNC builtin_source(char **argv) 7871static int FAST_FUNC builtin_source(char **argv)
7861{ 7872{
7862 char *arg_path; 7873 char *arg_path, *filename;
7863 FILE *input; 7874 FILE *input;
7864 save_arg_t sv; 7875 save_arg_t sv;
7865#if ENABLE_HUSH_FUNCTIONS 7876#if ENABLE_HUSH_FUNCTIONS
7866 smallint sv_flg; 7877 smallint sv_flg;
7867#endif 7878#endif
7868 7879
7869 if (*++argv == NULL) 7880 arg_path = NULL;
7870 return EXIT_FAILURE; 7881 filename = *++argv;
7871 7882 if (!filename) {
7872 if (strchr(*argv, '/') == NULL && (arg_path = find_in_path(*argv)) != NULL) { 7883 /* bash says: "bash: .: filename argument required" */
7873 input = fopen_for_read(arg_path); 7884 return 2; /* bash compat */
7874 free(arg_path); 7885 }
7875 } else 7886 if (!strchr(filename, '/')) {
7876 input = fopen_or_warn(*argv, "r"); 7887 arg_path = find_in_path(filename);
7888 if (arg_path)
7889 filename = arg_path;
7890 }
7891 input = fopen_or_warn(filename, "r");
7892 free(arg_path);
7877 if (!input) { 7893 if (!input) {
7878 /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ 7894 /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */
7879 return EXIT_FAILURE; 7895 return EXIT_FAILURE;
diff --git a/shell/hush_test/hush-parsing/group2.right b/shell/hush_test/hush-parsing/group2.right
new file mode 100644
index 000000000..df4d9306a
--- /dev/null
+++ b/shell/hush_test/hush-parsing/group2.right
@@ -0,0 +1,2 @@
1got TERM
2Done: 0
diff --git a/shell/hush_test/hush-parsing/group2.tests b/shell/hush_test/hush-parsing/group2.tests
new file mode 100755
index 000000000..d99178585
--- /dev/null
+++ b/shell/hush_test/hush-parsing/group2.tests
@@ -0,0 +1,3 @@
1# Bug was in handling of "}&" without space
2{ trap "echo got TERM" TERM; sleep 2; }& sleep 1; kill $!; wait
3echo Done: $?
diff --git a/testsuite/ar.tests b/testsuite/ar.tests
index f112eb64a..4630d08a4 100755
--- a/testsuite/ar.tests
+++ b/testsuite/ar.tests
@@ -18,10 +18,10 @@ testing "ar creates archives" \
18rm test.a 18rm test.a
19 19
20testing "ar replaces things in archives" \ 20testing "ar replaces things in archives" \
21 "echo 'blah!' >file1 && echo 'blast!'> file2 && ar cr test.a README file1 file2 && mv file2 file1 && ar cr test.a file1 && ar p test.a file1" \ 21 "echo 'blah!' >file1 && echo 'blast!' >file2 && ar cr test.a README file1 file2 && mv file2 file1 && ar cr test.a file1 && ar p test.a file1" \
22 "blast!\n" \ 22 "blast!\n" \
23 "" \ 23 "" \
24 "" 24 ""
25rm test.a 25rm test.a file1 file1 2>/dev/null
26 26
27exit $FAILCOUNT 27exit $FAILCOUNT
diff --git a/testsuite/ash.tests b/testsuite/ash.tests
index 6b2caf316..dd626e6d1 100755
--- a/testsuite/ash.tests
+++ b/testsuite/ash.tests
@@ -7,8 +7,34 @@
7 7
8. ./testing.sh 8. ./testing.sh
9 9
10test -f "$bindir/.config" && . "$bindir/.config"
11
12test x"CONFIG_SCRIPT" = x"y" || exit 0
13test x"CONFIG_HEXDUMP" = x"y" || exit 0
14test x"CONFIG_FEATURE_DEVPTS" = x"y" || exit 0
15
10# testing "test name" "options" "expected result" "file input" "stdin" 16# testing "test name" "options" "expected result" "file input" "stdin"
11 17
18if test x"$CONFIG_UNICODE_PRESERVE_BROKEN" = x"y"; then
19testing "One byte which is not valid unicode char followed by valid input" \
20 "script -q -c 'ash' /dev/null >/dev/null; cat ash.output" \
21 "\
2200000000 ff 2d 0a |.-.|
2300000003
24" \
25 "" \
26 "echo \xff- | hexdump -C >ash.output; exit; exit; exit; exit\n"
27
28testing "30 bytes which are not valid unicode chars followed by valid input" \
29 "script -q -c 'ash' /dev/null >/dev/null; cat ash.output" \
30 "\
3100000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
3200000010 ff ff ff ff ff ff ff ff ff ff ff ff ff ff 2d 0a |..............-.|
3300000020
34" \
35 "" \
36 "echo \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff- | hexdump -C >ash.output; exit; exit; exit; exit\n"
37else
12testing "One byte which is not valid unicode char followed by valid input" \ 38testing "One byte which is not valid unicode char followed by valid input" \
13 "script -q -c 'ash' /dev/null >/dev/null; cat ash.output" \ 39 "script -q -c 'ash' /dev/null >/dev/null; cat ash.output" \
14 "\ 40 "\
@@ -27,6 +53,8 @@ testing "30 bytes which are not valid unicode chars followed by valid input" \
27" \ 53" \
28 "" \ 54 "" \
29 "echo \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff- | hexdump -C >ash.output; exit; exit; exit; exit\n" 55 "echo \xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff- | hexdump -C >ash.output; exit; exit; exit; exit\n"
56fi
57
30 58
31# Not sure this behavior is perfect: we lose all invalid input which precedes 59# Not sure this behavior is perfect: we lose all invalid input which precedes
32# arrow keys and such. In this example, \xff\xff are lost 60# arrow keys and such. In this example, \xff\xff are lost
@@ -43,7 +71,7 @@ testing "2 bytes which are not valid unicode chars followed by left arrow key" \
43# not checked by the test), then read and execute the rest: "echo A | ..." 71# not checked by the test), then read and execute the rest: "echo A | ..."
44# The bug was that ash was eating the beginning of "echo A" despite the pause. 72# The bug was that ash was eating the beginning of "echo A" despite the pause.
45testing "Invalid unicode chars followed by a pause do not eat next chars" \ 73testing "Invalid unicode chars followed by a pause do not eat next chars" \
46 "{ echo -ne 'echo \xff\n'; sleep 1; echo -ne 'echo A | hexdump -C >ash.output; exit; exit; exit; exit\n'; } \ 74 "{ $ECHO -ne 'echo \xff\n'; sleep 1; $ECHO -ne 'echo A | hexdump -C >ash.output; exit; exit; exit; exit\n'; } \
47 | script -q -c 'ash' /dev/null >/dev/null; cat ash.output" \ 75 | script -q -c 'ash' /dev/null >/dev/null; cat ash.output" \
48 "\ 76 "\
4900000000 41 0a |A.| 7700000000 41 0a |A.|
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index 3a7c8f4d0..0691a7972 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -18,9 +18,11 @@ testing "awk -F case 7" "awk -F '[#]' '{ print NF }'" "5\n" "" "z##abc##zz\n"
18 18
19# 4294967295 = 0xffffffff 19# 4294967295 = 0xffffffff
20testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4.29497e+09\n" "" "\n" 20testing "awk bitwise op" "awk '{ print or(4294967295,1) }'" "4.29497e+09\n" "" "\n"
21optional DESKTOP
21testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4.29497e+09\n" "" "\n" 22testing "awk hex const 1" "awk '{ print or(0xffffffff,1) }'" "4.29497e+09\n" "" "\n"
22testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2.14748e+09\n" "" "\n" 23testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2.14748e+09\n" "" "\n"
23testing "awk oct const" "awk '{ print or(01234,1) }'" "669\n" "" "\n" 24testing "awk oct const" "awk '{ print or(01234,1) }'" "669\n" "" "\n"
25SKIP=
24 26
25# long field seps requiring regex 27# long field seps requiring regex
26testing "awk long field sep" "awk -F-- '{ print NF, length(\$NF), \$NF }'" \ 28testing "awk long field sep" "awk -F-- '{ print NF, length(\$NF), \$NF }'" \
@@ -33,12 +35,14 @@ testing "awk long field sep" "awk -F-- '{ print NF, length(\$NF), \$NF }'" \
33testing "awk gsub falls back to non-extended-regex" \ 35testing "awk gsub falls back to non-extended-regex" \
34 "awk 'gsub(\"@(samp|code|file)\{\",\"\");'; echo \$?" "0\n" "" "Hi\n" 36 "awk 'gsub(\"@(samp|code|file)\{\",\"\");'; echo \$?" "0\n" "" "Hi\n"
35 37
36tar xjf awk_t1.tar.bz2 38optional TAR BUNZIP2 FEATURE_SEAMLESS_BZ2
39test x"$SKIP" != x"1" && tar xjf awk_t1.tar.bz2
37testing "awk 'gcc build bug'" \ 40testing "awk 'gcc build bug'" \
38 "awk -f awk_t1_opt-functions.awk -f awk_t1_opth-gen.awk <awk_t1_input | md5sum" \ 41 "awk -f awk_t1_opt-functions.awk -f awk_t1_opth-gen.awk <awk_t1_input | md5sum" \
39 "f842e256461a5ab1ec60b58d16f1114f -\n" \ 42 "f842e256461a5ab1ec60b58d16f1114f -\n" \
40 "" "" 43 "" ""
41rm -rf awk_t1_* 44rm -rf awk_t1_* 2>/dev/null
45SKIP=
42 46
43Q='":"' 47Q='":"'
44 48
diff --git a/testsuite/busybox.tests b/testsuite/busybox.tests
index 6eeb3251d..0c740530d 100755
--- a/testsuite/busybox.tests
+++ b/testsuite/busybox.tests
@@ -10,8 +10,9 @@ HELPDUMP=`true | busybox 2>&1 | cat`
10 10
11# We need to test under calling the binary under other names. 11# We need to test under calling the binary under other names.
12 12
13 13optional FEATURE_VERBOSE_USAGE
14testing "busybox --help busybox" "true | busybox --help busybox 2>&1 | cat" "$HELPDUMP\n\n" "" "" 14testing "busybox --help busybox" "true | busybox --help busybox 2>&1 | cat" "$HELPDUMP\n\n" "" ""
15SKIP=
15 16
16ln -s `which busybox` busybox-suffix 17ln -s `which busybox` busybox-suffix
17for i in busybox ./busybox-suffix 18for i in busybox ./busybox-suffix
@@ -26,11 +27,11 @@ do
26 27
27 testing "$i --help" "$i --help 2>&1" "$HELPDUMP\n\n" "" "" 28 testing "$i --help" "$i --help 2>&1" "$HELPDUMP\n\n" "" ""
28 29
29 optional CAT 30 optional FEATURE_VERBOSE_USAGE CAT
30 testing "" "$i cat" "moo" "" "moo" 31 testing "" "$i cat" "moo" "" "moo"
31 testing "$i --help cat" "$i --help cat 2>&1 | grep print" \ 32 testing "$i --help cat" "$i --help cat 2>&1 | grep print" \
32 "Concatenate FILEs and print them to stdout\n" "" "" 33 "Concatenate FILEs and print them to stdout\n" "" ""
33 optional "" 34 SKIP=
34 35
35 testing "$i --help unknown" "$i --help unknown 2>&1" \ 36 testing "$i --help unknown" "$i --help unknown 2>&1" \
36 "unknown: applet not found\n" "" "" 37 "unknown: applet not found\n" "" ""
diff --git a/testsuite/cpio.tests b/testsuite/cpio.tests
index e53ade925..725e70eab 100755
--- a/testsuite/cpio.tests
+++ b/testsuite/cpio.tests
@@ -31,8 +31,9 @@ rm -rf cpio.testdir cpio.testdir2 2>/dev/null
31 31
32# testing "test name" "command" "expected result" "file input" "stdin" 32# testing "test name" "command" "expected result" "file input" "stdin"
33 33
34optional FEATURE_LS_SORTFILES FEATURE_LS_TIMESTAMPS
34testing "cpio extracts zero-sized hardlinks" \ 35testing "cpio extracts zero-sized hardlinks" \
35"$ECHO -ne '$hexdump' | bzcat | cpio -i; echo \$?; 36"$ECHO -ne '$hexdump' | bzcat | cpio -i 2>&1; echo \$?;
36ls -ln cpio.testdir | $FILTER_LS" \ 37ls -ln cpio.testdir | $FILTER_LS" \
37"\ 38"\
381 blocks 391 blocks
@@ -41,11 +42,12 @@ ls -ln cpio.testdir | $FILTER_LS" \
41-rw-r--r-- 2 $user $group 0 y 42-rw-r--r-- 2 $user $group 0 y
42" \ 43" \
43 "" "" 44 "" ""
45SKIP=
44 46
45 47
46test x"$SKIP_KNOWN_BUGS" = x"" && { 48test x"$SKIP_KNOWN_BUGS" = x"" && {
47# Currently fails. Numerous buglets: "1 blocks" versus "1 block", 49# Currently fails. Numerous buglets: "1 blocks" versus "1 block",
48# "1 block" must go to stderr, does not list cpio.testdir/x and cpio.testdir/y 50# does not list cpio.testdir/x and cpio.testdir/y
49testing "cpio lists hardlinks" \ 51testing "cpio lists hardlinks" \
50"$ECHO -ne '$hexdump' | bzcat | cpio -t 2>&1; echo \$?" \ 52"$ECHO -ne '$hexdump' | bzcat | cpio -t 2>&1; echo \$?" \
51"\ 53"\
@@ -69,8 +71,9 @@ ln cpio.testdir/empty cpio.testdir/empty1
69ln cpio.testdir/nonempty cpio.testdir/nonempty1 71ln cpio.testdir/nonempty cpio.testdir/nonempty1
70mkdir cpio.testdir2 72mkdir cpio.testdir2
71 73
74optional FEATURE_CPIO_O LONG_OPTS FEATURE_LS_SORTFILES FEATURE_LS_TIMESTAMPS
72testing "cpio extracts zero-sized hardlinks 2" \ 75testing "cpio extracts zero-sized hardlinks 2" \
73"find cpio.testdir | cpio -H newc --create | (cd cpio.testdir2 && cpio -i); echo \$?; 76"find cpio.testdir | cpio -H newc --create | (cd cpio.testdir2 && cpio -i 2>&1); echo \$?;
74ls -ln cpio.testdir2/cpio.testdir | $FILTER_LS" \ 77ls -ln cpio.testdir2/cpio.testdir | $FILTER_LS" \
75"\ 78"\
762 blocks 792 blocks
@@ -82,12 +85,14 @@ ls -ln cpio.testdir2/cpio.testdir | $FILTER_LS" \
82-rw-r--r-- 1 $user $group 0 solo 85-rw-r--r-- 1 $user $group 0 solo
83" \ 86" \
84 "" "" 87 "" ""
88SKIP=
85 89
86 90
87# Was trying to create "/usr/bin", correct is "usr/bin". 91# Was trying to create "/usr/bin", correct is "usr/bin".
88rm -rf cpio.testdir 92rm -rf cpio.testdir
93optional FEATURE_CPIO_P
89testing "cpio -p with absolute paths" \ 94testing "cpio -p with absolute paths" \
90"echo /usr/bin | cpio -dp cpio.testdir; echo \$?; 95"echo /usr/bin | cpio -dp cpio.testdir 2>&1; echo \$?;
91ls cpio.testdir" \ 96ls cpio.testdir" \
92"\ 97"\
931 blocks 981 blocks
@@ -95,6 +100,7 @@ ls cpio.testdir" \
95usr 100usr
96" \ 101" \
97 "" "" 102 "" ""
103SKIP=
98 104
99 105
100# Clean up 106# Clean up
diff --git a/testsuite/cut/cut-cuts-a-field b/testsuite/cut/cut-cuts-a-field
index 4c7f44007..e200b6b78 100644
--- a/testsuite/cut/cut-cuts-a-field
+++ b/testsuite/cut/cut-cuts-a-field
@@ -1 +1 @@
test $(echo -e "f1\tf2\tf3" | busybox cut -f 2) = f2 test $($ECHO -e "f1\tf2\tf3" | busybox cut -f 2) = f2
diff --git a/testsuite/date/date-R-works b/testsuite/date/date-R-works
index 34cd735e5..d05634456 100644
--- a/testsuite/date/date-R-works
+++ b/testsuite/date/date-R-works
@@ -1 +1,8 @@
1test x"`date -R`" = x"`busybox date -R`" 1dt1="`date -R`"
2# Wait for the start of next second
3dt="$dt1"
4while test x"$dt" = x"$dt1"; do
5 dt="`date -R`"
6done
7
8test x"$dt" = x"`busybox date -R`"
diff --git a/testsuite/diff.tests b/testsuite/diff.tests
index 72ebb6c4c..06d5a4fd7 100755
--- a/testsuite/diff.tests
+++ b/testsuite/diff.tests
@@ -106,6 +106,7 @@ rm -rf diff1 diff2
106mkdir diff1 diff2 diff2/subdir 106mkdir diff1 diff2 diff2/subdir
107echo qwe >diff1/- 107echo qwe >diff1/-
108echo asd >diff2/subdir/- 108echo asd >diff2/subdir/-
109optional FEATURE_DIFF_DIR
109testing "diff diff1 diff2/subdir" \ 110testing "diff diff1 diff2/subdir" \
110 "diff -ur diff1 diff2/subdir | $TRIM_TAB" \ 111 "diff -ur diff1 diff2/subdir | $TRIM_TAB" \
111"\ 112"\
@@ -116,8 +117,10 @@ testing "diff diff1 diff2/subdir" \
116+asd 117+asd
117" \ 118" \
118 "" "" 119 "" ""
120SKIP=
119 121
120# using directory structure from prev test... 122# using directory structure from prev test...
123optional FEATURE_DIFF_DIR
121testing "diff dir dir2/file/-" \ 124testing "diff dir dir2/file/-" \
122 "diff -ur diff1 diff2/subdir/- | $TRIM_TAB" \ 125 "diff -ur diff1 diff2/subdir/- | $TRIM_TAB" \
123"\ 126"\
@@ -128,10 +131,12 @@ testing "diff dir dir2/file/-" \
128+asd 131+asd
129" \ 132" \
130 "" "" 133 "" ""
134SKIP=
131 135
132# using directory structure from prev test... 136# using directory structure from prev test...
133mkdir diff1/test 137mkdir diff1/test
134mkfifo diff2/subdir/test 138mkfifo diff2/subdir/test
139optional FEATURE_DIFF_DIR
135testing "diff of dir and fifo" \ 140testing "diff of dir and fifo" \
136 "diff -ur diff1 diff2/subdir | $TRIM_TAB" \ 141 "diff -ur diff1 diff2/subdir | $TRIM_TAB" \
137"\ 142"\
@@ -143,10 +148,12 @@ testing "diff of dir and fifo" \
143Only in diff2/subdir: test 148Only in diff2/subdir: test
144" \ 149" \
145 "" "" 150 "" ""
151SKIP=
146 152
147# using directory structure from prev test... 153# using directory structure from prev test...
148rmdir diff1/test 154rmdir diff1/test
149echo >diff1/test 155echo >diff1/test
156optional FEATURE_DIFF_DIR
150testing "diff of file and fifo" \ 157testing "diff of file and fifo" \
151 "diff -ur diff1 diff2/subdir | $TRIM_TAB" \ 158 "diff -ur diff1 diff2/subdir | $TRIM_TAB" \
152"\ 159"\
@@ -158,9 +165,11 @@ testing "diff of file and fifo" \
158File diff2/subdir/test is not a regular file or directory and was skipped 165File diff2/subdir/test is not a regular file or directory and was skipped
159" \ 166" \
160 "" "" 167 "" ""
168SKIP=
161 169
162# using directory structure from prev test... 170# using directory structure from prev test...
163mkfifo diff1/test2 171mkfifo diff1/test2
172optional FEATURE_DIFF_DIR
164testing "diff -rN does not read non-regular files" \ 173testing "diff -rN does not read non-regular files" \
165 "diff -urN diff1 diff2/subdir | $TRIM_TAB" \ 174 "diff -urN diff1 diff2/subdir | $TRIM_TAB" \
166"\ 175"\
@@ -173,6 +182,7 @@ File diff2/subdir/test is not a regular file or directory and was skipped
173File diff1/test2 is not a regular file or directory and was skipped 182File diff1/test2 is not a regular file or directory and was skipped
174" \ 183" \
175 "" "" 184 "" ""
185SKIP=
176 186
177# clean up 187# clean up
178rm -rf diff1 diff2 188rm -rf diff1 diff2
diff --git a/testsuite/du/du-h-works b/testsuite/du/du-h-works
index 3f8ff3d0b..c18433c29 100644
--- a/testsuite/du/du-h-works
+++ b/testsuite/du/du-h-works
@@ -1,4 +1,4 @@
1d=/bin 1# FEATURE: CONFIG_FEATURE_HUMAN_READABLE
2du -h "$d" > logfile.gnu 2
3busybox du -h "$d" > logfile.bb 3dd if=/dev/zero of=file bs=1M count=1 2>/dev/null
4cmp logfile.gnu logfile.bb 4test x"`busybox du -h .`" = x"1.0M ."
diff --git a/testsuite/du/du-k-works b/testsuite/du/du-k-works
index 6c2c5d073..a52264945 100644
--- a/testsuite/du/du-k-works
+++ b/testsuite/du/du-k-works
@@ -1,4 +1,4 @@
1d=/bin 1dd if=/dev/zero of=file1 bs=1k count=64 2>/dev/null
2du -k "$d" > logfile.gnu 2dd if=/dev/zero of=file2 bs=1k count=16 2>/dev/null
3busybox du -k "$d" > logfile.bb 3test x"`busybox du -k .`" = x"80 ." \
4cmp logfile.gnu logfile.bb 4 -o x"`busybox du -k .`" = x"88 ." \
diff --git a/testsuite/du/du-l-works b/testsuite/du/du-l-works
index c3d2ec0c1..6b150e0dd 100644
--- a/testsuite/du/du-l-works
+++ b/testsuite/du/du-l-works
@@ -1,4 +1,8 @@
1d=/bin 1# FEATURE: CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
2du -l "$d" > logfile.gnu 2
3busybox du -l "$d" > logfile.bb 3dd if=/dev/zero of=file1 bs=1k count=64 2>/dev/null
4cmp logfile.gnu logfile.bb 4ln file1 file1.1
5dd if=/dev/zero of=file2 bs=1k count=16 2>/dev/null
6test x"`busybox du -l .`" = x"144 ." \
7 -o x"`busybox du -l .`" = x"148 ." \
8 -o x"`busybox du -l .`" = x"152 ." \
diff --git a/testsuite/du/du-m-works b/testsuite/du/du-m-works
index bf0a90e1b..9fa7437ac 100644
--- a/testsuite/du/du-m-works
+++ b/testsuite/du/du-m-works
@@ -1,4 +1,4 @@
1d=/bin 1# FEATURE: CONFIG_FEATURE_HUMAN_READABLE
2du -m "$d" > logfile.gnu 2
3busybox du -m "$d" > logfile.bb 3dd if=/dev/zero of=file bs=1M count=1 2>/dev/null
4cmp logfile.gnu logfile.bb 4test x"`busybox du -m .`" = x"1 ."
diff --git a/testsuite/du/du-s-works b/testsuite/du/du-s-works
index ae970772a..534432cb0 100644
--- a/testsuite/du/du-s-works
+++ b/testsuite/du/du-s-works
@@ -1,4 +1,8 @@
1# FEATURE: CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
2
1d=/bin 3d=/bin
2du -s "$d" > logfile.gnu 4du -s "$d" > logfile.gnu
3busybox du -s "$d" > logfile.bb 5busybox du -s "$d" > logfile.bb
4cmp logfile.gnu logfile.bb 6cmp logfile.gnu logfile.bb && exit 0
7diff -u logfile.gnu logfile.bb
8exit 1
diff --git a/testsuite/du/du-works b/testsuite/du/du-works
index 46a336dc3..e320f1dd0 100644
--- a/testsuite/du/du-works
+++ b/testsuite/du/du-works
@@ -1,4 +1,8 @@
1# FEATURE: CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
2
1d=/bin 3d=/bin
2du "$d" > logfile.gnu 4du "$d" > logfile.gnu
3busybox du "$d" > logfile.bb 5busybox du "$d" > logfile.bb
4cmp logfile.gnu logfile.bb 6cmp logfile.gnu logfile.bb && exit 0
7diff -u logfile.gnu logfile.bb
8exit 1
diff --git a/testsuite/echo/echo-does-not-print-newline b/testsuite/echo/echo-does-not-print-newline
index 2ed03caf5..2857c0d13 100644
--- a/testsuite/echo/echo-does-not-print-newline
+++ b/testsuite/echo/echo-does-not-print-newline
@@ -1 +1,3 @@
1# FEATURE: CONFIG_FEATURE_FANCY_ECHO
2
1test `busybox echo -n word | wc -c` -eq 4 3test `busybox echo -n word | wc -c` -eq 4
diff --git a/testsuite/echo/echo-prints-slash-zero b/testsuite/echo/echo-prints-slash-zero
index d2466326f..d97ed8e66 100644
--- a/testsuite/echo/echo-prints-slash-zero
+++ b/testsuite/echo/echo-prints-slash-zero
@@ -1 +1,3 @@
1# FEATURE: CONFIG_FEATURE_FANCY_ECHO
2
1test "`busybox echo -e -n 'msg\n\0' | od -t x1 | head -n 1`" = "0000000 6d 73 67 0a 00" 3test "`busybox echo -e -n 'msg\n\0' | od -t x1 | head -n 1`" = "0000000 6d 73 67 0a 00"
diff --git a/testsuite/expand.tests b/testsuite/expand.tests
index 996631450..357a9ad6b 100755
--- a/testsuite/expand.tests
+++ b/testsuite/expand.tests
@@ -10,12 +10,15 @@ testing "expand" \
10 "expand" \ 10 "expand" \
11 " 12345678 12345678\n" \ 11 " 12345678 12345678\n" \
12 "" \ 12 "" \
13 "\t12345678\t12345678\n" \ 13 "\t12345678\t12345678\n"
14 14
15optional UNICODE_SUPPORT
15testing "expand with unicode characher 0x394" \ 16testing "expand with unicode characher 0x394" \
16 "expand" \ 17 "expand" \
17 "Δ 12345ΔΔΔ 12345678\n" \ 18 "Δ 12345ΔΔΔ 12345678\n" \
18 "" \ 19 "" \
19 "Δ\t12345ΔΔΔ\t12345678\n" \ 20 "Δ\t12345ΔΔΔ\t12345678\n"
21SKIP=
22
20 23
21exit $FAILCOUNT 24exit $FAILCOUNT
diff --git a/testsuite/expand/expand-works-like-GNU b/testsuite/expand/expand-works-like-GNU
index ee8c793ed..b0278d88d 100644
--- a/testsuite/expand/expand-works-like-GNU
+++ b/testsuite/expand/expand-works-like-GNU
@@ -1,6 +1,8 @@
1# FEATURE: CONFIG_UNEXPAND
2
1rm -f foo bar 3rm -f foo bar
2echo -e "\ty" | expand -t 3 ../../busybox > foo 4$ECHO -e "\ty" | expand -t 3 ../../busybox > foo
3echo -e "\ty" | busybox unexpand -t 3 ../../busybox > bar 5$ECHO -e "\ty" | busybox unexpand -t 3 ../../busybox > bar
4set +e 6set +e
5test ! -f foo -a -f bar 7test ! -f foo -a -f bar
6if [ $? = 0 ] ; then 8if [ $? = 0 ] ; then
@@ -8,8 +10,8 @@ if [ $? = 0 ] ; then
8 diff -q foo bar 10 diff -q foo bar
9fi 11fi
10rm -f foo bar 12rm -f foo bar
11echo -e "\ty\tx" | expand -it 3 ../../busybox > foo 13$ECHO -e "\ty\tx" | expand -it 3 ../../busybox > foo
12echo -e "\ty\tx" | busybox unexpand -it 3 ../../busybox > bar 14$ECHO -e "\ty\tx" | busybox unexpand -it 3 ../../busybox > bar
13set +e 15set +e
14test ! -f foo -a -f bar 16test ! -f foo -a -f bar
15if [ $? = 0 ] ; then 17if [ $? = 0 ] ; then
diff --git a/testsuite/find/find-supports-minus-xdev b/testsuite/find/find-supports-minus-xdev
index 4c559a1f4..c807fc8f2 100644
--- a/testsuite/find/find-supports-minus-xdev
+++ b/testsuite/find/find-supports-minus-xdev
@@ -1 +1,3 @@
1# FEATURE: CONFIG_FEATURE_FIND_XDEV
2
1busybox find . -xdev >/dev/null 2>&1 3busybox find . -xdev >/dev/null 2>&1
diff --git a/testsuite/fold.tests b/testsuite/fold.tests
index 17721a180..0197d024d 100755
--- a/testsuite/fold.tests
+++ b/testsuite/fold.tests
@@ -28,6 +28,7 @@ be preserved
28is here:>\0< - they must be preserved 28is here:>\0< - they must be preserved
29" \ 29" \
30 30
31optional UNICODE_SUPPORT
31# The text was taken from English and Ukrainian wikipedia pages 32# The text was taken from English and Ukrainian wikipedia pages
32testing "fold -sw66 with unicode input" "fold -sw66" \ 33testing "fold -sw66 with unicode input" "fold -sw66" \
33 "\ 34 "\
@@ -54,6 +55,7 @@ Way.
54каталогом Мессьє та NGC224 за Новим загальним каталогом) — \ 55каталогом Мессьє та NGC224 за Новим загальним каталогом) — \
55спіральна галактика, що знаходиться на відстані приблизно у 2,5 \ 56спіральна галактика, що знаходиться на відстані приблизно у 2,5 \
56мільйони світлових років від нашої планети у сузір'ї Андромеди. \ 57мільйони світлових років від нашої планети у сузір'ї Андромеди. \
57На початку ХХІ ст. в центрі галактики виявлено чорну дірку." \ 58На початку ХХІ ст. в центрі галактики виявлено чорну дірку."
59SKIP=
58 60
59exit $FAILCOUNT 61exit $FAILCOUNT
diff --git a/testsuite/grep.tests b/testsuite/grep.tests
index 8692307dd..d4bf80d83 100755
--- a/testsuite/grep.tests
+++ b/testsuite/grep.tests
@@ -75,6 +75,8 @@ testing "grep handles multiple regexps" "grep -e one -e two input ; echo \$?" \
75 "one\ntwo\n0\n" "one\ntwo\n" "" 75 "one\ntwo\n0\n" "one\ntwo\n" ""
76testing "grep -F handles multiple expessions" "grep -F -e one -e two input ; echo \$?" \ 76testing "grep -F handles multiple expessions" "grep -F -e one -e two input ; echo \$?" \
77 "one\ntwo\n0\n" "one\ntwo\n" "" 77 "one\ntwo\n0\n" "one\ntwo\n" ""
78testing "grep -F handles -i" "grep -F -i foo input ; echo \$?" \
79 "FOO\n0\n" "FOO\n" ""
78 80
79# -f file/- 81# -f file/-
80testing "grep can read regexps from stdin" "grep -f - input ; echo \$?" \ 82testing "grep can read regexps from stdin" "grep -f - input ; echo \$?" \
diff --git a/testsuite/hostid/hostid-works b/testsuite/hostid/hostid-works
index e85698e66..bcfd717af 100644
--- a/testsuite/hostid/hostid-works
+++ b/testsuite/hostid/hostid-works
@@ -1,2 +1,8 @@
1test x$(hostid) = x$(busybox hostid) 1h=x$(busybox hostid)
2 2# Is $h a sequence of hex numbers?
3x="${h//[0123456789abcdef]/x}"
4x="${x//xxx/x}"
5x="${x//xxx/x}"
6x="${x//xxx/x}"
7x="${x//xx/x}"
8test x"$x" = x"x"
diff --git a/testsuite/hostname/hostname-d-works b/testsuite/hostname/hostname-d-works
index a9aeb92cb..e062242bb 100644
--- a/testsuite/hostname/hostname-d-works
+++ b/testsuite/hostname/hostname-d-works
@@ -1,2 +1,3 @@
1test x$(hostname -d) = x$(busybox hostname -d) 1f=$(busybox hostname -f)
2 2d=$(busybox hostname -d)
3test x"${f#*.}" = x"$d"
diff --git a/testsuite/ls/ls-1-works b/testsuite/ls/ls-1-works
index 885694920..71ab9a66b 100644
--- a/testsuite/ls/ls-1-works
+++ b/testsuite/ls/ls-1-works
@@ -1,3 +1,5 @@
1# FEATURE: CONFIG_FEATURE_LS_SORTFILES
2
1[ -n "$d" ] || d=.. 3[ -n "$d" ] || d=..
2LC_ALL=C ls -1 "$d" > logfile.gnu 4LC_ALL=C ls -1 "$d" > logfile.gnu
3LC_ALL=C busybox ls -1 "$d" > logfile.bb 5LC_ALL=C busybox ls -1 "$d" > logfile.bb
diff --git a/testsuite/ls/ls-h-works b/testsuite/ls/ls-h-works
index 0c83f7cc5..60016bac1 100644
--- a/testsuite/ls/ls-h-works
+++ b/testsuite/ls/ls-h-works
@@ -1,3 +1,5 @@
1# FEATURE: CONFIG_FEATURE_LS_SORTFILES CONFIG_FEATURE_HUMAN_READABLE
2
1[ -n "$d" ] || d=.. 3[ -n "$d" ] || d=..
2LC_ALL=C ls -h "$d" > logfile.gnu 4LC_ALL=C ls -h "$d" > logfile.gnu
3LC_ALL=C busybox ls -h "$d" > logfile.bb 5LC_ALL=C busybox ls -h "$d" > logfile.bb
diff --git a/testsuite/makedevs.tests b/testsuite/makedevs.tests
index b41614f13..f69b4a6b1 100755
--- a/testsuite/makedevs.tests
+++ b/testsuite/makedevs.tests
@@ -16,6 +16,7 @@ FILTER_LS2="sed -e 's/, */,/g' -e 's/ */ /g' | cut -d' ' -f 1-4,9-"
16rm -rf makedevs.testdir 16rm -rf makedevs.testdir
17mkdir makedevs.testdir 17mkdir makedevs.testdir
18 18
19optional FEATURE_MAKEDEVS_TABLE FEATURE_FIND_NOT FEATURE_FIND_TYPE FEATURE_LS_RECURSIVE FEATURE_LS_SORTFILES
19testing "makedevs -d ../makedevs.device_table.txt ." \ 20testing "makedevs -d ../makedevs.device_table.txt ." \
20 "(cd makedevs.testdir && makedevs -d ../makedevs.device_table.txt . 2>&1); 21 "(cd makedevs.testdir && makedevs -d ../makedevs.device_table.txt . 2>&1);
21 find makedevs.testdir ! -type d | sort | xargs ls -lnR | $FILTER_LS" \ 22 find makedevs.testdir ! -type d | sort | xargs ls -lnR | $FILTER_LS" \
@@ -132,6 +133,7 @@ crw-rw-rw- 1 0 0 1,9 makedevs.testdir/dev/urandom
132crw-rw-rw- 1 0 0 1,5 makedevs.testdir/dev/zero 133crw-rw-rw- 1 0 0 1,5 makedevs.testdir/dev/zero
133" \ 134" \
134 "" "" 135 "" ""
136SKIP=
135 137
136# clean up 138# clean up
137rm -rf makedevs.testdir 139rm -rf makedevs.testdir
diff --git a/testsuite/md5sum/md5sum-verifies-non-binary-file b/testsuite/md5sum/md5sum-verifies-non-binary-file
index 8566a234d..1df818eb5 100644
--- a/testsuite/md5sum/md5sum-verifies-non-binary-file
+++ b/testsuite/md5sum/md5sum-verifies-non-binary-file
@@ -1,3 +1,5 @@
1# FEATURE: CONFIG_FEATURE_MD5_SHA1_SUM_CHECK
2
1touch foo 3touch foo
2md5sum foo > bar 4md5sum foo > bar
3busybox md5sum -c bar 5busybox md5sum -c bar
diff --git a/testsuite/mdev.tests b/testsuite/mdev.tests
index 036738e52..c375fc774 100755
--- a/testsuite/mdev.tests
+++ b/testsuite/mdev.tests
@@ -27,6 +27,7 @@ echo "8:0" >mdev.testdir/sys/block/sda/dev
27 27
28# env - PATH=$PATH: on some systems chroot binary won't otherwise be found 28# env - PATH=$PATH: on some systems chroot binary won't otherwise be found
29 29
30optional STATIC FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME
30testing "mdev add /block/sda" \ 31testing "mdev add /block/sda" \
31 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; 32 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
32 ls -ln mdev.testdir/dev | $FILTER_LS" \ 33 ls -ln mdev.testdir/dev | $FILTER_LS" \
@@ -34,11 +35,13 @@ testing "mdev add /block/sda" \
34brw-rw---- 1 0 0 8,0 sda 35brw-rw---- 1 0 0 8,0 sda
35" \ 36" \
36 "" "" 37 "" ""
38SKIP=
37 39
38# continuing to use directory structure from prev test 40# continuing to use directory structure from prev test
39rm -rf mdev.testdir/dev/* 41rm -rf mdev.testdir/dev/*
40echo ".* 1:1 666" >mdev.testdir/etc/mdev.conf 42echo ".* 1:1 666" >mdev.testdir/etc/mdev.conf
41echo "sda 2:2 444" >>mdev.testdir/etc/mdev.conf 43echo "sda 2:2 444" >>mdev.testdir/etc/mdev.conf
44optional STATIC FEATURE_MDEV_CONF FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME
42testing "mdev stops on first rule" \ 45testing "mdev stops on first rule" \
43 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; 46 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
44 ls -ln mdev.testdir/dev | $FILTER_LS" \ 47 ls -ln mdev.testdir/dev | $FILTER_LS" \
@@ -46,11 +49,13 @@ testing "mdev stops on first rule" \
46brw-rw-rw- 1 1 1 8,0 sda 49brw-rw-rw- 1 1 1 8,0 sda
47" \ 50" \
48 "" "" 51 "" ""
52SKIP=
49 53
50# continuing to use directory structure from prev test 54# continuing to use directory structure from prev test
51rm -rf mdev.testdir/dev/* 55rm -rf mdev.testdir/dev/*
52echo "-.* 1:1 666" >mdev.testdir/etc/mdev.conf 56echo "-.* 1:1 666" >mdev.testdir/etc/mdev.conf
53echo "sda 2:2 444" >>mdev.testdir/etc/mdev.conf 57echo "sda 2:2 444" >>mdev.testdir/etc/mdev.conf
58optional STATIC FEATURE_MDEV_CONF FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME
54testing "mdev does not stop on dash-rule" \ 59testing "mdev does not stop on dash-rule" \
55 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; 60 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
56 ls -ln mdev.testdir/dev | $FILTER_LS" \ 61 ls -ln mdev.testdir/dev | $FILTER_LS" \
@@ -58,12 +63,14 @@ testing "mdev does not stop on dash-rule" \
58br--r--r-- 1 2 2 8,0 sda 63br--r--r-- 1 2 2 8,0 sda
59" \ 64" \
60 "" "" 65 "" ""
66SKIP=
61 67
62# continuing to use directory structure from prev test 68# continuing to use directory structure from prev test
63rm -rf mdev.testdir/dev/* 69rm -rf mdev.testdir/dev/*
64echo "\$MODALIAS=qw 1:1 666" >mdev.testdir/etc/mdev.conf 70echo "\$MODALIAS=qw 1:1 666" >mdev.testdir/etc/mdev.conf
65echo "\$MODALIAS=qw. 2:2 444" >>mdev.testdir/etc/mdev.conf 71echo "\$MODALIAS=qw. 2:2 444" >>mdev.testdir/etc/mdev.conf
66echo "\$MODALIAS=qw. 3:3 400" >>mdev.testdir/etc/mdev.conf 72echo "\$MODALIAS=qw. 3:3 400" >>mdev.testdir/etc/mdev.conf
73optional STATIC FEATURE_MDEV_CONF FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME
67testing "mdev \$ENVVAR=regex match" \ 74testing "mdev \$ENVVAR=regex match" \
68 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda MODALIAS=qwe chroot mdev.testdir /mdev 2>&1; 75 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda MODALIAS=qwe chroot mdev.testdir /mdev 2>&1;
69 ls -ln mdev.testdir/dev | $FILTER_LS" \ 76 ls -ln mdev.testdir/dev | $FILTER_LS" \
@@ -71,10 +78,12 @@ testing "mdev \$ENVVAR=regex match" \
71br--r--r-- 1 2 2 8,0 sda 78br--r--r-- 1 2 2 8,0 sda
72" \ 79" \
73 "" "" 80 "" ""
81SKIP=
74 82
75# continuing to use directory structure from prev test 83# continuing to use directory structure from prev test
76rm -rf mdev.testdir/dev/* 84rm -rf mdev.testdir/dev/*
77echo "sda 0:0 444 >disk/scsiA" >mdev.testdir/etc/mdev.conf 85echo "sda 0:0 444 >disk/scsiA" >mdev.testdir/etc/mdev.conf
86optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME
78testing "mdev move/symlink rule '>bar/baz'" \ 87testing "mdev move/symlink rule '>bar/baz'" \
79 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; 88 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
80 ls -lnR mdev.testdir/dev | $FILTER_LS2" \ 89 ls -lnR mdev.testdir/dev | $FILTER_LS2" \
@@ -87,10 +96,12 @@ mdev.testdir/dev/disk:
87br--r--r-- 1 0 0 scsiA 96br--r--r-- 1 0 0 scsiA
88" \ 97" \
89 "" "" 98 "" ""
99SKIP=
90 100
91# continuing to use directory structure from prev test 101# continuing to use directory structure from prev test
92rm -rf mdev.testdir/dev/* 102rm -rf mdev.testdir/dev/*
93echo "sda 0:0 444 >disk/" >mdev.testdir/etc/mdev.conf 103echo "sda 0:0 444 >disk/" >mdev.testdir/etc/mdev.conf
104optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME
94testing "mdev move/symlink rule '>bar/'" \ 105testing "mdev move/symlink rule '>bar/'" \
95 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; 106 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
96 ls -lnR mdev.testdir/dev | $FILTER_LS2" \ 107 ls -lnR mdev.testdir/dev | $FILTER_LS2" \
@@ -103,11 +114,13 @@ mdev.testdir/dev/disk:
103br--r--r-- 1 0 0 sda 114br--r--r-- 1 0 0 sda
104" \ 115" \
105 "" "" 116 "" ""
117SKIP=
106 118
107# continuing to use directory structure from prev test 119# continuing to use directory structure from prev test
108rm -rf mdev.testdir/dev/* 120rm -rf mdev.testdir/dev/*
109# here we complicate things by having non-matching group 1 and using %0 121# here we complicate things by having non-matching group 1 and using %0
110echo "s([0-9])*d([a-z]+) 0:0 644 >sd/%2_%0" >mdev.testdir/etc/mdev.conf 122echo "s([0-9])*d([a-z]+) 0:0 644 >sd/%2_%0" >mdev.testdir/etc/mdev.conf
123optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_RENAME_REGEXP FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_LS_SORTFILES
111testing "mdev regexp substring match + replace" \ 124testing "mdev regexp substring match + replace" \
112 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; 125 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
113 ls -lnR mdev.testdir/dev | $FILTER_LS2" \ 126 ls -lnR mdev.testdir/dev | $FILTER_LS2" \
@@ -120,10 +133,12 @@ mdev.testdir/dev/sd:
120brw-r--r-- 1 0 0 a_sda 133brw-r--r-- 1 0 0 a_sda
121" \ 134" \
122 "" "" 135 "" ""
136SKIP=
123 137
124# continuing to use directory structure from prev test 138# continuing to use directory structure from prev test
125rm -rf mdev.testdir/dev/* 139rm -rf mdev.testdir/dev/*
126echo "sda 0:0 644 @echo @echo TEST" >mdev.testdir/etc/mdev.conf 140echo "sda 0:0 644 @echo @echo TEST" >mdev.testdir/etc/mdev.conf
141optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_SH_IS_ASH
127testing "mdev command" \ 142testing "mdev command" \
128 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; 143 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
129 ls -lnR mdev.testdir/dev | $FILTER_LS" \ 144 ls -lnR mdev.testdir/dev | $FILTER_LS" \
@@ -133,10 +148,12 @@ mdev.testdir/dev:
133brw-r--r-- 1 0 0 8,0 sda 148brw-r--r-- 1 0 0 8,0 sda
134" \ 149" \
135 "" "" 150 "" ""
151SKIP=
136 152
137# continuing to use directory structure from prev test 153# continuing to use directory structure from prev test
138rm -rf mdev.testdir/dev/* 154rm -rf mdev.testdir/dev/*
139echo "sda 0:0 644 =block/ @echo @echo TEST:\$MDEV" >mdev.testdir/etc/mdev.conf 155echo "sda 0:0 644 =block/ @echo @echo TEST:\$MDEV" >mdev.testdir/etc/mdev.conf
156optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_SH_IS_ASH
140testing "mdev move and command" \ 157testing "mdev move and command" \
141 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; 158 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
142 ls -lnR mdev.testdir/dev | $FILTER_LS2" \ 159 ls -lnR mdev.testdir/dev | $FILTER_LS2" \
@@ -149,10 +166,12 @@ mdev.testdir/dev/block:
149brw-r--r-- 1 0 0 sda 166brw-r--r-- 1 0 0 sda
150" \ 167" \
151 "" "" 168 "" ""
169SKIP=
152 170
153# continuing to use directory structure from prev test 171# continuing to use directory structure from prev test
154rm -rf mdev.testdir/dev/* 172rm -rf mdev.testdir/dev/*
155echo "@8,0 0:1 644" >mdev.testdir/etc/mdev.conf 173echo "@8,0 0:1 644" >mdev.testdir/etc/mdev.conf
174optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_RENAME_REGEXP FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME
156testing "mdev #maj,min and no explicit uid" \ 175testing "mdev #maj,min and no explicit uid" \
157 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; 176 "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
158 ls -lnR mdev.testdir/dev | $FILTER_LS" \ 177 ls -lnR mdev.testdir/dev | $FILTER_LS" \
@@ -161,6 +180,7 @@ mdev.testdir/dev:
161brw-r--r-- 1 0 1 8,0 sda 180brw-r--r-- 1 0 1 8,0 sda
162" \ 181" \
163 "" "" 182 "" ""
183SKIP=
164 184
165# continuing to use directory structure from prev test 185# continuing to use directory structure from prev test
166rm -rf mdev.testdir/dev/* 186rm -rf mdev.testdir/dev/*
@@ -174,6 +194,7 @@ echo "capi 0:0 0660 =capi20" >mdev.testdir/etc/mdev.conf
174echo "capi([0-9]) 0:0 0660 =capi20.0%1" >>mdev.testdir/etc/mdev.conf 194echo "capi([0-9]) 0:0 0660 =capi20.0%1" >>mdev.testdir/etc/mdev.conf
175echo "capi([0-9]*) 0:0 0660 =capi20.%1" >>mdev.testdir/etc/mdev.conf 195echo "capi([0-9]*) 0:0 0660 =capi20.%1" >>mdev.testdir/etc/mdev.conf
176# mdev invocation with DEVPATH=/class/tty/capi20 was deleting /dev/capi20 196# mdev invocation with DEVPATH=/class/tty/capi20 was deleting /dev/capi20
197optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_RENAME_REGEXP FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_LS_SORTFILES
177testing "move rule does not delete node with name == device_name" \ 198testing "move rule does not delete node with name == device_name" \
178 "\ 199 "\
179 env - PATH=$PATH ACTION=add DEVPATH=/class/tty/capi chroot mdev.testdir /mdev 2>&1; 200 env - PATH=$PATH ACTION=add DEVPATH=/class/tty/capi chroot mdev.testdir /mdev 2>&1;
@@ -187,6 +208,7 @@ crw-rw---- 1 0 0 191,1 capi20.01
187crw-rw---- 1 0 0 191,20 capi20.20 208crw-rw---- 1 0 0 191,20 capi20.20
188" \ 209" \
189 "" "" 210 "" ""
211SKIP=
190 212
191# clean up 213# clean up
192rm -rf mdev.testdir 214rm -rf mdev.testdir
diff --git a/testsuite/mount.tests b/testsuite/mount.tests
index 043586f05..3c7405fbd 100755
--- a/testsuite/mount.tests
+++ b/testsuite/mount.tests
@@ -4,19 +4,24 @@
4 4
5. ./testing.sh 5. ./testing.sh
6 6
7test -f "$bindir/.config" && . "$bindir/.config"
8
7test "`id -u`" = 0 || { 9test "`id -u`" = 0 || {
8 echo "SKIPPED: must be root to test this" 10 echo "SKIPPED: mount (must be root to test this)"
9 exit 0 11 exit 0
10} 12}
11 13
12optional MKFS_MINIX 14if test x"$CONFIG_MKFS_MINIX" != x"y" \
13if [ -n "$SKIP" ] 15|| test x"$CONFIG_FEATURE_MINIX2" != x"y" \
14then 16|| test x"$CONFIG_FEATURE_MOUNT_LOOP" != x"y" \
15 echo "SKIPPED: mount" 17|| test x"$CONFIG_FEATURE_MOUNT_FLAGS" != x"y" \
16 exit 0 18|| test x"$CONFIG_FEATURE_DEVFS" = x"y" \
19; then
20 echo "SKIPPED: mount"
21 exit 0
17fi 22fi
18 23
19testdir=$PWD/testdir 24testdir=$PWD/mount.testdir
20 25
21dd if=/dev/zero of=mount.image1m count=1 bs=1M 2>/dev/null || { echo "dd error"; exit 1; } 26dd if=/dev/zero of=mount.image1m count=1 bs=1M 2>/dev/null || { echo "dd error"; exit 1; }
22mkfs.minix -v mount.image1m >/dev/null 2>&1 || { echo "mkfs.minix error"; exit 1; } 27mkfs.minix -v mount.image1m >/dev/null 2>&1 || { echo "mkfs.minix error"; exit 1; }
diff --git a/testsuite/od.tests b/testsuite/od.tests
index 0bf1f4c54..a2d015ad7 100755
--- a/testsuite/od.tests
+++ b/testsuite/od.tests
@@ -6,6 +6,7 @@
6 6
7# testing "test name" "options" "expected result" "file input" "stdin" 7# testing "test name" "options" "expected result" "file input" "stdin"
8 8
9optional DESKTOP
9testing "od -b" \ 10testing "od -b" \
10 "od -b" \ 11 "od -b" \
11"\ 12"\
@@ -13,5 +14,6 @@ testing "od -b" \
130000005 140000005
14" \ 15" \
15 "" "HELLO" 16 "" "HELLO"
17SKIP=
16 18
17exit $FAILCOUNT 19exit $FAILCOUNT
diff --git a/testsuite/patch.tests b/testsuite/patch.tests
index f3e607186..749d936ea 100755
--- a/testsuite/patch.tests
+++ b/testsuite/patch.tests
@@ -123,4 +123,6 @@ abc
123+456 123+456
124" \ 124" \
125 125
126rm input.orig 2>/dev/null
127
126exit $FAILCOUNT 128exit $FAILCOUNT
diff --git a/testsuite/pidof.tests b/testsuite/pidof.tests
index 45df1a958..624b0a720 100755
--- a/testsuite/pidof.tests
+++ b/testsuite/pidof.tests
@@ -20,12 +20,14 @@ testing "pidof this" "pidof pidof.tests | grep -o -w $$" "$$\n" "" ""
20 20
21optional FEATURE_PIDOF_SINGLE 21optional FEATURE_PIDOF_SINGLE
22testing "pidof -s" "pidof -s init" "1\n" "" "" 22testing "pidof -s" "pidof -s init" "1\n" "" ""
23SKIP=
23 24
24optional FEATURE_PIDOF_OMIT 25optional FEATURE_PIDOF_OMIT FEATURE_PIDOF_SINGLE
25# This test fails now because process name matching logic has changed, 26# This test fails now because process name matching logic has changed,
26# but new logic is not "wrong" either... see find_pid_by_name.c comments 27# but new logic is not "wrong" either... see find_pid_by_name.c comments
27#testing "pidof -o %PPID" "pidof -o %PPID pidof.tests | grep -o -w $$" "" "" "" 28#testing "pidof -o %PPID" "pidof -o %PPID pidof.tests | grep -o -w $$" "" "" ""
28testing "pidof -o %PPID NOP" "pidof -o %PPID -s init" "1\n" "" "" 29testing "pidof -o %PPID NOP" "pidof -o %PPID -s init" "1\n" "" ""
29testing "pidof -o init" "pidof -o 1 init | grep -o -w 1" "" "" "" 30testing "pidof -o init" "pidof -o 1 init | grep -o -w 1" "" "" ""
31SKIP=
30 32
31exit $FAILCOUNT 33exit $FAILCOUNT
diff --git a/testsuite/rx.tests b/testsuite/rx.tests
index c2b8814a2..985fcdc01 100755
--- a/testsuite/rx.tests
+++ b/testsuite/rx.tests
@@ -18,9 +18,9 @@ testing "rx" \
1800000000 43 06 06 |C..|\n\ 1800000000 43 06 06 |C..|\n\
1900000003\n\ 1900000003\n\
20???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????" \ 20???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????" \
21 "" "\1\1\376\ 21 "" "\01\01\0376\
22???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????\ 22???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????\
23\x1A\x1A\x1A\x1A\x1A\x4B\xB0\4" 23\x1A\x1A\x1A\x1A\x1A\x4B\xB0\04"
24 24
25rm -f rx.OUTFILE 2>/dev/null 25rm -f rx.OUTFILE 2>/dev/null
26 26
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index 875c946be..88b9c4e4b 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -110,7 +110,7 @@ testing "sed embedded NUL" "sed -e 's/woo/bang/'" "\0bang\0woo\0" "" \
110testing "sed embedded NUL g" "sed -e 's/woo/bang/g'" "bang\0bang\0" "" \ 110testing "sed embedded NUL g" "sed -e 's/woo/bang/g'" "bang\0bang\0" "" \
111 "woo\0woo\0" 111 "woo\0woo\0"
112test x"$SKIP_KNOWN_BUGS" = x"" && { 112test x"$SKIP_KNOWN_BUGS" = x"" && {
113echo -e "/woo/a he\0llo" > sed.commands 113$ECHO -e "/woo/a he\0llo" > sed.commands
114testing "sed NUL in command" "sed -f sed.commands" "woo\nhe\0llo\n" "" "woo" 114testing "sed NUL in command" "sed -f sed.commands" "woo\nhe\0llo\n" "" "woo"
115rm sed.commands 115rm sed.commands
116} 116}
@@ -153,7 +153,7 @@ testing "sed clusternewline" \
153 "one\none\n111\n222\ntwo\ntwo" "one" "two" 153 "one\none\n111\n222\ntwo\ntwo" "one" "two"
154} 154}
155testing "sed subst+write" \ 155testing "sed subst+write" \
156 "sed -e 's/i/z/' -e 'woutputw' input -; echo -n X; cat outputw" \ 156 "sed -e 's/i/z/' -e 'woutputw' input -; $ECHO -n X; cat outputw" \
157 "thzngy\nagaznXthzngy\nagazn" "thingy" "again" 157 "thzngy\nagaznXthzngy\nagazn" "thingy" "again"
158rm outputw 158rm outputw
159testing "sed trailing NUL" \ 159testing "sed trailing NUL" \
@@ -248,4 +248,28 @@ testing "sed beginning (^) matches only once" \
248 ">/usr</>lib<\n" "" \ 248 ">/usr</>lib<\n" "" \
249 "/usr/lib\n" 249 "/usr/lib\n"
250 250
251testing "sed c" \
252 "sed 'crepl'" \
253 "repl\nrepl\n" "" \
254 "first\nsecond\n"
255
256testing "sed nested {}s" \
257 "sed '/asd/ { p; /s/ { s/s/c/ }; p; q }'" \
258 "qwe\nasd\nacd\nacd\n" "" \
259 "qwe\nasd\nzxc\n"
260
261testing "sed a cmd ended by double backslash" \
262 "sed -e '/| one /a \\
263 | three \\\\' -e '/| one-/a \\
264 | three-* \\\\'" \
265' | one \\
266 | three \\
267 | two \\
268' '' \
269' | one \\
270 | two \\
271'
272
273# testing "description" "arguments" "result" "infile" "stdin"
274
251exit $FAILCOUNT 275exit $FAILCOUNT
diff --git a/testsuite/sort.tests b/testsuite/sort.tests
index 72df80b1f..8a810f8d4 100755
--- a/testsuite/sort.tests
+++ b/testsuite/sort.tests
@@ -118,7 +118,7 @@ testing "sort key doesn't strip leading blanks, disables fallback global sort" \
118"sort -n -k2 -t ' '" " a \n 1 \n 2 \n" "" " 2 \n 1 \n a \n" 118"sort -n -k2 -t ' '" " a \n 1 \n 2 \n" "" " 2 \n 1 \n a \n"
119 119
120testing "sort file in place" \ 120testing "sort file in place" \
121"strace -oZZZ sort -o input input && cat input" "\ 121"sort -o input input && cat input" "\
122111 122111
123222 123222
124" "\ 124" "\
diff --git a/testsuite/tail/tail-works b/testsuite/tail/tail-works
index f3434d1a9..50eca136e 100644
--- a/testsuite/tail/tail-works
+++ b/testsuite/tail/tail-works
@@ -1,3 +1,5 @@
1# FEATURE: CONFIG_INCLUDE_SUSv2
2
1$ECHO -ne "abc\ndef\n123\n" >input 3$ECHO -ne "abc\ndef\n123\n" >input
2$ECHO -ne "def\n123\n" >logfile.ok 4$ECHO -ne "def\n123\n" >logfile.ok
3busybox tail -2 input > logfile.bb 5busybox tail -2 input > logfile.bb
diff --git a/testsuite/tar.tests b/testsuite/tar.tests
index a96382932..f40079037 100755
--- a/testsuite/tar.tests
+++ b/testsuite/tar.tests
@@ -9,6 +9,7 @@ mkdir tar.tempdir && cd tar.tempdir || exit 1
9 9
10# testing "test name" "script" "expected result" "file input" "stdin" 10# testing "test name" "script" "expected result" "file input" "stdin"
11 11
12optional FEATURE_TAR_CREATE FEATURE_LS_SORTFILES
12testing "tar hardlinks and repeated files" '\ 13testing "tar hardlinks and repeated files" '\
13rm -rf input_* test.tar 2>/dev/null 14rm -rf input_* test.tar 2>/dev/null
14>input_hard1 15>input_hard1
@@ -39,7 +40,9 @@ drwxr-xr-x input_dir
39-rw-r--r-- input_hard2 40-rw-r--r-- input_hard2
40" \ 41" \
41"" "" 42"" ""
43SKIP=
42 44
45optional FEATURE_TAR_CREATE FEATURE_LS_SORTFILES
43testing "tar hardlinks mode" '\ 46testing "tar hardlinks mode" '\
44rm -rf input_* test.tar 2>/dev/null 47rm -rf input_* test.tar 2>/dev/null
45>input_hard1 48>input_hard1
@@ -68,7 +71,9 @@ dr-xr-x--- input_dir
68-rwxr----x input_hard2 71-rwxr----x input_hard2
69" \ 72" \
70"" "" 73"" ""
74SKIP=
71 75
76optional FEATURE_TAR_CREATE FEATURE_LS_SORTFILES
72testing "tar symlinks mode" '\ 77testing "tar symlinks mode" '\
73rm -rf input_* test.tar 2>/dev/null 78rm -rf input_* test.tar 2>/dev/null
74>input_file 79>input_file
@@ -79,7 +84,7 @@ chmod 550 input_dir
79ln input_file input_dir 84ln input_file input_dir
80ln input_soft input_dir 85ln input_soft input_dir
81tar cf test.tar input_* 86tar cf test.tar input_*
82tar tvf test.tar | sed "s/.*[0-9] input/input/" 87tar tvf test.tar | sed "s/.*[0-9] input/input/" | sort
83tar xf test.tar 2>&1 88tar xf test.tar 2>&1
84echo Ok: $? 89echo Ok: $?
85ls -l . input_dir/* | grep input_ | sed "s/\\(^[^ ]*\\) .* input/\\1 input/" 90ls -l . input_dir/* | grep input_ | sed "s/\\(^[^ ]*\\) .* input/\\1 input/"
@@ -97,8 +102,9 @@ dr-xr-x--- input_dir
97lrwxrwxrwx input_file 102lrwxrwxrwx input_file
98" \ 103" \
99"" "" 104"" ""
105SKIP=
100 106
101optional FEATURE_TAR_LONG_OPTIONS 107optional FEATURE_TAR_CREATE FEATURE_TAR_LONG_OPTIONS
102testing "tar --overwrite" "\ 108testing "tar --overwrite" "\
103rm -rf input_* test.tar 2>/dev/null 109rm -rf input_* test.tar 2>/dev/null
104ln input input_hard 110ln input input_hard
diff --git a/testsuite/tar/tar_with_link_with_size b/testsuite/tar/tar_with_link_with_size
index 5b61cc70b..774cd5698 100644
--- a/testsuite/tar/tar_with_link_with_size
+++ b/testsuite/tar/tar_with_link_with_size
@@ -1,3 +1,5 @@
1# FEATURE: CONFIG_FEATURE_TAR_UNAME_GNAME
2
1# This tarball contains a softlink with size field != 0. 3# This tarball contains a softlink with size field != 0.
2# If not ignored, it makes hext header to be skipped 4# If not ignored, it makes hext header to be skipped
3# and data to be read as a header. 5# and data to be read as a header.
diff --git a/testsuite/tar/tar_with_prefix_fields b/testsuite/tar/tar_with_prefix_fields
index 1c7124d52..8c1fda795 100644
--- a/testsuite/tar/tar_with_prefix_fields
+++ b/testsuite/tar/tar_with_prefix_fields
@@ -1,3 +1,6 @@
1# FEATURE: CONFIG_FEATURE_TAR_UNAME_GNAME
2# FEATURE: CONFIG_DESKTOP
3
1tar1_bz2() 4tar1_bz2()
2{ 5{
3 $ECHO -ne "\x42\x5a\x68\x39\x31\x41\x59\x26\x53\x59\x12\xd1\x86\x30\x00\x0c" 6 $ECHO -ne "\x42\x5a\x68\x39\x31\x41\x59\x26\x53\x59\x12\xd1\x86\x30\x00\x0c"
diff --git a/testsuite/testing.sh b/testsuite/testing.sh
index 22c640faf..913d7f8ef 100755..100644
--- a/testsuite/testing.sh
+++ b/testsuite/testing.sh
@@ -54,14 +54,14 @@ test x"$ECHO" != x"" || {
54 54
55optional() 55optional()
56{ 56{
57 option=`echo ":$OPTIONFLAGS:" | grep ":$1:"` 57 SKIP=
58 # Not set? 58 while test "$1"; do
59 if [ -z "$1" ] || [ -z "$OPTIONFLAGS" ] || [ ${#option} -ne 0 ] 59 if test x"${OPTIONFLAGS/*:$1:*/y}" != x"y"; then
60 then 60 SKIP=1
61 SKIP= 61 return
62 return 62 fi
63 fi 63 shift
64 SKIP=1 64 done
65} 65}
66 66
67# The testing function 67# The testing function
@@ -73,7 +73,7 @@ testing()
73 73
74 if [ $# -ne 5 ] 74 if [ $# -ne 5 ]
75 then 75 then
76 echo "Test $NAME has wrong number of arguments (must be 5) ($# $*)" >&2 76 echo "Test $NAME has wrong number of arguments: $# (must be 5)" >&2
77 exit 1 77 exit 1
78 fi 78 fi
79 79
diff --git a/testsuite/tr.tests b/testsuite/tr.tests
index 9706056c9..a1f83bfc6 100755
--- a/testsuite/tr.tests
+++ b/testsuite/tr.tests
@@ -15,17 +15,23 @@ testing "tr understands 0-9A-F" \
15 "tr -cd '[0-9A-F]'" \ 15 "tr -cd '[0-9A-F]'" \
16 "19AF" "" "19AFH\n" 16 "19AF" "" "19AFH\n"
17 17
18optional CONFIG_FEATURE_TR_CLASSES
18testing "tr understands [:xdigit:]" \ 19testing "tr understands [:xdigit:]" \
19 "tr -cd '[:xdigit:]'" \ 20 "tr -cd '[:xdigit:]'" \
20 "19AF" "" "19AFH\n" 21 "19AF" "" "19AFH\n"
22SKIP=
21 23
24optional CONFIG_FEATURE_TR_CLASSES
22testing "tr does not stop after [:digit:]" \ 25testing "tr does not stop after [:digit:]" \
23 "tr '[:digit:]y-z' 111111111123" \ 26 "tr '[:digit:]y-z' 111111111123" \
24 "111abcx23\n" "" "789abcxyz\n" 27 "111abcx23\n" "" "789abcxyz\n"
28SKIP=
25 29
30optional CONFIG_FEATURE_TR_CLASSES
26testing "tr has correct xdigit sequence" \ 31testing "tr has correct xdigit sequence" \
27 "tr '[:xdigit:]Gg' 1111111151242222333330xX" \ 32 "tr '[:xdigit:]Gg' 1111111151242222333330xX" \
28 "#1111111151242222x333330X\n" "" \ 33 "#1111111151242222x333330X\n" "" \
29 "#0123456789ABCDEFGabcdefg\n" 34 "#0123456789ABCDEFGabcdefg\n"
35SKIP=
30 36
31exit $FAILCOUNT 37exit $FAILCOUNT
diff --git a/testsuite/tr/tr-d-alnum-works b/testsuite/tr/tr-d-alnum-works
index d440f8f3b..6540ea527 100644
--- a/testsuite/tr/tr-d-alnum-works
+++ b/testsuite/tr/tr-d-alnum-works
@@ -1,3 +1,5 @@
1# FEATURE: CONFIG_FEATURE_TR_CLASSES
2
1echo testing | tr -d '[[:alnum:]]' > logfile.gnu 3echo testing | tr -d '[[:alnum:]]' > logfile.gnu
2echo testing | busybox tr -d '[[:alnum:]]' > logfile.bb 4echo testing | busybox tr -d '[[:alnum:]]' > logfile.bb
3 5
diff --git a/testsuite/tr/tr-rejects-wrong-class b/testsuite/tr/tr-rejects-wrong-class
index 97539360d..1d488a3df 100644
--- a/testsuite/tr/tr-rejects-wrong-class
+++ b/testsuite/tr/tr-rejects-wrong-class
@@ -1,3 +1,5 @@
1# FEATURE: CONFIG_FEATURE_TR_CLASSES
2
1echo t12esting | tr -d '[[:alpha:]]' > logfile.gnu 3echo t12esting | tr -d '[[:alpha:]]' > logfile.gnu
2echo t12esting | tr -d '[:alpha:]' >> logfile.gnu 4echo t12esting | tr -d '[:alpha:]' >> logfile.gnu
3echo t12esting | tr -d '[[:alpha:]' >> logfile.gnu 5echo t12esting | tr -d '[[:alpha:]' >> logfile.gnu
diff --git a/testsuite/tr/tr-works b/testsuite/tr/tr-works
index 2c0a9d196..5e4a30ee4 100644
--- a/testsuite/tr/tr-works
+++ b/testsuite/tr/tr-works
@@ -1,6 +1,8 @@
1# FEATURE: CONFIG_FEATURE_TR_CLASSES
2
1run_tr () 3run_tr ()
2{ 4{
3 echo -n "echo '$1' | tr '$2' '$3': " 5 $ECHO -n "echo '$1' | tr '$2' '$3': "
4 echo "$1" | $bb tr "$2" "$3" 6 echo "$1" | $bb tr "$2" "$3"
5 echo 7 echo
6} 8}
diff --git a/testsuite/unexpand.tests b/testsuite/unexpand.tests
index 1af2fdc5f..a48e3214e 100755
--- a/testsuite/unexpand.tests
+++ b/testsuite/unexpand.tests
@@ -30,7 +30,9 @@ testing "unexpand case 7" "unexpand" \
30testing "unexpand case 8" "unexpand" \ 30testing "unexpand case 8" "unexpand" \
31 "a b\n" "" "a b\n" \ 31 "a b\n" "" "a b\n" \
32 32
33optional UNICODE_SUPPORT
33testing "unexpand with unicode characher 0x394" "unexpand" \ 34testing "unexpand with unicode characher 0x394" "unexpand" \
34 "1ΔΔΔ5\t99999\n" "" "1ΔΔΔ5 99999\n" \ 35 "1ΔΔΔ5\t99999\n" "" "1ΔΔΔ5 99999\n"
36SKIP=
35 37
36exit $FAILCOUNT 38exit $FAILCOUNT
diff --git a/util-linux/Kbuild b/util-linux/Kbuild
index 99e3efea3..4fa392398 100644
--- a/util-linux/Kbuild
+++ b/util-linux/Kbuild
@@ -42,5 +42,4 @@ lib-$(CONFIG_SCRIPTREPLAY) += scriptreplay.o
42lib-$(CONFIG_SETARCH) += setarch.o 42lib-$(CONFIG_SETARCH) += setarch.o
43lib-$(CONFIG_SWAPONOFF) += swaponoff.o 43lib-$(CONFIG_SWAPONOFF) += swaponoff.o
44lib-$(CONFIG_SWITCH_ROOT) += switch_root.o 44lib-$(CONFIG_SWITCH_ROOT) += switch_root.o
45lib-$(CONFIG_MKFS_EXT2) += tune2fs.o
46lib-$(CONFIG_UMOUNT) += umount.o 45lib-$(CONFIG_UMOUNT) += umount.o
diff --git a/util-linux/mkfs_ext2.c b/util-linux/mkfs_ext2.c
index cf40c20eb..fd54734fc 100644
--- a/util-linux/mkfs_ext2.c
+++ b/util-linux/mkfs_ext2.c
@@ -10,7 +10,6 @@
10#include "libbb.h" 10#include "libbb.h"
11#include <linux/fs.h> 11#include <linux/fs.h>
12#include <linux/ext2_fs.h> 12#include <linux/ext2_fs.h>
13#include "volume_id/volume_id_internal.h"
14 13
15#define ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT 0 14#define ENABLE_FEATURE_MKFS_EXT2_RESERVED_GDT 0
16#define ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX 1 15#define ENABLE_FEATURE_MKFS_EXT2_DIR_INDEX 1
@@ -29,9 +28,9 @@ char BUG_wrong_field_size(void);
29#define STORE_LE(field, value) \ 28#define STORE_LE(field, value) \
30do { \ 29do { \
31 if (sizeof(field) == 4) \ 30 if (sizeof(field) == 4) \
32 field = cpu_to_le32(value); \ 31 field = SWAP_LE32(value); \
33 else if (sizeof(field) == 2) \ 32 else if (sizeof(field) == 2) \
34 field = cpu_to_le16(value); \ 33 field = SWAP_LE16(value); \
35 else if (sizeof(field) == 1) \ 34 else if (sizeof(field) == 1) \
36 field = (value); \ 35 field = (value); \
37 else \ 36 else \
@@ -39,7 +38,7 @@ do { \
39} while (0) 38} while (0)
40 39
41#define FETCH_LE32(field) \ 40#define FETCH_LE32(field) \
42 (sizeof(field) == 4 ? cpu_to_le32(field) : BUG_wrong_field_size()) 41 (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size())
43 42
44// All fields are little-endian 43// All fields are little-endian
45struct ext2_dir { 44struct ext2_dir {
diff --git a/util-linux/mkfs_reiser.c b/util-linux/mkfs_reiser.c
index eb2c94d02..f9a0ca82a 100644
--- a/util-linux/mkfs_reiser.c
+++ b/util-linux/mkfs_reiser.c
@@ -8,15 +8,14 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10#include <linux/fs.h> 10#include <linux/fs.h>
11#include "volume_id/volume_id_internal.h"
12 11
13char BUG_wrong_field_size(void); 12char BUG_wrong_field_size(void);
14#define STORE_LE(field, value) \ 13#define STORE_LE(field, value) \
15do { \ 14do { \
16 if (sizeof(field) == 4) \ 15 if (sizeof(field) == 4) \
17 field = cpu_to_le32(value); \ 16 field = SWAP_LE32(value); \
18 else if (sizeof(field) == 2) \ 17 else if (sizeof(field) == 2) \
19 field = cpu_to_le16(value); \ 18 field = SWAP_LE16(value); \
20 else if (sizeof(field) == 1) \ 19 else if (sizeof(field) == 1) \
21 field = (value); \ 20 field = (value); \
22 else \ 21 else \
@@ -24,7 +23,7 @@ do { \
24} while (0) 23} while (0)
25 24
26#define FETCH_LE32(field) \ 25#define FETCH_LE32(field) \
27 (sizeof(field) == 4 ? cpu_to_le32(field) : BUG_wrong_field_size()) 26 (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size())
28 27
29struct journal_params { 28struct journal_params {
30 uint32_t jp_journal_1st_block; /* where does journal start from on its device */ 29 uint32_t jp_journal_1st_block; /* where does journal start from on its device */
diff --git a/util-linux/mkfs_vfat.c b/util-linux/mkfs_vfat.c
index 1363612f2..ff3e4165a 100644
--- a/util-linux/mkfs_vfat.c
+++ b/util-linux/mkfs_vfat.c
@@ -16,7 +16,6 @@
16# define BLKSSZGET _IO(0x12, 104) 16# define BLKSSZGET _IO(0x12, 104)
17#endif 17#endif
18//#include <linux/msdos_fs.h> 18//#include <linux/msdos_fs.h>
19#include "volume_id/volume_id_internal.h"
20 19
21#define SECTOR_SIZE 512 20#define SECTOR_SIZE 512
22 21
@@ -168,15 +167,15 @@ static const char boot_code[] ALIGN1 =
168 167
169 168
170#define MARK_CLUSTER(cluster, value) \ 169#define MARK_CLUSTER(cluster, value) \
171 ((uint32_t *)fat)[cluster] = cpu_to_le32(value) 170 ((uint32_t *)fat)[cluster] = SWAP_LE32(value)
172 171
173void BUG_unsupported_field_size(void); 172void BUG_unsupported_field_size(void);
174#define STORE_LE(field, value) \ 173#define STORE_LE(field, value) \
175do { \ 174do { \
176 if (sizeof(field) == 4) \ 175 if (sizeof(field) == 4) \
177 field = cpu_to_le32(value); \ 176 field = SWAP_LE32(value); \
178 else if (sizeof(field) == 2) \ 177 else if (sizeof(field) == 2) \
179 field = cpu_to_le16(value); \ 178 field = SWAP_LE16(value); \
180 else if (sizeof(field) == 1) \ 179 else if (sizeof(field) == 1) \
181 field = (value); \ 180 field = (value); \
182 else \ 181 else \
diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c
index f647a32bc..f2f52fb88 100644
--- a/util-linux/swaponoff.c
+++ b/util-linux/swaponoff.c
@@ -66,11 +66,20 @@ static int do_em_all(void)
66 bb_perror_msg_and_die("/etc/fstab"); 66 bb_perror_msg_and_die("/etc/fstab");
67 67
68 err = 0; 68 err = 0;
69 while ((m = getmntent(f)) != NULL) 69 while ((m = getmntent(f)) != NULL) {
70 if (strcmp(m->mnt_type, MNTTYPE_SWAP) == 0) 70 if (strcmp(m->mnt_type, MNTTYPE_SWAP) == 0) {
71 err += swap_enable_disable(m->mnt_fsname); 71 /* swapon -a should ignore entries with noauto,
72 * but swapoff -a should process them */
73 if (applet_name[5] != 'n'
74 || hasmntopt(m, MNTOPT_NOAUTO) == NULL
75 ) {
76 err += swap_enable_disable(m->mnt_fsname);
77 }
78 }
79 }
72 80
73 endmntent(f); 81 if (ENABLE_FEATURE_CLEAN_UP)
82 endmntent(f);
74 83
75 return err; 84 return err;
76} 85}