aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2011-01-04 19:40:30 +0700
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2011-01-04 19:40:30 +0700
commit3b5c308768d76298bb964814ecc34de47bcac0b4 (patch)
tree795340e9d8f5e5bf9e8d895641099af343eec2a0
parent2b9a0e715ec459198f486653023d963b79291da7 (diff)
parent5fe2f863b9cee5ab0e7ac873538bce48846dbad8 (diff)
downloadbusybox-w32-3b5c308768d76298bb964814ecc34de47bcac0b4.tar.gz
busybox-w32-3b5c308768d76298bb964814ecc34de47bcac0b4.tar.bz2
busybox-w32-3b5c308768d76298bb964814ecc34de47bcac0b4.zip
Merge commit '06f719fd79fe15ce6fd5431bc58fcb22851de24d^'
-rw-r--r--Config.in61
-rwxr-xr-xapplets/usage_compressed7
-rw-r--r--archival/bbunzip.c2
-rw-r--r--archival/cpio.c2
-rw-r--r--archival/dpkg.c4
-rw-r--r--archival/libunarchive/data_extract_all.c4
-rw-r--r--coreutils/cksum.c2
-rw-r--r--coreutils/date.c106
-rw-r--r--coreutils/dos2unix.c2
-rw-r--r--coreutils/fold.c2
-rw-r--r--coreutils/head.c2
-rw-r--r--coreutils/id.c2
-rw-r--r--coreutils/md5_sha1_sum.c8
-rw-r--r--coreutils/mkfifo.c2
-rw-r--r--coreutils/mknod.c2
-rw-r--r--coreutils/printenv.c2
-rw-r--r--coreutils/seq.c3
-rw-r--r--coreutils/sleep.c21
-rw-r--r--coreutils/sort.c2
-rw-r--r--coreutils/tee.c2
-rw-r--r--coreutils/uniq.c4
-rw-r--r--coreutils/uudecode.c73
-rw-r--r--coreutils/wc.c79
-rw-r--r--docs/busybox_footer.pod30
-rw-r--r--docs/contributing.txt53
-rw-r--r--e2fsprogs/tune2fs.c40
-rw-r--r--editors/awk.c132
-rw-r--r--editors/patch.c14
-rw-r--r--editors/patch_toybox.c4
-rw-r--r--findutils/.gitignore3
-rw-r--r--findutils/grep.c15
-rw-r--r--include/applets.src.h54
-rw-r--r--include/busybox.h7
-rw-r--r--include/libbb.h27
-rw-r--r--include/platform.h4
-rw-r--r--include/usage.src.h406
-rw-r--r--init/Config.src127
-rw-r--r--init/Kbuild.src4
-rw-r--r--init/bootchartd.c4
-rw-r--r--init/halt.c62
-rw-r--r--init/init.c231
-rw-r--r--init/mesg.c18
-rw-r--r--libbb/appletlib.c8
-rw-r--r--libbb/md5.c245
-rw-r--r--libbb/procps.c2
-rw-r--r--libbb/pw_encrypt_md5.c32
-rw-r--r--libbb/sha1.c204
-rw-r--r--libbb/uuencode.c76
-rw-r--r--libbb/xfuncs_printf.c2
-rw-r--r--loginutils/Config.src84
-rw-r--r--loginutils/deluser.c52
-rw-r--r--mailutils/mail.c72
-rw-r--r--mailutils/mail.h1
-rw-r--r--mailutils/mime.c4
-rw-r--r--mailutils/popmaildir.c6
-rw-r--r--mailutils/sendmail.c8
-rw-r--r--miscutils/Config.src1
-rw-r--r--miscutils/man.c9
-rw-r--r--miscutils/nandwrite.c155
-rw-r--r--modutils/depmod.c16
-rw-r--r--modutils/insmod.c6
-rw-r--r--modutils/lsmod.c10
-rw-r--r--modutils/modprobe-small.c75
-rw-r--r--modutils/modprobe.c25
-rw-r--r--modutils/rmmod.c15
-rw-r--r--networking/Config.src2
-rw-r--r--networking/nbd-client.c153
-rw-r--r--networking/nc_bloaty.c3
-rw-r--r--networking/ntpd.c13
-rw-r--r--networking/udhcp/common.c4
-rw-r--r--networking/udhcp/common.h2
-rw-r--r--networking/udhcp/dhcpc.c17
-rw-r--r--networking/udhcp/dhcprelay.c189
-rw-r--r--procps/free.c98
-rw-r--r--runit/Kbuild.src8
-rw-r--r--runit/runit_lib.c275
-rw-r--r--runit/runit_lib.h53
-rw-r--r--runit/runsv.c6
-rw-r--r--runit/runsvdir.c2
-rw-r--r--runit/sv.c11
-rw-r--r--runit/svlogd.c50
-rw-r--r--shell/ash.c45
-rw-r--r--shell/ash_test/ash-arith/arith.right56
-rw-r--r--shell/ash_test/ash-signals/signal8.right3
-rwxr-xr-xshell/ash_test/ash-signals/signal8.tests18
-rw-r--r--shell/ash_test/ash-signals/signal9.right3
-rwxr-xr-xshell/ash_test/ash-signals/signal9.tests21
-rw-r--r--shell/hush.c183
-rw-r--r--shell/hush_test/hush-arith/arith.right54
-rw-r--r--shell/hush_test/hush-glob/bash_brace1.right4
-rwxr-xr-xshell/hush_test/hush-glob/bash_brace1.tests10
-rw-r--r--shell/math.c684
-rw-r--r--shell/math.h96
-rwxr-xr-xtestsuite/awk.tests6
-rwxr-xr-xtestsuite/cpio.tests10
-rwxr-xr-xtestsuite/gunzip.tests2
-rwxr-xr-xtestsuite/md5sum.tests38
-rwxr-xr-xtestsuite/sha1sum.tests3
-rwxr-xr-xtestsuite/sha256sum.tests3
-rwxr-xr-xtestsuite/sha512sum.tests3
-rw-r--r--util-linux/acpid.c306
101 files changed, 2872 insertions, 2299 deletions
diff --git a/Config.in b/Config.in
index d2e64a08d..273f2de38 100644
--- a/Config.in
+++ b/Config.in
@@ -146,6 +146,14 @@ config FEATURE_INSTALLER
146 busybox at runtime to create hard links or symlinks for all the 146 busybox at runtime to create hard links or symlinks for all the
147 applets that are compiled into busybox. 147 applets that are compiled into busybox.
148 148
149config INSTALL_NO_USR
150 bool "Don't use /usr"
151 default n
152 depends on FEATURE_INSTALLER
153 help
154 Disable use of /usr. busybox --install will install applets
155 only to /bin and /sbin, never to /usr/bin or /usr/sbin.
156
149config LOCALE_SUPPORT 157config LOCALE_SUPPORT
150 bool "Enable locale support (system needs locale for this to work)" 158 bool "Enable locale support (system needs locale for this to work)"
151 default n 159 default n
@@ -298,15 +306,6 @@ config FEATURE_CLEAN_UP
298 Don't enable this unless you have a really good reason to clean 306 Don't enable this unless you have a really good reason to clean
299 things up manually. 307 things up manually.
300 308
301config FEATURE_UTMP
302 bool "Support utmp file"
303 default y
304 help
305 The file /var/run/utmp is used to track who is currently logged in.
306 With this option on, certain applets (getty, login, telnetd etc)
307 will create and delete entries there.
308 "who" applet requires this option.
309
310config FEATURE_WTMP 309config FEATURE_WTMP
311 bool "Support wtmp file" 310 bool "Support wtmp file"
312 default y 311 default y
@@ -318,6 +317,15 @@ config FEATURE_WTMP
318 will append new entries there. 317 will append new entries there.
319 "last" applet requires this option. 318 "last" applet requires this option.
320 319
320config FEATURE_UTMP
321 bool "Support utmp file"
322 default y
323 help
324 The file /var/run/utmp is used to track who is currently logged in.
325 With this option on, certain applets (getty, login, telnetd etc)
326 will create and delete entries there.
327 "who" applet requires this option.
328
321config FEATURE_PIDFILE 329config FEATURE_PIDFILE
322 bool "Support writing pidfiles" 330 bool "Support writing pidfiles"
323 default y 331 default y
@@ -330,14 +338,19 @@ config FEATURE_SUID
330 default y 338 default y
331 help 339 help
332 With this option you can install the busybox binary belonging 340 With this option you can install the busybox binary belonging
333 to root with the suid bit set, and it will automatically drop 341 to root with the suid bit set, enabling some applets to perform
334 priviledges for applets that don't need root access. 342 root-level operations even when run by ordinary users
343 (for example, mounting of user mounts in fstab needs this).
344
345 Busybox will automatically drop priviledges for applets
346 that don't need root access.
335 347
336 If you are really paranoid and don't want to do this, build two 348 If you are really paranoid and don't want to do this, build two
337 busybox binaries with different applets in them (and the appropriate 349 busybox binaries with different applets in them (and the appropriate
338 symlinks pointing to each binary), and only set the suid bit on the 350 symlinks pointing to each binary), and only set the suid bit on the
339 one that needs it. The applets currently marked to need the suid bit 351 one that needs it.
340 are: 352
353 The applets currently marked to need the suid bit are:
341 354
342 crontab, dnsd, findfs, ipcrm, ipcs, login, passwd, ping, su, 355 crontab, dnsd, findfs, ipcrm, ipcs, login, passwd, ping, su,
343 traceroute, vlock. 356 traceroute, vlock.
@@ -674,20 +687,13 @@ endchoice
674 687
675endmenu 688endmenu
676 689
677menu 'Installation Options' 690menu 'Installation Options ("make install" behavior)'
678
679config INSTALL_NO_USR
680 bool "Don't use /usr"
681 default n
682 help
683 Disable use of /usr. Don't activate this option if you don't know
684 that you really want this behaviour.
685 691
686choice 692choice
687 prompt "Applets links" 693 prompt "What kind of applet links to install"
688 default INSTALL_APPLET_SYMLINKS 694 default INSTALL_APPLET_SYMLINKS
689 help 695 help
690 Choose how you install applets links. 696 Choose what kind of links to applets are created by "make install".
691 697
692config INSTALL_APPLET_SYMLINKS 698config INSTALL_APPLET_SYMLINKS
693 bool "as soft-links" 699 bool "as soft-links"
@@ -711,8 +717,9 @@ config INSTALL_APPLET_DONT
711 bool "not installed" 717 bool "not installed"
712 depends on FEATURE_INSTALLER || FEATURE_SH_STANDALONE || FEATURE_PREFER_APPLETS 718 depends on FEATURE_INSTALLER || FEATURE_SH_STANDALONE || FEATURE_PREFER_APPLETS
713 help 719 help
714 Do not install applet links. Useful when using the -install feature 720 Do not install applet links. Useful when you plan to use
715 or a standalone shell for rescue purposes. 721 busybox --install for installing links, or plan to use
722 a standalone shell and thus don't need applet links.
716 723
717endchoice 724endchoice
718 725
@@ -736,8 +743,8 @@ config INSTALL_SH_APPLET_HARDLINK
736config INSTALL_SH_APPLET_SCRIPT_WRAPPER 743config INSTALL_SH_APPLET_SCRIPT_WRAPPER
737 bool "as script wrapper" 744 bool "as script wrapper"
738 help 745 help
739 Install /bin/sh applet as script wrapper that call the busybox 746 Install /bin/sh applet as script wrapper that calls
740 binary. 747 the busybox binary.
741 748
742endchoice 749endchoice
743 750
diff --git a/applets/usage_compressed b/applets/usage_compressed
index e1fd0d94d..af66bc5dc 100755
--- a/applets/usage_compressed
+++ b/applets/usage_compressed
@@ -9,6 +9,13 @@ test -x "$loc/usage" || exit 1
9test "$SED" || SED=sed 9test "$SED" || SED=sed
10test "$DD" || DD=dd 10test "$DD" || DD=dd
11 11
12# Some people were bitten by their system lacking a (proper) od
13od -v -t x1 </dev/null >/dev/null
14if test $? != 0; then
15 echo 'od tool is not installed or cannot accept "-v -t x1" options'
16 exit 1
17fi
18
12exec >"$target.$$" 19exec >"$target.$$"
13 20
14echo '#define UNPACKED_USAGE "" \' 21echo '#define UNPACKED_USAGE "" \'
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index d96790b89..a195434e4 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -307,7 +307,7 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
307 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 307 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
308 */ 308 */
309//usage:#define bunzip2_trivial_usage 309//usage:#define bunzip2_trivial_usage
310//usage: "[OPTIONS] [FILE]..." 310//usage: "[-cf] [FILE]..."
311//usage:#define bunzip2_full_usage "\n\n" 311//usage:#define bunzip2_full_usage "\n\n"
312//usage: "Decompress FILEs (or stdin)\n" 312//usage: "Decompress FILEs (or stdin)\n"
313//usage: "\nOptions:" 313//usage: "\nOptions:"
diff --git a/archival/cpio.c b/archival/cpio.c
index 7cd8ee8a7..a2d74dc79 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -370,7 +370,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
370 if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */ 370 if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */
371 bb_show_usage(); 371 bb_show_usage();
372 if (opt & CPIO_OPT_FILE) { 372 if (opt & CPIO_OPT_FILE) {
373 xmove_fd(xopen3(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666), STDOUT_FILENO); 373 xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
374 } 374 }
375 dump: 375 dump:
376 return cpio_o(); 376 return cpio_o();
diff --git a/archival/dpkg.c b/archival/dpkg.c
index b36c26198..07f01501b 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -1524,8 +1524,8 @@ static char FAST_FUNC filter_rename_config(archive_handle_t *archive_handle)
1524 buf = xmalloc(4096); 1524 buf = xmalloc(4096);
1525 md5_begin(&md5); 1525 md5_begin(&md5);
1526 while ((count = safe_read(fd, buf, 4096)) > 0) 1526 while ((count = safe_read(fd, buf, 4096)) > 0)
1527 md5_hash(buf, count, &md5); 1527 md5_hash(&md5, buf, count);
1528 md5_end(buf, &md5); /* using buf as result storage */ 1528 md5_end(&md5, buf); /* using buf as result storage */
1529 close(fd); 1529 close(fd);
1530 1530
1531 md5line = xmalloc(16 * 2 + 2 + strlen(name_ptr) + 1); 1531 md5line = xmalloc(16 * 2 + 2 + strlen(name_ptr) + 1);
diff --git a/archival/libunarchive/data_extract_all.c b/archival/libunarchive/data_extract_all.c
index cc549cd78..5fb1ab2ae 100644
--- a/archival/libunarchive/data_extract_all.c
+++ b/archival/libunarchive/data_extract_all.c
@@ -69,7 +69,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
69 } 69 }
70 } 70 }
71 else if (existing_sb.st_mtime >= file_header->mtime) { 71 else if (existing_sb.st_mtime >= file_header->mtime) {
72 if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { 72 if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
73 && !S_ISDIR(file_header->mode)
74 ) {
73 bb_error_msg("%s not created: newer or " 75 bb_error_msg("%s not created: newer or "
74 "same age file exists", file_header->name); 76 "same age file exists", file_header->name);
75 } 77 }
diff --git a/coreutils/cksum.c b/coreutils/cksum.c
index 8e7800ee9..7bf383e2d 100644
--- a/coreutils/cksum.c
+++ b/coreutils/cksum.c
@@ -8,6 +8,8 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11/* This is a NOEXEC applet. Be very careful! */
12
11int cksum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 13int cksum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
12int cksum_main(int argc UNUSED_PARAM, char **argv) 14int cksum_main(int argc UNUSED_PARAM, char **argv)
13{ 15{
diff --git a/coreutils/date.c b/coreutils/date.c
index 881dcc429..eed4714f9 100644
--- a/coreutils/date.c
+++ b/coreutils/date.c
@@ -19,38 +19,7 @@
19/* Input parsing code is always bulky - used heavy duty libc stuff as 19/* Input parsing code is always bulky - used heavy duty libc stuff as
20 much as possible, missed out a lot of bounds checking */ 20 much as possible, missed out a lot of bounds checking */
21 21
22/* Default input handling to save surprising some people */ 22//applet:IF_DATE(APPLET(date, _BB_DIR_BIN, _BB_SUID_DROP))
23
24/* GNU coreutils 6.9 man page:
25 * date [OPTION]... [+FORMAT]
26 * date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]
27 * -d, --date=STRING
28 * display time described by STRING, not `now'
29 * -f, --file=DATEFILE
30 * like --date once for each line of DATEFILE
31 * -r, --reference=FILE
32 * display the last modification time of FILE
33 * -R, --rfc-2822
34 * output date and time in RFC 2822 format.
35 * Example: Mon, 07 Aug 2006 12:34:56 -0600
36 * --rfc-3339=TIMESPEC
37 * output date and time in RFC 3339 format.
38 * TIMESPEC='date', 'seconds', or 'ns'
39 * Date and time components are separated by a single space:
40 * 2006-08-07 12:34:56-06:00
41 * -s, --set=STRING
42 * set time described by STRING
43 * -u, --utc, --universal
44 * print or set Coordinated Universal Time
45 *
46 * Busybox:
47 * long options are not supported
48 * -f is not supported
49 * -I seems to roughly match --rfc-3339, but -I has _optional_ param
50 * (thus "-I seconds" doesn't work, only "-Iseconds"),
51 * and does not support -Ins
52 * -D FMT is a bbox extension for _input_ conversion of -d DATE
53 */
54 23
55//kbuild:lib-$(CONFIG_DATE) += date.o 24//kbuild:lib-$(CONFIG_DATE) += date.o
56 25
@@ -69,6 +38,7 @@
69//config: Enable option (-I) to output an ISO-8601 compliant 38//config: Enable option (-I) to output an ISO-8601 compliant
70//config: date/time string. 39//config: date/time string.
71//config: 40//config:
41//config:# defaults to "no": stat's nanosecond field is a bit non-portable
72//config:config FEATURE_DATE_NANO 42//config:config FEATURE_DATE_NANO
73//config: bool "Support %[num]N nanosecond format specifier" 43//config: bool "Support %[num]N nanosecond format specifier"
74//config: default n 44//config: default n
@@ -92,6 +62,78 @@
92//config: the same format. With it on, 'date DATE' additionally supports 62//config: the same format. With it on, 'date DATE' additionally supports
93//config: MMDDhhmm[[YY]YY][.ss] format. 63//config: MMDDhhmm[[YY]YY][.ss] format.
94 64
65/* GNU coreutils 6.9 man page:
66 * date [OPTION]... [+FORMAT]
67 * date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]
68 * -d, --date=STRING
69 * display time described by STRING, not `now'
70 * -f, --file=DATEFILE
71 * like --date once for each line of DATEFILE
72 * -r, --reference=FILE
73 * display the last modification time of FILE
74 * -R, --rfc-2822
75 * output date and time in RFC 2822 format.
76 * Example: Mon, 07 Aug 2006 12:34:56 -0600
77 * --rfc-3339=TIMESPEC
78 * output date and time in RFC 3339 format.
79 * TIMESPEC='date', 'seconds', or 'ns'
80 * Date and time components are separated by a single space:
81 * 2006-08-07 12:34:56-06:00
82 * -s, --set=STRING
83 * set time described by STRING
84 * -u, --utc, --universal
85 * print or set Coordinated Universal Time
86 *
87 * Busybox:
88 * long options are not supported
89 * -f is not supported
90 * -I seems to roughly match --rfc-3339, but -I has _optional_ param
91 * (thus "-I seconds" doesn't work, only "-Iseconds"),
92 * and does not support -Ins
93 * -D FMT is a bbox extension for _input_ conversion of -d DATE
94 */
95
96//usage:#define date_trivial_usage
97//usage: "[OPTIONS] [+FMT] [TIME]"
98//usage:#define date_full_usage "\n\n"
99//usage: "Display time (using +FMT), or set time\n"
100//usage: "\nOptions:"
101//usage: IF_NOT_LONG_OPTS(
102//usage: "\n [-s] TIME Set time to TIME"
103//usage: "\n -u Work in UTC (don't convert to local time)"
104//usage: "\n -R Output RFC-2822 compliant date string"
105//usage: ) IF_LONG_OPTS(
106//usage: "\n [-s,--set] TIME Set time to TIME"
107//usage: "\n -u,--utc Work in UTC (don't convert to local time)"
108//usage: "\n -R,--rfc-2822 Output RFC-2822 compliant date string"
109//usage: )
110//usage: IF_FEATURE_DATE_ISOFMT(
111//usage: "\n -I[SPEC] Output ISO-8601 compliant date string"
112//usage: "\n SPEC='date' (default) for date only,"
113//usage: "\n 'hours', 'minutes', or 'seconds' for date and"
114//usage: "\n time to the indicated precision"
115//usage: )
116//usage: IF_NOT_LONG_OPTS(
117//usage: "\n -r FILE Display last modification time of FILE"
118//usage: "\n -d TIME Display TIME, not 'now'"
119//usage: ) IF_LONG_OPTS(
120//usage: "\n -r,--reference FILE Display last modification time of FILE"
121//usage: "\n -d,--date TIME Display TIME, not 'now'"
122//usage: )
123//usage: IF_FEATURE_DATE_ISOFMT(
124//usage: "\n -D FMT Use FMT for -d TIME conversion"
125//usage: )
126//usage: "\n"
127//usage: "\nRecognized TIME formats:"
128//usage: "\n hh:mm[:ss]"
129//usage: "\n [YYYY.]MM.DD-hh:mm[:ss]"
130//usage: "\n YYYY-MM-DD hh:mm[:ss]"
131//usage: "\n [[[[[YY]YY]MM]DD]hh]mm[.ss]"
132//usage:
133//usage:#define date_example_usage
134//usage: "$ date\n"
135//usage: "Wed Apr 12 18:52:41 MDT 2000\n"
136
95#include "libbb.h" 137#include "libbb.h"
96#if ENABLE_FEATURE_DATE_NANO 138#if ENABLE_FEATURE_DATE_NANO
97# include <sys/syscall.h> 139# include <sys/syscall.h>
diff --git a/coreutils/dos2unix.c b/coreutils/dos2unix.c
index ef1ea4328..8aa1d93b5 100644
--- a/coreutils/dos2unix.c
+++ b/coreutils/dos2unix.c
@@ -14,6 +14,8 @@
14 14
15#include "libbb.h" 15#include "libbb.h"
16 16
17/* This is a NOEXEC applet. Be very careful! */
18
17enum { 19enum {
18 CT_UNIX2DOS = 1, 20 CT_UNIX2DOS = 1,
19 CT_DOS2UNIX 21 CT_DOS2UNIX
diff --git a/coreutils/fold.c b/coreutils/fold.c
index 54f1aa2ac..4a6429ad7 100644
--- a/coreutils/fold.c
+++ b/coreutils/fold.c
@@ -12,6 +12,8 @@
12#include "libbb.h" 12#include "libbb.h"
13#include "unicode.h" 13#include "unicode.h"
14 14
15/* This is a NOEXEC applet. Be very careful! */
16
15/* Must match getopt32 call */ 17/* Must match getopt32 call */
16#define FLAG_COUNT_BYTES 1 18#define FLAG_COUNT_BYTES 1
17#define FLAG_BREAK_SPACES 2 19#define FLAG_BREAK_SPACES 2
diff --git a/coreutils/head.c b/coreutils/head.c
index 0845b4375..669aae819 100644
--- a/coreutils/head.c
+++ b/coreutils/head.c
@@ -13,6 +13,8 @@
13 13
14#include "libbb.h" 14#include "libbb.h"
15 15
16/* This is a NOEXEC applet. Be very careful! */
17
16static const char head_opts[] ALIGN1 = 18static const char head_opts[] ALIGN1 =
17 "n:" 19 "n:"
18#if ENABLE_FEATURE_FANCY_HEAD 20#if ENABLE_FEATURE_FANCY_HEAD
diff --git a/coreutils/id.c b/coreutils/id.c
index 56286f4d4..ed1dc862e 100644
--- a/coreutils/id.c
+++ b/coreutils/id.c
@@ -17,6 +17,8 @@
17 17
18#include "libbb.h" 18#include "libbb.h"
19 19
20/* This is a NOEXEC applet. Be very careful! */
21
20#if !ENABLE_USE_BB_PWD_GRP 22#if !ENABLE_USE_BB_PWD_GRP
21#if defined(__UCLIBC_MAJOR__) && (__UCLIBC_MAJOR__ == 0) 23#if defined(__UCLIBC_MAJOR__) && (__UCLIBC_MAJOR__ == 0)
22#if (__UCLIBC_MINOR__ < 9) || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 30) 24#if (__UCLIBC_MINOR__ < 9) || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 30)
diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c
index 646f8bd10..e79210c0d 100644
--- a/coreutils/md5_sha1_sum.c
+++ b/coreutils/md5_sha1_sum.c
@@ -8,6 +8,8 @@
8 8
9#include "libbb.h" 9#include "libbb.h"
10 10
11/* This is a NOEXEC applet. Be very careful! */
12
11typedef enum { 13typedef enum {
12 /* 4th letter of applet_name is... */ 14 /* 4th letter of applet_name is... */
13 HASH_MD5 = 's', /* "md5>s<um" */ 15 HASH_MD5 = 's', /* "md5>s<um" */
@@ -41,7 +43,7 @@ static uint8_t *hash_file(const char *filename /*, hash_algo_t hash_algo*/)
41 } context; 43 } context;
42 uint8_t *hash_value = NULL; 44 uint8_t *hash_value = NULL;
43 RESERVE_CONFIG_UBUFFER(in_buf, 4096); 45 RESERVE_CONFIG_UBUFFER(in_buf, 4096);
44 void FAST_FUNC (*update)(const void*, size_t, void*); 46 void FAST_FUNC (*update)(void*, const void*, size_t);
45 void FAST_FUNC (*final)(void*, void*); 47 void FAST_FUNC (*final)(void*, void*);
46 hash_algo_t hash_algo = applet_name[3]; 48 hash_algo_t hash_algo = applet_name[3];
47 49
@@ -76,11 +78,11 @@ static uint8_t *hash_file(const char *filename /*, hash_algo_t hash_algo*/)
76 } 78 }
77 79
78 while (0 < (count = safe_read(src_fd, in_buf, 4096))) { 80 while (0 < (count = safe_read(src_fd, in_buf, 4096))) {
79 update(in_buf, count, &context); 81 update(&context, in_buf, count);
80 } 82 }
81 83
82 if (count == 0) { 84 if (count == 0) {
83 final(in_buf, &context); 85 final(&context, in_buf);
84 hash_value = hash_bin_to_hex(in_buf, hash_len); 86 hash_value = hash_bin_to_hex(in_buf, hash_len);
85 } 87 }
86 88
diff --git a/coreutils/mkfifo.c b/coreutils/mkfifo.c
index 41aedd099..4388ccaa3 100644
--- a/coreutils/mkfifo.c
+++ b/coreutils/mkfifo.c
@@ -13,6 +13,8 @@
13#include "libbb.h" 13#include "libbb.h"
14#include "libcoreutils/coreutils.h" 14#include "libcoreutils/coreutils.h"
15 15
16/* This is a NOEXEC applet. Be very careful! */
17
16int mkfifo_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 18int mkfifo_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
17int mkfifo_main(int argc UNUSED_PARAM, char **argv) 19int mkfifo_main(int argc UNUSED_PARAM, char **argv)
18{ 20{
diff --git a/coreutils/mknod.c b/coreutils/mknod.c
index 0e5542dde..14d91b5df 100644
--- a/coreutils/mknod.c
+++ b/coreutils/mknod.c
@@ -14,6 +14,8 @@
14#include "libbb.h" 14#include "libbb.h"
15#include "libcoreutils/coreutils.h" 15#include "libcoreutils/coreutils.h"
16 16
17/* This is a NOEXEC applet. Be very careful! */
18
17static const char modes_chars[] ALIGN1 = { 'p', 'c', 'u', 'b', 0, 1, 1, 2 }; 19static const char modes_chars[] ALIGN1 = { 'p', 'c', 'u', 'b', 0, 1, 1, 2 };
18static const mode_t modes_cubp[] = { S_IFIFO, S_IFCHR, S_IFBLK }; 20static const mode_t modes_cubp[] = { S_IFIFO, S_IFCHR, S_IFBLK };
19 21
diff --git a/coreutils/printenv.c b/coreutils/printenv.c
index d38f8fb5f..33be5c096 100644
--- a/coreutils/printenv.c
+++ b/coreutils/printenv.c
@@ -10,6 +10,8 @@
10 10
11#include "libbb.h" 11#include "libbb.h"
12 12
13/* This is a NOFORK applet. Be very careful! */
14
13int printenv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 15int printenv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14int printenv_main(int argc UNUSED_PARAM, char **argv) 16int printenv_main(int argc UNUSED_PARAM, char **argv)
15{ 17{
diff --git a/coreutils/seq.c b/coreutils/seq.c
index 8be25360f..22bf3ec9d 100644
--- a/coreutils/seq.c
+++ b/coreutils/seq.c
@@ -86,7 +86,8 @@ int seq_main(int argc, char **argv)
86 v = first; 86 v = first;
87 n = 0; 87 n = 0;
88 while (increment >= 0 ? v <= last : v >= last) { 88 while (increment >= 0 ? v <= last : v >= last) {
89 printf("%s%0*.*f", sep, width, frac_part, v); 89 if (printf("%s%0*.*f", sep, width, frac_part, v) < 0)
90 break; /* I/O error, bail out (yes, this really happens) */
90 sep = opt_s; 91 sep = opt_s;
91 /* v += increment; - would accumulate floating point errors */ 92 /* v += increment; - would accumulate floating point errors */
92 n++; 93 n++;
diff --git a/coreutils/sleep.c b/coreutils/sleep.c
index b983df47e..433f9d6ee 100644
--- a/coreutils/sleep.c
+++ b/coreutils/sleep.c
@@ -20,7 +20,7 @@
20 20
21#include "libbb.h" 21#include "libbb.h"
22 22
23/* This is a NOFORK applet. Be very careful! */ 23/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */
24 24
25 25
26#if ENABLE_FEATURE_FANCY_SLEEP || ENABLE_FEATURE_FLOAT_SLEEP 26#if ENABLE_FEATURE_FANCY_SLEEP || ENABLE_FEATURE_FLOAT_SLEEP
@@ -49,6 +49,10 @@ int sleep_main(int argc UNUSED_PARAM, char **argv)
49 49
50#if ENABLE_FEATURE_FLOAT_SLEEP 50#if ENABLE_FEATURE_FLOAT_SLEEP
51 51
52# if ENABLE_LOCALE_SUPPORT
53 /* undo busybox.c setlocale */
54 setlocale(LC_NUMERIC, "C");
55# endif
52 duration = 0; 56 duration = 0;
53 do { 57 do {
54 char *arg = *argv; 58 char *arg = *argv;
@@ -62,14 +66,15 @@ int sleep_main(int argc UNUSED_PARAM, char **argv)
62 d = strtod(arg, &pp); 66 d = strtod(arg, &pp);
63 if (errno || *pp) 67 if (errno || *pp)
64 bb_show_usage(); 68 bb_show_usage();
65 arg[len] = sv; 69 arg += len;
66 len--; 70 *arg-- = sv;
67 sv = arg[len]; 71 sv = *arg;
68 arg[len] = '1'; 72 *arg = '1';
69 duration += d * xatoul_sfx(&arg[len], sfx); 73 duration += d * xatoul_sfx(arg, sfx);
70 arg[len] = sv; 74 *arg = sv;
71 } else 75 } else {
72 duration += xatoul_sfx(arg, sfx); 76 duration += xatoul_sfx(arg, sfx);
77 }
73 } while (*++argv); 78 } while (*++argv);
74 79
75 ts.tv_sec = MAXINT(typeof(ts.tv_sec)); 80 ts.tv_sec = MAXINT(typeof(ts.tv_sec));
diff --git a/coreutils/sort.c b/coreutils/sort.c
index 4407b7105..eccc2d437 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -412,7 +412,7 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
412#if ENABLE_FEATURE_SORT_BIG 412#if ENABLE_FEATURE_SORT_BIG
413 /* Open output file _after_ we read all input ones */ 413 /* Open output file _after_ we read all input ones */
414 if (option_mask32 & FLAG_o) 414 if (option_mask32 & FLAG_o)
415 xmove_fd(xopen3(str_o, O_WRONLY, 0666), STDOUT_FILENO); 415 xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), STDOUT_FILENO);
416#endif 416#endif
417 flag = (option_mask32 & FLAG_z) ? '\0' : '\n'; 417 flag = (option_mask32 & FLAG_z) ? '\0' : '\n';
418 for (i = 0; i < linecount; i++) 418 for (i = 0; i < linecount; i++)
diff --git a/coreutils/tee.c b/coreutils/tee.c
index 2e1e367f2..e66e885ec 100644
--- a/coreutils/tee.c
+++ b/coreutils/tee.c
@@ -42,7 +42,7 @@ int tee_main(int argc, char **argv)
42 * that doesn't consume all its input. Good idea... */ 42 * that doesn't consume all its input. Good idea... */
43 signal(SIGPIPE, SIG_IGN); 43 signal(SIGPIPE, SIG_IGN);
44 44
45 /* Allocate an array of FILE *'s, with one extra for a sentinal. */ 45 /* Allocate an array of FILE *'s, with one extra for a sentinel. */
46 fp = files = xzalloc(sizeof(FILE *) * (argc + 2)); 46 fp = files = xzalloc(sizeof(FILE *) * (argc + 2));
47 np = names = argv - 1; 47 np = names = argv - 1;
48 48
diff --git a/coreutils/uniq.c b/coreutils/uniq.c
index f0364b9a1..358de7894 100644
--- a/coreutils/uniq.c
+++ b/coreutils/uniq.c
@@ -52,8 +52,8 @@ int uniq_main(int argc UNUSED_PARAM, char **argv)
52 if (output[0] != '-' || output[1]) { 52 if (output[0] != '-' || output[1]) {
53 // Won't work with "uniq - FILE" and closed stdin: 53 // Won't work with "uniq - FILE" and closed stdin:
54 //close(STDOUT_FILENO); 54 //close(STDOUT_FILENO);
55 //xopen3(output, O_WRONLY | O_CREAT | O_TRUNC, 0666); 55 //xopen(output, O_WRONLY | O_CREAT | O_TRUNC);
56 xmove_fd(xopen3(output, O_WRONLY | O_CREAT | O_TRUNC, 0666), STDOUT_FILENO); 56 xmove_fd(xopen(output, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
57 } 57 }
58 } 58 }
59 } 59 }
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c
index 0da9b0988..0c4311f24 100644
--- a/coreutils/uudecode.c
+++ b/coreutils/uudecode.c
@@ -13,7 +13,7 @@
13#include "libbb.h" 13#include "libbb.h"
14 14
15#if ENABLE_UUDECODE 15#if ENABLE_UUDECODE
16static void read_stduu(FILE *src_stream, FILE *dst_stream) 16static void FAST_FUNC read_stduu(FILE *src_stream, FILE *dst_stream, int flags UNUSED_PARAM)
17{ 17{
18 char *line; 18 char *line;
19 19
@@ -75,71 +75,6 @@ static void read_stduu(FILE *src_stream, FILE *dst_stream)
75} 75}
76#endif 76#endif
77 77
78static void read_base64(FILE *src_stream, FILE *dst_stream)
79{
80 int term_count = 0;
81
82 while (1) {
83 unsigned char translated[4];
84 int count = 0;
85
86 /* Process one group of 4 chars */
87 while (count < 4) {
88 char *table_ptr;
89 int ch;
90
91 /* Get next _valid_ character.
92 * bb_uuenc_tbl_base64[] contains this string:
93 * 0 1 2 3 4 5 6
94 * 012345678901234567890123456789012345678901234567890123456789012345
95 * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n"
96 */
97 do {
98 ch = fgetc(src_stream);
99 if (ch == EOF) {
100 if (ENABLE_BASE64
101 && (!ENABLE_UUDECODE || applet_name[0] == 'b')
102 && count == 0
103 ) {
104 return;
105 }
106 bb_error_msg_and_die("short file");
107 }
108 table_ptr = strchr(bb_uuenc_tbl_base64, ch);
109 } while (!table_ptr);
110
111 /* Convert encoded character to decimal */
112 ch = table_ptr - bb_uuenc_tbl_base64;
113
114 if (ch == 65 /* '\n' */) {
115 /* Terminating "====" line? */
116 if (term_count == 4)
117 return; /* yes */
118 term_count = 0;
119 continue;
120 }
121 /* ch is 64 is char was '=', otherwise 0..63 */
122 translated[count] = ch & 63; /* 64 -> 0 */
123 if (ch == 64) {
124 term_count++;
125 break;
126 }
127 count++;
128 }
129
130 /* Merge 6 bit chars to 8 bit.
131 * count can be < 4 when we decode the tail:
132 * "eQ==" -> "y", not "y NUL NUL"
133 */
134 if (count > 1)
135 fputc(translated[0] << 2 | translated[1] >> 4, dst_stream);
136 if (count > 2)
137 fputc(translated[1] << 4 | translated[2] >> 2, dst_stream);
138 if (count > 3)
139 fputc(translated[2] << 6 | translated[3], dst_stream);
140 } /* while (1) */
141}
142
143#if ENABLE_UUDECODE 78#if ENABLE_UUDECODE
144int uudecode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 79int uudecode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
145int uudecode_main(int argc UNUSED_PARAM, char **argv) 80int uudecode_main(int argc UNUSED_PARAM, char **argv)
@@ -158,7 +93,7 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv)
158 93
159 /* Search for the start of the encoding */ 94 /* Search for the start of the encoding */
160 while ((line = xmalloc_fgetline(src_stream)) != NULL) { 95 while ((line = xmalloc_fgetline(src_stream)) != NULL) {
161 void (*decode_fn_ptr)(FILE *src, FILE *dst); 96 void FAST_FUNC (*decode_fn_ptr)(FILE *src, FILE *dst, int flags);
162 char *line_ptr; 97 char *line_ptr;
163 FILE *dst_stream; 98 FILE *dst_stream;
164 int mode; 99 int mode;
@@ -189,7 +124,7 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv)
189 fchmod(fileno(dst_stream), mode & (S_IRWXU | S_IRWXG | S_IRWXO)); 124 fchmod(fileno(dst_stream), mode & (S_IRWXU | S_IRWXG | S_IRWXO));
190 } 125 }
191 free(line); 126 free(line);
192 decode_fn_ptr(src_stream, dst_stream); 127 decode_fn_ptr(src_stream, dst_stream, /*flags:*/ BASE64_FLAG_UU_STOP + BASE64_FLAG_NO_STOP_CHAR);
193 /* fclose_if_not_stdin(src_stream); - redundant */ 128 /* fclose_if_not_stdin(src_stream); - redundant */
194 return EXIT_SUCCESS; 129 return EXIT_SUCCESS;
195 } 130 }
@@ -231,7 +166,7 @@ int base64_main(int argc UNUSED_PARAM, char **argv)
231 *--argv = (char*)"-"; 166 *--argv = (char*)"-";
232 src_stream = xfopen_stdin(argv[0]); 167 src_stream = xfopen_stdin(argv[0]);
233 if (opts) { 168 if (opts) {
234 read_base64(src_stream, stdout); 169 read_base64(src_stream, stdout, /*flags:*/ (char)EOF);
235 } else { 170 } else {
236 enum { 171 enum {
237 SRC_BUF_SIZE = 76/4*3, /* This *MUST* be a multiple of 3 */ 172 SRC_BUF_SIZE = 76/4*3, /* This *MUST* be a multiple of 3 */
diff --git a/coreutils/wc.c b/coreutils/wc.c
index 4f14374c3..ecadae59b 100644
--- a/coreutils/wc.c
+++ b/coreutils/wc.c
@@ -7,7 +7,7 @@
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9 9
10/* BB_AUDIT SUSv3 _NOT_ compliant -- option -m is not currently supported. */ 10/* BB_AUDIT SUSv3 compliant. */
11/* http://www.opengroup.org/onlinepubs/007904975/utilities/wc.html */ 11/* http://www.opengroup.org/onlinepubs/007904975/utilities/wc.html */
12 12
13/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) 13/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
@@ -19,10 +19,6 @@
19 * 3) no checking of ferror on EOF returns 19 * 3) no checking of ferror on EOF returns
20 * 4) isprint() wasn't considered when word counting. 20 * 4) isprint() wasn't considered when word counting.
21 * 21 *
22 * TODO:
23 *
24 * When locale support is enabled, count multibyte chars in the '-m' case.
25 *
26 * NOTES: 22 * NOTES:
27 * 23 *
28 * The previous busybox wc attempted an optimization using stat for the 24 * The previous busybox wc attempted an optimization using stat for the
@@ -40,8 +36,8 @@
40 * 36 *
41 * for which 'wc -c' should output '0'. 37 * for which 'wc -c' should output '0'.
42 */ 38 */
43
44#include "libbb.h" 39#include "libbb.h"
40#include "unicode.h"
45 41
46#if !ENABLE_LOCALE_SUPPORT 42#if !ENABLE_LOCALE_SUPPORT
47# undef isprint 43# undef isprint
@@ -58,11 +54,39 @@
58# define COUNT_FMT "u" 54# define COUNT_FMT "u"
59#endif 55#endif
60 56
57/* We support -m even when UNICODE_SUPPORT is off,
58 * we just don't advertise it in help text,
59 * since it is the same as -c in this case.
60 */
61
62//usage:#define wc_trivial_usage
63//usage: "[-c"IF_UNICODE_SUPPORT("m")"lwL] [FILE]..."
64//usage:
65//usage:#define wc_full_usage "\n\n"
66//usage: "Count lines, words, and bytes for each FILE (or stdin)\n"
67//usage: "\nOptions:"
68//usage: "\n -c Count bytes"
69//usage: IF_UNICODE_SUPPORT(
70//usage: "\n -m Count characters"
71//usage: )
72//usage: "\n -l Count newlines"
73//usage: "\n -w Count words"
74//usage: "\n -L Print longest line length"
75//usage:
76//usage:#define wc_example_usage
77//usage: "$ wc /etc/passwd\n"
78//usage: " 31 46 1365 /etc/passwd\n"
79
80/* Order is important if we want to be compatible with
81 * column order in "wc -cmlwL" output:
82 */
61enum { 83enum {
62 WC_LINES = 0, 84 WC_LINES = 0,
63 WC_WORDS = 1, 85 WC_WORDS = 1,
64 WC_CHARS = 2, 86 WC_UNICHARS = 2,
65 WC_LENGTH = 3 87 WC_CHARS = 3,
88 WC_LENGTH = 4,
89 NUM_WCS = 5,
66}; 90};
67 91
68int wc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 92int wc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -72,13 +96,15 @@ int wc_main(int argc UNUSED_PARAM, char **argv)
72 const char *start_fmt = " %9"COUNT_FMT + 1; 96 const char *start_fmt = " %9"COUNT_FMT + 1;
73 const char *fname_fmt = " %s\n"; 97 const char *fname_fmt = " %s\n";
74 COUNT_T *pcounts; 98 COUNT_T *pcounts;
75 COUNT_T counts[4]; 99 COUNT_T counts[NUM_WCS];
76 COUNT_T totals[4]; 100 COUNT_T totals[NUM_WCS];
77 int num_files; 101 int num_files;
78 smallint status = EXIT_SUCCESS; 102 smallint status = EXIT_SUCCESS;
79 unsigned print_type; 103 unsigned print_type;
80 104
81 print_type = getopt32(argv, "lwcL"); 105 init_unicode();
106
107 print_type = getopt32(argv, "lwcmL");
82 108
83 if (print_type == 0) { 109 if (print_type == 0) {
84 print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_CHARS); 110 print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_CHARS);
@@ -99,7 +125,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv)
99 pcounts = counts; 125 pcounts = counts;
100 126
101 num_files = 0; 127 num_files = 0;
102 while ((arg = *argv++) != 0) { 128 while ((arg = *argv++) != NULL) {
103 FILE *fp; 129 FILE *fp;
104 const char *s; 130 const char *s;
105 unsigned u; 131 unsigned u;
@@ -117,21 +143,28 @@ int wc_main(int argc UNUSED_PARAM, char **argv)
117 linepos = 0; 143 linepos = 0;
118 in_word = 0; 144 in_word = 0;
119 145
120 do { 146 while (1) {
121 int c; 147 int c;
122 /* Our -w doesn't match GNU wc exactly... oh well */ 148 /* Our -w doesn't match GNU wc exactly... oh well */
123 149
124 ++counts[WC_CHARS];
125 c = getc(fp); 150 c = getc(fp);
126 if (c == EOF) { 151 if (c == EOF) {
127 if (ferror(fp)) { 152 if (ferror(fp)) {
128 bb_simple_perror_msg(arg); 153 bb_simple_perror_msg(arg);
129 status = EXIT_FAILURE; 154 status = EXIT_FAILURE;
130 } 155 }
131 --counts[WC_CHARS];
132 goto DO_EOF; /* Treat an EOF as '\r'. */ 156 goto DO_EOF; /* Treat an EOF as '\r'. */
133 } 157 }
134 if (isprint_asciionly(c)) { 158
159 /* Cater for -c and -m */
160 ++counts[WC_CHARS];
161 if (unicode_status != UNICODE_ON /* every byte is a new char */
162 || (c & 0xc0) != 0x80 /* it isn't a 2nd+ byte of a Unicode char */
163 ) {
164 ++counts[WC_UNICHARS];
165 }
166
167 if (isprint_asciionly(c)) { /* FIXME: not unicode-aware */
135 ++linepos; 168 ++linepos;
136 if (!isspace(c)) { 169 if (!isspace(c)) {
137 in_word = 1; 170 in_word = 1;
@@ -167,18 +200,18 @@ int wc_main(int argc UNUSED_PARAM, char **argv)
167 if (c == EOF) { 200 if (c == EOF) {
168 break; 201 break;
169 } 202 }
170 } while (1); 203 }
204
205 fclose_if_not_stdin(fp);
171 206
172 if (totals[WC_LENGTH] < counts[WC_LENGTH]) { 207 if (totals[WC_LENGTH] < counts[WC_LENGTH]) {
173 totals[WC_LENGTH] = counts[WC_LENGTH]; 208 totals[WC_LENGTH] = counts[WC_LENGTH];
174 } 209 }
175 totals[WC_LENGTH] -= counts[WC_LENGTH]; 210 totals[WC_LENGTH] -= counts[WC_LENGTH];
176 211
177 fclose_if_not_stdin(fp);
178
179 OUTPUT: 212 OUTPUT:
180 /* coreutils wc tries hard to print pretty columns 213 /* coreutils wc tries hard to print pretty columns
181 * (saves results for all files, find max col len etc...) 214 * (saves results for all files, finds max col len etc...)
182 * we won't try that hard, it will bloat us too much */ 215 * we won't try that hard, it will bloat us too much */
183 s = start_fmt; 216 s = start_fmt;
184 u = 0; 217 u = 0;
@@ -188,7 +221,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv)
188 s = " %9"COUNT_FMT; /* Ok... restore the leading space. */ 221 s = " %9"COUNT_FMT; /* Ok... restore the leading space. */
189 } 222 }
190 totals[u] += pcounts[u]; 223 totals[u] += pcounts[u];
191 } while (++u < 4); 224 } while (++u < NUM_WCS);
192 printf(fname_fmt, arg); 225 printf(fname_fmt, arg);
193 } 226 }
194 227
diff --git a/docs/busybox_footer.pod b/docs/busybox_footer.pod
index 47eabaeeb..c346c736b 100644
--- a/docs/busybox_footer.pod
+++ b/docs/busybox_footer.pod
@@ -252,4 +252,34 @@ Tito Ragusa <farmatito@tiscali.it>
252 252
253 devfsd and size optimizations in strings, openvt and deallocvt. 253 devfsd and size optimizations in strings, openvt and deallocvt.
254 254
255=for html <br>
256
257Paul Fox <pgf@foxharp.boston.ma.us>
258
259 vi editing mode for ash, various other patches/fixes
260
261=for html <br>
262
263Roberto A. Foglietta <me@roberto.foglietta.name>
264
265 port: dnsd
266
267=for html <br>
268
269Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
270
271 misc
272
273=for html <br>
274
275Mike Frysinger <vapier@gentoo.org>
276
277 initial e2fsprogs, printenv, setarch, sum, misc
278
279=for html <br>
280
281Jie Zhang <jie.zhang@analog.com>
282
283 fixed two bugs in msh and hush (exitcode of killed processes)
284
255=cut 285=cut
diff --git a/docs/contributing.txt b/docs/contributing.txt
index 39aaef1b5..e3289fd49 100644
--- a/docs/contributing.txt
+++ b/docs/contributing.txt
@@ -229,8 +229,11 @@ Here are some guidelines on how to submit a patch to Busybox.
229Making A Patch 229Making A Patch
230~~~~~~~~~~~~~~ 230~~~~~~~~~~~~~~
231 231
232If you've got anonymous CVS access set up, making a patch is simple. Just make 232If you've got anonymous Git access set up, making a patch is simple. Just make
233sure you're in the busybox/ directory and type 'cvs diff -bwu > mychanges.patch'. 233sure you're in the busybox/ directory and type:
234
235 git diff -b -w > mychanges.patch
236
234You can send the resulting .patch file to the mailing list with a description 237You can send the resulting .patch file to the mailing list with a description
235of what it does. (But not before you test it! See the next section for some 238of what it does. (But not before you test it! See the next section for some
236guidelines.) It is preferred that patches be sent as attachments, but it is 239guidelines.) It is preferred that patches be sent as attachments, but it is
@@ -238,8 +241,12 @@ not required.
238 241
239Also, feel free to help test other people's patches and reply to them with 242Also, feel free to help test other people's patches and reply to them with
240comments. You can apply a patch by saving it into your busybox/ directory and 243comments. You can apply a patch by saving it into your busybox/ directory and
241typing 'patch < mychanges.patch'. Then you can recompile, see if it runs, test 244typing:
242if it works as advertised, and post your findings to the mailing list. 245
246 patch -p1 < mychanges.patch
247
248Then you can recompile, see if it runs, test if it works as advertised, and
249post your findings to the mailing list.
243 250
244NOTE: Please do not include extraneous or irrelevant changes in your patches. 251NOTE: Please do not include extraneous or irrelevant changes in your patches.
245Please do not try to "bundle" two patches together into one. Make single, 252Please do not try to "bundle" two patches together into one. Make single,
@@ -252,7 +259,7 @@ Testing Guidelines
252~~~~~~~~~~~~~~~~~~ 259~~~~~~~~~~~~~~~~~~
253 260
254It's considered good form to test your new feature before you submit a patch 261It's considered good form to test your new feature before you submit a patch
255to the mailing list, and especially before you commit a change to CVS. Here 262to the mailing list, and especially before you push a change to Git. Here
256are some guidelines on how to test your changes. 263are some guidelines on how to test your changes.
257 264
258 - Always test Busybox applets against GNU counterparts and make sure the 265 - Always test Busybox applets against GNU counterparts and make sure the
@@ -348,7 +355,7 @@ responses from queries to applet maintainer or positive responses from folks
348on the mailing list. 355on the mailing list.
349 356
350We've made strident efforts to put a useful "collaboration" infrastructure in 357We've made strident efforts to put a useful "collaboration" infrastructure in
351place in the form of mailing lists, the bug tracking system, and CVS. Please 358place in the form of mailing lists, the bug tracking system, and Git. Please
352use these resources. 359use these resources.
353 360
354 361
@@ -373,39 +380,43 @@ opposite effect.
373 380
374 381
375 382
376Committing Changes to CVS 383Pushing Changes to Git
377------------------------- 384----------------------
378 385
379If you submit several patches that demonstrate that you are a skilled and wise 386If you submit several patches that demonstrate that you are a skilled and wise
380coder, you may be invited to become a committer, thus enabling you to commit 387coder, you may be invited to become a committer, thus enabling you to push
381changes directly to CVS. This is nice because you don't have to wait for 388changes directly to Git. This is nice because you don't have to wait for
382someone else to commit your change for you, you can just do it yourself. 389someone else to push your change for you, you can just do it yourself.
383 390
384But note that this is a privilege that comes with some responsibilities. You 391But note that this is a privilege that comes with some responsibilities. You
385should test your changes before you commit them. You should also talk to an 392should test your changes before you push them. You should also talk to an
386applet maintainer before you make any kind of sweeping changes to somebody 393applet maintainer before you make any kind of sweeping changes to somebody
387else's code. Big changes should still go to the mailing list first. Remember, 394else's code. Big changes should still go to the mailing list first. Remember,
388being wise, polite, and discreet is more important than being clever. 395being wise, polite, and discreet is more important than being clever.
389 396
397For more information on Git push access, see:
390 398
391When To Commit 399 http://busybox.net/developer.html
392~~~~~~~~~~~~~~
393 400
394Generally, you should feel free to commit a change if: 401
402When To Push
403~~~~~~~~~~~~
404
405Generally, you should feel free to push a change if:
395 406
396 - Your changes are small and don't touch many files 407 - Your changes are small and don't touch many files
397 - You are fixing a bug 408 - You are fixing a bug
398 - Somebody has told you that it's okay 409 - Somebody has told you that it's okay
399 - It's obviously the Right Thing 410 - It's obviously the Right Thing
400 411
401The more of the above are true, the better it is to just commit a change 412The more of the above are true, the better it is to just push a change
402directly to CVS. 413directly to Git.
403 414
404 415
405When Not To Commit 416When Not To Push
406~~~~~~~~~~~~~~~~~~ 417~~~~~~~~~~~~~~~~
407 418
408Even if you have commit rights, you should probably still post a patch to the 419Even if you have push access, you should probably still post a patch to the
409mailing list if: 420mailing list if:
410 421
411 - Your changes are broad and touch many different files 422 - Your changes are broad and touch many different files
@@ -414,7 +425,7 @@ mailing list if:
414 - You are not the maintainer and your changes make the maintainer cringe 425 - You are not the maintainer and your changes make the maintainer cringe
415 426
416The more of the above are true, the better it is to post a patch to the 427The more of the above are true, the better it is to post a patch to the
417mailing list instead of committing. 428mailing list instead of pushing.
418 429
419 430
420 431
diff --git a/e2fsprogs/tune2fs.c b/e2fsprogs/tune2fs.c
index 311349fec..75e4f6bcf 100644
--- a/e2fsprogs/tune2fs.c
+++ b/e2fsprogs/tune2fs.c
@@ -27,24 +27,40 @@ do { \
27#define FETCH_LE32(field) \ 27#define FETCH_LE32(field) \
28 (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size()) 28 (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size())
29 29
30//usage:#define tune2fs_trivial_usage
31//usage: "[-c MOUNT_CNT] "
32////usage: "[-e errors-behavior] [-g group] "
33//usage: "[-i DAYS] "
34////usage: "[-j] [-J journal-options] [-l] [-s sparse-flag] "
35////usage: "[-m reserved-blocks-percent] [-o [^]mount-options[,...]] "
36////usage: "[-r reserved-blocks-count] [-u user] [-C mount-count] "
37//usage: "[-L LABEL] "
38////usage: "[-M last-mounted-dir] [-O [^]feature[,...]] "
39////usage: "[-T last-check-time] [-U UUID] "
40//usage: "BLOCKDEV"
41//usage:
42//usage:#define tune2fs_full_usage "\n\n"
43//usage: "Adjust filesystem options on ext[23] filesystems"
44
30enum { 45enum {
31 OPT_L = 1 << 0, // label 46 OPT_L = 1 << 0, // label
47 OPT_c = 1 << 1, // max mount count
48 OPT_i = 1 << 2, // check interval
32}; 49};
33 50
34int tune2fs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 51int tune2fs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
35int tune2fs_main(int argc UNUSED_PARAM, char **argv) 52int tune2fs_main(int argc UNUSED_PARAM, char **argv)
36{ 53{
37 unsigned opts; 54 unsigned opts;
38 const char *label; 55 const char *label, *str_c, *str_i;
39 struct ext2_super_block *sb; 56 struct ext2_super_block *sb;
40 int fd; 57 int fd;
41 58
42 opt_complementary = "=1"; 59 opt_complementary = "=1";
43 opts = getopt32(argv, "L:", &label); 60 opts = getopt32(argv, "L:c:i:", &label, &str_c, &str_i);
44 argv += optind; // argv[0] -- device
45
46 if (!opts) 61 if (!opts)
47 bb_show_usage(); 62 bb_show_usage();
63 argv += optind; // argv[0] -- device
48 64
49 // read superblock 65 // read superblock
50 fd = xopen(argv[0], O_RDWR); 66 fd = xopen(argv[0], O_RDWR);
@@ -54,9 +70,23 @@ int tune2fs_main(int argc UNUSED_PARAM, char **argv)
54 70
55 // mangle superblock 71 // mangle superblock
56 //STORE_LE(sb->s_wtime, time(NULL)); - why bother? 72 //STORE_LE(sb->s_wtime, time(NULL)); - why bother?
73
57 // set the label 74 // set the label
58 if (1 /*opts & OPT_L*/) 75 if (opts & OPT_L)
59 safe_strncpy((char *)sb->s_volume_name, label, sizeof(sb->s_volume_name)); 76 safe_strncpy((char *)sb->s_volume_name, label, sizeof(sb->s_volume_name));
77
78 if (opts & OPT_c) {
79 int n = xatoi_range(str_c, -1, 0xfffe);
80 if (n == 0)
81 n = -1;
82 STORE_LE(sb->s_max_mnt_count, (unsigned)n);
83 }
84
85 if (opts & OPT_i) {
86 unsigned n = xatou_range(str_i, 0, (unsigned)0xffffffff / (24*60*60)) * 24*60*60;
87 STORE_LE(sb->s_checkinterval, n);
88 }
89
60 // write superblock 90 // write superblock
61 xlseek(fd, 1024, SEEK_SET); 91 xlseek(fd, 1024, SEEK_SET);
62 xwrite(fd, sb, 1024); 92 xwrite(fd, sb, 1024);
diff --git a/editors/awk.c b/editors/awk.c
index f47d1ab02..2245cad03 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -17,10 +17,14 @@
17/* If you comment out one of these below, it will be #defined later 17/* If you comment out one of these below, it will be #defined later
18 * to perform debug printfs to stderr: */ 18 * to perform debug printfs to stderr: */
19#define debug_printf_walker(...) do {} while (0) 19#define debug_printf_walker(...) do {} while (0)
20#define debug_printf_eval(...) do {} while (0)
20 21
21#ifndef debug_printf_walker 22#ifndef debug_printf_walker
22# define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__)) 23# define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__))
23#endif 24#endif
25#ifndef debug_printf_eval
26# define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__))
27#endif
24 28
25 29
26 30
@@ -700,14 +704,27 @@ static ALWAYS_INLINE int isalnum_(int c)
700 704
701static double my_strtod(char **pp) 705static double my_strtod(char **pp)
702{ 706{
707 char *cp = *pp;
703#if ENABLE_DESKTOP 708#if ENABLE_DESKTOP
704 if ((*pp)[0] == '0' 709 if (cp[0] == '0') {
705 && ((((*pp)[1] | 0x20) == 'x') || isdigit((*pp)[1])) 710 /* Might be hex or octal integer: 0x123abc or 07777 */
706 ) { 711 char c = (cp[1] | 0x20);
707 return strtoull(*pp, pp, 0); 712 if (c == 'x' || isdigit(cp[1])) {
713 unsigned long long ull = strtoull(cp, pp, 0);
714 if (c == 'x')
715 return ull;
716 c = **pp;
717 if (!isdigit(c) && c != '.')
718 return ull;
719 /* else: it may be a floating number. Examples:
720 * 009.123 (*pp points to '9')
721 * 000.123 (*pp points to '.')
722 * fall through to strtod.
723 */
724 }
708 } 725 }
709#endif 726#endif
710 return strtod(*pp, pp); 727 return strtod(cp, pp);
711} 728}
712 729
713/* -------- working with variables (set/get/copy/etc) -------- */ 730/* -------- working with variables (set/get/copy/etc) -------- */
@@ -817,17 +834,21 @@ static double getvar_i(var *v)
817 v->number = 0; 834 v->number = 0;
818 s = v->string; 835 s = v->string;
819 if (s && *s) { 836 if (s && *s) {
837 debug_printf_eval("getvar_i: '%s'->", s);
820 v->number = my_strtod(&s); 838 v->number = my_strtod(&s);
839 debug_printf_eval("%f (s:'%s')\n", v->number, s);
821 if (v->type & VF_USER) { 840 if (v->type & VF_USER) {
822 s = skip_spaces(s); 841 s = skip_spaces(s);
823 if (*s != '\0') 842 if (*s != '\0')
824 v->type &= ~VF_USER; 843 v->type &= ~VF_USER;
825 } 844 }
826 } else { 845 } else {
846 debug_printf_eval("getvar_i: '%s'->zero\n", s);
827 v->type &= ~VF_USER; 847 v->type &= ~VF_USER;
828 } 848 }
829 v->type |= VF_CACHED; 849 v->type |= VF_CACHED;
830 } 850 }
851 debug_printf_eval("getvar_i: %f\n", v->number);
831 return v->number; 852 return v->number;
832} 853}
833 854
@@ -849,6 +870,7 @@ static var *copyvar(var *dest, const var *src)
849 if (dest != src) { 870 if (dest != src) {
850 clrvar(dest); 871 clrvar(dest);
851 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR)); 872 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
873 debug_printf_eval("copyvar: number:%f string:'%s'\n", src->number, src->string);
852 dest->number = src->number; 874 dest->number = src->number;
853 if (src->string) 875 if (src->string)
854 dest->string = xstrdup(src->string); 876 dest->string = xstrdup(src->string);
@@ -965,7 +987,6 @@ static uint32_t next_token(uint32_t expected)
965 const char *tl; 987 const char *tl;
966 uint32_t tc; 988 uint32_t tc;
967 const uint32_t *ti; 989 const uint32_t *ti;
968 int l;
969 990
970 if (t_rollback) { 991 if (t_rollback) {
971 t_rollback = FALSE; 992 t_rollback = FALSE;
@@ -1031,7 +1052,7 @@ static uint32_t next_token(uint32_t expected)
1031 char *pp = p; 1052 char *pp = p;
1032 t_double = my_strtod(&pp); 1053 t_double = my_strtod(&pp);
1033 p = pp; 1054 p = pp;
1034 if (*pp == '.') 1055 if (*p == '.')
1035 syntax_error(EMSG_UNEXP_TOKEN); 1056 syntax_error(EMSG_UNEXP_TOKEN);
1036 tc = TC_NUMBER; 1057 tc = TC_NUMBER;
1037 1058
@@ -1041,52 +1062,51 @@ static uint32_t next_token(uint32_t expected)
1041 tc = 0x00000001; 1062 tc = 0x00000001;
1042 ti = tokeninfo; 1063 ti = tokeninfo;
1043 while (*tl) { 1064 while (*tl) {
1044 l = *tl++; 1065 int l = (unsigned char) *tl++;
1045 if (l == NTCC) { 1066 if (l == (unsigned char) NTCC) {
1046 tc <<= 1; 1067 tc <<= 1;
1047 continue; 1068 continue;
1048 } 1069 }
1049 /* if token class is expected, token 1070 /* if token class is expected,
1050 * matches and it's not a longer word, 1071 * token matches,
1051 * then this is what we are looking for 1072 * and it's not a longer word,
1052 */ 1073 */
1053 if ((tc & (expected | TC_WORD | TC_NEWLINE)) 1074 if ((tc & (expected | TC_WORD | TC_NEWLINE))
1054 && *tl == *p && strncmp(p, tl, l) == 0 1075 && strncmp(p, tl, l) == 0
1055 && !((tc & TC_WORD) && isalnum_(p[l])) 1076 && !((tc & TC_WORD) && isalnum_(p[l]))
1056 ) { 1077 ) {
1078 /* then this is what we are looking for */
1057 t_info = *ti; 1079 t_info = *ti;
1058 p += l; 1080 p += l;
1059 break; 1081 goto token_found;
1060 } 1082 }
1061 ti++; 1083 ti++;
1062 tl += l; 1084 tl += l;
1063 } 1085 }
1064 1086 /* not a known token */
1065 if (!*tl) { 1087
1066 /* it's a name (var/array/function), 1088 /* is it a name? (var/array/function) */
1067 * otherwise it's something wrong 1089 if (!isalnum_(*p))
1068 */ 1090 syntax_error(EMSG_UNEXP_TOKEN); /* no */
1069 if (!isalnum_(*p)) 1091 /* yes */
1070 syntax_error(EMSG_UNEXP_TOKEN); 1092 t_string = --p;
1071 1093 while (isalnum_(*++p)) {
1072 t_string = --p; 1094 p[-1] = *p;
1073 while (isalnum_(*++p)) { 1095 }
1074 p[-1] = *p; 1096 p[-1] = '\0';
1075 } 1097 tc = TC_VARIABLE;
1076 p[-1] = '\0'; 1098 /* also consume whitespace between functionname and bracket */
1077 tc = TC_VARIABLE; 1099 if (!(expected & TC_VARIABLE) || (expected & TC_ARRAY))
1078 /* also consume whitespace between functionname and bracket */ 1100 p = skip_spaces(p);
1079 if (!(expected & TC_VARIABLE) || (expected & TC_ARRAY)) 1101 if (*p == '(') {
1080 p = skip_spaces(p); 1102 tc = TC_FUNCTION;
1081 if (*p == '(') { 1103 } else {
1082 tc = TC_FUNCTION; 1104 if (*p == '[') {
1083 } else { 1105 p++;
1084 if (*p == '[') { 1106 tc = TC_ARRAY;
1085 p++;
1086 tc = TC_ARRAY;
1087 }
1088 } 1107 }
1089 } 1108 }
1109 token_found: ;
1090 } 1110 }
1091 g_pos = p; 1111 g_pos = p;
1092 1112
@@ -1164,6 +1184,7 @@ static node *parse_expr(uint32_t iexp)
1164 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; 1184 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
1165 1185
1166 while (!((tc = next_token(xtc)) & iexp)) { 1186 while (!((tc = next_token(xtc)) & iexp)) {
1187
1167 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { 1188 if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
1168 /* input redirection (<) attached to glptr node */ 1189 /* input redirection (<) attached to glptr node */
1169 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); 1190 cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
@@ -1500,10 +1521,10 @@ static node *mk_splitter(const char *s, tsplitter *spl)
1500 regfree(re); 1521 regfree(re);
1501 regfree(ire); // TODO: nuke ire, use re+1? 1522 regfree(ire); // TODO: nuke ire, use re+1?
1502 } 1523 }
1503 if (strlen(s) > 1) { 1524 if (s[0] && s[1]) { /* strlen(s) > 1 */
1504 mk_re_node(s, n, re); 1525 mk_re_node(s, n, re);
1505 } else { 1526 } else {
1506 n->info = (uint32_t) *s; 1527 n->info = (uint32_t) s[0];
1507 } 1528 }
1508 1529
1509 return n; 1530 return n;
@@ -1560,24 +1581,22 @@ static void fsrealloc(int size)
1560 if (size >= maxfields) { 1581 if (size >= maxfields) {
1561 i = maxfields; 1582 i = maxfields;
1562 maxfields = size + 16; 1583 maxfields = size + 16;
1563 Fields = xrealloc(Fields, maxfields * sizeof(var)); 1584 Fields = xrealloc(Fields, maxfields * sizeof(Fields[0]));
1564 for (; i < maxfields; i++) { 1585 for (; i < maxfields; i++) {
1565 Fields[i].type = VF_SPECIAL; 1586 Fields[i].type = VF_SPECIAL;
1566 Fields[i].string = NULL; 1587 Fields[i].string = NULL;
1567 } 1588 }
1568 } 1589 }
1569 1590 /* if size < nfields, clear extra field variables */
1570 if (size < nfields) { 1591 for (i = size; i < nfields; i++) {
1571 for (i = size; i < nfields; i++) { 1592 clrvar(Fields + i);
1572 clrvar(Fields + i);
1573 }
1574 } 1593 }
1575 nfields = size; 1594 nfields = size;
1576} 1595}
1577 1596
1578static int awk_split(const char *s, node *spl, char **slist) 1597static int awk_split(const char *s, node *spl, char **slist)
1579{ 1598{
1580 int l, n = 0; 1599 int l, n;
1581 char c[4]; 1600 char c[4];
1582 char *s1; 1601 char *s1;
1583 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... 1602 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
@@ -1591,6 +1610,7 @@ static int awk_split(const char *s, node *spl, char **slist)
1591 if (*getvar_s(intvar[RS]) == '\0') 1610 if (*getvar_s(intvar[RS]) == '\0')
1592 c[2] = '\n'; 1611 c[2] = '\n';
1593 1612
1613 n = 0;
1594 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */ 1614 if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
1595 if (!*s) 1615 if (!*s)
1596 return n; /* "": zero fields */ 1616 return n; /* "": zero fields */
@@ -1636,7 +1656,7 @@ static int awk_split(const char *s, node *spl, char **slist)
1636 } 1656 }
1637 if (*s1) 1657 if (*s1)
1638 n++; 1658 n++;
1639 while ((s1 = strpbrk(s1, c))) { 1659 while ((s1 = strpbrk(s1, c)) != NULL) {
1640 *s1++ = '\0'; 1660 *s1++ = '\0';
1641 n++; 1661 n++;
1642 } 1662 }
@@ -2347,18 +2367,25 @@ static var *evaluate(node *op, var *res)
2347 opn = (opinfo & OPNMASK); 2367 opn = (opinfo & OPNMASK);
2348 g_lineno = op->lineno; 2368 g_lineno = op->lineno;
2349 op1 = op->l.n; 2369 op1 = op->l.n;
2370 debug_printf_eval("opinfo:%08x opn:%08x XC:%x\n", opinfo, opn, XC(opinfo & OPCLSMASK));
2350 2371
2351 /* execute inevitable things */ 2372 /* execute inevitable things */
2352 if (opinfo & OF_RES1) 2373 if (opinfo & OF_RES1)
2353 L.v = evaluate(op1, v1); 2374 L.v = evaluate(op1, v1);
2354 if (opinfo & OF_RES2) 2375 if (opinfo & OF_RES2)
2355 R.v = evaluate(op->r.n, v1+1); 2376 R.v = evaluate(op->r.n, v1+1);
2356 if (opinfo & OF_STR1) 2377 if (opinfo & OF_STR1) {
2357 L.s = getvar_s(L.v); 2378 L.s = getvar_s(L.v);
2358 if (opinfo & OF_STR2) 2379 debug_printf_eval("L.s:'%s'\n", L.s);
2380 }
2381 if (opinfo & OF_STR2) {
2359 R.s = getvar_s(R.v); 2382 R.s = getvar_s(R.v);
2360 if (opinfo & OF_NUM1) 2383 debug_printf_eval("R.s:'%s'\n", R.s);
2384 }
2385 if (opinfo & OF_NUM1) {
2361 L_d = getvar_i(L.v); 2386 L_d = getvar_i(L.v);
2387 debug_printf_eval("L_d:%f\n", L_d);
2388 }
2362 2389
2363 switch (XC(opinfo & OPCLSMASK)) { 2390 switch (XC(opinfo & OPCLSMASK)) {
2364 2391
@@ -2526,6 +2553,7 @@ static var *evaluate(node *op, var *res)
2526 break; 2553 break;
2527 2554
2528 case XC( OC_MOVE ): 2555 case XC( OC_MOVE ):
2556 debug_printf_eval("MOVE\n");
2529 /* if source is a temporary string, jusk relink it to dest */ 2557 /* if source is a temporary string, jusk relink it to dest */
2530//Disabled: if R.v is numeric but happens to have cached R.v->string, 2558//Disabled: if R.v is numeric but happens to have cached R.v->string,
2531//then L.v ends up being a string, which is wrong 2559//then L.v ends up being a string, which is wrong
@@ -2777,6 +2805,7 @@ static var *evaluate(node *op, var *res)
2777 case XC( OC_BINARY ): 2805 case XC( OC_BINARY ):
2778 case XC( OC_REPLACE ): { 2806 case XC( OC_REPLACE ): {
2779 double R_d = getvar_i(R.v); 2807 double R_d = getvar_i(R.v);
2808 debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn);
2780 switch (opn) { 2809 switch (opn) {
2781 case '+': 2810 case '+':
2782 L_d += R_d; 2811 L_d += R_d;
@@ -2805,6 +2834,7 @@ static var *evaluate(node *op, var *res)
2805 L_d -= (int)(L_d / R_d) * R_d; 2834 L_d -= (int)(L_d / R_d) * R_d;
2806 break; 2835 break;
2807 } 2836 }
2837 debug_printf_eval("BINARY/REPLACE result:%f\n", L_d);
2808 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : L.v, L_d); 2838 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : L.v, L_d);
2809 break; 2839 break;
2810 } 2840 }
diff --git a/editors/patch.c b/editors/patch.c
index c40f54155..66a9474fe 100644
--- a/editors/patch.c
+++ b/editors/patch.c
@@ -344,14 +344,12 @@ static int apply_one_hunk(void)
344 while (plist && *plist->data == "+-"[reverse]) { 344 while (plist && *plist->data == "+-"[reverse]) {
345 if (data && !strcmp(data, plist->data+1)) { 345 if (data && !strcmp(data, plist->data+1)) {
346 if (!backwarn) { 346 if (!backwarn) {
347 backwarn++; 347 backwarn = TT.linenum;
348 if (option_mask32 & FLAG_IGNORE) { 348 if (option_mask32 & FLAG_IGNORE) {
349 dummy_revert = 1; 349 dummy_revert = 1;
350 reverse ^= 1; 350 reverse ^= 1;
351 continue; 351 continue;
352 } 352 }
353 fdprintf(2,"Possibly reversed hunk %d at %ld\n",
354 TT.hunknum, TT.linenum);
355 } 353 }
356 } 354 }
357 plist = plist->next; 355 plist = plist->next;
@@ -364,6 +362,10 @@ static int apply_one_hunk(void)
364 // Does this hunk need to match EOF? 362 // Does this hunk need to match EOF?
365 if (!plist && matcheof) break; 363 if (!plist && matcheof) break;
366 364
365 if (backwarn)
366 fdprintf(2,"Possibly reversed hunk %d at %ld\n",
367 TT.hunknum, TT.linenum);
368
367 // File ended before we found a place for this hunk. 369 // File ended before we found a place for this hunk.
368 fail_hunk(); 370 fail_hunk();
369 goto done; 371 goto done;
@@ -552,7 +554,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
552 int oldsum, newsum, del = 0; 554 int oldsum, newsum, del = 0;
553 char *name; 555 char *name;
554 556
555 oldsum = TT.oldline + TT.oldlen; 557 oldsum = TT.oldline + TT.oldlen;
556 newsum = TT.newline + TT.newlen; 558 newsum = TT.newline + TT.newlen;
557 559
558 name = reverse ? oldname : newname; 560 name = reverse ? oldname : newname;
@@ -589,10 +591,10 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
589 xmkpath(name, -1); 591 xmkpath(name, -1);
590 *s = '/'; 592 *s = '/';
591 } 593 }
592 TT.filein = xopen3(name, O_CREAT|O_EXCL|O_RDWR, 0666); 594 TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR);
593 } else { 595 } else {
594 printf("patching file %s\n", name); 596 printf("patching file %s\n", name);
595 TT.filein = xopen(name, O_RDWR); 597 TT.filein = xopen(name, O_RDONLY);
596 } 598 }
597 TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname); 599 TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname);
598 TT.linenum = 0; 600 TT.linenum = 0;
diff --git a/editors/patch_toybox.c b/editors/patch_toybox.c
index 7f3234e66..a60bf070f 100644
--- a/editors/patch_toybox.c
+++ b/editors/patch_toybox.c
@@ -522,7 +522,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
522 int oldsum, newsum, del = 0; 522 int oldsum, newsum, del = 0;
523 char *s, *name; 523 char *s, *name;
524 524
525 oldsum = TT.oldline + TT.oldlen; 525 oldsum = TT.oldline + TT.oldlen;
526 newsum = TT.newline + TT.newlen; 526 newsum = TT.newline + TT.newlen;
527 527
528 name = reverse ? oldname : newname; 528 name = reverse ? oldname : newname;
@@ -559,7 +559,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
559 xmkpath(name, -1); 559 xmkpath(name, -1);
560 *s = '/'; 560 *s = '/';
561 } 561 }
562 TT.filein = xopen3(name, O_CREAT|O_EXCL|O_RDWR, 0666); 562 TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR);
563 } else { 563 } else {
564 printf("patching file %s\n", name); 564 printf("patching file %s\n", name);
565 TT.filein = xopen(name, O_RDWR); 565 TT.filein = xopen(name, O_RDWR);
diff --git a/findutils/.gitignore b/findutils/.gitignore
deleted file mode 100644
index 7a30caf5c..000000000
--- a/findutils/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
1# Config.in and Kbuild are auto-generated
2Config.in
3Kbuild
diff --git a/findutils/grep.c b/findutils/grep.c
index bf42753c5..f166aa48a 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -629,30 +629,33 @@ int grep_main(int argc UNUSED_PARAM, char **argv)
629 629
630 /* do normal option parsing */ 630 /* do normal option parsing */
631#if ENABLE_FEATURE_GREP_CONTEXT 631#if ENABLE_FEATURE_GREP_CONTEXT
632 int Copt; 632 int Copt, opts;
633 633
634 /* -H unsets -h; -C unsets -A,-B; -e,-f are lists; 634 /* -H unsets -h; -C unsets -A,-B; -e,-f are lists;
635 * -m,-A,-B,-C have numeric param */ 635 * -m,-A,-B,-C have numeric param */
636 opt_complementary = "H-h:C-AB:e::f::m+:A+:B+:C+"; 636 opt_complementary = "H-h:C-AB:e::f::m+:A+:B+:C+";
637 getopt32(argv, 637 opts = getopt32(argv,
638 OPTSTR_GREP, 638 OPTSTR_GREP,
639 &pattern_head, &fopt, &max_matches, 639 &pattern_head, &fopt, &max_matches,
640 &lines_after, &lines_before, &Copt); 640 &lines_after, &lines_before, &Copt);
641 641
642 if (option_mask32 & OPT_C) { 642 if (opts & OPT_C) {
643 /* -C unsets prev -A and -B, but following -A or -B 643 /* -C unsets prev -A and -B, but following -A or -B
644 may override it */ 644 may override it */
645 if (!(option_mask32 & OPT_A)) /* not overridden */ 645 if (!(opts & OPT_A)) /* not overridden */
646 lines_after = Copt; 646 lines_after = Copt;
647 if (!(option_mask32 & OPT_B)) /* not overridden */ 647 if (!(opts & OPT_B)) /* not overridden */
648 lines_before = Copt; 648 lines_before = Copt;
649 } 649 }
650 /* sanity checks */ 650 /* sanity checks */
651 if (option_mask32 & (OPT_c|OPT_q|OPT_l|OPT_L)) { 651 if (opts & (OPT_c|OPT_q|OPT_l|OPT_L)) {
652 option_mask32 &= ~OPT_n; 652 option_mask32 &= ~OPT_n;
653 lines_before = 0; 653 lines_before = 0;
654 lines_after = 0; 654 lines_after = 0;
655 } else if (lines_before > 0) { 655 } else if (lines_before > 0) {
656 if (lines_before > INT_MAX / sizeof(long long))
657 lines_before = INT_MAX / sizeof(long long);
658 /* overflow in (lines_before * sizeof(x)) is prevented (above) */
656 before_buf = xzalloc(lines_before * sizeof(before_buf[0])); 659 before_buf = xzalloc(lines_before * sizeof(before_buf[0]));
657 IF_EXTRA_COMPAT(before_buf_size = xzalloc(lines_before * sizeof(before_buf_size[0]));) 660 IF_EXTRA_COMPAT(before_buf_size = xzalloc(lines_before * sizeof(before_buf_size[0]));)
658 } 661 }
diff --git a/include/applets.src.h b/include/applets.src.h
index 0e4f966de..879dbf760 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -56,11 +56,6 @@ s - suid type:
56# define APPLET_NOFORK(name,main,l,s,name2) { #name, #main, l, s, 1, 1 }, 56# define APPLET_NOFORK(name,main,l,s,name2) { #name, #main, l, s, 1, 1 },
57#endif 57#endif
58 58
59#if ENABLE_INSTALL_NO_USR
60# define _BB_DIR_USR_BIN _BB_DIR_BIN
61# define _BB_DIR_USR_SBIN _BB_DIR_SBIN
62#endif
63
64 59
65INSERT 60INSERT
66IF_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_DROP, test)) 61IF_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_DROP, test))
@@ -77,7 +72,6 @@ IF_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_DROP, ba
77IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_DROP)) 72IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_DROP))
78IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 73IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP))
79IF_BLKID(APPLET(blkid, _BB_DIR_SBIN, _BB_SUID_DROP)) 74IF_BLKID(APPLET(blkid, _BB_DIR_SBIN, _BB_SUID_DROP))
80IF_BOOTCHARTD(APPLET(bootchartd, _BB_DIR_SBIN, _BB_SUID_DROP))
81IF_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 75IF_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
82IF_BZIP2(APPLET(bzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 76IF_BZIP2(APPLET(bzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP))
83IF_CAL(APPLET(cal, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 77IF_CAL(APPLET(cal, _BB_DIR_USR_BIN, _BB_SUID_DROP))
@@ -94,7 +88,7 @@ IF_CHPST(APPLET(chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP))
94IF_CHROOT(APPLET(chroot, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 88IF_CHROOT(APPLET(chroot, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
95IF_CHRT(APPLET(chrt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 89IF_CHRT(APPLET(chrt, _BB_DIR_USR_BIN, _BB_SUID_DROP))
96IF_CHVT(APPLET(chvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 90IF_CHVT(APPLET(chvt, _BB_DIR_USR_BIN, _BB_SUID_DROP))
97IF_CKSUM(APPLET(cksum, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 91IF_CKSUM(APPLET_NOEXEC(cksum, cksum, _BB_DIR_USR_BIN, _BB_SUID_DROP, cksum))
98IF_CLEAR(APPLET(clear, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 92IF_CLEAR(APPLET(clear, _BB_DIR_USR_BIN, _BB_SUID_DROP))
99IF_CMP(APPLET(cmp, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 93IF_CMP(APPLET(cmp, _BB_DIR_USR_BIN, _BB_SUID_DROP))
100IF_COMM(APPLET(comm, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 94IF_COMM(APPLET(comm, _BB_DIR_USR_BIN, _BB_SUID_DROP))
@@ -104,14 +98,11 @@ IF_CROND(APPLET(crond, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
104IF_CRONTAB(APPLET(crontab, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) 98IF_CRONTAB(APPLET(crontab, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE))
105IF_CRYPTPW(APPLET(cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 99IF_CRYPTPW(APPLET(cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP))
106IF_CUT(APPLET_NOEXEC(cut, cut, _BB_DIR_USR_BIN, _BB_SUID_DROP, cut)) 100IF_CUT(APPLET_NOEXEC(cut, cut, _BB_DIR_USR_BIN, _BB_SUID_DROP, cut))
107IF_DATE(APPLET(date, _BB_DIR_BIN, _BB_SUID_DROP))
108IF_DC(APPLET(dc, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 101IF_DC(APPLET(dc, _BB_DIR_USR_BIN, _BB_SUID_DROP))
109IF_DD(APPLET_NOEXEC(dd, dd, _BB_DIR_BIN, _BB_SUID_DROP, dd)) 102IF_DD(APPLET_NOEXEC(dd, dd, _BB_DIR_BIN, _BB_SUID_DROP, dd))
110IF_DEALLOCVT(APPLET(deallocvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 103IF_DEALLOCVT(APPLET(deallocvt, _BB_DIR_USR_BIN, _BB_SUID_DROP))
111IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_DROP, delgroup)) 104IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_DROP, delgroup))
112IF_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_DROP)) 105IF_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_DROP))
113IF_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_DROP))
114IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe))
115IF_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_DROP)) 106IF_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_DROP))
116IF_DEVMEM(APPLET(devmem, _BB_DIR_SBIN, _BB_SUID_DROP)) 107IF_DEVMEM(APPLET(devmem, _BB_DIR_SBIN, _BB_SUID_DROP))
117IF_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_DROP)) 108IF_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_DROP))
@@ -121,7 +112,7 @@ IF_DIRNAME(APPLET_NOFORK(dirname, dirname, _BB_DIR_USR_BIN, _BB_SUID_DROP, dirna
121IF_DMESG(APPLET(dmesg, _BB_DIR_BIN, _BB_SUID_DROP)) 112IF_DMESG(APPLET(dmesg, _BB_DIR_BIN, _BB_SUID_DROP))
122IF_DNSD(APPLET(dnsd, _BB_DIR_USR_SBIN, _BB_SUID_REQUIRE)) 113IF_DNSD(APPLET(dnsd, _BB_DIR_USR_SBIN, _BB_SUID_REQUIRE))
123IF_HOSTNAME(APPLET_ODDNAME(dnsdomainname, hostname, _BB_DIR_BIN, _BB_SUID_DROP, dnsdomainname)) 114IF_HOSTNAME(APPLET_ODDNAME(dnsdomainname, hostname, _BB_DIR_BIN, _BB_SUID_DROP, dnsdomainname))
124IF_DOS2UNIX(APPLET(dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 115IF_DOS2UNIX(APPLET_NOEXEC(dos2unix, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP, dos2unix))
125IF_DPKG(APPLET(dpkg, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 116IF_DPKG(APPLET(dpkg, _BB_DIR_USR_BIN, _BB_SUID_DROP))
126IF_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, _BB_DIR_USR_BIN, _BB_SUID_DROP, dpkg_deb)) 117IF_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, _BB_DIR_USR_BIN, _BB_SUID_DROP, dpkg_deb))
127IF_DU(APPLET(du, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 118IF_DU(APPLET(du, _BB_DIR_USR_BIN, _BB_SUID_DROP))
@@ -152,7 +143,7 @@ IF_FLASH_LOCK(APPLET_ODDNAME(flash_lock, flash_lock_unlock, _BB_DIR_USR_SBIN, _B
152IF_FLASH_UNLOCK(APPLET_ODDNAME(flash_unlock, flash_lock_unlock, _BB_DIR_USR_SBIN, _BB_SUID_DROP, flash_unlock)) 143IF_FLASH_UNLOCK(APPLET_ODDNAME(flash_unlock, flash_lock_unlock, _BB_DIR_USR_SBIN, _BB_SUID_DROP, flash_unlock))
153IF_FLASHCP(APPLET(flashcp, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 144IF_FLASHCP(APPLET(flashcp, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
154IF_FLOCK(APPLET(flock, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 145IF_FLOCK(APPLET(flock, _BB_DIR_USR_BIN, _BB_SUID_DROP))
155IF_FOLD(APPLET(fold, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 146IF_FOLD(APPLET_NOEXEC(fold, fold, _BB_DIR_USR_BIN, _BB_SUID_DROP, fold))
156IF_FREE(APPLET(free, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 147IF_FREE(APPLET(free, _BB_DIR_USR_BIN, _BB_SUID_DROP))
157IF_FREERAMDISK(APPLET(freeramdisk, _BB_DIR_SBIN, _BB_SUID_DROP)) 148IF_FREERAMDISK(APPLET(freeramdisk, _BB_DIR_SBIN, _BB_SUID_DROP))
158IF_FSCK(APPLET(fsck, _BB_DIR_SBIN, _BB_SUID_DROP)) 149IF_FSCK(APPLET(fsck, _BB_DIR_SBIN, _BB_SUID_DROP))
@@ -170,26 +161,22 @@ IF_GETSEBOOL(APPLET(getsebool, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
170IF_GETTY(APPLET(getty, _BB_DIR_SBIN, _BB_SUID_DROP)) 161IF_GETTY(APPLET(getty, _BB_DIR_SBIN, _BB_SUID_DROP))
171IF_GUNZIP(APPLET(gunzip, _BB_DIR_BIN, _BB_SUID_DROP)) 162IF_GUNZIP(APPLET(gunzip, _BB_DIR_BIN, _BB_SUID_DROP))
172IF_GZIP(APPLET(gzip, _BB_DIR_BIN, _BB_SUID_DROP)) 163IF_GZIP(APPLET(gzip, _BB_DIR_BIN, _BB_SUID_DROP))
173IF_HALT(APPLET(halt, _BB_DIR_SBIN, _BB_SUID_DROP))
174IF_HD(APPLET_NOEXEC(hd, hexdump, _BB_DIR_USR_BIN, _BB_SUID_DROP, hd)) 164IF_HD(APPLET_NOEXEC(hd, hexdump, _BB_DIR_USR_BIN, _BB_SUID_DROP, hd))
175IF_HDPARM(APPLET(hdparm, _BB_DIR_SBIN, _BB_SUID_DROP)) 165IF_HDPARM(APPLET(hdparm, _BB_DIR_SBIN, _BB_SUID_DROP))
176IF_HEAD(APPLET(head, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 166IF_HEAD(APPLET_NOEXEC(head, head, _BB_DIR_USR_BIN, _BB_SUID_DROP, head))
177IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, _BB_DIR_USR_BIN, _BB_SUID_DROP, hexdump)) 167IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, _BB_DIR_USR_BIN, _BB_SUID_DROP, hexdump))
178IF_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_DROP, hostid)) 168IF_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_DROP, hostid))
179IF_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_DROP)) 169IF_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_DROP))
180IF_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 170IF_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
181IF_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_DROP)) 171IF_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_DROP))
182IF_ID(APPLET(id, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 172IF_ID(APPLET_NOEXEC(id, id, _BB_DIR_USR_BIN, _BB_SUID_DROP, id))
183IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) 173IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_DROP))
184IF_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, _BB_DIR_SBIN, _BB_SUID_DROP, ifdown)) 174IF_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, _BB_DIR_SBIN, _BB_SUID_DROP, ifdown))
185IF_IFENSLAVE(APPLET(ifenslave, _BB_DIR_SBIN, _BB_SUID_DROP)) 175IF_IFENSLAVE(APPLET(ifenslave, _BB_DIR_SBIN, _BB_SUID_DROP))
186IF_IFPLUGD(APPLET(ifplugd, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 176IF_IFPLUGD(APPLET(ifplugd, _BB_DIR_USR_BIN, _BB_SUID_DROP))
187IF_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, _BB_DIR_SBIN, _BB_SUID_DROP, ifup)) 177IF_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, _BB_DIR_SBIN, _BB_SUID_DROP, ifup))
188IF_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 178IF_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
189IF_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_DROP))
190IF_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_DROP)) 179IF_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_DROP))
191IF_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_DROP))
192IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe))
193IF_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 180IF_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_DROP))
194IF_IONICE(APPLET(ionice, _BB_DIR_BIN, _BB_SUID_DROP)) 181IF_IONICE(APPLET(ionice, _BB_DIR_BIN, _BB_SUID_DROP))
195#if ENABLE_FEATURE_IP_ADDRESS \ 182#if ENABLE_FEATURE_IP_ADDRESS \
@@ -217,7 +204,6 @@ IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_DROP, length))
217IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 204IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_DROP))
218IF_SETARCH(APPLET_ODDNAME(linux32, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux32)) 205IF_SETARCH(APPLET_ODDNAME(linux32, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux32))
219IF_SETARCH(APPLET_ODDNAME(linux64, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux64)) 206IF_SETARCH(APPLET_ODDNAME(linux64, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux64))
220IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, _BB_DIR_ROOT, _BB_SUID_DROP, linuxrc))
221IF_LN(APPLET_NOEXEC(ln, ln, _BB_DIR_BIN, _BB_SUID_DROP, ln)) 207IF_LN(APPLET_NOEXEC(ln, ln, _BB_DIR_BIN, _BB_SUID_DROP, ln))
222IF_LOAD_POLICY(APPLET(load_policy, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 208IF_LOAD_POLICY(APPLET(load_policy, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
223IF_LOADFONT(APPLET(loadfont, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 209IF_LOADFONT(APPLET(loadfont, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
@@ -232,8 +218,6 @@ IF_LPQ(APPLET_ODDNAME(lpq, lpqr, _BB_DIR_USR_BIN, _BB_SUID_DROP, lpq))
232IF_LPR(APPLET_ODDNAME(lpr, lpqr, _BB_DIR_USR_BIN, _BB_SUID_DROP, lpr)) 218IF_LPR(APPLET_ODDNAME(lpr, lpqr, _BB_DIR_USR_BIN, _BB_SUID_DROP, lpr))
233IF_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_DROP, ls)) 219IF_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_DROP, ls))
234IF_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_DROP)) 220IF_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_DROP))
235IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_DROP))
236IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe))
237IF_LSPCI(APPLET(lspci, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 221IF_LSPCI(APPLET(lspci, _BB_DIR_USR_BIN, _BB_SUID_DROP))
238IF_LSUSB(APPLET(lsusb, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 222IF_LSUSB(APPLET(lsusb, _BB_DIR_USR_BIN, _BB_SUID_DROP))
239IF_UNLZMA(APPLET_ODDNAME(lzcat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzcat)) 223IF_UNLZMA(APPLET_ODDNAME(lzcat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzcat))
@@ -244,25 +228,22 @@ IF_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_DROP))
244IF_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_DROP)) 228IF_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_DROP))
245IF_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_DROP)) 229IF_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_DROP))
246IF_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 230IF_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
247IF_MD5SUM(APPLET_ODDNAME(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, md5sum)) 231IF_MD5SUM(APPLET_NOEXEC(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, md5sum))
248IF_MDEV(APPLET(mdev, _BB_DIR_SBIN, _BB_SUID_DROP)) 232IF_MDEV(APPLET(mdev, _BB_DIR_SBIN, _BB_SUID_DROP))
249IF_MESG(APPLET(mesg, _BB_DIR_USR_BIN, _BB_SUID_DROP))
250IF_MICROCOM(APPLET(microcom, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 233IF_MICROCOM(APPLET(microcom, _BB_DIR_USR_BIN, _BB_SUID_DROP))
251IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, _BB_DIR_BIN, _BB_SUID_DROP, mkdir)) 234IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, _BB_DIR_BIN, _BB_SUID_DROP, mkdir))
252IF_MKFS_VFAT(APPLET_ODDNAME(mkdosfs, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_vfat)) 235IF_MKFS_VFAT(APPLET_ODDNAME(mkdosfs, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_vfat))
253IF_MKFS_EXT2(APPLET_ODDNAME(mke2fs, mkfs_ext2, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext2)) 236IF_MKFS_EXT2(APPLET_ODDNAME(mke2fs, mkfs_ext2, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext2))
254IF_MKFIFO(APPLET(mkfifo, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 237IF_MKFIFO(APPLET_NOEXEC(mkfifo, mkfifo, _BB_DIR_USR_BIN, _BB_SUID_DROP, mkfifo))
255IF_MKFS_EXT2(APPLET_ODDNAME(mkfs.ext2, mkfs_ext2, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext2)) 238IF_MKFS_EXT2(APPLET_ODDNAME(mkfs.ext2, mkfs_ext2, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext2))
256//IF_MKE2FS(APPLET_ODDNAME(mkfs.ext3, mke2fs, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext3)) 239//IF_MKE2FS(APPLET_ODDNAME(mkfs.ext3, mke2fs, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext3))
257IF_MKFS_MINIX(APPLET_ODDNAME(mkfs.minix, mkfs_minix, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_minix)) 240IF_MKFS_MINIX(APPLET_ODDNAME(mkfs.minix, mkfs_minix, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_minix))
258IF_MKFS_REISER(APPLET_ODDNAME(mkfs.reiser, mkfs_reiser, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_reiser)) 241IF_MKFS_REISER(APPLET_ODDNAME(mkfs.reiser, mkfs_reiser, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_reiser))
259IF_MKFS_VFAT(APPLET_ODDNAME(mkfs.vfat, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_vfat)) 242IF_MKFS_VFAT(APPLET_ODDNAME(mkfs.vfat, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_vfat))
260IF_MKNOD(APPLET(mknod, _BB_DIR_BIN, _BB_SUID_DROP)) 243IF_MKNOD(APPLET_NOEXEC(mknod, mknod, _BB_DIR_BIN, _BB_SUID_DROP, mknod))
261IF_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP, mkpasswd)) 244IF_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP, mkpasswd))
262IF_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_DROP)) 245IF_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_DROP))
263IF_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_DROP)) 246IF_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_DROP))
264IF_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP))
265IF_MODPROBE_SMALL(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP))
266IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP)) 247IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP))
267IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP))) 248IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP)))
268IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP)) 249IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP))
@@ -289,8 +270,7 @@ IF_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_DROP))
289IF_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_DROP)) 270IF_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_DROP))
290IF_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP, pkill)) 271IF_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP, pkill))
291IF_POPMAILDIR(APPLET(popmaildir, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 272IF_POPMAILDIR(APPLET(popmaildir, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
292IF_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_DROP, poweroff)) 273IF_PRINTENV(APPLET_NOFORK(printenv, printenv, _BB_DIR_BIN, _BB_SUID_DROP, printenv))
293IF_PRINTENV(APPLET(printenv, _BB_DIR_BIN, _BB_SUID_DROP))
294IF_PRINTF(APPLET_NOFORK(printf, printf, _BB_DIR_USR_BIN, _BB_SUID_DROP, printf)) 274IF_PRINTF(APPLET_NOFORK(printf, printf, _BB_DIR_USR_BIN, _BB_SUID_DROP, printf))
295IF_PS(APPLET(ps, _BB_DIR_BIN, _BB_SUID_DROP)) 275IF_PS(APPLET(ps, _BB_DIR_BIN, _BB_SUID_DROP))
296IF_PSCAN(APPLET(pscan, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 276IF_PSCAN(APPLET(pscan, _BB_DIR_USR_BIN, _BB_SUID_DROP))
@@ -302,7 +282,6 @@ IF_READAHEAD(APPLET(readahead, _BB_DIR_USR_BIN, _BB_SUID_DROP))
302IF_READLINK(APPLET(readlink, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 282IF_READLINK(APPLET(readlink, _BB_DIR_USR_BIN, _BB_SUID_DROP))
303IF_READPROFILE(APPLET(readprofile, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 283IF_READPROFILE(APPLET(readprofile, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
304IF_REALPATH(APPLET(realpath, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 284IF_REALPATH(APPLET(realpath, _BB_DIR_USR_BIN, _BB_SUID_DROP))
305IF_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_DROP, reboot))
306IF_REFORMIME(APPLET(reformime, _BB_DIR_BIN, _BB_SUID_DROP)) 285IF_REFORMIME(APPLET(reformime, _BB_DIR_BIN, _BB_SUID_DROP))
307IF_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 286IF_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_DROP))
308IF_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 287IF_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_DROP))
@@ -311,8 +290,6 @@ IF_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, _BB_DIR_SBIN, _BB_SUID_DROP,
311IF_RFKILL(APPLET(rfkill, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 290IF_RFKILL(APPLET(rfkill, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
312IF_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_DROP, rm)) 291IF_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_DROP, rm))
313IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_DROP, rmdir)) 292IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_DROP, rmdir))
314IF_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_DROP))
315IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe))
316IF_ROUTE(APPLET(route, _BB_DIR_SBIN, _BB_SUID_DROP)) 293IF_ROUTE(APPLET(route, _BB_DIR_SBIN, _BB_SUID_DROP))
317IF_RPM(APPLET(rpm, _BB_DIR_BIN, _BB_SUID_DROP)) 294IF_RPM(APPLET(rpm, _BB_DIR_BIN, _BB_SUID_DROP))
318IF_RPM2CPIO(APPLET(rpm2cpio, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 295IF_RPM2CPIO(APPLET(rpm2cpio, _BB_DIR_USR_BIN, _BB_SUID_DROP))
@@ -340,12 +317,13 @@ IF_SETLOGCONS(APPLET(setlogcons, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
340IF_SETSEBOOL(APPLET(setsebool, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 317IF_SETSEBOOL(APPLET(setsebool, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
341IF_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 318IF_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_DROP))
342IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, setuidgid)) 319IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, setuidgid))
343IF_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha1sum)) 320IF_SHA1SUM(APPLET_NOEXEC(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha1sum))
344IF_SHA256SUM(APPLET_ODDNAME(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha256sum)) 321IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha256sum))
345IF_SHA512SUM(APPLET_ODDNAME(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum)) 322IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum))
346IF_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 323IF_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_DROP))
347IF_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_DROP)) 324IF_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_DROP))
348IF_SLEEP(APPLET_NOFORK(sleep, sleep, _BB_DIR_BIN, _BB_SUID_DROP, sleep)) 325/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */
326IF_SLEEP(APPLET(sleep, _BB_DIR_BIN, _BB_SUID_DROP))
349IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, softlimit)) 327IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, softlimit))
350IF_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_DROP, sort)) 328IF_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_DROP, sort))
351IF_SPLIT(APPLET(split, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 329IF_SPLIT(APPLET(split, _BB_DIR_USR_BIN, _BB_SUID_DROP))
@@ -358,7 +336,7 @@ IF_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_DROP))
358IF_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 336IF_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_DROP))
359IF_SV(APPLET(sv, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 337IF_SV(APPLET(sv, _BB_DIR_USR_BIN, _BB_SUID_DROP))
360IF_SVLOGD(APPLET(svlogd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 338IF_SVLOGD(APPLET(svlogd, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
361IF_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_DROP,swapoff)) 339IF_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_DROP, swapoff))
362IF_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_DROP, swapon)) 340IF_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_DROP, swapon))
363IF_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_DROP)) 341IF_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_DROP))
364IF_SYNC(APPLET_NOFORK(sync, sync, _BB_DIR_BIN, _BB_SUID_DROP, sync)) 342IF_SYNC(APPLET_NOFORK(sync, sync, _BB_DIR_BIN, _BB_SUID_DROP, sync))
@@ -398,7 +376,7 @@ IF_UNAME(APPLET(uname, _BB_DIR_BIN, _BB_SUID_DROP))
398IF_UNCOMPRESS(APPLET(uncompress, _BB_DIR_BIN, _BB_SUID_DROP)) 376IF_UNCOMPRESS(APPLET(uncompress, _BB_DIR_BIN, _BB_SUID_DROP))
399IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, _BB_DIR_USR_BIN, _BB_SUID_DROP, unexpand)) 377IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, _BB_DIR_USR_BIN, _BB_SUID_DROP, unexpand))
400IF_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 378IF_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_DROP))
401IF_UNIX2DOS(APPLET_ODDNAME(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP, unix2dos)) 379IF_UNIX2DOS(APPLET_NOEXEC(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP, unix2dos))
402IF_UNXZ(APPLET(unxz, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 380IF_UNXZ(APPLET(unxz, _BB_DIR_USR_BIN, _BB_SUID_DROP))
403IF_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 381IF_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP))
404IF_LZOP(APPLET_ODDNAME(unlzop, lzop, _BB_DIR_USR_BIN, _BB_SUID_DROP, unlzop)) 382IF_LZOP(APPLET_ODDNAME(unlzop, lzop, _BB_DIR_USR_BIN, _BB_SUID_DROP, unlzop))
diff --git a/include/busybox.h b/include/busybox.h
index 76415dd72..757317fc7 100644
--- a/include/busybox.h
+++ b/include/busybox.h
@@ -16,8 +16,13 @@ typedef enum bb_install_loc_t {
16 _BB_DIR_ROOT = 0, 16 _BB_DIR_ROOT = 0,
17 _BB_DIR_BIN, 17 _BB_DIR_BIN,
18 _BB_DIR_SBIN, 18 _BB_DIR_SBIN,
19#if ENABLE_INSTALL_NO_USR
20 _BB_DIR_USR_BIN = _BB_DIR_BIN,
21 _BB_DIR_USR_SBIN = _BB_DIR_SBIN,
22#else
19 _BB_DIR_USR_BIN, 23 _BB_DIR_USR_BIN,
20 _BB_DIR_USR_SBIN 24 _BB_DIR_USR_SBIN,
25#endif
21} bb_install_loc_t; 26} bb_install_loc_t;
22 27
23typedef enum bb_suid_t { 28typedef enum bb_suid_t {
diff --git a/include/libbb.h b/include/libbb.h
index 221837b64..9ece2f9ec 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1522,37 +1522,42 @@ unsigned get_cpu_count(void) FAST_FUNC;
1522extern const char bb_uuenc_tbl_base64[]; 1522extern const char bb_uuenc_tbl_base64[];
1523extern const char bb_uuenc_tbl_std[]; 1523extern const char bb_uuenc_tbl_std[];
1524void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC; 1524void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC;
1525enum {
1526 BASE64_FLAG_UU_STOP = 0x100,
1527 /* Sign-extends to a value which never matches fgetc result: */
1528 BASE64_FLAG_NO_STOP_CHAR = 0x80,
1529};
1530void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags);
1525 1531
1526typedef struct sha1_ctx_t { 1532typedef struct sha1_ctx_t {
1527 uint32_t hash[8]; /* 5, +3 elements for sha256 */ 1533 uint32_t hash[8]; /* 5, +3 elements for sha256 */
1528 uint64_t total64; 1534 uint64_t total64; /* must be directly after hash[] */
1529 uint8_t wbuffer[64]; /* NB: always correctly aligned for uint64_t */ 1535 uint8_t wbuffer[64]; /* NB: always correctly aligned for uint64_t */
1530 void (*process_block)(struct sha1_ctx_t*) FAST_FUNC; 1536 void (*process_block)(struct sha1_ctx_t*) FAST_FUNC;
1531} sha1_ctx_t; 1537} sha1_ctx_t;
1532void sha1_begin(sha1_ctx_t *ctx) FAST_FUNC; 1538void sha1_begin(sha1_ctx_t *ctx) FAST_FUNC;
1533void sha1_hash(const void *data, size_t length, sha1_ctx_t *ctx) FAST_FUNC; 1539void sha1_hash(sha1_ctx_t *ctx, const void *data, size_t length) FAST_FUNC;
1534void sha1_end(void *resbuf, sha1_ctx_t *ctx) FAST_FUNC; 1540void sha1_end(sha1_ctx_t *ctx, void *resbuf) FAST_FUNC;
1535typedef struct sha1_ctx_t sha256_ctx_t; 1541typedef struct sha1_ctx_t sha256_ctx_t;
1536void sha256_begin(sha256_ctx_t *ctx) FAST_FUNC; 1542void sha256_begin(sha256_ctx_t *ctx) FAST_FUNC;
1537#define sha256_hash sha1_hash 1543#define sha256_hash sha1_hash
1538#define sha256_end sha1_end 1544#define sha256_end sha1_end
1539typedef struct sha512_ctx_t { 1545typedef struct sha512_ctx_t {
1540 uint64_t hash[8]; 1546 uint64_t hash[8];
1541 uint64_t total64[2]; 1547 uint64_t total64[2]; /* must be directly after hash[] */
1542 uint8_t wbuffer[128]; /* NB: always correctly aligned for uint64_t */ 1548 uint8_t wbuffer[128]; /* NB: always correctly aligned for uint64_t */
1543} sha512_ctx_t; 1549} sha512_ctx_t;
1544void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; 1550void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC;
1545void sha512_hash(const void *buffer, size_t len, sha512_ctx_t *ctx) FAST_FUNC; 1551void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC;
1546void sha512_end(void *resbuf, sha512_ctx_t *ctx) FAST_FUNC; 1552void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC;
1547#if 1 1553#if 1
1548typedef struct md5_ctx_t { 1554typedef struct md5_ctx_t {
1549 uint32_t A; 1555 uint32_t A;
1550 uint32_t B; 1556 uint32_t B;
1551 uint32_t C; 1557 uint32_t C;
1552 uint32_t D; 1558 uint32_t D;
1553 uint64_t total; 1559 uint64_t total64;
1554 uint32_t buflen; 1560 char wbuffer[64];
1555 char buffer[128];
1556} md5_ctx_t; 1561} md5_ctx_t;
1557#else 1562#else
1558/* libbb/md5prime.c uses a bit different one: */ 1563/* libbb/md5prime.c uses a bit different one: */
@@ -1563,8 +1568,8 @@ typedef struct md5_ctx_t {
1563} md5_ctx_t; 1568} md5_ctx_t;
1564#endif 1569#endif
1565void md5_begin(md5_ctx_t *ctx) FAST_FUNC; 1570void md5_begin(md5_ctx_t *ctx) FAST_FUNC;
1566void md5_hash(const void *data, size_t length, md5_ctx_t *ctx) FAST_FUNC; 1571void md5_hash(md5_ctx_t *ctx, const void *data, size_t length) FAST_FUNC;
1567void md5_end(void *resbuf, md5_ctx_t *ctx) FAST_FUNC; 1572void md5_end(md5_ctx_t *ctx, void *resbuf) FAST_FUNC;
1568 1573
1569 1574
1570uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; 1575uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC;
diff --git a/include/platform.h b/include/platform.h
index 2b3ad42bd..ed8c137e1 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -215,6 +215,8 @@
215# define SWAP_LE16(x) bswap_16(x) 215# define SWAP_LE16(x) bswap_16(x)
216# define SWAP_LE32(x) bswap_32(x) 216# define SWAP_LE32(x) bswap_32(x)
217# define SWAP_LE64(x) bswap_64(x) 217# define SWAP_LE64(x) bswap_64(x)
218# define IF_BIG_ENDIAN(...) __VA_ARGS__
219# define IF_LITTLE_ENDIAN(...)
218#else 220#else
219# define SWAP_BE16(x) bswap_16(x) 221# define SWAP_BE16(x) bswap_16(x)
220# define SWAP_BE32(x) bswap_32(x) 222# define SWAP_BE32(x) bswap_32(x)
@@ -222,6 +224,8 @@
222# define SWAP_LE16(x) (x) 224# define SWAP_LE16(x) (x)
223# define SWAP_LE32(x) (x) 225# define SWAP_LE32(x) (x)
224# define SWAP_LE64(x) (x) 226# define SWAP_LE64(x) (x)
227# define IF_BIG_ENDIAN(...)
228# define IF_LITTLE_ENDIAN(...) __VA_ARGS__
225#endif 229#endif
226 230
227/* ---- Unaligned access ------------------------------------ */ 231/* ---- Unaligned access ------------------------------------ */
diff --git a/include/usage.src.h b/include/usage.src.h
index 2866bdbba..5d7767bb4 100644
--- a/include/usage.src.h
+++ b/include/usage.src.h
@@ -18,21 +18,27 @@
18INSERT 18INSERT
19 19
20#define acpid_trivial_usage \ 20#define acpid_trivial_usage \
21 "[-d] [-c CONFDIR] [-l LOGFILE] [-e PROC_EVENT_FILE] [EVDEV_EVENT_FILE]..." 21 "[-d] [-c CONFDIR] [-l LOGFILE] [-a ACTIONFILE] [-M MAPFILE] [-e PROC_EVENT_FILE] [-p PIDFILE]"
22#define acpid_full_usage "\n\n" \ 22#define acpid_full_usage "\n\n" \
23 "Listen to ACPI events and spawn specific helpers on event arrival\n" \ 23 "Listen to ACPI events and spawn specific helpers on event arrival\n" \
24 "\nOptions:" \ 24 "\nOptions:" \
25 "\n -d Don't daemonize, log to stderr" \
26 "\n -c DIR Config directory [/etc/acpi]" \ 25 "\n -c DIR Config directory [/etc/acpi]" \
26 "\n -d Don't daemonize, (implies -f)" \
27 "\n -e FILE /proc event file [/proc/acpi/event]" \ 27 "\n -e FILE /proc event file [/proc/acpi/event]" \
28 "\n -l FILE Log file [/var/log/acpid]" \ 28 "\n -f Run in foreground" \
29 "\n -l FILE Log file [/var/log/acpid.log]" \
30 "\n -p FILE Pid file [/var/run/acpid.pid]" \
31 "\n -a FILE Action file [/etc/acpid.conf]" \
32 "\n -M FILE Map file [/etc/acpi.map]" \
29 IF_FEATURE_ACPID_COMPAT( \ 33 IF_FEATURE_ACPID_COMPAT( \
30 "\n\nAccept and ignore compatibility options -g -m -s -S -v" \ 34 "\n\nAccept and ignore compatibility options -g -m -s -S -v" \
31 ) 35 )
32 36
33#define acpid_example_usage \ 37#define acpid_example_usage \
38 "Without -e option, acpid uses all /dev/input/event* files\n" \
39 "# acpid\n" \
34 "# acpid -l /var/log/my-acpi-log\n" \ 40 "# acpid -l /var/log/my-acpi-log\n" \
35 "# acpid -d /dev/input/event*\n" 41 "# acpid -e /proc/acpi/event\n"
36 42
37#define addgroup_trivial_usage \ 43#define addgroup_trivial_usage \
38 "[-g GID] " IF_FEATURE_ADDUSER_TO_GROUP("[USER] ") "GROUP" 44 "[-g GID] " IF_FEATURE_ADDUSER_TO_GROUP("[USER] ") "GROUP"
@@ -95,7 +101,7 @@ INSERT
95 "\n -n Don't resolve names" \ 101 "\n -n Don't resolve names" \
96 "\n -i IF Network interface" \ 102 "\n -i IF Network interface" \
97 "\n -D Read <hwaddr> from given device" \ 103 "\n -D Read <hwaddr> from given device" \
98 "\n -A, -p AF Protocol family" \ 104 "\n -A,-p AF Protocol family" \
99 "\n -H HWTYPE Hardware address type" \ 105 "\n -H HWTYPE Hardware address type" \
100 106
101#define arping_trivial_usage \ 107#define arping_trivial_usage \
@@ -214,7 +220,7 @@ INSERT
214 "\n -F Don't store or verify checksum" \ 220 "\n -F Don't store or verify checksum" \
215 221
216#define unlzma_trivial_usage \ 222#define unlzma_trivial_usage \
217 "[OPTIONS] [FILE]..." 223 "[-cf] [FILE]..."
218#define unlzma_full_usage "\n\n" \ 224#define unlzma_full_usage "\n\n" \
219 "Decompress FILE (or stdin)\n" \ 225 "Decompress FILE (or stdin)\n" \
220 "\nOptions:" \ 226 "\nOptions:" \
@@ -222,7 +228,7 @@ INSERT
222 "\n -f Force" \ 228 "\n -f Force" \
223 229
224#define lzma_trivial_usage \ 230#define lzma_trivial_usage \
225 "-d [OPTIONS] [FILE]..." 231 "-d [-cf] [FILE]..."
226#define lzma_full_usage "\n\n" \ 232#define lzma_full_usage "\n\n" \
227 "Decompress FILE (or stdin)\n" \ 233 "Decompress FILE (or stdin)\n" \
228 "\nOptions:" \ 234 "\nOptions:" \
@@ -236,7 +242,7 @@ INSERT
236 "Decompress to stdout" 242 "Decompress to stdout"
237 243
238#define unxz_trivial_usage \ 244#define unxz_trivial_usage \
239 "[OPTIONS] [FILE]..." 245 "[-cf] [FILE]..."
240#define unxz_full_usage "\n\n" \ 246#define unxz_full_usage "\n\n" \
241 "Decompress FILE (or stdin)\n" \ 247 "Decompress FILE (or stdin)\n" \
242 "\nOptions:" \ 248 "\nOptions:" \
@@ -244,7 +250,7 @@ INSERT
244 "\n -f Force" \ 250 "\n -f Force" \
245 251
246#define xz_trivial_usage \ 252#define xz_trivial_usage \
247 "-d [OPTIONS] [FILE]..." 253 "-d [-cf] [FILE]..."
248#define xz_full_usage "\n\n" \ 254#define xz_full_usage "\n\n" \
249 "Decompress FILE (or stdin)\n" \ 255 "Decompress FILE (or stdin)\n" \
250 "\nOptions:" \ 256 "\nOptions:" \
@@ -528,7 +534,7 @@ INSERT
528 "Print the config file used by busybox build" 534 "Print the config file used by busybox build"
529 535
530#define chrt_trivial_usage \ 536#define chrt_trivial_usage \
531 "[OPTIONS] [PRIO] [PID | PROG ARGS]" 537 "[-prfom] [PRIO] [PID | PROG ARGS]"
532#define chrt_full_usage "\n\n" \ 538#define chrt_full_usage "\n\n" \
533 "Change scheduling priority and class for a process\n" \ 539 "Change scheduling priority and class for a process\n" \
534 "\nOptions:" \ 540 "\nOptions:" \
@@ -696,46 +702,6 @@ INSERT
696 "$ echo \"Hello world\" | cut -f 2 -d ' '\n" \ 702 "$ echo \"Hello world\" | cut -f 2 -d ' '\n" \
697 "world\n" 703 "world\n"
698 704
699#define date_trivial_usage \
700 "[OPTIONS] [+FMT] [TIME]"
701#define date_full_usage "\n\n" \
702 "Display time (using +FMT), or set time\n" \
703 "\nOptions:" \
704 IF_NOT_LONG_OPTS( \
705 "\n [-s] TIME Set time to TIME" \
706 "\n -u Work in UTC (don't convert to local time)" \
707 "\n -R Output RFC-2822 compliant date string" \
708 ) IF_LONG_OPTS( \
709 "\n [-s,--set] TIME Set time to TIME" \
710 "\n -u,--utc Work in UTC (don't convert to local time)" \
711 "\n -R,--rfc-2822 Output RFC-2822 compliant date string" \
712 ) \
713 IF_FEATURE_DATE_ISOFMT( \
714 "\n -I[SPEC] Output ISO-8601 compliant date string" \
715 "\n SPEC='date' (default) for date only," \
716 "\n 'hours', 'minutes', or 'seconds' for date and" \
717 "\n time to the indicated precision" \
718 ) IF_NOT_LONG_OPTS( \
719 "\n -r FILE Display last modification time of FILE" \
720 "\n -d TIME Display TIME, not 'now'" \
721 ) IF_LONG_OPTS( \
722 "\n -r,--reference FILE Display last modification time of FILE" \
723 "\n -d,--date TIME Display TIME, not 'now'" \
724 ) \
725 IF_FEATURE_DATE_ISOFMT( \
726 "\n -D FMT Use FMT for -d TIME conversion" \
727 ) \
728 "\n" \
729 "\nRecognized TIME formats:" \
730 "\n hh:mm[:ss]" \
731 "\n [YYYY.]MM.DD-hh:mm[:ss]" \
732 "\n YYYY-MM-DD hh:mm[:ss]" \
733 "\n [[[[[YY]YY]MM]DD]hh]mm[.ss]" \
734
735#define date_example_usage \
736 "$ date\n" \
737 "Wed Apr 12 18:52:41 MDT 2000\n"
738
739#define dd_trivial_usage \ 705#define dd_trivial_usage \
740 "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" \ 706 "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" \
741 " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]") 707 " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]")
@@ -785,9 +751,6 @@ INSERT
785#define deluser_full_usage "\n\n" \ 751#define deluser_full_usage "\n\n" \
786 "Delete USER from the system" 752 "Delete USER from the system"
787 753
788#define depmod_trivial_usage NOUSAGE_STR
789#define depmod_full_usage ""
790
791#define devmem_trivial_usage \ 754#define devmem_trivial_usage \
792 "ADDRESS [WIDTH [VALUE]]" 755 "ADDRESS [WIDTH [VALUE]]"
793 756
@@ -910,7 +873,7 @@ INSERT
910 "\n nameserver NORNAL_DNS_SERVER" \ 873 "\n nameserver NORNAL_DNS_SERVER" \
911 874
912#define dos2unix_trivial_usage \ 875#define dos2unix_trivial_usage \
913 "[OPTIONS] [FILE]" 876 "[-ud] [FILE]"
914#define dos2unix_full_usage "\n\n" \ 877#define dos2unix_full_usage "\n\n" \
915 "Convert FILE in-place from DOS to Unix format.\n" \ 878 "Convert FILE in-place from DOS to Unix format.\n" \
916 "When no file is given, use stdin/stdout.\n" \ 879 "When no file is given, use stdin/stdout.\n" \
@@ -919,7 +882,7 @@ INSERT
919 "\n -d unix2dos" \ 882 "\n -d unix2dos" \
920 883
921#define unix2dos_trivial_usage \ 884#define unix2dos_trivial_usage \
922 "[OPTIONS] [FILE]" 885 "[-ud] [FILE]"
923#define unix2dos_full_usage "\n\n" \ 886#define unix2dos_full_usage "\n\n" \
924 "Convert FILE in-place from Unix to DOS format.\n" \ 887 "Convert FILE in-place from Unix to DOS format.\n" \
925 "When no file is given, use stdin/stdout.\n" \ 888 "When no file is given, use stdin/stdout.\n" \
@@ -1295,7 +1258,7 @@ INSERT
1295 "\n -w Use WIDTH columns instead of 80" \ 1258 "\n -w Use WIDTH columns instead of 80" \
1296 1259
1297#define free_trivial_usage \ 1260#define free_trivial_usage \
1298 "" 1261 "" IF_DESKTOP("[-b/k/m/g]")
1299#define free_full_usage "\n\n" \ 1262#define free_full_usage "\n\n" \
1300 "Display the amount of free and used system memory" 1263 "Display the amount of free and used system memory"
1301#define free_example_usage \ 1264#define free_example_usage \
@@ -1400,8 +1363,7 @@ INSERT
1400 "Find processes which use FILEs or PORTs\n" \ 1363 "Find processes which use FILEs or PORTs\n" \
1401 "\nOptions:" \ 1364 "\nOptions:" \
1402 "\n -m Find processes which use same fs as FILEs" \ 1365 "\n -m Find processes which use same fs as FILEs" \
1403 "\n -4 Search only IPv4 space" \ 1366 "\n -4,-6 Search only IPv4/IPv6 space" \
1404 "\n -6 Search only IPv6 space" \
1405 "\n -s Don't display PIDs" \ 1367 "\n -s Don't display PIDs" \
1406 "\n -k Kill found processes" \ 1368 "\n -k Kill found processes" \
1407 "\n -SIGNAL Signal to send (default: KILL)" \ 1369 "\n -SIGNAL Signal to send (default: KILL)" \
@@ -1479,7 +1441,7 @@ INSERT
1479 "\n -H HOST Log HOST into the utmp file as the hostname" \ 1441 "\n -H HOST Log HOST into the utmp file as the hostname" \
1480 1442
1481#define gunzip_trivial_usage \ 1443#define gunzip_trivial_usage \
1482 "[OPTIONS] [FILE]..." 1444 "[-cft] [FILE]..."
1483#define gunzip_full_usage "\n\n" \ 1445#define gunzip_full_usage "\n\n" \
1484 "Decompress FILEs (or stdin)\n" \ 1446 "Decompress FILEs (or stdin)\n" \
1485 "\nOptions:" \ 1447 "\nOptions:" \
@@ -1495,7 +1457,7 @@ INSERT
1495 "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" 1457 "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n"
1496 1458
1497#define gzip_trivial_usage \ 1459#define gzip_trivial_usage \
1498 "[OPTIONS] [FILE]..." 1460 "[-cfd] [FILE]..."
1499#define gzip_full_usage "\n\n" \ 1461#define gzip_full_usage "\n\n" \
1500 "Compress FILEs (or stdin)\n" \ 1462 "Compress FILEs (or stdin)\n" \
1501 "\nOptions:" \ 1463 "\nOptions:" \
@@ -1510,18 +1472,6 @@ INSERT
1510 "$ ls -la /tmp/busybox*\n" \ 1472 "$ ls -la /tmp/busybox*\n" \
1511 "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n" 1473 "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
1512 1474
1513#define halt_trivial_usage \
1514 "[-d DELAY] [-n] [-f]" IF_FEATURE_WTMP(" [-w]")
1515#define halt_full_usage "\n\n" \
1516 "Halt the system\n" \
1517 "\nOptions:" \
1518 "\n -d Delay interval for halting" \
1519 "\n -n No call to sync()" \
1520 "\n -f Force halt (don't go through init)" \
1521 IF_FEATURE_WTMP( \
1522 "\n -w Only write a wtmp record" \
1523 )
1524
1525#define hdparm_trivial_usage \ 1475#define hdparm_trivial_usage \
1526 "[OPTIONS] [DEVICE]" 1476 "[OPTIONS] [DEVICE]"
1527#define hdparm_full_usage "\n\n" \ 1477#define hdparm_full_usage "\n\n" \
@@ -1679,7 +1629,7 @@ INSERT
1679 "\n -i Inetd mode" \ 1629 "\n -i Inetd mode" \
1680 "\n -f Don't daemonize" \ 1630 "\n -f Don't daemonize" \
1681 "\n -v[v] Verbose" \ 1631 "\n -v[v] Verbose" \
1682 "\n -p [IP:]PORT Bind to ip:port (default *:80)" \ 1632 "\n -p [IP:]PORT Bind to IP:PORT (default *:80)" \
1683 IF_FEATURE_HTTPD_SETUID( \ 1633 IF_FEATURE_HTTPD_SETUID( \
1684 "\n -u USER[:GRP] Set uid/gid after binding to port") \ 1634 "\n -u USER[:GRP] Set uid/gid after binding to port") \
1685 IF_FEATURE_HTTPD_BASIC_AUTH( \ 1635 IF_FEATURE_HTTPD_BASIC_AUTH( \
@@ -1716,13 +1666,13 @@ INSERT
1716 "Print information about USER or the current user\n" \ 1666 "Print information about USER or the current user\n" \
1717 "\nOptions:" \ 1667 "\nOptions:" \
1718 IF_SELINUX( \ 1668 IF_SELINUX( \
1719 "\n -Z Print the security context" \ 1669 "\n -Z Security context" \
1720 ) \ 1670 ) \
1721 "\n -u Print user ID" \ 1671 "\n -u User ID" \
1722 "\n -g Print group ID" \ 1672 "\n -g Group ID" \
1723 "\n -G Print supplementary group IDs" \ 1673 "\n -G Supplementary group IDs" \
1724 "\n -n Print name instead of a number" \ 1674 "\n -n Print names instead of numbers" \
1725 "\n -r Print real user ID instead of effective ID" \ 1675 "\n -r Print real ID instead of effective ID" \
1726 1676
1727#define id_example_usage \ 1677#define id_example_usage \
1728 "$ id\n" \ 1678 "$ id\n" \
@@ -1754,10 +1704,10 @@ INSERT
1754#define ifenslave_full_usage "\n\n" \ 1704#define ifenslave_full_usage "\n\n" \
1755 "Configure network interfaces for parallel routing\n" \ 1705 "Configure network interfaces for parallel routing\n" \
1756 "\nOptions:" \ 1706 "\nOptions:" \
1757 "\n -c, --change-active Change active slave" \ 1707 "\n -c,--change-active Change active slave" \
1758 "\n -d, --detach Remove slave interface from bonding device" \ 1708 "\n -d,--detach Remove slave interface from bonding device" \
1759 "\n -f, --force Force, even if interface is not Ethernet" \ 1709 "\n -f,--force Force, even if interface is not Ethernet" \
1760/* "\n -r, --receive-slave Create a receive-only slave" */ 1710/* "\n -r,--receive-slave Create a receive-only slave" */
1761 1711
1762#define ifenslave_example_usage \ 1712#define ifenslave_example_usage \
1763 "To create a bond device, simply follow these three steps:\n" \ 1713 "To create a bond device, simply follow these three steps:\n" \
@@ -1802,7 +1752,7 @@ INSERT
1802 "\n -k Kill running daemon" \ 1752 "\n -k Kill running daemon" \
1803 1753
1804#define ifup_trivial_usage \ 1754#define ifup_trivial_usage \
1805 "[-ain"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] IFACE..." 1755 "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..."
1806#define ifup_full_usage "\n\n" \ 1756#define ifup_full_usage "\n\n" \
1807 "Options:" \ 1757 "Options:" \
1808 "\n -a De/configure all interfaces automatically" \ 1758 "\n -a De/configure all interfaces automatically" \
@@ -1816,7 +1766,7 @@ INSERT
1816 "\n -f Force de/configuration" \ 1766 "\n -f Force de/configuration" \
1817 1767
1818#define ifdown_trivial_usage \ 1768#define ifdown_trivial_usage \
1819 "[-ain"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] ifaces..." 1769 "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..."
1820#define ifdown_full_usage "\n\n" \ 1770#define ifdown_full_usage "\n\n" \
1821 "Options:" \ 1771 "Options:" \
1822 "\n -a De/configure all interfaces automatically" \ 1772 "\n -a De/configure all interfaces automatically" \
@@ -1840,138 +1790,6 @@ INSERT
1840 "\n -R N Pause services after N connects/min" \ 1790 "\n -R N Pause services after N connects/min" \
1841 "\n (default: 0 - disabled)" \ 1791 "\n (default: 0 - disabled)" \
1842 1792
1843#define init_trivial_usage \
1844 ""
1845#define init_full_usage "\n\n" \
1846 "Init is the parent of all processes"
1847
1848#define init_notes_usage \
1849"This version of init is designed to be run only by the kernel.\n" \
1850"\n" \
1851"BusyBox init doesn't support multiple runlevels. The runlevels field of\n" \
1852"the /etc/inittab file is completely ignored by BusyBox init. If you want\n" \
1853"runlevels, use sysvinit.\n" \
1854"\n" \
1855"BusyBox init works just fine without an inittab. If no inittab is found,\n" \
1856"it has the following default behavior:\n" \
1857"\n" \
1858" ::sysinit:/etc/init.d/rcS\n" \
1859" ::askfirst:/bin/sh\n" \
1860" ::ctrlaltdel:/sbin/reboot\n" \
1861" ::shutdown:/sbin/swapoff -a\n" \
1862" ::shutdown:/bin/umount -a -r\n" \
1863" ::restart:/sbin/init\n" \
1864"\n" \
1865"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \
1866"\n" \
1867" tty2::askfirst:/bin/sh\n" \
1868" tty3::askfirst:/bin/sh\n" \
1869" tty4::askfirst:/bin/sh\n" \
1870"\n" \
1871"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \
1872"\n" \
1873" <id>:<runlevels>:<action>:<process>\n" \
1874"\n" \
1875" <id>:\n" \
1876"\n" \
1877" WARNING: This field has a non-traditional meaning for BusyBox init!\n" \
1878" The id field is used by BusyBox init to specify the controlling tty for\n" \
1879" the specified process to run on. The contents of this field are\n" \
1880" appended to \"/dev/\" and used as-is. There is no need for this field to\n" \
1881" be unique, although if it isn't you may have strange results. If this\n" \
1882" field is left blank, the controlling tty is set to the console. Also\n" \
1883" note that if BusyBox detects that a serial console is in use, then only\n" \
1884" entries whose controlling tty is either the serial console or /dev/null\n" \
1885" will be run. BusyBox init does nothing with utmp. We don't need no\n" \
1886" stinkin' utmp.\n" \
1887"\n" \
1888" <runlevels>:\n" \
1889"\n" \
1890" The runlevels field is completely ignored.\n" \
1891"\n" \
1892" <action>:\n" \
1893"\n" \
1894" Valid actions include: sysinit, respawn, askfirst, wait,\n" \
1895" once, restart, ctrlaltdel, and shutdown.\n" \
1896"\n" \
1897" The available actions can be classified into two groups: actions\n" \
1898" that are run only once, and actions that are re-run when the specified\n" \
1899" process exits.\n" \
1900"\n" \
1901" Run only-once actions:\n" \
1902"\n" \
1903" 'sysinit' is the first item run on boot. init waits until all\n" \
1904" sysinit actions are completed before continuing. Following the\n" \
1905" completion of all sysinit actions, all 'wait' actions are run.\n" \
1906" 'wait' actions, like 'sysinit' actions, cause init to wait until\n" \
1907" the specified task completes. 'once' actions are asynchronous,\n" \
1908" therefore, init does not wait for them to complete. 'restart' is\n" \
1909" the action taken to restart the init process. By default this should\n" \
1910" simply run /sbin/init, but can be a script which runs pivot_root or it\n" \
1911" can do all sorts of other interesting things. The 'ctrlaltdel' init\n" \
1912" actions are run when the system detects that someone on the system\n" \
1913" console has pressed the CTRL-ALT-DEL key combination. Typically one\n" \
1914" wants to run 'reboot' at this point to cause the system to reboot.\n" \
1915" Finally the 'shutdown' action specifies the actions to taken when\n" \
1916" init is told to reboot. Unmounting filesystems and disabling swap\n" \
1917" is a very good here.\n" \
1918"\n" \
1919" Run repeatedly actions:\n" \
1920"\n" \
1921" 'respawn' actions are run after the 'once' actions. When a process\n" \
1922" started with a 'respawn' action exits, init automatically restarts\n" \
1923" it. Unlike sysvinit, BusyBox init does not stop processes from\n" \
1924" respawning out of control. The 'askfirst' actions acts just like\n" \
1925" respawn, except that before running the specified process it\n" \
1926" displays the line \"Please press Enter to activate this console.\"\n" \
1927" and then waits for the user to press enter before starting the\n" \
1928" specified process.\n" \
1929"\n" \
1930" Unrecognized actions (like initdefault) will cause init to emit an\n" \
1931" error message, and then go along with its business. All actions are\n" \
1932" run in the order they appear in /etc/inittab.\n" \
1933"\n" \
1934" <process>:\n" \
1935"\n" \
1936" Specifies the process to be executed and its command line.\n" \
1937"\n" \
1938"Example /etc/inittab file:\n" \
1939"\n" \
1940" # This is run first except when booting in single-user mode\n" \
1941" #\n" \
1942" ::sysinit:/etc/init.d/rcS\n" \
1943" \n" \
1944" # /bin/sh invocations on selected ttys\n" \
1945" #\n" \
1946" # Start an \"askfirst\" shell on the console (whatever that may be)\n" \
1947" ::askfirst:-/bin/sh\n" \
1948" # Start an \"askfirst\" shell on /dev/tty2-4\n" \
1949" tty2::askfirst:-/bin/sh\n" \
1950" tty3::askfirst:-/bin/sh\n" \
1951" tty4::askfirst:-/bin/sh\n" \
1952" \n" \
1953" # /sbin/getty invocations for selected ttys\n" \
1954" #\n" \
1955" tty4::respawn:/sbin/getty 38400 tty4\n" \
1956" tty5::respawn:/sbin/getty 38400 tty5\n" \
1957" \n" \
1958" \n" \
1959" # Example of how to put a getty on a serial line (for a terminal)\n" \
1960" #\n" \
1961" #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \
1962" #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \
1963" #\n" \
1964" # Example how to put a getty on a modem line\n" \
1965" #::respawn:/sbin/getty 57600 ttyS2\n" \
1966" \n" \
1967" # Stuff to do when restarting the init process\n" \
1968" ::restart:/sbin/init\n" \
1969" \n" \
1970" # Stuff to do before rebooting\n" \
1971" ::ctrlaltdel:/sbin/reboot\n" \
1972" ::shutdown:/bin/umount -a -r\n" \
1973" ::shutdown:/sbin/swapoff -a\n"
1974
1975#define inotifyd_trivial_usage \ 1793#define inotifyd_trivial_usage \
1976 "PROG FILE1[:MASK]..." 1794 "PROG FILE1[:MASK]..."
1977#define inotifyd_full_usage "\n\n" \ 1795#define inotifyd_full_usage "\n\n" \
@@ -2303,7 +2121,7 @@ INSERT
2303 "root\n" 2121 "root\n"
2304 2122
2305#define logread_trivial_usage \ 2123#define logread_trivial_usage \
2306 "[OPTIONS]" 2124 "[-f]"
2307#define logread_full_usage "\n\n" \ 2125#define logread_full_usage "\n\n" \
2308 "Show messages in syslogd's circular buffer\n" \ 2126 "Show messages in syslogd's circular buffer\n" \
2309 "\nOptions:" \ 2127 "\nOptions:" \
@@ -2430,11 +2248,6 @@ INSERT
2430 "\n -l List long flag names" \ 2248 "\n -l List long flag names" \
2431 "\n -v List the file's version/generation number" \ 2249 "\n -v List the file's version/generation number" \
2432 2250
2433#define lsmod_trivial_usage \
2434 ""
2435#define lsmod_full_usage "\n\n" \
2436 "List the currently loaded kernel modules"
2437
2438#define lspci_trivial_usage \ 2251#define lspci_trivial_usage \
2439 "[-mk]" 2252 "[-mk]"
2440#define lspci_full_usage "\n\n" \ 2253#define lspci_full_usage "\n\n" \
@@ -2520,7 +2333,7 @@ INSERT
2520 "\nOther options are silently ignored" \ 2333 "\nOther options are silently ignored" \
2521 2334
2522#define man_trivial_usage \ 2335#define man_trivial_usage \
2523 "[OPTIONS] [MANPAGE]..." 2336 "[-aw] [MANPAGE]..."
2524#define man_full_usage "\n\n" \ 2337#define man_full_usage "\n\n" \
2525 "Format and display manual page\n" \ 2338 "Format and display manual page\n" \
2526 "\nOptions:" \ 2339 "\nOptions:" \
@@ -2537,8 +2350,8 @@ INSERT
2537 "\n -V Verify file context on disk matches defaults" \ 2350 "\n -V Verify file context on disk matches defaults" \
2538 2351
2539#define md5sum_trivial_usage \ 2352#define md5sum_trivial_usage \
2540 "[OPTIONS] [FILE]..." \ 2353 "[FILE]..." \
2541 IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: md5sum [OPTIONS] -c [FILE]") 2354 IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: md5sum -c [-sw] [FILE]")
2542#define md5sum_full_usage "\n\n" \ 2355#define md5sum_full_usage "\n\n" \
2543 "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " MD5 checksums" \ 2356 "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " MD5 checksums" \
2544 IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ 2357 IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \
@@ -2559,8 +2372,8 @@ INSERT
2559 "^D\n" 2372 "^D\n"
2560 2373
2561#define sha1sum_trivial_usage \ 2374#define sha1sum_trivial_usage \
2562 "[OPTIONS] [FILE]..." \ 2375 "[FILE]..." \
2563 IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha1sum [OPTIONS] -c [FILE]") 2376 IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha1sum -c [-sw] [FILE]")
2564#define sha1sum_full_usage "\n\n" \ 2377#define sha1sum_full_usage "\n\n" \
2565 "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums" \ 2378 "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums" \
2566 IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ 2379 IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \
@@ -2571,8 +2384,8 @@ INSERT
2571 ) 2384 )
2572 2385
2573#define sha256sum_trivial_usage \ 2386#define sha256sum_trivial_usage \
2574 "[OPTIONS] [FILE]..." \ 2387 "[FILE]..." \
2575 IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha256sum [OPTIONS] -c [FILE]") 2388 IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha256sum -c [-sw] [FILE]")
2576#define sha256sum_full_usage "\n\n" \ 2389#define sha256sum_full_usage "\n\n" \
2577 "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA256 checksums" \ 2390 "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA256 checksums" \
2578 IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ 2391 IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \
@@ -2583,8 +2396,8 @@ INSERT
2583 ) 2396 )
2584 2397
2585#define sha512sum_trivial_usage \ 2398#define sha512sum_trivial_usage \
2586 "[OPTIONS] [FILE]..." \ 2399 "[FILE]..." \
2587 IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha512sum [OPTIONS] -c [FILE]") 2400 IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha512sum -c [-sw] [FILE]")
2588#define sha512sum_full_usage "\n\n" \ 2401#define sha512sum_full_usage "\n\n" \
2589 "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA512 checksums" \ 2402 "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA512 checksums" \
2590 IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ 2403 IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \
@@ -2628,13 +2441,6 @@ INSERT
2628 "the last line match .* to override this.)\n\n" \ 2441 "the last line match .* to override this.)\n\n" \
2629 ) 2442 )
2630 2443
2631#define mesg_trivial_usage \
2632 "[y|n]"
2633#define mesg_full_usage "\n\n" \
2634 "Control write access to your terminal\n" \
2635 " y Allow write access to your terminal\n" \
2636 " n Disallow write access to your terminal"
2637
2638#define microcom_trivial_usage \ 2444#define microcom_trivial_usage \
2639 "[-d DELAY] [-t TIMEOUT] [-s SPEED] [-X] TTY" 2445 "[-d DELAY] [-t TIMEOUT] [-s SPEED] [-X] TTY"
2640#define microcom_full_usage "\n\n" \ 2446#define microcom_full_usage "\n\n" \
@@ -2651,7 +2457,7 @@ INSERT
2651#define mkdir_full_usage "\n\n" \ 2457#define mkdir_full_usage "\n\n" \
2652 "Create DIRECTORY\n" \ 2458 "Create DIRECTORY\n" \
2653 "\nOptions:" \ 2459 "\nOptions:" \
2654 "\n -m Mode" \ 2460 "\n -m MODE Mode" \
2655 "\n -p No error if exists; make parent directories as needed" \ 2461 "\n -p No error if exists; make parent directories as needed" \
2656 IF_SELINUX( \ 2462 IF_SELINUX( \
2657 "\n -Z Set security context" \ 2463 "\n -Z Set security context" \
@@ -2666,9 +2472,9 @@ INSERT
2666 "$ mkdir -p /tmp/foo/bar/baz\n" 2472 "$ mkdir -p /tmp/foo/bar/baz\n"
2667 2473
2668#define mkfifo_trivial_usage \ 2474#define mkfifo_trivial_usage \
2669 "[OPTIONS] name" 2475 "[-m MODE] " IF_SELINUX("[-Z] ") "NAME"
2670#define mkfifo_full_usage "\n\n" \ 2476#define mkfifo_full_usage "\n\n" \
2671 "Create named pipe (identical to 'mknod name p')\n" \ 2477 "Create named pipe\n" \
2672 "\nOptions:" \ 2478 "\nOptions:" \
2673 "\n -m MODE Mode (default a=rw)" \ 2479 "\n -m MODE Mode (default a=rw)" \
2674 IF_SELINUX( \ 2480 IF_SELINUX( \
@@ -2750,25 +2556,25 @@ INSERT
2750 "\n -n LBL Volume label" \ 2556 "\n -n LBL Volume label" \
2751 2557
2752#define mknod_trivial_usage \ 2558#define mknod_trivial_usage \
2753 "[OPTIONS] NAME TYPE MAJOR MINOR" 2559 "[-m MODE] " IF_SELINUX("[-Z] ") "NAME TYPE MAJOR MINOR"
2754#define mknod_full_usage "\n\n" \ 2560#define mknod_full_usage "\n\n" \
2755 "Create a special file (block, character, or pipe)\n" \ 2561 "Create a special file (block, character, or pipe)\n" \
2756 "\nOptions:" \ 2562 "\nOptions:" \
2757 "\n -m Create the special file using the specified mode (default a=rw)" \ 2563 "\n -m MODE Creation mode (default a=rw)" \
2758 "\nTYPEs include:" \
2759 "\n b: Make a block device" \
2760 "\n c or u: Make a character device" \
2761 "\n p: Make a named pipe (MAJOR and MINOR are ignored)" \
2762 IF_SELINUX( \ 2564 IF_SELINUX( \
2763 "\n -Z Set security context" \ 2565 "\n -Z Set security context" \
2764 ) 2566 ) \
2567 "\nTYPE:" \
2568 "\n b Block device" \
2569 "\n c or u Character device" \
2570 "\n p Named pipe (MAJOR and MINOR are ignored)" \
2765 2571
2766#define mknod_example_usage \ 2572#define mknod_example_usage \
2767 "$ mknod /dev/fd0 b 2 0\n" \ 2573 "$ mknod /dev/fd0 b 2 0\n" \
2768 "$ mknod -m 644 /tmp/pipe p\n" 2574 "$ mknod -m 644 /tmp/pipe p\n"
2769 2575
2770#define mkswap_trivial_usage \ 2576#define mkswap_trivial_usage \
2771 "[OPTIONS] BLOCKDEV [KBYTES]" 2577 "[-L LBL] BLOCKDEV [KBYTES]"
2772#define mkswap_full_usage "\n\n" \ 2578#define mkswap_full_usage "\n\n" \
2773 "Prepare BLOCKDEV to be used as swap partition\n" \ 2579 "Prepare BLOCKDEV to be used as swap partition\n" \
2774 "\nOptions:" \ 2580 "\nOptions:" \
@@ -2890,8 +2696,8 @@ INSERT
2890 "setpart tell unload unlock weof wset" \ 2696 "setpart tell unload unlock weof wset" \
2891 2697
2892#define mv_trivial_usage \ 2698#define mv_trivial_usage \
2893 "[OPTIONS] SOURCE DEST\n" \ 2699 "[-fi] SOURCE DEST\n" \
2894 "or: mv [OPTIONS] SOURCE... DIRECTORY" 2700 "or: mv [-fi] SOURCE... DIRECTORY"
2895#define mv_full_usage "\n\n" \ 2701#define mv_full_usage "\n\n" \
2896 "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n" \ 2702 "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n" \
2897 "\nOptions:" \ 2703 "\nOptions:" \
@@ -3026,7 +2832,7 @@ INSERT
3026 "Change USER's password. If no USER is specified,\n" \ 2832 "Change USER's password. If no USER is specified,\n" \
3027 "changes the password for the current user.\n" \ 2833 "changes the password for the current user.\n" \
3028 "\nOptions:" \ 2834 "\nOptions:" \
3029 "\n -a Algorithm to use for password (des, md5)" /* ", sha1)" */ \ 2835 "\n -a ALG Algorithm to use for password (des, md5)" /* ", sha1)" */ \
3030 "\n -d Delete password for the account" \ 2836 "\n -d Delete password for the account" \
3031 "\n -l Lock (disable) account" \ 2837 "\n -l Lock (disable) account" \
3032 "\n -u Unlock (re-enable) account" \ 2838 "\n -u Unlock (re-enable) account" \
@@ -3093,10 +2899,12 @@ INSERT
3093 "List PIDs of all processes with names that match NAMEs" \ 2899 "List PIDs of all processes with names that match NAMEs" \
3094 USAGE_PIDOF \ 2900 USAGE_PIDOF \
3095 IF_FEATURE_PIDOF_SINGLE( \ 2901 IF_FEATURE_PIDOF_SINGLE( \
3096 "\n -s Show only one PID") \ 2902 "\n -s Show only one PID" \
2903 ) \
3097 IF_FEATURE_PIDOF_OMIT( \ 2904 IF_FEATURE_PIDOF_OMIT( \
3098 "\n -o PID Omit given pid" \ 2905 "\n -o PID Omit given pid" \
3099 "\n Use %PPID to omit pid of pidof's parent") \ 2906 "\n Use %PPID to omit pid of pidof's parent" \
2907 ) \
3100 2908
3101#define pidof_example_usage \ 2909#define pidof_example_usage \
3102 "$ pidof init\n" \ 2910 "$ pidof init\n" \
@@ -3121,7 +2929,7 @@ INSERT
3121#define ping_full_usage "\n\n" \ 2929#define ping_full_usage "\n\n" \
3122 "Send ICMP ECHO_REQUEST packets to network hosts\n" \ 2930 "Send ICMP ECHO_REQUEST packets to network hosts\n" \
3123 "\nOptions:" \ 2931 "\nOptions:" \
3124 "\n -4, -6 Force IP or IPv6 name resolution" \ 2932 "\n -4,-6 Force IP or IPv6 name resolution" \
3125 "\n -c CNT Send only CNT pings" \ 2933 "\n -c CNT Send only CNT pings" \
3126 "\n -s SIZE Send SIZE data bytes in packets (default:56)" \ 2934 "\n -s SIZE Send SIZE data bytes in packets (default:56)" \
3127 "\n -I IFACE/IP Use interface or IP address as source" \ 2935 "\n -I IFACE/IP Use interface or IP address as source" \
@@ -3216,15 +3024,6 @@ INSERT
3216 "$ popmaildir -k ~/Maildir -- nc pop.drvv.ru 110 [<password_file]\n" \ 3024 "$ popmaildir -k ~/Maildir -- nc pop.drvv.ru 110 [<password_file]\n" \
3217 "$ popmaildir ~/Maildir -- openssl s_client -quiet -connect pop.gmail.com:995 [<password_file]\n" 3025 "$ popmaildir ~/Maildir -- openssl s_client -quiet -connect pop.gmail.com:995 [<password_file]\n"
3218 3026
3219#define poweroff_trivial_usage \
3220 "[-d DELAY] [-n] [-f]"
3221#define poweroff_full_usage "\n\n" \
3222 "Halt and shut off power\n" \
3223 "\nOptions:" \
3224 "\n -d Delay interval for halting" \
3225 "\n -n Do not sync" \
3226 "\n -f Force power off (don't go through init)" \
3227
3228#define printenv_trivial_usage \ 3027#define printenv_trivial_usage \
3229 "[VARIABLE]..." 3028 "[VARIABLE]..."
3230#define printenv_full_usage "\n\n" \ 3029#define printenv_full_usage "\n\n" \
@@ -3367,15 +3166,6 @@ INSERT
3367#define realpath_full_usage "\n\n" \ 3166#define realpath_full_usage "\n\n" \
3368 "Return the absolute pathnames of given FILE" 3167 "Return the absolute pathnames of given FILE"
3369 3168
3370#define reboot_trivial_usage \
3371 "[-d DELAY] [-n] [-f]"
3372#define reboot_full_usage "\n\n" \
3373 "Reboot the system\n" \
3374 "\nOptions:" \
3375 "\n -d Delay interval for rebooting" \
3376 "\n -n No call to sync()" \
3377 "\n -f Force reboot (don't go through init)" \
3378
3379#define reformime_trivial_usage \ 3169#define reformime_trivial_usage \
3380 "[OPTIONS] [FILE]..." 3170 "[OPTIONS] [FILE]..."
3381#define reformime_full_usage "\n\n" \ 3171#define reformime_full_usage "\n\n" \
@@ -3431,7 +3221,7 @@ INSERT
3431 "\n wimax, wwan, gps, fm" \ 3221 "\n wimax, wwan, gps, fm" \
3432 3222
3433#define rm_trivial_usage \ 3223#define rm_trivial_usage \
3434 "[OPTIONS] FILE..." 3224 "[-irf] FILE..."
3435#define rm_full_usage "\n\n" \ 3225#define rm_full_usage "\n\n" \
3436 "Remove (unlink) FILEs\n" \ 3226 "Remove (unlink) FILEs\n" \
3437 "\nOptions:" \ 3227 "\nOptions:" \
@@ -3458,18 +3248,6 @@ INSERT
3458#define rmdir_example_usage \ 3248#define rmdir_example_usage \
3459 "# rmdir /tmp/foo\n" 3249 "# rmdir /tmp/foo\n"
3460 3250
3461#define rmmod_trivial_usage \
3462 "[OPTIONS] [MODULE]..."
3463#define rmmod_full_usage "\n\n" \
3464 "Unload the specified kernel modules from the kernel\n" \
3465 "\nOptions:" \
3466 "\n -w Wait until the module is no longer used" \
3467 "\n -f Force unloading" \
3468 "\n -a Remove all unused modules (recursively)" \
3469
3470#define rmmod_example_usage \
3471 "$ rmmod tulip\n"
3472
3473#define route_trivial_usage \ 3251#define route_trivial_usage \
3474 "[{add|del|delete}]" 3252 "[{add|del|delete}]"
3475#define route_full_usage "\n\n" \ 3253#define route_full_usage "\n\n" \
@@ -3849,9 +3627,9 @@ INSERT
3849 "[OPTIONS] [INPUT [PREFIX]]" 3627 "[OPTIONS] [INPUT [PREFIX]]"
3850#define split_full_usage "\n\n" \ 3628#define split_full_usage "\n\n" \
3851 "Options:" \ 3629 "Options:" \
3852 "\n -b n[k|m] Split by bytes" \ 3630 "\n -b N[k|m] Split by N (kilo|mega)bytes" \
3853 "\n -l n Split by lines" \ 3631 "\n -l N Split by N lines" \
3854 "\n -a n Use n letters as suffix" \ 3632 "\n -a N Use N letters as suffix" \
3855 3633
3856#define split_example_usage \ 3634#define split_example_usage \
3857 "$ split TODO foo\n" \ 3635 "$ split TODO foo\n" \
@@ -4080,7 +3858,7 @@ INSERT
4080 "Write all buffered blocks to disk" 3858 "Write all buffered blocks to disk"
4081 3859
4082#define fsync_trivial_usage \ 3860#define fsync_trivial_usage \
4083 "[OPTIONS] FILE..." 3861 "[-d] FILE..."
4084#define fsync_full_usage "\n\n" \ 3862#define fsync_full_usage "\n\n" \
4085 "Write files' buffered blocks to disk\n" \ 3863 "Write files' buffered blocks to disk\n" \
4086 "\nOptions:" \ 3864 "\nOptions:" \
@@ -4156,7 +3934,7 @@ INSERT
4156 "pid 1's current affinity mask: 3\n" 3934 "pid 1's current affinity mask: 3\n"
4157 3935
4158#define tee_trivial_usage \ 3936#define tee_trivial_usage \
4159 "[OPTIONS] [FILE]..." 3937 "[-ai] [FILE]..."
4160#define tee_full_usage "\n\n" \ 3938#define tee_full_usage "\n\n" \
4161 "Copy stdin to each FILE, and also to stdout\n" \ 3939 "Copy stdin to each FILE, and also to stdout\n" \
4162 "\nOptions:" \ 3940 "\nOptions:" \
@@ -4261,7 +4039,7 @@ INSERT
4261 "\n -u USER[:GRP] Change to user/group after bind" \ 4039 "\n -u USER[:GRP] Change to user/group after bind" \
4262 "\n -c N Handle up to N connections simultaneously" \ 4040 "\n -c N Handle up to N connections simultaneously" \
4263 "\n -b N Allow a backlog of approximately N TCP SYNs" \ 4041 "\n -b N Allow a backlog of approximately N TCP SYNs" \
4264 "\n -C N[:MSG] Allow only up to N connections from the same IP" \ 4042 "\n -C N[:MSG] Allow only up to N connections from the same IP." \
4265 "\n New connections from this IP address are closed" \ 4043 "\n New connections from this IP address are closed" \
4266 "\n immediately. MSG is written to the peer before close" \ 4044 "\n immediately. MSG is written to the peer before close" \
4267 "\n -h Look up peer's hostname" \ 4045 "\n -h Look up peer's hostname" \
@@ -4317,7 +4095,7 @@ INSERT
4317 "\n -u Access files as USER" \ 4095 "\n -u Access files as USER" \
4318 4096
4319#define time_trivial_usage \ 4097#define time_trivial_usage \
4320 "[OPTIONS] PROG ARGS" 4098 "[-v] PROG ARGS"
4321#define time_full_usage "\n\n" \ 4099#define time_full_usage "\n\n" \
4322 "Run PROG, display resource usage when it exits\n" \ 4100 "Run PROG, display resource usage when it exits\n" \
4323 "\nOptions:" \ 4101 "\nOptions:" \
@@ -4338,12 +4116,13 @@ INSERT
4338//TODO: add options and keyboard commands 4116//TODO: add options and keyboard commands
4339 4117
4340#define touch_trivial_usage \ 4118#define touch_trivial_usage \
4341 "[-c] [-d DATE] FILE [FILE]..." 4119 "[-c] [-d DATE] [-r FILE] FILE [FILE]..."
4342#define touch_full_usage "\n\n" \ 4120#define touch_full_usage "\n\n" \
4343 "Update the last-modified date on the given FILE[s]\n" \ 4121 "Update the last-modified date on the given FILE[s]\n" \
4344 "\nOptions:" \ 4122 "\nOptions:" \
4345 "\n -c Don't create files" \ 4123 "\n -c Don't create files" \
4346 "\n -d DT Date/time to use" \ 4124 "\n -d DT Date/time to use" \
4125 "\n -r FILE Use FILE's date/time" \
4347 4126
4348#define touch_example_usage \ 4127#define touch_example_usage \
4349 "$ ls -l /tmp/foo\n" \ 4128 "$ ls -l /tmp/foo\n" \
@@ -4373,7 +4152,7 @@ INSERT
4373 "Trace the route to HOST\n" \ 4152 "Trace the route to HOST\n" \
4374 "\nOptions:" \ 4153 "\nOptions:" \
4375 IF_TRACEROUTE6( \ 4154 IF_TRACEROUTE6( \
4376 "\n -4, -6 Force IP or IPv6 name resolution" \ 4155 "\n -4,-6 Force IP or IPv6 name resolution" \
4377 ) \ 4156 ) \
4378 "\n -F Set the don't fragment bit" \ 4157 "\n -F Set the don't fragment bit" \
4379 "\n -I Use ICMP ECHO instead of UDP datagrams" \ 4158 "\n -I Use ICMP ECHO instead of UDP datagrams" \
@@ -4453,18 +4232,6 @@ INSERT
4453 "# tunctl\n" \ 4232 "# tunctl\n" \
4454 "# tunctl -d tun0\n" 4233 "# tunctl -d tun0\n"
4455 4234
4456#define tune2fs_trivial_usage \
4457/* "[-c max-mounts-count] [-e errors-behavior] [-g group] " */ \
4458/* "[-i interval[d|m|w]] [-j] [-J journal-options] [-l] [-s sparse-flag] " */ \
4459/* "[-m reserved-blocks-percent] [-o [^]mount-options[,...]] " */ \
4460/* "[-r reserved-blocks-count] [-u user] [-C mount-count] " */ \
4461 "[-L LABEL] " \
4462/* "[-M last-mounted-dir] [-O [^]feature[,...]] " */ \
4463/* "[-T last-check-time] [-U UUID] " */ \
4464 "BLOCKDEV"
4465#define tune2fs_full_usage "\n\n" \
4466 "Adjust filesystem options on ext[23] filesystems"
4467
4468#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 4235#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
4469# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ 4236# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
4470#else 4237#else
@@ -4708,13 +4475,15 @@ INSERT
4708 "Edit FILE\n" \ 4475 "Edit FILE\n" \
4709 "\nOptions:" \ 4476 "\nOptions:" \
4710 IF_FEATURE_VI_COLON( \ 4477 IF_FEATURE_VI_COLON( \
4711 "\n -c Initial command to run ($EXINIT also available)") \ 4478 "\n -c Initial command to run ($EXINIT also available)" \
4479 ) \
4712 IF_FEATURE_VI_READONLY( \ 4480 IF_FEATURE_VI_READONLY( \
4713 "\n -R Read-only") \ 4481 "\n -R Read-only" \
4482 ) \
4714 "\n -H Short help regarding available features" \ 4483 "\n -H Short help regarding available features" \
4715 4484
4716#define vlock_trivial_usage \ 4485#define vlock_trivial_usage \
4717 "[OPTIONS]" 4486 "[-a]"
4718#define vlock_full_usage "\n\n" \ 4487#define vlock_full_usage "\n\n" \
4719 "Lock a virtual terminal. A password is required to unlock.\n" \ 4488 "Lock a virtual terminal. A password is required to unlock.\n" \
4720 "\nOptions:" \ 4489 "\nOptions:" \
@@ -4758,21 +4527,6 @@ INSERT
4758 "\n" \ 4527 "\n" \
4759 "\nUse 500ms to specify period in milliseconds" \ 4528 "\nUse 500ms to specify period in milliseconds" \
4760 4529
4761#define wc_trivial_usage \
4762 "[OPTIONS] [FILE]..."
4763#define wc_full_usage "\n\n" \
4764 "Print line, word, and byte counts for each FILE (or stdin),\n" \
4765 "and a total line if more than one FILE is specified\n" \
4766 "\nOptions:" \
4767 "\n -c Print the byte counts" \
4768 "\n -l Print the newline counts" \
4769 "\n -L Print the length of the longest line" \
4770 "\n -w Print the word counts" \
4771
4772#define wc_example_usage \
4773 "$ wc /etc/passwd\n" \
4774 " 31 46 1365 /etc/passwd\n"
4775
4776#define wget_trivial_usage \ 4530#define wget_trivial_usage \
4777 IF_FEATURE_WGET_LONG_OPTIONS( \ 4531 IF_FEATURE_WGET_LONG_OPTIONS( \
4778 "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document FILE]\n" \ 4532 "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document FILE]\n" \
diff --git a/init/Config.src b/init/Config.src
index 2cac3573e..5767c93f0 100644
--- a/init/Config.src
+++ b/init/Config.src
@@ -7,131 +7,4 @@ menu "Init Utilities"
7 7
8INSERT 8INSERT
9 9
10config INIT
11 bool "init"
12 default y
13 select FEATURE_SYSLOG
14 help
15 init is the first program run when the system boots.
16
17config FEATURE_USE_INITTAB
18 bool "Support reading an inittab file"
19 default y
20 depends on INIT
21 help
22 Allow init to read an inittab file when the system boot.
23
24config FEATURE_KILL_REMOVED
25 bool "Support killing processes that have been removed from inittab"
26 default n
27 depends on FEATURE_USE_INITTAB
28 help
29 When respawn entries are removed from inittab and a SIGHUP is
30 sent to init, this option will make init kill the processes
31 that have been removed.
32
33config FEATURE_KILL_DELAY
34 int "How long to wait between TERM and KILL (0 - send TERM only)" if FEATURE_KILL_REMOVED
35 range 0 1024
36 default 0
37 depends on FEATURE_KILL_REMOVED
38 help
39 With nonzero setting, init sends TERM, forks, child waits N
40 seconds, sends KILL and exits. Setting it too high is unwise
41 (child will hang around for too long and could actually kill
42 the wrong process!)
43
44config FEATURE_INIT_SCTTY
45 bool "Run commands with leading dash with controlling tty"
46 default y
47 depends on INIT
48 help
49 If this option is enabled, init will try to give a controlling
50 tty to any command which has leading hyphen (often it's "-/bin/sh").
51 More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)".
52 If device attached to STDIN_FILENO can be a ctty but is not yet
53 a ctty for other session, it will become this process' ctty.
54 This is not the traditional init behavour, but is often what you want
55 in an embedded system where the console is only accessed during
56 development or for maintenance.
57 NB: using cttyhack applet may work better.
58
59config FEATURE_INIT_SYSLOG
60 bool "Enable init to write to syslog"
61 default y
62 depends on INIT
63
64config FEATURE_EXTRA_QUIET
65 bool "Be _extra_ quiet on boot"
66 default y
67 depends on INIT
68 help
69 Prevent init from logging some messages to the console during boot.
70
71config FEATURE_INIT_COREDUMPS
72 bool "Support dumping core for child processes (debugging only)"
73 default y
74 depends on INIT
75 help
76 If this option is enabled and the file /.init_enable_core
77 exists, then init will call setrlimit() to allow unlimited
78 core file sizes. If this option is disabled, processes
79 will not generate any core files.
80
81config FEATURE_INITRD
82 bool "Support running init from within an initrd (not initramfs)"
83 default y
84 depends on INIT
85 help
86 Legacy support for running init under the old-style initrd. Allows
87 the name linuxrc to act as init, and it doesn't assume init is PID 1.
88
89 This does not apply to initramfs, which runs /init as PID 1 and
90 requires no special support.
91
92config INIT_TERMINAL_TYPE
93 string "Initial terminal type"
94 default "linux"
95 depends on INIT
96 help
97 This is the initial value set by init for the TERM environment
98 variable. This variable is used by programs which make use of
99 extended terminal capabilities.
100
101 Note that on Linux, init attempts to detect serial terminal and
102 sets TERM to "vt102" if one is found.
103
104config HALT
105 bool "poweroff, halt, and reboot"
106 default y
107 help
108 Stop all processes and either halt, reboot, or power off the system.
109
110config FEATURE_CALL_TELINIT
111 bool "Call telinit on shutdown and reboot"
112 default y
113 depends on HALT && !INIT
114 help
115 Call an external program (normally telinit) to facilitate
116 a switch to a proper runlevel.
117
118 This option is only available if you selected halt and friends,
119 but did not select init.
120
121config TELINIT_PATH
122 string "Path to telinit executable"
123 default "/sbin/telinit"
124 depends on FEATURE_CALL_TELINIT
125 help
126 When busybox halt and friends have to call external telinit
127 to facilitate proper shutdown, this path is to be used when
128 locating telinit executable.
129
130config MESG
131 bool "mesg"
132 default y
133 help
134 Mesg controls access to your terminal by others. It is typically
135 used to allow or disallow other users to write to your terminal
136
137endmenu 10endmenu
diff --git a/init/Kbuild.src b/init/Kbuild.src
index 32dd5a045..6b4fb7470 100644
--- a/init/Kbuild.src
+++ b/init/Kbuild.src
@@ -7,7 +7,3 @@
7lib-y:= 7lib-y:=
8 8
9INSERT 9INSERT
10lib-$(CONFIG_HALT) += halt.o
11lib-$(CONFIG_INIT) += init.o
12lib-$(CONFIG_MESG) += mesg.o
13lib-$(CONFIG_BOOTCHARTD) += bootchartd.o
diff --git a/init/bootchartd.c b/init/bootchartd.c
index f14d5c0fd..5a1b3e8e8 100644
--- a/init/bootchartd.c
+++ b/init/bootchartd.c
@@ -3,6 +3,10 @@
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */ 4 */
5 5
6//applet:IF_BOOTCHARTD(APPLET(bootchartd, _BB_DIR_SBIN, _BB_SUID_DROP))
7
8//kbuild:lib-$(CONFIG_BOOTCHARTD) += bootchartd.o
9
6//config:config BOOTCHARTD 10//config:config BOOTCHARTD
7//config: bool "bootchartd" 11//config: bool "bootchartd"
8//config: default y 12//config: default y
diff --git a/init/halt.c b/init/halt.c
index 903953e80..47f1ef7b2 100644
--- a/init/halt.c
+++ b/init/halt.c
@@ -7,6 +7,68 @@
7 * Licensed under GPLv2, see file LICENSE in this source tree. 7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */ 8 */
9 9
10//applet:IF_HALT(APPLET(halt, _BB_DIR_SBIN, _BB_SUID_DROP))
11//applet:IF_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_DROP, poweroff))
12//applet:IF_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_DROP, reboot))
13
14//kbuild:lib-$(CONFIG_HALT) += halt.o
15
16//config:config HALT
17//config: bool "poweroff, halt, and reboot"
18//config: default y
19//config: help
20//config: Stop all processes and either halt, reboot, or power off the system.
21//config:
22//config:config FEATURE_CALL_TELINIT
23//config: bool "Call telinit on shutdown and reboot"
24//config: default y
25//config: depends on HALT && !INIT
26//config: help
27//config: Call an external program (normally telinit) to facilitate
28//config: a switch to a proper runlevel.
29//config:
30//config: This option is only available if you selected halt and friends,
31//config: but did not select init.
32//config:
33//config:config TELINIT_PATH
34//config: string "Path to telinit executable"
35//config: default "/sbin/telinit"
36//config: depends on FEATURE_CALL_TELINIT
37//config: help
38//config: When busybox halt and friends have to call external telinit
39//config: to facilitate proper shutdown, this path is to be used when
40//config: locating telinit executable.
41
42//usage:#define halt_trivial_usage
43//usage: "[-d DELAY] [-n] [-f]" IF_FEATURE_WTMP(" [-w]")
44//usage:#define halt_full_usage "\n\n"
45//usage: "Halt the system\n"
46//usage: "\nOptions:"
47//usage: "\n -d SEC Delay interval"
48//usage: "\n -n Do not sync"
49//usage: "\n -f Force (don't go through init)"
50//usage: IF_FEATURE_WTMP(
51//usage: "\n -w Only write a wtmp record"
52//usage: )
53//usage:
54//usage:#define poweroff_trivial_usage
55//usage: "[-d DELAY] [-n] [-f]"
56//usage:#define poweroff_full_usage "\n\n"
57//usage: "Halt and shut off power\n"
58//usage: "\nOptions:"
59//usage: "\n -d SEC Delay interval"
60//usage: "\n -n Do not sync"
61//usage: "\n -f Force (don't go through init)"
62//usage:
63//usage:#define reboot_trivial_usage
64//usage: "[-d DELAY] [-n] [-f]"
65//usage:#define reboot_full_usage "\n\n"
66//usage: "Reboot the system\n"
67//usage: "\nOptions:"
68//usage: "\n -d SEC Delay interval"
69//usage: "\n -n Do not sync"
70//usage: "\n -f Force (don't go through init)"
71
10#include "libbb.h" 72#include "libbb.h"
11#include "reboot.h" 73#include "reboot.h"
12 74
diff --git a/init/init.c b/init/init.c
index 5c0d11402..340731b8b 100644
--- a/init/init.c
+++ b/init/init.c
@@ -9,6 +9,237 @@
9 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
10 */ 10 */
11 11
12//applet:IF_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_DROP))
13//applet:IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, _BB_DIR_ROOT, _BB_SUID_DROP, linuxrc))
14
15//kbuild:lib-$(CONFIG_INIT) += init.o
16
17//config:config INIT
18//config: bool "init"
19//config: default y
20//config: select FEATURE_SYSLOG
21//config: help
22//config: init is the first program run when the system boots.
23//config:
24//config:config FEATURE_USE_INITTAB
25//config: bool "Support reading an inittab file"
26//config: default y
27//config: depends on INIT
28//config: help
29//config: Allow init to read an inittab file when the system boot.
30//config:
31//config:config FEATURE_KILL_REMOVED
32//config: bool "Support killing processes that have been removed from inittab"
33//config: default n
34//config: depends on FEATURE_USE_INITTAB
35//config: help
36//config: When respawn entries are removed from inittab and a SIGHUP is
37//config: sent to init, this option will make init kill the processes
38//config: that have been removed.
39//config:
40//config:config FEATURE_KILL_DELAY
41//config: int "How long to wait between TERM and KILL (0 - send TERM only)" if FEATURE_KILL_REMOVED
42//config: range 0 1024
43//config: default 0
44//config: depends on FEATURE_KILL_REMOVED
45//config: help
46//config: With nonzero setting, init sends TERM, forks, child waits N
47//config: seconds, sends KILL and exits. Setting it too high is unwise
48//config: (child will hang around for too long and could actually kill
49//config: the wrong process!)
50//config:
51//config:config FEATURE_INIT_SCTTY
52//config: bool "Run commands with leading dash with controlling tty"
53//config: default y
54//config: depends on INIT
55//config: help
56//config: If this option is enabled, init will try to give a controlling
57//config: tty to any command which has leading hyphen (often it's "-/bin/sh").
58//config: More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)".
59//config: If device attached to STDIN_FILENO can be a ctty but is not yet
60//config: a ctty for other session, it will become this process' ctty.
61//config: This is not the traditional init behavour, but is often what you want
62//config: in an embedded system where the console is only accessed during
63//config: development or for maintenance.
64//config: NB: using cttyhack applet may work better.
65//config:
66//config:config FEATURE_INIT_SYSLOG
67//config: bool "Enable init to write to syslog"
68//config: default y
69//config: depends on INIT
70//config:
71//config:config FEATURE_EXTRA_QUIET
72//config: bool "Be _extra_ quiet on boot"
73//config: default y
74//config: depends on INIT
75//config: help
76//config: Prevent init from logging some messages to the console during boot.
77//config:
78//config:config FEATURE_INIT_COREDUMPS
79//config: bool "Support dumping core for child processes (debugging only)"
80//config: default y
81//config: depends on INIT
82//config: help
83//config: If this option is enabled and the file /.init_enable_core
84//config: exists, then init will call setrlimit() to allow unlimited
85//config: core file sizes. If this option is disabled, processes
86//config: will not generate any core files.
87//config:
88//config:config FEATURE_INITRD
89//config: bool "Support running init from within an initrd (not initramfs)"
90//config: default y
91//config: depends on INIT
92//config: help
93//config: Legacy support for running init under the old-style initrd. Allows
94//config: the name linuxrc to act as init, and it doesn't assume init is PID 1.
95//config:
96//config: This does not apply to initramfs, which runs /init as PID 1 and
97//config: requires no special support.
98//config:
99//config:config INIT_TERMINAL_TYPE
100//config: string "Initial terminal type"
101//config: default "linux"
102//config: depends on INIT
103//config: help
104//config: This is the initial value set by init for the TERM environment
105//config: variable. This variable is used by programs which make use of
106//config: extended terminal capabilities.
107//config:
108//config: Note that on Linux, init attempts to detect serial terminal and
109//config: sets TERM to "vt102" if one is found.
110
111//usage:#define init_trivial_usage
112//usage: ""
113//usage:#define init_full_usage "\n\n"
114//usage: "Init is the parent of all processes"
115//usage:
116//usage:#define init_notes_usage
117//usage: "This version of init is designed to be run only by the kernel.\n"
118//usage: "\n"
119//usage: "BusyBox init doesn't support multiple runlevels. The runlevels field of\n"
120//usage: "the /etc/inittab file is completely ignored by BusyBox init. If you want\n"
121//usage: "runlevels, use sysvinit.\n"
122//usage: "\n"
123//usage: "BusyBox init works just fine without an inittab. If no inittab is found,\n"
124//usage: "it has the following default behavior:\n"
125//usage: "\n"
126//usage: " ::sysinit:/etc/init.d/rcS\n"
127//usage: " ::askfirst:/bin/sh\n"
128//usage: " ::ctrlaltdel:/sbin/reboot\n"
129//usage: " ::shutdown:/sbin/swapoff -a\n"
130//usage: " ::shutdown:/bin/umount -a -r\n"
131//usage: " ::restart:/sbin/init\n"
132//usage: "\n"
133//usage: "if it detects that /dev/console is _not_ a serial console, it will also run:\n"
134//usage: "\n"
135//usage: " tty2::askfirst:/bin/sh\n"
136//usage: " tty3::askfirst:/bin/sh\n"
137//usage: " tty4::askfirst:/bin/sh\n"
138//usage: "\n"
139//usage: "If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n"
140//usage: "\n"
141//usage: " <id>:<runlevels>:<action>:<process>\n"
142//usage: "\n"
143//usage: " <id>:\n"
144//usage: "\n"
145//usage: " WARNING: This field has a non-traditional meaning for BusyBox init!\n"
146//usage: " The id field is used by BusyBox init to specify the controlling tty for\n"
147//usage: " the specified process to run on. The contents of this field are\n"
148//usage: " appended to \"/dev/\" and used as-is. There is no need for this field to\n"
149//usage: " be unique, although if it isn't you may have strange results. If this\n"
150//usage: " field is left blank, the controlling tty is set to the console. Also\n"
151//usage: " note that if BusyBox detects that a serial console is in use, then only\n"
152//usage: " entries whose controlling tty is either the serial console or /dev/null\n"
153//usage: " will be run. BusyBox init does nothing with utmp. We don't need no\n"
154//usage: " stinkin' utmp.\n"
155//usage: "\n"
156//usage: " <runlevels>:\n"
157//usage: "\n"
158//usage: " The runlevels field is completely ignored.\n"
159//usage: "\n"
160//usage: " <action>:\n"
161//usage: "\n"
162//usage: " Valid actions include: sysinit, respawn, askfirst, wait,\n"
163//usage: " once, restart, ctrlaltdel, and shutdown.\n"
164//usage: "\n"
165//usage: " The available actions can be classified into two groups: actions\n"
166//usage: " that are run only once, and actions that are re-run when the specified\n"
167//usage: " process exits.\n"
168//usage: "\n"
169//usage: " Run only-once actions:\n"
170//usage: "\n"
171//usage: " 'sysinit' is the first item run on boot. init waits until all\n"
172//usage: " sysinit actions are completed before continuing. Following the\n"
173//usage: " completion of all sysinit actions, all 'wait' actions are run.\n"
174//usage: " 'wait' actions, like 'sysinit' actions, cause init to wait until\n"
175//usage: " the specified task completes. 'once' actions are asynchronous,\n"
176//usage: " therefore, init does not wait for them to complete. 'restart' is\n"
177//usage: " the action taken to restart the init process. By default this should\n"
178//usage: " simply run /sbin/init, but can be a script which runs pivot_root or it\n"
179//usage: " can do all sorts of other interesting things. The 'ctrlaltdel' init\n"
180//usage: " actions are run when the system detects that someone on the system\n"
181//usage: " console has pressed the CTRL-ALT-DEL key combination. Typically one\n"
182//usage: " wants to run 'reboot' at this point to cause the system to reboot.\n"
183//usage: " Finally the 'shutdown' action specifies the actions to taken when\n"
184//usage: " init is told to reboot. Unmounting filesystems and disabling swap\n"
185//usage: " is a very good here.\n"
186//usage: "\n"
187//usage: " Run repeatedly actions:\n"
188//usage: "\n"
189//usage: " 'respawn' actions are run after the 'once' actions. When a process\n"
190//usage: " started with a 'respawn' action exits, init automatically restarts\n"
191//usage: " it. Unlike sysvinit, BusyBox init does not stop processes from\n"
192//usage: " respawning out of control. The 'askfirst' actions acts just like\n"
193//usage: " respawn, except that before running the specified process it\n"
194//usage: " displays the line \"Please press Enter to activate this console.\"\n"
195//usage: " and then waits for the user to press enter before starting the\n"
196//usage: " specified process.\n"
197//usage: "\n"
198//usage: " Unrecognized actions (like initdefault) will cause init to emit an\n"
199//usage: " error message, and then go along with its business. All actions are\n"
200//usage: " run in the order they appear in /etc/inittab.\n"
201//usage: "\n"
202//usage: " <process>:\n"
203//usage: "\n"
204//usage: " Specifies the process to be executed and its command line.\n"
205//usage: "\n"
206//usage: "Example /etc/inittab file:\n"
207//usage: "\n"
208//usage: " # This is run first except when booting in single-user mode\n"
209//usage: " #\n"
210//usage: " ::sysinit:/etc/init.d/rcS\n"
211//usage: " \n"
212//usage: " # /bin/sh invocations on selected ttys\n"
213//usage: " #\n"
214//usage: " # Start an \"askfirst\" shell on the console (whatever that may be)\n"
215//usage: " ::askfirst:-/bin/sh\n"
216//usage: " # Start an \"askfirst\" shell on /dev/tty2-4\n"
217//usage: " tty2::askfirst:-/bin/sh\n"
218//usage: " tty3::askfirst:-/bin/sh\n"
219//usage: " tty4::askfirst:-/bin/sh\n"
220//usage: " \n"
221//usage: " # /sbin/getty invocations for selected ttys\n"
222//usage: " #\n"
223//usage: " tty4::respawn:/sbin/getty 38400 tty4\n"
224//usage: " tty5::respawn:/sbin/getty 38400 tty5\n"
225//usage: " \n"
226//usage: " \n"
227//usage: " # Example of how to put a getty on a serial line (for a terminal)\n"
228//usage: " #\n"
229//usage: " #::respawn:/sbin/getty -L ttyS0 9600 vt100\n"
230//usage: " #::respawn:/sbin/getty -L ttyS1 9600 vt100\n"
231//usage: " #\n"
232//usage: " # Example how to put a getty on a modem line\n"
233//usage: " #::respawn:/sbin/getty 57600 ttyS2\n"
234//usage: " \n"
235//usage: " # Stuff to do when restarting the init process\n"
236//usage: " ::restart:/sbin/init\n"
237//usage: " \n"
238//usage: " # Stuff to do before rebooting\n"
239//usage: " ::ctrlaltdel:/sbin/reboot\n"
240//usage: " ::shutdown:/bin/umount -a -r\n"
241//usage: " ::shutdown:/sbin/swapoff -a\n"
242
12#include "libbb.h" 243#include "libbb.h"
13#include <syslog.h> 244#include <syslog.h>
14#include <paths.h> 245#include <paths.h>
diff --git a/init/mesg.c b/init/mesg.c
index ef5f0eb66..b560df205 100644
--- a/init/mesg.c
+++ b/init/mesg.c
@@ -7,6 +7,24 @@
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9 9
10//applet:IF_MESG(APPLET(mesg, _BB_DIR_USR_BIN, _BB_SUID_DROP))
11
12//kbuild:lib-$(CONFIG_MESG) += mesg.o
13
14//config:config MESG
15//config: bool "mesg"
16//config: default y
17//config: help
18//config: Mesg controls access to your terminal by others. It is typically
19//config: used to allow or disallow other users to write to your terminal
20
21//usage:#define mesg_trivial_usage
22//usage: "[y|n]"
23//usage:#define mesg_full_usage "\n\n"
24//usage: "Control write access to your terminal\n"
25//usage: " y Allow write access to your terminal\n"
26//usage: " n Disallow write access to your terminal"
27
10#include "libbb.h" 28#include "libbb.h"
11 29
12#ifdef USE_TTY_GROUP 30#ifdef USE_TTY_GROUP
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index ab1d48c31..3b691f945 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -592,9 +592,11 @@ static const char usr_sbin[] ALIGN1 = "/usr/sbin/";
592static const char *const install_dir[] = { 592static const char *const install_dir[] = {
593 &usr_bin [8], /* "/" */ 593 &usr_bin [8], /* "/" */
594 &usr_bin [4], /* "/bin/" */ 594 &usr_bin [4], /* "/bin/" */
595 &usr_sbin[4], /* "/sbin/" */ 595 &usr_sbin[4] /* "/sbin/" */
596 usr_bin, 596# if !ENABLE_INSTALL_NO_USR
597 usr_sbin 597 ,usr_bin
598 ,usr_sbin
599# endif
598}; 600};
599 601
600 602
diff --git a/libbb/md5.c b/libbb/md5.c
index d8655ba91..051c8ede4 100644
--- a/libbb/md5.c
+++ b/libbb/md5.c
@@ -1,7 +1,7 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * md5.c - Compute MD5 checksum of strings according to the 3 * Compute MD5 checksum of strings according to the
4 * definition of MD5 in RFC 1321 from April 1992. 4 * definition of MD5 in RFC 1321 from April 1992.
5 * 5 *
6 * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. 6 * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
7 * 7 *
@@ -33,8 +33,7 @@ void FAST_FUNC md5_begin(md5_ctx_t *ctx)
33 ctx->B = 0xefcdab89; 33 ctx->B = 0xefcdab89;
34 ctx->C = 0x98badcfe; 34 ctx->C = 0x98badcfe;
35 ctx->D = 0x10325476; 35 ctx->D = 0x10325476;
36 ctx->total = 0; 36 ctx->total64 = 0;
37 ctx->buflen = 0;
38} 37}
39 38
40/* These are the four functions used in the four steps of the MD5 algorithm 39/* These are the four functions used in the four steps of the MD5 algorithm
@@ -49,13 +48,14 @@ void FAST_FUNC md5_begin(md5_ctx_t *ctx)
49 48
50#define rotl32(w, s) (((w) << (s)) | ((w) >> (32 - (s)))) 49#define rotl32(w, s) (((w) << (s)) | ((w) >> (32 - (s))))
51 50
52/* Hash a single block, 64 bytes long and 4-byte aligned. */ 51/* Hash a single block, 64 bytes long and 4-byte aligned */
53static void md5_hash_block(const void *buffer, md5_ctx_t *ctx) 52static void md5_process_block64(md5_ctx_t *ctx)
54{ 53{
55 uint32_t correct_words[16];
56 const uint32_t *words = buffer;
57
58#if MD5_SIZE_VS_SPEED > 0 54#if MD5_SIZE_VS_SPEED > 0
55 /* Before we start, one word to the strange constants.
56 They are defined in RFC 1321 as
57 T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64
58 */
59 static const uint32_t C_array[] = { 59 static const uint32_t C_array[] = {
60 /* round 1 */ 60 /* round 1 */
61 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 61 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
@@ -64,7 +64,7 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
64 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 64 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
65 /* round 2 */ 65 /* round 2 */
66 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 66 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
67 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 67 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
68 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 68 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
69 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 69 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
70 /* round 3 */ 70 /* round 3 */
@@ -86,40 +86,33 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
86 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ 86 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
87 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ 87 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
88 }; 88 };
89# if MD5_SIZE_VS_SPEED > 1
90 static const char S_array[] ALIGN1 = {
91 7, 12, 17, 22,
92 5, 9, 14, 20,
93 4, 11, 16, 23,
94 6, 10, 15, 21
95 };
96# endif /* MD5_SIZE_VS_SPEED > 1 */
97#endif 89#endif
90 uint32_t *words = (void*) ctx->wbuffer;
98 uint32_t A = ctx->A; 91 uint32_t A = ctx->A;
99 uint32_t B = ctx->B; 92 uint32_t B = ctx->B;
100 uint32_t C = ctx->C; 93 uint32_t C = ctx->C;
101 uint32_t D = ctx->D; 94 uint32_t D = ctx->D;
102 95
103 /* Process all bytes in the buffer with 64 bytes in each round of 96#if MD5_SIZE_VS_SPEED >= 2 /* 2 or 3 */
104 the loop. */
105 uint32_t *cwp = correct_words;
106 uint32_t A_save = A;
107 uint32_t B_save = B;
108 uint32_t C_save = C;
109 uint32_t D_save = D;
110 97
111#if MD5_SIZE_VS_SPEED > 1 98 static const char S_array[] ALIGN1 = {
99 7, 12, 17, 22,
100 5, 9, 14, 20,
101 4, 11, 16, 23,
102 6, 10, 15, 21
103 };
112 const uint32_t *pc; 104 const uint32_t *pc;
113 const char *pp; 105 const char *pp;
114 const char *ps; 106 const char *ps;
115 int i; 107 int i;
116 uint32_t temp; 108 uint32_t temp;
117 109
110# if BB_BIG_ENDIAN
118 for (i = 0; i < 16; i++) 111 for (i = 0; i < 16; i++)
119 cwp[i] = SWAP_LE32(words[i]); 112 words[i] = SWAP_LE32(words[i]);
120 words += 16; 113# endif
121 114
122# if MD5_SIZE_VS_SPEED > 2 115# if MD5_SIZE_VS_SPEED == 3
123 pc = C_array; 116 pc = C_array;
124 pp = P_array; 117 pp = P_array;
125 ps = S_array - 4; 118 ps = S_array - 4;
@@ -141,7 +134,7 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
141 case 3: 134 case 3:
142 temp += FI(B, C, D); 135 temp += FI(B, C, D);
143 } 136 }
144 temp += cwp[(int) (*pp++)] + *pc++; 137 temp += words[(int) (*pp++)] + *pc++;
145 temp = rotl32(temp, ps[i & 3]); 138 temp = rotl32(temp, ps[i & 3]);
146 temp += B; 139 temp += B;
147 A = D; 140 A = D;
@@ -149,13 +142,13 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
149 C = B; 142 C = B;
150 B = temp; 143 B = temp;
151 } 144 }
152# else 145# else /* MD5_SIZE_VS_SPEED == 2 */
153 pc = C_array; 146 pc = C_array;
154 pp = P_array; 147 pp = P_array;
155 ps = S_array; 148 ps = S_array;
156 149
157 for (i = 0; i < 16; i++) { 150 for (i = 0; i < 16; i++) {
158 temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++; 151 temp = A + FF(B, C, D) + words[(int) (*pp++)] + *pc++;
159 temp = rotl32(temp, ps[i & 3]); 152 temp = rotl32(temp, ps[i & 3]);
160 temp += B; 153 temp += B;
161 A = D; 154 A = D;
@@ -165,7 +158,7 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
165 } 158 }
166 ps += 4; 159 ps += 4;
167 for (i = 0; i < 16; i++) { 160 for (i = 0; i < 16; i++) {
168 temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++; 161 temp = A + FG(B, C, D) + words[(int) (*pp++)] + *pc++;
169 temp = rotl32(temp, ps[i & 3]); 162 temp = rotl32(temp, ps[i & 3]);
170 temp += B; 163 temp += B;
171 A = D; 164 A = D;
@@ -175,7 +168,7 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
175 } 168 }
176 ps += 4; 169 ps += 4;
177 for (i = 0; i < 16; i++) { 170 for (i = 0; i < 16; i++) {
178 temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++; 171 temp = A + FH(B, C, D) + words[(int) (*pp++)] + *pc++;
179 temp = rotl32(temp, ps[i & 3]); 172 temp = rotl32(temp, ps[i & 3]);
180 temp += B; 173 temp += B;
181 A = D; 174 A = D;
@@ -185,7 +178,7 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
185 } 178 }
186 ps += 4; 179 ps += 4;
187 for (i = 0; i < 16; i++) { 180 for (i = 0; i < 16; i++) {
188 temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++; 181 temp = A + FI(B, C, D) + words[(int) (*pp++)] + *pc++;
189 temp = rotl32(temp, ps[i & 3]); 182 temp = rotl32(temp, ps[i & 3]);
190 temp += B; 183 temp += B;
191 A = D; 184 A = D;
@@ -193,35 +186,41 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
193 C = B; 186 C = B;
194 B = temp; 187 B = temp;
195 } 188 }
189# endif
190 /* Add checksum to the starting values */
191 ctx->A += A;
192 ctx->B += B;
193 ctx->C += C;
194 ctx->D += D;
195
196#else /* MD5_SIZE_VS_SPEED == 0 or 1 */
197
198 uint32_t A_save = A;
199 uint32_t B_save = B;
200 uint32_t C_save = C;
201 uint32_t D_save = D;
202# if MD5_SIZE_VS_SPEED == 1
203 const uint32_t *pc;
204 const char *pp;
205 int i;
206# endif
196 207
197# endif /* MD5_SIZE_VS_SPEED > 2 */
198#else
199 /* First round: using the given function, the context and a constant 208 /* First round: using the given function, the context and a constant
200 the next context is computed. Because the algorithms processing 209 the next context is computed. Because the algorithm's processing
201 unit is a 32-bit word and it is determined to work on words in 210 unit is a 32-bit word and it is determined to work on words in
202 little endian byte order we perhaps have to change the byte order 211 little endian byte order we perhaps have to change the byte order
203 before the computation. To reduce the work for the next steps 212 before the computation. To reduce the work for the next steps
204 we store the swapped words in the array CORRECT_WORDS. */ 213 we save swapped words in WORDS array. */
214# undef OP
205# define OP(a, b, c, d, s, T) \ 215# define OP(a, b, c, d, s, T) \
206 do { \ 216 do { \
207 a += FF(b, c, d) + (*cwp++ = SWAP_LE32(*words)) + T; \ 217 a += FF(b, c, d) + (*words IF_BIG_ENDIAN(= SWAP_LE32(*words))) + T; \
208 ++words; \ 218 words++; \
209 a = rotl32(a, s); \ 219 a = rotl32(a, s); \
210 a += b; \ 220 a += b; \
211 } while (0) 221 } while (0)
212 222
213 /* Before we start, one word to the strange constants. 223 /* Round 1 */
214 They are defined in RFC 1321 as
215 T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64
216 */
217
218# if MD5_SIZE_VS_SPEED == 1
219 const uint32_t *pc;
220 const char *pp;
221 int i;
222# endif /* MD5_SIZE_VS_SPEED */
223
224 /* Round 1. */
225# if MD5_SIZE_VS_SPEED == 1 224# if MD5_SIZE_VS_SPEED == 1
226 pc = C_array; 225 pc = C_array;
227 for (i = 0; i < 4; i++) { 226 for (i = 0; i < 4; i++) {
@@ -247,20 +246,21 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
247 OP(D, A, B, C, 12, 0xfd987193); 246 OP(D, A, B, C, 12, 0xfd987193);
248 OP(C, D, A, B, 17, 0xa679438e); 247 OP(C, D, A, B, 17, 0xa679438e);
249 OP(B, C, D, A, 22, 0x49b40821); 248 OP(B, C, D, A, 22, 0x49b40821);
250# endif /* MD5_SIZE_VS_SPEED == 1 */ 249# endif
250 words -= 16;
251 251
252 /* For the second to fourth round we have the possibly swapped words 252 /* For the second to fourth round we have the possibly swapped words
253 in CORRECT_WORDS. Redefine the macro to take an additional first 253 in WORDS. Redefine the macro to take an additional first
254 argument specifying the function to use. */ 254 argument specifying the function to use. */
255# undef OP 255# undef OP
256# define OP(f, a, b, c, d, k, s, T) \ 256# define OP(f, a, b, c, d, k, s, T) \
257 do { \ 257 do { \
258 a += f(b, c, d) + correct_words[k] + T; \ 258 a += f(b, c, d) + words[k] + T; \
259 a = rotl32(a, s); \ 259 a = rotl32(a, s); \
260 a += b; \ 260 a += b; \
261 } while (0) 261 } while (0)
262 262
263 /* Round 2. */ 263 /* Round 2 */
264# if MD5_SIZE_VS_SPEED == 1 264# if MD5_SIZE_VS_SPEED == 1
265 pp = P_array; 265 pp = P_array;
266 for (i = 0; i < 4; i++) { 266 for (i = 0; i < 4; i++) {
@@ -286,9 +286,9 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
286 OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8); 286 OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
287 OP(FG, C, D, A, B, 7, 14, 0x676f02d9); 287 OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
288 OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a); 288 OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
289# endif /* MD5_SIZE_VS_SPEED == 1 */ 289# endif
290 290
291 /* Round 3. */ 291 /* Round 3 */
292# if MD5_SIZE_VS_SPEED == 1 292# if MD5_SIZE_VS_SPEED == 1
293 for (i = 0; i < 4; i++) { 293 for (i = 0; i < 4; i++) {
294 OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++); 294 OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++);
@@ -313,9 +313,9 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
313 OP(FH, D, A, B, C, 12, 11, 0xe6db99e5); 313 OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
314 OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8); 314 OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
315 OP(FH, B, C, D, A, 2, 23, 0xc4ac5665); 315 OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
316# endif /* MD5_SIZE_VS_SPEED == 1 */ 316# endif
317 317
318 /* Round 4. */ 318 /* Round 4 */
319# if MD5_SIZE_VS_SPEED == 1 319# if MD5_SIZE_VS_SPEED == 1
320 for (i = 0; i < 4; i++) { 320 for (i = 0; i < 4; i++) {
321 OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++); 321 OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++);
@@ -340,52 +340,62 @@ static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
340 OP(FI, D, A, B, C, 11, 10, 0xbd3af235); 340 OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
341 OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb); 341 OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
342 OP(FI, B, C, D, A, 9, 21, 0xeb86d391); 342 OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
343# endif /* MD5_SIZE_VS_SPEED == 1 */ 343# endif
344#endif /* MD5_SIZE_VS_SPEED > 1 */ 344 /* Add checksum to the starting values */
345 345 ctx->A = A_save + A;
346 /* Add the starting values of the context. */ 346 ctx->B = B_save + B;
347 A += A_save; 347 ctx->C = C_save + C;
348 B += B_save; 348 ctx->D = D_save + D;
349 C += C_save; 349#endif
350 D += D_save;
351
352 /* Put checksum in context given as argument. */
353 ctx->A = A;
354 ctx->B = B;
355 ctx->C = C;
356 ctx->D = D;
357} 350}
358 351
359/* Feed data through a temporary buffer to call md5_hash_aligned_block() 352/* Feed data through a temporary buffer to call md5_hash_aligned_block()
360 * with chunks of data that are 4-byte aligned and a multiple of 64 bytes. 353 * with chunks of data that are 4-byte aligned and a multiple of 64 bytes.
361 * This function's internal buffer remembers previous data until it has 64 354 * This function's internal buffer remembers previous data until it has 64
362 * bytes worth to pass on. Call md5_end() to flush this buffer. */ 355 * bytes worth to pass on. Call md5_end() to flush this buffer. */
363void FAST_FUNC md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx) 356void FAST_FUNC md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len)
364{ 357{
365 char *buf = (char *)buffer; 358 unsigned bufpos = ctx->total64 & 63;
359 unsigned remaining;
366 360
367 /* RFC 1321 specifies the possible length of the file up to 2^64 bits, 361 /* RFC 1321 specifies the possible length of the file up to 2^64 bits.
368 * Here we only track the number of bytes. */ 362 * Here we only track the number of bytes. */
369 ctx->total += len; 363 ctx->total64 += len;
370 364#if 0
371 /* Process all input. */ 365 remaining = 64 - bufpos;
372 while (len) { 366
373 unsigned i = 64 - ctx->buflen; 367 /* Hash whole blocks */
374 368 while (len >= remaining) {
375 /* Copy data into aligned buffer. */ 369 memcpy(ctx->wbuffer + bufpos, buffer, remaining);
376 if (i > len) 370 buffer = (const char *)buffer + remaining;
377 i = len; 371 len -= remaining;
378 memcpy(ctx->buffer + ctx->buflen, buf, i); 372 remaining = 64;
379 len -= i; 373 bufpos = 0;
380 ctx->buflen += i; 374 md5_process_block64(ctx);
381 buf += i; 375 }
382 376
383 /* When buffer fills up, process it. */ 377 /* Save last, partial blosk */
384 if (ctx->buflen == 64) { 378 memcpy(ctx->wbuffer + bufpos, buffer, len);
385 md5_hash_block(ctx->buffer, ctx); 379#else
386 ctx->buflen = 0; 380 /* Tiny bit smaller code */
387 } 381 while (1) {
382 remaining = 64 - bufpos;
383 if (remaining > len)
384 remaining = len;
385 /* Copy data into aligned buffer */
386 memcpy(ctx->wbuffer + bufpos, buffer, remaining);
387 len -= remaining;
388 buffer = (const char *)buffer + remaining;
389 bufpos += remaining;
390 /* clever way to do "if (bufpos != 64) break; ... ; bufpos = 0;" */
391 bufpos -= 64;
392 if (bufpos != 0)
393 break;
394 /* Buffer is filled up, process it */
395 md5_process_block64(ctx);
396 /*bufpos = 0; - already is */
388 } 397 }
398#endif
389} 399}
390 400
391/* Process the remaining bytes in the buffer and put result from CTX 401/* Process the remaining bytes in the buffer and put result from CTX
@@ -393,26 +403,31 @@ void FAST_FUNC md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx)
393 * endian byte order, so that a byte-wise output yields to the wanted 403 * endian byte order, so that a byte-wise output yields to the wanted
394 * ASCII representation of the message digest. 404 * ASCII representation of the message digest.
395 */ 405 */
396void FAST_FUNC md5_end(void *resbuf, md5_ctx_t *ctx) 406void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf)
397{ 407{
398 char *buf = ctx->buffer; 408 unsigned bufpos = ctx->total64 & 63;
399 int i; 409 /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */
400 410 ctx->wbuffer[bufpos++] = 0x80;
401 /* Pad data to block size. */ 411
402 buf[ctx->buflen++] = 0x80; 412 /* This loop iterates either once or twice, no more, no less */
403 memset(buf + ctx->buflen, 0, 128 - ctx->buflen); 413 while (1) {
404 414 unsigned remaining = 64 - bufpos;
405 /* Put the 64-bit file length in *bits* at the end of the buffer. */ 415 memset(ctx->wbuffer + bufpos, 0, remaining);
406 ctx->total <<= 3; 416 /* Do we have enough space for the length count? */
407 if (ctx->buflen > 56) 417 if (remaining >= 8) {
408 buf += 64; 418 /* Store the 64-bit counter of bits in the buffer in BE format */
409 for (i = 0; i < 8; i++) 419 uint64_t t = ctx->total64 << 3;
410 buf[56 + i] = ctx->total >> (i*8); 420 unsigned i;
411 421 for (i = 0; i < 8; i++) {
412 /* Process last bytes. */ 422 ctx->wbuffer[56 + i] = t;
413 if (buf != ctx->buffer) 423 t >>= 8;
414 md5_hash_block(ctx->buffer, ctx); 424 }
415 md5_hash_block(buf, ctx); 425 }
426 md5_process_block64(ctx);
427 if (remaining >= 8)
428 break;
429 bufpos = 0;
430 }
416 431
417 /* The MD5 result is in little endian byte order. 432 /* The MD5 result is in little endian byte order.
418 * We (ab)use the fact that A-D are consecutive in memory. 433 * We (ab)use the fact that A-D are consecutive in memory.
diff --git a/libbb/procps.c b/libbb/procps.c
index 7ffcd8dbc..ec43b221e 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -121,7 +121,7 @@ void FAST_FUNC free_procps_scan(procps_status_t* sp)
121 free(sp); 121 free(sp);
122} 122}
123 123
124#if ENABLE_FEATURE_TOPMEM 124#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
125static unsigned long fast_strtoul_16(char **endptr) 125static unsigned long fast_strtoul_16(char **endptr)
126{ 126{
127 unsigned char c; 127 unsigned char c;
diff --git a/libbb/pw_encrypt_md5.c b/libbb/pw_encrypt_md5.c
index 58964b567..889e09cab 100644
--- a/libbb/pw_encrypt_md5.c
+++ b/libbb/pw_encrypt_md5.c
@@ -92,10 +92,10 @@ md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned
92 /* Hash. the password first, since that is what is most unknown */ 92 /* Hash. the password first, since that is what is most unknown */
93 md5_begin(&ctx); 93 md5_begin(&ctx);
94 pw_len = strlen((char*)pw); 94 pw_len = strlen((char*)pw);
95 md5_hash(pw, pw_len, &ctx); 95 md5_hash(&ctx, pw, pw_len);
96 96
97 /* Then the salt including "$1$" */ 97 /* Then the salt including "$1$" */
98 md5_hash(salt, sl, &ctx); 98 md5_hash(&ctx, salt, sl);
99 99
100 /* Copy salt to result; skip "$1$" */ 100 /* Copy salt to result; skip "$1$" */
101 memcpy(result, salt, sl); 101 memcpy(result, salt, sl);
@@ -105,19 +105,19 @@ md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned
105 105
106 /* Then just as many characters of the MD5(pw, salt, pw) */ 106 /* Then just as many characters of the MD5(pw, salt, pw) */
107 md5_begin(&ctx1); 107 md5_begin(&ctx1);
108 md5_hash(pw, pw_len, &ctx1); 108 md5_hash(&ctx1, pw, pw_len);
109 md5_hash(salt, sl, &ctx1); 109 md5_hash(&ctx1, salt, sl);
110 md5_hash(pw, pw_len, &ctx1); 110 md5_hash(&ctx1, pw, pw_len);
111 md5_end(final, &ctx1); 111 md5_end(&ctx1, final);
112 for (pl = pw_len; pl > 0; pl -= 16) 112 for (pl = pw_len; pl > 0; pl -= 16)
113 md5_hash(final, pl > 16 ? 16 : pl, &ctx); 113 md5_hash(&ctx, final, pl > 16 ? 16 : pl);
114 114
115 /* Then something really weird... */ 115 /* Then something really weird... */
116 memset(final, 0, sizeof(final)); 116 memset(final, 0, sizeof(final));
117 for (i = pw_len; i; i >>= 1) { 117 for (i = pw_len; i; i >>= 1) {
118 md5_hash(((i & 1) ? final : (const unsigned char *) pw), 1, &ctx); 118 md5_hash(&ctx, ((i & 1) ? final : (const unsigned char *) pw), 1);
119 } 119 }
120 md5_end(final, &ctx); 120 md5_end(&ctx, final);
121 121
122 /* And now, just to make sure things don't run too fast. 122 /* And now, just to make sure things don't run too fast.
123 * On a 60 Mhz Pentium this takes 34 msec, so you would 123 * On a 60 Mhz Pentium this takes 34 msec, so you would
@@ -126,21 +126,21 @@ md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned
126 for (i = 0; i < 1000; i++) { 126 for (i = 0; i < 1000; i++) {
127 md5_begin(&ctx1); 127 md5_begin(&ctx1);
128 if (i & 1) 128 if (i & 1)
129 md5_hash(pw, pw_len, &ctx1); 129 md5_hash(&ctx1, pw, pw_len);
130 else 130 else
131 md5_hash(final, 16, &ctx1); 131 md5_hash(&ctx1, final, 16);
132 132
133 if (i % 3) 133 if (i % 3)
134 md5_hash(salt, sl, &ctx1); 134 md5_hash(&ctx1, salt, sl);
135 135
136 if (i % 7) 136 if (i % 7)
137 md5_hash(pw, pw_len, &ctx1); 137 md5_hash(&ctx1, pw, pw_len);
138 138
139 if (i & 1) 139 if (i & 1)
140 md5_hash(final, 16, &ctx1); 140 md5_hash(&ctx1, final, 16);
141 else 141 else
142 md5_hash(pw, pw_len, &ctx1); 142 md5_hash(&ctx1, pw, pw_len);
143 md5_end(final, &ctx1); 143 md5_end(&ctx1, final);
144 } 144 }
145 145
146 p = result + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */ 146 p = result + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */
diff --git a/libbb/sha1.c b/libbb/sha1.c
index beeb70cf6..d79291148 100644
--- a/libbb/sha1.c
+++ b/libbb/sha1.c
@@ -30,11 +30,29 @@
30 30
31#include "libbb.h" 31#include "libbb.h"
32 32
33#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n)))) 33/* gcc 4.2.1 optimizes rotr64 better with inline than with macro
34#define rotr32(x,n) (((x) >> (n)) | ((x) << (32 - (n)))) 34 * (for rotX32, there is no difference). Why? My guess is that
35/* for sha512: */ 35 * macro requires clever common subexpression elimination heuristics
36#define rotr64(x,n) (((x) >> (n)) | ((x) << (64 - (n)))) 36 * in gcc, while inline basically forces it to happen.
37 */
38//#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n))))
39static ALWAYS_INLINE uint32_t rotl32(uint32_t x, unsigned n)
40{
41 return (x << n) | (x >> (32 - n));
42}
43//#define rotr32(x,n) (((x) >> (n)) | ((x) << (32 - (n))))
44static ALWAYS_INLINE uint32_t rotr32(uint32_t x, unsigned n)
45{
46 return (x >> n) | (x << (32 - n));
47}
48/* rotr64 in needed for sha512 only: */
49//#define rotr64(x,n) (((x) >> (n)) | ((x) << (64 - (n))))
50static ALWAYS_INLINE uint64_t rotr64(uint64_t x, unsigned n)
51{
52 return (x >> n) | (x << (64 - n));
53}
37#if BB_LITTLE_ENDIAN 54#if BB_LITTLE_ENDIAN
55/* ALWAYS_INLINE below would hurt code size, using plain inline: */
38static inline uint64_t hton64(uint64_t v) 56static inline uint64_t hton64(uint64_t v)
39{ 57{
40 return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32); 58 return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32);
@@ -44,14 +62,6 @@ static inline uint64_t hton64(uint64_t v)
44#endif 62#endif
45#define ntoh64(v) hton64(v) 63#define ntoh64(v) hton64(v)
46 64
47/* To check alignment gcc has an appropriate operator. Other
48 compilers don't. */
49#if defined(__GNUC__) && __GNUC__ >= 2
50# define UNALIGNED_P(p,type) (((uintptr_t) p) % __alignof__(type) != 0)
51#else
52# define UNALIGNED_P(p,type) (((uintptr_t) p) % sizeof(type) != 0)
53#endif
54
55 65
56/* Some arch headers have conflicting defines */ 66/* Some arch headers have conflicting defines */
57#undef ch 67#undef ch
@@ -65,11 +75,8 @@ static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx)
65 uint32_t W[80], a, b, c, d, e; 75 uint32_t W[80], a, b, c, d, e;
66 const uint32_t *words = (uint32_t*) ctx->wbuffer; 76 const uint32_t *words = (uint32_t*) ctx->wbuffer;
67 77
68 for (t = 0; t < 16; ++t) { 78 for (t = 0; t < 16; ++t)
69 W[t] = ntohl(*words); 79 W[t] = ntohl(words[t]);
70 words++;
71 }
72
73 for (/*t = 16*/; t < 80; ++t) { 80 for (/*t = 16*/; t < 80; ++t) {
74 uint32_t T = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; 81 uint32_t T = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
75 W[t] = rotl32(T, 1); 82 W[t] = rotl32(T, 1);
@@ -190,11 +197,8 @@ static void FAST_FUNC sha256_process_block64(sha256_ctx_t *ctx)
190#define R1(x) (rotr32(x, 17) ^ rotr32(x, 19) ^ (x >> 10)) 197#define R1(x) (rotr32(x, 17) ^ rotr32(x, 19) ^ (x >> 10))
191 198
192 /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */ 199 /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */
193 for (t = 0; t < 16; ++t) { 200 for (t = 0; t < 16; ++t)
194 W[t] = ntohl(*words); 201 W[t] = ntohl(words[t]);
195 words++;
196 }
197
198 for (/*t = 16*/; t < 64; ++t) 202 for (/*t = 16*/; t < 64; ++t)
199 W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16]; 203 W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16];
200 204
@@ -269,10 +273,8 @@ static void FAST_FUNC sha512_process_block128(sha512_ctx_t *ctx)
269#define R1(x) (rotr64(x, 19) ^ rotr64(x, 61) ^ (x >> 6)) 273#define R1(x) (rotr64(x, 19) ^ rotr64(x, 61) ^ (x >> 6))
270 274
271 /* Compute the message schedule according to FIPS 180-2:6.3.2 step 2. */ 275 /* Compute the message schedule according to FIPS 180-2:6.3.2 step 2. */
272 for (t = 0; t < 16; ++t) { 276 for (t = 0; t < 16; ++t)
273 W[t] = ntoh64(*words); 277 W[t] = ntoh64(words[t]);
274 words++;
275 }
276 for (/*t = 16*/; t < 80; ++t) 278 for (/*t = 16*/; t < 80; ++t)
277 W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16]; 279 W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16];
278 280
@@ -327,7 +329,9 @@ static const uint32_t init256[] = {
327 0x510e527f, 329 0x510e527f,
328 0x9b05688c, 330 0x9b05688c,
329 0x1f83d9ab, 331 0x1f83d9ab,
330 0x5be0cd19 332 0x5be0cd19,
333 0,
334 0,
331}; 335};
332static const uint32_t init512_lo[] = { 336static const uint32_t init512_lo[] = {
333 0xf3bcc908, 337 0xf3bcc908,
@@ -337,7 +341,9 @@ static const uint32_t init512_lo[] = {
337 0xade682d1, 341 0xade682d1,
338 0x2b3e6c1f, 342 0x2b3e6c1f,
339 0xfb41bd6b, 343 0xfb41bd6b,
340 0x137e2179 344 0x137e2179,
345 0,
346 0,
341}; 347};
342 348
343/* Initialize structure containing state of computation. 349/* Initialize structure containing state of computation.
@@ -345,7 +351,7 @@ static const uint32_t init512_lo[] = {
345void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) 351void FAST_FUNC sha256_begin(sha256_ctx_t *ctx)
346{ 352{
347 memcpy(ctx->hash, init256, sizeof(init256)); 353 memcpy(ctx->hash, init256, sizeof(init256));
348 ctx->total64 = 0; 354 /*ctx->total64 = 0; - done by extending init256 with two 32-bit zeros */
349 ctx->process_block = sha256_process_block64; 355 ctx->process_block = sha256_process_block64;
350} 356}
351 357
@@ -354,36 +360,61 @@ void FAST_FUNC sha256_begin(sha256_ctx_t *ctx)
354void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) 360void FAST_FUNC sha512_begin(sha512_ctx_t *ctx)
355{ 361{
356 int i; 362 int i;
357 for (i = 0; i < 8; i++) 363 /* Two extra iterations zero out ctx->total64[] */
364 for (i = 0; i < 8+2; i++)
358 ctx->hash[i] = ((uint64_t)(init256[i]) << 32) + init512_lo[i]; 365 ctx->hash[i] = ((uint64_t)(init256[i]) << 32) + init512_lo[i];
359 ctx->total64[0] = ctx->total64[1] = 0; 366 /*ctx->total64[0] = ctx->total64[1] = 0; - already done */
360} 367}
361 368
362 369
363/* Used also for sha256 */ 370/* Used also for sha256 */
364void FAST_FUNC sha1_hash(const void *buffer, size_t len, sha1_ctx_t *ctx) 371void FAST_FUNC sha1_hash(sha1_ctx_t *ctx, const void *buffer, size_t len)
365{ 372{
366 unsigned in_buf = ctx->total64 & 63; 373 unsigned bufpos = ctx->total64 & 63;
367 unsigned add = 64 - in_buf; 374 unsigned remaining;
368 375
369 ctx->total64 += len; 376 ctx->total64 += len;
370 377#if 0
371 while (len >= add) { /* transfer whole blocks while possible */ 378 remaining = 64 - bufpos;
372 memcpy(ctx->wbuffer + in_buf, buffer, add); 379
373 buffer = (const char *)buffer + add; 380 /* Hash whole blocks */
374 len -= add; 381 while (len >= remaining) {
375 add = 64; 382 memcpy(ctx->wbuffer + bufpos, buffer, remaining);
376 in_buf = 0; 383 buffer = (const char *)buffer + remaining;
384 len -= remaining;
385 remaining = 64;
386 bufpos = 0;
377 ctx->process_block(ctx); 387 ctx->process_block(ctx);
378 } 388 }
379 389
380 memcpy(ctx->wbuffer + in_buf, buffer, len); 390 /* Save last, partial blosk */
391 memcpy(ctx->wbuffer + bufpos, buffer, len);
392#else
393 /* Tiny bit smaller code */
394 while (1) {
395 remaining = 64 - bufpos;
396 if (remaining > len)
397 remaining = len;
398 /* Copy data into aligned buffer */
399 memcpy(ctx->wbuffer + bufpos, buffer, remaining);
400 len -= remaining;
401 buffer = (const char *)buffer + remaining;
402 bufpos += remaining;
403 /* clever way to do "if (bufpos != 64) break; ... ; bufpos = 0;" */
404 bufpos -= 64;
405 if (bufpos != 0)
406 break;
407 /* Buffer is filled up, process it */
408 ctx->process_block(ctx);
409 /*bufpos = 0; - already is */
410 }
411#endif
381} 412}
382 413
383void FAST_FUNC sha512_hash(const void *buffer, size_t len, sha512_ctx_t *ctx) 414void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len)
384{ 415{
385 unsigned in_buf = ctx->total64[0] & 127; 416 unsigned bufpos = ctx->total64[0] & 127;
386 unsigned add = 128 - in_buf; 417 unsigned remaining;
387 418
388 /* First increment the byte count. FIPS 180-2 specifies the possible 419 /* First increment the byte count. FIPS 180-2 specifies the possible
389 length of the file up to 2^128 _bits_. 420 length of the file up to 2^128 _bits_.
@@ -391,36 +422,57 @@ void FAST_FUNC sha512_hash(const void *buffer, size_t len, sha512_ctx_t *ctx)
391 ctx->total64[0] += len; 422 ctx->total64[0] += len;
392 if (ctx->total64[0] < len) 423 if (ctx->total64[0] < len)
393 ctx->total64[1]++; 424 ctx->total64[1]++;
394 425#if 0
395 while (len >= add) { /* transfer whole blocks while possible */ 426 remaining = 128 - bufpos;
396 memcpy(ctx->wbuffer + in_buf, buffer, add); 427
397 buffer = (const char *)buffer + add; 428 /* Hash whole blocks */
398 len -= add; 429 while (len >= remaining) {
399 add = 128; 430 memcpy(ctx->wbuffer + bufpos, buffer, remaining);
400 in_buf = 0; 431 buffer = (const char *)buffer + remaining;
432 len -= remaining;
433 remaining = 128;
434 bufpos = 0;
401 sha512_process_block128(ctx); 435 sha512_process_block128(ctx);
402 } 436 }
403 437
404 memcpy(ctx->wbuffer + in_buf, buffer, len); 438 /* Save last, partial blosk */
439 memcpy(ctx->wbuffer + bufpos, buffer, len);
440#else
441 while (1) {
442 remaining = 128 - bufpos;
443 if (remaining > len)
444 remaining = len;
445 /* Copy data into aligned buffer */
446 memcpy(ctx->wbuffer + bufpos, buffer, remaining);
447 len -= remaining;
448 buffer = (const char *)buffer + remaining;
449 bufpos += remaining;
450 /* clever way to do "if (bufpos != 128) break; ... ; bufpos = 0;" */
451 bufpos -= 128;
452 if (bufpos != 0)
453 break;
454 /* Buffer is filled up, process it */
455 sha512_process_block128(ctx);
456 /*bufpos = 0; - already is */
457 }
458#endif
405} 459}
406 460
407 461
408/* Used also for sha256 */ 462/* Used also for sha256 */
409void FAST_FUNC sha1_end(void *resbuf, sha1_ctx_t *ctx) 463void FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf)
410{ 464{
411 unsigned pad, in_buf; 465 unsigned bufpos = ctx->total64 & 63;
412 466
413 in_buf = ctx->total64 & 63;
414 /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */ 467 /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */
415 ctx->wbuffer[in_buf++] = 0x80; 468 ctx->wbuffer[bufpos++] = 0x80;
416 469
417 /* This loop iterates either once or twice, no more, no less */ 470 /* This loop iterates either once or twice, no more, no less */
418 while (1) { 471 while (1) {
419 pad = 64 - in_buf; 472 unsigned remaining = 64 - bufpos;
420 memset(ctx->wbuffer + in_buf, 0, pad); 473 memset(ctx->wbuffer + bufpos, 0, remaining);
421 in_buf = 0;
422 /* Do we have enough space for the length count? */ 474 /* Do we have enough space for the length count? */
423 if (pad >= 8) { 475 if (remaining >= 8) {
424 /* Store the 64-bit counter of bits in the buffer in BE format */ 476 /* Store the 64-bit counter of bits in the buffer in BE format */
425 uint64_t t = ctx->total64 << 3; 477 uint64_t t = ctx->total64 << 3;
426 t = hton64(t); 478 t = hton64(t);
@@ -428,35 +480,32 @@ void FAST_FUNC sha1_end(void *resbuf, sha1_ctx_t *ctx)
428 *(uint64_t *) (&ctx->wbuffer[64 - 8]) = t; 480 *(uint64_t *) (&ctx->wbuffer[64 - 8]) = t;
429 } 481 }
430 ctx->process_block(ctx); 482 ctx->process_block(ctx);
431 if (pad >= 8) 483 if (remaining >= 8)
432 break; 484 break;
485 bufpos = 0;
433 } 486 }
434 487
435 in_buf = (ctx->process_block == sha1_process_block64) ? 5 : 8; 488 bufpos = (ctx->process_block == sha1_process_block64) ? 5 : 8;
436 /* This way we do not impose alignment constraints on resbuf: */ 489 /* This way we do not impose alignment constraints on resbuf: */
437 if (BB_LITTLE_ENDIAN) { 490 if (BB_LITTLE_ENDIAN) {
438 unsigned i; 491 unsigned i;
439 for (i = 0; i < in_buf; ++i) 492 for (i = 0; i < bufpos; ++i)
440 ctx->hash[i] = htonl(ctx->hash[i]); 493 ctx->hash[i] = htonl(ctx->hash[i]);
441 } 494 }
442 memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * in_buf); 495 memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * bufpos);
443} 496}
444 497
445void FAST_FUNC sha512_end(void *resbuf, sha512_ctx_t *ctx) 498void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf)
446{ 499{
447 unsigned pad, in_buf; 500 unsigned bufpos = ctx->total64[0] & 127;
448 501
449 in_buf = ctx->total64[0] & 127; 502 /* Pad the buffer to the next 128-byte boundary with 0x80,0,0,0... */
450 /* Pad the buffer to the next 128-byte boundary with 0x80,0,0,0... 503 ctx->wbuffer[bufpos++] = 0x80;
451 * (FIPS 180-2:5.1.2)
452 */
453 ctx->wbuffer[in_buf++] = 0x80;
454 504
455 while (1) { 505 while (1) {
456 pad = 128 - in_buf; 506 unsigned remaining = 128 - bufpos;
457 memset(ctx->wbuffer + in_buf, 0, pad); 507 memset(ctx->wbuffer + bufpos, 0, remaining);
458 in_buf = 0; 508 if (remaining >= 16) {
459 if (pad >= 16) {
460 /* Store the 128-bit counter of bits in the buffer in BE format */ 509 /* Store the 128-bit counter of bits in the buffer in BE format */
461 uint64_t t; 510 uint64_t t;
462 t = ctx->total64[0] << 3; 511 t = ctx->total64[0] << 3;
@@ -467,8 +516,9 @@ void FAST_FUNC sha512_end(void *resbuf, sha512_ctx_t *ctx)
467 *(uint64_t *) (&ctx->wbuffer[128 - 16]) = t; 516 *(uint64_t *) (&ctx->wbuffer[128 - 16]) = t;
468 } 517 }
469 sha512_process_block128(ctx); 518 sha512_process_block128(ctx);
470 if (pad >= 16) 519 if (remaining >= 16)
471 break; 520 break;
521 bufpos = 0;
472 } 522 }
473 523
474 if (BB_LITTLE_ENDIAN) { 524 if (BB_LITTLE_ENDIAN) {
diff --git a/libbb/uuencode.c b/libbb/uuencode.c
index 181f49de0..03e708fd5 100644
--- a/libbb/uuencode.c
+++ b/libbb/uuencode.c
@@ -1,6 +1,8 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * Copyright 2006 Rob Landley <rob@landley.net> 3 * Copyright 2003, Glenn McGrath
4 * Copyright 2006, Rob Landley <rob@landley.net>
5 * Copyright 2010, Denys Vlasenko
4 * 6 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 */ 8 */
@@ -69,3 +71,75 @@ void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl
69 length++; 71 length++;
70 } 72 }
71} 73}
74
75/*
76 * Decode base64 encoded stream.
77 * Can stop on EOF, specified char, or on uuencode-style "====" line:
78 * flags argument controls it.
79 */
80void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
81{
82/* Note that EOF _can_ be passed as exit_char too */
83#define exit_char ((int)(signed char)flags)
84#define uu_style_end (flags & BASE64_FLAG_UU_STOP)
85
86 int term_count = 0;
87
88 while (1) {
89 unsigned char translated[4];
90 int count = 0;
91
92 /* Process one group of 4 chars */
93 while (count < 4) {
94 char *table_ptr;
95 int ch;
96
97 /* Get next _valid_ character.
98 * bb_uuenc_tbl_base64[] contains this string:
99 * 0 1 2 3 4 5 6
100 * 012345678901234567890123456789012345678901234567890123456789012345
101 * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n"
102 */
103 do {
104 ch = fgetc(src_stream);
105 if (ch == exit_char && count == 0)
106 return;
107 if (ch == EOF)
108 bb_error_msg_and_die("truncated base64 input");
109 table_ptr = strchr(bb_uuenc_tbl_base64, ch);
110//TODO: add BASE64_FLAG_foo to die on bad char?
111//Note that then we may need to still allow '\r' (for mail processing)
112 } while (!table_ptr);
113
114 /* Convert encoded character to decimal */
115 ch = table_ptr - bb_uuenc_tbl_base64;
116
117 if (ch == 65 /* '\n' */) {
118 /* Terminating "====" line? */
119 if (uu_style_end && term_count == 4)
120 return; /* yes */
121 term_count = 0;
122 continue;
123 }
124 /* ch is 64 if char was '=', otherwise 0..63 */
125 translated[count] = ch & 63; /* 64 -> 0 */
126 if (ch == 64) {
127 term_count++;
128 break;
129 }
130 count++;
131 term_count = 0;
132 }
133
134 /* Merge 6 bit chars to 8 bit.
135 * count can be < 4 when we decode the tail:
136 * "eQ==" -> "y", not "y NUL NUL"
137 */
138 if (count > 1)
139 fputc(translated[0] << 2 | translated[1] >> 4, dst_stream);
140 if (count > 2)
141 fputc(translated[1] << 4 | translated[2] >> 2, dst_stream);
142 if (count > 3)
143 fputc(translated[2] << 6 | translated[3], dst_stream);
144 } /* while (1) */
145}
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index ae950f94f..8e60e2165 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -134,7 +134,7 @@ int FAST_FUNC xopen3(const char *pathname, int flags, int mode)
134 return ret; 134 return ret;
135} 135}
136 136
137// Die if we can't open an existing file and return a fd. 137// Die if we can't open a file and return a fd.
138int FAST_FUNC xopen(const char *pathname, int flags) 138int FAST_FUNC xopen(const char *pathname, int flags)
139{ 139{
140 return xopen3(pathname, flags, 0666); 140 return xopen3(pathname, flags, 0666);
diff --git a/loginutils/Config.src b/loginutils/Config.src
index 5d497c4dc..8158bce74 100644
--- a/loginutils/Config.src
+++ b/loginutils/Config.src
@@ -93,41 +93,18 @@ config USE_BB_CRYPT_SHA
93 With this option off, login will fail password check for any 93 With this option off, login will fail password check for any
94 user which has password encrypted with these algorithms. 94 user which has password encrypted with these algorithms.
95 95
96config ADDGROUP 96config ADDUSER
97 bool "addgroup" 97 bool "adduser"
98 default y 98 default y
99 help 99 help
100 Utility for creating a new group account. 100 Utility for creating a new user account.
101 101
102config FEATURE_ADDGROUP_LONG_OPTIONS 102config FEATURE_ADDUSER_LONG_OPTIONS
103 bool "Enable long options" 103 bool "Enable long options"
104 default y 104 default y
105 depends on ADDGROUP && LONG_OPTS 105 depends on ADDUSER && LONG_OPTS
106 help
107 Support long options for the addgroup applet.
108
109config FEATURE_ADDUSER_TO_GROUP
110 bool "Support for adding users to groups"
111 default y
112 depends on ADDGROUP
113 help
114 If called with two non-option arguments,
115 addgroup will add an existing user to an
116 existing group.
117
118config DELGROUP
119 bool "delgroup"
120 default y
121 help
122 Utility for deleting a group account.
123
124config FEATURE_DEL_USER_FROM_GROUP
125 bool "Support for removing users from groups"
126 default y
127 depends on DELGROUP
128 help 106 help
129 If called with two non-option arguments, deluser 107 Support long options for the adduser applet.
130 or delgroup will remove an user from a specified group.
131 108
132config FEATURE_CHECK_NAMES 109config FEATURE_CHECK_NAMES
133 bool "Enable sanity check on user/group names in adduser and addgroup" 110 bool "Enable sanity check on user/group names in adduser and addgroup"
@@ -141,19 +118,6 @@ config FEATURE_CHECK_NAMES
141 For compatibility with Samba machine accounts "$" is also supported 118 For compatibility with Samba machine accounts "$" is also supported
142 at the end of the user or group name. 119 at the end of the user or group name.
143 120
144config ADDUSER
145 bool "adduser"
146 default y
147 help
148 Utility for creating a new user account.
149
150config FEATURE_ADDUSER_LONG_OPTIONS
151 bool "Enable long options"
152 default y
153 depends on ADDUSER && LONG_OPTS
154 help
155 Support long options for the adduser applet.
156
157config FIRST_SYSTEM_ID 121config FIRST_SYSTEM_ID
158 int "First valid system uid or gid for adduser and addgroup" 122 int "First valid system uid or gid for adduser and addgroup"
159 depends on ADDUSER || ADDGROUP 123 depends on ADDUSER || ADDGROUP
@@ -170,12 +134,48 @@ config LAST_SYSTEM_ID
170 help 134 help
171 Last valid system uid or gid for adduser and addgroup 135 Last valid system uid or gid for adduser and addgroup
172 136
137config ADDGROUP
138 bool "addgroup"
139 default y
140 help
141 Utility for creating a new group account.
142
143config FEATURE_ADDGROUP_LONG_OPTIONS
144 bool "Enable long options"
145 default y
146 depends on ADDGROUP && LONG_OPTS
147 help
148 Support long options for the addgroup applet.
149
150config FEATURE_ADDUSER_TO_GROUP
151 bool "Support for adding users to groups"
152 default y
153 depends on ADDGROUP
154 help
155 If called with two non-option arguments,
156 addgroup will add an existing user to an
157 existing group.
158
173config DELUSER 159config DELUSER
174 bool "deluser" 160 bool "deluser"
175 default y 161 default y
176 help 162 help
177 Utility for deleting a user account. 163 Utility for deleting a user account.
178 164
165config DELGROUP
166 bool "delgroup"
167 default y
168 help
169 Utility for deleting a group account.
170
171config FEATURE_DEL_USER_FROM_GROUP
172 bool "Support for removing users from groups"
173 default y
174 depends on DELGROUP
175 help
176 If called with two non-option arguments, deluser
177 or delgroup will remove an user from a specified group.
178
179config GETTY 179config GETTY
180 bool "getty" 180 bool "getty"
181 default y 181 default y
diff --git a/loginutils/deluser.c b/loginutils/deluser.c
index e234d6678..08ca266d0 100644
--- a/loginutils/deluser.c
+++ b/loginutils/deluser.c
@@ -11,20 +11,13 @@
11 */ 11 */
12#include "libbb.h" 12#include "libbb.h"
13 13
14static int del_line_matching(char **args, const char *filename)
15{
16 if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && args[2]) {
17 return update_passwd(filename, args[2], NULL, args[1]);
18 }
19 return update_passwd(filename, args[1], NULL, NULL);
20}
21
22int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 14int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
23int deluser_main(int argc, char **argv) 15int deluser_main(int argc, char **argv)
24{ 16{
25 if (argc != 2 17 if (argc != 2
26 && (!ENABLE_FEATURE_DEL_USER_FROM_GROUP 18 && (!ENABLE_FEATURE_DEL_USER_FROM_GROUP
27 || (applet_name[3] != 'g' || argc != 3)) 19 || applet_name[3] != 'g'
20 || argc != 3)
28 ) { 21 ) {
29 bb_show_usage(); 22 bb_show_usage();
30 } 23 }
@@ -32,25 +25,30 @@ int deluser_main(int argc, char **argv)
32 if (geteuid()) 25 if (geteuid())
33 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 26 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
34 27
35 if ((ENABLE_FEATURE_DEL_USER_FROM_GROUP && argc != 3) 28 if (ENABLE_DELUSER && applet_name[3] == 'u') {
36 || ENABLE_DELUSER 29 /* deluser USER */
37 || (ENABLE_DELGROUP && ENABLE_DESKTOP) 30 if (update_passwd(bb_path_passwd_file, argv[1], NULL, NULL) < 0)
38 ) { 31 return EXIT_FAILURE;
39 if (ENABLE_DELUSER 32 if (ENABLE_FEATURE_SHADOWPASSWDS)
40 && (!ENABLE_DELGROUP || applet_name[3] == 'u') 33 if (update_passwd(bb_path_shadow_file, argv[1], NULL, NULL) < 0)
41 ) {
42 if (del_line_matching(argv, bb_path_passwd_file) < 0)
43 return EXIT_FAILURE; 34 return EXIT_FAILURE;
44 if (ENABLE_FEATURE_SHADOWPASSWDS) { 35 } else if (ENABLE_DELGROUP) {
45 del_line_matching(argv, bb_path_shadow_file); 36 /* delgroup ... */
46 } 37 if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || argc != 3) {
47 } else if (ENABLE_DESKTOP && ENABLE_DELGROUP && getpwnam(argv[1])) 38 /* delgroup GROUP */
48 bb_error_msg_and_die("can't remove primary group of user %s", argv[1]); 39 if (update_passwd(bb_path_group_file, argv[1], NULL, NULL) < 0)
49 } 40 return EXIT_FAILURE;
50 if (del_line_matching(argv, bb_path_group_file) < 0) 41 if (ENABLE_FEATURE_SHADOWPASSWDS)
51 return EXIT_FAILURE; 42 if (update_passwd(bb_path_gshadow_file, argv[1], NULL, NULL) < 0)
52 if (ENABLE_FEATURE_SHADOWPASSWDS) { 43 return EXIT_FAILURE;
53 del_line_matching(argv, bb_path_gshadow_file); 44 } else {
45 /* delgroup USER GROUP */
46 if (update_passwd(bb_path_group_file, argv[2], NULL, argv[1]) < 0)
47 return EXIT_FAILURE;
48 if (ENABLE_FEATURE_SHADOWPASSWDS)
49 if (update_passwd(bb_path_gshadow_file, argv[2], NULL, argv[1]) < 0)
50 return EXIT_FAILURE;
51 }
54 } 52 }
55 return EXIT_SUCCESS; 53 return EXIT_SUCCESS;
56} 54}
diff --git a/mailutils/mail.c b/mailutils/mail.c
index 8e52a3efc..9b4bebce5 100644
--- a/mailutils/mail.c
+++ b/mailutils/mail.c
@@ -116,16 +116,15 @@ void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol)
116 SRC_BUF_SIZE = 45, /* This *MUST* be a multiple of 3 */ 116 SRC_BUF_SIZE = 45, /* This *MUST* be a multiple of 3 */
117 DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), 117 DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3),
118 }; 118 };
119
120#define src_buf text 119#define src_buf text
120 char src[SRC_BUF_SIZE];
121 FILE *fp = fp; 121 FILE *fp = fp;
122 ssize_t len = len; 122 ssize_t len = len;
123 char dst_buf[DST_BUF_SIZE + 1]; 123 char dst_buf[DST_BUF_SIZE + 1];
124 124
125 if (fname) { 125 if (fname) {
126 fp = (NOT_LONE_DASH(fname)) ? xfopen_for_read(fname) : (FILE *)text; 126 fp = (NOT_LONE_DASH(fname)) ? xfopen_for_read(fname) : (FILE *)text;
127 src_buf = bb_common_bufsiz1; 127 src_buf = src;
128 // N.B. strlen(NULL) segfaults!
129 } else if (text) { 128 } else if (text) {
130 // though we do not call uuencode(NULL, NULL) explicitly 129 // though we do not call uuencode(NULL, NULL) explicitly
131 // still we do not want to break things suddenly 130 // still we do not want to break things suddenly
@@ -161,73 +160,6 @@ void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol)
161#undef src_buf 160#undef src_buf
162} 161}
163 162
164void FAST_FUNC decode_base64(FILE *src_stream, FILE *dst_stream)
165{
166 int term_count = 1;
167
168 while (1) {
169 char translated[4];
170 int count = 0;
171
172 while (count < 4) {
173 char *table_ptr;
174 int ch;
175
176 /* Get next _valid_ character.
177 * global vector bb_uuenc_tbl_base64[] contains this string:
178 * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n"
179 */
180 do {
181 ch = fgetc(src_stream);
182 if (ch == EOF) {
183 bb_error_msg_and_die(bb_msg_read_error);
184 }
185 // - means end of MIME section
186 if ('-' == ch) {
187 // push it back
188 ungetc(ch, src_stream);
189 return;
190 }
191 table_ptr = strchr(bb_uuenc_tbl_base64, ch);
192 } while (table_ptr == NULL);
193
194 /* Convert encoded character to decimal */
195 ch = table_ptr - bb_uuenc_tbl_base64;
196
197 if (*table_ptr == '=') {
198 if (term_count == 0) {
199 translated[count] = '\0';
200 break;
201 }
202 term_count++;
203 } else if (*table_ptr == '\n') {
204 /* Check for terminating line */
205 if (term_count == 5) {
206 return;
207 }
208 term_count = 1;
209 continue;
210 } else {
211 translated[count] = ch;
212 count++;
213 term_count = 0;
214 }
215 }
216
217 /* Merge 6 bit chars to 8 bit */
218 if (count > 1) {
219 fputc(translated[0] << 2 | translated[1] >> 4, dst_stream);
220 }
221 if (count > 2) {
222 fputc(translated[1] << 4 | translated[2] >> 2, dst_stream);
223 }
224 if (count > 3) {
225 fputc(translated[2] << 6 | translated[3], dst_stream);
226 }
227 }
228}
229
230
231/* 163/*
232 * get username and password from a file descriptor 164 * get username and password from a file descriptor
233 */ 165 */
diff --git a/mailutils/mail.h b/mailutils/mail.h
index bb747c4c5..e0048fbfa 100644
--- a/mailutils/mail.h
+++ b/mailutils/mail.h
@@ -32,4 +32,3 @@ void FAST_FUNC get_cred_or_die(int fd);
32const FAST_FUNC char *command(const char *fmt, const char *param); 32const FAST_FUNC char *command(const char *fmt, const char *param);
33 33
34void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol); 34void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol);
35void FAST_FUNC decode_base64(FILE *src_stream, FILE *dst_stream);
diff --git a/mailutils/mime.c b/mailutils/mime.c
index 44c7d0216..682cf4536 100644
--- a/mailutils/mime.c
+++ b/mailutils/mime.c
@@ -225,7 +225,7 @@ static int parse(const char *boundary, char **argv)
225 // prepare unique string pattern 225 // prepare unique string pattern
226 uniq = xasprintf("%%llu.%u.%s", (unsigned)getpid(), safe_gethostname()); 226 uniq = xasprintf("%%llu.%u.%s", (unsigned)getpid(), safe_gethostname());
227 227
228//bb_info_msg("PARSE[%s]", terminator); 228//bb_info_msg("PARSE[%s]", uniq);
229 229
230 while ((line = xmalloc_fgets_str(stdin, "\r\n\r\n")) != NULL) { 230 while ((line = xmalloc_fgets_str(stdin, "\r\n\r\n")) != NULL) {
231 231
@@ -306,7 +306,7 @@ static int parse(const char *boundary, char **argv)
306 306
307 // dump to fp 307 // dump to fp
308 if (0 == strcasecmp(encoding, "base64")) { 308 if (0 == strcasecmp(encoding, "base64")) {
309 decode_base64(stdin, fp); 309 read_base64(stdin, fp, '-');
310 } else if (0 != strcasecmp(encoding, "7bit") 310 } else if (0 != strcasecmp(encoding, "7bit")
311 && 0 != strcasecmp(encoding, "8bit") 311 && 0 != strcasecmp(encoding, "8bit")
312 ) { 312 ) {
diff --git a/mailutils/popmaildir.c b/mailutils/popmaildir.c
index f37db03d5..77ec71129 100644
--- a/mailutils/popmaildir.c
+++ b/mailutils/popmaildir.c
@@ -109,9 +109,9 @@ int popmaildir_main(int argc UNUSED_PARAM, char **argv)
109 s[1] = '\0'; 109 s[1] = '\0';
110 // get md5 sum of "<stamp>password" string 110 // get md5 sum of "<stamp>password" string
111 md5_begin(&md5.ctx); 111 md5_begin(&md5.ctx);
112 md5_hash(buf, strlen(buf), &md5.ctx); 112 md5_hash(&md5.ctx, buf, strlen(buf));
113 md5_hash(G.pass, strlen(G.pass), &md5.ctx); 113 md5_hash(&md5.ctx, G.pass, strlen(G.pass));
114 md5_end(res, &md5.ctx); 114 md5_end(&md5.ctx, res);
115 *bin2hex(md5.hex, (char*)res, 16) = '\0'; 115 *bin2hex(md5.hex, (char*)res, 16) = '\0';
116 // APOP 116 // APOP
117 s = xasprintf("%s %s", G.user, md5.hex); 117 s = xasprintf("%s %s", G.user, md5.hex);
diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c
index 59591ee4b..ec97cf8af 100644
--- a/mailutils/sendmail.c
+++ b/mailutils/sendmail.c
@@ -221,12 +221,12 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
221 221
222 // analyze headers 222 // analyze headers
223 // To: or Cc: headers add recipients 223 // To: or Cc: headers add recipients
224 if (0 == strncasecmp("To: ", s, 4) || 0 == strncasecmp("Bcc: " + 1, s, 4)) { 224 if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) {
225 rcptto(sane_address(s+4)); 225 rcptto(sane_address(s+3));
226 goto addheader; 226 goto addheader;
227 // Bcc: header adds blind copy (hidden) recipient 227 // Bcc: header adds blind copy (hidden) recipient
228 } else if (0 == strncasecmp("Bcc: ", s, 5)) { 228 } else if (0 == strncasecmp("Bcc:", s, 4)) {
229 rcptto(sane_address(s+5)); 229 rcptto(sane_address(s+4));
230 free(s); 230 free(s);
231 // N.B. Bcc: vanishes from headers! 231 // N.B. Bcc: vanishes from headers!
232 232
diff --git a/miscutils/Config.src b/miscutils/Config.src
index 151f61bcc..4912daf88 100644
--- a/miscutils/Config.src
+++ b/miscutils/Config.src
@@ -136,7 +136,6 @@ config CHRT
136config CROND 136config CROND
137 bool "crond" 137 bool "crond"
138 default y 138 default y
139 select FEATURE_SUID
140 select FEATURE_SYSLOG 139 select FEATURE_SYSLOG
141 help 140 help
142 Crond is a background daemon that parses individual crontab 141 Crond is a background daemon that parses individual crontab
diff --git a/miscutils/man.c b/miscutils/man.c
index 2d3776cf3..b356e726f 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -182,16 +182,21 @@ int man_main(int argc UNUSED_PARAM, char **argv)
182 pager = "more"; 182 pager = "more";
183 } 183 }
184 184
185 /* Parse man.conf[ig] */ 185 /* Parse man.conf[ig] or man_db.conf */
186 /* man version 1.6f uses man.config */ 186 /* man version 1.6f uses man.config */
187 /* man-db implementation of man uses man_db.conf */
187 parser = config_open2("/etc/man.config", fopen_for_read); 188 parser = config_open2("/etc/man.config", fopen_for_read);
188 if (!parser) 189 if (!parser)
189 parser = config_open2("/etc/man.conf", fopen_for_read); 190 parser = config_open2("/etc/man.conf", fopen_for_read);
191 if (!parser)
192 parser = config_open2("/etc/man_db.conf", fopen_for_read);
190 193
191 while (config_read(parser, token, 2, 0, "# \t", PARSE_NORMAL)) { 194 while (config_read(parser, token, 2, 0, "# \t", PARSE_NORMAL)) {
192 if (!token[1]) 195 if (!token[1])
193 continue; 196 continue;
194 if (strcmp("MANPATH", token[0]) == 0) { 197 if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */
198 || strcmp("MANDATORY_MANPATH", token[0]) == 0
199 ) {
195 char *path = token[1]; 200 char *path = token[1];
196 while (*path) { 201 while (*path) {
197 char *next_path; 202 char *next_path;
diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c
index f42242687..6c85ea346 100644
--- a/miscutils/nandwrite.c
+++ b/miscutils/nandwrite.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * nandwrite.c - ported to busybox from mtd-utils 2 * nandwrite and nanddump ported to busybox from mtd-utils
3 * 3 *
4 * Author: Baruch Siach <baruch@tkos.co.il>, Orex Computed Radiography 4 * Author: Baruch Siach <baruch@tkos.co.il>, Orex Computed Radiography
5 * 5 *
@@ -9,8 +9,10 @@
9 */ 9 */
10 10
11//applet:IF_NANDWRITE(APPLET(nandwrite, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 11//applet:IF_NANDWRITE(APPLET(nandwrite, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
12//applet:IF_NANDWRITE(APPLET_ODDNAME(nanddump, nandwrite, _BB_DIR_USR_SBIN, _BB_SUID_DROP, nanddump))
12 13
13//kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o 14//kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o
15//kbuild:lib-$(CONFIG_NANDDUMP) += nandwrite.o
14 16
15//config:config NANDWRITE 17//config:config NANDWRITE
16//config: bool "nandwrite" 18//config: bool "nandwrite"
@@ -18,9 +20,13 @@
18//config: depends on PLATFORM_LINUX 20//config: depends on PLATFORM_LINUX
19//config: help 21//config: help
20//config: Write to the specified MTD device, with bad blocks awareness 22//config: Write to the specified MTD device, with bad blocks awareness
21 23//config:
22#include "libbb.h" 24//config:config NANDDUMP
23#include <mtd/mtd-user.h> 25//config: bool "nanddump"
26//config: default n
27//config: depends on PLATFORM_LINUX
28//config: help
29//config: Dump the content of raw NAND chip
24 30
25//usage:#define nandwrite_trivial_usage 31//usage:#define nandwrite_trivial_usage
26//usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]" 32//usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]"
@@ -30,18 +36,65 @@
30//usage: "\n -p Pad to page size" 36//usage: "\n -p Pad to page size"
31//usage: "\n -s ADDR Start address" 37//usage: "\n -s ADDR Start address"
32 38
39//usage:#define nanddump_trivial_usage
40//usage: "[-o] [-b] [-s ADDR] [-f FILE] MTD_DEVICE"
41//usage:#define nanddump_full_usage "\n\n"
42//usage: "Dump the sepcified MTD device\n"
43//usage: "\nOptions:"
44//usage: "\n -o Omit oob data"
45//usage: "\n -b Omit bad block from the dump"
46//usage: "\n -s ADDR Start address"
47//usage: "\n -l LEN Length"
48//usage: "\n -f FILE Dump to file ('-' for stdout)"
49
50#include "libbb.h"
51#include <mtd/mtd-user.h>
52
53#define IS_NANDDUMP (ENABLE_NANDDUMP && (!ENABLE_NANDWRITE || (applet_name[4] == 'd')))
54#define IS_NANDWRITE (ENABLE_NANDWRITE && (!ENABLE_NANDDUMP || (applet_name[4] != 'd')))
55
56#define OPT_p (1 << 0) /* nandwrite only */
57#define OPT_o (1 << 0) /* nanddump only */
58#define OPT_s (1 << 1)
59#define OPT_b (1 << 2)
60#define OPT_f (1 << 3)
61#define OPT_l (1 << 4)
62
63#define NAND_MAX_OOBSIZE 256
64/* helper for writing out 0xff for bad blocks pad */
65static void dump_bad(struct mtd_info_user *meminfo, unsigned len, int oob)
66{
67 unsigned char buf[meminfo->writesize];
68 unsigned count;
69
70 /* round len to the next page */
71 len = (len | ~(meminfo->writesize - 1)) + 1;
72
73 memset(buf, 0xff, sizeof(buf));
74 for (count = 0; count < len; count += meminfo->writesize) {
75 xwrite(STDOUT_FILENO, buf, meminfo->writesize);
76 if (oob)
77 xwrite(STDOUT_FILENO, buf, meminfo->oobsize);
78 }
79}
80
33static unsigned next_good_eraseblock(int fd, struct mtd_info_user *meminfo, 81static unsigned next_good_eraseblock(int fd, struct mtd_info_user *meminfo,
34 unsigned block_offset) 82 unsigned block_offset)
35{ 83{
36 while (1) { 84 while (1) {
37 loff_t offs; 85 loff_t offs;
38 if (block_offset >= meminfo->size) 86
39 bb_error_msg_and_die("not enough space in MTD device"); 87 if (block_offset >= meminfo->size) {
88 if (IS_NANDWRITE)
89 bb_error_msg_and_die("not enough space in MTD device");
90 return block_offset; /* let the caller exit */
91 }
40 offs = block_offset; 92 offs = block_offset;
41 if (xioctl(fd, MEMGETBADBLOCK, &offs) == 0) 93 if (xioctl(fd, MEMGETBADBLOCK, &offs) == 0)
42 return block_offset; 94 return block_offset;
43 /* ioctl returned 1 => "bad block" */ 95 /* ioctl returned 1 => "bad block" */
44 printf("Skipping bad block at 0x%08x\n", block_offset); 96 if (IS_NANDWRITE)
97 printf("Skipping bad block at 0x%08x\n", block_offset);
45 block_offset += meminfo->erasesize; 98 block_offset += meminfo->erasesize;
46 } 99 }
47} 100}
@@ -49,31 +102,49 @@ static unsigned next_good_eraseblock(int fd, struct mtd_info_user *meminfo,
49int nandwrite_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 102int nandwrite_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
50int nandwrite_main(int argc UNUSED_PARAM, char **argv) 103int nandwrite_main(int argc UNUSED_PARAM, char **argv)
51{ 104{
105 /* Buffer for OOB data */
106 unsigned char oobbuf[NAND_MAX_OOBSIZE];
52 unsigned opts; 107 unsigned opts;
53 int fd; 108 int fd;
54 ssize_t cnt; 109 ssize_t cnt;
55 unsigned mtdoffset, meminfo_writesize, blockstart; 110 unsigned mtdoffset, meminfo_writesize, blockstart, limit;
111 unsigned end_addr = ~0;
56 struct mtd_info_user meminfo; 112 struct mtd_info_user meminfo;
113 struct mtd_oob_buf oob;
57 unsigned char *filebuf; 114 unsigned char *filebuf;
58 const char *opt_s = "0"; 115 const char *opt_s = "0", *opt_f = "-", *opt_l;
59 enum { 116
60 OPT_p = (1 << 0), 117 if (IS_NANDDUMP) {
61 OPT_s = (1 << 1), 118 opt_complementary = "=1";
62 }; 119 opts = getopt32(argv, "os:bf:l:", &opt_s, &opt_f, &opt_l);
63 120 } else { /* nandwrite */
64 opt_complementary = "-1:?2"; 121 opt_complementary = "-1:?2";
65 opts = getopt32(argv, "ps:", &opt_s); 122 opts = getopt32(argv, "ps:", &opt_s);
123 }
66 argv += optind; 124 argv += optind;
67 125
68 if (argv[1]) 126 if (IS_NANDWRITE && argv[1])
69 xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO); 127 opt_f = argv[1];
128 if (!LONE_DASH(opt_f)) {
129 int tmp_fd = xopen(opt_f,
130 IS_NANDDUMP ? O_WRONLY | O_TRUNC | O_CREAT : O_RDONLY
131 );
132 xmove_fd(tmp_fd, IS_NANDDUMP ? STDOUT_FILENO : STDIN_FILENO);
133 }
70 134
71 fd = xopen(argv[0], O_RDWR); 135 fd = xopen(argv[0], O_RDWR);
72 xioctl(fd, MEMGETINFO, &meminfo); 136 xioctl(fd, MEMGETINFO, &meminfo);
73 137
74 mtdoffset = bb_strtou(opt_s, NULL, 0); 138 oob.start = 0;
75 if (errno) 139 oob.length = meminfo.oobsize;
76 bb_error_msg_and_die("invalid number '%s'", opt_s); 140 oob.ptr = oobbuf;
141
142 mtdoffset = xstrtou(opt_s, 0);
143 if (IS_NANDDUMP && (opts & OPT_l)) {
144 unsigned length = xstrtou(opt_l, 0);
145 if (length < meminfo.size - mtdoffset)
146 end_addr = mtdoffset + length;
147 }
77 148
78 /* Pull it into a CPU register (hopefully) - smaller code that way */ 149 /* Pull it into a CPU register (hopefully) - smaller code that way */
79 meminfo_writesize = meminfo.writesize; 150 meminfo_writesize = meminfo.writesize;
@@ -91,20 +162,39 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv)
91 * bad. 162 * bad.
92 */ 163 */
93 tmp = next_good_eraseblock(fd, &meminfo, blockstart); 164 tmp = next_good_eraseblock(fd, &meminfo, blockstart);
94 if (tmp != blockstart) /* bad block(s), advance mtdoffset */ 165 if (tmp != blockstart) {
166 /* bad block(s), advance mtdoffset */
167 if (IS_NANDDUMP & !(opts & OPT_b)) {
168 int bad_len = MIN(tmp, end_addr) - mtdoffset;
169 dump_bad(&meminfo, bad_len, !(opts & OPT_o));
170 }
95 mtdoffset = tmp; 171 mtdoffset = tmp;
172 }
96 } 173 }
97 174
98 cnt = -1; 175 cnt = -1;
99 while (mtdoffset < meminfo.size) { 176 limit = MIN(meminfo.size, end_addr);
177 while (mtdoffset < limit) {
178 int input_fd = IS_NANDWRITE ? STDIN_FILENO : fd;
179 int output_fd = IS_NANDWRITE ? fd : STDOUT_FILENO;
180
100 blockstart = mtdoffset & ~(meminfo.erasesize - 1); 181 blockstart = mtdoffset & ~(meminfo.erasesize - 1);
101 if (blockstart == mtdoffset) { 182 if (blockstart == mtdoffset) {
102 /* starting a new eraseblock */ 183 /* starting a new eraseblock */
103 mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart); 184 mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart);
104 printf("Writing at 0x%08x\n", mtdoffset); 185 if (IS_NANDWRITE)
186 printf("Writing at 0x%08x\n", mtdoffset);
187 else if (mtdoffset > blockstart) {
188 int bad_len = MIN(mtdoffset, limit) - blockstart;
189 dump_bad(&meminfo, bad_len, !(opts & OPT_o));
190 }
191 if (mtdoffset >= limit)
192 break;
105 } 193 }
194 xlseek(fd, mtdoffset, SEEK_SET);
195
106 /* get some more data from input */ 196 /* get some more data from input */
107 cnt = full_read(STDIN_FILENO, filebuf, meminfo_writesize); 197 cnt = full_read(input_fd, filebuf, meminfo_writesize);
108 if (cnt == 0) { 198 if (cnt == 0) {
109 /* even with -p, we do not pad past the end of input 199 /* even with -p, we do not pad past the end of input
110 * (-p only zero-pads last incomplete page) 200 * (-p only zero-pads last incomplete page)
@@ -112,20 +202,29 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv)
112 break; 202 break;
113 } 203 }
114 if (cnt < meminfo_writesize) { 204 if (cnt < meminfo_writesize) {
205 if (IS_NANDDUMP)
206 bb_error_msg_and_die("short read");
115 if (!(opts & OPT_p)) 207 if (!(opts & OPT_p))
116 bb_error_msg_and_die("input size is not rounded up to page size, " 208 bb_error_msg_and_die("input size is not rounded up to page size, "
117 "use -p to zero pad"); 209 "use -p to zero pad");
118 /* zero pad to end of write block */ 210 /* zero pad to end of write block */
119 memset(filebuf + cnt, 0, meminfo_writesize - cnt); 211 memset(filebuf + cnt, 0, meminfo_writesize - cnt);
120 } 212 }
121 xlseek(fd, mtdoffset, SEEK_SET); 213 xwrite(output_fd, filebuf, meminfo_writesize);
122 xwrite(fd, filebuf, meminfo_writesize); 214
215 if (IS_NANDDUMP && !(opts & OPT_o)) {
216 /* Dump OOB data */
217 oob.start = mtdoffset;
218 xioctl(fd, MEMREADOOB, &oob);
219 xwrite(output_fd, oobbuf, meminfo.oobsize);
220 }
221
123 mtdoffset += meminfo_writesize; 222 mtdoffset += meminfo_writesize;
124 if (cnt < meminfo_writesize) 223 if (cnt < meminfo_writesize)
125 break; 224 break;
126 } 225 }
127 226
128 if (cnt != 0) { 227 if (IS_NANDWRITE && cnt != 0) {
129 /* We filled entire MTD, but did we reach EOF on input? */ 228 /* We filled entire MTD, but did we reach EOF on input? */
130 if (full_read(STDIN_FILENO, filebuf, meminfo_writesize) != 0) { 229 if (full_read(STDIN_FILENO, filebuf, meminfo_writesize) != 0) {
131 /* no */ 230 /* no */
diff --git a/modutils/depmod.c b/modutils/depmod.c
index 006a7bcc1..85b64a229 100644
--- a/modutils/depmod.c
+++ b/modutils/depmod.c
@@ -8,6 +8,13 @@
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */ 9 */
10 10
11//applet:IF_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_DROP))
12
13//usage:#if !ENABLE_MODPROBE_SMALL
14//usage:#define depmod_trivial_usage NOUSAGE_STR
15//usage:#define depmod_full_usage ""
16//usage:#endif
17
11#include "libbb.h" 18#include "libbb.h"
12#include "modutils.h" 19#include "modutils.h"
13#include <sys/utsname.h> /* uname() */ 20#include <sys/utsname.h> /* uname() */
@@ -144,6 +151,8 @@ static void xfreopen_write(const char *file, FILE *f)
144 * Print to stdout all the symbols each module depends on 151 * Print to stdout all the symbols each module depends on
145 * and the module's file name which provides that symbol. 152 * and the module's file name which provides that symbol.
146 * -r No-op 153 * -r No-op
154 * -u No-op
155 * -q No-op
147 * 156 *
148 * So far we only support: [-rn] [-b BASE] [VERSION] [MODFILES]... 157 * So far we only support: [-rn] [-b BASE] [VERSION] [MODFILES]...
149 * -aAeF are accepted but ignored. -vC are not accepted. 158 * -aAeF are accepted but ignored. -vC are not accepted.
@@ -155,7 +164,10 @@ enum {
155 //OPT_e = (1 << 3), /* with -F, print unresolved symbols */ 164 //OPT_e = (1 << 3), /* with -F, print unresolved symbols */
156 //OPT_F = (1 << 4), /* System.map that contains the symbols */ 165 //OPT_F = (1 << 4), /* System.map that contains the symbols */
157 OPT_n = (1 << 5), /* dry-run, print to stdout only */ 166 OPT_n = (1 << 5), /* dry-run, print to stdout only */
158 OPT_r = (1 << 6) /* Compat dummy. Linux Makefile uses it */ 167 OPT_r = (1 << 6), /* Compat dummy. Linux Makefile uses it */
168 OPT_u = (1 << 7), /* -u,--unresolved-error: ignored */
169 OPT_q = (1 << 8), /* -q,--quiet: ignored */
170 OPT_C = (1 << 9), /* -C,--config etc_modules_conf: ignored */
159}; 171};
160 172
161int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 173int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -167,7 +179,7 @@ int depmod_main(int argc UNUSED_PARAM, char **argv)
167 struct utsname uts; 179 struct utsname uts;
168 int tmp; 180 int tmp;
169 181
170 getopt32(argv, "aAb:eF:nr", &moddir_base, NULL); 182 getopt32(argv, "aAb:eF:nruqC:", &moddir_base, NULL, NULL);
171 argv += optind; 183 argv += optind;
172 184
173 /* goto modules location */ 185 /* goto modules location */
diff --git a/modutils/insmod.c b/modutils/insmod.c
index 17fc18c09..7ec3cae47 100644
--- a/modutils/insmod.c
+++ b/modutils/insmod.c
@@ -7,16 +7,19 @@
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9 9
10//applet:IF_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_DROP))
11
10#include "libbb.h" 12#include "libbb.h"
11#include "modutils.h" 13#include "modutils.h"
12 14
13/* 2.6 style insmod has no options and required filename 15/* 2.6 style insmod has no options and required filename
14 * (not module name - .ko can't be omitted) */ 16 * (not module name - .ko can't be omitted) */
15 17
18//usage:#if !ENABLE_MODPROBE_SMALL
16//usage:#define insmod_trivial_usage 19//usage:#define insmod_trivial_usage
17//usage: IF_FEATURE_2_4_MODULES("[OPTIONS] MODULE ") 20//usage: IF_FEATURE_2_4_MODULES("[OPTIONS] MODULE ")
18//usage: IF_NOT_FEATURE_2_4_MODULES("FILE ") 21//usage: IF_NOT_FEATURE_2_4_MODULES("FILE ")
19//usage: "[symbol=value]..." 22//usage: "[SYMBOL=VALUE]..."
20//usage:#define insmod_full_usage "\n\n" 23//usage:#define insmod_full_usage "\n\n"
21//usage: "Load the specified kernel modules into the kernel" 24//usage: "Load the specified kernel modules into the kernel"
22//usage: IF_FEATURE_2_4_MODULES( "\n" 25//usage: IF_FEATURE_2_4_MODULES( "\n"
@@ -31,6 +34,7 @@
31//usage: ) 34//usage: )
32//usage: "\n -x Don't export externs" 35//usage: "\n -x Don't export externs"
33//usage: ) 36//usage: )
37//usage:#endif
34 38
35int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 39int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
36int insmod_main(int argc UNUSED_PARAM, char **argv) 40int insmod_main(int argc UNUSED_PARAM, char **argv)
diff --git a/modutils/lsmod.c b/modutils/lsmod.c
index 9558a2510..ab7c11f2a 100644
--- a/modutils/lsmod.c
+++ b/modutils/lsmod.c
@@ -7,6 +7,16 @@
7 * 7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */ 9 */
10
11//applet:IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_DROP))
12
13//usage:#if !ENABLE_MODPROBE_SMALL
14//usage:#define lsmod_trivial_usage
15//usage: ""
16//usage:#define lsmod_full_usage "\n\n"
17//usage: "List the currently loaded kernel modules"
18//usage:#endif
19
10#include "libbb.h" 20#include "libbb.h"
11#include "unicode.h" 21#include "unicode.h"
12 22
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index 05f2c34eb..ec3ddfb8f 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -8,6 +8,12 @@
8 * Licensed under GPLv2, see file LICENSE in this source tree. 8 * Licensed under GPLv2, see file LICENSE in this source tree.
9 */ 9 */
10 10
11//applet:IF_MODPROBE_SMALL(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP))
12//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe))
13//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe))
14//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe))
15//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe))
16
11#include "libbb.h" 17#include "libbb.h"
12/* After libbb.h, since it needs sys/types.h on some systems */ 18/* After libbb.h, since it needs sys/types.h on some systems */
13#include <sys/utsname.h> /* uname() */ 19#include <sys/utsname.h> /* uname() */
@@ -18,10 +24,13 @@ extern int delete_module(const char *module, unsigned flags);
18extern int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret); 24extern int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
19 25
20 26
21#define dbg1_error_msg(...) ((void)0) 27#if 1
22#define dbg2_error_msg(...) ((void)0) 28# define dbg1_error_msg(...) ((void)0)
23//#define dbg1_error_msg(...) bb_error_msg(__VA_ARGS__) 29# define dbg2_error_msg(...) ((void)0)
24//#define dbg2_error_msg(...) bb_error_msg(__VA_ARGS__) 30#else
31# define dbg1_error_msg(...) bb_error_msg(__VA_ARGS__)
32# define dbg2_error_msg(...) bb_error_msg(__VA_ARGS__)
33#endif
25 34
26#define DEPFILE_BB CONFIG_DEFAULT_DEPMOD_FILE".bb" 35#define DEPFILE_BB CONFIG_DEFAULT_DEPMOD_FILE".bb"
27 36
@@ -579,10 +588,9 @@ static void process_module(char *name, const char *cmdline_options)
579 588
580 /* rmmod? unload it by name */ 589 /* rmmod? unload it by name */
581 if (is_rmmod) { 590 if (is_rmmod) {
582 if (delete_module(name, O_NONBLOCK | O_EXCL) != 0 591 if (delete_module(name, O_NONBLOCK | O_EXCL) != 0) {
583 && !(option_mask32 & OPT_q) 592 if (!(option_mask32 & OPT_q))
584 ) { 593 bb_perror_msg("remove '%s'", name);
585 bb_perror_msg("remove '%s'", name);
586 goto ret; 594 goto ret;
587 } 595 }
588 /* N.B. we do not stop here - 596 /* N.B. we do not stop here -
@@ -594,9 +602,9 @@ static void process_module(char *name, const char *cmdline_options)
594 602
595 if (!info) { 603 if (!info) {
596 /* both dirscan and find_alias found nothing */ 604 /* both dirscan and find_alias found nothing */
597 if (applet_name[0] != 'd') /* it wasn't depmod */ 605 if (!is_rmmod && applet_name[0] != 'd') /* it wasn't rmmod or depmod */
598 bb_error_msg("module '%s' not found", name); 606 bb_error_msg("module '%s' not found", name);
599//TODO: _and_die()? 607//TODO: _and_die()? or should we continue (un)loading modules listed on cmdline?
600 goto ret; 608 goto ret;
601 } 609 }
602 610
@@ -686,6 +694,46 @@ The following options are useful for people managing distributions:
686*/ 694*/
687 695
688//usage:#if ENABLE_MODPROBE_SMALL 696//usage:#if ENABLE_MODPROBE_SMALL
697
698//usage:#define depmod_trivial_usage NOUSAGE_STR
699//usage:#define depmod_full_usage ""
700
701//usage:#define lsmod_trivial_usage
702//usage: ""
703//usage:#define lsmod_full_usage "\n\n"
704//usage: "List the currently loaded kernel modules"
705
706//usage:#define insmod_trivial_usage
707//usage: IF_FEATURE_2_4_MODULES("[OPTIONS] MODULE ")
708//usage: IF_NOT_FEATURE_2_4_MODULES("FILE ")
709//usage: "[SYMBOL=VALUE]..."
710//usage:#define insmod_full_usage "\n\n"
711//usage: "Load the specified kernel modules into the kernel"
712//usage: IF_FEATURE_2_4_MODULES( "\n"
713//usage: "\nOptions:"
714//usage: "\n -f Force module to load into the wrong kernel version"
715//usage: "\n -k Make module autoclean-able"
716//usage: "\n -v Verbose"
717//usage: "\n -q Quiet"
718//usage: "\n -L Lock: prevent simultaneous loads"
719//usage: IF_FEATURE_INSMOD_LOAD_MAP(
720//usage: "\n -m Output load map to stdout"
721//usage: )
722//usage: "\n -x Don't export externs"
723//usage: )
724
725//usage:#define rmmod_trivial_usage
726//usage: "[-wfa] [MODULE]..."
727//usage:#define rmmod_full_usage "\n\n"
728//usage: "Unload kernel modules\n"
729//usage: "\nOptions:"
730//usage: "\n -w Wait until the module is no longer used"
731//usage: "\n -f Force unload"
732//usage: "\n -a Remove all unused modules (recursively)"
733//usage:
734//usage:#define rmmod_example_usage
735//usage: "$ rmmod tulip\n"
736
689//usage:#define modprobe_trivial_usage 737//usage:#define modprobe_trivial_usage
690//usage: "[-qfwrsv] MODULE [symbol=value]..." 738//usage: "[-qfwrsv] MODULE [symbol=value]..."
691//usage:#define modprobe_full_usage "\n\n" 739//usage:#define modprobe_full_usage "\n\n"
@@ -696,7 +744,8 @@ The following options are useful for people managing distributions:
696//usage: "\n -f Force" 744//usage: "\n -f Force"
697//usage: "\n -w Wait for unload" 745//usage: "\n -w Wait for unload"
698//usage: "\n -s Report via syslog instead of stderr" 746//usage: "\n -s Report via syslog instead of stderr"
699//usage:#endif /* ENABLE_MODPROBE_SMALL */ 747
748//usage:#endif
700 749
701int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 750int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
702int modprobe_main(int argc UNUSED_PARAM, char **argv) 751int modprobe_main(int argc UNUSED_PARAM, char **argv)
@@ -811,8 +860,8 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
811 /* Load/remove modules. 860 /* Load/remove modules.
812 * Only rmmod loops here, modprobe has only argv[0] */ 861 * Only rmmod loops here, modprobe has only argv[0] */
813 do { 862 do {
814 process_module(*argv++, options); 863 process_module(*argv, options);
815 } while (*argv); 864 } while (*++argv);
816 865
817 if (ENABLE_FEATURE_CLEAN_UP) { 866 if (ENABLE_FEATURE_CLEAN_UP) {
818 IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);) 867 IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);)
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index ab35628f4..a5cf4babf 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -8,17 +8,7 @@
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */ 9 */
10 10
11/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t), 11//applet:IF_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP))
12 * we expect the full dependency list to be specified in modules.dep.
13 * Older versions would only export the direct dependency list.
14 */
15#include "libbb.h"
16#include "modutils.h"
17#include <sys/utsname.h>
18#include <fnmatch.h>
19
20//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
21#define DBG(...) ((void)0)
22 12
23//usage:#if !ENABLE_MODPROBE_SMALL 13//usage:#if !ENABLE_MODPROBE_SMALL
24//usage:#define modprobe_notes_usage 14//usage:#define modprobe_notes_usage
@@ -98,6 +88,19 @@
98//usage: ) 88//usage: )
99//usage:#endif /* !ENABLE_MODPROBE_SMALL */ 89//usage:#endif /* !ENABLE_MODPROBE_SMALL */
100 90
91#include "libbb.h"
92#include "modutils.h"
93#include <sys/utsname.h>
94#include <fnmatch.h>
95
96//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
97#define DBG(...) ((void)0)
98
99/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t),
100 * we expect the full dependency list to be specified in modules.dep.
101 * Older versions would only export the direct dependency list.
102 */
103
101/* Note that usage text doesn't document various 2.4 options 104/* Note that usage text doesn't document various 2.4 options
102 * we pull in through INSMOD_OPTS define */ 105 * we pull in through INSMOD_OPTS define */
103 106
diff --git a/modutils/rmmod.c b/modutils/rmmod.c
index aa1bb01d6..dde77731f 100644
--- a/modutils/rmmod.c
+++ b/modutils/rmmod.c
@@ -8,6 +8,21 @@
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */ 9 */
10 10
11//applet:IF_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_DROP))
12
13//usage:#if !ENABLE_MODPROBE_SMALL
14//usage:#define rmmod_trivial_usage
15//usage: "[-wfa] [MODULE]..."
16//usage:#define rmmod_full_usage "\n\n"
17//usage: "Unload kernel modules\n"
18//usage: "\nOptions:"
19//usage: "\n -w Wait until the module is no longer used"
20//usage: "\n -f Force unload"
21//usage: "\n -a Remove all unused modules (recursively)"
22//usage:#define rmmod_example_usage
23//usage: "$ rmmod tulip\n"
24//usage:#endif
25
11#include "libbb.h" 26#include "libbb.h"
12#include "modutils.h" 27#include "modutils.h"
13 28
diff --git a/networking/Config.src b/networking/Config.src
index 9fc122bf3..6dd7df754 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -804,7 +804,7 @@ config TELNETD
804 804
805 mount -t devpts devpts /dev/pts 805 mount -t devpts devpts /dev/pts
806 806
807 You need to be sure that Busybox has LOGIN and 807 You need to be sure that busybox has LOGIN and
808 FEATURE_SUID enabled. And finally, you should make 808 FEATURE_SUID enabled. And finally, you should make
809 certain that Busybox has been installed setuid root: 809 certain that Busybox has been installed setuid root:
810 810
diff --git a/networking/nbd-client.c b/networking/nbd-client.c
new file mode 100644
index 000000000..5ac190c32
--- /dev/null
+++ b/networking/nbd-client.c
@@ -0,0 +1,153 @@
1/*
2 * Copyright 2010 Rob Landley <rob@landley.net>
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6#include "libbb.h"
7#include <netinet/tcp.h>
8#include <linux/fs.h>
9
10//applet:IF_NBDCLIENT(APPLET_ODDNAME(nbd-client, nbdclient, _BB_DIR_USR_SBIN, _BB_SUID_DROP, nbdclient))
11
12//kbuild:lib-$(CONFIG_NBDCLIENT) += nbd-client.o
13
14//config:config NBDCLIENT
15//config: bool "nbd-client"
16//config: default y
17//config: help
18//config: Network block device client
19
20#define NBD_SET_SOCK _IO(0xab, 0)
21#define NBD_SET_BLKSIZE _IO(0xab, 1)
22#define NBD_SET_SIZE _IO(0xab, 2)
23#define NBD_DO_IT _IO(0xab, 3)
24#define NBD_CLEAR_SOCK _IO(0xab, 4)
25#define NBD_CLEAR_QUEUE _IO(0xab, 5)
26#define NBD_PRINT_DEBUG _IO(0xab, 6)
27#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7)
28#define NBD_DISCONNECT _IO(0xab, 8)
29#define NBD_SET_TIMEOUT _IO(0xab, 9)
30
31//usage:#define nbdclient_trivial_usage
32//usage: "HOST PORT BLOCKDEV"
33//usage:#define nbdclient_full_usage "\n\n"
34//usage: "Connect to HOST and provide a network block device on BLOCKDEV"
35
36//TODO: more compat with nbd-client version 2.9.13 -
37//Usage: nbd-client [bs=blocksize] [timeout=sec] host port nbd_device [-swap] [-persist] [-nofork]
38//Or : nbd-client -d nbd_device
39//Or : nbd-client -c nbd_device
40//Default value for blocksize is 1024 (recommended for ethernet)
41//Allowed values for blocksize are 512,1024,2048,4096
42//Note, that kernel 2.4.2 and older ones do not work correctly with
43//blocksizes other than 1024 without patches
44
45int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
46int nbdclient_main(int argc, char **argv)
47{
48 unsigned long timeout = 0;
49 int nofork = 0;
50 char *host, *port, *device;
51 struct nbd_header_t {
52 uint64_t magic1; // "NBDMAGIC"
53 uint64_t magic2; // 0x420281861253 big endian
54 uint64_t devsize;
55 uint32_t flags;
56 char data[124];
57 } nbd_header;
58 struct bug_check {
59 char c[offsetof(struct nbd_header_t, data) == 8+8+8+4 ? 1 : -1];
60 };
61
62 // Parse command line stuff (just a stub now)
63 if (argc != 4)
64 bb_show_usage();
65
66#if !BB_MMU
67 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
68#endif
69
70 host = argv[1];
71 port = argv[2];
72 device = argv[3];
73
74 // Repeat until spanked (-persist behavior)
75 for (;;) {
76 int sock, nbd;
77 int ro;
78
79 // Make sure the /dev/nbd exists
80 nbd = xopen(device, O_RDWR);
81
82 // Find and connect to server
83 sock = create_and_connect_stream_or_die(host, xatou16(port));
84 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &const_int_1, sizeof(const_int_1));
85
86 // Log on to the server
87 xread(sock, &nbd_header, 8+8+8+4 + 124);
88 if (memcmp(&nbd_header.magic1, "NBDMAGIC""\x00\x00\x42\x02\x81\x86\x12\x53", 16) != 0)
89 bb_error_msg_and_die("login failed");
90
91 // Set 4k block size. Everything uses that these days
92 ioctl(nbd, NBD_SET_BLKSIZE, 4096);
93 ioctl(nbd, NBD_SET_SIZE_BLOCKS, SWAP_BE64(nbd_header.devsize) / 4096);
94 ioctl(nbd, NBD_CLEAR_SOCK);
95
96 // If the sucker was exported read only, respect that locally
97 ro = (nbd_header.flags & SWAP_BE32(2)) / SWAP_BE32(2);
98 if (ioctl(nbd, BLKROSET, &ro) < 0)
99 bb_perror_msg_and_die("BLKROSET");
100
101 if (timeout)
102 if (ioctl(nbd, NBD_SET_TIMEOUT, timeout))
103 bb_perror_msg_and_die("NBD_SET_TIMEOUT");
104 if (ioctl(nbd, NBD_SET_SOCK, sock))
105 bb_perror_msg_and_die("NBD_SET_SOCK");
106
107 // if (swap) mlockall(MCL_CURRENT|MCL_FUTURE);
108
109#if BB_MMU
110 // Open the device to force reread of the partition table.
111 // Need to do it in a separate process, since open(device)
112 // needs some other process to sit in ioctl(nbd, NBD_DO_IT).
113 if (fork() == 0) {
114 char *s = strrchr(device, '/');
115 sprintf(nbd_header.data, "/sys/block/%.32s/pid", s ? s + 1 : device);
116 // Is it up yet?
117 for (;;) {
118 int fd = open(nbd_header.data, O_RDONLY);
119 if (fd >= 0) {
120 //close(fd);
121 break;
122 }
123 sleep(1);
124 }
125 open(device, O_RDONLY);
126 return 0;
127 }
128
129 // Daemonize here
130 if (!nofork) {
131 daemon(0, 0);
132 nofork = 1;
133 }
134#endif
135
136 // This turns us (the process that calls this ioctl)
137 // into a dedicated NBD request handler.
138 // We block here for a long time.
139 // When exactly ioctl returns? On a signal,
140 // or if someone does ioctl(NBD_DISCONNECT) [nbd-client -d].
141 if (ioctl(nbd, NBD_DO_IT) >= 0 || errno == EBADR) {
142 // Flush queue and exit
143 ioctl(nbd, NBD_CLEAR_QUEUE);
144 ioctl(nbd, NBD_CLEAR_SOCK);
145 break;
146 }
147
148 close(sock);
149 close(nbd);
150 }
151
152 return 0;
153}
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 6b5b176c9..8594a67a6 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -57,7 +57,8 @@
57//usage:#define nc_trivial_usage 57//usage:#define nc_trivial_usage
58//usage: "[OPTIONS] HOST PORT - connect" 58//usage: "[OPTIONS] HOST PORT - connect"
59//usage: IF_NC_SERVER("\n" 59//usage: IF_NC_SERVER("\n"
60//usage: "nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen") 60//usage: "nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen"
61//usage: )
61//usage:#define nc_full_usage "\n\n" 62//usage:#define nc_full_usage "\n\n"
62//usage: "Options:" 63//usage: "Options:"
63//usage: "\n -e PROG Run PROG after connect (must be last)" 64//usage: "\n -e PROG Run PROG after connect (must be last)"
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 6707e9bdb..ca4afa045 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -1765,6 +1765,10 @@ recv_and_process_client_pkt(void /*int fd*/)
1765 /* this time was obtained between poll() and recv() */ 1765 /* this time was obtained between poll() and recv() */
1766 msg.m_rectime = d_to_lfp(G.cur_time); 1766 msg.m_rectime = d_to_lfp(G.cur_time);
1767 msg.m_xmttime = d_to_lfp(gettime1900d()); /* this instant */ 1767 msg.m_xmttime = d_to_lfp(gettime1900d()); /* this instant */
1768 if (G.peer_cnt == 0) {
1769 /* we have no peers: "stratum 1 server" mode. reftime = our own time */
1770 G.reftime = G.cur_time;
1771 }
1768 msg.m_reftime = d_to_lfp(G.reftime); 1772 msg.m_reftime = d_to_lfp(G.reftime);
1769 msg.m_orgtime = query_xmttime; 1773 msg.m_orgtime = query_xmttime;
1770 msg.m_rootdelay = d_to_sfp(G.rootdelay); 1774 msg.m_rootdelay = d_to_sfp(G.rootdelay);
@@ -1902,8 +1906,13 @@ static NOINLINE void ntp_init(char **argv)
1902 bb_show_usage(); 1906 bb_show_usage();
1903// if (opts & OPT_x) /* disable stepping, only slew is allowed */ 1907// if (opts & OPT_x) /* disable stepping, only slew is allowed */
1904// G.time_was_stepped = 1; 1908// G.time_was_stepped = 1;
1905 while (peers) 1909 if (peers) {
1906 add_peers(llist_pop(&peers)); 1910 while (peers)
1911 add_peers(llist_pop(&peers));
1912 } else {
1913 /* -l but no peers: "stratum 1 server" mode */
1914 G.stratum = 1;
1915 }
1907 if (!(opts & OPT_n)) { 1916 if (!(opts & OPT_n)) {
1908 bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv); 1917 bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv);
1909 logmode = LOGMODE_NONE; 1918 logmode = LOGMODE_NONE;
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 97ab4cdbb..b6b274d91 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -37,6 +37,7 @@ const struct dhcp_optflag dhcp_optflags[] = {
37 { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */ 37 { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */
38 { OPTION_U16 , 0x1a }, /* DHCP_MTU */ 38 { OPTION_U16 , 0x1a }, /* DHCP_MTU */
39 { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ 39 { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */
40 { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */
40 { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ 41 { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */
41 { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */ 42 { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */
42 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */ 43 { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */
@@ -54,6 +55,7 @@ const struct dhcp_optflag dhcp_optflags[] = {
54 { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */ 55 { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */
55#endif 56#endif
56 { OPTION_STATIC_ROUTES , 0x79 }, /* DHCP_STATIC_ROUTES */ 57 { OPTION_STATIC_ROUTES , 0x79 }, /* DHCP_STATIC_ROUTES */
58 { OPTION_STATIC_ROUTES , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
57 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ 59 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */
58 60
59 /* Options below have no match in dhcp_option_strings[], 61 /* Options below have no match in dhcp_option_strings[],
@@ -95,6 +97,7 @@ const char dhcp_option_strings[] ALIGN1 =
95 "ipttl" "\0" /* DHCP_IP_TTL */ 97 "ipttl" "\0" /* DHCP_IP_TTL */
96 "mtu" "\0" /* DHCP_MTU */ 98 "mtu" "\0" /* DHCP_MTU */
97 "broadcast" "\0" /* DHCP_BROADCAST */ 99 "broadcast" "\0" /* DHCP_BROADCAST */
100 "routes" "\0" /* DHCP_ROUTES */
98 "nisdomain" "\0" /* DHCP_NIS_DOMAIN */ 101 "nisdomain" "\0" /* DHCP_NIS_DOMAIN */
99 "nissrv" "\0" /* DHCP_NIS_SERVER */ 102 "nissrv" "\0" /* DHCP_NIS_SERVER */
100 "ntpsrv" "\0" /* DHCP_NTP_SERVER */ 103 "ntpsrv" "\0" /* DHCP_NTP_SERVER */
@@ -114,6 +117,7 @@ const char dhcp_option_strings[] ALIGN1 =
114// doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES 117// doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES
115// is not handled yet by "string->option" conversion code: 118// is not handled yet by "string->option" conversion code:
116 "staticroutes" "\0"/* DHCP_STATIC_ROUTES */ 119 "staticroutes" "\0"/* DHCP_STATIC_ROUTES */
120 "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
117 "wpad" "\0" /* DHCP_WPAD */ 121 "wpad" "\0" /* DHCP_WPAD */
118 ; 122 ;
119 123
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index c5abf17d5..9020b9c96 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -123,6 +123,7 @@ enum {
123//#define DHCP_IP_TTL 0x17 123//#define DHCP_IP_TTL 0x17
124//#define DHCP_MTU 0x1a 124//#define DHCP_MTU 0x1a
125//#define DHCP_BROADCAST 0x1c 125//#define DHCP_BROADCAST 0x1c
126//#define DHCP_ROUTES 0x21
126//#define DHCP_NIS_DOMAIN 0x28 127//#define DHCP_NIS_DOMAIN 0x28
127//#define DHCP_NIS_SERVER 0x29 128//#define DHCP_NIS_SERVER 0x29
128//#define DHCP_NTP_SERVER 0x2a 129//#define DHCP_NTP_SERVER 0x2a
@@ -144,6 +145,7 @@ enum {
144//#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */ 145//#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */
145//#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */ 146//#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */
146//#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */ 147//#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */
148//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */
147//#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */ 149//#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */
148#define DHCP_END 0xff 150#define DHCP_END 0xff
149 151
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index de1b79844..27d6ad1a8 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -89,6 +89,7 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
89 89
90 /* option points to OPT_DATA, need to go back and get OPT_LEN */ 90 /* option points to OPT_DATA, need to go back and get OPT_LEN */
91 len = option[OPT_LEN - OPT_DATA]; 91 len = option[OPT_LEN - OPT_DATA];
92
92 type = optflag->flags & OPTION_TYPE_MASK; 93 type = optflag->flags & OPTION_TYPE_MASK;
93 optlen = dhcp_option_lengths[type]; 94 optlen = dhcp_option_lengths[type];
94 upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen); 95 upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen);
@@ -97,17 +98,16 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
97 dest += sprintf(ret, "%s=", opt_name); 98 dest += sprintf(ret, "%s=", opt_name);
98 99
99 while (len >= optlen) { 100 while (len >= optlen) {
101 unsigned ip_ofs = 0;
102
100 switch (type) { 103 switch (type) {
101 case OPTION_IP_PAIR: 104 case OPTION_IP_PAIR:
102 dest += sprint_nip(dest, "", option); 105 dest += sprint_nip(dest, "", option);
103 *dest++ = '/'; 106 *dest++ = '/';
104 option += 4; 107 ip_ofs = 4;
105 optlen = 4; 108 /* fall through */
106 case OPTION_IP: 109 case OPTION_IP:
107 dest += sprint_nip(dest, "", option); 110 dest += sprint_nip(dest, "", option + ip_ofs);
108// TODO: it can be a list only if (optflag->flags & OPTION_LIST).
109// Should we bail out/warn if we see multi-ip option which is
110// not allowed to be such? For example, DHCP_BROADCAST...
111 break; 111 break;
112// case OPTION_BOOLEAN: 112// case OPTION_BOOLEAN:
113// dest += sprintf(dest, *option ? "yes" : "no"); 113// dest += sprintf(dest, *option ? "yes" : "no");
@@ -218,7 +218,10 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
218 } /* switch */ 218 } /* switch */
219 option += optlen; 219 option += optlen;
220 len -= optlen; 220 len -= optlen;
221 if (len <= 0) 221// TODO: it can be a list only if (optflag->flags & OPTION_LIST).
222// Should we bail out/warn if we see multi-ip option which is
223// not allowed to be such (for example, DHCP_BROADCAST)? -
224 if (len <= 0 /* || !(optflag->flags & OPTION_LIST) */)
222 break; 225 break;
223 *dest++ = ' '; 226 *dest++ = ' ';
224 *dest = '\0'; 227 *dest = '\0';
diff --git a/networking/udhcp/dhcprelay.c b/networking/udhcp/dhcprelay.c
index a2c7f359d..759a4ba03 100644
--- a/networking/udhcp/dhcprelay.c
+++ b/networking/udhcp/dhcprelay.c
@@ -11,9 +11,12 @@
11 */ 11 */
12#include "common.h" 12#include "common.h"
13 13
14#define SERVER_PORT 67 14#define SERVER_PORT 67
15#define SELECT_TIMEOUT 5 /* select timeout in sec. */ 15
16#define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */ 16/* lifetime of an xid entry in sec. */
17#define MAX_LIFETIME 2*60
18/* select timeout in sec. */
19#define SELECT_TIMEOUT (MAX_LIFETIME / 8)
17 20
18/* This list holds information about clients. The xid_* functions manipulate this list. */ 21/* This list holds information about clients. The xid_* functions manipulate this list. */
19struct xid_item { 22struct xid_item {
@@ -67,11 +70,11 @@ static struct xid_item *xid_find(uint32_t xid)
67 struct xid_item *item = dhcprelay_xid_list.next; 70 struct xid_item *item = dhcprelay_xid_list.next;
68 while (item != NULL) { 71 while (item != NULL) {
69 if (item->xid == xid) { 72 if (item->xid == xid) {
70 return item; 73 break;
71 } 74 }
72 item = item->next; 75 item = item->next;
73 } 76 }
74 return NULL; 77 return item;
75} 78}
76 79
77static void xid_del(uint32_t xid) 80static void xid_del(uint32_t xid)
@@ -110,62 +113,72 @@ static int get_dhcp_packet_type(struct dhcp_packet *p)
110} 113}
111 114
112/** 115/**
113 * get_client_devices - parses the devices list 116 * make_iface_list - parses client/server interface names
114 * dev_list - comma separated list of devices
115 * returns array 117 * returns array
116 */ 118 */
117static char **get_client_devices(char *dev_list, int *client_number) 119static char **make_iface_list(char **client_and_server_ifaces, int *client_number)
118{ 120{
119 char *s, **client_dev; 121 char *s, **iface_list;
120 int i, cn; 122 int i, cn;
121 123
122 /* copy list */ 124 /* get number of items */
123 dev_list = xstrdup(dev_list); 125 cn = 2; /* 1 server iface + at least 1 client one */
124 126 s = client_and_server_ifaces[0]; /* list of client ifaces */
125 /* get number of items, replace ',' with NULs */
126 s = dev_list;
127 cn = 1;
128 while (*s) { 127 while (*s) {
129 if (*s == ',') { 128 if (*s == ',')
130 *s = '\0';
131 cn++; 129 cn++;
132 }
133 s++; 130 s++;
134 } 131 }
135 *client_number = cn; 132 *client_number = cn;
136 133
137 /* create vector of pointers */ 134 /* create vector of pointers */
138 client_dev = xzalloc(cn * sizeof(*client_dev)); 135 iface_list = xzalloc(cn * sizeof(iface_list[0]));
139 client_dev[0] = dev_list; 136
137 iface_list[0] = client_and_server_ifaces[1]; /* server iface */
138
140 i = 1; 139 i = 1;
141 while (i != cn) { 140 s = xstrdup(client_and_server_ifaces[0]); /* list of client ifaces */
142 client_dev[i] = client_dev[i - 1] + strlen(client_dev[i - 1]) + 1; 141 goto store_client_iface_name;
143 i++; 142
143 while (i < cn) {
144 if (*s++ == ',') {
145 s[-1] = '\0';
146 store_client_iface_name:
147 iface_list[i++] = s;
148 }
144 } 149 }
145 return client_dev; 150
151 return iface_list;
146} 152}
147 153
148/* Creates listen sockets (in fds) bound to client and server ifaces, 154/* Creates listen sockets (in fds) bound to client and server ifaces,
149 * and returns numerically max fd. 155 * and returns numerically max fd.
150 */ 156 */
151static int init_sockets(char **client_ifaces, int num_clients, 157static int init_sockets(char **iface_list, int num_clients, int *fds)
152 char *server_iface, int *fds)
153{ 158{
154 int i, n; 159 int i, n;
155 160
156 /* talk to real server on bootps */ 161 n = 0;
157 fds[0] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, server_iface); 162 for (i = 0; i < num_clients; i++) {
158 n = fds[0]; 163 fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, iface_list[i]);
159 164 if (n < fds[i])
160 for (i = 1; i < num_clients; i++) {
161 /* listen for clients on bootps */
162 fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, client_ifaces[i-1]);
163 if (fds[i] > n)
164 n = fds[i]; 165 n = fds[i];
165 } 166 }
166 return n; 167 return n;
167} 168}
168 169
170static int sendto_ip4(int sock, const void *msg, int msg_len, struct sockaddr_in *to)
171{
172 int err;
173
174 errno = 0;
175 err = sendto(sock, msg, msg_len, 0, (struct sockaddr*) to, sizeof(*to));
176 err -= msg_len;
177 if (err)
178 bb_perror_msg("sendto");
179 return err;
180}
181
169/** 182/**
170 * pass_to_server() - forwards dhcp packets from client to server 183 * pass_to_server() - forwards dhcp packets from client to server
171 * p - packet to send 184 * p - packet to send
@@ -174,7 +187,7 @@ static int init_sockets(char **client_ifaces, int num_clients,
174static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds, 187static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds,
175 struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) 188 struct sockaddr_in *client_addr, struct sockaddr_in *server_addr)
176{ 189{
177 int res, type; 190 int type;
178 191
179 /* check packet_type */ 192 /* check packet_type */
180 type = get_dhcp_packet_type(p); 193 type = get_dhcp_packet_type(p);
@@ -188,13 +201,12 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in
188 /* create new xid entry */ 201 /* create new xid entry */
189 xid_add(p->xid, client_addr, client); 202 xid_add(p->xid, client_addr, client);
190 203
191 /* forward request to LAN (server) */ 204 /* forward request to server */
192 errno = 0; 205 /* note that we send from fds[0] which is bound to SERVER_PORT (67).
193 res = sendto(fds[0], p, packet_len, 0, (struct sockaddr*)server_addr, 206 * IOW: we send _from_ SERVER_PORT! Although this may look strange,
194 sizeof(struct sockaddr_in)); 207 * RFC 1542 not only allows, but prescribes this for BOOTP relays.
195 if (res != packet_len) { 208 */
196 bb_perror_msg("sendto"); 209 sendto_ip4(fds[0], p, packet_len, server_addr);
197 }
198} 210}
199 211
200/** 212/**
@@ -203,7 +215,7 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in
203 */ 215 */
204static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds) 216static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds)
205{ 217{
206 int res, type; 218 int type;
207 struct xid_item *item; 219 struct xid_item *item;
208 220
209 /* check xid */ 221 /* check xid */
@@ -218,14 +230,12 @@ static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds)
218 return; 230 return;
219 } 231 }
220 232
233//TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set!
221 if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY)) 234 if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY))
222 item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST); 235 item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST);
223 errno = 0; 236
224 res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*) &(item->ip), 237 if (sendto_ip4(fds[item->client], p, packet_len, &item->ip) != 0) {
225 sizeof(item->ip)); 238 return; /* send error occurred */
226 if (res != packet_len) {
227 bb_perror_msg("sendto");
228 return;
229 } 239 }
230 240
231 /* remove xid entry */ 241 /* remove xid entry */
@@ -235,36 +245,30 @@ static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds)
235int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 245int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
236int dhcprelay_main(int argc, char **argv) 246int dhcprelay_main(int argc, char **argv)
237{ 247{
238 struct dhcp_packet dhcp_msg;
239 struct sockaddr_in server_addr; 248 struct sockaddr_in server_addr;
240 struct sockaddr_in client_addr; 249 char **iface_list;
241 fd_set rfds;
242 char **client_ifaces;
243 int *fds; 250 int *fds;
244 int num_sockets, max_socket; 251 int num_sockets, max_socket;
245 uint32_t our_nip; 252 uint32_t our_nip;
246 253
247 server_addr.sin_family = AF_INET; 254 server_addr.sin_family = AF_INET;
255 server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
248 server_addr.sin_port = htons(SERVER_PORT); 256 server_addr.sin_port = htons(SERVER_PORT);
249 257
250 /* dhcprelay client_iface1,client_iface2,... server_iface [server_IP] */ 258 /* dhcprelay CLIENT_IFACE1[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP] */
251 if (argc == 4) { 259 if (argc == 4) {
252 if (!inet_aton(argv[3], &server_addr.sin_addr)) 260 if (!inet_aton(argv[3], &server_addr.sin_addr))
253 bb_perror_msg_and_die("bad server IP"); 261 bb_perror_msg_and_die("bad server IP");
254 } else if (argc == 3) { 262 } else if (argc != 3) {
255 server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
256 } else {
257 bb_show_usage(); 263 bb_show_usage();
258 } 264 }
259 265
260 /* Produce list of client ifaces */ 266 iface_list = make_iface_list(argv + 1, &num_sockets);
261 client_ifaces = get_client_devices(argv[1], &num_sockets);
262 267
263 num_sockets++; /* for server socket at fds[0] */
264 fds = xmalloc(num_sockets * sizeof(fds[0])); 268 fds = xmalloc(num_sockets * sizeof(fds[0]));
265 269
266 /* Create sockets and bind one to every iface */ 270 /* Create sockets and bind one to every iface */
267 max_socket = init_sockets(client_ifaces, num_sockets, argv[2], fds); 271 max_socket = init_sockets(iface_list, num_sockets, fds);
268 272
269 /* Get our IP on server_iface */ 273 /* Get our IP on server_iface */
270 if (udhcp_read_interface(argv[2], NULL, &our_nip, NULL)) 274 if (udhcp_read_interface(argv[2], NULL, &our_nip, NULL))
@@ -272,11 +276,10 @@ int dhcprelay_main(int argc, char **argv)
272 276
273 /* Main loop */ 277 /* Main loop */
274 while (1) { 278 while (1) {
275//reinit stuff from time to time? go back to get_client_devices 279// reinit stuff from time to time? go back to make_iface_list
276//every N minutes? 280// every N minutes?
281 fd_set rfds;
277 struct timeval tv; 282 struct timeval tv;
278 size_t packlen;
279 socklen_t addr_size;
280 int i; 283 int i;
281 284
282 FD_ZERO(&rfds); 285 FD_ZERO(&rfds);
@@ -285,6 +288,9 @@ int dhcprelay_main(int argc, char **argv)
285 tv.tv_sec = SELECT_TIMEOUT; 288 tv.tv_sec = SELECT_TIMEOUT;
286 tv.tv_usec = 0; 289 tv.tv_usec = 0;
287 if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) { 290 if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) {
291 int packlen;
292 struct dhcp_packet dhcp_msg;
293
288 /* server */ 294 /* server */
289 if (FD_ISSET(fds[0], &rfds)) { 295 if (FD_ISSET(fds[0], &rfds)) {
290 packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]); 296 packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]);
@@ -292,24 +298,65 @@ int dhcprelay_main(int argc, char **argv)
292 pass_to_client(&dhcp_msg, packlen, fds); 298 pass_to_client(&dhcp_msg, packlen, fds);
293 } 299 }
294 } 300 }
301
295 /* clients */ 302 /* clients */
296 for (i = 1; i < num_sockets; i++) { 303 for (i = 1; i < num_sockets; i++) {
304 struct sockaddr_in client_addr;
305 socklen_t addr_size;
306
297 if (!FD_ISSET(fds[i], &rfds)) 307 if (!FD_ISSET(fds[i], &rfds))
298 continue; 308 continue;
299 addr_size = sizeof(struct sockaddr_in); 309
310 addr_size = sizeof(client_addr);
300 packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0, 311 packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0,
301 (struct sockaddr *)(&client_addr), &addr_size); 312 (struct sockaddr *)(&client_addr), &addr_size);
302 if (packlen <= 0) 313 if (packlen <= 0)
303 continue; 314 continue;
304 315
305 /* Get our IP on corresponding client_iface */ 316 /* Get our IP on corresponding client_iface */
306//why? what if server can't route such IP? 317// RFC 1542
307 if (udhcp_read_interface(client_ifaces[i-1], NULL, &dhcp_msg.gateway_nip, NULL)) { 318// 4.1 General BOOTP Processing for Relay Agents
308 /* Fall back to our server_iface's IP */ 319// 4.1.1 BOOTREQUEST Messages
309//this makes more sense! 320// If the relay agent does decide to relay the request, it MUST examine
321// the 'giaddr' ("gateway" IP address) field. If this field is zero,
322// the relay agent MUST fill this field with the IP address of the
323// interface on which the request was received. If the interface has
324// more than one IP address logically associated with it, the relay
325// agent SHOULD choose one IP address associated with that interface and
326// use it consistently for all BOOTP messages it relays. If the
327// 'giaddr' field contains some non-zero value, the 'giaddr' field MUST
328// NOT be modified. The relay agent MUST NOT, under any circumstances,
329// fill the 'giaddr' field with a broadcast address as is suggested in
330// [1] (Section 8, sixth paragraph).
331
332// but why? what if server can't route such IP? Client ifaces may be, say, NATed!
333
334// 4.1.2 BOOTREPLY Messages
335// BOOTP relay agents relay BOOTREPLY messages only to BOOTP clients.
336// It is the responsibility of BOOTP servers to send BOOTREPLY messages
337// directly to the relay agent identified in the 'giaddr' field.
338// (yeah right, unless it is impossible... see comment above)
339// Therefore, a relay agent may assume that all BOOTREPLY messages it
340// receives are intended for BOOTP clients on its directly-connected
341// networks.
342//
343// When a relay agent receives a BOOTREPLY message, it should examine
344// the BOOTP 'giaddr', 'yiaddr', 'chaddr', 'htype', and 'hlen' fields.
345// These fields should provide adequate information for the relay agent
346// to deliver the BOOTREPLY message to the client.
347//
348// The 'giaddr' field can be used to identify the logical interface from
349// which the reply must be sent (i.e., the host or router interface
350// connected to the same network as the BOOTP client). If the content
351// of the 'giaddr' field does not match one of the relay agent's
352// directly-connected logical interfaces, the BOOTREPLY messsage MUST be
353// silently discarded.
354 if (udhcp_read_interface(iface_list[i], NULL, &dhcp_msg.gateway_nip, NULL)) {
355 /* Fall back to our IP on server iface */
356// this makes more sense!
310 dhcp_msg.gateway_nip = our_nip; 357 dhcp_msg.gateway_nip = our_nip;
311 } 358 }
312//maybe set dhcp_msg.flags |= BROADCAST_FLAG too? 359// maybe dhcp_msg.hops++? drop packets with too many hops (RFC 1542 says 4 or 16)?
313 pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr); 360 pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr);
314 } 361 }
315 } 362 }
diff --git a/procps/free.c b/procps/free.c
index be65f46f1..efbac5ba6 100644
--- a/procps/free.c
+++ b/procps/free.c
@@ -11,47 +11,58 @@
11 11
12#include "libbb.h" 12#include "libbb.h"
13 13
14struct globals {
15 unsigned mem_unit;
16#if ENABLE_DESKTOP
17 unsigned unit_steps;
18# define G_unit_steps G.unit_steps
19#else
20# define G_unit_steps 10
21#endif
22};
23#define G (*(struct globals*)&bb_common_bufsiz1)
24#define INIT_G() do { } while (0)
25
26
27static unsigned long long scale(unsigned long d)
28{
29 return ((unsigned long long)d * G.mem_unit) >> G_unit_steps;
30}
31
32
14int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 33int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
15int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) 34int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
16{ 35{
17 struct sysinfo info; 36 struct sysinfo info;
18 unsigned mem_unit; 37
38 INIT_G();
19 39
20#if ENABLE_DESKTOP 40#if ENABLE_DESKTOP
21 if (argv[1] && argv[1][0] == '-') 41 G.unit_steps = 10;
22 bb_show_usage(); 42 if (argv[1] && argv[1][0] == '-') {
43 switch (argv[1][1]) {
44 case 'b':
45 G.unit_steps = 0;
46 break;
47 case 'k': /* 2^10 */
48 /* G.unit_steps = 10; - already is */
49 break;
50 case 'm': /* 2^(2*10) */
51 G.unit_steps = 20;
52 break;
53 case 'g': /* 2^(3*10) */
54 G.unit_steps = 30;
55 break;
56 default:
57 bb_show_usage();
58 }
59 }
23#endif 60#endif
24 61
25 sysinfo(&info); 62 sysinfo(&info);
26 63
27 /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */ 64 /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */
28 mem_unit = 1; 65 G.mem_unit = (info.mem_unit ? info.mem_unit : 1);
29 if (info.mem_unit != 0) {
30 mem_unit = info.mem_unit;
31 }
32
33 /* Convert values to kbytes */
34 if (mem_unit == 1) {
35 info.totalram >>= 10;
36 info.freeram >>= 10;
37#if BB_MMU
38 info.totalswap >>= 10;
39 info.freeswap >>= 10;
40#endif
41 info.sharedram >>= 10;
42 info.bufferram >>= 10;
43 } else {
44 mem_unit >>= 10;
45 /* TODO: Make all this stuff not overflow when mem >= 4 Tb */
46 info.totalram *= mem_unit;
47 info.freeram *= mem_unit;
48#if BB_MMU
49 info.totalswap *= mem_unit;
50 info.freeswap *= mem_unit;
51#endif
52 info.sharedram *= mem_unit;
53 info.bufferram *= mem_unit;
54 }
55 66
56 printf(" %13s%13s%13s%13s%13s\n", 67 printf(" %13s%13s%13s%13s%13s\n",
57 "total", 68 "total",
@@ -63,30 +74,33 @@ int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
63 * /proc/meminfo instead and get "Cached: NNN kB" from there. 74 * /proc/meminfo instead and get "Cached: NNN kB" from there.
64 */ 75 */
65 ); 76 );
66#define FIELDS_5 "%13lu%13lu%13lu%13lu%13lu\n" 77
67#define FIELDS_3 (FIELDS_5 + 2*5) 78#define FIELDS_5 "%13llu%13llu%13llu%13llu%13llu\n"
68#define FIELDS_2 (FIELDS_5 + 3*5) 79#define FIELDS_3 (FIELDS_5 + 2*6)
80#define FIELDS_2 (FIELDS_5 + 3*6)
81
69 printf("Mem: "); 82 printf("Mem: ");
70 printf(FIELDS_5, 83 printf(FIELDS_5,
71 info.totalram, 84 scale(info.totalram),
72 info.totalram - info.freeram, 85 scale(info.totalram - info.freeram),
73 info.freeram, 86 scale(info.freeram),
74 info.sharedram, info.bufferram 87 scale(info.sharedram),
88 scale(info.bufferram)
75 ); 89 );
76 /* Show alternate, more meaningful busy/free numbers by counting 90 /* Show alternate, more meaningful busy/free numbers by counting
77 * buffer cache as free memory (make it "-/+ buffers/cache" 91 * buffer cache as free memory (make it "-/+ buffers/cache"
78 * if/when we add support for "cached" column): */ 92 * if/when we add support for "cached" column): */
79 printf("-/+ buffers: "); 93 printf("-/+ buffers: ");
80 printf(FIELDS_2, 94 printf(FIELDS_2,
81 info.totalram - info.freeram - info.bufferram, 95 scale(info.totalram - info.freeram - info.bufferram),
82 info.freeram + info.bufferram 96 scale(info.freeram + info.bufferram)
83 ); 97 );
84#if BB_MMU 98#if BB_MMU
85 printf("Swap:"); 99 printf("Swap:");
86 printf(FIELDS_3, 100 printf(FIELDS_3,
87 info.totalswap, 101 scale(info.totalswap),
88 info.totalswap - info.freeswap, 102 scale(info.totalswap - info.freeswap),
89 info.freeswap 103 scale(info.freeswap)
90 ); 104 );
91#endif 105#endif
92 return EXIT_SUCCESS; 106 return EXIT_SUCCESS;
diff --git a/runit/Kbuild.src b/runit/Kbuild.src
index d38bad20f..0fce95507 100644
--- a/runit/Kbuild.src
+++ b/runit/Kbuild.src
@@ -8,10 +8,10 @@ lib-y:=
8 8
9INSERT 9INSERT
10 10
11lib-$(CONFIG_RUNSV) += runsv.o runit_lib.o 11lib-$(CONFIG_RUNSV) += runsv.o
12lib-$(CONFIG_RUNSVDIR) += runsvdir.o runit_lib.o 12lib-$(CONFIG_RUNSVDIR) += runsvdir.o
13lib-$(CONFIG_SV) += sv.o runit_lib.o 13lib-$(CONFIG_SV) += sv.o
14lib-$(CONFIG_SVLOGD) += svlogd.o runit_lib.o 14lib-$(CONFIG_SVLOGD) += svlogd.o
15lib-$(CONFIG_CHPST) += chpst.o 15lib-$(CONFIG_CHPST) += chpst.o
16 16
17lib-$(CONFIG_ENVDIR) += chpst.o 17lib-$(CONFIG_ENVDIR) += chpst.o
diff --git a/runit/runit_lib.c b/runit/runit_lib.c
deleted file mode 100644
index 8182a909a..000000000
--- a/runit/runit_lib.c
+++ /dev/null
@@ -1,275 +0,0 @@
1/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
29/* Collected into one file from runit's many tiny files */
30/* TODO: review, eliminate unneeded stuff, move good stuff to libbb */
31
32#include <sys/poll.h>
33#include <sys/file.h>
34#include "libbb.h"
35#include "runit_lib.h"
36
37#ifdef UNUSED
38unsigned byte_chr(char *s,unsigned n,int c)
39{
40 char ch;
41 char *t;
42
43 ch = c;
44 t = s;
45 for (;;) {
46 if (!n) break;
47 if (*t == ch) break;
48 ++t;
49 --n;
50 }
51 return t - s;
52}
53
54static /* as it isn't used anywhere else */
55void tai_pack(char *s, const struct tai *t)
56{
57 uint64_t x;
58
59 x = t->x;
60 s[7] = x & 255; x >>= 8;
61 s[6] = x & 255; x >>= 8;
62 s[5] = x & 255; x >>= 8;
63 s[4] = x & 255; x >>= 8;
64 s[3] = x & 255; x >>= 8;
65 s[2] = x & 255; x >>= 8;
66 s[1] = x & 255; x >>= 8;
67 s[0] = x;
68}
69
70void tai_unpack(const char *s,struct tai *t)
71{
72 uint64_t x;
73
74 x = (unsigned char) s[0];
75 x <<= 8; x += (unsigned char) s[1];
76 x <<= 8; x += (unsigned char) s[2];
77 x <<= 8; x += (unsigned char) s[3];
78 x <<= 8; x += (unsigned char) s[4];
79 x <<= 8; x += (unsigned char) s[5];
80 x <<= 8; x += (unsigned char) s[6];
81 x <<= 8; x += (unsigned char) s[7];
82 t->x = x;
83}
84
85
86void taia_add(struct taia *t,const struct taia *u,const struct taia *v)
87{
88 t->sec.x = u->sec.x + v->sec.x;
89 t->nano = u->nano + v->nano;
90 t->atto = u->atto + v->atto;
91 if (t->atto > 999999999UL) {
92 t->atto -= 1000000000UL;
93 ++t->nano;
94 }
95 if (t->nano > 999999999UL) {
96 t->nano -= 1000000000UL;
97 ++t->sec.x;
98 }
99}
100
101int taia_less(const struct taia *t, const struct taia *u)
102{
103 if (t->sec.x < u->sec.x) return 1;
104 if (t->sec.x > u->sec.x) return 0;
105 if (t->nano < u->nano) return 1;
106 if (t->nano > u->nano) return 0;
107 return t->atto < u->atto;
108}
109
110void taia_now(struct taia *t)
111{
112 struct timeval now;
113 gettimeofday(&now, NULL);
114 tai_unix(&t->sec, now.tv_sec);
115 t->nano = 1000 * now.tv_usec + 500;
116 t->atto = 0;
117}
118
119/* UNUSED
120void taia_pack(char *s, const struct taia *t)
121{
122 unsigned long x;
123
124 tai_pack(s, &t->sec);
125 s += 8;
126
127 x = t->atto;
128 s[7] = x & 255; x >>= 8;
129 s[6] = x & 255; x >>= 8;
130 s[5] = x & 255; x >>= 8;
131 s[4] = x;
132 x = t->nano;
133 s[3] = x & 255; x >>= 8;
134 s[2] = x & 255; x >>= 8;
135 s[1] = x & 255; x >>= 8;
136 s[0] = x;
137}
138*/
139
140void taia_sub(struct taia *t, const struct taia *u, const struct taia *v)
141{
142 unsigned long unano = u->nano;
143 unsigned long uatto = u->atto;
144
145 t->sec.x = u->sec.x - v->sec.x;
146 t->nano = unano - v->nano;
147 t->atto = uatto - v->atto;
148 if (t->atto > uatto) {
149 t->atto += 1000000000UL;
150 --t->nano;
151 }
152 if (t->nano > unano) {
153 t->nano += 1000000000UL;
154 --t->sec.x;
155 }
156}
157
158/* XXX: breaks tai encapsulation */
159void taia_uint(struct taia *t, unsigned s)
160{
161 t->sec.x = s;
162 t->nano = 0;
163 t->atto = 0;
164}
165
166static
167uint64_t taia2millisec(const struct taia *t)
168{
169 return (t->sec.x * 1000) + (t->nano / 1000000);
170}
171
172void iopause(iopause_fd *x, unsigned len, struct taia *deadline, struct taia *stamp)
173{
174 int millisecs;
175 int i;
176
177 if (taia_less(deadline, stamp))
178 millisecs = 0;
179 else {
180 uint64_t m;
181 struct taia t;
182 t = *stamp;
183 taia_sub(&t, deadline, &t);
184 millisecs = m = taia2millisec(&t);
185 if (m > 1000) millisecs = 1000;
186 millisecs += 20;
187 }
188
189 for (i = 0; i < len; ++i)
190 x[i].revents = 0;
191
192 poll(x, len, millisecs);
193 /* XXX: some kernels apparently need x[0] even if len is 0 */
194 /* XXX: how to handle EAGAIN? are kernels really this dumb? */
195 /* XXX: how to handle EINVAL? when exactly can this happen? */
196}
197#endif
198
199int lock_ex(int fd)
200{
201 return flock(fd, LOCK_EX);
202}
203
204int lock_exnb(int fd)
205{
206 return flock(fd, LOCK_EX | LOCK_NB);
207}
208
209#ifdef UNUSED
210int open_append(const char *fn)
211{
212 return open(fn, O_WRONLY | O_NDELAY | O_APPEND | O_CREAT, 0600);
213}
214
215int open_trunc(const char *fn)
216{
217 return open(fn, O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT, 0644);
218}
219#endif
220
221int open_read(const char *fn)
222{
223 return open(fn, O_RDONLY|O_NDELAY);
224}
225
226int open_write(const char *fn)
227{
228 return open(fn, O_WRONLY|O_NDELAY);
229}
230
231unsigned FAST_FUNC pmatch(const char *p, const char *s, unsigned len)
232{
233 for (;;) {
234 char c = *p++;
235 if (!c) return !len;
236 switch (c) {
237 case '*':
238 c = *p;
239 if (!c) return 1;
240 for (;;) {
241 if (!len) return 0;
242 if (*s == c) break;
243 ++s;
244 --len;
245 }
246 continue;
247 case '+':
248 c = *p++;
249 if (c != *s) return 0;
250 for (;;) {
251 if (!len) return 1;
252 if (*s != c) break;
253 ++s;
254 --len;
255 }
256 continue;
257 /*
258 case '?':
259 if (*p == '?') {
260 if (*s != '?') return 0;
261 ++p;
262 }
263 ++s; --len;
264 continue;
265 */
266 default:
267 if (!len) return 0;
268 if (*s != c) return 0;
269 ++s;
270 --len;
271 continue;
272 }
273 }
274 return 0;
275}
diff --git a/runit/runit_lib.h b/runit/runit_lib.h
index d8304aca6..c36ea4ca5 100644
--- a/runit/runit_lib.h
+++ b/runit/runit_lib.h
@@ -27,59 +27,6 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 28PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
29 29
30//extern unsigned byte_chr(char *s,unsigned n,int c);
31//
32//struct tai {
33// uint64_t x;
34//};
35//
36//#define tai_unix(t,u) ((void) ((t)->x = 0x400000000000000aULL + (uint64_t) (u)))
37//
38//#define TAI_PACK 8
39//extern void tai_unpack(const char *,struct tai *);
40//
41//extern void tai_uint(struct tai *,unsigned);
42//
43//struct taia {
44// struct tai sec;
45// unsigned long nano; /* 0...999999999 */
46// unsigned long atto; /* 0...999999999 */
47//};
48//
49//extern void taia_now(struct taia *);
50//
51//extern void taia_add(struct taia *,const struct taia *,const struct taia *);
52//extern void taia_addsec(struct taia *,const struct taia *,int);
53//extern void taia_sub(struct taia *,const struct taia *,const struct taia *);
54//extern void taia_half(struct taia *,const struct taia *);
55//extern int taia_less(const struct taia *,const struct taia *);
56//
57//#define TAIA_PACK 16
58//extern void taia_pack(char *,const struct taia *);
59//
60//extern void taia_uint(struct taia *,unsigned);
61//
62//typedef struct pollfd iopause_fd;
63//#define IOPAUSE_READ POLLIN
64//#define IOPAUSE_WRITE POLLOUT
65//
66//extern void iopause(iopause_fd *,unsigned,struct taia *,struct taia *);
67
68extern int lock_ex(int);
69//extern int lock_un(int);
70extern int lock_exnb(int);
71
72extern int open_read(const char *);
73extern int open_write(const char *);
74//extern int open_excl(const char *);
75//extern int open_append(const char *);
76//extern int open_trunc(const char *);
77
78extern unsigned FAST_FUNC pmatch(const char *, const char *, unsigned);
79
80//#define str_diff(s,t) strcmp((s), (t))
81#define str_equal(s,t) (!strcmp((s), (t)))
82
83/* 30/*
84 * runsv / supervise / sv stuff 31 * runsv / supervise / sv stuff
85 */ 32 */
diff --git a/runit/runsv.c b/runit/runsv.c
index 6bb6ec886..ebb031837 100644
--- a/runit/runsv.c
+++ b/runit/runsv.c
@@ -524,7 +524,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
524 } 524 }
525 svd[0].fdlock = xopen3("log/supervise/lock"+4, 525 svd[0].fdlock = xopen3("log/supervise/lock"+4,
526 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); 526 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
527 if (lock_exnb(svd[0].fdlock) == -1) 527 if (flock(svd[0].fdlock, LOCK_EX | LOCK_NB) == -1)
528 fatal_cannot("lock supervise/lock"); 528 fatal_cannot("lock supervise/lock");
529 close_on_exec_on(svd[0].fdlock); 529 close_on_exec_on(svd[0].fdlock);
530 if (haslog) { 530 if (haslog) {
@@ -548,7 +548,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
548 } 548 }
549 svd[1].fdlock = xopen3("log/supervise/lock", 549 svd[1].fdlock = xopen3("log/supervise/lock",
550 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); 550 O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
551 if (lock_ex(svd[1].fdlock) == -1) 551 if (flock(svd[1].fdlock, LOCK_EX) == -1)
552 fatal_cannot("lock log/supervise/lock"); 552 fatal_cannot("lock log/supervise/lock");
553 close_on_exec_on(svd[1].fdlock); 553 close_on_exec_on(svd[1].fdlock);
554 } 554 }
@@ -618,7 +618,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv)
618 pidchanged = 1; 618 pidchanged = 1;
619 svd[0].ctrl &= ~C_TERM; 619 svd[0].ctrl &= ~C_TERM;
620 if (svd[0].state != S_FINISH) { 620 if (svd[0].state != S_FINISH) {
621 fd = open_read("finish"); 621 fd = open("finish", O_RDONLY|O_NDELAY);
622 if (fd != -1) { 622 if (fd != -1) {
623 close(fd); 623 close(fd);
624 svd[0].state = S_FINISH; 624 svd[0].state = S_FINISH;
diff --git a/runit/runsvdir.c b/runit/runsvdir.c
index 71fde757e..e77eeff04 100644
--- a/runit/runsvdir.c
+++ b/runit/runsvdir.c
@@ -276,7 +276,7 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv)
276 } 276 }
277 run: 277 run:
278#endif 278#endif
279 curdir = open_read("."); 279 curdir = open(".", O_RDONLY|O_NDELAY);
280 if (curdir == -1) 280 if (curdir == -1)
281 fatal2_cannot("open current directory", ""); 281 fatal2_cannot("open current directory", "");
282 close_on_exec_on(curdir); 282 close_on_exec_on(curdir);
diff --git a/runit/sv.c b/runit/sv.c
index 3f76a2d47..c420a91a6 100644
--- a/runit/sv.c
+++ b/runit/sv.c
@@ -176,6 +176,9 @@ struct globals {
176#define INIT_G() do { } while (0) 176#define INIT_G() do { } while (0)
177 177
178 178
179#define str_equal(s,t) (!strcmp((s), (t)))
180
181
179static void fatal_cannot(const char *m1) NORETURN; 182static void fatal_cannot(const char *m1) NORETURN;
180static void fatal_cannot(const char *m1) 183static void fatal_cannot(const char *m1)
181{ 184{
@@ -221,7 +224,7 @@ static int svstatus_get(void)
221{ 224{
222 int fd, r; 225 int fd, r;
223 226
224 fd = open_write("supervise/ok"); 227 fd = open("supervise/ok", O_WRONLY|O_NDELAY);
225 if (fd == -1) { 228 if (fd == -1) {
226 if (errno == ENODEV) { 229 if (errno == ENODEV) {
227 *acts == 'x' ? ok("runsv not running") 230 *acts == 'x' ? ok("runsv not running")
@@ -232,7 +235,7 @@ static int svstatus_get(void)
232 return -1; 235 return -1;
233 } 236 }
234 close(fd); 237 close(fd);
235 fd = open_read("supervise/status"); 238 fd = open("supervise/status", O_RDONLY|O_NDELAY);
236 if (fd == -1) { 239 if (fd == -1) {
237 warn("can't open supervise/status"); 240 warn("can't open supervise/status");
238 return -1; 241 return -1;
@@ -397,7 +400,7 @@ static int control(const char *a)
397 if (svstatus.want == *a) 400 if (svstatus.want == *a)
398 return 0; 401 return 0;
399*/ 402*/
400 fd = open_write("supervise/control"); 403 fd = open("supervise/control", O_WRONLY|O_NDELAY);
401 if (fd == -1) { 404 if (fd == -1) {
402 if (errno != ENODEV) 405 if (errno != ENODEV)
403 warn("can't open supervise/control"); 406 warn("can't open supervise/control");
@@ -446,7 +449,7 @@ int sv_main(int argc UNUSED_PARAM, char **argv)
446 449
447 tnow = time(NULL) + 0x400000000000000aULL; 450 tnow = time(NULL) + 0x400000000000000aULL;
448 tstart = tnow; 451 tstart = tnow;
449 curdir = open_read("."); 452 curdir = open(".", O_RDONLY|O_NDELAY);
450 if (curdir == -1) 453 if (curdir == -1)
451 fatal_cannot("open current directory"); 454 fatal_cannot("open current directory");
452 455
diff --git a/runit/svlogd.c b/runit/svlogd.c
index 1f0a77cc2..052806c25 100644
--- a/runit/svlogd.c
+++ b/runit/svlogd.c
@@ -261,6 +261,52 @@ static char* wstrdup(const char *str)
261 return s; 261 return s;
262} 262}
263 263
264static unsigned pmatch(const char *p, const char *s, unsigned len)
265{
266 for (;;) {
267 char c = *p++;
268 if (!c) return !len;
269 switch (c) {
270 case '*':
271 c = *p;
272 if (!c) return 1;
273 for (;;) {
274 if (!len) return 0;
275 if (*s == c) break;
276 ++s;
277 --len;
278 }
279 continue;
280 case '+':
281 c = *p++;
282 if (c != *s) return 0;
283 for (;;) {
284 if (!len) return 1;
285 if (*s != c) break;
286 ++s;
287 --len;
288 }
289 continue;
290 /*
291 case '?':
292 if (*p == '?') {
293 if (*s != '?') return 0;
294 ++p;
295 }
296 ++s; --len;
297 continue;
298 */
299 default:
300 if (!len) return 0;
301 if (*s != c) return 0;
302 ++s;
303 --len;
304 continue;
305 }
306 }
307 return 0;
308}
309
264/*** ex fmt_ptime.[ch] ***/ 310/*** ex fmt_ptime.[ch] ***/
265 311
266/* NUL terminated */ 312/* NUL terminated */
@@ -342,7 +388,7 @@ static void processorstart(struct logdir *ld)
342 ld->fnsave[26] = 't'; /* <- that's why we need sv_ch! */ 388 ld->fnsave[26] = 't'; /* <- that's why we need sv_ch! */
343 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT); 389 fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT);
344 xmove_fd(fd, 1); 390 xmove_fd(fd, 1);
345 fd = open_read("state"); 391 fd = open("state", O_RDONLY|O_NDELAY);
346 if (fd == -1) { 392 if (fd == -1) {
347 if (errno != ENOENT) 393 if (errno != ENOENT)
348 bb_perror_msg_and_die(FATAL"can't %s processor %s", "open state for", ld->name); 394 bb_perror_msg_and_die(FATAL"can't %s processor %s", "open state for", ld->name);
@@ -626,7 +672,7 @@ static NOINLINE unsigned logdir_open(struct logdir *ld, const char *fn)
626 } 672 }
627 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); 673 ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600);
628 if ((ld->fdlock == -1) 674 if ((ld->fdlock == -1)
629 || (lock_exnb(ld->fdlock) == -1) 675 || (flock(ld->fdlock, LOCK_EX | LOCK_NB) == -1)
630 ) { 676 ) {
631 logdir_close(ld); 677 logdir_close(ld);
632 warn2("can't lock directory", (char*)fn); 678 warn2("can't lock directory", (char*)fn);
diff --git a/shell/ash.c b/shell/ash.c
index f1f044cbf..45ec13097 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5766,25 +5766,17 @@ redirectsafe(union node *redir, int flags)
5766static arith_t 5766static arith_t
5767ash_arith(const char *s) 5767ash_arith(const char *s)
5768{ 5768{
5769 arith_eval_hooks_t math_hooks; 5769 arith_state_t math_state;
5770 arith_t result; 5770 arith_t result;
5771 int errcode = 0;
5772 5771
5773 math_hooks.lookupvar = lookupvar; 5772 math_state.lookupvar = lookupvar;
5774 math_hooks.setvar = setvar2; 5773 math_state.setvar = setvar2;
5775 //math_hooks.endofname = endofname; 5774 //math_state.endofname = endofname;
5776 5775
5777 INT_OFF; 5776 INT_OFF;
5778 result = arith(s, &errcode, &math_hooks); 5777 result = arith(&math_state, s);
5779 if (errcode < 0) { 5778 if (math_state.errmsg)
5780 if (errcode == -3) 5779 ash_msg_and_raise_error(math_state.errmsg);
5781 ash_msg_and_raise_error("exponent less than 0");
5782 if (errcode == -2)
5783 ash_msg_and_raise_error("divide by zero");
5784 if (errcode == -5)
5785 ash_msg_and_raise_error("expression recursion loop detected");
5786 raise_error_syntax(s);
5787 }
5788 INT_ON; 5780 INT_ON;
5789 5781
5790 return result; 5782 return result;
@@ -5848,7 +5840,7 @@ cvtnum(arith_t num)
5848 int len; 5840 int len;
5849 5841
5850 expdest = makestrspace(32, expdest); 5842 expdest = makestrspace(32, expdest);
5851 len = fmtstr(expdest, 32, arith_t_fmt, num); 5843 len = fmtstr(expdest, 32, ARITH_FMT, num);
5852 STADJUST(len, expdest); 5844 STADJUST(len, expdest);
5853 return len; 5845 return len;
5854} 5846}
@@ -8624,7 +8616,7 @@ static int evalstring(char *s, int mask);
8624 8616
8625/* Called to execute a trap. 8617/* Called to execute a trap.
8626 * Single callsite - at the end of evaltree(). 8618 * Single callsite - at the end of evaltree().
8627 * If we return non-zero, exaltree raises EXEXIT exception. 8619 * If we return non-zero, evaltree raises EXEXIT exception.
8628 * 8620 *
8629 * Perhaps we should avoid entering new trap handlers 8621 * Perhaps we should avoid entering new trap handlers
8630 * while we are executing a trap handler. [is it a TODO?] 8622 * while we are executing a trap handler. [is it a TODO?]
@@ -8814,11 +8806,15 @@ evaltree(union node *n, int flags)
8814 8806
8815 out: 8807 out:
8816 exception_handler = savehandler; 8808 exception_handler = savehandler;
8809
8817 out1: 8810 out1:
8811 /* Order of checks below is important:
8812 * signal handlers trigger before exit caused by "set -e".
8813 */
8814 if (pending_sig && dotrap())
8815 goto exexit;
8818 if (checkexit & exitstatus) 8816 if (checkexit & exitstatus)
8819 evalskip |= SKIPEVAL; 8817 evalskip |= SKIPEVAL;
8820 else if (pending_sig && dotrap())
8821 goto exexit;
8822 8818
8823 if (flags & EV_EXIT) { 8819 if (flags & EV_EXIT) {
8824 exexit: 8820 exexit:
@@ -9212,7 +9208,7 @@ poplocalvars(void)
9212 while ((lvp = localvars) != NULL) { 9208 while ((lvp = localvars) != NULL) {
9213 localvars = lvp->next; 9209 localvars = lvp->next;
9214 vp = lvp->vp; 9210 vp = lvp->vp;
9215 TRACE(("poplocalvar %s\n", vp ? vp->text : "-")); 9211 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
9216 if (vp == NULL) { /* $- saved */ 9212 if (vp == NULL) { /* $- saved */
9217 memcpy(optlist, lvp->text, sizeof(optlist)); 9213 memcpy(optlist, lvp->text, sizeof(optlist));
9218 free((char*)lvp->text); 9214 free((char*)lvp->text);
@@ -13383,7 +13379,7 @@ init(void)
13383 /* bash re-enables SIGHUP which is SIG_IGNed on entry. 13379 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13384 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" 13380 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13385 */ 13381 */
13386 signal(SIGHUP, SIG_DFL); 13382 signal(SIGHUP, SIG_DFL);
13387 13383
13388 /* from var.c: */ 13384 /* from var.c: */
13389 { 13385 {
@@ -13598,10 +13594,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13598 if (e == EXERROR) 13594 if (e == EXERROR)
13599 exitstatus = 2; 13595 exitstatus = 2;
13600 s = state; 13596 s = state;
13601 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) 13597 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
13602 exitshell(); 13598 exitshell();
13603 if (e == EXINT) 13599 }
13600 if (e == EXINT) {
13604 outcslow('\n', stderr); 13601 outcslow('\n', stderr);
13602 }
13605 13603
13606 popstackmark(&smark); 13604 popstackmark(&smark);
13607 FORCE_INT_ON; /* enable interrupts */ 13605 FORCE_INT_ON; /* enable interrupts */
@@ -13705,6 +13703,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13705 _mcleanup(); 13703 _mcleanup();
13706 } 13704 }
13707#endif 13705#endif
13706 TRACE(("End of main reached\n"));
13708 exitshell(); 13707 exitshell();
13709 /* NOTREACHED */ 13708 /* NOTREACHED */
13710} 13709}
diff --git a/shell/ash_test/ash-arith/arith.right b/shell/ash_test/ash-arith/arith.right
index 3ea7ce680..9b9ca8e2f 100644
--- a/shell/ash_test/ash-arith/arith.right
+++ b/shell/ash_test/ash-arith/arith.right
@@ -55,28 +55,28 @@ Format: 'expected actual'
5530 30 5530 30
5620 20 5620 20
5730 30 5730 30
58./arith.tests: line 117: syntax error: 1 ? 20 : x+=2 58./arith.tests: line 117: arithmetic syntax error
596 6 596 6
606,5,3 6,5,3 606,5,3 6,5,3
61263 263 61263 263
62255 255 62255 255
6340 40 6340 40
64./arith.tests: line 163: syntax error: 7 = 43 64./arith.tests: line 163: arithmetic syntax error
65./arith.tests: line 165: divide by zero 65./arith.tests: line 165: divide by zero
66./arith.tests: let: line 166: syntax error: jv += $iv 66./arith.tests: let: line 166: arithmetic syntax error
67./arith.tests: line 167: syntax error: jv += $iv 67./arith.tests: line 167: arithmetic syntax error
68./arith.tests: let: line 168: syntax error: rv = 7 + (43 * 6 68./arith.tests: let: line 168: arithmetic syntax error
69abc 69abc
70def 70def
71ghi 71ghi
72./arith.tests: line 191: syntax error: ( 4 + A ) + 4 72./arith.tests: line 191: arithmetic syntax error
7316 16 7316 16
74./arith.tests: line 196: syntax error: 4 ? : 3 + 5 74./arith.tests: line 196: arithmetic syntax error
75./arith.tests: line 197: syntax error: 1 ? 20 75./arith.tests: line 197: malformed ?: operator
76./arith.tests: line 198: syntax error: 4 ? 20 : 76./arith.tests: line 198: arithmetic syntax error
779 9 779 9
78./arith.tests: line 205: syntax error: 0 && B=42 78./arith.tests: line 205: arithmetic syntax error
79./arith.tests: line 208: syntax error: 1 || B=88 79./arith.tests: line 208: arithmetic syntax error
809 9 809 9
819 9 819 9
829 9 829 9
@@ -97,18 +97,18 @@ ghi
973 3 973 3
984 4 984 4
994 4 994 4
100./arith.tests: line 257: syntax error: 7-- 100./arith.tests: line 257: arithmetic syntax error
101./arith.tests: line 259: syntax error: --x=7 101./arith.tests: line 259: arithmetic syntax error
102./arith.tests: line 260: syntax error: ++x=7 102./arith.tests: line 260: arithmetic syntax error
103./arith.tests: line 262: syntax error: x++=7 103./arith.tests: line 262: arithmetic syntax error
104./arith.tests: line 263: syntax error: x--=7 104./arith.tests: line 263: arithmetic syntax error
1054 4 1054 4
1067 7 1067 7
107-7 -7 107-7 -7
108./arith1.sub: line 2: syntax error: 4-- 108./arith1.sub: line 2: arithmetic syntax error
109./arith1.sub: line 3: syntax error: 4++ 109./arith1.sub: line 3: arithmetic syntax error
110./arith1.sub: line 4: syntax error: 4 -- 110./arith1.sub: line 4: arithmetic syntax error
111./arith1.sub: line 5: syntax error: 4 ++ 111./arith1.sub: line 5: arithmetic syntax error
1126 6 1126 6
1133 3 1133 3
1147 7 1147 7
@@ -119,19 +119,19 @@ ghi
1192 2 1192 2
120-2 -2 120-2 -2
1211 1 1211 1
122./arith1.sub: line 37: syntax error: +++7 122./arith1.sub: line 37: arithmetic syntax error
123./arith2.sub: line 2: syntax error: --7 123./arith2.sub: line 2: arithmetic syntax error
124./arith2.sub: line 3: syntax error: ++7 124./arith2.sub: line 3: arithmetic syntax error
125./arith2.sub: line 4: syntax error: -- 7 125./arith2.sub: line 4: arithmetic syntax error
126./arith2.sub: line 5: syntax error: ++ 7 126./arith2.sub: line 5: arithmetic syntax error
1275 5 1275 5
1281 1 1281 1
1294 4 1294 4
1300 0 1300 0
131./arith2.sub: line 42: syntax error: -- - 7 131./arith2.sub: line 42: arithmetic syntax error
132./arith2.sub: line 47: syntax error: ++ + 7 132./arith2.sub: line 47: arithmetic syntax error
1338 12 1338 12
134./arith.tests: line 290: syntax error: a b 134./arith.tests: line 290: arithmetic syntax error
13542 13542
13642 13642
13742 13742
diff --git a/shell/ash_test/ash-signals/signal8.right b/shell/ash_test/ash-signals/signal8.right
new file mode 100644
index 000000000..39572f30e
--- /dev/null
+++ b/shell/ash_test/ash-signals/signal8.right
@@ -0,0 +1,3 @@
1Removing traps
2End of exit_func
3Done: 0
diff --git a/shell/ash_test/ash-signals/signal8.tests b/shell/ash_test/ash-signals/signal8.tests
new file mode 100755
index 000000000..731af7477
--- /dev/null
+++ b/shell/ash_test/ash-signals/signal8.tests
@@ -0,0 +1,18 @@
1"$THIS_SH" -c '
2exit_func() {
3 echo "Removing traps"
4 trap - EXIT TERM INT
5 echo "End of exit_func"
6}
7set -e
8trap exit_func EXIT TERM INT
9sleep 2
10exit 77
11' &
12
13sleep 1
14# BUG: ash kills -PGRP, but in non-interactive shell we do not create pgrps!
15# In this case, bash kills by PID, not PGRP.
16kill -TERM %1
17wait
18echo Done: $?
diff --git a/shell/ash_test/ash-signals/signal9.right b/shell/ash_test/ash-signals/signal9.right
new file mode 100644
index 000000000..39572f30e
--- /dev/null
+++ b/shell/ash_test/ash-signals/signal9.right
@@ -0,0 +1,3 @@
1Removing traps
2End of exit_func
3Done: 0
diff --git a/shell/ash_test/ash-signals/signal9.tests b/shell/ash_test/ash-signals/signal9.tests
new file mode 100755
index 000000000..18e71012b
--- /dev/null
+++ b/shell/ash_test/ash-signals/signal9.tests
@@ -0,0 +1,21 @@
1# Note: the inner script is a test which checks for a different bug
2# (ordering between INT handler and exit on "set -e"),
3# but so far I did not figure out how to simulate it non-interactively.
4
5"$THIS_SH" -c '
6exit_func() {
7 echo "Removing traps"
8 trap - EXIT TERM INT
9 echo "End of exit_func"
10}
11set -e
12trap exit_func EXIT TERM INT
13sleep 2
14exit 77
15' &
16
17child=$!
18sleep 1
19kill -TERM $child
20wait
21echo Done: $?
diff --git a/shell/hush.c b/shell/hush.c
index 752efd0c8..75083dc2e 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -8,6 +8,8 @@
8 * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org> 8 * Copyright (C) 2000,2001 Larry Doolittle <larry@doolittle.boa.org>
9 * Copyright (C) 2008,2009 Denys Vlasenko <vda.linux@googlemail.com> 9 * Copyright (C) 2008,2009 Denys Vlasenko <vda.linux@googlemail.com>
10 * 10 *
11 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
12 *
11 * Credits: 13 * Credits:
12 * The parser routines proper are all original material, first 14 * The parser routines proper are all original material, first
13 * written Dec 2000 and Jan 2001 by Larry Doolittle. The 15 * written Dec 2000 and Jan 2001 by Larry Doolittle. The
@@ -50,7 +52,6 @@
50 * 52 *
51 * Bash compat TODO: 53 * Bash compat TODO:
52 * redirection of stdout+stderr: &> and >& 54 * redirection of stdout+stderr: &> and >&
53 * brace expansion: one/{two,three,four}
54 * reserved words: function select 55 * reserved words: function select
55 * advanced test: [[ ]] 56 * advanced test: [[ ]]
56 * process substitution: <(list) and >(list) 57 * process substitution: <(list) and >(list)
@@ -63,7 +64,9 @@
63 * The EXPR is evaluated according to ARITHMETIC EVALUATION. 64 * The EXPR is evaluated according to ARITHMETIC EVALUATION.
64 * This is exactly equivalent to let "EXPR". 65 * This is exactly equivalent to let "EXPR".
65 * $[EXPR]: synonym for $((EXPR)) 66 * $[EXPR]: synonym for $((EXPR))
66 * export builtin should be special, its arguments are assignments 67 *
68 * Won't do:
69 * In bash, export builtin is special, its arguments are assignments
67 * and therefore expansion of them should be "one-word" expansion: 70 * and therefore expansion of them should be "one-word" expansion:
68 * $ export i=`echo 'a b'` # export has one arg: "i=a b" 71 * $ export i=`echo 'a b'` # export has one arg: "i=a b"
69 * compare with: 72 * compare with:
@@ -77,8 +80,6 @@
77 * aaa bbb 80 * aaa bbb
78 * $ "export" i=`echo 'aaa bbb'`; echo "$i" 81 * $ "export" i=`echo 'aaa bbb'`; echo "$i"
79 * aaa 82 * aaa
80 *
81 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
82 */ 83 */
83#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 84#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
84#include <malloc.h> /* for malloc_trim */ 85#include <malloc.h> /* for malloc_trim */
@@ -119,8 +120,8 @@
119//config: 120//config:
120//config: It will compile and work on no-mmu systems. 121//config: It will compile and work on no-mmu systems.
121//config: 122//config:
122//config: It does not handle select, aliases, brace expansion, 123//config: It does not handle select, aliases, tilde expansion,
123//config: tilde expansion, &>file and >&file redirection of stdout+stderr. 124//config: &>file and >&file redirection of stdout+stderr.
124//config: 125//config:
125//config:config HUSH_BASH_COMPAT 126//config:config HUSH_BASH_COMPAT
126//config: bool "bash-compatible extensions" 127//config: bool "bash-compatible extensions"
@@ -129,6 +130,13 @@
129//config: help 130//config: help
130//config: Enable bash-compatible extensions. 131//config: Enable bash-compatible extensions.
131//config: 132//config:
133//config:config HUSH_BRACE_EXPANSION
134//config: bool "Brace expansion"
135//config: default y
136//config: depends on HUSH_BASH_COMPAT
137//config: help
138//config: Enable {abc,def} extension.
139//config:
132//config:config HUSH_HELP 140//config:config HUSH_HELP
133//config: bool "help builtin" 141//config: bool "help builtin"
134//config: default y 142//config: default y
@@ -391,18 +399,10 @@ enum {
391 RES_SNTX 399 RES_SNTX
392}; 400};
393 401
394enum {
395 EXP_FLAG_GLOB = 0x200,
396 EXP_FLAG_ESC_GLOB_CHARS = 0x100,
397 EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */
398};
399
400typedef struct o_string { 402typedef struct o_string {
401 char *data; 403 char *data;
402 int length; /* position where data is appended */ 404 int length; /* position where data is appended */
403 int maxlen; 405 int maxlen;
404 /* Protect newly added chars against globbing
405 * (by prepending \ to *, ?, [, \) */
406 int o_expflags; 406 int o_expflags;
407 /* At least some part of the string was inside '' or "", 407 /* At least some part of the string was inside '' or "",
408 * possibly empty one: word"", wo''rd etc. */ 408 * possibly empty one: word"", wo''rd etc. */
@@ -411,10 +411,18 @@ typedef struct o_string {
411 smallint o_assignment; /* 0:maybe, 1:yes, 2:no */ 411 smallint o_assignment; /* 0:maybe, 1:yes, 2:no */
412} o_string; 412} o_string;
413enum { 413enum {
414 MAYBE_ASSIGNMENT = 0, 414 EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */
415 EXP_FLAG_GLOB = 0x2,
416 /* Protect newly added chars against globbing
417 * by prepending \ to *, ?, [, \ */
418 EXP_FLAG_ESC_GLOB_CHARS = 0x1,
419};
420enum {
421 MAYBE_ASSIGNMENT = 0,
415 DEFINITELY_ASSIGNMENT = 1, 422 DEFINITELY_ASSIGNMENT = 1,
416 NOT_ASSIGNMENT = 2, 423 NOT_ASSIGNMENT = 2,
417 WORD_IS_KEYWORD = 3, /* not assigment, but next word may be: "if v=xyz cmd;" */ 424 /* Not an assigment, but next word may be: "if v=xyz cmd;" */
425 WORD_IS_KEYWORD = 3,
418}; 426};
419/* Used for initialization: o_string foo = NULL_O_STRING; */ 427/* Used for initialization: o_string foo = NULL_O_STRING; */
420#define NULL_O_STRING { NULL } 428#define NULL_O_STRING { NULL }
@@ -707,8 +715,7 @@ struct globals {
707#endif 715#endif
708 const char *ifs; 716 const char *ifs;
709 const char *cwd; 717 const char *cwd;
710 struct variable *top_var; /* = &G.shell_ver (set in main()) */ 718 struct variable *top_var;
711 struct variable shell_ver;
712 char **expanded_assignments; 719 char **expanded_assignments;
713#if ENABLE_HUSH_FUNCTIONS 720#if ENABLE_HUSH_FUNCTIONS
714 struct function *top_func; 721 struct function *top_func;
@@ -2001,26 +2008,8 @@ static void o_addstr_with_NUL(o_string *o, const char *str)
2001 o_addblock(o, str, strlen(str) + 1); 2008 o_addblock(o, str, strlen(str) + 1);
2002} 2009}
2003 2010
2004static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len)
2005{
2006 while (len) {
2007 len--;
2008 o_addchr(o, *str);
2009 if (*str++ == '\\') {
2010 /* \z -> \\\z; \<eol> -> \\<eol> */
2011 o_addchr(o, '\\');
2012 if (len) {
2013 len--;
2014 o_addchr(o, '\\');
2015 o_addchr(o, *str++);
2016 }
2017 }
2018 }
2019}
2020
2021#undef HUSH_BRACE_EXP
2022/* 2011/*
2023 * HUSH_BRACE_EXP code needs corresponding quoting on variable expansion side. 2012 * HUSH_BRACE_EXPANSION code needs corresponding quoting on variable expansion side.
2024 * Currently, "v='{q,w}'; echo $v" erroneously expands braces in $v. 2013 * Currently, "v='{q,w}'; echo $v" erroneously expands braces in $v.
2025 * Apparently, on unquoted $v bash still does globbing 2014 * Apparently, on unquoted $v bash still does globbing
2026 * ("v='*.txt'; echo $v" prints all .txt files), 2015 * ("v='*.txt'; echo $v" prints all .txt files),
@@ -2030,7 +2019,7 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len
2030 * We have only second one. 2019 * We have only second one.
2031 */ 2020 */
2032 2021
2033#ifdef HUSH_BRACE_EXP 2022#if ENABLE_HUSH_BRACE_EXPANSION
2034# define MAYBE_BRACES "{}" 2023# define MAYBE_BRACES "{}"
2035#else 2024#else
2036# define MAYBE_BRACES "" 2025# define MAYBE_BRACES ""
@@ -2198,7 +2187,7 @@ static int o_get_last_ptr(o_string *o, int n)
2198 return ((int)(uintptr_t)list[n-1]) + string_start; 2187 return ((int)(uintptr_t)list[n-1]) + string_start;
2199} 2188}
2200 2189
2201#ifdef HUSH_BRACE_EXP 2190#if ENABLE_HUSH_BRACE_EXPANSION
2202/* There in a GNU extension, GLOB_BRACE, but it is not usable: 2191/* There in a GNU extension, GLOB_BRACE, but it is not usable:
2203 * first, it processes even {a} (no commas), second, 2192 * first, it processes even {a} (no commas), second,
2204 * I didn't manage to make it return strings when they don't match 2193 * I didn't manage to make it return strings when they don't match
@@ -2394,7 +2383,7 @@ static int perform_glob(o_string *o, int n)
2394 return n; 2383 return n;
2395} 2384}
2396 2385
2397#else /* !HUSH_BRACE_EXP */ 2386#else /* !HUSH_BRACE_EXPANSION */
2398 2387
2399/* Helper */ 2388/* Helper */
2400static int glob_needed(const char *s) 2389static int glob_needed(const char *s)
@@ -2471,7 +2460,7 @@ static int perform_glob(o_string *o, int n)
2471 return n; 2460 return n;
2472} 2461}
2473 2462
2474#endif /* !HUSH_BRACE_EXP */ 2463#endif /* !HUSH_BRACE_EXPANSION */
2475 2464
2476/* If o->o_expflags & EXP_FLAG_GLOB, glob the string so far remembered. 2465/* If o->o_expflags & EXP_FLAG_GLOB, glob the string so far remembered.
2477 * Otherwise, just finish current list[] and start new */ 2466 * Otherwise, just finish current list[] and start new */
@@ -4388,6 +4377,37 @@ static int process_command_subs(o_string *dest, const char *s);
4388 * followed by strings themselves. 4377 * followed by strings themselves.
4389 * Caller can deallocate entire list by single free(list). */ 4378 * Caller can deallocate entire list by single free(list). */
4390 4379
4380/* A horde of its helpers come first: */
4381
4382static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len)
4383{
4384 while (--len >= 0) {
4385 char c = *str++;
4386
4387#if ENABLE_HUSH_BRACE_EXPANSION
4388 if (c == '{' || c == '}') {
4389 /* { -> \{, } -> \} */
4390 o_addchr(o, '\\');
4391 /* And now we want to add { or } and continue:
4392 * o_addchr(o, c);
4393 * continue;
4394 * luckily, just falling throught achieves this.
4395 */
4396 }
4397#endif
4398 o_addchr(o, c);
4399 if (c == '\\') {
4400 /* \z -> \\\z; \<eol> -> \\<eol> */
4401 o_addchr(o, '\\');
4402 if (len) {
4403 len--;
4404 o_addchr(o, '\\');
4405 o_addchr(o, *str++);
4406 }
4407 }
4408 }
4409}
4410
4391/* Store given string, finalizing the word and starting new one whenever 4411/* Store given string, finalizing the word and starting new one whenever
4392 * we encounter IFS char(s). This is used for expanding variable values. 4412 * we encounter IFS char(s). This is used for expanding variable values.
4393 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ 4413 * End-of-string does NOT finalize word: think about 'echo -$VAR-' */
@@ -4396,9 +4416,9 @@ static int expand_on_ifs(o_string *output, int n, const char *str)
4396 while (1) { 4416 while (1) {
4397 int word_len = strcspn(str, G.ifs); 4417 int word_len = strcspn(str, G.ifs);
4398 if (word_len) { 4418 if (word_len) {
4399 if (!(output->o_expflags & EXP_FLAG_GLOB)) 4419 if (!(output->o_expflags & EXP_FLAG_GLOB)) {
4400 o_addblock(output, str, word_len); 4420 o_addblock(output, str, word_len);
4401 else { 4421 } else {
4402 /* Protect backslashes against globbing up :) 4422 /* Protect backslashes against globbing up :)
4403 * Example: "v='\*'; echo b$v" prints "b\*" 4423 * Example: "v='\*'; echo b$v" prints "b\*"
4404 * (and does not try to glob on "*") 4424 * (and does not try to glob on "*")
@@ -4461,18 +4481,22 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int
4461} 4481}
4462 4482
4463#if ENABLE_SH_MATH_SUPPORT 4483#if ENABLE_SH_MATH_SUPPORT
4464static arith_t expand_and_evaluate_arith(const char *arg, int *errcode_p) 4484static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
4465{ 4485{
4466 arith_eval_hooks_t hooks; 4486 arith_state_t math_state;
4467 arith_t res; 4487 arith_t res;
4468 char *exp_str; 4488 char *exp_str;
4469 4489
4470 hooks.lookupvar = get_local_var_value; 4490 math_state.lookupvar = get_local_var_value;
4471 hooks.setvar = set_local_var_from_halves; 4491 math_state.setvar = set_local_var_from_halves;
4472 //hooks.endofname = endofname; 4492 //math_state.endofname = endofname;
4473 exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); 4493 exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1);
4474 res = arith(exp_str ? exp_str : arg, errcode_p, &hooks); 4494 res = arith(&math_state, exp_str ? exp_str : arg);
4475 free(exp_str); 4495 free(exp_str);
4496 if (errmsg_p)
4497 *errmsg_p = math_state.errmsg;
4498 if (math_state.errmsg)
4499 die_if_script(math_state.errmsg);
4476 return res; 4500 return res;
4477} 4501}
4478#endif 4502#endif
@@ -4713,24 +4737,28 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
4713 * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL> 4737 * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL>
4714 */ 4738 */
4715 arith_t beg, len; 4739 arith_t beg, len;
4716 int errcode = 0; 4740 const char *errmsg;
4717 4741
4718 beg = expand_and_evaluate_arith(exp_word, &errcode); 4742 beg = expand_and_evaluate_arith(exp_word, &errmsg);
4743 if (errmsg)
4744 goto arith_err;
4719 debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg); 4745 debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg);
4720 *p++ = SPECIAL_VAR_SYMBOL; 4746 *p++ = SPECIAL_VAR_SYMBOL;
4721 exp_word = p; 4747 exp_word = p;
4722 p = strchr(p, SPECIAL_VAR_SYMBOL); 4748 p = strchr(p, SPECIAL_VAR_SYMBOL);
4723 *p = '\0'; 4749 *p = '\0';
4724 len = expand_and_evaluate_arith(exp_word, &errcode); 4750 len = expand_and_evaluate_arith(exp_word, &errmsg);
4751 if (errmsg)
4752 goto arith_err;
4725 debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len); 4753 debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len);
4726 4754 if (len >= 0) { /* bash compat: len < 0 is illegal */
4727 if (errcode >= 0 && len >= 0) { /* bash compat: len < 0 is illegal */
4728 if (beg < 0) /* bash compat */ 4755 if (beg < 0) /* bash compat */
4729 beg = 0; 4756 beg = 0;
4730 debug_printf_varexp("from val:'%s'\n", val); 4757 debug_printf_varexp("from val:'%s'\n", val);
4731 if (len == 0 || !val || beg >= strlen(val)) 4758 if (len == 0 || !val || beg >= strlen(val)) {
4732 val = ""; 4759 arith_err:
4733 else { 4760 val = NULL;
4761 } else {
4734 /* Paranoia. What if user entered 9999999999999 4762 /* Paranoia. What if user entered 9999999999999
4735 * which fits in arith_t but not int? */ 4763 * which fits in arith_t but not int? */
4736 if (len >= INT_MAX) 4764 if (len >= INT_MAX)
@@ -4742,7 +4770,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
4742#endif 4770#endif
4743 { 4771 {
4744 die_if_script("malformed ${%s:...}", var); 4772 die_if_script("malformed ${%s:...}", var);
4745 val = ""; 4773 val = NULL;
4746 } 4774 }
4747 } else { /* one of "-=+?" */ 4775 } else { /* one of "-=+?" */
4748 /* Standard-mandated substitution ops: 4776 /* Standard-mandated substitution ops:
@@ -4925,30 +4953,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg)
4925#if ENABLE_SH_MATH_SUPPORT 4953#if ENABLE_SH_MATH_SUPPORT
4926 case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */ 4954 case '+': { /* <SPECIAL_VAR_SYMBOL>+cmd<SPECIAL_VAR_SYMBOL> */
4927 arith_t res; 4955 arith_t res;
4928 int errcode;
4929 4956
4930 arg++; /* skip '+' */ 4957 arg++; /* skip '+' */
4931 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */ 4958 *p = '\0'; /* replace trailing <SPECIAL_VAR_SYMBOL> */
4932 debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch); 4959 debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch);
4933 res = expand_and_evaluate_arith(arg, &errcode); 4960 res = expand_and_evaluate_arith(arg, NULL);
4934 4961 debug_printf_subst("ARITH RES '"ARITH_FMT"'\n", res);
4935 if (errcode < 0) { 4962 sprintf(arith_buf, ARITH_FMT, res);
4936 const char *msg = "error in arithmetic";
4937 switch (errcode) {
4938 case -3:
4939 msg = "exponent less than 0";
4940 break;
4941 case -2:
4942 msg = "divide by 0";
4943 break;
4944 case -5:
4945 msg = "expression recursion loop detected";
4946 break;
4947 }
4948 die_if_script(msg);
4949 }
4950 debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res);
4951 sprintf(arith_buf, arith_t_fmt, res);
4952 val = arith_buf; 4963 val = arith_buf;
4953 break; 4964 break;
4954 } 4965 }
@@ -7346,6 +7357,7 @@ int hush_main(int argc, char **argv)
7346 unsigned builtin_argc; 7357 unsigned builtin_argc;
7347 char **e; 7358 char **e;
7348 struct variable *cur_var; 7359 struct variable *cur_var;
7360 struct variable shell_ver;
7349 7361
7350 INIT_G(); 7362 INIT_G();
7351 if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */ 7363 if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */
@@ -7354,12 +7366,13 @@ int hush_main(int argc, char **argv)
7354 G.argv0_for_re_execing = argv[0]; 7366 G.argv0_for_re_execing = argv[0];
7355#endif 7367#endif
7356 /* Deal with HUSH_VERSION */ 7368 /* Deal with HUSH_VERSION */
7357 G.shell_ver.flg_export = 1; 7369 memset(&shell_ver, 0, sizeof(shell_ver));
7358 G.shell_ver.flg_read_only = 1; 7370 shell_ver.flg_export = 1;
7371 shell_ver.flg_read_only = 1;
7359 /* Code which handles ${var<op>...} needs writable values for all variables, 7372 /* Code which handles ${var<op>...} needs writable values for all variables,
7360 * therefore we xstrdup: */ 7373 * therefore we xstrdup: */
7361 G.shell_ver.varstr = xstrdup(hush_version_str), 7374 shell_ver.varstr = xstrdup(hush_version_str),
7362 G.top_var = &G.shell_ver; 7375 G.top_var = &shell_ver;
7363 /* Create shell local variables from the values 7376 /* Create shell local variables from the values
7364 * currently living in the environment */ 7377 * currently living in the environment */
7365 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); 7378 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
@@ -7378,8 +7391,8 @@ int hush_main(int argc, char **argv)
7378 e++; 7391 e++;
7379 } 7392 }
7380 /* (Re)insert HUSH_VERSION into env (AFTER we scanned the env!) */ 7393 /* (Re)insert HUSH_VERSION into env (AFTER we scanned the env!) */
7381 debug_printf_env("putenv '%s'\n", G.shell_ver.varstr); 7394 debug_printf_env("putenv '%s'\n", shell_ver.varstr);
7382 putenv(G.shell_ver.varstr); 7395 putenv(shell_ver.varstr);
7383 7396
7384 /* Export PWD */ 7397 /* Export PWD */
7385 set_pwd_var(/*exp:*/ 1); 7398 set_pwd_var(/*exp:*/ 1);
diff --git a/shell/hush_test/hush-arith/arith.right b/shell/hush_test/hush-arith/arith.right
index 718c26ad0..8a201fb3b 100644
--- a/shell/hush_test/hush-arith/arith.right
+++ b/shell/hush_test/hush-arith/arith.right
@@ -61,7 +61,7 @@ check that the unevaluated part of the ternary operator does not do evaluation o
6120 20 6120 20
6230 30 6230 30
63check precedence of assignment vs. conditional operator 63check precedence of assignment vs. conditional operator
64hush: error in arithmetic 64hush: arithmetic syntax error
65check precedence of assignment vs. conditional operator 65check precedence of assignment vs. conditional operator
66associativity of assignment-operator operator 66associativity of assignment-operator operator
676 6 676 6
@@ -70,22 +70,22 @@ octal, hex
70263 263 70263 263
71255 255 71255 255
7240 40 7240 40
73hush: error in arithmetic 73hush: arithmetic syntax error
74hush: divide by 0 74hush: divide by zero
75hush: can't execute 'let': No such file or directory 75hush: can't execute 'let': No such file or directory
76hush: error in arithmetic 76hush: arithmetic syntax error
77hush: can't execute 'let': No such file or directory 77hush: can't execute 'let': No such file or directory
78abc 78abc
79def 79def
80ghi 80ghi
81hush: error in arithmetic 81hush: arithmetic syntax error
8216 16 8216 16
83hush: error in arithmetic 83hush: arithmetic syntax error
84hush: error in arithmetic 84hush: malformed ?: operator
85hush: error in arithmetic 85hush: arithmetic syntax error
869 9 869 9
87hush: error in arithmetic 87hush: arithmetic syntax error
88hush: error in arithmetic 88hush: arithmetic syntax error
899 9 899 9
909 9 909 9
919 9 919 9
@@ -106,18 +106,18 @@ hush: error in arithmetic
1063 3 1063 3
1074 4 1074 4
1084 4 1084 4
109hush: error in arithmetic 109hush: arithmetic syntax error
110hush: error in arithmetic 110hush: arithmetic syntax error
111hush: error in arithmetic 111hush: arithmetic syntax error
112hush: error in arithmetic 112hush: arithmetic syntax error
113hush: error in arithmetic 113hush: arithmetic syntax error
1144 4 1144 4
1157 7 1157 7
116-7 -7 116-7 -7
117hush: error in arithmetic 117hush: arithmetic syntax error
118hush: error in arithmetic 118hush: arithmetic syntax error
119hush: error in arithmetic 119hush: arithmetic syntax error
120hush: error in arithmetic 120hush: arithmetic syntax error
1216 6 1216 6
1223 3 1223 3
1237 7 1237 7
@@ -128,19 +128,19 @@ hush: error in arithmetic
1282 2 1282 2
129-2 -2 129-2 -2
1301 1 1301 1
131hush: error in arithmetic 131hush: arithmetic syntax error
132hush: error in arithmetic 132hush: arithmetic syntax error
133hush: error in arithmetic 133hush: arithmetic syntax error
134hush: error in arithmetic 134hush: arithmetic syntax error
135hush: error in arithmetic 135hush: arithmetic syntax error
1365 5 1365 5
1371 1 1371 1
1384 4 1384 4
1390 0 1390 0
140hush: error in arithmetic 140hush: arithmetic syntax error
141hush: error in arithmetic 141hush: arithmetic syntax error
1428 12 1428 12
143hush: error in arithmetic 143hush: arithmetic syntax error
14442 14442
14542 14542
14642 14642
diff --git a/shell/hush_test/hush-glob/bash_brace1.right b/shell/hush_test/hush-glob/bash_brace1.right
new file mode 100644
index 000000000..63365c9e4
--- /dev/null
+++ b/shell/hush_test/hush-glob/bash_brace1.right
@@ -0,0 +1,4 @@
1bash_brace1.tests
2*{b,b}race1.t*
3bash_brace1.tests bash_brace1.tests
4Done: 0
diff --git a/shell/hush_test/hush-glob/bash_brace1.tests b/shell/hush_test/hush-glob/bash_brace1.tests
new file mode 100755
index 000000000..eb2f0e974
--- /dev/null
+++ b/shell/hush_test/hush-glob/bash_brace1.tests
@@ -0,0 +1,10 @@
1# unquoted $v should be globbed:
2v='*brace1.t*'; echo $v
3
4# ...but not brace expanded:
5v='*{b,b}race1.t*'; echo $v
6
7# whereas direct brces are expanded:
8echo *{b,b}race1.t*
9
10echo Done: $?
diff --git a/shell/math.c b/shell/math.c
index a4c55a4d0..760645d0f 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * arithmetic code ripped out of ash shell for code sharing 2 * Arithmetic code ripped out of ash shell for code sharing.
3 * 3 *
4 * This code is derived from software contributed to Berkeley by 4 * This code is derived from software contributed to Berkeley by
5 * Kenneth Almquist. 5 * Kenneth Almquist.
@@ -26,43 +26,41 @@
26 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 26 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
27 */ 27 */
28/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> 28/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
29 29 *
30 Permission is hereby granted, free of charge, to any person obtaining 30 * Permission is hereby granted, free of charge, to any person obtaining
31 a copy of this software and associated documentation files (the 31 * a copy of this software and associated documentation files (the
32 "Software"), to deal in the Software without restriction, including 32 * "Software"), to deal in the Software without restriction, including
33 without limitation the rights to use, copy, modify, merge, publish, 33 * without limitation the rights to use, copy, modify, merge, publish,
34 distribute, sublicense, and/or sell copies of the Software, and to 34 * distribute, sublicense, and/or sell copies of the Software, and to
35 permit persons to whom the Software is furnished to do so, subject to 35 * permit persons to whom the Software is furnished to do so, subject to
36 the following conditions: 36 * the following conditions:
37 37 *
38 The above copyright notice and this permission notice shall be 38 * The above copyright notice and this permission notice shall be
39 included in all copies or substantial portions of the Software. 39 * included in all copies or substantial portions of the Software.
40 40 *
41 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 41 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
42 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 42 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
43 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 43 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
44 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 44 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
45 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 45 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
46 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 46 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
47 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 47 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48*/ 48 */
49 49
50/* This is my infix parser/evaluator. It is optimized for size, intended 50/* This is my infix parser/evaluator. It is optimized for size, intended
51 * as a replacement for yacc-based parsers. However, it may well be faster 51 * as a replacement for yacc-based parsers. However, it may well be faster
52 * than a comparable parser written in yacc. The supported operators are 52 * than a comparable parser written in yacc. The supported operators are
53 * listed in #defines below. Parens, order of operations, and error handling 53 * listed in #defines below. Parens, order of operations, and error handling
54 * are supported. This code is thread safe. The exact expression format should 54 * are supported. This code is thread safe. The exact expression format should
55 * be that which POSIX specifies for shells. */ 55 * be that which POSIX specifies for shells.
56 56 *
57/* The code uses a simple two-stack algorithm. See 57 * The code uses a simple two-stack algorithm. See
58 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html 58 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
59 * for a detailed explanation of the infix-to-postfix algorithm on which 59 * for a detailed explanation of the infix-to-postfix algorithm on which
60 * this is based (this code differs in that it applies operators immediately 60 * this is based (this code differs in that it applies operators immediately
61 * to the stack instead of adding them to a queue to end up with an 61 * to the stack instead of adding them to a queue to end up with an
62 * expression). */ 62 * expression).
63 63 */
64/* To use the routine, call it with an expression string and error return
65 * pointer */
66 64
67/* 65/*
68 * Aug 24, 2001 Manuel Novoa III 66 * Aug 24, 2001 Manuel Novoa III
@@ -104,28 +102,23 @@
104 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 102 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
105 * 103 *
106 * - allow access to variable, 104 * - allow access to variable,
107 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6) 105 * use recursive value indirection: c="2*2"; a="c"; echo $((a+=2)) produce 6
108 * - realize assign syntax (VAR=expr, +=, *= etc) 106 * - implement assign syntax (VAR=expr, +=, *= etc)
109 * - realize exponentiation (** operator) 107 * - implement exponentiation (** operator)
110 * - realize comma separated - expr, expr 108 * - implement comma separated - expr, expr
111 * - realise ++expr --expr expr++ expr-- 109 * - implement ++expr --expr expr++ expr--
112 * - realise expr ? expr : expr (but, second expr calculate always) 110 * - implement expr ? expr : expr (but second expr is always calculated)
113 * - allow hexadecimal and octal numbers 111 * - allow hexadecimal and octal numbers
114 * - was restored loses XOR operator 112 * - restore lost XOR operator
115 * - remove one goto label, added three ;-) 113 * - protect $((num num)) as true zero expr (Manuel's error)
116 * - protect $((num num)) as true zero expr (Manuel`s error)
117 * - always use special isspace(), see comment from bash ;-) 114 * - always use special isspace(), see comment from bash ;-)
118 */ 115 */
119#include "libbb.h" 116#include "libbb.h"
120#include "math.h" 117#include "math.h"
121 118
122#define a_e_h_t arith_eval_hooks_t 119#define lookupvar (math_state->lookupvar)
123#define lookupvar (math_hooks->lookupvar) 120#define setvar (math_state->setvar )
124#define setvar (math_hooks->setvar ) 121//#define endofname (math_state->endofname)
125//#define endofname (math_hooks->endofname)
126
127#define arith_isspace(arithval) \
128 (arithval == ' ' || arithval == '\n' || arithval == '\t')
129 122
130typedef unsigned char operator; 123typedef unsigned char operator;
131 124
@@ -133,181 +126,199 @@ typedef unsigned char operator;
133 * precedence, and 3 high bits are an ID unique across operators of that 126 * precedence, and 3 high bits are an ID unique across operators of that
134 * precedence. The ID portion is so that multiple operators can have the 127 * precedence. The ID portion is so that multiple operators can have the
135 * same precedence, ensuring that the leftmost one is evaluated first. 128 * same precedence, ensuring that the leftmost one is evaluated first.
136 * Consider * and /. */ 129 * Consider * and /
137 130 */
138#define tok_decl(prec,id) (((id)<<5)|(prec)) 131#define tok_decl(prec,id) (((id)<<5) | (prec))
139#define PREC(op) ((op) & 0x1F) 132#define PREC(op) ((op) & 0x1F)
140
141#define TOK_LPAREN tok_decl(0,0)
142 133
143#define TOK_COMMA tok_decl(1,0) 134#define TOK_LPAREN tok_decl(0,0)
144 135
145#define TOK_ASSIGN tok_decl(2,0) 136#define TOK_COMMA tok_decl(1,0)
146#define TOK_AND_ASSIGN tok_decl(2,1)
147#define TOK_OR_ASSIGN tok_decl(2,2)
148#define TOK_XOR_ASSIGN tok_decl(2,3)
149#define TOK_PLUS_ASSIGN tok_decl(2,4)
150#define TOK_MINUS_ASSIGN tok_decl(2,5)
151#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
152#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
153 137
154#define TOK_MUL_ASSIGN tok_decl(3,0) 138/* All assignments are right associative and have the same precedence,
155#define TOK_DIV_ASSIGN tok_decl(3,1) 139 * but there are 11 of them, which doesn't fit into 3 bits for unique id.
156#define TOK_REM_ASSIGN tok_decl(3,2) 140 * Abusing another precedence level:
141 */
142#define TOK_ASSIGN tok_decl(2,0)
143#define TOK_AND_ASSIGN tok_decl(2,1)
144#define TOK_OR_ASSIGN tok_decl(2,2)
145#define TOK_XOR_ASSIGN tok_decl(2,3)
146#define TOK_PLUS_ASSIGN tok_decl(2,4)
147#define TOK_MINUS_ASSIGN tok_decl(2,5)
148#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
149#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
157 150
158/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ 151#define TOK_MUL_ASSIGN tok_decl(3,0)
159#define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0) 152#define TOK_DIV_ASSIGN tok_decl(3,1)
153#define TOK_REM_ASSIGN tok_decl(3,2)
160 154
161/* conditional is right associativity too */ 155#define fix_assignment_prec(prec) do { if (prec == 3) prec = 2; } while (0)
162#define TOK_CONDITIONAL tok_decl(4,0)
163#define TOK_CONDITIONAL_SEP tok_decl(4,1)
164 156
165#define TOK_OR tok_decl(5,0) 157/* Ternary conditional operator is right associative too */
158#define TOK_CONDITIONAL tok_decl(4,0)
159#define TOK_CONDITIONAL_SEP tok_decl(4,1)
166 160
167#define TOK_AND tok_decl(6,0) 161#define TOK_OR tok_decl(5,0)
168 162
169#define TOK_BOR tok_decl(7,0) 163#define TOK_AND tok_decl(6,0)
170 164
171#define TOK_BXOR tok_decl(8,0) 165#define TOK_BOR tok_decl(7,0)
172 166
173#define TOK_BAND tok_decl(9,0) 167#define TOK_BXOR tok_decl(8,0)
174 168
175#define TOK_EQ tok_decl(10,0) 169#define TOK_BAND tok_decl(9,0)
176#define TOK_NE tok_decl(10,1)
177 170
178#define TOK_LT tok_decl(11,0) 171#define TOK_EQ tok_decl(10,0)
179#define TOK_GT tok_decl(11,1) 172#define TOK_NE tok_decl(10,1)
180#define TOK_GE tok_decl(11,2)
181#define TOK_LE tok_decl(11,3)
182 173
183#define TOK_LSHIFT tok_decl(12,0) 174#define TOK_LT tok_decl(11,0)
184#define TOK_RSHIFT tok_decl(12,1) 175#define TOK_GT tok_decl(11,1)
176#define TOK_GE tok_decl(11,2)
177#define TOK_LE tok_decl(11,3)
185 178
186#define TOK_ADD tok_decl(13,0) 179#define TOK_LSHIFT tok_decl(12,0)
187#define TOK_SUB tok_decl(13,1) 180#define TOK_RSHIFT tok_decl(12,1)
188 181
189#define TOK_MUL tok_decl(14,0) 182#define TOK_ADD tok_decl(13,0)
190#define TOK_DIV tok_decl(14,1) 183#define TOK_SUB tok_decl(13,1)
191#define TOK_REM tok_decl(14,2)
192 184
193/* exponent is right associativity */ 185#define TOK_MUL tok_decl(14,0)
194#define TOK_EXPONENT tok_decl(15,1) 186#define TOK_DIV tok_decl(14,1)
187#define TOK_REM tok_decl(14,2)
195 188
196/* For now unary operators. */ 189/* Exponent is right associative */
197#define UNARYPREC 16 190#define TOK_EXPONENT tok_decl(15,1)
198#define TOK_BNOT tok_decl(UNARYPREC,0)
199#define TOK_NOT tok_decl(UNARYPREC,1)
200 191
201#define TOK_UMINUS tok_decl(UNARYPREC+1,0) 192/* Unary operators */
202#define TOK_UPLUS tok_decl(UNARYPREC+1,1) 193#define UNARYPREC 16
194#define TOK_BNOT tok_decl(UNARYPREC,0)
195#define TOK_NOT tok_decl(UNARYPREC,1)
203 196
204#define PREC_PRE (UNARYPREC+2) 197#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
198#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
205 199
206#define TOK_PRE_INC tok_decl(PREC_PRE, 0) 200#define PREC_PRE (UNARYPREC+2)
207#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
208 201
209#define PREC_POST (UNARYPREC+3) 202#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
203#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
210 204
211#define TOK_POST_INC tok_decl(PREC_POST, 0) 205#define PREC_POST (UNARYPREC+3)
212#define TOK_POST_DEC tok_decl(PREC_POST, 1)
213 206
214#define SPEC_PREC (UNARYPREC+4) 207#define TOK_POST_INC tok_decl(PREC_POST, 0)
208#define TOK_POST_DEC tok_decl(PREC_POST, 1)
215 209
216#define TOK_NUM tok_decl(SPEC_PREC, 0) 210#define SPEC_PREC (UNARYPREC+4)
217#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
218 211
219#define NUMPTR (*numstackptr) 212#define TOK_NUM tok_decl(SPEC_PREC, 0)
213#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
220 214
221static int 215static int
222tok_have_assign(operator op) 216is_assign_op(operator op)
223{ 217{
224 operator prec = PREC(op); 218 operator prec = PREC(op);
225 219 fix_assignment_prec(prec);
226 convert_prec_is_assing(prec); 220 return prec == PREC(TOK_ASSIGN)
227 return (prec == PREC(TOK_ASSIGN) || 221 || prec == PREC_PRE
228 prec == PREC_PRE || prec == PREC_POST); 222 || prec == PREC_POST;
229} 223}
230 224
231static int 225static int
232is_right_associativity(operator prec) 226is_right_associative(operator prec)
233{ 227{
234 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) 228 return prec == PREC(TOK_ASSIGN)
235 || prec == PREC(TOK_CONDITIONAL)); 229 || prec == PREC(TOK_EXPONENT)
230 || prec == PREC(TOK_CONDITIONAL);
236} 231}
237 232
233
238typedef struct { 234typedef struct {
239 arith_t val; 235 arith_t val;
240 arith_t contidional_second_val; 236 /* We acquire second_val only when "expr1 : expr2" part
241 char contidional_second_val_initialized; 237 * of ternary ?: op is evaluated.
242 char *var; /* if NULL then is regular number, 238 * We treat ?: as two binary ops: (expr ? (expr1 : expr2)).
243 else is variable name */ 239 * ':' produces a new value which has two parts, val and second_val;
244} v_n_t; 240 * then '?' selects one of them based on its left side.
245 241 */
246typedef struct chk_var_recursive_looped_t { 242 arith_t second_val;
243 char second_val_present;
244 /* If NULL then it's just a number, else it's a named variable */
245 char *var;
246} var_or_num_t;
247
248typedef struct remembered_name {
249 struct remembered_name *next;
247 const char *var; 250 const char *var;
248 struct chk_var_recursive_looped_t *next; 251} remembered_name;
249} chk_var_recursive_looped_t;
250 252
251static chk_var_recursive_looped_t *prev_chk_var_recursive;
252 253
253static int 254static arith_t FAST_FUNC
254arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks) 255evaluate_string(arith_state_t *math_state, const char *expr);
256
257static const char*
258arith_lookup_val(arith_state_t *math_state, var_or_num_t *t)
255{ 259{
256 if (t->var) { 260 if (t->var) {
257 const char *p = lookupvar(t->var); 261 const char *p = lookupvar(t->var);
258
259 if (p) { 262 if (p) {
260 int errcode; 263 remembered_name *cur;
261 264 remembered_name cur_save;
262 /* recursive try as expression */
263 chk_var_recursive_looped_t *cur;
264 chk_var_recursive_looped_t cur_save;
265 265
266 for (cur = prev_chk_var_recursive; cur; cur = cur->next) { 266 /* did we already see this name?
267 * testcase: a=b; b=a; echo $((a))
268 */
269 for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) {
267 if (strcmp(cur->var, t->var) == 0) { 270 if (strcmp(cur->var, t->var) == 0) {
268 /* expression recursion loop detected */ 271 /* Yes */
269 return -5; 272 return "expression recursion loop detected";
270 } 273 }
271 } 274 }
272 /* save current lookuped var name */ 275
273 cur = prev_chk_var_recursive; 276 /* push current var name */
277 cur = math_state->list_of_recursed_names;
274 cur_save.var = t->var; 278 cur_save.var = t->var;
275 cur_save.next = cur; 279 cur_save.next = cur;
276 prev_chk_var_recursive = &cur_save; 280 math_state->list_of_recursed_names = &cur_save;
281
282 /* recursively evaluate p as expression */
283 t->val = evaluate_string(math_state, p);
277 284
278 t->val = arith (p, &errcode, math_hooks); 285 /* pop current var name */
279 /* restore previous ptr after recursiving */ 286 math_state->list_of_recursed_names = cur;
280 prev_chk_var_recursive = cur; 287
281 return errcode; 288 return math_state->errmsg;
282 } 289 }
283 /* allow undefined var as 0 */ 290 /* treat undefined var as 0 */
284 t->val = 0; 291 t->val = 0;
285 } 292 }
286 return 0; 293 return 0;
287} 294}
288 295
289/* "applying" a token means performing it on the top elements on the integer 296/* "Applying" a token means performing it on the top elements on the integer
290 * stack. For a unary operator it will only change the top element, but a 297 * stack. For an unary operator it will only change the top element, but a
291 * binary operator will pop two arguments and push a result */ 298 * binary operator will pop two arguments and push the result */
292static NOINLINE int 299static NOINLINE const char*
293arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hooks) 300arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_or_num_t **numstackptr)
294{ 301{
295 v_n_t *numptr_m1; 302#define NUMPTR (*numstackptr)
296 arith_t numptr_val, rez; 303
297 int ret_arith_lookup_val; 304 var_or_num_t *top_of_stack;
305 arith_t rez;
306 const char *err;
298 307
299 /* There is no operator that can work without arguments */ 308 /* There is no operator that can work without arguments */
300 if (NUMPTR == numstack) goto err; 309 if (NUMPTR == numstack)
301 numptr_m1 = NUMPTR - 1; 310 goto err;
311
312 top_of_stack = NUMPTR - 1;
302 313
303 /* check operand is var with noninteger value */ 314 /* Resolve name to value, if needed */
304 ret_arith_lookup_val = arith_lookup_val(numptr_m1, math_hooks); 315 err = arith_lookup_val(math_state, top_of_stack);
305 if (ret_arith_lookup_val) 316 if (err)
306 return ret_arith_lookup_val; 317 return err;
307 318
308 rez = numptr_m1->val; 319 rez = top_of_stack->val;
309 if (op == TOK_UMINUS) 320 if (op == TOK_UMINUS)
310 rez *= -1; 321 rez = -rez;
311 else if (op == TOK_NOT) 322 else if (op == TOK_NOT)
312 rez = !rez; 323 rez = !rez;
313 else if (op == TOK_BNOT) 324 else if (op == TOK_BNOT)
@@ -318,118 +329,123 @@ arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hoo
318 rez--; 329 rez--;
319 else if (op != TOK_UPLUS) { 330 else if (op != TOK_UPLUS) {
320 /* Binary operators */ 331 /* Binary operators */
332 arith_t right_side_val;
333 char bad_second_val;
321 334
322 /* check and binary operators need two arguments */ 335 /* Binary operators need two arguments */
323 if (numptr_m1 == numstack) goto err; 336 if (top_of_stack == numstack)
324
325 /* ... and they pop one */
326 --NUMPTR;
327 numptr_val = rez;
328 if (op == TOK_CONDITIONAL) {
329 if (!numptr_m1->contidional_second_val_initialized) {
330 /* protect $((expr1 ? expr2)) without ": expr" */
331 goto err;
332 }
333 rez = numptr_m1->contidional_second_val;
334 } else if (numptr_m1->contidional_second_val_initialized) {
335 /* protect $((expr1 : expr2)) without "expr ? " */
336 goto err; 337 goto err;
338 /* ...and they pop one */
339 NUMPTR = top_of_stack; /* this decrements NUMPTR */
340
341 bad_second_val = top_of_stack->second_val_present;
342 if (op == TOK_CONDITIONAL) { /* ? operation */
343 /* Make next if (...) protect against
344 * $((expr1 ? expr2)) - that is, missing ": expr" */
345 bad_second_val = !bad_second_val;
346 }
347 if (bad_second_val) {
348 /* Protect against $((expr <not_?_op> expr1 : expr2)) */
349 return "malformed ?: operator";
337 } 350 }
338 numptr_m1 = NUMPTR - 1; 351
352 top_of_stack--; /* now points to left side */
353
339 if (op != TOK_ASSIGN) { 354 if (op != TOK_ASSIGN) {
340 /* check operand is var with noninteger value for not '=' */ 355 /* Resolve left side value (unless the op is '=') */
341 ret_arith_lookup_val = arith_lookup_val(numptr_m1, math_hooks); 356 err = arith_lookup_val(math_state, top_of_stack);
342 if (ret_arith_lookup_val) 357 if (err)
343 return ret_arith_lookup_val; 358 return err;
344 } 359 }
345 if (op == TOK_CONDITIONAL) { 360
346 numptr_m1->contidional_second_val = rez; 361 right_side_val = rez;
362 rez = top_of_stack->val;
363 if (op == TOK_CONDITIONAL) /* ? operation */
364 rez = (rez ? right_side_val : top_of_stack[1].second_val);
365 else if (op == TOK_CONDITIONAL_SEP) { /* : operation */
366 if (top_of_stack == numstack) {
367 /* Protect against $((expr : expr)) */
368 return "malformed ?: operator";
369 }
370 top_of_stack->second_val_present = op;
371 top_of_stack->second_val = right_side_val;
347 } 372 }
348 rez = numptr_m1->val; 373 else if (op == TOK_BOR || op == TOK_OR_ASSIGN)
349 if (op == TOK_BOR || op == TOK_OR_ASSIGN) 374 rez |= right_side_val;
350 rez |= numptr_val;
351 else if (op == TOK_OR) 375 else if (op == TOK_OR)
352 rez = numptr_val || rez; 376 rez = right_side_val || rez;
353 else if (op == TOK_BAND || op == TOK_AND_ASSIGN) 377 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
354 rez &= numptr_val; 378 rez &= right_side_val;
355 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) 379 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
356 rez ^= numptr_val; 380 rez ^= right_side_val;
357 else if (op == TOK_AND) 381 else if (op == TOK_AND)
358 rez = rez && numptr_val; 382 rez = rez && right_side_val;
359 else if (op == TOK_EQ) 383 else if (op == TOK_EQ)
360 rez = (rez == numptr_val); 384 rez = (rez == right_side_val);
361 else if (op == TOK_NE) 385 else if (op == TOK_NE)
362 rez = (rez != numptr_val); 386 rez = (rez != right_side_val);
363 else if (op == TOK_GE) 387 else if (op == TOK_GE)
364 rez = (rez >= numptr_val); 388 rez = (rez >= right_side_val);
365 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) 389 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
366 rez >>= numptr_val; 390 rez >>= right_side_val;
367 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) 391 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
368 rez <<= numptr_val; 392 rez <<= right_side_val;
369 else if (op == TOK_GT) 393 else if (op == TOK_GT)
370 rez = (rez > numptr_val); 394 rez = (rez > right_side_val);
371 else if (op == TOK_LT) 395 else if (op == TOK_LT)
372 rez = (rez < numptr_val); 396 rez = (rez < right_side_val);
373 else if (op == TOK_LE) 397 else if (op == TOK_LE)
374 rez = (rez <= numptr_val); 398 rez = (rez <= right_side_val);
375 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) 399 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
376 rez *= numptr_val; 400 rez *= right_side_val;
377 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) 401 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
378 rez += numptr_val; 402 rez += right_side_val;
379 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) 403 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
380 rez -= numptr_val; 404 rez -= right_side_val;
381 else if (op == TOK_ASSIGN || op == TOK_COMMA) 405 else if (op == TOK_ASSIGN || op == TOK_COMMA)
382 rez = numptr_val; 406 rez = right_side_val;
383 else if (op == TOK_CONDITIONAL_SEP) { 407 else if (op == TOK_EXPONENT) {
384 if (numptr_m1 == numstack) { 408 arith_t c;
385 /* protect $((expr : expr)) without "expr ? " */ 409 if (right_side_val < 0)
386 goto err; 410 return "exponent less than 0";
387 } 411 c = 1;
388 numptr_m1->contidional_second_val_initialized = op; 412 while (--right_side_val >= 0)
389 numptr_m1->contidional_second_val = numptr_val; 413 c *= rez;
390 } else if (op == TOK_CONDITIONAL) { 414 rez = c;
391 rez = rez ? 415 }
392 numptr_val : numptr_m1->contidional_second_val; 416 else if (right_side_val == 0)
393 } else if (op == TOK_EXPONENT) { 417 return "divide by zero";
394 if (numptr_val < 0)
395 return -3; /* exponent less than 0 */
396 else {
397 arith_t c = 1;
398
399 if (numptr_val)
400 while (numptr_val--)
401 c *= rez;
402 rez = c;
403 }
404 } else if (numptr_val==0) /* zero divisor check */
405 return -2;
406 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) 418 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
407 rez /= numptr_val; 419 rez /= right_side_val;
408 else if (op == TOK_REM || op == TOK_REM_ASSIGN) 420 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
409 rez %= numptr_val; 421 rez %= right_side_val;
410 } 422 }
411 if (tok_have_assign(op)) { 423
424 if (is_assign_op(op)) {
412 char buf[sizeof(arith_t)*3 + 2]; 425 char buf[sizeof(arith_t)*3 + 2];
413 426
414 if (numptr_m1->var == NULL) { 427 if (top_of_stack->var == NULL) {
415 /* Hmm, 1=2 ? */ 428 /* Hmm, 1=2 ? */
429//TODO: actually, bash allows ++7 but for some reason it evals to 7, not 8
416 goto err; 430 goto err;
417 } 431 }
418 /* save to shell variable */ 432 /* Save to shell variable */
419 sprintf(buf, arith_t_fmt, rez); 433 sprintf(buf, ARITH_FMT, rez);
420 setvar(numptr_m1->var, buf); 434 setvar(top_of_stack->var, buf);
421 /* after saving, make previous value for v++ or v-- */ 435 /* After saving, make previous value for v++ or v-- */
422 if (op == TOK_POST_INC) 436 if (op == TOK_POST_INC)
423 rez--; 437 rez--;
424 else if (op == TOK_POST_DEC) 438 else if (op == TOK_POST_DEC)
425 rez++; 439 rez++;
426 } 440 }
427 numptr_m1->val = rez; 441
428 /* protect geting var value, is number now */ 442 top_of_stack->val = rez;
429 numptr_m1->var = NULL; 443 /* Erase var name, it is just a number now */
430 return 0; 444 top_of_stack->var = NULL;
445 return NULL;
431 err: 446 err:
432 return -1; 447 return "arithmetic syntax error";
448#undef NUMPTR
433} 449}
434 450
435/* longest must be first */ 451/* longest must be first */
@@ -476,8 +492,7 @@ static const char op_tokens[] ALIGN1 = {
476 '(', 0, TOK_LPAREN, 492 '(', 0, TOK_LPAREN,
477 0 493 0
478}; 494};
479/* ptr to ")" */ 495#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
480#define endexpression (&op_tokens[sizeof(op_tokens)-7])
481 496
482const char* FAST_FUNC 497const char* FAST_FUNC
483endofname(const char *name) 498endofname(const char *name)
@@ -491,35 +506,40 @@ endofname(const char *name)
491 return name; 506 return name;
492} 507}
493 508
494arith_t 509static arith_t FAST_FUNC
495arith(const char *expr, int *perrcode, a_e_h_t *math_hooks) 510evaluate_string(arith_state_t *math_state, const char *expr)
496{ 511{
497 char arithval; /* Current character under analysis */ 512 operator lasttok;
498 operator lasttok, op; 513 const char *errmsg;
499 operator prec; 514 const char *start_expr = expr = skip_whitespace(expr);
500 operator *stack, *stackptr; 515 unsigned expr_len = strlen(expr) + 2;
501 const char *p = endexpression;
502 int errcode;
503 v_n_t *numstack, *numstackptr;
504 unsigned datasizes = strlen(expr) + 2;
505
506 /* Stack of integers */ 516 /* Stack of integers */
507 /* The proof that there can be no more than strlen(startbuf)/2+1 integers 517 /* The proof that there can be no more than strlen(startbuf)/2+1
508 * in any given correct or incorrect expression is left as an exercise to 518 * integers in any given correct or incorrect expression
509 * the reader. */ 519 * is left as an exercise to the reader. */
510 numstackptr = numstack = alloca((datasizes / 2) * sizeof(numstack[0])); 520 var_or_num_t *const numstack = alloca((expr_len / 2) * sizeof(numstack[0]));
521 var_or_num_t *numstackptr = numstack;
511 /* Stack of operator tokens */ 522 /* Stack of operator tokens */
512 stackptr = stack = alloca(datasizes * sizeof(stack[0])); 523 operator *const stack = alloca(expr_len * sizeof(stack[0]));
524 operator *stackptr = stack;
513 525
514 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ 526 /* Start with a left paren */
515 *perrcode = errcode = 0; 527 *stackptr++ = lasttok = TOK_LPAREN;
528 errmsg = NULL;
516 529
517 while (1) { 530 while (1) {
531 const char *p;
532 operator op;
533 operator prec;
534 char arithval;
535
536 expr = skip_whitespace(expr);
518 arithval = *expr; 537 arithval = *expr;
519 if (arithval == 0) { 538 if (arithval == '\0') {
520 if (p == endexpression) { 539 if (expr == start_expr) {
521 /* Null expression. */ 540 /* Null expression */
522 return 0; 541 numstack->val = 0;
542 goto ret;
523 } 543 }
524 544
525 /* This is only reached after all tokens have been extracted from the 545 /* This is only reached after all tokens have been extracted from the
@@ -527,77 +547,80 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
527 * are to be applied in order. At the end, there should be a final 547 * are to be applied in order. At the end, there should be a final
528 * result on the integer stack */ 548 * result on the integer stack */
529 549
530 if (expr != endexpression + 1) { 550 if (expr != ptr_to_rparen + 1) {
531 /* If we haven't done so already, */ 551 /* If we haven't done so already,
532 /* append a closing right paren */ 552 * append a closing right paren
533 expr = endexpression; 553 * and let the loop process it */
534 /* and let the loop process it. */ 554 expr = ptr_to_rparen;
535 continue; 555 continue;
536 } 556 }
537 /* At this point, we're done with the expression. */ 557 /* At this point, we're done with the expression */
538 if (numstackptr != numstack+1) { 558 if (numstackptr != numstack + 1) {
539 /* ... but if there isn't, it's bad */ 559 /* ...but if there isn't, it's bad */
540 err: 560 goto err;
541 *perrcode = -1;
542 return *perrcode;
543 } 561 }
544 if (numstack->var) { 562 if (numstack->var) {
545 /* expression is $((var)) only, lookup now */ 563 /* expression is $((var)) only, lookup now */
546 errcode = arith_lookup_val(numstack, math_hooks); 564 errmsg = arith_lookup_val(math_state, numstack);
547 } 565 }
548 ret: 566 goto ret;
549 *perrcode = errcode;
550 return numstack->val;
551 } 567 }
552 568
553 /* Continue processing the expression. */
554 if (arith_isspace(arithval)) {
555 /* Skip whitespace */
556 goto prologue;
557 }
558 p = endofname(expr); 569 p = endofname(expr);
559 if (p != expr) { 570 if (p != expr) {
560 size_t var_name_size = (p-expr) + 1; /* trailing zero */ 571 /* Name */
561 572 size_t var_name_size = (p-expr) + 1; /* +1 for NUL */
562 numstackptr->var = alloca(var_name_size); 573 numstackptr->var = alloca(var_name_size);
563 safe_strncpy(numstackptr->var, expr, var_name_size); 574 safe_strncpy(numstackptr->var, expr, var_name_size);
564 expr = p; 575 expr = p;
565 num: 576 num:
566 numstackptr->contidional_second_val_initialized = 0; 577 numstackptr->second_val_present = 0;
567 numstackptr++; 578 numstackptr++;
568 lasttok = TOK_NUM; 579 lasttok = TOK_NUM;
569 continue; 580 continue;
570 } 581 }
582
571 if (isdigit(arithval)) { 583 if (isdigit(arithval)) {
584 /* Number */
572 numstackptr->var = NULL; 585 numstackptr->var = NULL;
573 errno = 0; 586 errno = 0;
574 /* call strtoul[l]: */ 587 numstackptr->val = strto_arith_t(expr, (char**) &expr, 0);
575 numstackptr->val = strto_arith_t(expr, (char **) &expr, 0);
576 if (errno) 588 if (errno)
577 numstackptr->val = 0; /* bash compat */ 589 numstackptr->val = 0; /* bash compat */
578 goto num; 590 goto num;
579 } 591 }
580 for (p = op_tokens; ; p++) {
581 const char *o;
582 592
583 if (*p == 0) { 593 /* Should be an operator */
584 /* strange operator not found */ 594 p = op_tokens;
585 goto err; 595 while (1) {
586 } 596// TODO: bash allows 7+++v, treats it as 7 + ++v
587 for (o = expr; *p && *o == *p; p++) 597// we treat it as 7++ + v and reject
588 o++; 598 /* Compare expr to current op_tokens[] element */
589 if (!*p) { 599 const char *e = expr;
590 /* found */ 600 while (1) {
591 expr = o - 1; 601 if (*p == '\0') {
592 break; 602 /* Match: operator is found */
603 expr = e;
604 goto tok_found;
605 }
606 if (*p != *e)
607 break;
608 p++;
609 e++;
593 } 610 }
594 /* skip tail uncompared token */ 611 /* No match, go to next element of op_tokens[] */
595 while (*p) 612 while (*p)
596 p++; 613 p++;
597 /* skip zero delim */ 614 p += 2; /* skip NUL and TOK_foo bytes */
598 p++; 615 if (*p == '\0') {
616 /* No next element, operator not found */
617 //math_state->syntax_error_at = expr;
618 goto err;
619 }
599 } 620 }
600 op = p[1]; 621 tok_found:
622 op = p[1]; /* fetch TOK_foo value */
623 /* NB: expr now points past the operator */
601 624
602 /* post grammar: a++ reduce to num */ 625 /* post grammar: a++ reduce to num */
603 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) 626 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
@@ -626,13 +649,13 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
626 /* We don't want an unary operator to cause recursive descent on the 649 /* We don't want an unary operator to cause recursive descent on the
627 * stack, because there can be many in a row and it could cause an 650 * stack, because there can be many in a row and it could cause an
628 * operator to be evaluated before its argument is pushed onto the 651 * operator to be evaluated before its argument is pushed onto the
629 * integer stack. */ 652 * integer stack.
630 /* But for binary operators, "apply" everything on the operator 653 * But for binary operators, "apply" everything on the operator
631 * stack until we find an operator with a lesser priority than the 654 * stack until we find an operator with a lesser priority than the
632 * one we have just extracted. */ 655 * one we have just extracted. If op is right-associative,
633 /* Left paren is given the lowest priority so it will never be 656 * then stop "applying" on the equal priority too.
657 * Left paren is given the lowest priority so it will never be
634 * "applied" in this way. 658 * "applied" in this way.
635 * if associativity is right and priority eq, applied also skip
636 */ 659 */
637 prec = PREC(op); 660 prec = PREC(op);
638 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { 661 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
@@ -642,41 +665,56 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
642 goto err; 665 goto err;
643 } 666 }
644 while (stackptr != stack) { 667 while (stackptr != stack) {
668 operator prev_op = *--stackptr;
645 if (op == TOK_RPAREN) { 669 if (op == TOK_RPAREN) {
646 /* The algorithm employed here is simple: while we don't 670 /* The algorithm employed here is simple: while we don't
647 * hit an open paren nor the bottom of the stack, pop 671 * hit an open paren nor the bottom of the stack, pop
648 * tokens and apply them */ 672 * tokens and apply them */
649 if (stackptr[-1] == TOK_LPAREN) { 673 if (prev_op == TOK_LPAREN) {
650 --stackptr; 674 /* Any operator directly after a
651 /* Any operator directly after a */ 675 * close paren should consider itself binary */
652 lasttok = TOK_NUM; 676 lasttok = TOK_NUM;
653 /* close paren should consider itself binary */ 677 goto next;
654 goto prologue;
655 } 678 }
656 } else { 679 } else {
657 operator prev_prec = PREC(stackptr[-1]); 680 operator prev_prec = PREC(prev_op);
658 681 fix_assignment_prec(prec);
659 convert_prec_is_assing(prec); 682 fix_assignment_prec(prev_prec);
660 convert_prec_is_assing(prev_prec); 683 if (prev_prec < prec
661 if (prev_prec < prec) 684 || (prev_prec == prec && is_right_associative(prec))
662 break; 685 ) {
663 /* check right assoc */ 686 stackptr++;
664 if (prev_prec == prec && is_right_associativity(prec))
665 break; 687 break;
688 }
666 } 689 }
667 errcode = arith_apply(*--stackptr, numstack, &numstackptr, math_hooks); 690 errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr);
668 if (errcode) goto ret; 691 if (errmsg)
692 goto err_with_custom_msg;
669 } 693 }
670 if (op == TOK_RPAREN) { 694 if (op == TOK_RPAREN)
671 goto err; 695 goto err;
672 }
673 } 696 }
674 697
675 /* Push this operator to the stack and remember it. */ 698 /* Push this operator to the stack and remember it */
676 *stackptr++ = lasttok = op; 699 *stackptr++ = lasttok = op;
677 prologue: 700 next: ;
678 ++expr; 701 } /* while (1) */
679 } /* while */ 702
703 err:
704 errmsg = "arithmetic syntax error";
705 err_with_custom_msg:
706 numstack->val = -1;
707 ret:
708 math_state->errmsg = errmsg;
709 return numstack->val;
710}
711
712arith_t FAST_FUNC
713arith(arith_state_t *math_state, const char *expr)
714{
715 math_state->errmsg = NULL;
716 math_state->list_of_recursed_names = NULL;
717 return evaluate_string(math_state, expr);
680} 718}
681 719
682/* 720/*
diff --git a/shell/math.h b/shell/math.h
index 96088b4d2..2d305eb12 100644
--- a/shell/math.h
+++ b/shell/math.h
@@ -9,67 +9,53 @@
9 9
10/* The math library has just one function: 10/* The math library has just one function:
11 * 11 *
12 * arith_t arith(const char *expr, int *perrcode, arith_eval_hooks_t *hooks); 12 * arith_t arith(arith_state_t *state, const char *expr);
13 * 13 *
14 * The first argument is the math string to parse. All normal expansions must 14 * The expr argument is the math string to parse. All normal expansions must
15 * be done already. i.e. no dollar symbols should be present. 15 * be done already. i.e. no dollar symbols should be present.
16 * 16 *
17 * The second argument is a semi-detailed error description in case something 17 * The state argument is a pointer to a struct of hooks for your shell (see below),
18 * goes wrong in the parsing steps. Currently, those values are (for 18 * and an error message string (NULL if no error).
19 * compatibility, you should assume all negative values are errors):
20 * 0 - no errors (yay!)
21 * -1 - unspecified problem
22 * -2 - divide by zero
23 * -3 - exponent less than 0
24 * -5 - expression recursion loop detected
25 * 19 *
26 * The third argument is a struct pointer of hooks for your shell (see below). 20 * The function returns the answer to the expression. So if you called it
27 * 21 * with the expression:
28 * The function returns the answer to the expression. So if you called it 22 * "1 + 2 + 3"
29 * with the expression: 23 * you would obviously get back 6.
30 * "1 + 2 + 3"
31 * You would obviously get back 6.
32 */ 24 */
33 25
34/* To add support to a shell, you need to implement three functions: 26/* To add support to a shell, you need to implement three functions:
35 * 27 *
36 * lookupvar() - look up and return the value of a variable 28 * lookupvar() - look up and return the value of a variable
37 * 29 *
38 * If the shell does: 30 * If the shell does:
39 * foo=123 31 * foo=123
40 * Then the code: 32 * Then the code:
41 * const char *val = lookupvar("foo"); 33 * const char *val = lookupvar("foo");
42 * Will result in val pointing to "123" 34 * will result in val pointing to "123"
43 * 35 *
44 * setvar() - set a variable to some value 36 * setvar() - set a variable to some value
45 * 37 *
46 * If the arithmetic expansion does something like: 38 * If the arithmetic expansion does something like:
47 * $(( i = 1)) 39 * $(( i = 1))
48 * Then the math code will make a call like so: 40 * then the math code will make a call like so:
49 * setvar("i", "1", 0); 41 * setvar("i", "1", 0);
50 * The storage for the first two parameters are not allocated, so your 42 * The storage for the first two parameters are not allocated, so your
51 * shell implementation will most likely need to strdup() them to save. 43 * shell implementation will most likely need to strdup() them to save.
52 * 44 *
53 * endofname() - return the end of a variable name from input 45 * endofname() - return the end of a variable name from input
54 * 46 *
55 * The arithmetic code does not know about variable naming conventions. 47 * The arithmetic code does not know about variable naming conventions.
56 * So when it is given an experession, it knows something is not numeric, 48 * So when it is given an experession, it knows something is not numeric,
57 * but it is up to the shell to dictate what is a valid identifiers. 49 * but it is up to the shell to dictate what is a valid identifiers.
58 * So when it encounters something like: 50 * So when it encounters something like:
59 * $(( some_var + 123 )) 51 * $(( some_var + 123 ))
60 * It will make a call like so: 52 * It will make a call like so:
61 * end = endofname("some_var + 123"); 53 * end = endofname("some_var + 123");
62 * So the shell needs to scan the input string and return a pointer to the 54 * So the shell needs to scan the input string and return a pointer to the
63 * first non-identifier string. In this case, it should return the input 55 * first non-identifier string. In this case, it should return the input
64 * pointer with an offset pointing to the first space. The typical 56 * pointer with an offset pointing to the first space. The typical
65 * implementation will return the offset of first char that does not match 57 * implementation will return the offset of first char that does not match
66 * the regex (in C locale): ^[a-zA-Z_][a-zA-Z_0-9]* 58 * the regex (in C locale): ^[a-zA-Z_][a-zA-Z_0-9]*
67 */
68
69/* To make your life easier when dealing with optional 64bit math support,
70 * rather than assume that the type is "signed long" and you can always
71 * use "%ld" to scan/print the value, use the arith_t helper defines. See
72 * below for the exact things that are available.
73 */ 59 */
74 60
75#ifndef SHELL_MATH_H 61#ifndef SHELL_MATH_H
@@ -79,11 +65,11 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
79 65
80#if ENABLE_SH_MATH_SUPPORT_64 66#if ENABLE_SH_MATH_SUPPORT_64
81typedef long long arith_t; 67typedef long long arith_t;
82#define arith_t_fmt "%lld" 68#define ARITH_FMT "%lld"
83#define strto_arith_t strtoull 69#define strto_arith_t strtoull
84#else 70#else
85typedef long arith_t; 71typedef long arith_t;
86#define arith_t_fmt "%ld" 72#define ARITH_FMT "%ld"
87#define strto_arith_t strtoul 73#define strto_arith_t strtoul
88#endif 74#endif
89 75
@@ -96,13 +82,15 @@ typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name);
96typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val); 82typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val);
97//typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name); 83//typedef const char* FAST_FUNC (*arith_var_endofname_t)(const char *name);
98 84
99typedef struct arith_eval_hooks { 85typedef struct arith_state_t {
86 const char *errmsg;
100 arith_var_lookup_t lookupvar; 87 arith_var_lookup_t lookupvar;
101 arith_var_set_t setvar; 88 arith_var_set_t setvar;
102// arith_var_endofname_t endofname; 89// arith_var_endofname_t endofname;
103} arith_eval_hooks_t; 90 void *list_of_recursed_names;
91} arith_state_t;
104 92
105arith_t arith(const char *expr, int *perrcode, arith_eval_hooks_t*); 93arith_t FAST_FUNC arith(arith_state_t *state, const char *expr);
106 94
107POP_SAVED_FUNCTION_VISIBILITY 95POP_SAVED_FUNCTION_VISIBILITY
108 96
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index 9e5e5a0f1..56b11ca46 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -24,6 +24,12 @@ testing "awk hex const 2" "awk '{ print or(0x80000000,1) }'" "2.14748e+09\n" ""
24testing "awk oct const" "awk '{ print or(01234,1) }'" "669\n" "" "\n" 24testing "awk oct const" "awk '{ print or(01234,1) }'" "669\n" "" "\n"
25SKIP= 25SKIP=
26 26
27# check that "hex/oct integer" heuristic doesn't kick in on 00NN.NNN
28testing "awk floating const with leading zeroes" \
29 "awk '{ printf \"%f %f\n\", \"000.123\", \"009.123\" }'" \
30 "0.123000 9.123000\n" \
31 "" "\n"
32
27# long field seps requiring regex 33# long field seps requiring regex
28testing "awk long field sep" "awk -F-- '{ print NF, length(\$NF), \$NF }'" \ 34testing "awk long field sep" "awk -F-- '{ print NF, length(\$NF), \$NF }'" \
29 "2 0 \n3 0 \n4 0 \n5 0 \n" \ 35 "2 0 \n3 0 \n4 0 \n5 0 \n" \
diff --git a/testsuite/cpio.tests b/testsuite/cpio.tests
index 05b92dbe4..4cd441a60 100755
--- a/testsuite/cpio.tests
+++ b/testsuite/cpio.tests
@@ -116,6 +116,16 @@ link
116" "" "" 116" "" ""
117SKIP= 117SKIP=
118 118
119# avoid 'not created: newer or same age file exists' message for directories
120rm -rf cpio.testdir cpio.testdir2 2>/dev/null
121mkdir cpio.testdir
122testing "cpio extracts in existing directory" \
123"$ECHO -ne '$hexdump' | bzcat | cpio -id 2>&1; echo \$?" \
124"\
1251 blocks
1260
127" "" ""
128SKIP=
119 129
120# Clean up 130# Clean up
121rm -rf cpio.testdir cpio.testdir2 2>/dev/null 131rm -rf cpio.testdir cpio.testdir2 2>/dev/null
diff --git a/testsuite/gunzip.tests b/testsuite/gunzip.tests
index d7810044f..68c07555d 100755
--- a/testsuite/gunzip.tests
+++ b/testsuite/gunzip.tests
@@ -1,3 +1,3 @@
1#!/bin/sh 1#!/bin/sh
2 2
3. bunzip2.tests 3. ./bunzip2.tests
diff --git a/testsuite/md5sum.tests b/testsuite/md5sum.tests
new file mode 100755
index 000000000..35ec67cb4
--- /dev/null
+++ b/testsuite/md5sum.tests
@@ -0,0 +1,38 @@
1#!/bin/sh
2# Used by {ms5,shaN}sum
3
4# We pipe texts 0...999 bytes long, {md5,shaN}sum them,
5# then {md5,shaN}sum the resulting list.
6# Then we compare the result with expected result.
7#
8# Here are the expected results:
9# efe30c482e0b687e0cca0612f42ca29b
10# d41337e834377140ae7f98460d71d908598ef04f
11# 8e1d3ed57ebc130f0f72508446559eeae06451ae6d61b1e8ce46370cfb8963c3
12# fe413e0f177324d1353893ca0772ceba83fd41512ba63895a0eebb703ef9feac2fb4e92b2cb430b3bda41b46b0cb4ea8307190a5cc795157cfb680a9cd635d0f
13
14if ! test "$1"; then
15 set -- md5sum efe30c482e0b687e0cca0612f42ca29b
16fi
17
18sum="$1"
19expected="$2"
20
21text="The quick brown fox jumps over the lazy dog"
22text=`yes "$text" | head -c 9999`
23
24result=`(
25n=0
26while test $n -le 999; do
27 echo "$text" | head -c $n | "$sum"
28 : $((n++))
29done | "$sum"
30)`
31
32if test x"$result" = x"$expected -"; then
33 echo "PASS: $sum"
34 exit 0
35fi
36
37echo "FAIL: $sum (r:$result exp:$expected)"
38exit 1
diff --git a/testsuite/sha1sum.tests b/testsuite/sha1sum.tests
new file mode 100755
index 000000000..a968fa87c
--- /dev/null
+++ b/testsuite/sha1sum.tests
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3. ./md5sum.tests sha1sum d41337e834377140ae7f98460d71d908598ef04f
diff --git a/testsuite/sha256sum.tests b/testsuite/sha256sum.tests
new file mode 100755
index 000000000..d2dd78f2a
--- /dev/null
+++ b/testsuite/sha256sum.tests
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3. ./md5sum.tests sha256sum 8e1d3ed57ebc130f0f72508446559eeae06451ae6d61b1e8ce46370cfb8963c3
diff --git a/testsuite/sha512sum.tests b/testsuite/sha512sum.tests
new file mode 100755
index 000000000..3bc7cae4f
--- /dev/null
+++ b/testsuite/sha512sum.tests
@@ -0,0 +1,3 @@
1#!/bin/sh
2
3. ./md5sum.tests sha512sum fe413e0f177324d1353893ca0772ceba83fd41512ba63895a0eebb703ef9feac2fb4e92b2cb430b3bda41b46b0cb4ea8307190a5cc795157cfb680a9cd635d0f
diff --git a/util-linux/acpid.c b/util-linux/acpid.c
index c3b3c8b0b..5a3bd5a6a 100644
--- a/util-linux/acpid.c
+++ b/util-linux/acpid.c
@@ -7,27 +7,58 @@
7 * Licensed under GPLv2, see file LICENSE in this source tree. 7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10#include <syslog.h>
11#include <linux/input.h> 11#include <linux/input.h>
12#ifndef EV_SW
13# define EV_SW 0x05
14#endif
15#ifndef EV_KEY
16# define EV_KEY 0x01
17#endif
18#ifndef SW_LID
19# define SW_LID 0x00
20#endif
21#ifndef SW_RFKILL_ALL
22# define SW_RFKILL_ALL 0x03
23#endif
24#ifndef KEY_POWER
25# define KEY_POWER 116 /* SC System Power Down */
26#endif
27#ifndef KEY_SLEEP
28# define KEY_SLEEP 142 /* SC System Sleep */
29#endif
30 12
13enum {
14 OPT_c = (1 << 0),
15 OPT_d = (1 << 1),
16 OPT_e = (1 << 2),
17 OPT_f = (1 << 3),
18 OPT_l = (1 << 4),
19 OPT_p = (1 << 5) * ENABLE_FEATURE_PIDFILE,
20 OPT_a = (1 << 6),
21 OPT_M = (1 << 7),
22};
23
24struct acpi_event {
25 const char *s_type;
26 uint16_t n_type;
27 const char *s_code;
28 uint16_t n_code;
29 uint32_t value;
30 const char *desc;
31};
32
33static const struct acpi_event f_evt_tab[] = {
34 { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRF 00000080" },
35 { "EV_KEY", 0x01, "KEY_POWER", 116, 1, "button/power PWRB 00000080" },
36};
37
38struct acpi_action {
39 const char *key;
40 const char *action;
41};
42
43static const struct acpi_action f_act_tab[] = {
44 { "PWRF", "PWRF/00000080" },
45 { "LID0", "LID/00000080" },
46};
47
48struct globals {
49 struct acpi_action *act_tab;
50 int n_act;
51 struct acpi_event *evt_tab;
52 int n_evt;
53} FIX_ALIASING;
54#define G (*ptr_to_globals)
55#define act_tab (G.act_tab)
56#define n_act (G.n_act )
57#define evt_tab (G.evt_tab)
58#define n_evt (G.n_evt )
59#define INIT_G() do { \
60 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
61} while (0)
31 62
32/* 63/*
33 * acpid listens to ACPI events coming either in textual form 64 * acpid listens to ACPI events coming either in textual form
@@ -48,7 +79,7 @@ static void process_event(const char *event)
48 const char *args[] = { "run-parts", handler, NULL }; 79 const char *args[] = { "run-parts", handler, NULL };
49 80
50 // debug info 81 // debug info
51 if (option_mask32 & 8) { // -d 82 if (option_mask32 & OPT_d) {
52 bb_error_msg("%s", event); 83 bb_error_msg("%s", event);
53 } 84 }
54 85
@@ -60,125 +91,204 @@ static void process_event(const char *event)
60 spawn((char **)args + (0==(st.st_mode & S_IFDIR))); 91 spawn((char **)args + (0==(st.st_mode & S_IFDIR)));
61 else 92 else
62 bb_simple_perror_msg(event); 93 bb_simple_perror_msg(event);
94
63 free(handler); 95 free(handler);
64} 96}
65 97
98static const char *find_action(struct input_event *ev, const char *buf)
99{
100 const char *action = NULL;
101 int i;
102
103 // map event
104 for (i = 0; i < n_evt; i++) {
105 if (ev) {
106 if (ev->type == evt_tab[i].n_type && ev->code == evt_tab[i].n_code && ev->value == evt_tab[i].value) {
107 action = evt_tab[i].desc;
108 break;
109 }
110 }
111
112 if (buf) {
113 if (strncmp(buf, evt_tab[i].desc, strlen(buf)) == 0) {
114 action = evt_tab[i].desc;
115 break;
116 }
117 }
118 }
119
120 // get action
121 if (action) {
122 for (i = 0; i < n_act; i++) {
123 if (strstr(action, act_tab[i].key)) {
124 action = act_tab[i].action;
125 break;
126 }
127 }
128 }
129
130 return action;
131}
132
133static void parse_conf_file(const char *filename)
134{
135 parser_t *parser;
136 char *tokens[2];
137
138 parser = config_open2(filename, fopen_for_read);
139
140 if (parser) {
141 while (config_read(parser, tokens, 2, 2, "# \t", PARSE_NORMAL)) {
142 act_tab = xrealloc_vector(act_tab, 1, n_act);
143 act_tab[n_act].key = xstrdup(tokens[0]);
144 act_tab[n_act].action = xstrdup(tokens[1]);
145 n_act++;
146 }
147 config_close(parser);
148 } else {
149 act_tab = (void*)f_act_tab;
150 n_act = ARRAY_SIZE(f_act_tab);
151 }
152}
153
154static void parse_map_file(const char *filename)
155{
156 parser_t *parser;
157 char *tokens[6];
158
159 parser = config_open2(filename, fopen_for_read);
160
161 if (parser) {
162 while (config_read(parser, tokens, 6, 6, "# \t", PARSE_NORMAL)) {
163 evt_tab = xrealloc_vector(evt_tab, 1, n_evt);
164 evt_tab[n_evt].s_type = xstrdup(tokens[0]);
165 evt_tab[n_evt].n_type = xstrtou(tokens[1], 16);
166 evt_tab[n_evt].s_code = xstrdup(tokens[2]);
167 evt_tab[n_evt].n_code = xatou16(tokens[3]);
168 evt_tab[n_evt].value = xatoi_positive(tokens[4]);
169 evt_tab[n_evt].desc = xstrdup(tokens[5]);
170 n_evt++;
171 }
172 config_close(parser);
173 } else {
174 evt_tab = (void*)f_evt_tab;
175 n_evt = ARRAY_SIZE(f_evt_tab);
176 }
177}
178
66/* 179/*
67 * acpid [-c conf_dir] [-l log_file] [-e proc_event_file] [evdev_event_file...] 180 * acpid [-c conf_dir] [-r conf_file ] [-a map_file ] [-l log_file] [-e proc_event_file]
68*/ 181 */
69 182
70int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 183int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
71int acpid_main(int argc, char **argv) 184int acpid_main(int argc UNUSED_PARAM, char **argv)
72{ 185{
186 struct input_event ev;
187 int nfd;
188 int opts;
73 struct pollfd *pfd; 189 struct pollfd *pfd;
74 int i, nfd; 190 const char *opt_dir = "/etc/acpi";
75 const char *opt_conf = "/etc/acpi"; 191 const char *opt_input = "/dev/input/event";
76 const char *opt_input = "/proc/acpi/event";
77 const char *opt_logfile = "/var/log/acpid.log"; 192 const char *opt_logfile = "/var/log/acpid.log";
193 const char *opt_action = "/etc/acpid.conf";
194 const char *opt_map = "/etc/acpi.map";
195#if ENABLE_FEATURE_PIDFILE
196 const char *opt_pidfile = "/var/run/acpid.pid";
197#endif
198
199 INIT_G();
78 200
79 getopt32(argv, "c:e:l:d" 201 opt_complementary = "df:e--e";
80 IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"), 202 opts = getopt32(argv, "c:de:fl:p:a:M:" IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
81 &opt_conf, &opt_input, &opt_logfile 203 &opt_dir, &opt_input, &opt_logfile, &opt_pidfile, &opt_action, &opt_map
82 IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL, NULL) 204 IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL)
83 ); 205 );
84 206
85 // daemonize unless -d given 207 if (!(opts & OPT_f)) {
86 if (!(option_mask32 & 8)) { // ! -d 208 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
87 bb_daemonize_or_rexec(0, argv);
88 close(2);
89 xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC);
90 } 209 }
91 210
92 argv += optind; 211 if (!(opts & OPT_d)) {
93 argc -= optind; 212 openlog(applet_name, LOG_PID, LOG_DAEMON);
213 logmode = LOGMODE_SYSLOG | LOGMODE_STDIO;
214 } else {
215 xmove_fd(xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
216 }
94 217
95 // goto configuration directory 218 parse_conf_file(opt_action);
96 xchdir(opt_conf); 219 parse_map_file(opt_map);
97 220
98 // prevent zombies 221 xchdir(opt_dir);
99 signal(SIGCHLD, SIG_IGN);
100 222
101 // no explicit evdev files given? -> use proc event interface 223 bb_signals((1 << SIGCHLD), SIG_IGN);
102 if (!*argv) { 224 bb_signals(BB_FATAL_SIGS, record_signo);
103 // proc_event file is just a "config" :)
104 char *token[4];
105 parser_t *parser = config_open(opt_input);
106 225
107 // dispatch events 226 pfd = NULL;
108 while (config_read(parser, token, 4, 4, "\0 ", PARSE_NORMAL)) { 227 nfd = 0;
109 char *event = xasprintf("%s/%s", token[1], token[2]); 228 while (1) {
110 process_event(event); 229 int fd;
111 free(event); 230 char *dev_event;
112 }
113 231
114 if (ENABLE_FEATURE_CLEAN_UP) 232 dev_event = xasprintf((option_mask32 & OPT_e) ? "%s" : "%s%u", opt_input, nfd);
115 config_close(parser); 233 fd = open(dev_event, O_RDONLY | O_NONBLOCK);
116 return EXIT_SUCCESS; 234 if (fd < 0) {
235 if (nfd == 0)
236 bb_simple_perror_msg_and_die(dev_event);
237 break;
238 }
239 pfd = xrealloc_vector(pfd, 1, nfd);
240 pfd[nfd].fd = fd;
241 pfd[nfd].events = POLLIN;
242 nfd++;
117 } 243 }
118 244
119 // evdev files given, use evdev interface 245 write_pidfile(opt_pidfile);
120
121 // open event devices
122 pfd = xzalloc(sizeof(*pfd) * argc);
123 nfd = 0;
124 while (*argv) {
125 pfd[nfd].fd = open_or_warn(*argv++, O_RDONLY | O_NONBLOCK);
126 if (pfd[nfd].fd >= 0)
127 pfd[nfd++].events = POLLIN;
128 }
129 246
130 // dispatch events 247 while (poll(pfd, nfd, -1) > 0) {
131 while (/* !bb_got_signal && */ poll(pfd, nfd, -1) > 0) { 248 int i;
132 for (i = 0; i < nfd; i++) { 249 for (i = 0; i < nfd; i++) {
133 const char *event; 250 const char *event = NULL;
134 struct input_event ev;
135 251
136 if (!(pfd[i].revents & POLLIN)) 252 memset(&ev, 0, sizeof(ev));
137 continue;
138 253
139 if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev))) 254 if (!(pfd[i].revents & POLLIN))
140 continue;
141//bb_info_msg("%d: %d %d %4d", i, ev.type, ev.code, ev.value);
142
143 // filter out unneeded events
144 if (ev.value != 1)
145 continue; 255 continue;
146 256
147 event = NULL; 257 if (option_mask32 & OPT_e) {
258 char *buf;
259 int len;
148 260
149 // N.B. we will conform to /proc/acpi/event 261 buf = xmalloc_reads(pfd[i].fd, NULL, NULL);
150 // naming convention when assigning event names 262 /* buf = "button/power PWRB 00000080 00000000" */
263 len = strlen(buf) - 9;
264 if (len >= 0)
265 buf[len] = '\0';
266 event = find_action(NULL, buf);
267 } else {
268 if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev)))
269 continue;
151 270
152 // TODO: do we want other events? 271 if (ev.value != 1 && ev.value != 0)
272 continue;
153 273
154 // power and sleep buttons delivered as keys pressed 274 event = find_action(&ev, NULL);
155 if (EV_KEY == ev.type) {
156 if (KEY_POWER == ev.code)
157 event = "PWRF/00000080";
158 else if (KEY_SLEEP == ev.code)
159 event = "SLPB/00000080";
160 }
161 // switches
162 else if (EV_SW == ev.type) {
163 if (SW_LID == ev.code)
164 event = "LID/00000080";
165 else if (SW_RFKILL_ALL == ev.code)
166 event = "RFKILL";
167 } 275 }
168 // filter out unneeded events
169 if (!event) 276 if (!event)
170 continue; 277 continue;
171
172 // spawn event handler 278 // spawn event handler
173 process_event(event); 279 process_event(event);
174 } 280 }
175 } 281 }
176 282
177 if (ENABLE_FEATURE_CLEAN_UP) { 283 if (ENABLE_FEATURE_CLEAN_UP) {
178 for (i = 0; i < nfd; i++) 284 while (nfd--) {
179 close(pfd[i].fd); 285 if (pfd[nfd].fd) {
286 close(pfd[nfd].fd);
287 }
288 }
180 free(pfd); 289 free(pfd);
181 } 290 }
291 remove_pidfile(opt_pidfile);
182 292
183 return EXIT_SUCCESS; 293 return EXIT_SUCCESS;
184} 294}