aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2014-01-02 10:25:11 +0000
committerRon Yorston <rmy@pobox.com>2014-01-02 10:25:11 +0000
commitb8f278ee745778806118f57fb7884d205eba05ad (patch)
treefef237f6dd302c59918cf389a60c120e58d3e086
parent3fd34651ea72ea1c335d3170f234cb0517fd897f (diff)
parent57434022cefde87133b8ad39fb3b79c1274e7684 (diff)
downloadbusybox-w32-b8f278ee745778806118f57fb7884d205eba05ad.tar.gz
busybox-w32-b8f278ee745778806118f57fb7884d205eba05ad.tar.bz2
busybox-w32-b8f278ee745778806118f57fb7884d205eba05ad.zip
Merge branch 'busybox' into merge
Conflicts: archival/Config.src shell/ash.c
-rw-r--r--Makefile2
-rw-r--r--Makefile.custom4
-rw-r--r--TODO5
-rw-r--r--applets/applet_tables.c10
-rwxr-xr-xapplets/usage_compressed12
-rw-r--r--archival/Config.src351
-rw-r--r--archival/Kbuild.src19
-rw-r--r--archival/ar.c43
-rw-r--r--archival/bbunzip.c96
-rw-r--r--archival/bzip2.c16
-rw-r--r--archival/cpio.c33
-rw-r--r--archival/dpkg.c16
-rw-r--r--archival/dpkg_deb.c27
-rw-r--r--archival/gzip.c31
-rw-r--r--archival/libarchive/bz/compress.c16
-rw-r--r--archival/libarchive/decompress_bunzip2.c27
-rw-r--r--archival/libarchive/decompress_gunzip.c2
-rw-r--r--archival/libarchive/get_header_ar.c35
-rw-r--r--archival/libarchive/get_header_tar.c14
-rw-r--r--archival/libarchive/lzo1x_9x.c3
-rw-r--r--archival/libarchive/open_transformer.c5
-rw-r--r--archival/lzop.c20
-rw-r--r--archival/rpm.c9
-rw-r--r--archival/rpm2cpio.c9
-rw-r--r--archival/tar.c117
-rw-r--r--archival/unzip.c19
-rw-r--r--console-tools/dumpkmap.c37
-rw-r--r--console-tools/loadkmap.c27
-rw-r--r--coreutils/cal.c2
-rw-r--r--coreutils/expand.c13
-rw-r--r--coreutils/sum.c4
-rw-r--r--coreutils/tail.c5
-rw-r--r--coreutils/touch.c39
-rw-r--r--debianutils/run_parts.c2
-rw-r--r--docs/keep_data_small.txt15
-rw-r--r--docs/tcp.txt21
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/blkidP.h4
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/cache.c2
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/dev.c4
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/read.c2
-rw-r--r--e2fsprogs/old_e2fsprogs/blkid/tag.c6
-rw-r--r--e2fsprogs/old_e2fsprogs/e2fsck.c10
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/initialize.c2
-rw-r--r--e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c4
-rw-r--r--e2fsprogs/old_e2fsprogs/fsck.c1
-rw-r--r--e2fsprogs/old_e2fsprogs/mke2fs.c8
-rw-r--r--e2fsprogs/old_e2fsprogs/tune2fs.c2
-rw-r--r--e2fsprogs/old_e2fsprogs/util.c4
-rw-r--r--editors/Config.src60
-rw-r--r--editors/Kbuild.src5
-rw-r--r--editors/awk.c125
-rw-r--r--editors/cmp.c11
-rw-r--r--editors/diff.c27
-rw-r--r--editors/ed.c12
-rw-r--r--editors/patch_bbox.c4
-rw-r--r--editors/sed.c256
-rw-r--r--include/applets.src.h30
-rw-r--r--include/libbb.h28
-rw-r--r--include/platform.h2
-rw-r--r--init/bootchartd.c6
-rw-r--r--init/init.c32
-rw-r--r--libbb/Kbuild.src2
-rw-r--r--libbb/bb_pwd.c48
-rw-r--r--libbb/correct_password.c23
-rw-r--r--libbb/fclose_nonstdin.c3
-rw-r--r--libbb/human_readable.c6
-rw-r--r--libbb/in_ether.c1
-rw-r--r--libbb/inet_common.c3
-rw-r--r--libbb/nuke_str.c21
-rw-r--r--libbb/pw_encrypt_md5.c2
-rw-r--r--libbb/xfuncs_printf.c45
-rw-r--r--libbb/xreadlink.c6
-rw-r--r--loginutils/adduser.c4
-rw-r--r--loginutils/login.c2
-rw-r--r--loginutils/passwd.c5
-rw-r--r--loginutils/su.c2
-rw-r--r--loginutils/sulogin.c43
-rw-r--r--loginutils/vlock.c2
-rw-r--r--miscutils/Config.src19
-rw-r--r--miscutils/Kbuild.src2
-rw-r--r--miscutils/chat.c2
-rw-r--r--miscutils/crontab.c27
-rw-r--r--miscutils/devfsd.c20
-rw-r--r--miscutils/hdparm.c8
-rw-r--r--miscutils/rfkill.c17
-rw-r--r--miscutils/wall.c21
-rw-r--r--networking/Config.src16
-rw-r--r--networking/arp.c4
-rw-r--r--networking/ether-wake.c19
-rw-r--r--networking/hostname.c7
-rw-r--r--networking/httpd.c39
-rw-r--r--networking/netstat.c8
-rw-r--r--networking/ntpd.c173
-rw-r--r--networking/ping.c21
-rw-r--r--networking/pscan.c2
-rw-r--r--networking/tc.c3
-rw-r--r--networking/traceroute.c4
-rw-r--r--networking/udhcp/common.c2
-rw-r--r--networking/udhcp/common.h5
-rw-r--r--networking/udhcp/dhcpc.c36
-rw-r--r--networking/udhcp/packet.c9
-rw-r--r--networking/wget.c49
-rw-r--r--procps/kill.c43
-rw-r--r--procps/nmeter.c3
-rw-r--r--procps/pgrep.c4
-rw-r--r--procps/powertop.c3
-rw-r--r--procps/ps.c9
-rw-r--r--procps/top.c5
-rw-r--r--runit/chpst.c5
-rw-r--r--runit/runsv.c1
-rw-r--r--runit/runsvdir.c1
-rw-r--r--runit/sv.c1
-rw-r--r--runit/svlogd.c1
-rwxr-xr-xscripts/bloat-o-meter11
-rw-r--r--scripts/kconfig/Makefile2
-rwxr-xr-xscripts/mkconfigs4
-rwxr-xr-xscripts/randomtest2
-rwxr-xr-xscripts/trylink6
-rw-r--r--shell/ash.c18
-rw-r--r--shell/hush.c4
-rw-r--r--sysklogd/logread.c16
-rwxr-xr-xtestsuite/awk.tests21
-rw-r--r--testsuite/date/date-works8
-rw-r--r--testsuite/date/date-works-16
-rw-r--r--testsuite/du/du-k-works2
-rw-r--r--testsuite/du/du-l-works1
-rw-r--r--testsuite/hostid/hostid-works10
-rwxr-xr-xtestsuite/md5sum.tests6
-rwxr-xr-xtestsuite/sed.tests2
-rwxr-xr-xtestsuite/tar.tests38
-rw-r--r--testsuite/testing.sh8
-rw-r--r--testsuite/which/which-uses-default-path2
-rw-r--r--util-linux/fdformat.c2
-rw-r--r--util-linux/fdisk_gpt.c6
-rw-r--r--util-linux/fsck_minix.c2
-rw-r--r--util-linux/fstrim.c119
-rw-r--r--util-linux/ipcs.c10
-rw-r--r--util-linux/mkfs_minix.c2
-rw-r--r--util-linux/readprofile.c12
-rw-r--r--util-linux/swaponoff.c4
-rw-r--r--util-linux/volume_id/unused_msdos.c2
141 files changed, 1724 insertions, 1162 deletions
diff --git a/Makefile b/Makefile
index cecf6c02d..6029f427f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
1VERSION = 1 1VERSION = 1
2PATCHLEVEL = 22 2PATCHLEVEL = 23
3SUBLEVEL = 0 3SUBLEVEL = 0
4EXTRAVERSION = .git 4EXTRAVERSION = .git
5NAME = Unnamed 5NAME = Unnamed
diff --git a/Makefile.custom b/Makefile.custom
index 3561e5768..8c95ef2d4 100644
--- a/Makefile.custom
+++ b/Makefile.custom
@@ -74,6 +74,10 @@ release: distclean
74 -print \ 74 -print \
75 -exec rm -r -f {} \; ; \ 75 -exec rm -r -f {} \; ; \
76 find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type f \ 76 find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type f \
77 -name .gitignore \
78 -print \
79 -exec rm -f {} \; ; \
80 find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type f \
77 -name .\#* \ 81 -name .\#* \
78 -print \ 82 -print \
79 -exec rm -f {} \; ; \ 83 -exec rm -f {} \; ; \
diff --git a/TODO b/TODO
index d2a085ede..dcf48c2c2 100644
--- a/TODO
+++ b/TODO
@@ -127,11 +127,6 @@ patch
127 127
128 And while we're at it, a new patch filename quoting format is apparently 128 And while we're at it, a new patch filename quoting format is apparently
129 coming soon: http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2 129 coming soon: http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
130---
131tail
132 ./busybox tail -f foo.c~ TODO
133 should not print fmt=header_fmt for subsequent date >> TODO; i.e. only
134 fmt+ if another (not the current) file did change
135 130
136Architectural issues: 131Architectural issues:
137 132
diff --git a/applets/applet_tables.c b/applets/applet_tables.c
index 152d5f441..94b974e09 100644
--- a/applets/applet_tables.c
+++ b/applets/applet_tables.c
@@ -53,7 +53,7 @@ int main(int argc, char **argv)
53{ 53{
54 int i; 54 int i;
55 int ofs; 55 int ofs;
56 unsigned MAX_APPLET_NAME_LEN = 1; 56// unsigned MAX_APPLET_NAME_LEN = 1;
57 57
58 qsort(applets, NUM_APPLETS, sizeof(applets[0]), cmp_name); 58 qsort(applets, NUM_APPLETS, sizeof(applets[0]), cmp_name);
59 59
@@ -89,8 +89,8 @@ int main(int argc, char **argv)
89 printf("const char applet_names[] ALIGN1 = \"\"\n"); 89 printf("const char applet_names[] ALIGN1 = \"\"\n");
90 for (i = 0; i < NUM_APPLETS; i++) { 90 for (i = 0; i < NUM_APPLETS; i++) {
91 printf("\"%s\" \"\\0\"\n", applets[i].name); 91 printf("\"%s\" \"\\0\"\n", applets[i].name);
92 if (MAX_APPLET_NAME_LEN < strlen(applets[i].name)) 92// if (MAX_APPLET_NAME_LEN < strlen(applets[i].name))
93 MAX_APPLET_NAME_LEN = strlen(applets[i].name); 93// MAX_APPLET_NAME_LEN = strlen(applets[i].name);
94 } 94 }
95 printf(";\n\n"); 95 printf(";\n\n");
96 96
@@ -130,8 +130,8 @@ int main(int argc, char **argv)
130 printf("};\n"); 130 printf("};\n");
131#endif 131#endif
132 //printf("#endif /* SKIP_definitions */\n"); 132 //printf("#endif /* SKIP_definitions */\n");
133 printf("\n"); 133// printf("\n");
134 printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN); 134// printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN);
135 135
136 if (argv[2]) { 136 if (argv[2]) {
137 char line_old[80]; 137 char line_old[80];
diff --git a/applets/usage_compressed b/applets/usage_compressed
index af66bc5dc..fb6e1c286 100755
--- a/applets/usage_compressed
+++ b/applets/usage_compressed
@@ -10,20 +10,20 @@ test "$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 12# Some people were bitten by their system lacking a (proper) od
13od -v -t x1 </dev/null >/dev/null 13od -v -b </dev/null >/dev/null
14if test $? != 0; then 14if test $? != 0; then
15 echo 'od tool is not installed or cannot accept "-v -t x1" options' 15 echo 'od tool is not installed or cannot accept "-v -b" options'
16 exit 1 16 exit 1
17fi 17fi
18 18
19exec >"$target.$$" 19exec >"$target.$$"
20 20
21echo '#define UNPACKED_USAGE "" \' 21echo '#define UNPACKED_USAGE "" \'
22"$loc/usage" | od -v -t x1 \ 22"$loc/usage" | od -v -b \
23| $SED -e 's/^[^ ]*//' \ 23| $SED -e 's/^[^ ]*//' \
24 -e 's/ //g' \ 24 -e 's/ //g' \
25 -e '/^$/d' \ 25 -e '/^$/d' \
26 -e 's/\(..\)/\\x\1/g' \ 26 -e 's/\(...\)/\\\1/g' \
27 -e 's/^/"/' \ 27 -e 's/^/"/' \
28 -e 's/$/" \\/' 28 -e 's/$/" \\/'
29echo '' 29echo ''
@@ -39,11 +39,11 @@ echo '#define PACKED_USAGE \'
39## -e '/^$/d' \ 39## -e '/^$/d' \
40## -e 's/\(..\)\(..\)/0x\2,0x\1,/g' 40## -e 's/\(..\)\(..\)/0x\2,0x\1,/g'
41## -e 's/$/ \\/' 41## -e 's/$/ \\/'
42"$loc/usage" | bzip2 -1 | $DD bs=2 skip=1 2>/dev/null | od -v -t x1 \ 42"$loc/usage" | bzip2 -1 | $DD bs=2 skip=1 2>/dev/null | od -v -b \
43| $SED -e 's/^[^ ]*//' \ 43| $SED -e 's/^[^ ]*//' \
44 -e 's/ //g' \ 44 -e 's/ //g' \
45 -e '/^$/d' \ 45 -e '/^$/d' \
46 -e 's/\(..\)/0x\1,/g' \ 46 -e 's/\(...\)/0\1,/g' \
47 -e 's/$/ \\/' 47 -e 's/$/ \\/'
48echo '' 48echo ''
49 49
diff --git a/archival/Config.src b/archival/Config.src
index 13c33c795..76635ba78 100644
--- a/archival/Config.src
+++ b/archival/Config.src
@@ -5,8 +5,6 @@
5 5
6menu "Archival Utilities" 6menu "Archival Utilities"
7 7
8INSERT
9
10config FEATURE_SEAMLESS_XZ 8config FEATURE_SEAMLESS_XZ
11 bool "Make tar, rpm, modprobe etc understand .xz data" 9 bool "Make tar, rpm, modprobe etc understand .xz data"
12 default y 10 default y
@@ -37,353 +35,6 @@ config FEATURE_SEAMLESS_Z
37 help 35 help
38 Make tar, rpm, modprobe etc understand .Z data. 36 Make tar, rpm, modprobe etc understand .Z data.
39 37
40config AR 38INSERT
41 bool "ar"
42 default n # needs to be improved to be able to replace binutils ar
43 help
44 ar is an archival utility program used to create, modify, and
45 extract contents from archives. An archive is a single file holding
46 a collection of other files in a structure that makes it possible to
47 retrieve the original individual files (called archive members).
48 The original files' contents, mode (permissions), timestamp, owner,
49 and group are preserved in the archive, and can be restored on
50 extraction.
51
52 The stored filename is limited to 15 characters. (for more information
53 see long filename support).
54 ar has 60 bytes of overheads for every stored file.
55
56 This implementation of ar can extract archives, it cannot create or
57 modify them.
58 On an x86 system, the ar applet adds about 1K.
59
60 Unless you have a specific application which requires ar, you should
61 probably say N here.
62
63config FEATURE_AR_LONG_FILENAMES
64 bool "Support for long filenames (not needed for debs)"
65 default y
66 depends on AR
67 help
68 By default the ar format can only store the first 15 characters
69 of the filename, this option removes that limitation.
70 It supports the GNU ar long filename method which moves multiple long
71 filenames into a the data section of a new ar entry.
72
73config FEATURE_AR_CREATE
74 bool "Support archive creation"
75 default y
76 depends on AR
77 help
78 This enables archive creation (-c and -r) with busybox ar.
79
80config BUNZIP2
81 bool "bunzip2"
82 default y
83 help
84 bunzip2 is a compression utility using the Burrows-Wheeler block
85 sorting text compression algorithm, and Huffman coding. Compression
86 is generally considerably better than that achieved by more
87 conventional LZ77/LZ78-based compressors, and approaches the
88 performance of the PPM family of statistical compressors.
89
90 Unless you have a specific application which requires bunzip2, you
91 should probably say N here.
92
93config BZIP2
94 bool "bzip2"
95 default y
96 help
97 bzip2 is a compression utility using the Burrows-Wheeler block
98 sorting text compression algorithm, and Huffman coding. Compression
99 is generally considerably better than that achieved by more
100 conventional LZ77/LZ78-based compressors, and approaches the
101 performance of the PPM family of statistical compressors.
102
103 Unless you have a specific application which requires bzip2, you
104 should probably say N here.
105
106config CPIO
107 bool "cpio"
108 default y
109 help
110 cpio is an archival utility program used to create, modify, and
111 extract contents from archives.
112 cpio has 110 bytes of overheads for every stored file.
113
114 This implementation of cpio can extract cpio archives created in the
115 "newc" or "crc" format, it cannot create or modify them.
116
117 Unless you have a specific application which requires cpio, you
118 should probably say N here.
119
120config FEATURE_CPIO_O
121 bool "Support for archive creation"
122 default y
123 depends on CPIO
124 help
125 This implementation of cpio can create cpio archives in the "newc"
126 format only.
127
128config FEATURE_CPIO_P
129 bool "Support for passthrough mode"
130 default y
131 depends on FEATURE_CPIO_O
132 help
133 Passthrough mode. Rarely used.
134
135config DPKG
136 bool "dpkg"
137 default n
138 select FEATURE_SEAMLESS_GZ
139 help
140 dpkg is a medium-level tool to install, build, remove and manage
141 Debian packages.
142
143 This implementation of dpkg has a number of limitations,
144 you should use the official dpkg if possible.
145
146config DPKG_DEB
147 bool "dpkg_deb"
148 default n
149 select FEATURE_SEAMLESS_GZ
150 help
151 dpkg-deb unpacks and provides information about Debian archives.
152
153 This implementation of dpkg-deb cannot pack archives.
154
155 Unless you have a specific application which requires dpkg-deb,
156 say N here.
157
158config FEATURE_DPKG_DEB_EXTRACT_ONLY
159 bool "Extract only (-x)"
160 default n
161 depends on DPKG_DEB
162 help
163 This reduces dpkg-deb to the equivalent of
164 "ar -p <deb> data.tar.gz | tar -zx". However it saves space as none
165 of the extra dpkg-deb, ar or tar options are needed, they are linked
166 to internally.
167
168config GUNZIP
169 bool "gunzip"
170 default y
171 help
172 gunzip is used to decompress archives created by gzip.
173 You can use the `-t' option to test the integrity of
174 an archive, without decompressing it.
175
176config GZIP
177 bool "gzip"
178 default y
179 help
180 gzip is used to compress files.
181 It's probably the most widely used UNIX compression program.
182
183config FEATURE_GZIP_LONG_OPTIONS
184 bool "Enable long options"
185 default y
186 depends on GZIP && LONG_OPTS
187 help
188 Enable use of long options, increases size by about 106 Bytes
189
190config GZIP_FAST
191 int "Trade memory for gzip speed (0:small,slow - 2:fast,big)"
192 default 0
193 range 0 2
194 depends on GZIP
195 help
196 Enable big memory options for gzip.
197 0: small buffers, small hash-tables
198 1: larger buffers, larger hash-tables
199 2: larger buffers, largest hash-tables
200 Larger models may give slightly better compression
201
202config LZOP
203 bool "lzop"
204 default y
205 depends on PLATFORM_POSIX || WIN32_NET
206 help
207 Lzop compression/decompresion.
208
209config LZOP_COMPR_HIGH
210 bool "lzop compression levels 7,8,9 (not very useful)"
211 default n
212 depends on LZOP
213 help
214 High levels (7,8,9) of lzop compression. These levels
215 are actually slower than gzip at equivalent compression ratios
216 and take up 3.2K of code.
217
218config RPM2CPIO
219 bool "rpm2cpio"
220 default y
221 help
222 Converts a RPM file into a CPIO archive.
223
224config RPM
225 bool "rpm"
226 default y
227 help
228 Mini RPM applet - queries and extracts RPM packages.
229
230config TAR
231 bool "tar"
232 default y
233 help
234 tar is an archiving program. It's commonly used with gzip to
235 create compressed archives. It's probably the most widely used
236 UNIX archive program.
237
238config FEATURE_TAR_CREATE
239 bool "Enable archive creation"
240 default y
241 depends on TAR
242 help
243 If you enable this option you'll be able to create
244 tar archives using the `-c' option.
245
246config FEATURE_TAR_AUTODETECT
247 bool "Autodetect compressed tarballs"
248 default y
249 depends on TAR && (FEATURE_SEAMLESS_Z || FEATURE_SEAMLESS_GZ || FEATURE_SEAMLESS_BZ2 || FEATURE_SEAMLESS_LZMA || FEATURE_SEAMLESS_XZ)
250 help
251 With this option tar can automatically detect compressed
252 tarballs. Currently it works only on files (not pipes etc).
253
254config FEATURE_TAR_FROM
255 bool "Enable -X (exclude from) and -T (include from) options)"
256 default y
257 depends on TAR
258 help
259 If you enable this option you'll be able to specify
260 a list of files to include or exclude from an archive.
261
262config FEATURE_TAR_OLDGNU_COMPATIBILITY
263 bool "Support for old tar header format"
264 default y
265 depends on TAR || DPKG
266 help
267 This option is required to unpack archives created in
268 the old GNU format; help to kill this old format by
269 repacking your ancient archives with the new format.
270
271config FEATURE_TAR_OLDSUN_COMPATIBILITY
272 bool "Enable untarring of tarballs with checksums produced by buggy Sun tar"
273 default y
274 depends on TAR || DPKG
275 help
276 This option is required to unpack archives created by some old
277 version of Sun's tar (it was calculating checksum using signed
278 arithmetic). It is said to be fixed in newer Sun tar, but "old"
279 tarballs still exist.
280
281config FEATURE_TAR_GNU_EXTENSIONS
282 bool "Support for GNU tar extensions (long filenames)"
283 default y
284 depends on TAR || DPKG
285 help
286 With this option busybox supports GNU long filenames and
287 linknames.
288
289config FEATURE_TAR_LONG_OPTIONS
290 bool "Enable long options"
291 default y
292 depends on TAR && LONG_OPTS
293 help
294 Enable use of long options, increases size by about 400 Bytes
295
296config FEATURE_TAR_TO_COMMAND
297 bool "Support for writing to an external program"
298 default y
299 depends on TAR && FEATURE_TAR_LONG_OPTIONS
300 help
301 If you enable this option you'll be able to instruct tar to send
302 the contents of each extracted file to the standard input of an
303 external program.
304
305config FEATURE_TAR_UNAME_GNAME
306 bool "Enable use of user and group names"
307 default y
308 depends on TAR
309 help
310 Enables use of user and group names in tar. This affects contents
311 listings (-t) and preserving permissions when unpacking (-p).
312 +200 bytes.
313
314config FEATURE_TAR_NOPRESERVE_TIME
315 bool "Enable -m (do not preserve time) option"
316 default y
317 depends on TAR
318 help
319 With this option busybox supports GNU tar -m
320 (do not preserve time) option.
321
322config FEATURE_TAR_SELINUX
323 bool "Support for extracting SELinux labels"
324 default n
325 depends on TAR && SELINUX
326 help
327 With this option busybox supports restoring SELinux labels
328 when extracting files from tar archives.
329
330config UNCOMPRESS
331 bool "uncompress"
332 default n
333 help
334 uncompress is used to decompress archives created by compress.
335 Not much used anymore, replaced by gzip/gunzip.
336
337config UNLZMA
338 bool "unlzma"
339 default y
340 help
341 unlzma is a compression utility using the Lempel-Ziv-Markov chain
342 compression algorithm, and range coding. Compression
343 is generally considerably better than that achieved by the bzip2
344 compressors.
345
346 The BusyBox unlzma applet is limited to decompression only.
347 On an x86 system, this applet adds about 4K.
348
349config FEATURE_LZMA_FAST
350 bool "Optimize unlzma for speed"
351 default n
352 depends on UNLZMA
353 help
354 This option reduces decompression time by about 25% at the cost of
355 a 1K bigger binary.
356
357config LZMA
358 bool "Provide lzma alias which supports only unpacking"
359 default y
360 depends on UNLZMA
361 help
362 Enable this option if you want commands like "lzma -d" to work.
363 IOW: you'll get lzma applet, but it will always require -d option.
364
365config UNXZ
366 bool "unxz"
367 default y
368 help
369 unxz is a unlzma successor.
370
371config XZ
372 bool "Provide xz alias which supports only unpacking"
373 default y
374 depends on UNXZ
375 help
376 Enable this option if you want commands like "xz -d" to work.
377 IOW: you'll get xz applet, but it will always require -d option.
378
379config UNZIP
380 bool "unzip"
381 default y
382 help
383 unzip will list or extract files from a ZIP archive,
384 commonly found on DOS/WIN systems. The default behavior
385 (with no options) is to extract the archive into the
386 current directory. Use the `-d' option to extract to a
387 directory of your choice.
388 39
389endmenu 40endmenu
diff --git a/archival/Kbuild.src b/archival/Kbuild.src
index 3466452f7..a6fd2eac0 100644
--- a/archival/Kbuild.src
+++ b/archival/Kbuild.src
@@ -9,22 +9,3 @@ libs-y += libarchive/
9lib-y:= 9lib-y:=
10 10
11INSERT 11INSERT
12
13lib-$(CONFIG_AR) += ar.o
14lib-$(CONFIG_CPIO) += cpio.o
15lib-$(CONFIG_DPKG) += dpkg.o
16lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o
17lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o
18lib-$(CONFIG_RPM) += rpm.o
19lib-$(CONFIG_TAR) += tar.o
20lib-$(CONFIG_UNZIP) += unzip.o
21
22lib-$(CONFIG_LZOP) += lzop.o bbunzip.o
23lib-$(CONFIG_GZIP) += gzip.o bbunzip.o
24lib-$(CONFIG_BZIP2) += bzip2.o bbunzip.o
25
26lib-$(CONFIG_UNXZ) += bbunzip.o
27lib-$(CONFIG_UNLZMA) += bbunzip.o
28lib-$(CONFIG_BUNZIP2) += bbunzip.o
29lib-$(CONFIG_GUNZIP) += bbunzip.o
30lib-$(CONFIG_UNCOMPRESS) += bbunzip.o
diff --git a/archival/ar.c b/archival/ar.c
index 88236e878..f86c52d9b 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -17,6 +17,49 @@
17 * http://www.unix-systems.org/single_unix_specification_v2/xcu/ar.html 17 * http://www.unix-systems.org/single_unix_specification_v2/xcu/ar.html
18 */ 18 */
19 19
20//config:config AR
21//config: bool "ar"
22//config: default n # needs to be improved to be able to replace binutils ar
23//config: help
24//config: ar is an archival utility program used to create, modify, and
25//config: extract contents from archives. An archive is a single file holding
26//config: a collection of other files in a structure that makes it possible to
27//config: retrieve the original individual files (called archive members).
28//config: The original files' contents, mode (permissions), timestamp, owner,
29//config: and group are preserved in the archive, and can be restored on
30//config: extraction.
31//config:
32//config: The stored filename is limited to 15 characters. (for more information
33//config: see long filename support).
34//config: ar has 60 bytes of overheads for every stored file.
35//config:
36//config: This implementation of ar can extract archives, it cannot create or
37//config: modify them.
38//config: On an x86 system, the ar applet adds about 1K.
39//config:
40//config: Unless you have a specific application which requires ar, you should
41//config: probably say N here.
42//config:
43//config:config FEATURE_AR_LONG_FILENAMES
44//config: bool "Support for long filenames (not needed for debs)"
45//config: default y
46//config: depends on AR
47//config: help
48//config: By default the ar format can only store the first 15 characters
49//config: of the filename, this option removes that limitation.
50//config: It supports the GNU ar long filename method which moves multiple long
51//config: filenames into a the data section of a new ar entry.
52//config:
53//config:config FEATURE_AR_CREATE
54//config: bool "Support archive creation"
55//config: default y
56//config: depends on AR
57//config: help
58//config: This enables archive creation (-c and -r) with busybox ar.
59
60//applet:IF_AR(APPLET(ar, BB_DIR_USR_BIN, BB_SUID_DROP))
61//kbuild:lib-$(CONFIG_AR) += ar.o
62
20//usage:#define ar_trivial_usage 63//usage:#define ar_trivial_usage
21//usage: "[-o] [-v] [-p] [-t] [-x] ARCHIVE FILES" 64//usage: "[-o] [-v] [-p] [-t] [-x] ARCHIVE FILES"
22//usage:#define ar_full_usage "\n\n" 65//usage:#define ar_full_usage "\n\n"
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index 9d1cd9485..3de8e1d48 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -7,6 +7,9 @@
7#include "libbb.h" 7#include "libbb.h"
8#include "bb_archive.h" 8#include "bb_archive.h"
9 9
10/* lzop_main() uses bbunpack(), need this: */
11//kbuild:lib-$(CONFIG_LZOP) += bbunzip.o
12
10/* Note: must be kept in sync with archival/lzop.c */ 13/* Note: must be kept in sync with archival/lzop.c */
11enum { 14enum {
12 OPT_STDOUT = 1 << 0, 15 OPT_STDOUT = 1 << 0,
@@ -207,7 +210,6 @@ char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext)
207 * 210 *
208 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 211 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
209 */ 212 */
210
211//usage:#define uncompress_trivial_usage 213//usage:#define uncompress_trivial_usage
212//usage: "[-cf] [FILE]..." 214//usage: "[-cf] [FILE]..."
213//usage:#define uncompress_full_usage "\n\n" 215//usage:#define uncompress_full_usage "\n\n"
@@ -215,6 +217,15 @@ char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext)
215//usage: "\n -c Write to stdout" 217//usage: "\n -c Write to stdout"
216//usage: "\n -f Overwrite" 218//usage: "\n -f Overwrite"
217 219
220//config:config UNCOMPRESS
221//config: bool "uncompress"
222//config: default n
223//config: help
224//config: uncompress is used to decompress archives created by compress.
225//config: Not much used anymore, replaced by gzip/gunzip.
226
227//applet:IF_UNCOMPRESS(APPLET(uncompress, BB_DIR_BIN, BB_SUID_DROP))
228//kbuild:lib-$(CONFIG_UNCOMPRESS) += bbunzip.o
218#if ENABLE_UNCOMPRESS 229#if ENABLE_UNCOMPRESS
219static 230static
220IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux) 231IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux)
@@ -255,11 +266,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv)
255 * Portions of the lzw code are derived from the public domain 'compress' 266 * Portions of the lzw code are derived from the public domain 'compress'
256 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, 267 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
257 * Ken Turkowski, Dave Mack and Peter Jannesen. 268 * Ken Turkowski, Dave Mack and Peter Jannesen.
258 *
259 * See the license_msg below and the file COPYING for the software license.
260 * See the file algorithm.doc for the compression algorithms and file formats.
261 */ 269 */
262
263//usage:#define gunzip_trivial_usage 270//usage:#define gunzip_trivial_usage
264//usage: "[-cft] [FILE]..." 271//usage: "[-cft] [FILE]..."
265//usage:#define gunzip_full_usage "\n\n" 272//usage:#define gunzip_full_usage "\n\n"
@@ -280,6 +287,18 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv)
280//usage:#define zcat_full_usage "\n\n" 287//usage:#define zcat_full_usage "\n\n"
281//usage: "Decompress to stdout" 288//usage: "Decompress to stdout"
282 289
290//config:config GUNZIP
291//config: bool "gunzip"
292//config: default y
293//config: help
294//config: gunzip is used to decompress archives created by gzip.
295//config: You can use the `-t' option to test the integrity of
296//config: an archive, without decompressing it.
297
298//applet:IF_GUNZIP(APPLET(gunzip, BB_DIR_BIN, BB_SUID_DROP))
299//applet:IF_GUNZIP(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat))
300//kbuild:lib-$(CONFIG_GZIP) += bbunzip.o
301//kbuild:lib-$(CONFIG_GUNZIP) += bbunzip.o
283#if ENABLE_GUNZIP 302#if ENABLE_GUNZIP
284static 303static
285char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM) 304char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM)
@@ -358,8 +377,24 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv)
358//usage: "[FILE]..." 377//usage: "[FILE]..."
359//usage:#define bzcat_full_usage "\n\n" 378//usage:#define bzcat_full_usage "\n\n"
360//usage: "Decompress to stdout" 379//usage: "Decompress to stdout"
380
381//config:config BUNZIP2
382//config: bool "bunzip2"
383//config: default y
384//config: help
385//config: bunzip2 is a compression utility using the Burrows-Wheeler block
386//config: sorting text compression algorithm, and Huffman coding. Compression
387//config: is generally considerably better than that achieved by more
388//config: conventional LZ77/LZ78-based compressors, and approaches the
389//config: performance of the PPM family of statistical compressors.
390//config:
391//config: Unless you have a specific application which requires bunzip2, you
392//config: should probably say N here.
393
361//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) 394//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
362//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat)) 395//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat))
396//kbuild:lib-$(CONFIG_BZIP2) += bbunzip.o
397//kbuild:lib-$(CONFIG_BUNZIP2) += bbunzip.o
363#if ENABLE_BUNZIP2 398#if ENABLE_BUNZIP2
364static 399static
365IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux) 400IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux)
@@ -387,7 +422,6 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
387 * 422 *
388 * Licensed under GPLv2, see file LICENSE in this source tree. 423 * Licensed under GPLv2, see file LICENSE in this source tree.
389 */ 424 */
390
391//usage:#define unlzma_trivial_usage 425//usage:#define unlzma_trivial_usage
392//usage: "[-cf] [FILE]..." 426//usage: "[-cf] [FILE]..."
393//usage:#define unlzma_full_usage "\n\n" 427//usage:#define unlzma_full_usage "\n\n"
@@ -428,6 +462,38 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv)
428//usage:#define xzcat_full_usage "\n\n" 462//usage:#define xzcat_full_usage "\n\n"
429//usage: "Decompress to stdout" 463//usage: "Decompress to stdout"
430 464
465//config:config UNLZMA
466//config: bool "unlzma"
467//config: default y
468//config: help
469//config: unlzma is a compression utility using the Lempel-Ziv-Markov chain
470//config: compression algorithm, and range coding. Compression
471//config: is generally considerably better than that achieved by the bzip2
472//config: compressors.
473//config:
474//config: The BusyBox unlzma applet is limited to decompression only.
475//config: On an x86 system, this applet adds about 4K.
476//config:
477//config:config FEATURE_LZMA_FAST
478//config: bool "Optimize unlzma for speed"
479//config: default n
480//config: depends on UNLZMA
481//config: help
482//config: This option reduces decompression time by about 25% at the cost of
483//config: a 1K bigger binary.
484//config:
485//config:config LZMA
486//config: bool "Provide lzma alias which supports only unpacking"
487//config: default y
488//config: depends on UNLZMA
489//config: help
490//config: Enable this option if you want commands like "lzma -d" to work.
491//config: IOW: you'll get lzma applet, but it will always require -d option.
492
493//applet:IF_UNLZMA(APPLET(unlzma, BB_DIR_USR_BIN, BB_SUID_DROP))
494//applet:IF_UNLZMA(APPLET_ODDNAME(lzcat, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzcat))
495//applet:IF_LZMA(APPLET_ODDNAME(lzma, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzma))
496//kbuild:lib-$(CONFIG_UNLZMA) += bbunzip.o
431#if ENABLE_UNLZMA 497#if ENABLE_UNLZMA
432static 498static
433IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux) 499IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux)
@@ -453,6 +519,24 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv)
453#endif 519#endif
454 520
455 521
522//config:config UNXZ
523//config: bool "unxz"
524//config: default y
525//config: help
526//config: unxz is a unlzma successor.
527//config:
528//config:config XZ
529//config: bool "Provide xz alias which supports only unpacking"
530//config: default y
531//config: depends on UNXZ
532//config: help
533//config: Enable this option if you want commands like "xz -d" to work.
534//config: IOW: you'll get xz applet, but it will always require -d option.
535
536//applet:IF_UNXZ(APPLET(unxz, BB_DIR_USR_BIN, BB_SUID_DROP))
537//applet:IF_UNXZ(APPLET_ODDNAME(xzcat, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xzcat))
538//applet:IF_XZ(APPLET_ODDNAME(xz, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xz))
539//kbuild:lib-$(CONFIG_UNXZ) += bbunzip.o
456#if ENABLE_UNXZ 540#if ENABLE_UNXZ
457static 541static
458IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux) 542IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux)
diff --git a/archival/bzip2.c b/archival/bzip2.c
index dd77c8efc..f7718b411 100644
--- a/archival/bzip2.c
+++ b/archival/bzip2.c
@@ -7,6 +7,22 @@
7 * about bzip2 library code. 7 * about bzip2 library code.
8 */ 8 */
9 9
10//config:config BZIP2
11//config: bool "bzip2"
12//config: default y
13//config: help
14//config: bzip2 is a compression utility using the Burrows-Wheeler block
15//config: sorting text compression algorithm, and Huffman coding. Compression
16//config: is generally considerably better than that achieved by more
17//config: conventional LZ77/LZ78-based compressors, and approaches the
18//config: performance of the PPM family of statistical compressors.
19//config:
20//config: Unless you have a specific application which requires bzip2, you
21//config: should probably say N here.
22
23//applet:IF_BZIP2(APPLET(bzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
24//kbuild:lib-$(CONFIG_BZIP2) += bzip2.o
25
10//usage:#define bzip2_trivial_usage 26//usage:#define bzip2_trivial_usage
11//usage: "[OPTIONS] [FILE]..." 27//usage: "[OPTIONS] [FILE]..."
12//usage:#define bzip2_full_usage "\n\n" 28//usage:#define bzip2_full_usage "\n\n"
diff --git a/archival/cpio.c b/archival/cpio.c
index 699c6dbb7..1cce7c8b4 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -9,11 +9,42 @@
9 * Limitations: 9 * Limitations:
10 * Doesn't check CRC's 10 * Doesn't check CRC's
11 * Only supports new ASCII and CRC formats 11 * Only supports new ASCII and CRC formats
12 *
13 */ 12 */
14#include "libbb.h" 13#include "libbb.h"
15#include "bb_archive.h" 14#include "bb_archive.h"
16 15
16//config:config CPIO
17//config: bool "cpio"
18//config: default y
19//config: help
20//config: cpio is an archival utility program used to create, modify, and
21//config: extract contents from archives.
22//config: cpio has 110 bytes of overheads for every stored file.
23//config:
24//config: This implementation of cpio can extract cpio archives created in the
25//config: "newc" or "crc" format, it cannot create or modify them.
26//config:
27//config: Unless you have a specific application which requires cpio, you
28//config: should probably say N here.
29//config:
30//config:config FEATURE_CPIO_O
31//config: bool "Support for archive creation"
32//config: default y
33//config: depends on CPIO
34//config: help
35//config: This implementation of cpio can create cpio archives in the "newc"
36//config: format only.
37//config:
38//config:config FEATURE_CPIO_P
39//config: bool "Support for passthrough mode"
40//config: default y
41//config: depends on FEATURE_CPIO_O
42//config: help
43//config: Passthrough mode. Rarely used.
44
45//applet:IF_CPIO(APPLET(cpio, BB_DIR_BIN, BB_SUID_DROP))
46//kbuild:lib-$(CONFIG_CPIO) += cpio.o
47
17//usage:#define cpio_trivial_usage 48//usage:#define cpio_trivial_usage
18//usage: "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]") 49//usage: "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]")
19//usage: " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]") 50//usage: " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]")
diff --git a/archival/dpkg.c b/archival/dpkg.c
index ed86f3355..2893cfc2d 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -14,7 +14,6 @@
14 * 14 *
15 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 15 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
16 */ 16 */
17
18/* 17/*
19 * known difference between busybox dpkg and the official dpkg that i don't 18 * known difference between busybox dpkg and the official dpkg that i don't
20 * consider important, its worth keeping a note of differences anyway, just to 19 * consider important, its worth keeping a note of differences anyway, just to
@@ -25,9 +24,22 @@
25 * 24 *
26 * bugs that need to be fixed 25 * bugs that need to be fixed
27 * - (unknown, please let me know when you find any) 26 * - (unknown, please let me know when you find any)
28 *
29 */ 27 */
30 28
29//config:config DPKG
30//config: bool "dpkg"
31//config: default n
32//config: select FEATURE_SEAMLESS_GZ
33//config: help
34//config: dpkg is a medium-level tool to install, build, remove and manage
35//config: Debian packages.
36//config:
37//config: This implementation of dpkg has a number of limitations,
38//config: you should use the official dpkg if possible.
39
40//applet:IF_DPKG(APPLET(dpkg, BB_DIR_USR_BIN, BB_SUID_DROP))
41//kbuild:lib-$(CONFIG_DPKG) += dpkg.o
42
31//usage:#define dpkg_trivial_usage 43//usage:#define dpkg_trivial_usage
32//usage: "[-ilCPru] [-F OPT] PACKAGE" 44//usage: "[-ilCPru] [-F OPT] PACKAGE"
33//usage:#define dpkg_full_usage "\n\n" 45//usage:#define dpkg_full_usage "\n\n"
diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c
index a04ec9407..13f9db991 100644
--- a/archival/dpkg_deb.c
+++ b/archival/dpkg_deb.c
@@ -5,8 +5,33 @@
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 */ 6 */
7 7
8//config:config DPKG_DEB
9//config: bool "dpkg_deb"
10//config: default n
11//config: select FEATURE_SEAMLESS_GZ
12//config: help
13//config: dpkg-deb unpacks and provides information about Debian archives.
14//config:
15//config: This implementation of dpkg-deb cannot pack archives.
16//config:
17//config: Unless you have a specific application which requires dpkg-deb,
18//config: say N here.
19//config:
20//config:config FEATURE_DPKG_DEB_EXTRACT_ONLY
21//config: bool "Extract only (-x)"
22//config: default n
23//config: depends on DPKG_DEB
24//config: help
25//config: This reduces dpkg-deb to the equivalent of
26//config: "ar -p <deb> data.tar.gz | tar -zx". However it saves space as none
27//config: of the extra dpkg-deb, ar or tar options are needed, they are linked
28//config: to internally.
29
30//applet:IF_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, BB_DIR_USR_BIN, BB_SUID_DROP, dpkg_deb))
31//kbuild:lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o
32
8//usage:#define dpkg_deb_trivial_usage 33//usage:#define dpkg_deb_trivial_usage
9//usage: "[-cefxX] FILE [argument" 34//usage: "[-cefxX] FILE [argument]"
10//usage:#define dpkg_deb_full_usage "\n\n" 35//usage:#define dpkg_deb_full_usage "\n\n"
11//usage: "Perform actions on Debian packages (.debs)\n" 36//usage: "Perform actions on Debian packages (.debs)\n"
12//usage: "\n -c List contents of filesystem tree" 37//usage: "\n -c List contents of filesystem tree"
diff --git a/archival/gzip.c b/archival/gzip.c
index 31ccab3cd..1e779c9c3 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -15,7 +15,6 @@
15 * 15 *
16 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
17 */ 17 */
18
19/* big objects in bss: 18/* big objects in bss:
20 * 00000020 b bl_count 19 * 00000020 b bl_count
21 * 00000074 b base_length 20 * 00000074 b base_length
@@ -31,7 +30,6 @@
31 * 00000480 b static_ltree 30 * 00000480 b static_ltree
32 * 000008f4 b dyn_ltree 31 * 000008f4 b dyn_ltree
33 */ 32 */
34
35/* TODO: full support for -v for DESKTOP 33/* TODO: full support for -v for DESKTOP
36 * "/usr/bin/gzip -v a bogus aa" should say: 34 * "/usr/bin/gzip -v a bogus aa" should say:
37a: 85.1% -- replaced with a.gz 35a: 85.1% -- replaced with a.gz
@@ -39,6 +37,35 @@ gzip: bogus: No such file or directory
39aa: 85.1% -- replaced with aa.gz 37aa: 85.1% -- replaced with aa.gz
40*/ 38*/
41 39
40//config:config GZIP
41//config: bool "gzip"
42//config: default y
43//config: help
44//config: gzip is used to compress files.
45//config: It's probably the most widely used UNIX compression program.
46//config:
47//config:config FEATURE_GZIP_LONG_OPTIONS
48//config: bool "Enable long options"
49//config: default y
50//config: depends on GZIP && LONG_OPTS
51//config: help
52//config: Enable use of long options, increases size by about 106 Bytes
53//config:
54//config:config GZIP_FAST
55//config: int "Trade memory for gzip speed (0:small,slow - 2:fast,big)"
56//config: default 0
57//config: range 0 2
58//config: depends on GZIP
59//config: help
60//config: Enable big memory options for gzip.
61//config: 0: small buffers, small hash-tables
62//config: 1: larger buffers, larger hash-tables
63//config: 2: larger buffers, largest hash-tables
64//config: Larger models may give slightly better compression
65
66//applet:IF_GZIP(APPLET(gzip, BB_DIR_BIN, BB_SUID_DROP))
67//kbuild:lib-$(CONFIG_GZIP) += gzip.o
68
42//usage:#define gzip_trivial_usage 69//usage:#define gzip_trivial_usage
43//usage: "[-cfd] [FILE]..." 70//usage: "[-cfd] [FILE]..."
44//usage:#define gzip_full_usage "\n\n" 71//usage:#define gzip_full_usage "\n\n"
diff --git a/archival/libarchive/bz/compress.c b/archival/libarchive/bz/compress.c
index e9f1afdaf..23de9d3f5 100644
--- a/archival/libarchive/bz/compress.c
+++ b/archival/libarchive/bz/compress.c
@@ -249,7 +249,7 @@ void generateMTFValues(EState* s)
249static NOINLINE 249static NOINLINE
250void sendMTFValues(EState* s) 250void sendMTFValues(EState* s)
251{ 251{
252 int32_t v, t, i, j, gs, ge, totc, bt, bc, iter; 252 int32_t v, t, i, j, gs, ge, bt, bc, iter;
253 int32_t nSelectors, alphaSize, minLen, maxLen, selCtr; 253 int32_t nSelectors, alphaSize, minLen, maxLen, selCtr;
254 int32_t nGroups; 254 int32_t nGroups;
255 255
@@ -345,7 +345,6 @@ void sendMTFValues(EState* s)
345 } 345 }
346#endif 346#endif
347 nSelectors = 0; 347 nSelectors = 0;
348 totc = 0;
349 gs = 0; 348 gs = 0;
350 while (1) { 349 while (1) {
351 /*--- Set group start & end marks. --*/ 350 /*--- Set group start & end marks. --*/
@@ -411,7 +410,6 @@ void sendMTFValues(EState* s)
411 bt = t; 410 bt = t;
412 } 411 }
413 } 412 }
414 totc += bc;
415 fave[bt]++; 413 fave[bt]++;
416 s->selector[nSelectors] = bt; 414 s->selector[nSelectors] = bt;
417 nSelectors++; 415 nSelectors++;
@@ -501,14 +499,14 @@ void sendMTFValues(EState* s)
501 for (i = 0; i < 16; i++) { 499 for (i = 0; i < 16; i++) {
502 if (sizeof(long) <= 4) { 500 if (sizeof(long) <= 4) {
503 inUse16 = inUse16*2 + 501 inUse16 = inUse16*2 +
504 ((*(uint32_t*)&(s->inUse[i * 16 + 0]) 502 ((*(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 0])
505 | *(uint32_t*)&(s->inUse[i * 16 + 4]) 503 | *(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 4])
506 | *(uint32_t*)&(s->inUse[i * 16 + 8]) 504 | *(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 8])
507 | *(uint32_t*)&(s->inUse[i * 16 + 12])) != 0); 505 | *(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 12])) != 0);
508 } else { /* Our CPU can do better */ 506 } else { /* Our CPU can do better */
509 inUse16 = inUse16*2 + 507 inUse16 = inUse16*2 +
510 ((*(uint64_t*)&(s->inUse[i * 16 + 0]) 508 ((*(bb__aliased_uint64_t*)&(s->inUse[i * 16 + 0])
511 | *(uint64_t*)&(s->inUse[i * 16 + 8])) != 0); 509 | *(bb__aliased_uint64_t*)&(s->inUse[i * 16 + 8])) != 0);
512 } 510 }
513 } 511 }
514 512
diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c
index dc252bb82..6396fe40d 100644
--- a/archival/libarchive/decompress_bunzip2.c
+++ b/archival/libarchive/decompress_bunzip2.c
@@ -42,6 +42,12 @@
42#include "libbb.h" 42#include "libbb.h"
43#include "bb_archive.h" 43#include "bb_archive.h"
44 44
45#if 0
46# define dbg(...) bb_error_msg(__VA_ARGS__)
47#else
48# define dbg(...) ((void)0)
49#endif
50
45/* Constants for Huffman coding */ 51/* Constants for Huffman coding */
46#define MAX_GROUPS 6 52#define MAX_GROUPS 6
47#define GROUP_SIZE 50 /* 64 would have been more efficient */ 53#define GROUP_SIZE 50 /* 64 would have been more efficient */
@@ -52,13 +58,13 @@
52 58
53/* Status return values */ 59/* Status return values */
54#define RETVAL_OK 0 60#define RETVAL_OK 0
55#define RETVAL_LAST_BLOCK (-1) 61#define RETVAL_LAST_BLOCK (dbg("%d", __LINE__), -1)
56#define RETVAL_NOT_BZIP_DATA (-2) 62#define RETVAL_NOT_BZIP_DATA (dbg("%d", __LINE__), -2)
57#define RETVAL_UNEXPECTED_INPUT_EOF (-3) 63#define RETVAL_UNEXPECTED_INPUT_EOF (dbg("%d", __LINE__), -3)
58#define RETVAL_SHORT_WRITE (-4) 64#define RETVAL_SHORT_WRITE (dbg("%d", __LINE__), -4)
59#define RETVAL_DATA_ERROR (-5) 65#define RETVAL_DATA_ERROR (dbg("%d", __LINE__), -5)
60#define RETVAL_OUT_OF_MEMORY (-6) 66#define RETVAL_OUT_OF_MEMORY (dbg("%d", __LINE__), -6)
61#define RETVAL_OBSOLETE_INPUT (-7) 67#define RETVAL_OBSOLETE_INPUT (dbg("%d", __LINE__), -7)
62 68
63/* Other housekeeping constants */ 69/* Other housekeeping constants */
64#define IOBUF_SIZE 4096 70#define IOBUF_SIZE 4096
@@ -440,7 +446,11 @@ static int get_next_block(bunzip_data *bd)
440 literal used is the one at the head of the mtfSymbol array.) */ 446 literal used is the one at the head of the mtfSymbol array.) */
441 if (runPos != 0) { 447 if (runPos != 0) {
442 uint8_t tmp_byte; 448 uint8_t tmp_byte;
443 if (dbufCount + runCnt >= dbufSize) return RETVAL_DATA_ERROR; 449 if (dbufCount + runCnt > dbufSize) {
450 dbg("dbufCount:%d+runCnt:%d %d > dbufSize:%d RETVAL_DATA_ERROR",
451 dbufCount, runCnt, dbufCount + runCnt, dbufSize);
452 return RETVAL_DATA_ERROR;
453 }
444 tmp_byte = symToByte[mtfSymbol[0]]; 454 tmp_byte = symToByte[mtfSymbol[0]];
445 byteCount[tmp_byte] += runCnt; 455 byteCount[tmp_byte] += runCnt;
446 while (--runCnt >= 0) dbuf[dbufCount++] = (uint32_t)tmp_byte; 456 while (--runCnt >= 0) dbuf[dbufCount++] = (uint32_t)tmp_byte;
@@ -808,7 +818,6 @@ static char *const bunzip_errors[] = {
808/* Dumb little test thing, decompress stdin to stdout */ 818/* Dumb little test thing, decompress stdin to stdout */
809int main(int argc, char **argv) 819int main(int argc, char **argv)
810{ 820{
811 int i;
812 char c; 821 char c;
813 822
814 int i = unpack_bz2_stream(0, 1); 823 int i = unpack_bz2_stream(0, 1);
diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c
index 4e6b138c3..7c6f38ec3 100644
--- a/archival/libarchive/decompress_gunzip.c
+++ b/archival/libarchive/decompress_gunzip.c
@@ -336,7 +336,7 @@ static int huft_build(const unsigned *b, const unsigned n,
336 } 336 }
337 337
338 /* Find minimum and maximum length, bound *m by those */ 338 /* Find minimum and maximum length, bound *m by those */
339 for (j = 1; (c[j] == 0) && (j <= BMAX); j++) 339 for (j = 1; (j <= BMAX) && (c[j] == 0); j++)
340 continue; 340 continue;
341 k = j; /* minimum code length */ 341 k = j; /* minimum code length */
342 for (i = BMAX; (c[i] == 0) && i; i--) 342 for (i = BMAX; (c[i] == 0) && i; i--)
diff --git a/archival/libarchive/get_header_ar.c b/archival/libarchive/get_header_ar.c
index 23c412496..c66bb3ee7 100644
--- a/archival/libarchive/get_header_ar.c
+++ b/archival/libarchive/get_header_ar.c
@@ -8,11 +8,19 @@
8#include "bb_archive.h" 8#include "bb_archive.h"
9#include "ar.h" 9#include "ar.h"
10 10
11static unsigned read_num(const char *str, int base) 11/* WARNING: Clobbers str[len], so fields must be read in reverse order! */
12static unsigned read_num(char *str, int base, int len)
12{ 13{
14 int err;
15
16 /* ar fields are fixed length text strings (padded with spaces).
17 * Ensure bb_strtou doesn't read past the field in case the full
18 * width is used. */
19 str[len] = 0;
20
13 /* This code works because 21 /* This code works because
14 * on misformatted numbers bb_strtou returns all-ones */ 22 * on misformatted numbers bb_strtou returns all-ones */
15 int err = bb_strtou(str, NULL, base); 23 err = bb_strtou(str, NULL, base);
16 if (err == -1) 24 if (err == -1)
17 bb_error_msg_and_die("invalid ar header"); 25 bb_error_msg_and_die("invalid ar header");
18 return err; 26 return err;
@@ -51,11 +59,13 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
51 if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n') 59 if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n')
52 bb_error_msg_and_die("invalid ar header"); 60 bb_error_msg_and_die("invalid ar header");
53 61
54 /* FIXME: more thorough routine would be in order here 62 /*
55 * (we have something like that in tar) 63 * Note that the fields MUST be read in reverse order as
56 * but for now we are lax. */ 64 * read_num() clobbers the next byte after the field!
57 ar.formatted.magic[0] = '\0'; /* else 4G-2 file will have size="4294967294`\n..." */ 65 * Order is: name, date, uid, gid, mode, size, magic.
58 typed->size = size = read_num(ar.formatted.size, 10); 66 */
67 typed->size = size = read_num(ar.formatted.size, 10,
68 sizeof(ar.formatted.size));
59 69
60 /* special filenames have '/' as the first character */ 70 /* special filenames have '/' as the first character */
61 if (ar.formatted.name[0] == '/') { 71 if (ar.formatted.name[0] == '/') {
@@ -87,10 +97,10 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
87 * long filename pseudo file. Thus we decode the rest 97 * long filename pseudo file. Thus we decode the rest
88 * after dealing with long filename pseudo file. 98 * after dealing with long filename pseudo file.
89 */ 99 */
90 typed->mode = read_num(ar.formatted.mode, 8); 100 typed->mode = read_num(ar.formatted.mode, 8, sizeof(ar.formatted.mode));
91 typed->mtime = read_num(ar.formatted.date, 10); 101 typed->gid = read_num(ar.formatted.gid, 10, sizeof(ar.formatted.gid));
92 typed->uid = read_num(ar.formatted.uid, 10); 102 typed->uid = read_num(ar.formatted.uid, 10, sizeof(ar.formatted.uid));
93 typed->gid = read_num(ar.formatted.gid, 10); 103 typed->mtime = read_num(ar.formatted.date, 10, sizeof(ar.formatted.date));
94 104
95#if ENABLE_FEATURE_AR_LONG_FILENAMES 105#if ENABLE_FEATURE_AR_LONG_FILENAMES
96 if (ar.formatted.name[0] == '/') { 106 if (ar.formatted.name[0] == '/') {
@@ -98,7 +108,8 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
98 108
99 /* The number after the '/' indicates the offset in the ar data section 109 /* The number after the '/' indicates the offset in the ar data section
100 * (saved in ar_long_names) that conatains the real filename */ 110 * (saved in ar_long_names) that conatains the real filename */
101 long_offset = read_num(&ar.formatted.name[1], 10); 111 long_offset = read_num(&ar.formatted.name[1], 10,
112 sizeof(ar.formatted.name) - 1);
102 if (long_offset >= ar_long_name_size) { 113 if (long_offset >= ar_long_name_size) {
103 bb_error_msg_and_die("can't resolve long filename"); 114 bb_error_msg_and_die("can't resolve long filename");
104 } 115 }
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index bc09756ba..32f842095 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -198,13 +198,13 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
198 * the message and we don't check whether we indeed 198 * the message and we don't check whether we indeed
199 * saw zero block directly before this. */ 199 * saw zero block directly before this. */
200 if (i == 0) { 200 if (i == 0) {
201 xfunc_error_retval = 0; 201 bb_error_msg("short read");
202 short_read: 202 /* this merely signals end of archive, not exit(1): */
203 bb_error_msg_and_die("short read"); 203 return EXIT_FAILURE;
204 } 204 }
205 if (i != 512) { 205 if (i != 512) {
206 IF_FEATURE_TAR_AUTODETECT(goto autodetect;) 206 IF_FEATURE_TAR_AUTODETECT(goto autodetect;)
207 goto short_read; 207 bb_error_msg_and_die("short read");
208 } 208 }
209 209
210#else 210#else
@@ -221,10 +221,10 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
221 */ 221 */
222 while (full_read(archive_handle->src_fd, &tar, 512) == 512) 222 while (full_read(archive_handle->src_fd, &tar, 512) == 512)
223 continue; 223 continue;
224 return EXIT_FAILURE; 224 return EXIT_FAILURE; /* "end of archive" */
225 } 225 }
226 archive_handle->tar__end = 1; 226 archive_handle->tar__end = 1;
227 return EXIT_SUCCESS; 227 return EXIT_SUCCESS; /* "decoded one header" */
228 } 228 }
229 archive_handle->tar__end = 0; 229 archive_handle->tar__end = 0;
230 230
@@ -471,5 +471,5 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
471 free(file_header->tar__uname); 471 free(file_header->tar__uname);
472 free(file_header->tar__gname); 472 free(file_header->tar__gname);
473#endif 473#endif
474 return EXIT_SUCCESS; 474 return EXIT_SUCCESS; /* "decoded one header" */
475} 475}
diff --git a/archival/libarchive/lzo1x_9x.c b/archival/libarchive/lzo1x_9x.c
index 897132987..2b490ae83 100644
--- a/archival/libarchive/lzo1x_9x.c
+++ b/archival/libarchive/lzo1x_9x.c
@@ -94,7 +94,7 @@ typedef struct {
94 ( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) ) 94 ( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) )
95 95
96#if defined(LZO_UNALIGNED_OK_2) 96#if defined(LZO_UNALIGNED_OK_2)
97# define HEAD2(b,p) (* (uint16_t *) &(b[p])) 97# define HEAD2(b,p) (* (bb__aliased_uint16_t *) &(b[p]))
98#else 98#else
99# define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8)) 99# define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8))
100#endif 100#endif
@@ -466,7 +466,6 @@ static int find_match(lzo1x_999_t *c, lzo_swd_p s,
466 } 466 }
467 467
468 s->m_len = 1; 468 s->m_len = 1;
469 s->m_len = 1;
470#ifdef SWD_BEST_OFF 469#ifdef SWD_BEST_OFF
471 if (s->use_best_off) 470 if (s->use_best_off)
472 memset(s->best_pos, 0, sizeof(s->best_pos)); 471 memset(s->best_pos, 0, sizeof(s->best_pos));
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index 841e9dce9..c4e02f0f7 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -81,16 +81,17 @@ void FAST_FUNC open_transformer(int fd, const char *transform_prog)
81 // FIXME: error check? 81 // FIXME: error check?
82#if BB_MMU 82#if BB_MMU
83 { 83 {
84 IF_DESKTOP(long long) int r;
84 transformer_aux_data_t aux; 85 transformer_aux_data_t aux;
85 init_transformer_aux_data(&aux); 86 init_transformer_aux_data(&aux);
86 aux.check_signature = check_signature; 87 aux.check_signature = check_signature;
87 transformer(&aux, fd, fd_pipe.wr); 88 r = transformer(&aux, fd, fd_pipe.wr);
88 if (ENABLE_FEATURE_CLEAN_UP) { 89 if (ENABLE_FEATURE_CLEAN_UP) {
89 close(fd_pipe.wr); /* send EOF */ 90 close(fd_pipe.wr); /* send EOF */
90 close(fd); 91 close(fd);
91 } 92 }
92 /* must be _exit! bug was actually seen here */ 93 /* must be _exit! bug was actually seen here */
93 _exit(EXIT_SUCCESS); 94 _exit(/*error if:*/ r < 0);
94 } 95 }
95#else 96#else
96 { 97 {
diff --git a/archival/lzop.c b/archival/lzop.c
index 9b42e5fd3..5062d9300 100644
--- a/archival/lzop.c
+++ b/archival/lzop.c
@@ -25,6 +25,26 @@
25 "Minimalized" for busybox by Alain Knaff 25 "Minimalized" for busybox by Alain Knaff
26*/ 26*/
27 27
28//config:config LZOP
29//config: bool "lzop"
30//config: default y
31//config: help
32//config: Lzop compression/decompresion.
33//config:
34//config:config LZOP_COMPR_HIGH
35//config: bool "lzop compression levels 7,8,9 (not very useful)"
36//config: default n
37//config: depends on LZOP
38//config: help
39//config: High levels (7,8,9) of lzop compression. These levels
40//config: are actually slower than gzip at equivalent compression ratios
41//config: and take up 3.2K of code.
42
43//applet:IF_LZOP(APPLET(lzop, BB_DIR_BIN, BB_SUID_DROP))
44//applet:IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, lzopcat))
45//applet:IF_LZOP(APPLET_ODDNAME(unlzop, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, unlzop))
46//kbuild:lib-$(CONFIG_LZOP) += lzop.o
47
28//usage:#define lzop_trivial_usage 48//usage:#define lzop_trivial_usage
29//usage: "[-cfvd123456789CF] [FILE]..." 49//usage: "[-cfvd123456789CF] [FILE]..."
30//usage:#define lzop_full_usage "\n\n" 50//usage:#define lzop_full_usage "\n\n"
diff --git a/archival/rpm.c b/archival/rpm.c
index 86ba4dca4..885eddd64 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -7,6 +7,15 @@
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//config:config RPM
11//config: bool "rpm"
12//config: default y
13//config: help
14//config: Mini RPM applet - queries and extracts RPM packages.
15
16//applet:IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP))
17//kbuild:lib-$(CONFIG_RPM) += rpm.o
18
10//usage:#define rpm_trivial_usage 19//usage:#define rpm_trivial_usage
11//usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm" 20//usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm"
12//usage:#define rpm_full_usage "\n\n" 21//usage:#define rpm_full_usage "\n\n"
diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c
index f3dfa5159..61adde795 100644
--- a/archival/rpm2cpio.c
+++ b/archival/rpm2cpio.c
@@ -7,6 +7,15 @@
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//config:config RPM2CPIO
11//config: bool "rpm2cpio"
12//config: default y
13//config: help
14//config: Converts a RPM file into a CPIO archive.
15
16//applet:IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP))
17//kbuild:lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o
18
10//usage:#define rpm2cpio_trivial_usage 19//usage:#define rpm2cpio_trivial_usage
11//usage: "package.rpm" 20//usage: "package.rpm"
12//usage:#define rpm2cpio_full_usage "\n\n" 21//usage:#define rpm2cpio_full_usage "\n\n"
diff --git a/archival/tar.c b/archival/tar.c
index 3129781d2..2909eca1b 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -22,7 +22,6 @@
22 * 22 *
23 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 23 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
24 */ 24 */
25
26/* TODO: security with -C DESTDIR option can be enhanced. 25/* TODO: security with -C DESTDIR option can be enhanced.
27 * Consider tar file created via: 26 * Consider tar file created via:
28 * $ tar cvf bug.tar anything.txt 27 * $ tar cvf bug.tar anything.txt
@@ -42,6 +41,109 @@
42 * This doesn't feel right, and IIRC GNU tar doesn't do that. 41 * This doesn't feel right, and IIRC GNU tar doesn't do that.
43 */ 42 */
44 43
44//config:config TAR
45//config: bool "tar"
46//config: default y
47//config: help
48//config: tar is an archiving program. It's commonly used with gzip to
49//config: create compressed archives. It's probably the most widely used
50//config: UNIX archive program.
51//config:
52//config:config FEATURE_TAR_CREATE
53//config: bool "Enable archive creation"
54//config: default y
55//config: depends on TAR
56//config: help
57//config: If you enable this option you'll be able to create
58//config: tar archives using the `-c' option.
59//config:
60//config:config FEATURE_TAR_AUTODETECT
61//config: bool "Autodetect compressed tarballs"
62//config: default y
63//config: depends on TAR && (FEATURE_SEAMLESS_Z || FEATURE_SEAMLESS_GZ || FEATURE_SEAMLESS_BZ2 || FEATURE_SEAMLESS_LZMA || FEATURE_SEAMLESS_XZ)
64//config: help
65//config: With this option tar can automatically detect compressed
66//config: tarballs. Currently it works only on files (not pipes etc).
67//config:
68//config:config FEATURE_TAR_FROM
69//config: bool "Enable -X (exclude from) and -T (include from) options)"
70//config: default y
71//config: depends on TAR
72//config: help
73//config: If you enable this option you'll be able to specify
74//config: a list of files to include or exclude from an archive.
75//config:
76//config:config FEATURE_TAR_OLDGNU_COMPATIBILITY
77//config: bool "Support for old tar header format"
78//config: default y
79//config: depends on TAR || DPKG
80//config: help
81//config: This option is required to unpack archives created in
82//config: the old GNU format; help to kill this old format by
83//config: repacking your ancient archives with the new format.
84//config:
85//config:config FEATURE_TAR_OLDSUN_COMPATIBILITY
86//config: bool "Enable untarring of tarballs with checksums produced by buggy Sun tar"
87//config: default y
88//config: depends on TAR || DPKG
89//config: help
90//config: This option is required to unpack archives created by some old
91//config: version of Sun's tar (it was calculating checksum using signed
92//config: arithmetic). It is said to be fixed in newer Sun tar, but "old"
93//config: tarballs still exist.
94//config:
95//config:config FEATURE_TAR_GNU_EXTENSIONS
96//config: bool "Support for GNU tar extensions (long filenames)"
97//config: default y
98//config: depends on TAR || DPKG
99//config: help
100//config: With this option busybox supports GNU long filenames and
101//config: linknames.
102//config:
103//config:config FEATURE_TAR_LONG_OPTIONS
104//config: bool "Enable long options"
105//config: default y
106//config: depends on TAR && LONG_OPTS
107//config: help
108//config: Enable use of long options, increases size by about 400 Bytes
109//config:
110//config:config FEATURE_TAR_TO_COMMAND
111//config: bool "Support for writing to an external program"
112//config: default y
113//config: depends on TAR && FEATURE_TAR_LONG_OPTIONS
114//config: help
115//config: If you enable this option you'll be able to instruct tar to send
116//config: the contents of each extracted file to the standard input of an
117//config: external program.
118//config:
119//config:config FEATURE_TAR_UNAME_GNAME
120//config: bool "Enable use of user and group names"
121//config: default y
122//config: depends on TAR
123//config: help
124//config: Enables use of user and group names in tar. This affects contents
125//config: listings (-t) and preserving permissions when unpacking (-p).
126//config: +200 bytes.
127//config:
128//config:config FEATURE_TAR_NOPRESERVE_TIME
129//config: bool "Enable -m (do not preserve time) option"
130//config: default y
131//config: depends on TAR
132//config: help
133//config: With this option busybox supports GNU tar -m
134//config: (do not preserve time) option.
135//config:
136//config:config FEATURE_TAR_SELINUX
137//config: bool "Support for extracting SELinux labels"
138//config: default n
139//config: depends on TAR && SELINUX
140//config: help
141//config: With this option busybox supports restoring SELinux labels
142//config: when extracting files from tar archives.
143
144//applet:IF_TAR(APPLET(tar, BB_DIR_BIN, BB_SUID_DROP))
145//kbuild:lib-$(CONFIG_TAR) += tar.o
146
45#include <fnmatch.h> 147#include <fnmatch.h>
46#include "libbb.h" 148#include "libbb.h"
47#include "bb_archive.h" 149#include "bb_archive.h"
@@ -1096,8 +1198,14 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1096 /*tar_handle->offset = 0; - already is */ 1198 /*tar_handle->offset = 0; - already is */
1097 } 1199 }
1098 1200
1201 /* Zero processed headers (== empty file) is not a valid tarball.
1202 * We (ab)use bb_got_signal as exitcode here,
1203 * because check_errors_in_children() uses _it_ as error indicator.
1204 */
1205 bb_got_signal = EXIT_FAILURE;
1206
1099 while (get_header_tar(tar_handle) == EXIT_SUCCESS) 1207 while (get_header_tar(tar_handle) == EXIT_SUCCESS)
1100 continue; 1208 bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */
1101 1209
1102 /* Check that every file that should have been extracted was */ 1210 /* Check that every file that should have been extracted was */
1103 while (tar_handle->accept) { 1211 while (tar_handle->accept) {
@@ -1113,8 +1221,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1113 close(tar_handle->src_fd); 1221 close(tar_handle->src_fd);
1114 1222
1115 if (SEAMLESS_COMPRESSION || OPT_COMPRESS) { 1223 if (SEAMLESS_COMPRESSION || OPT_COMPRESS) {
1224 /* Set bb_got_signal to 1 if a child died with !0 exitcode */
1116 check_errors_in_children(0); 1225 check_errors_in_children(0);
1117 return bb_got_signal;
1118 } 1226 }
1119 return EXIT_SUCCESS; 1227
1228 return bb_got_signal;
1120} 1229}
diff --git a/archival/unzip.c b/archival/unzip.c
index 673e5fe08..fcfc9a448 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -9,16 +9,27 @@
9 * 9 *
10 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
11 */ 11 */
12
13/* For reference see 12/* For reference see
14 * http://www.pkware.com/company/standards/appnote/ 13 * http://www.pkware.com/company/standards/appnote/
15 * http://www.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip 14 * http://www.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
16 */ 15 *
17 16 * TODO
18/* TODO
19 * Zip64 + other methods 17 * Zip64 + other methods
20 */ 18 */
21 19
20//config:config UNZIP
21//config: bool "unzip"
22//config: default y
23//config: help
24//config: unzip will list or extract files from a ZIP archive,
25//config: commonly found on DOS/WIN systems. The default behavior
26//config: (with no options) is to extract the archive into the
27//config: current directory. Use the `-d' option to extract to a
28//config: directory of your choice.
29
30//applet:IF_UNZIP(APPLET(unzip, BB_DIR_USR_BIN, BB_SUID_DROP))
31//kbuild:lib-$(CONFIG_UNZIP) += unzip.o
32
22//usage:#define unzip_trivial_usage 33//usage:#define unzip_trivial_usage
23//usage: "[-lnopq] FILE[.zip] [FILE]... [-x FILE...] [-d DIR]" 34//usage: "[-lnopq] FILE[.zip] [FILE]... [-x FILE...] [-d DIR]"
24//usage:#define unzip_full_usage "\n\n" 35//usage:#define unzip_full_usage "\n\n"
diff --git a/console-tools/dumpkmap.c b/console-tools/dumpkmap.c
index 6b923d2d4..bf8d690da 100644
--- a/console-tools/dumpkmap.c
+++ b/console-tools/dumpkmap.c
@@ -36,47 +36,56 @@ int dumpkmap_main(int argc UNUSED_PARAM, char **argv)
36{ 36{
37 struct kbentry ke; 37 struct kbentry ke;
38 int i, j, fd; 38 int i, j, fd;
39 RESERVE_CONFIG_BUFFER(flags, MAX_NR_KEYMAPS); 39#define flags bb_common_bufsiz1
40 40
41 /* When user accidentally runs "dumpkmap FILE" 41 /* When user accidentally runs "dumpkmap FILE"
42 * instead of "dumpkmap >FILE", we'd dump binary stuff to tty. 42 * instead of "dumpkmap >FILE", we'd dump binary stuff to tty.
43 * Let's prevent it: */ 43 * Let's prevent it:
44 */
44 if (argv[1]) 45 if (argv[1])
45 bb_show_usage(); 46 bb_show_usage();
46/* bb_warn_ignoring_args(argv[1]);*/ 47/* bb_warn_ignoring_args(argv[1]);*/
47 48
48 fd = get_console_fd_or_die(); 49 fd = get_console_fd_or_die();
49 50
51#if 0
50 write(STDOUT_FILENO, "bkeymap", 7); 52 write(STDOUT_FILENO, "bkeymap", 7);
51
52 /* Here we want to set everything to 0 except for indexes: 53 /* Here we want to set everything to 0 except for indexes:
53 * [0-2] [4-6] [8-10] [12] */ 54 * [0-2] [4-6] [8-10] [12]
54 memset(flags, 0x00, MAX_NR_KEYMAPS); 55 */
56 /*memset(flags, 0x00, MAX_NR_KEYMAPS); - already is */
55 memset(flags, 0x01, 13); 57 memset(flags, 0x01, 13);
56 flags[3] = flags[7] = flags[11] = 0; 58 flags[3] = flags[7] = flags[11] = 0;
57
58 /* dump flags */ 59 /* dump flags */
59 write(STDOUT_FILENO, flags, MAX_NR_KEYMAPS); 60 write(STDOUT_FILENO, flags, MAX_NR_KEYMAPS);
61#define flags7 flags
62#else
63 /* Same effect */
64 /* 0 1 2 3 4 5 6 7 8 9 a b c=12 */
65 memcpy(flags, "bkeymap\1\1\1\0\1\1\1\0\1\1\1\0\1",
66 /* Can use sizeof, or sizeof-1. sizeof is even, using that */
67 /****/ sizeof("bkeymap\1\1\1\0\1\1\1\0\1\1\1\0\1")
68 );
69 write(STDOUT_FILENO, flags, 7 + MAX_NR_KEYMAPS);
70#define flags7 (flags + 7)
71#endif
60 72
61 for (i = 0; i < MAX_NR_KEYMAPS; i++) { 73 for (i = 0; i < 13; i++) {
62 if (flags[i] == 1) { 74 if (flags7[i]) {
63 for (j = 0; j < NR_KEYS; j++) { 75 for (j = 0; j < NR_KEYS; j++) {
64 ke.kb_index = j; 76 ke.kb_index = j;
65 ke.kb_table = i; 77 ke.kb_table = i;
66 if (!ioctl_or_perror(fd, KDGKBENT, &ke, 78 if (!ioctl_or_perror(fd, KDGKBENT, &ke,
67 "ioctl failed with %s, %s, %p", 79 "ioctl(KDGKBENT{%d,%d}) failed",
68 (char *)&ke.kb_index, 80 j, i)
69 (char *)&ke.kb_table,
70 &ke.kb_value)
71 ) { 81 ) {
72 write(STDOUT_FILENO, (void*)&ke.kb_value, 2); 82 write(STDOUT_FILENO, &ke.kb_value, 2);
73 } 83 }
74 } 84 }
75 } 85 }
76 } 86 }
77 if (ENABLE_FEATURE_CLEAN_UP) { 87 if (ENABLE_FEATURE_CLEAN_UP) {
78 close(fd); 88 close(fd);
79 RELEASE_CONFIG_BUFFER(flags);
80 } 89 }
81 return EXIT_SUCCESS; 90 return EXIT_SUCCESS;
82} 91}
diff --git a/console-tools/loadkmap.c b/console-tools/loadkmap.c
index bcffe16b1..66ec3b043 100644
--- a/console-tools/loadkmap.c
+++ b/console-tools/loadkmap.c
@@ -48,6 +48,7 @@ int loadkmap_main(int argc UNUSED_PARAM, char **argv)
48 if (argv[1]) 48 if (argv[1])
49 bb_show_usage(); 49 bb_show_usage();
50/* bb_warn_ignoring_args(argv[1]); */ 50/* bb_warn_ignoring_args(argv[1]); */
51
51 fd = get_console_fd_or_die(); 52 fd = get_console_fd_or_die();
52/* or maybe: 53/* or maybe:
53 opt = getopt32(argv, "C:", &tty_name); 54 opt = getopt32(argv, "C:", &tty_name);
@@ -61,14 +62,24 @@ int loadkmap_main(int argc UNUSED_PARAM, char **argv)
61 xread(STDIN_FILENO, flags, MAX_NR_KEYMAPS); 62 xread(STDIN_FILENO, flags, MAX_NR_KEYMAPS);
62 63
63 for (i = 0; i < MAX_NR_KEYMAPS; i++) { 64 for (i = 0; i < MAX_NR_KEYMAPS; i++) {
64 if (flags[i] == 1) { 65 if (flags[i] != 1)
65 xread(STDIN_FILENO, ibuff, NR_KEYS * sizeof(uint16_t)); 66 continue;
66 for (j = 0; j < NR_KEYS; j++) { 67 xread(STDIN_FILENO, ibuff, NR_KEYS * sizeof(uint16_t));
67 ke.kb_index = j; 68 for (j = 0; j < NR_KEYS; j++) {
68 ke.kb_table = i; 69 ke.kb_index = j;
69 ke.kb_value = ibuff[j]; 70 ke.kb_table = i;
70 ioctl(fd, KDSKBENT, &ke); 71 ke.kb_value = ibuff[j];
71 } 72 /*
73 * Note: table[idx:0] can contain special value
74 * K_ALLOCATED (marks allocated tables in kernel).
75 * dumpkmap saves the value as-is; but attempts
76 * to load it here fail, since it isn't a valid
77 * key value: it is K(KT_SPEC,126) == 2<<8 + 126,
78 * whereas last valid KT_SPEC is
79 * K_BARENUMLOCK == K(KT_SPEC,19).
80 * So far we just ignore these errors:
81 */
82 ioctl(fd, KDSKBENT, &ke);
72 } 83 }
73 } 84 }
74 85
diff --git a/coreutils/cal.c b/coreutils/cal.c
index 0d388aa1c..12c46b14f 100644
--- a/coreutils/cal.c
+++ b/coreutils/cal.c
@@ -165,7 +165,7 @@ int cal_main(int argc UNUSED_PARAM, char **argv)
165 char lineout[30]; 165 char lineout[30];
166 166
167 day_array(month, year, dp); 167 day_array(month, year, dp);
168 len = sprintf(lineout, "%s %d", month_names[month - 1], year); 168 len = sprintf(lineout, "%s %u", month_names[month - 1], year);
169 printf("%*s%s\n%s\n", 169 printf("%*s%s\n%s\n",
170 ((7*julian + WEEK_LEN) - len) / 2, "", 170 ((7*julian + WEEK_LEN) - len) / 2, "",
171 lineout, day_headings); 171 lineout, day_headings);
diff --git a/coreutils/expand.c b/coreutils/expand.c
index 25bbffc66..8d376ff4e 100644
--- a/coreutils/expand.c
+++ b/coreutils/expand.c
@@ -78,11 +78,7 @@ static void expand(FILE *file, unsigned tab_size, unsigned opt)
78 unsigned len; 78 unsigned len;
79 *ptr = '\0'; 79 *ptr = '\0';
80# if ENABLE_UNICODE_SUPPORT 80# if ENABLE_UNICODE_SUPPORT
81 { 81 len = unicode_strwidth(ptr_strbeg);
82 uni_stat_t uni_stat;
83 printable_string(&uni_stat, ptr_strbeg);
84 len = uni_stat.unicode_width;
85 }
86# else 82# else
87 len = ptr - ptr_strbeg; 83 len = ptr - ptr_strbeg;
88# endif 84# endif
@@ -138,12 +134,9 @@ static void unexpand(FILE *file, unsigned tab_size, unsigned opt)
138 printf("%*s%.*s", len, "", n, ptr); 134 printf("%*s%.*s", len, "", n, ptr);
139# if ENABLE_UNICODE_SUPPORT 135# if ENABLE_UNICODE_SUPPORT
140 { 136 {
141 char c; 137 char c = ptr[n];
142 uni_stat_t uni_stat;
143 c = ptr[n];
144 ptr[n] = '\0'; 138 ptr[n] = '\0';
145 printable_string(&uni_stat, ptr); 139 len = unicode_strwidth(ptr);
146 len = uni_stat.unicode_width;
147 ptr[n] = c; 140 ptr[n] = c;
148 } 141 }
149# else 142# else
diff --git a/coreutils/sum.c b/coreutils/sum.c
index 75f6ef60a..deb068e10 100644
--- a/coreutils/sum.c
+++ b/coreutils/sum.c
@@ -70,9 +70,9 @@ static unsigned sum_file(const char *file, unsigned type)
70 if (type >= SUM_SYSV) { 70 if (type >= SUM_SYSV) {
71 r = (s & 0xffff) + ((s & 0xffffffff) >> 16); 71 r = (s & 0xffff) + ((s & 0xffffffff) >> 16);
72 s = (r & 0xffff) + (r >> 16); 72 s = (r & 0xffff) + (r >> 16);
73 printf("%d %llu %s\n", s, (total_bytes + 511) / 512, file); 73 printf("%u %llu %s\n", s, (total_bytes + 511) / 512, file);
74 } else 74 } else
75 printf("%05d %5llu %s\n", s, (total_bytes + 1023) / 1024, file); 75 printf("%05u %5llu %s\n", s, (total_bytes + 1023) / 1024, file);
76 return 1; 76 return 1;
77#undef buf 77#undef buf
78} 78}
diff --git a/coreutils/tail.c b/coreutils/tail.c
index 07c71ca4b..eab502beb 100644
--- a/coreutils/tail.c
+++ b/coreutils/tail.c
@@ -105,6 +105,7 @@ int tail_main(int argc, char **argv)
105 105
106 int *fds; 106 int *fds;
107 const char *fmt; 107 const char *fmt;
108 int prev_fd;
108 109
109 INIT_G(); 110 INIT_G();
110 111
@@ -309,6 +310,7 @@ int tail_main(int argc, char **argv)
309 xwrite(STDOUT_FILENO, tailbuf, taillen); 310 xwrite(STDOUT_FILENO, tailbuf, taillen);
310 } 311 }
311 } while (++i < nfiles); 312 } while (++i < nfiles);
313 prev_fd = fds[i-1];
312 314
313 tailbuf = xrealloc(tailbuf, BUFSIZ); 315 tailbuf = xrealloc(tailbuf, BUFSIZ);
314 316
@@ -365,9 +367,10 @@ int tail_main(int argc, char **argv)
365 nread = tail_read(fd, tailbuf, BUFSIZ); 367 nread = tail_read(fd, tailbuf, BUFSIZ);
366 if (nread <= 0) 368 if (nread <= 0)
367 break; 369 break;
368 if (fmt) { 370 if (fmt && (fd != prev_fd)) {
369 tail_xprint_header(fmt, filename); 371 tail_xprint_header(fmt, filename);
370 fmt = NULL; 372 fmt = NULL;
373 prev_fd = fd;
371 } 374 }
372 xwrite(STDOUT_FILENO, tailbuf, nread); 375 xwrite(STDOUT_FILENO, tailbuf, nread);
373 } 376 }
diff --git a/coreutils/touch.c b/coreutils/touch.c
index 1216ca202..293a96890 100644
--- a/coreutils/touch.c
+++ b/coreutils/touch.c
@@ -26,6 +26,14 @@
26//config: touch is used to create or change the access and/or 26//config: touch is used to create or change the access and/or
27//config: modification timestamp of specified files. 27//config: modification timestamp of specified files.
28//config: 28//config:
29//config:config FEATURE_TOUCH_NODEREF
30//config: bool "Add support for -h"
31//config: default y
32//config: depends on TOUCH
33//config: help
34//config: Enable touch to have the -h option.
35//config: This requires libc support for lutimes() function.
36//config:
29//config:config FEATURE_TOUCH_SUSV3 37//config:config FEATURE_TOUCH_SUSV3
30//config: bool "Add support for SUSV3 features (-d -t -r)" 38//config: bool "Add support for SUSV3 features (-d -t -r)"
31//config: default y 39//config: default y
@@ -42,6 +50,9 @@
42//usage:#define touch_full_usage "\n\n" 50//usage:#define touch_full_usage "\n\n"
43//usage: "Update the last-modified date on the given FILE[s]\n" 51//usage: "Update the last-modified date on the given FILE[s]\n"
44//usage: "\n -c Don't create files" 52//usage: "\n -c Don't create files"
53//usage: IF_FEATURE_TOUCH_NODEREF(
54//usage: "\n -h Don't follow links"
55//usage: )
45//usage: IF_FEATURE_TOUCH_SUSV3( 56//usage: IF_FEATURE_TOUCH_SUSV3(
46//usage: "\n -d DT Date/time to use" 57//usage: "\n -d DT Date/time to use"
47//usage: "\n -t DT Date/time to use" 58//usage: "\n -t DT Date/time to use"
@@ -65,6 +76,7 @@
65 * parse STRING and use it instead of current time 76 * parse STRING and use it instead of current time
66 * -f (ignored, BSD compat) 77 * -f (ignored, BSD compat)
67 * -m change only the modification time 78 * -m change only the modification time
79 * -h, --no-dereference
68 * -r, --reference=FILE 80 * -r, --reference=FILE
69 * use this file's times instead of current time 81 * use this file's times instead of current time
70 * -t STAMP 82 * -t STAMP
@@ -79,6 +91,13 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
79 int fd; 91 int fd;
80 int status = EXIT_SUCCESS; 92 int status = EXIT_SUCCESS;
81 int opts; 93 int opts;
94 enum {
95 OPT_c = (1 << 0),
96 OPT_r = (1 << 1) * ENABLE_FEATURE_TOUCH_SUSV3,
97 OPT_d = (1 << 2) * ENABLE_FEATURE_TOUCH_SUSV3,
98 OPT_t = (1 << 3) * ENABLE_FEATURE_TOUCH_SUSV3,
99 OPT_h = (1 << 4) * ENABLE_FEATURE_TOUCH_NODEREF,
100 };
82#if ENABLE_FEATURE_TOUCH_SUSV3 101#if ENABLE_FEATURE_TOUCH_SUSV3
83# if ENABLE_LONG_OPTS 102# if ENABLE_LONG_OPTS
84 static const char touch_longopts[] ALIGN1 = 103 static const char touch_longopts[] ALIGN1 =
@@ -86,6 +105,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
86 "no-create\0" No_argument "c" 105 "no-create\0" No_argument "c"
87 "reference\0" Required_argument "r" 106 "reference\0" Required_argument "r"
88 "date\0" Required_argument "d" 107 "date\0" Required_argument "d"
108 IF_FEATURE_TOUCH_NODEREF("no-dereference\0" No_argument "h")
89 ; 109 ;
90# endif 110# endif
91 char *reference_file = NULL; 111 char *reference_file = NULL;
@@ -105,13 +125,13 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
105 * accepted data format differs a bit between -d and -t. 125 * accepted data format differs a bit between -d and -t.
106 * We accept the same formats for both */ 126 * We accept the same formats for both */
107 opts = getopt32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:") 127 opts = getopt32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:")
128 IF_FEATURE_TOUCH_NODEREF("h")
108 /*ignored:*/ "fma" 129 /*ignored:*/ "fma"
109 IF_FEATURE_TOUCH_SUSV3(, &reference_file) 130 IF_FEATURE_TOUCH_SUSV3(, &reference_file)
110 IF_FEATURE_TOUCH_SUSV3(, &date_str) 131 IF_FEATURE_TOUCH_SUSV3(, &date_str)
111 IF_FEATURE_TOUCH_SUSV3(, &date_str) 132 IF_FEATURE_TOUCH_SUSV3(, &date_str)
112 ); 133 );
113 134
114 opts &= 1; /* only -c bit is left */
115 argv += optind; 135 argv += optind;
116 if (!*argv) { 136 if (!*argv) {
117 bb_show_usage(); 137 bb_show_usage();
@@ -121,6 +141,10 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
121 struct stat stbuf; 141 struct stat stbuf;
122 xstat(reference_file, &stbuf); 142 xstat(reference_file, &stbuf);
123 timebuf[1].tv_sec = timebuf[0].tv_sec = stbuf.st_mtime; 143 timebuf[1].tv_sec = timebuf[0].tv_sec = stbuf.st_mtime;
144 /* Can use .st_mtim.tv_nsec
145 * (or is it .st_mtimensec?? see date.c)
146 * to set microseconds too.
147 */
124 } 148 }
125 149
126 if (date_str) { 150 if (date_str) {
@@ -141,9 +165,16 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
141 } 165 }
142 166
143 do { 167 do {
144 if (utimes(*argv, (reference_file || date_str) ? timebuf : NULL) != 0) { 168 int result;
145 if (errno == ENOENT) { /* no such file */ 169 result = (
146 if (opts) { /* creation is disabled, so ignore */ 170#if ENABLE_FEATURE_TOUCH_NODEREF
171 (opts & OPT_h) ? lutimes :
172#endif
173 utimes)(*argv, (reference_file || date_str) ? timebuf : NULL);
174 if (result != 0) {
175 if (errno == ENOENT) { /* no such file? */
176 if (opts & OPT_c) {
177 /* Creation is disabled, so ignore */
147 continue; 178 continue;
148 } 179 }
149 /* Try to create the file */ 180 /* Try to create the file */
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c
index 2c2b032be..527fae227 100644
--- a/debianutils/run_parts.c
+++ b/debianutils/run_parts.c
@@ -59,7 +59,7 @@
59struct globals { 59struct globals {
60 char **names; 60 char **names;
61 int cur; 61 int cur;
62 char *cmd[1]; 62 char *cmd[2 /* using 1 provokes compiler warning */];
63} FIX_ALIASING; 63} FIX_ALIASING;
64#define G (*(struct globals*)&bb_common_bufsiz1) 64#define G (*(struct globals*)&bb_common_bufsiz1)
65#define names (G.names) 65#define names (G.names)
diff --git a/docs/keep_data_small.txt b/docs/keep_data_small.txt
index 21d732674..9fc799646 100644
--- a/docs/keep_data_small.txt
+++ b/docs/keep_data_small.txt
@@ -138,13 +138,6 @@ less readable, use #defines:
138#define sector (G.sector) 138#define sector (G.sector)
139 139
140 140
141 Word of caution
142
143If applet doesn't use much of global data, converting it to use
144one of above methods is not worth the resulting code obfuscation.
145If you have less than ~300 bytes of global data - don't bother.
146
147
148 Finding non-shared duplicated strings 141 Finding non-shared duplicated strings
149 142
150strings busybox | sort | uniq -c | sort -nr 143strings busybox | sort | uniq -c | sort -nr
@@ -224,6 +217,14 @@ Result (non-static busybox built against glibc):
224 217
225 Keeping code small 218 Keeping code small
226 219
220Use scripts/bloat-o-meter to check whether introduced changes
221didn't generate unnecessary bloat. This script needs unstripped binaries
222to generate a detailed report. To automate this, just use
223"make bloatcheck". It requires busybox_old binary to be present,
224use "make baseline" to generate it from unmodified source, or
225copy busybox_unstripped to busybox_old before modifying sources
226and rebuilding.
227
227Set CONFIG_EXTRA_CFLAGS="-fno-inline-functions-called-once", 228Set CONFIG_EXTRA_CFLAGS="-fno-inline-functions-called-once",
228produce "make bloatcheck", see the biggest auto-inlined functions. 229produce "make bloatcheck", see the biggest auto-inlined functions.
229Now, set CONFIG_EXTRA_CFLAGS back to "", but add NOINLINE 230Now, set CONFIG_EXTRA_CFLAGS back to "", but add NOINLINE
diff --git a/docs/tcp.txt b/docs/tcp.txt
index 766766387..2000f3110 100644
--- a/docs/tcp.txt
+++ b/docs/tcp.txt
@@ -18,8 +18,11 @@ What will happen if we close the socket?
18 received after close() is called, its TCP SHOULD send a RST 18 received after close() is called, its TCP SHOULD send a RST
19 to show that data was lost." 19 to show that data was lost."
20 20
21IOW: if we just close(sock) now, kernel can reset the TCP connection, 21IOW: if we just close(sock) now, kernel can reset the TCP connection
22discarding some not-yet sent data. 22(send RST packet).
23
24This is problematic for two reasons: it discards some not-yet sent
25data, and it may be reported as error, not EOF, on peer's side.
23 26
24What can be done about it? 27What can be done about it?
25 28
@@ -46,14 +49,14 @@ This makes kernel send FIN after all data is written:
46 49
47However, experiments on Linux 3.9.4 show that kernel can return from 50However, experiments on Linux 3.9.4 show that kernel can return from
48shutdown() and from close() before all data is sent, 51shutdown() and from close() before all data is sent,
49and if peer sends any data to us after this, kernel stll responds with 52and if peer sends any data to us after this, kernel still responds with
50RST before all our data is sent. 53RST before all our data is sent.
51 54
52In practice the protocol in use often does not allow peer to send 55In practice the protocol in use often does not allow peer to send
53such data to us, in which case this solution is acceptable. 56such data to us, in which case this solution is acceptable.
54 57
55If you know that peer is going to close its end after it sees our FIN 58Solution #3: if you know that peer is going to close its end after it sees
56(as EOF), it might be a good idea to perform a read after shutdown(). 59our FIN (as EOF), it might be a good idea to perform a read after shutdown().
57When read finishes with 0-sized result, we conclude that peer received all 60When read finishes with 0-sized result, we conclude that peer received all
58the data, saw EOF, and closed its end. 61the data, saw EOF, and closed its end.
59 62
@@ -61,6 +64,14 @@ However, this incurs small performance penalty (we run for a longer time)
61and requires safeguards (nonblocking reads, timeouts etc) against 64and requires safeguards (nonblocking reads, timeouts etc) against
62malicious peers which don't close the connection. 65malicious peers which don't close the connection.
63 66
67Solutions #1 and #2 can be combined:
68
69 /* ...set up struct linger... then: */
70 setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
71 shutdown(sock, SHUT_WR);
72 /* At this point, kernel sent FIN packet, not RST, to the peer, */
73 /* even if there is buffered read data from the peer. */
74 close(sock);
64 75
65 Defeating Nagle. 76 Defeating Nagle.
66 77
diff --git a/e2fsprogs/old_e2fsprogs/blkid/blkidP.h b/e2fsprogs/old_e2fsprogs/blkid/blkidP.h
index d6b2b42cc..bbadc8eb5 100644
--- a/e2fsprogs/old_e2fsprogs/blkid/blkidP.h
+++ b/e2fsprogs/old_e2fsprogs/blkid/blkidP.h
@@ -179,8 +179,4 @@ extern int blkid_set_tag(blkid_dev dev, const char *name,
179extern blkid_dev blkid_new_dev(void); 179extern blkid_dev blkid_new_dev(void);
180extern void blkid_free_dev(blkid_dev dev); 180extern void blkid_free_dev(blkid_dev dev);
181 181
182#ifdef __cplusplus
183}
184#endif
185
186#endif 182#endif
diff --git a/e2fsprogs/old_e2fsprogs/blkid/cache.c b/e2fsprogs/old_e2fsprogs/blkid/cache.c
index d1d29146b..251e49900 100644
--- a/e2fsprogs/old_e2fsprogs/blkid/cache.c
+++ b/e2fsprogs/old_e2fsprogs/blkid/cache.c
@@ -115,7 +115,7 @@ int main(int argc, char** argv)
115 argv[0], ret); 115 argv[0], ret);
116 exit(1); 116 exit(1);
117 } 117 }
118 if ((ret = blkid_probe_all(cache) < 0)) 118 if ((ret = blkid_probe_all(cache)) < 0)
119 fprintf(stderr, "error probing devices\n"); 119 fprintf(stderr, "error probing devices\n");
120 120
121 blkid_put_cache(cache); 121 blkid_put_cache(cache);
diff --git a/e2fsprogs/old_e2fsprogs/blkid/dev.c b/e2fsprogs/old_e2fsprogs/blkid/dev.c
index bb0cc914a..260e49c65 100644
--- a/e2fsprogs/old_e2fsprogs/blkid/dev.c
+++ b/e2fsprogs/old_e2fsprogs/blkid/dev.c
@@ -153,7 +153,7 @@ extern int optind;
153void usage(char *prog) 153void usage(char *prog)
154{ 154{
155 fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask]\n", prog); 155 fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask]\n", prog);
156 fprintf(stderr, "\tList all devices and exit\n", prog); 156 fprintf(stderr, "\tList all devices and exit\n");
157 exit(1); 157 exit(1);
158} 158}
159 159
@@ -176,7 +176,7 @@ int main(int argc, char **argv)
176 case 'm': 176 case 'm':
177 blkid_debug_mask = strtoul (optarg, &tmp, 0); 177 blkid_debug_mask = strtoul (optarg, &tmp, 0);
178 if (*tmp) { 178 if (*tmp) {
179 fprintf(stderr, "Invalid debug mask: %d\n", 179 fprintf(stderr, "Invalid debug mask: %s\n",
180 optarg); 180 optarg);
181 exit(1); 181 exit(1);
182 } 182 }
diff --git a/e2fsprogs/old_e2fsprogs/blkid/read.c b/e2fsprogs/old_e2fsprogs/blkid/read.c
index f795a5d14..feeda518b 100644
--- a/e2fsprogs/old_e2fsprogs/blkid/read.c
+++ b/e2fsprogs/old_e2fsprogs/blkid/read.c
@@ -385,7 +385,7 @@ void blkid_read_cache(blkid_cache cache)
385 continue; 385 continue;
386 end = strlen(buf) - 1; 386 end = strlen(buf) - 1;
387 /* Continue reading next line if it ends with a backslash */ 387 /* Continue reading next line if it ends with a backslash */
388 while (buf[end] == '\\' && end < sizeof(buf) - 2 && 388 while (end < sizeof(buf) - 2 && buf[end] == '\\' &&
389 fgets(buf + end, sizeof(buf) - end, file)) { 389 fgets(buf + end, sizeof(buf) - end, file)) {
390 end = strlen(buf) - 1; 390 end = strlen(buf) - 1;
391 lineno++; 391 lineno++;
diff --git a/e2fsprogs/old_e2fsprogs/blkid/tag.c b/e2fsprogs/old_e2fsprogs/blkid/tag.c
index 8337b46b6..7424edeb8 100644
--- a/e2fsprogs/old_e2fsprogs/blkid/tag.c
+++ b/e2fsprogs/old_e2fsprogs/blkid/tag.c
@@ -356,7 +356,7 @@ void usage(char *prog)
356 fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device " 356 fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device "
357 "[type value]\n", 357 "[type value]\n",
358 prog); 358 prog);
359 fprintf(stderr, "\tList all tags for a device and exit\n", prog); 359 fprintf(stderr, "\tList all tags for a device and exit\n");
360 exit(1); 360 exit(1);
361} 361}
362 362
@@ -382,7 +382,7 @@ int main(int argc, char **argv)
382 case 'm': 382 case 'm':
383 blkid_debug_mask = strtoul (optarg, &tmp, 0); 383 blkid_debug_mask = strtoul (optarg, &tmp, 0);
384 if (*tmp) { 384 if (*tmp) {
385 fprintf(stderr, "Invalid debug mask: %d\n", 385 fprintf(stderr, "Invalid debug mask: %s\n",
386 optarg); 386 optarg);
387 exit(1); 387 exit(1);
388 } 388 }
@@ -407,7 +407,7 @@ int main(int argc, char **argv)
407 407
408 dev = blkid_get_dev(cache, devname, flags); 408 dev = blkid_get_dev(cache, devname, flags);
409 if (!dev) { 409 if (!dev) {
410 fprintf(stderr, "%s: cannot find device in blkid cache\n"); 410 fprintf(stderr, "%s: cannot find device in blkid cache\n", devname);
411 exit(1); 411 exit(1);
412 } 412 }
413 if (search_type) { 413 if (search_type) {
diff --git a/e2fsprogs/old_e2fsprogs/e2fsck.c b/e2fsprogs/old_e2fsprogs/e2fsck.c
index 373e8ce91..8400a92ce 100644
--- a/e2fsprogs/old_e2fsprogs/e2fsck.c
+++ b/e2fsprogs/old_e2fsprogs/e2fsck.c
@@ -1050,7 +1050,7 @@ static errcode_t ea_refcount_create(int size, ext2_refcount_t *ret)
1050 refcount->size = size; 1050 refcount->size = size;
1051 bytes = (size_t) (size * sizeof(struct ea_refcount_el)); 1051 bytes = (size_t) (size * sizeof(struct ea_refcount_el));
1052#ifdef DEBUG 1052#ifdef DEBUG
1053 printf("Refcount allocated %d entries, %d bytes.\n", 1053 printf("Refcount allocated %d entries, %lu bytes.\n",
1054 refcount->size, bytes); 1054 refcount->size, bytes);
1055#endif 1055#endif
1056 retval = ext2fs_get_mem(bytes, &refcount->list); 1056 retval = ext2fs_get_mem(bytes, &refcount->list);
@@ -3424,7 +3424,7 @@ static void e2fsck_pass1(e2fsck_t ctx)
3424 continue; 3424 continue;
3425 } 3425 }
3426 if ((inode->i_links_count || inode->i_blocks || 3426 if ((inode->i_links_count || inode->i_blocks ||
3427 inode->i_blocks || inode->i_block[0]) && 3427 inode->i_block[0]) &&
3428 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR, 3428 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
3429 &pctx)) { 3429 &pctx)) {
3430 memset(inode, 0, inode_size); 3430 memset(inode, 0, inode_size);
@@ -12195,11 +12195,7 @@ static void swap_filesys(e2fsck_t ctx)
12195void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size, 12195void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size,
12196 const char *description) 12196 const char *description)
12197{ 12197{
12198 void *ret; 12198 return xzalloc(size);
12199 char buf[256];
12200
12201 ret = xzalloc(size);
12202 return ret;
12203} 12199}
12204 12200
12205static char *string_copy(const char *str, int len) 12201static char *string_copy(const char *str, int len)
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c b/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c
index da2d15137..240335b32 100644
--- a/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c
@@ -83,7 +83,7 @@ static int calc_reserved_gdt_blocks(ext2_filsys fs)
83 if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb)) 83 if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
84 rsv_gdb = EXT2_ADDR_PER_BLOCK(sb); 84 rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
85#ifdef RES_GDT_DEBUG 85#ifdef RES_GDT_DEBUG
86 printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %lu\n", 86 printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %u\n",
87 max_blocks, rsv_groups, rsv_gdb); 87 max_blocks, rsv_groups, rsv_gdb);
88#endif 88#endif
89 89
diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c b/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c
index 474f07340..3c95829f0 100644
--- a/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c
+++ b/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c
@@ -544,7 +544,7 @@ static errcode_t unix_read_blk(io_channel channel, unsigned long block,
544 /* If it's in the cache, use it! */ 544 /* If it's in the cache, use it! */
545 if ((cache = find_cached_block(data, block, &reuse[0]))) { 545 if ((cache = find_cached_block(data, block, &reuse[0]))) {
546#ifdef DEBUG 546#ifdef DEBUG
547 printf("Using cached block %d\n", block); 547 printf("Using cached block %lu\n", block);
548#endif 548#endif
549 memcpy(cp, cache->buf, channel->block_size); 549 memcpy(cp, cache->buf, channel->block_size);
550 count--; 550 count--;
@@ -560,7 +560,7 @@ static errcode_t unix_read_blk(io_channel channel, unsigned long block,
560 if (find_cached_block(data, block+i, &reuse[i])) 560 if (find_cached_block(data, block+i, &reuse[i]))
561 break; 561 break;
562#ifdef DEBUG 562#ifdef DEBUG
563 printf("Reading %d blocks starting at %d\n", i, block); 563 printf("Reading %d blocks starting at %lu\n", i, block);
564#endif 564#endif
565 if ((retval = raw_read_blk(channel, data, block, i, cp))) 565 if ((retval = raw_read_blk(channel, data, block, i, cp)))
566 return retval; 566 return retval;
diff --git a/e2fsprogs/old_e2fsprogs/fsck.c b/e2fsprogs/old_e2fsprogs/fsck.c
index 3a0743bb1..91cce970c 100644
--- a/e2fsprogs/old_e2fsprogs/fsck.c
+++ b/e2fsprogs/old_e2fsprogs/fsck.c
@@ -1239,7 +1239,6 @@ static void PRS(int argc, char **argv)
1239 progress_fd = 0; 1239 progress_fd = 0;
1240 else { 1240 else {
1241 goto next_arg; 1241 goto next_arg;
1242 i++;
1243 } 1242 }
1244 } 1243 }
1245 break; 1244 break;
diff --git a/e2fsprogs/old_e2fsprogs/mke2fs.c b/e2fsprogs/old_e2fsprogs/mke2fs.c
index 35d717a55..ebcb46cf2 100644
--- a/e2fsprogs/old_e2fsprogs/mke2fs.c
+++ b/e2fsprogs/old_e2fsprogs/mke2fs.c
@@ -239,7 +239,7 @@ static void test_disk(ext2_filsys fs, badblocks_list *bb_list)
239 errcode_t retval; 239 errcode_t retval;
240 char buf[1024]; 240 char buf[1024];
241 241
242 sprintf(buf, "badblocks -b %d %s%s%s %d", fs->blocksize, 242 sprintf(buf, "badblocks -b %u %s%s%s %d", fs->blocksize,
243 quiet ? "" : "-s ", (cflag > 1) ? "-w " : "", 243 quiet ? "" : "-s ", (cflag > 1) ? "-w " : "",
244 fs->device_name, fs->super->s_blocks_count); 244 fs->device_name, fs->super->s_blocks_count);
245 mke2fs_verbose("Running command: %s\n", buf); 245 mke2fs_verbose("Running command: %s\n", buf);
@@ -385,7 +385,7 @@ static errcode_t zero_blocks(ext2_filsys fs, blk_t blk, int num,
385 struct progress_struct *progress, 385 struct progress_struct *progress,
386 blk_t *ret_blk, int *ret_count) 386 blk_t *ret_blk, int *ret_count)
387{ 387{
388 int j, count, next_update, next_update_incr; 388 int j, count, next_update;
389 static char *buf; 389 static char *buf;
390 errcode_t retval; 390 errcode_t retval;
391 391
@@ -403,9 +403,7 @@ static errcode_t zero_blocks(ext2_filsys fs, blk_t blk, int num,
403 } 403 }
404 /* OK, do the write loop */ 404 /* OK, do the write loop */
405 next_update = 0; 405 next_update = 0;
406 next_update_incr = num / 100; 406
407 if (next_update_incr < 1)
408 next_update_incr = 1;
409 for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) { 407 for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
410 count = num - j; 408 count = num - j;
411 if (count > STRIDE_LENGTH) 409 if (count > STRIDE_LENGTH)
diff --git a/e2fsprogs/old_e2fsprogs/tune2fs.c b/e2fsprogs/old_e2fsprogs/tune2fs.c
index 3c3f4afa5..bbe30e5a0 100644
--- a/e2fsprogs/old_e2fsprogs/tune2fs.c
+++ b/e2fsprogs/old_e2fsprogs/tune2fs.c
@@ -607,7 +607,7 @@ int tune2fs_main(int argc, char **argv)
607 if (e_flag) { 607 if (e_flag) {
608 sb->s_errors = errors; 608 sb->s_errors = errors;
609 ext2fs_mark_super_dirty(fs); 609 ext2fs_mark_super_dirty(fs);
610 printf("Setting error behavior to %d\n", errors); 610 printf("Setting error behavior to %u\n", errors);
611 } 611 }
612 if (g_flag) { 612 if (g_flag) {
613 sb->s_def_resgid = resgid; 613 sb->s_def_resgid = resgid;
diff --git a/e2fsprogs/old_e2fsprogs/util.c b/e2fsprogs/old_e2fsprogs/util.c
index a61abc2c6..3e7ee8e75 100644
--- a/e2fsprogs/old_e2fsprogs/util.c
+++ b/e2fsprogs/old_e2fsprogs/util.c
@@ -117,7 +117,7 @@ void parse_journal_opts(char **journal_device, int *journal_flags,
117 } 117 }
118 if (strcmp(token, "device") == 0) { 118 if (strcmp(token, "device") == 0) {
119 *journal_device = blkid_get_devname(NULL, arg, NULL); 119 *journal_device = blkid_get_devname(NULL, arg, NULL);
120 if (!journal_device) { 120 if (!*journal_device) {
121 journal_usage++; 121 journal_usage++;
122 continue; 122 continue;
123 } 123 }
@@ -239,7 +239,7 @@ void make_journal_blocks(ext2_filsys fs, int journal_size, int journal_flags, in
239 return; 239 return;
240 } 240 }
241 if (!quiet) 241 if (!quiet)
242 printf("Creating journal (%ld blocks): ", journal_blocks); 242 printf("Creating journal (%lu blocks): ", journal_blocks);
243 fflush(stdout); 243 fflush(stdout);
244 retval = ext2fs_add_journal_inode(fs, journal_blocks, 244 retval = ext2fs_add_journal_inode(fs, journal_blocks,
245 journal_flags); 245 journal_flags);
diff --git a/editors/Config.src b/editors/Config.src
index af1e1de5e..c6e9d92af 100644
--- a/editors/Config.src
+++ b/editors/Config.src
@@ -7,66 +7,6 @@ menu "Editors"
7 7
8INSERT 8INSERT
9 9
10config AWK
11 bool "awk"
12 default y
13 help
14 Awk is used as a pattern scanning and processing language. This is
15 the BusyBox implementation of that programming language.
16
17config FEATURE_AWK_LIBM
18 bool "Enable math functions (requires libm)"
19 default y
20 depends on AWK
21 help
22 Enable math functions of the Awk programming language.
23 NOTE: This will require libm to be present for linking.
24
25config CMP
26 bool "cmp"
27 default y
28 help
29 cmp is used to compare two files and returns the result
30 to standard output.
31
32config DIFF
33 bool "diff"
34 default y
35 help
36 diff compares two files or directories and outputs the
37 differences between them in a form that can be given to
38 the patch command.
39
40config FEATURE_DIFF_LONG_OPTIONS
41 bool "Enable long options"
42 default y
43 depends on DIFF && LONG_OPTS
44 help
45 Enable use of long options.
46
47config FEATURE_DIFF_DIR
48 bool "Enable directory support"
49 default y
50 depends on DIFF
51 help
52 This option enables support for directory and subdirectory
53 comparison.
54
55config ED
56 bool "ed"
57 default y
58 help
59 The original 1970's Unix text editor, from the days of teletypes.
60 Small, simple, evil. Part of SUSv3. If you're not already using
61 this, you don't need it.
62
63config SED
64 bool "sed"
65 default y
66 help
67 sed is used to perform text transformations on a file
68 or input from a pipeline.
69
70config FEATURE_ALLOW_EXEC 10config FEATURE_ALLOW_EXEC
71 bool "Allow vi and awk to execute shell commands" 11 bool "Allow vi and awk to execute shell commands"
72 default y 12 default y
diff --git a/editors/Kbuild.src b/editors/Kbuild.src
index 8888cba12..6b4fb7470 100644
--- a/editors/Kbuild.src
+++ b/editors/Kbuild.src
@@ -7,8 +7,3 @@
7lib-y:= 7lib-y:=
8 8
9INSERT 9INSERT
10lib-$(CONFIG_AWK) += awk.o
11lib-$(CONFIG_CMP) += cmp.o
12lib-$(CONFIG_DIFF) += diff.o
13lib-$(CONFIG_ED) += ed.o
14lib-$(CONFIG_SED) += sed.o
diff --git a/editors/awk.c b/editors/awk.c
index 77784dfc1..d0e3781e7 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -7,12 +7,45 @@
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//config:config AWK
11//config: bool "awk"
12//config: default y
13//config: help
14//config: Awk is used as a pattern scanning and processing language. This is
15//config: the BusyBox implementation of that programming language.
16//config:
17//config:config FEATURE_AWK_LIBM
18//config: bool "Enable math functions (requires libm)"
19//config: default y
20//config: depends on AWK
21//config: help
22//config: Enable math functions of the Awk programming language.
23//config: NOTE: This will require libm to be present for linking.
24//config:
25//config:config FEATURE_AWK_GNU_EXTENSIONS
26//config: bool "Enable a few GNU extensions"
27//config: default y
28//config: depends on AWK
29//config: help
30//config: Enable a few features from gawk:
31//config: * command line option -e AWK_PROGRAM
32//config: * simultaneous use of -f and -e on the command line.
33//config: This enables the use of awk library files.
34//config: Ex: awk -f mylib.awk -e '{print myfunction($1);}' ...
35
36//applet:IF_AWK(APPLET_NOEXEC(awk, awk, BB_DIR_USR_BIN, BB_SUID_DROP, awk))
37
38//kbuild:lib-$(CONFIG_AWK) += awk.o
39
10//usage:#define awk_trivial_usage 40//usage:#define awk_trivial_usage
11//usage: "[OPTIONS] [AWK_PROGRAM] [FILE]..." 41//usage: "[OPTIONS] [AWK_PROGRAM] [FILE]..."
12//usage:#define awk_full_usage "\n\n" 42//usage:#define awk_full_usage "\n\n"
13//usage: " -v VAR=VAL Set variable" 43//usage: " -v VAR=VAL Set variable"
14//usage: "\n -F SEP Use SEP as field separator" 44//usage: "\n -F SEP Use SEP as field separator"
15//usage: "\n -f FILE Read program from FILE" 45//usage: "\n -f FILE Read program from FILE"
46//usage: IF_FEATURE_AWK_GNU_EXTENSIONS(
47//usage: "\n -e AWK_PROGRAM"
48//usage: )
16 49
17#include "libbb.h" 50#include "libbb.h"
18#include "xregex.h" 51#include "xregex.h"
@@ -38,6 +71,25 @@
38#endif 71#endif
39 72
40 73
74#define OPTSTR_AWK \
75 "F:v:f:" \
76 IF_FEATURE_AWK_GNU_EXTENSIONS("e:") \
77 "W:"
78#define OPTCOMPLSTR_AWK \
79 "v::f::" \
80 IF_FEATURE_AWK_GNU_EXTENSIONS("e::")
81enum {
82 OPTBIT_F, /* define field separator */
83 OPTBIT_v, /* define variable */
84 OPTBIT_f, /* pull in awk program from file */
85 IF_FEATURE_AWK_GNU_EXTENSIONS(OPTBIT_e,) /* -e AWK_PROGRAM */
86 OPTBIT_W, /* -W ignored */
87 OPT_F = 1 << OPTBIT_F,
88 OPT_v = 1 << OPTBIT_v,
89 OPT_f = 1 << OPTBIT_f,
90 OPT_e = IF_FEATURE_AWK_GNU_EXTENSIONS((1 << OPTBIT_e)) + 0,
91 OPT_W = 1 << OPTBIT_W
92};
41 93
42#define MAXVARFMT 240 94#define MAXVARFMT 240
43#define MINNVBLOCK 64 95#define MINNVBLOCK 64
@@ -2784,8 +2836,16 @@ static var *evaluate(node *op, var *res)
2784 break; 2836 break;
2785 2837
2786 case F_le: 2838 case F_le:
2787 if (!op1) 2839 debug_printf_eval("length: L.s:'%s'\n", L.s);
2840 if (!op1) {
2788 L.s = getvar_s(intvar[F0]); 2841 L.s = getvar_s(intvar[F0]);
2842 debug_printf_eval("length: L.s='%s'\n", L.s);
2843 }
2844 else if (L.v->type & VF_ARRAY) {
2845 R_d = L.v->x.array->nel;
2846 debug_printf_eval("length: array_len:%d\n", L.v->x.array->nel);
2847 break;
2848 }
2789 R_d = strlen(L.s); 2849 R_d = strlen(L.s);
2790 break; 2850 break;
2791 2851
@@ -3079,6 +3139,9 @@ int awk_main(int argc, char **argv)
3079 char *opt_F; 3139 char *opt_F;
3080 llist_t *list_v = NULL; 3140 llist_t *list_v = NULL;
3081 llist_t *list_f = NULL; 3141 llist_t *list_f = NULL;
3142#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
3143 llist_t *list_e = NULL;
3144#endif
3082 int i, j; 3145 int i, j;
3083 var *v; 3146 var *v;
3084 var tv; 3147 var tv;
@@ -3137,47 +3200,51 @@ int awk_main(int argc, char **argv)
3137 *s1 = '='; 3200 *s1 = '=';
3138 } 3201 }
3139 } 3202 }
3140 opt_complementary = "v::f::"; /* -v and -f can occur multiple times */ 3203 opt_complementary = OPTCOMPLSTR_AWK;
3141 opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL); 3204 opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL);
3142 argv += optind; 3205 argv += optind;
3143 argc -= optind; 3206 argc -= optind;
3144 if (opt & 0x1) { /* -F */ 3207 if (opt & OPT_W)
3208 bb_error_msg("warning: option -W is ignored");
3209 if (opt & OPT_F) {
3145 unescape_string_in_place(opt_F); 3210 unescape_string_in_place(opt_F);
3146 setvar_s(intvar[FS], opt_F); 3211 setvar_s(intvar[FS], opt_F);
3147 } 3212 }
3148 while (list_v) { /* -v */ 3213 while (list_v) {
3149 if (!is_assignment(llist_pop(&list_v))) 3214 if (!is_assignment(llist_pop(&list_v)))
3150 bb_show_usage(); 3215 bb_show_usage();
3151 } 3216 }
3152 if (list_f) { /* -f */ 3217 while (list_f) {
3153 do { 3218 char *s = NULL;
3154 char *s = NULL; 3219 FILE *from_file;
3155 FILE *from_file; 3220
3156 3221 g_progname = llist_pop(&list_f);
3157 g_progname = llist_pop(&list_f); 3222 from_file = xfopen_stdin(g_progname);
3158 from_file = xfopen_stdin(g_progname); 3223 /* one byte is reserved for some trick in next_token */
3159 /* one byte is reserved for some trick in next_token */ 3224 for (i = j = 1; j > 0; i += j) {
3160 for (i = j = 1; j > 0; i += j) { 3225 s = xrealloc(s, i + 4096);
3161 s = xrealloc(s, i + 4096); 3226 j = fread(s + i, 1, 4094, from_file);
3162 j = fread(s + i, 1, 4094, from_file); 3227 }
3163 } 3228 s[i] = '\0';
3164 s[i] = '\0'; 3229 fclose(from_file);
3165 fclose(from_file); 3230 parse_program(s + 1);
3166 parse_program(s + 1); 3231 free(s);
3167 free(s); 3232 }
3168 } while (list_f); 3233 g_progname = "cmd. line";
3169 argc++; 3234#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
3170 } else { // no -f: take program from 1st parameter 3235 while (list_e) {
3171 if (!argc) 3236 parse_program(llist_pop(&list_e));
3237 }
3238#endif
3239 if (!(opt & (OPT_f | OPT_e))) {
3240 if (!*argv)
3172 bb_show_usage(); 3241 bb_show_usage();
3173 g_progname = "cmd. line";
3174 parse_program(*argv++); 3242 parse_program(*argv++);
3243 argc--;
3175 } 3244 }
3176 if (opt & 0x8) // -W
3177 bb_error_msg("warning: option -W is ignored");
3178 3245
3179 /* fill in ARGV array */ 3246 /* fill in ARGV array */
3180 setvar_i(intvar[ARGC], argc); 3247 setvar_i(intvar[ARGC], argc + 1);
3181 setari_u(intvar[ARGV], 0, "awk"); 3248 setari_u(intvar[ARGV], 0, "awk");
3182 i = 0; 3249 i = 0;
3183 while (*argv) 3250 while (*argv)
diff --git a/editors/cmp.c b/editors/cmp.c
index fbe6b9753..a4af6f480 100644
--- a/editors/cmp.c
+++ b/editors/cmp.c
@@ -10,6 +10,17 @@
10/* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */ 10/* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */
11/* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */ 11/* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */
12 12
13//config:config CMP
14//config: bool "cmp"
15//config: default y
16//config: help
17//config: cmp is used to compare two files and returns the result
18//config: to standard output.
19
20//kbuild:lib-$(CONFIG_CMP) += cmp.o
21
22//applet:IF_CMP(APPLET(cmp, BB_DIR_USR_BIN, BB_SUID_DROP))
23
13//usage:#define cmp_trivial_usage 24//usage:#define cmp_trivial_usage
14//usage: "[-l] [-s] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]" 25//usage: "[-l] [-s] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]"
15//usage:#define cmp_full_usage "\n\n" 26//usage:#define cmp_full_usage "\n\n"
diff --git a/editors/diff.c b/editors/diff.c
index b08ded3a1..a78a0ee28 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -76,6 +76,33 @@
76 * 6n words for files of length n. 76 * 6n words for files of length n.
77 */ 77 */
78 78
79//config:config DIFF
80//config: bool "diff"
81//config: default y
82//config: help
83//config: diff compares two files or directories and outputs the
84//config: differences between them in a form that can be given to
85//config: the patch command.
86//config:
87//config:config FEATURE_DIFF_LONG_OPTIONS
88//config: bool "Enable long options"
89//config: default y
90//config: depends on DIFF && LONG_OPTS
91//config: help
92//config: Enable use of long options.
93//config:
94//config:config FEATURE_DIFF_DIR
95//config: bool "Enable directory support"
96//config: default y
97//config: depends on DIFF
98//config: help
99//config: This option enables support for directory and subdirectory
100//config: comparison.
101
102//kbuild:lib-$(CONFIG_DIFF) += diff.o
103
104//applet:IF_DIFF(APPLET(diff, BB_DIR_USR_BIN, BB_SUID_DROP))
105
79//usage:#define diff_trivial_usage 106//usage:#define diff_trivial_usage
80//usage: "[-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2" 107//usage: "[-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2"
81//usage:#define diff_full_usage "\n\n" 108//usage:#define diff_full_usage "\n\n"
diff --git a/editors/ed.c b/editors/ed.c
index dbb51306c..3087fb0b9 100644
--- a/editors/ed.c
+++ b/editors/ed.c
@@ -7,6 +7,18 @@
7 * The "ed" built-in command (much simplified) 7 * The "ed" built-in command (much simplified)
8 */ 8 */
9 9
10//config:config ED
11//config: bool "ed"
12//config: default y
13//config: help
14//config: The original 1970's Unix text editor, from the days of teletypes.
15//config: Small, simple, evil. Part of SUSv3. If you're not already using
16//config: this, you don't need it.
17
18//kbuild:lib-$(CONFIG_ED) += ed.o
19
20//applet:IF_ED(APPLET(ed, BB_DIR_BIN, BB_SUID_DROP))
21
10//usage:#define ed_trivial_usage "" 22//usage:#define ed_trivial_usage ""
11//usage:#define ed_full_usage "" 23//usage:#define ed_full_usage ""
12 24
diff --git a/editors/patch_bbox.c b/editors/patch_bbox.c
index 78aa5fde8..aae7b7987 100644
--- a/editors/patch_bbox.c
+++ b/editors/patch_bbox.c
@@ -188,8 +188,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
188 unsigned src_last_line = 1; 188 unsigned src_last_line = 1;
189 unsigned dst_last_line = 1; 189 unsigned dst_last_line = 1;
190 190
191 if ((sscanf(patch_line, "@@ -%d,%d +%d,%d", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3) 191 if ((sscanf(patch_line, "@@ -%u,%u +%u,%u", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3)
192 && (sscanf(patch_line, "@@ -%d +%d,%d", &src_beg_line, &dst_beg_line, &dst_last_line) < 2) 192 && (sscanf(patch_line, "@@ -%u +%u,%u", &src_beg_line, &dst_beg_line, &dst_last_line) < 2)
193 ) { 193 ) {
194 /* No more hunks for this file */ 194 /* No more hunks for this file */
195 break; 195 break;
diff --git a/editors/sed.c b/editors/sed.c
index 3a0d917aa..e18e48ab5 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -23,9 +23,6 @@
23 * resulting sed_cmd_t structures are appended to a linked list 23 * resulting sed_cmd_t structures are appended to a linked list
24 * (G.sed_cmd_head/G.sed_cmd_tail). 24 * (G.sed_cmd_head/G.sed_cmd_tail).
25 * 25 *
26 * add_input_file() adds a FILE* to the list of input files. We need to
27 * know all input sources ahead of time to find the last line for the $ match.
28 *
29 * process_files() does actual sedding, reading data lines from each input FILE* 26 * process_files() does actual sedding, reading data lines from each input FILE*
30 * (which could be stdin) and applying the sed command list (sed_cmd_head) to 27 * (which could be stdin) and applying the sed command list (sed_cmd_head) to
31 * each of the resulting lines. 28 * each of the resulting lines.
@@ -58,16 +55,27 @@
58 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html 55 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html
59 */ 56 */
60 57
58//config:config SED
59//config: bool "sed"
60//config: default y
61//config: help
62//config: sed is used to perform text transformations on a file
63//config: or input from a pipeline.
64
65//kbuild:lib-$(CONFIG_SED) += sed.o
66
67//applet:IF_SED(APPLET(sed, BB_DIR_BIN, BB_SUID_DROP))
68
61//usage:#define sed_trivial_usage 69//usage:#define sed_trivial_usage
62//usage: "[-inr] [-f FILE]... [-e CMD]... [FILE]...\n" 70//usage: "[-inrE] [-f FILE]... [-e CMD]... [FILE]...\n"
63//usage: "or: sed [-inr] CMD [FILE]..." 71//usage: "or: sed [-inrE] CMD [FILE]..."
64//usage:#define sed_full_usage "\n\n" 72//usage:#define sed_full_usage "\n\n"
65//usage: " -e CMD Add CMD to sed commands to be executed" 73//usage: " -e CMD Add CMD to sed commands to be executed"
66//usage: "\n -f FILE Add FILE contents to sed commands to be executed" 74//usage: "\n -f FILE Add FILE contents to sed commands to be executed"
67//usage: "\n -i[SFX] Edit files in-place (otherwise sends to stdout)" 75//usage: "\n -i[SFX] Edit files in-place (otherwise sends to stdout)"
68//usage: "\n Optionally back files up, appending SFX" 76//usage: "\n Optionally back files up, appending SFX"
69//usage: "\n -n Suppress automatic printing of pattern space" 77//usage: "\n -n Suppress automatic printing of pattern space"
70//usage: "\n -r Use extended regex syntax" 78//usage: "\n -r,-E Use extended regex syntax"
71//usage: "\n" 79//usage: "\n"
72//usage: "\nIf no -e or -f, the first non-option argument is the sed command string." 80//usage: "\nIf no -e or -f, the first non-option argument is the sed command string."
73//usage: "\nRemaining arguments are input files (stdin if none)." 81//usage: "\nRemaining arguments are input files (stdin if none)."
@@ -124,12 +132,15 @@ static const char semicolon_whitespace[] ALIGN1 = "; \n\r\t\v";
124struct globals { 132struct globals {
125 /* options */ 133 /* options */
126 int be_quiet, regex_type; 134 int be_quiet, regex_type;
135
127 FILE *nonstdout; 136 FILE *nonstdout;
128 char *outname, *hold_space; 137 char *outname, *hold_space;
138 smallint exitcode;
129 139
130 /* List of input files */ 140 /* list of input files */
131 int input_file_count, current_input_file; 141 int current_input_file, last_input_file;
132 FILE **input_file_list; 142 char **input_file_list;
143 FILE *current_fp;
133 144
134 regmatch_t regmatch[10]; 145 regmatch_t regmatch[10];
135 regex_t *previous_regex_ptr; 146 regex_t *previous_regex_ptr;
@@ -137,7 +148,7 @@ struct globals {
137 /* linked list of sed commands */ 148 /* linked list of sed commands */
138 sed_cmd_t *sed_cmd_head, **sed_cmd_tail; 149 sed_cmd_t *sed_cmd_head, **sed_cmd_tail;
139 150
140 /* Linked list of append lines */ 151 /* linked list of append lines */
141 llist_t *append_head; 152 llist_t *append_head;
142 153
143 char *add_cmd_line; 154 char *add_cmd_line;
@@ -189,8 +200,8 @@ static void sed_free_and_close_stuff(void)
189 200
190 free(G.hold_space); 201 free(G.hold_space);
191 202
192 while (G.current_input_file < G.input_file_count) 203 if (G.current_fp)
193 fclose(G.input_file_list[G.current_input_file++]); 204 fclose(G.current_fp);
194} 205}
195#else 206#else
196void sed_free_and_close_stuff(void); 207void sed_free_and_close_stuff(void);
@@ -370,7 +381,7 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
370 381
371 /* 382 /*
372 * A substitution command should look something like this: 383 * A substitution command should look something like this:
373 * s/match/replace/ #gIpw 384 * s/match/replace/ #giIpw
374 * || | ||| 385 * || | |||
375 * mandatory optional 386 * mandatory optional
376 */ 387 */
@@ -418,6 +429,7 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
418 break; 429 break;
419 } 430 }
420 /* Ignore case (gnu exension) */ 431 /* Ignore case (gnu exension) */
432 case 'i':
421 case 'I': 433 case 'I':
422 cflags |= REG_ICASE; 434 cflags |= REG_ICASE;
423 break; 435 break;
@@ -848,46 +860,100 @@ static sed_cmd_t *branch_to(char *label)
848 860
849static void append(char *s) 861static void append(char *s)
850{ 862{
851 llist_add_to_end(&G.append_head, xstrdup(s)); 863 llist_add_to_end(&G.append_head, s);
852} 864}
853 865
854static void flush_append(void) 866/* Output line of text. */
867/* Note:
868 * The tricks with NO_EOL_CHAR and last_puts_char are there to emulate gnu sed.
869 * Without them, we had this:
870 * echo -n thingy >z1
871 * echo -n again >z2
872 * >znull
873 * sed "s/i/z/" z1 z2 znull | hexdump -vC
874 * output:
875 * gnu sed 4.1.5:
876 * 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn|
877 * bbox:
878 * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn|
879 */
880enum {
881 NO_EOL_CHAR = 1,
882 LAST_IS_NUL = 2,
883};
884static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char last_gets_char)
885{
886 char lpc = *last_puts_char;
887
888 /* Need to insert a '\n' between two files because first file's
889 * last line wasn't terminated? */
890 if (lpc != '\n' && lpc != '\0') {
891 fputc('\n', file);
892 lpc = '\n';
893 }
894 fputs(s, file);
895
896 /* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */
897 if (s[0])
898 lpc = 'x';
899
900 /* had trailing '\0' and it was last char of file? */
901 if (last_gets_char == LAST_IS_NUL) {
902 fputc('\0', file);
903 lpc = 'x'; /* */
904 } else
905 /* had trailing '\n' or '\0'? */
906 if (last_gets_char != NO_EOL_CHAR) {
907 fputc(last_gets_char, file);
908 lpc = last_gets_char;
909 }
910
911 if (ferror(file)) {
912 xfunc_error_retval = 4; /* It's what gnu sed exits with... */
913 bb_error_msg_and_die(bb_msg_write_error);
914 }
915 *last_puts_char = lpc;
916}
917
918static void flush_append(char *last_puts_char, char last_gets_char)
855{ 919{
856 char *data; 920 char *data;
857 921
858 /* Output appended lines. */ 922 /* Output appended lines. */
859 while ((data = (char *)llist_pop(&G.append_head))) { 923 while ((data = (char *)llist_pop(&G.append_head))) {
860 fprintf(G.nonstdout, "%s\n", data); 924 puts_maybe_newline(data, G.nonstdout, last_puts_char, last_gets_char);
861 free(data); 925 free(data);
862 } 926 }
863} 927}
864 928
865static void add_input_file(FILE *file)
866{
867 G.input_file_list = xrealloc_vector(G.input_file_list, 2, G.input_file_count);
868 G.input_file_list[G.input_file_count++] = file;
869}
870
871/* Get next line of input from G.input_file_list, flushing append buffer and 929/* Get next line of input from G.input_file_list, flushing append buffer and
872 * noting if we ran out of files without a newline on the last line we read. 930 * noting if we ran out of files without a newline on the last line we read.
873 */ 931 */
874enum { 932static char *get_next_line(char *gets_char, char *last_puts_char, char last_gets_char)
875 NO_EOL_CHAR = 1,
876 LAST_IS_NUL = 2,
877};
878static char *get_next_line(char *gets_char)
879{ 933{
880 char *temp = NULL; 934 char *temp = NULL;
881 int len; 935 int len;
882 char gc; 936 char gc;
883 937
884 flush_append(); 938 flush_append(last_puts_char, last_gets_char);
885 939
886 /* will be returned if last line in the file 940 /* will be returned if last line in the file
887 * doesn't end with either '\n' or '\0' */ 941 * doesn't end with either '\n' or '\0' */
888 gc = NO_EOL_CHAR; 942 gc = NO_EOL_CHAR;
889 while (G.current_input_file < G.input_file_count) { 943 for (; G.current_input_file <= G.last_input_file; G.current_input_file++) {
890 FILE *fp = G.input_file_list[G.current_input_file]; 944 FILE *fp = G.current_fp;
945 if (!fp) {
946 const char *path = G.input_file_list[G.current_input_file];
947 fp = stdin;
948 if (path != bb_msg_standard_input) {
949 fp = fopen_or_warn(path, "r");
950 if (!fp) {
951 G.exitcode = EXIT_FAILURE;
952 continue;
953 }
954 }
955 G.current_fp = fp;
956 }
891 /* Read line up to a newline or NUL byte, inclusive, 957 /* Read line up to a newline or NUL byte, inclusive,
892 * return malloc'ed char[]. length of the chunk read 958 * return malloc'ed char[]. length of the chunk read
893 * is stored in len. NULL if EOF/error */ 959 * is stored in len. NULL if EOF/error */
@@ -918,61 +984,13 @@ static char *get_next_line(char *gets_char)
918 * (note: *no* newline after "b bang"!) */ 984 * (note: *no* newline after "b bang"!) */
919 } 985 }
920 /* Close this file and advance to next one */ 986 /* Close this file and advance to next one */
921 fclose(fp); 987 fclose_if_not_stdin(fp);
922 G.current_input_file++; 988 G.current_fp = NULL;
923 } 989 }
924 *gets_char = gc; 990 *gets_char = gc;
925 return temp; 991 return temp;
926} 992}
927 993
928/* Output line of text. */
929/* Note:
930 * The tricks with NO_EOL_CHAR and last_puts_char are there to emulate gnu sed.
931 * Without them, we had this:
932 * echo -n thingy >z1
933 * echo -n again >z2
934 * >znull
935 * sed "s/i/z/" z1 z2 znull | hexdump -vC
936 * output:
937 * gnu sed 4.1.5:
938 * 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn|
939 * bbox:
940 * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn|
941 */
942static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char last_gets_char)
943{
944 char lpc = *last_puts_char;
945
946 /* Need to insert a '\n' between two files because first file's
947 * last line wasn't terminated? */
948 if (lpc != '\n' && lpc != '\0') {
949 fputc('\n', file);
950 lpc = '\n';
951 }
952 fputs(s, file);
953
954 /* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */
955 if (s[0])
956 lpc = 'x';
957
958 /* had trailing '\0' and it was last char of file? */
959 if (last_gets_char == LAST_IS_NUL) {
960 fputc('\0', file);
961 lpc = 'x'; /* */
962 } else
963 /* had trailing '\n' or '\0'? */
964 if (last_gets_char != NO_EOL_CHAR) {
965 fputc(last_gets_char, file);
966 lpc = last_gets_char;
967 }
968
969 if (ferror(file)) {
970 xfunc_error_retval = 4; /* It's what gnu sed exits with... */
971 bb_error_msg_and_die(bb_msg_write_error);
972 }
973 *last_puts_char = lpc;
974}
975
976#define sed_puts(s, n) (puts_maybe_newline(s, G.nonstdout, &last_puts_char, n)) 994#define sed_puts(s, n) (puts_maybe_newline(s, G.nonstdout, &last_puts_char, n))
977 995
978static int beg_match(sed_cmd_t *sed_cmd, const char *pattern_space) 996static int beg_match(sed_cmd_t *sed_cmd, const char *pattern_space)
@@ -995,7 +1013,7 @@ static void process_files(void)
995 int substituted; 1013 int substituted;
996 1014
997 /* Prime the pump */ 1015 /* Prime the pump */
998 next_line = get_next_line(&next_gets_char); 1016 next_line = get_next_line(&next_gets_char, &last_puts_char, '\n' /*last_gets_char*/);
999 1017
1000 /* Go through every line in each file */ 1018 /* Go through every line in each file */
1001 again: 1019 again:
@@ -1009,7 +1027,7 @@ static void process_files(void)
1009 1027
1010 /* Read one line in advance so we can act on the last line, 1028 /* Read one line in advance so we can act on the last line,
1011 * the '$' address */ 1029 * the '$' address */
1012 next_line = get_next_line(&next_gets_char); 1030 next_line = get_next_line(&next_gets_char, &last_puts_char, last_gets_char);
1013 linenum++; 1031 linenum++;
1014 1032
1015 /* For every line, go through all the commands */ 1033 /* For every line, go through all the commands */
@@ -1181,7 +1199,7 @@ static void process_files(void)
1181 1199
1182 /* Append line to linked list to be printed later */ 1200 /* Append line to linked list to be printed later */
1183 case 'a': 1201 case 'a':
1184 append(sed_cmd->string); 1202 append(xstrdup(sed_cmd->string));
1185 break; 1203 break;
1186 1204
1187 /* Insert text before this line */ 1205 /* Insert text before this line */
@@ -1203,11 +1221,10 @@ static void process_files(void)
1203 rfile = fopen_for_read(sed_cmd->string); 1221 rfile = fopen_for_read(sed_cmd->string);
1204 if (rfile) { 1222 if (rfile) {
1205 char *line; 1223 char *line;
1206
1207 while ((line = xmalloc_fgetline(rfile)) 1224 while ((line = xmalloc_fgetline(rfile))
1208 != NULL) 1225 != NULL)
1209 append(line); 1226 append(line);
1210 xprint_and_close_file(rfile); 1227 fclose(rfile);
1211 } 1228 }
1212 1229
1213 break; 1230 break;
@@ -1228,7 +1245,7 @@ static void process_files(void)
1228 free(pattern_space); 1245 free(pattern_space);
1229 pattern_space = next_line; 1246 pattern_space = next_line;
1230 last_gets_char = next_gets_char; 1247 last_gets_char = next_gets_char;
1231 next_line = get_next_line(&next_gets_char); 1248 next_line = get_next_line(&next_gets_char, &last_puts_char, last_gets_char);
1232 substituted = 0; 1249 substituted = 0;
1233 linenum++; 1250 linenum++;
1234 break; 1251 break;
@@ -1264,7 +1281,7 @@ static void process_files(void)
1264 pattern_space[len] = '\n'; 1281 pattern_space[len] = '\n';
1265 strcpy(pattern_space + len+1, next_line); 1282 strcpy(pattern_space + len+1, next_line);
1266 last_gets_char = next_gets_char; 1283 last_gets_char = next_gets_char;
1267 next_line = get_next_line(&next_gets_char); 1284 next_line = get_next_line(&next_gets_char, &last_puts_char, last_gets_char);
1268 linenum++; 1285 linenum++;
1269 break; 1286 break;
1270 } 1287 }
@@ -1368,7 +1385,7 @@ static void process_files(void)
1368 1385
1369 /* Delete and such jump here. */ 1386 /* Delete and such jump here. */
1370 discard_line: 1387 discard_line:
1371 flush_append(); 1388 flush_append(&last_puts_char, last_gets_char);
1372 free(pattern_space); 1389 free(pattern_space);
1373 1390
1374 goto again; 1391 goto again;
@@ -1413,8 +1430,6 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1413 "file\0" Required_argument "f"; 1430 "file\0" Required_argument "f";
1414#endif 1431#endif
1415 1432
1416 int status = EXIT_SUCCESS;
1417
1418 INIT_G(); 1433 INIT_G();
1419 1434
1420 /* destroy command strings on exit */ 1435 /* destroy command strings on exit */
@@ -1435,15 +1450,21 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1435 IF_LONG_OPTS(applet_long_options = sed_longopts); 1450 IF_LONG_OPTS(applet_long_options = sed_longopts);
1436 1451
1437 /* -i must be first, to match OPT_in_place definition */ 1452 /* -i must be first, to match OPT_in_place definition */
1438 opt = getopt32(argv, "i::rne:f:", &opt_i, &opt_e, &opt_f, 1453 /* -E is a synonym of -r:
1454 * GNU sed 4.2.1 mentions it in neither --help
1455 * nor manpage, but does recognize it.
1456 */
1457 opt = getopt32(argv, "i::rEne:f:", &opt_i, &opt_e, &opt_f,
1439 &G.be_quiet); /* counter for -n */ 1458 &G.be_quiet); /* counter for -n */
1440 //argc -= optind; 1459 //argc -= optind;
1441 argv += optind; 1460 argv += optind;
1442 if (opt & OPT_in_place) { // -i 1461 if (opt & OPT_in_place) { // -i
1443 atexit(cleanup_outname); 1462 atexit(cleanup_outname);
1444 } 1463 }
1445 if (opt & 0x2) G.regex_type |= REG_EXTENDED; // -r 1464 if (opt & (2|4))
1446 //if (opt & 0x4) G.be_quiet++; // -n 1465 G.regex_type |= REG_EXTENDED; // -r or -E
1466 //if (opt & 8)
1467 // G.be_quiet++; // -n (implemented with a counter instead)
1447 while (opt_e) { // -e 1468 while (opt_e) { // -e
1448 add_cmd_block(llist_pop(&opt_e)); 1469 add_cmd_block(llist_pop(&opt_e));
1449 } 1470 }
@@ -1458,7 +1479,7 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1458 fclose(cmdfile); 1479 fclose(cmdfile);
1459 } 1480 }
1460 /* if we didn't get a pattern from -e or -f, use argv[0] */ 1481 /* if we didn't get a pattern from -e or -f, use argv[0] */
1461 if (!(opt & 0x18)) { 1482 if (!(opt & 0x30)) {
1462 if (!*argv) 1483 if (!*argv)
1463 bb_show_usage(); 1484 bb_show_usage();
1464 add_cmd_block(*argv++); 1485 add_cmd_block(*argv++);
@@ -1472,42 +1493,38 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1472 /* argv[0..(argc-1)] should be names of file to process. If no 1493 /* argv[0..(argc-1)] should be names of file to process. If no
1473 * files were specified or '-' was specified, take input from stdin. 1494 * files were specified or '-' was specified, take input from stdin.
1474 * Otherwise, we process all the files specified. */ 1495 * Otherwise, we process all the files specified. */
1475 if (argv[0] == NULL) { 1496 G.input_file_list = argv;
1497 if (!argv[0]) {
1476 if (opt & OPT_in_place) 1498 if (opt & OPT_in_place)
1477 bb_error_msg_and_die(bb_msg_requires_arg, "-i"); 1499 bb_error_msg_and_die(bb_msg_requires_arg, "-i");
1478 add_input_file(stdin); 1500 argv[0] = (char*)bb_msg_standard_input;
1501 /* G.last_input_file = 0; - already is */
1479 } else { 1502 } else {
1480 int i; 1503 goto start;
1481 1504
1482 for (i = 0; argv[i]; i++) { 1505 for (; *argv; argv++) {
1483 struct stat statbuf; 1506 struct stat statbuf;
1484 int nonstdoutfd; 1507 int nonstdoutfd;
1485 FILE *file;
1486 sed_cmd_t *sed_cmd; 1508 sed_cmd_t *sed_cmd;
1487 1509
1488 if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) { 1510 G.last_input_file++;
1489 add_input_file(stdin); 1511 start:
1490 process_files();
1491 continue;
1492 }
1493 file = fopen_or_warn(argv[i], "r");
1494 if (!file) {
1495 status = EXIT_FAILURE;
1496 continue;
1497 }
1498 add_input_file(file);
1499 if (!(opt & OPT_in_place)) { 1512 if (!(opt & OPT_in_place)) {
1513 if (LONE_DASH(*argv)) {
1514 *argv = (char*)bb_msg_standard_input;
1515 process_files();
1516 }
1500 continue; 1517 continue;
1501 } 1518 }
1502 1519
1503 /* -i: process each FILE separately: */ 1520 /* -i: process each FILE separately: */
1504 1521
1505 G.outname = xasprintf("%sXXXXXX", argv[i]); 1522 G.outname = xasprintf("%sXXXXXX", *argv);
1506 nonstdoutfd = xmkstemp(G.outname); 1523 nonstdoutfd = xmkstemp(G.outname);
1507 G.nonstdout = xfdopen_for_write(nonstdoutfd); 1524 G.nonstdout = xfdopen_for_write(nonstdoutfd);
1508 1525
1509 /* Set permissions/owner of output file */ 1526 /* Set permissions/owner of output file */
1510 fstat(fileno(file), &statbuf); 1527 stat(*argv, &statbuf);
1511 /* chmod'ing AFTER chown would preserve suid/sgid bits, 1528 /* chmod'ing AFTER chown would preserve suid/sgid bits,
1512 * but GNU sed 4.2.1 does not preserve them either */ 1529 * but GNU sed 4.2.1 does not preserve them either */
1513 fchmod(nonstdoutfd, statbuf.st_mode); 1530 fchmod(nonstdoutfd, statbuf.st_mode);
@@ -1518,12 +1535,12 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1518 G.nonstdout = stdout; 1535 G.nonstdout = stdout;
1519 1536
1520 if (opt_i) { 1537 if (opt_i) {
1521 char *backupname = xasprintf("%s%s", argv[i], opt_i); 1538 char *backupname = xasprintf("%s%s", *argv, opt_i);
1522 xrename(argv[i], backupname); 1539 xrename(*argv, backupname);
1523 free(backupname); 1540 free(backupname);
1524 } 1541 }
1525 /* else unlink(argv[i]); - rename below does this */ 1542 /* else unlink(*argv); - rename below does this */
1526 xrename(G.outname, argv[i]); //TODO: rollback backup on error? 1543 xrename(G.outname, *argv); //TODO: rollback backup on error?
1527 free(G.outname); 1544 free(G.outname);
1528 G.outname = NULL; 1545 G.outname = NULL;
1529 1546
@@ -1533,12 +1550,13 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1533 } 1550 }
1534 } 1551 }
1535 /* Here, to handle "sed 'cmds' nonexistent_file" case we did: 1552 /* Here, to handle "sed 'cmds' nonexistent_file" case we did:
1536 * if (G.current_input_file >= G.input_file_count) 1553 * if (G.current_input_file[G.current_input_file] == NULL)
1537 * return status; 1554 * return G.exitcode;
1538 * but it's not needed since process_files() works correctly 1555 * but it's not needed since process_files() works correctly
1539 * in this case too. */ 1556 * in this case too. */
1540 } 1557 }
1558
1541 process_files(); 1559 process_files();
1542 1560
1543 return status; 1561 return G.exitcode;
1544} 1562}
diff --git a/include/applets.src.h b/include/applets.src.h
index aa319bbc9..7dbd4c7f3 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -79,16 +79,13 @@ IF_ACPID(APPLET(acpid, BB_DIR_SBIN, BB_SUID_DROP))
79IF_ADDGROUP(APPLET(addgroup, BB_DIR_USR_SBIN, BB_SUID_DROP)) 79IF_ADDGROUP(APPLET(addgroup, BB_DIR_USR_SBIN, BB_SUID_DROP))
80IF_ADDUSER(APPLET(adduser, BB_DIR_USR_SBIN, BB_SUID_DROP)) 80IF_ADDUSER(APPLET(adduser, BB_DIR_USR_SBIN, BB_SUID_DROP))
81IF_ADJTIMEX(APPLET(adjtimex, BB_DIR_SBIN, BB_SUID_DROP)) 81IF_ADJTIMEX(APPLET(adjtimex, BB_DIR_SBIN, BB_SUID_DROP))
82IF_AR(APPLET(ar, BB_DIR_USR_BIN, BB_SUID_DROP))
83IF_ARP(APPLET(arp, BB_DIR_SBIN, BB_SUID_DROP)) 82IF_ARP(APPLET(arp, BB_DIR_SBIN, BB_SUID_DROP))
84IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP)) 83IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP))
85IF_AWK(APPLET_NOEXEC(awk, awk, BB_DIR_USR_BIN, BB_SUID_DROP, awk))
86IF_BASENAME(APPLET_NOFORK(basename, basename, BB_DIR_USR_BIN, BB_SUID_DROP, basename)) 84IF_BASENAME(APPLET_NOFORK(basename, basename, BB_DIR_USR_BIN, BB_SUID_DROP, basename))
87IF_BBCONFIG(APPLET(bbconfig, BB_DIR_BIN, BB_SUID_DROP)) 85IF_BBCONFIG(APPLET(bbconfig, BB_DIR_BIN, BB_SUID_DROP))
88IF_BEEP(APPLET(beep, BB_DIR_USR_BIN, BB_SUID_DROP)) 86IF_BEEP(APPLET(beep, BB_DIR_USR_BIN, BB_SUID_DROP))
89IF_BLKID(APPLET(blkid, BB_DIR_SBIN, BB_SUID_DROP)) 87IF_BLKID(APPLET(blkid, BB_DIR_SBIN, BB_SUID_DROP))
90IF_BRCTL(APPLET(brctl, BB_DIR_USR_SBIN, BB_SUID_DROP)) 88IF_BRCTL(APPLET(brctl, BB_DIR_USR_SBIN, BB_SUID_DROP))
91IF_BZIP2(APPLET(bzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
92IF_CAL(APPLET(cal, BB_DIR_USR_BIN, BB_SUID_DROP)) 89IF_CAL(APPLET(cal, BB_DIR_USR_BIN, BB_SUID_DROP))
93IF_CAT(APPLET_NOFORK(cat, cat, BB_DIR_BIN, BB_SUID_DROP, cat)) 90IF_CAT(APPLET_NOFORK(cat, cat, BB_DIR_BIN, BB_SUID_DROP, cat))
94IF_CATV(APPLET(catv, BB_DIR_BIN, BB_SUID_DROP)) 91IF_CATV(APPLET(catv, BB_DIR_BIN, BB_SUID_DROP))
@@ -105,10 +102,8 @@ IF_CHRT(APPLET(chrt, BB_DIR_USR_BIN, BB_SUID_DROP))
105IF_CHVT(APPLET(chvt, BB_DIR_USR_BIN, BB_SUID_DROP)) 102IF_CHVT(APPLET(chvt, BB_DIR_USR_BIN, BB_SUID_DROP))
106IF_CKSUM(APPLET_NOEXEC(cksum, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum)) 103IF_CKSUM(APPLET_NOEXEC(cksum, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum))
107IF_CLEAR(APPLET(clear, BB_DIR_USR_BIN, BB_SUID_DROP)) 104IF_CLEAR(APPLET(clear, BB_DIR_USR_BIN, BB_SUID_DROP))
108IF_CMP(APPLET(cmp, BB_DIR_USR_BIN, BB_SUID_DROP))
109IF_COMM(APPLET(comm, BB_DIR_USR_BIN, BB_SUID_DROP)) 105IF_COMM(APPLET(comm, BB_DIR_USR_BIN, BB_SUID_DROP))
110IF_CP(APPLET_NOEXEC(cp, cp, BB_DIR_BIN, BB_SUID_DROP, cp)) 106IF_CP(APPLET_NOEXEC(cp, cp, BB_DIR_BIN, BB_SUID_DROP, cp))
111IF_CPIO(APPLET(cpio, BB_DIR_BIN, BB_SUID_DROP))
112IF_CROND(APPLET(crond, BB_DIR_USR_SBIN, BB_SUID_DROP)) 107IF_CROND(APPLET(crond, BB_DIR_USR_SBIN, BB_SUID_DROP))
113/* Needs to be run by root or be suid root - needs to change /var/spool/cron* files: */ 108/* Needs to be run by root or be suid root - needs to change /var/spool/cron* files: */
114IF_CRONTAB(APPLET(crontab, BB_DIR_USR_BIN, BB_SUID_REQUIRE)) 109IF_CRONTAB(APPLET(crontab, BB_DIR_USR_BIN, BB_SUID_REQUIRE))
@@ -123,21 +118,17 @@ IF_DEVFSD(APPLET(devfsd, BB_DIR_SBIN, BB_SUID_DROP))
123IF_DEVMEM(APPLET(devmem, BB_DIR_SBIN, BB_SUID_DROP)) 118IF_DEVMEM(APPLET(devmem, BB_DIR_SBIN, BB_SUID_DROP))
124IF_DF(APPLET(df, BB_DIR_BIN, BB_SUID_DROP)) 119IF_DF(APPLET(df, BB_DIR_BIN, BB_SUID_DROP))
125IF_DHCPRELAY(APPLET(dhcprelay, BB_DIR_USR_SBIN, BB_SUID_DROP)) 120IF_DHCPRELAY(APPLET(dhcprelay, BB_DIR_USR_SBIN, BB_SUID_DROP))
126IF_DIFF(APPLET(diff, BB_DIR_USR_BIN, BB_SUID_DROP))
127IF_DIRNAME(APPLET_NOFORK(dirname, dirname, BB_DIR_USR_BIN, BB_SUID_DROP, dirname)) 121IF_DIRNAME(APPLET_NOFORK(dirname, dirname, BB_DIR_USR_BIN, BB_SUID_DROP, dirname))
128IF_DMESG(APPLET(dmesg, BB_DIR_BIN, BB_SUID_DROP)) 122IF_DMESG(APPLET(dmesg, BB_DIR_BIN, BB_SUID_DROP))
129IF_DNSD(APPLET(dnsd, BB_DIR_USR_SBIN, BB_SUID_DROP)) 123IF_DNSD(APPLET(dnsd, BB_DIR_USR_SBIN, BB_SUID_DROP))
130IF_HOSTNAME(APPLET_ODDNAME(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) 124IF_HOSTNAME(APPLET_ODDNAME(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname))
131IF_DOS2UNIX(APPLET_NOEXEC(dos2unix, dos2unix, BB_DIR_USR_BIN, BB_SUID_DROP, dos2unix)) 125IF_DOS2UNIX(APPLET_NOEXEC(dos2unix, dos2unix, BB_DIR_USR_BIN, BB_SUID_DROP, dos2unix))
132IF_DPKG(APPLET(dpkg, BB_DIR_USR_BIN, BB_SUID_DROP))
133IF_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, BB_DIR_USR_BIN, BB_SUID_DROP, dpkg_deb))
134IF_DU(APPLET(du, BB_DIR_USR_BIN, BB_SUID_DROP)) 126IF_DU(APPLET(du, BB_DIR_USR_BIN, BB_SUID_DROP))
135IF_DUMPKMAP(APPLET(dumpkmap, BB_DIR_BIN, BB_SUID_DROP)) 127IF_DUMPKMAP(APPLET(dumpkmap, BB_DIR_BIN, BB_SUID_DROP))
136IF_DUMPLEASES(APPLET(dumpleases, BB_DIR_USR_BIN, BB_SUID_DROP)) 128IF_DUMPLEASES(APPLET(dumpleases, BB_DIR_USR_BIN, BB_SUID_DROP))
137//IF_E2FSCK(APPLET(e2fsck, BB_DIR_SBIN, BB_SUID_DROP)) 129//IF_E2FSCK(APPLET(e2fsck, BB_DIR_SBIN, BB_SUID_DROP))
138//IF_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, BB_DIR_SBIN, BB_SUID_DROP, e2label)) 130//IF_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, BB_DIR_SBIN, BB_SUID_DROP, e2label))
139IF_ECHO(APPLET_NOFORK(echo, echo, BB_DIR_BIN, BB_SUID_DROP, echo)) 131IF_ECHO(APPLET_NOFORK(echo, echo, BB_DIR_BIN, BB_SUID_DROP, echo))
140IF_ED(APPLET(ed, BB_DIR_BIN, BB_SUID_DROP))
141IF_EJECT(APPLET(eject, BB_DIR_USR_BIN, BB_SUID_DROP)) 132IF_EJECT(APPLET(eject, BB_DIR_USR_BIN, BB_SUID_DROP))
142IF_ENV(APPLET_NOEXEC(env, env, BB_DIR_USR_BIN, BB_SUID_DROP, env)) 133IF_ENV(APPLET_NOEXEC(env, env, BB_DIR_USR_BIN, BB_SUID_DROP, env))
143IF_ENVDIR(APPLET_ODDNAME(envdir, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envdir)) 134IF_ENVDIR(APPLET_ODDNAME(envdir, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envdir))
@@ -176,8 +167,6 @@ IF_GETENFORCE(APPLET(getenforce, BB_DIR_USR_SBIN, BB_SUID_DROP))
176IF_GETOPT(APPLET(getopt, BB_DIR_BIN, BB_SUID_DROP)) 167IF_GETOPT(APPLET(getopt, BB_DIR_BIN, BB_SUID_DROP))
177IF_GETSEBOOL(APPLET(getsebool, BB_DIR_USR_SBIN, BB_SUID_DROP)) 168IF_GETSEBOOL(APPLET(getsebool, BB_DIR_USR_SBIN, BB_SUID_DROP))
178IF_GETTY(APPLET(getty, BB_DIR_SBIN, BB_SUID_DROP)) 169IF_GETTY(APPLET(getty, BB_DIR_SBIN, BB_SUID_DROP))
179IF_GUNZIP(APPLET(gunzip, BB_DIR_BIN, BB_SUID_DROP))
180IF_GZIP(APPLET(gzip, BB_DIR_BIN, BB_SUID_DROP))
181IF_HD(APPLET_NOEXEC(hd, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hd)) 170IF_HD(APPLET_NOEXEC(hd, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hd))
182IF_HDPARM(APPLET(hdparm, BB_DIR_SBIN, BB_SUID_DROP)) 171IF_HDPARM(APPLET(hdparm, BB_DIR_SBIN, BB_SUID_DROP))
183IF_HEAD(APPLET_NOEXEC(head, head, BB_DIR_USR_BIN, BB_SUID_DROP, head)) 172IF_HEAD(APPLET_NOEXEC(head, head, BB_DIR_USR_BIN, BB_SUID_DROP, head))
@@ -236,10 +225,6 @@ IF_LS(APPLET_NOEXEC(ls, ls, BB_DIR_BIN, BB_SUID_DROP, ls))
236IF_LSATTR(APPLET(lsattr, BB_DIR_BIN, BB_SUID_DROP)) 225IF_LSATTR(APPLET(lsattr, BB_DIR_BIN, BB_SUID_DROP))
237IF_LSPCI(APPLET(lspci, BB_DIR_USR_BIN, BB_SUID_DROP)) 226IF_LSPCI(APPLET(lspci, BB_DIR_USR_BIN, BB_SUID_DROP))
238IF_LSUSB(APPLET(lsusb, BB_DIR_USR_BIN, BB_SUID_DROP)) 227IF_LSUSB(APPLET(lsusb, BB_DIR_USR_BIN, BB_SUID_DROP))
239IF_UNLZMA(APPLET_ODDNAME(lzcat, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzcat))
240IF_LZMA(APPLET_ODDNAME(lzma, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzma))
241IF_LZOP(APPLET(lzop, BB_DIR_BIN, BB_SUID_DROP))
242IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, lzopcat))
243IF_MAKEDEVS(APPLET(makedevs, BB_DIR_SBIN, BB_SUID_DROP)) 228IF_MAKEDEVS(APPLET(makedevs, BB_DIR_SBIN, BB_SUID_DROP))
244IF_MAKEMIME(APPLET(makemime, BB_DIR_BIN, BB_SUID_DROP)) 229IF_MAKEMIME(APPLET(makemime, BB_DIR_BIN, BB_SUID_DROP))
245IF_MAN(APPLET(man, BB_DIR_USR_BIN, BB_SUID_DROP)) 230IF_MAN(APPLET(man, BB_DIR_USR_BIN, BB_SUID_DROP))
@@ -303,12 +288,9 @@ IF_RENICE(APPLET(renice, BB_DIR_USR_BIN, BB_SUID_DROP))
303IF_RESET(APPLET(reset, BB_DIR_USR_BIN, BB_SUID_DROP)) 288IF_RESET(APPLET(reset, BB_DIR_USR_BIN, BB_SUID_DROP))
304IF_RESIZE(APPLET(resize, BB_DIR_USR_BIN, BB_SUID_DROP)) 289IF_RESIZE(APPLET(resize, BB_DIR_USR_BIN, BB_SUID_DROP))
305IF_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, BB_DIR_SBIN, BB_SUID_DROP, restorecon)) 290IF_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, BB_DIR_SBIN, BB_SUID_DROP, restorecon))
306IF_RFKILL(APPLET(rfkill, BB_DIR_USR_SBIN, BB_SUID_DROP))
307IF_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))
308IF_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))
309IF_ROUTE(APPLET(route, BB_DIR_SBIN, BB_SUID_DROP)) 293IF_ROUTE(APPLET(route, BB_DIR_SBIN, BB_SUID_DROP))
310IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP))
311IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP))
312IF_RTCWAKE(APPLET(rtcwake, BB_DIR_USR_SBIN, BB_SUID_DROP)) 294IF_RTCWAKE(APPLET(rtcwake, BB_DIR_USR_SBIN, BB_SUID_DROP))
313IF_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, BB_DIR_BIN, BB_SUID_DROP, run_parts)) 295IF_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, BB_DIR_BIN, BB_SUID_DROP, run_parts))
314IF_RUNCON(APPLET(runcon, BB_DIR_USR_BIN, BB_SUID_DROP)) 296IF_RUNCON(APPLET(runcon, BB_DIR_USR_BIN, BB_SUID_DROP))
@@ -318,7 +300,6 @@ IF_RUNSVDIR(APPLET(runsvdir, BB_DIR_USR_BIN, BB_SUID_DROP))
318IF_RX(APPLET(rx, BB_DIR_USR_BIN, BB_SUID_DROP)) 300IF_RX(APPLET(rx, BB_DIR_USR_BIN, BB_SUID_DROP))
319IF_SCRIPT(APPLET(script, BB_DIR_USR_BIN, BB_SUID_DROP)) 301IF_SCRIPT(APPLET(script, BB_DIR_USR_BIN, BB_SUID_DROP))
320IF_SCRIPTREPLAY(APPLET(scriptreplay, BB_DIR_BIN, BB_SUID_DROP)) 302IF_SCRIPTREPLAY(APPLET(scriptreplay, BB_DIR_BIN, BB_SUID_DROP))
321IF_SED(APPLET(sed, BB_DIR_BIN, BB_SUID_DROP))
322IF_SELINUXENABLED(APPLET(selinuxenabled, BB_DIR_USR_SBIN, BB_SUID_DROP)) 303IF_SELINUXENABLED(APPLET(selinuxenabled, BB_DIR_USR_SBIN, BB_SUID_DROP))
323IF_SENDMAIL(APPLET(sendmail, BB_DIR_USR_SBIN, BB_SUID_DROP)) 304IF_SENDMAIL(APPLET(sendmail, BB_DIR_USR_SBIN, BB_SUID_DROP))
324IF_SEQ(APPLET_NOFORK(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq)) 305IF_SEQ(APPLET_NOFORK(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq))
@@ -362,7 +343,6 @@ IF_BB_SYSCTL(APPLET(sysctl, BB_DIR_SBIN, BB_SUID_DROP))
362IF_SYSLOGD(APPLET(syslogd, BB_DIR_SBIN, BB_SUID_DROP)) 343IF_SYSLOGD(APPLET(syslogd, BB_DIR_SBIN, BB_SUID_DROP))
363IF_TAC(APPLET_NOEXEC(tac, tac, BB_DIR_USR_BIN, BB_SUID_DROP, tac)) 344IF_TAC(APPLET_NOEXEC(tac, tac, BB_DIR_USR_BIN, BB_SUID_DROP, tac))
364IF_TAIL(APPLET(tail, BB_DIR_USR_BIN, BB_SUID_DROP)) 345IF_TAIL(APPLET(tail, BB_DIR_USR_BIN, BB_SUID_DROP))
365IF_TAR(APPLET(tar, BB_DIR_BIN, BB_SUID_DROP))
366IF_TASKSET(APPLET(taskset, BB_DIR_USR_BIN, BB_SUID_DROP)) 346IF_TASKSET(APPLET(taskset, BB_DIR_USR_BIN, BB_SUID_DROP))
367/* IF_TC(APPLET(tc, BB_DIR_SBIN, BB_SUID_DROP)) */ 347/* IF_TC(APPLET(tc, BB_DIR_SBIN, BB_SUID_DROP)) */
368IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, tcpsvd)) 348IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, tcpsvd))
@@ -391,14 +371,9 @@ IF_UDHCPD(APPLET(udhcpd, BB_DIR_USR_SBIN, BB_SUID_DROP))
391IF_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, udpsvd)) 371IF_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, udpsvd))
392IF_UMOUNT(APPLET(umount, BB_DIR_BIN, BB_SUID_DROP)) 372IF_UMOUNT(APPLET(umount, BB_DIR_BIN, BB_SUID_DROP))
393IF_UNAME(APPLET(uname, BB_DIR_BIN, BB_SUID_DROP)) 373IF_UNAME(APPLET(uname, BB_DIR_BIN, BB_SUID_DROP))
394IF_UNCOMPRESS(APPLET(uncompress, BB_DIR_BIN, BB_SUID_DROP))
395IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, BB_DIR_USR_BIN, BB_SUID_DROP, unexpand)) 374IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, BB_DIR_USR_BIN, BB_SUID_DROP, unexpand))
396IF_UNIQ(APPLET(uniq, BB_DIR_USR_BIN, BB_SUID_DROP)) 375IF_UNIQ(APPLET(uniq, BB_DIR_USR_BIN, BB_SUID_DROP))
397IF_UNIX2DOS(APPLET_NOEXEC(unix2dos, dos2unix, BB_DIR_USR_BIN, BB_SUID_DROP, unix2dos)) 376IF_UNIX2DOS(APPLET_NOEXEC(unix2dos, dos2unix, BB_DIR_USR_BIN, BB_SUID_DROP, unix2dos))
398IF_UNXZ(APPLET(unxz, BB_DIR_USR_BIN, BB_SUID_DROP))
399IF_UNLZMA(APPLET(unlzma, BB_DIR_USR_BIN, BB_SUID_DROP))
400IF_LZOP(APPLET_ODDNAME(unlzop, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, unlzop))
401IF_UNZIP(APPLET(unzip, BB_DIR_USR_BIN, BB_SUID_DROP))
402IF_UPTIME(APPLET(uptime, BB_DIR_USR_BIN, BB_SUID_DROP)) 377IF_UPTIME(APPLET(uptime, BB_DIR_USR_BIN, BB_SUID_DROP))
403IF_USLEEP(APPLET_NOFORK(usleep, usleep, BB_DIR_BIN, BB_SUID_DROP, usleep)) 378IF_USLEEP(APPLET_NOFORK(usleep, usleep, BB_DIR_BIN, BB_SUID_DROP, usleep))
404IF_UUDECODE(APPLET(uudecode, BB_DIR_USR_BIN, BB_SUID_DROP)) 379IF_UUDECODE(APPLET(uudecode, BB_DIR_USR_BIN, BB_SUID_DROP))
@@ -407,18 +382,13 @@ IF_VCONFIG(APPLET(vconfig, BB_DIR_SBIN, BB_SUID_DROP))
407/* Needs to be run by root or be suid root - needs to change uid and gid: */ 382/* Needs to be run by root or be suid root - needs to change uid and gid: */
408IF_VLOCK(APPLET(vlock, BB_DIR_USR_BIN, BB_SUID_REQUIRE)) 383IF_VLOCK(APPLET(vlock, BB_DIR_USR_BIN, BB_SUID_REQUIRE))
409IF_VOLNAME(APPLET(volname, BB_DIR_USR_BIN, BB_SUID_DROP)) 384IF_VOLNAME(APPLET(volname, BB_DIR_USR_BIN, BB_SUID_DROP))
410/* Needs to be run by root or be suid root - needs to write to /dev/TTY: */
411IF_WALL(APPLET(wall, BB_DIR_USR_BIN, BB_SUID_REQUIRE))
412IF_WATCH(APPLET(watch, BB_DIR_BIN, BB_SUID_DROP)) 385IF_WATCH(APPLET(watch, BB_DIR_BIN, BB_SUID_DROP))
413IF_WATCHDOG(APPLET(watchdog, BB_DIR_SBIN, BB_SUID_DROP)) 386IF_WATCHDOG(APPLET(watchdog, BB_DIR_SBIN, BB_SUID_DROP))
414IF_WC(APPLET(wc, BB_DIR_USR_BIN, BB_SUID_DROP)) 387IF_WC(APPLET(wc, BB_DIR_USR_BIN, BB_SUID_DROP))
415IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP)) 388IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP))
416IF_WHICH(APPLET(which, BB_DIR_USR_BIN, BB_SUID_DROP)) 389IF_WHICH(APPLET(which, BB_DIR_USR_BIN, BB_SUID_DROP))
417IF_WHOAMI(APPLET_NOFORK(whoami, whoami, BB_DIR_USR_BIN, BB_SUID_DROP, whoami)) 390IF_WHOAMI(APPLET_NOFORK(whoami, whoami, BB_DIR_USR_BIN, BB_SUID_DROP, whoami))
418IF_UNXZ(APPLET_ODDNAME(xzcat, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xzcat))
419IF_XZ(APPLET_ODDNAME(xz, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xz))
420IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) 391IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes))
421IF_GUNZIP(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat))
422IF_ZCIP(APPLET(zcip, BB_DIR_SBIN, BB_SUID_DROP)) 392IF_ZCIP(APPLET(zcip, BB_DIR_SBIN, BB_SUID_DROP))
423 393
424#if !defined(PROTOTYPES) && !defined(NAME_MAIN_CNAME) && !defined(MAKE_USAGE) \ 394#if !defined(PROTOTYPES) && !defined(NAME_MAIN_CNAME) && !defined(MAKE_USAGE) \
diff --git a/include/libbb.h b/include/libbb.h
index 9adb037ca..e516f0ee3 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -32,12 +32,12 @@
32#include <stdarg.h> 32#include <stdarg.h>
33#include <stddef.h> 33#include <stddef.h>
34#include <string.h> 34#include <string.h>
35/* There are two incompatible basename's, let not use them! */ 35/* There are two incompatible basename's, let's not use them! */
36/* See the dirname/basename man page for details */ 36/* See the dirname/basename man page for details */
37#include <libgen.h> /* dirname,basename */ 37#include <libgen.h> /* dirname,basename */
38#undef basename 38#undef basename
39#define basename dont_use_basename 39#define basename dont_use_basename
40#include <sys/poll.h> 40#include <poll.h>
41#include <sys/ioctl.h> 41#include <sys/ioctl.h>
42#include <sys/mman.h> 42#include <sys/mman.h>
43#include <sys/socket.h> 43#include <sys/socket.h>
@@ -474,6 +474,8 @@ void record_signo(int signo); /* not FAST_FUNC! */
474 474
475void xsetgid(gid_t gid) FAST_FUNC; 475void xsetgid(gid_t gid) FAST_FUNC;
476void xsetuid(uid_t uid) FAST_FUNC; 476void xsetuid(uid_t uid) FAST_FUNC;
477void xsetegid(gid_t egid) FAST_FUNC;
478void xseteuid(uid_t euid) FAST_FUNC;
477void xchdir(const char *path) FAST_FUNC; 479void xchdir(const char *path) FAST_FUNC;
478void xchroot(const char *path) FAST_FUNC; 480void xchroot(const char *path) FAST_FUNC;
479void xsetenv(const char *key, const char *value) FAST_FUNC; 481void xsetenv(const char *key, const char *value) FAST_FUNC;
@@ -482,11 +484,12 @@ void bb_unsetenv_and_free(char *key) FAST_FUNC;
482void xunlink(const char *pathname) FAST_FUNC; 484void xunlink(const char *pathname) FAST_FUNC;
483void xstat(const char *pathname, struct stat *buf) FAST_FUNC; 485void xstat(const char *pathname, struct stat *buf) FAST_FUNC;
484void xfstat(int fd, struct stat *buf, const char *errmsg) FAST_FUNC; 486void xfstat(int fd, struct stat *buf, const char *errmsg) FAST_FUNC;
487int open3_or_warn(const char *pathname, int flags, int mode) FAST_FUNC;
488int open_or_warn(const char *pathname, int flags) FAST_FUNC;
489int xopen3(const char *pathname, int flags, int mode) FAST_FUNC;
485int xopen(const char *pathname, int flags) FAST_FUNC; 490int xopen(const char *pathname, int flags) FAST_FUNC;
486int xopen_nonblocking(const char *pathname) FAST_FUNC; 491int xopen_nonblocking(const char *pathname) FAST_FUNC;
487int xopen3(const char *pathname, int flags, int mode) FAST_FUNC; 492int xopen_as_uid_gid(const char *pathname, int flags, uid_t u, gid_t g) FAST_FUNC;
488int open_or_warn(const char *pathname, int flags) FAST_FUNC;
489int open3_or_warn(const char *pathname, int flags, int mode) FAST_FUNC;
490int open_or_warn_stdin(const char *pathname) FAST_FUNC; 493int open_or_warn_stdin(const char *pathname) FAST_FUNC;
491int xopen_stdin(const char *pathname) FAST_FUNC; 494int xopen_stdin(const char *pathname) FAST_FUNC;
492void xrename(const char *oldpath, const char *newpath) FAST_FUNC; 495void xrename(const char *oldpath, const char *newpath) FAST_FUNC;
@@ -831,8 +834,8 @@ char *itoa(int n) FAST_FUNC;
831char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; 834char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC;
832char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC; 835char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC;
833/* Intelligent formatters of bignums */ 836/* Intelligent formatters of bignums */
834void smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) FAST_FUNC; 837char *smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) FAST_FUNC;
835void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; 838char *smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC;
836/* If block_size == 0, display size without fractional part, 839/* If block_size == 0, display size without fractional part,
837 * else display (size * block_size) with one decimal digit. 840 * else display (size * block_size) with one decimal digit.
838 * If display_unit == 0, show value no bigger than 1024 with suffix (K,M,G...), 841 * If display_unit == 0, show value no bigger than 1024 with suffix (K,M,G...),
@@ -1313,8 +1316,10 @@ int sd_listen_fds(void);
1313#define SETUP_ENV_CLEARENV (1 << 1) 1316#define SETUP_ENV_CLEARENV (1 << 1)
1314#define SETUP_ENV_TO_TMP (1 << 2) 1317#define SETUP_ENV_TO_TMP (1 << 2)
1315#define SETUP_ENV_NO_CHDIR (1 << 4) 1318#define SETUP_ENV_NO_CHDIR (1 << 4)
1316extern void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC; 1319void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC;
1317extern int correct_password(const struct passwd *pw) FAST_FUNC; 1320void nuke_str(char *str) FAST_FUNC;
1321int ask_and_check_password_extended(const struct passwd *pw, int timeout, const char *prompt) FAST_FUNC;
1322int ask_and_check_password(const struct passwd *pw) FAST_FUNC;
1318/* Returns a malloced string */ 1323/* Returns a malloced string */
1319#if !ENABLE_USE_BB_CRYPT 1324#if !ENABLE_USE_BB_CRYPT
1320#define pw_encrypt(clear, salt, cleanup) pw_encrypt(clear, salt) 1325#define pw_encrypt(clear, salt, cleanup) pw_encrypt(clear, salt)
@@ -1793,6 +1798,11 @@ extern struct globals *const ptr_to_globals;
1793 (*(struct globals**)&ptr_to_globals) = (void*)(x); \ 1798 (*(struct globals**)&ptr_to_globals) = (void*)(x); \
1794 barrier(); \ 1799 barrier(); \
1795} while (0) 1800} while (0)
1801#define FREE_PTR_TO_GLOBALS() do { \
1802 if (ENABLE_FEATURE_CLEAN_UP) { \
1803 free(ptr_to_globals); \
1804 } \
1805} while (0)
1796 1806
1797/* You can change LIBBB_DEFAULT_LOGIN_SHELL, but don't use it, 1807/* You can change LIBBB_DEFAULT_LOGIN_SHELL, but don't use it,
1798 * use bb_default_login_shell and following defines. 1808 * use bb_default_login_shell and following defines.
diff --git a/include/platform.h b/include/platform.h
index f18d5b74e..66615b400 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -469,7 +469,7 @@ typedef unsigned smalluint;
469# undef HAVE_UNLOCKED_LINE_OPS 469# undef HAVE_UNLOCKED_LINE_OPS
470#endif 470#endif
471 471
472#if defined(__FreeBSD__) 472#if defined(__FreeBSD__) || defined(__APPLE__)
473# undef HAVE_STRCHRNUL 473# undef HAVE_STRCHRNUL
474#endif 474#endif
475 475
diff --git a/init/bootchartd.c b/init/bootchartd.c
index 9fd623357..c7388c99e 100644
--- a/init/bootchartd.c
+++ b/init/bootchartd.c
@@ -60,6 +60,12 @@
60# endif 60# endif
61#endif 61#endif
62 62
63#if !ENABLE_TAR && !ENABLE_WERROR
64# warning Note: bootchartd requires tar command, but you did not select it.
65#elif !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_WERROR
66# warning Note: bootchartd requires tar -z support, but you did not select it.
67#endif
68
63#define BC_VERSION_STR "0.8" 69#define BC_VERSION_STR "0.8"
64 70
65/* For debugging, set to 0: 71/* For debugging, set to 0:
diff --git a/init/init.c b/init/init.c
index edb5be696..d29328c36 100644
--- a/init/init.c
+++ b/init/init.c
@@ -9,11 +9,6 @@
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 12//config:config INIT
18//config: bool "init" 13//config: bool "init"
19//config: default y 14//config: default y
@@ -108,6 +103,11 @@
108//config: Note that on Linux, init attempts to detect serial terminal and 103//config: Note that on Linux, init attempts to detect serial terminal and
109//config: sets TERM to "vt102" if one is found. 104//config: sets TERM to "vt102" if one is found.
110 105
106//applet:IF_INIT(APPLET(init, BB_DIR_SBIN, BB_SUID_DROP))
107//applet:IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, BB_DIR_ROOT, BB_SUID_DROP, linuxrc))
108
109//kbuild:lib-$(CONFIG_INIT) += init.o
110
111#define DEBUG_SEGV_HANDLER 0 111#define DEBUG_SEGV_HANDLER 0
112 112
113#include "libbb.h" 113#include "libbb.h"
@@ -222,8 +222,8 @@ static void message(int where, const char *fmt, ...)
222 msg[0] = '\r'; 222 msg[0] = '\r';
223 va_start(arguments, fmt); 223 va_start(arguments, fmt);
224 l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments); 224 l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments);
225 if (l > sizeof(msg) - 1) 225 if (l > sizeof(msg) - 2)
226 l = sizeof(msg) - 1; 226 l = sizeof(msg) - 2;
227 va_end(arguments); 227 va_end(arguments);
228 228
229#if ENABLE_FEATURE_INIT_SYSLOG 229#if ENABLE_FEATURE_INIT_SYSLOG
@@ -789,7 +789,7 @@ static void run_shutdown_and_kill_processes(void)
789 * and only one will be remembered and acted upon. 789 * and only one will be remembered and acted upon.
790 */ 790 */
791 791
792/* The SIGUSR[12]/SIGTERM handler */ 792/* The SIGPWR/SIGUSR[12]/SIGTERM handler */
793static void halt_reboot_pwoff(int sig) NORETURN; 793static void halt_reboot_pwoff(int sig) NORETURN;
794static void halt_reboot_pwoff(int sig) 794static void halt_reboot_pwoff(int sig)
795{ 795{
@@ -1103,8 +1103,8 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1103 1103
1104 /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined, 1104 /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
1105 * then parse_inittab() simply adds in some default 1105 * then parse_inittab() simply adds in some default
1106 * actions(i.e., INIT_SCRIPT and a pair 1106 * actions (i.e., INIT_SCRIPT and a pair
1107 * of "askfirst" shells */ 1107 * of "askfirst" shells) */
1108 parse_inittab(); 1108 parse_inittab();
1109 } 1109 }
1110 1110
@@ -1128,13 +1128,14 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1128 strncpy(argv[0], "init", strlen(argv[0])); 1128 strncpy(argv[0], "init", strlen(argv[0]));
1129 /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ 1129 /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
1130 while (*++argv) 1130 while (*++argv)
1131 memset(*argv, 0, strlen(*argv)); 1131 nuke_str(*argv);
1132 1132
1133 /* Set up signal handlers */ 1133 /* Set up signal handlers */
1134 if (!DEBUG_INIT) { 1134 if (!DEBUG_INIT) {
1135 struct sigaction sa; 1135 struct sigaction sa;
1136 1136
1137 bb_signals(0 1137 bb_signals(0
1138 + (1 << SIGPWR) /* halt */
1138 + (1 << SIGUSR1) /* halt */ 1139 + (1 << SIGUSR1) /* halt */
1139 + (1 << SIGTERM) /* reboot */ 1140 + (1 << SIGTERM) /* reboot */
1140 + (1 << SIGUSR2) /* poweroff */ 1141 + (1 << SIGUSR2) /* poweroff */
@@ -1230,7 +1231,14 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1230//usage:#define init_trivial_usage 1231//usage:#define init_trivial_usage
1231//usage: "" 1232//usage: ""
1232//usage:#define init_full_usage "\n\n" 1233//usage:#define init_full_usage "\n\n"
1233//usage: "Init is the parent of all processes" 1234//usage: "Init is the first process started during boot. It never exits."
1235//usage: IF_FEATURE_USE_INITTAB(
1236//usage: "\n""It (re)spawns children according to /etc/inittab."
1237//usage: )
1238//usage: IF_NOT_FEATURE_USE_INITTAB(
1239//usage: "\n""This version of init doesn't use /etc/inittab,"
1240//usage: "\n""has fixed set of processed to run."
1241//usage: )
1234//usage: 1242//usage:
1235//usage:#define init_notes_usage 1243//usage:#define init_notes_usage
1236//usage: "This version of init is designed to be run only by the kernel.\n" 1244//usage: "This version of init is designed to be run only by the kernel.\n"
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index db79ff62b..adaab92d6 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -146,7 +146,7 @@ lib-$(CONFIG_DELUSER) += update_passwd.o
146lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o obscure.o 146lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o obscure.o
147lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o 147lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o
148lib-$(CONFIG_CRYPTPW) += pw_encrypt.o 148lib-$(CONFIG_CRYPTPW) += pw_encrypt.o
149lib-$(CONFIG_SULOGIN) += pw_encrypt.o 149lib-$(CONFIG_SULOGIN) += pw_encrypt.o correct_password.o
150lib-$(CONFIG_VLOCK) += pw_encrypt.o correct_password.o 150lib-$(CONFIG_VLOCK) += pw_encrypt.o correct_password.o
151lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o 151lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o
152lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o 152lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o
diff --git a/libbb/bb_pwd.c b/libbb/bb_pwd.c
index 4829b723a..8250cd446 100644
--- a/libbb/bb_pwd.c
+++ b/libbb/bb_pwd.c
@@ -110,3 +110,51 @@ unsigned long FAST_FUNC get_ug_id(const char *s,
110 return xname2id(s); 110 return xname2id(s);
111 return r; 111 return r;
112} 112}
113
114/* Experimental "mallocing" API.
115 * The goal is nice: "we want to support a case when "guests" group is very large"
116 * but the code is butt-ugly.
117 */
118#if 0
119static char *find_latest(char last, char *cp)
120{
121 if (!cp)
122 return last;
123 cp += strlen(cp) + 1;
124 if (last < cp)
125 last = cp;
126 return last;
127}
128
129struct group* FAST_FUNC xmalloc_getgrnam(const char *name)
130{
131 struct {
132 struct group gr;
133 // May still be not enough!
134 char buf[64*1024 - sizeof(struct group) - 16];
135 } *s;
136 struct group *grp;
137 int r;
138 char *last;
139 char **gr_mem;
140
141 s = xmalloc(sizeof(*s));
142 r = getgrnam_r(name, &s->gr, s->buf, sizeof(s->buf), &grp);
143 if (!grp) {
144 free(s);
145 return grp;
146 }
147 last = find_latest(s->buf, grp->gr_name);
148 last = find_latest(last, grp->gr_passwd);
149 gr_mem = grp->gr_mem;
150 while (*gr_mem)
151 last = find_latest(last, *gr_mem++);
152 gr_mem++; /* points past NULL */
153 if (last < (char*)gr_mem)
154 last = (char*)gr_mem;
155//FIXME: what if we get not only truncated, but also moved here?
156// grp->gr_name pointer and friends are invalid now!!!
157 s = xrealloc(s, last - (char*)s);
158 return grp;
159}
160#endif
diff --git a/libbb/correct_password.c b/libbb/correct_password.c
index 7cabd33d0..acadf3914 100644
--- a/libbb/correct_password.c
+++ b/libbb/correct_password.c
@@ -31,12 +31,15 @@
31#include "libbb.h" 31#include "libbb.h"
32 32
33/* Ask the user for a password. 33/* Ask the user for a password.
34 * Return 1 without asking if PW has an empty password.
35 * Return -1 on EOF, error while reading input, or timeout.
34 * Return 1 if the user gives the correct password for entry PW, 36 * Return 1 if the user gives the correct password for entry PW,
35 * 0 if not. Return 1 without asking if PW has an empty password. 37 * 0 if not.
36 * 38 *
37 * NULL pw means "just fake it for login with bad username" */ 39 * NULL pw means "just fake it for login with bad username"
38 40 */
39int FAST_FUNC correct_password(const struct passwd *pw) 41int FAST_FUNC ask_and_check_password_extended(const struct passwd *pw,
42 int timeout, const char *prompt)
40{ 43{
41 char *unencrypted, *encrypted; 44 char *unencrypted, *encrypted;
42 const char *correct; 45 const char *correct;
@@ -65,13 +68,19 @@ int FAST_FUNC correct_password(const struct passwd *pw)
65 return 1; 68 return 1;
66 69
67 fake_it: 70 fake_it:
68 unencrypted = bb_ask_stdin("Password: "); 71 unencrypted = bb_ask(STDIN_FILENO, timeout, prompt);
69 if (!unencrypted) { 72 if (!unencrypted) {
70 return 0; 73 /* EOF (such as ^D) or error (such as ^C) or timeout */
74 return -1;
71 } 75 }
72 encrypted = pw_encrypt(unencrypted, correct, 1); 76 encrypted = pw_encrypt(unencrypted, correct, 1);
73 r = (strcmp(encrypted, correct) == 0); 77 r = (strcmp(encrypted, correct) == 0);
74 free(encrypted); 78 free(encrypted);
75 memset(unencrypted, 0, strlen(unencrypted)); 79 nuke_str(unencrypted);
76 return r; 80 return r;
77} 81}
82
83int FAST_FUNC ask_and_check_password(const struct passwd *pw)
84{
85 return ask_and_check_password_extended(pw, 0, "Password: ");
86}
diff --git a/libbb/fclose_nonstdin.c b/libbb/fclose_nonstdin.c
index 5ce9d5b48..1b1441347 100644
--- a/libbb/fclose_nonstdin.c
+++ b/libbb/fclose_nonstdin.c
@@ -18,7 +18,8 @@ int FAST_FUNC fclose_if_not_stdin(FILE *f)
18{ 18{
19 /* Some more paranoid applets want ferror() check too */ 19 /* Some more paranoid applets want ferror() check too */
20 int r = ferror(f); /* NB: does NOT set errno! */ 20 int r = ferror(f); /* NB: does NOT set errno! */
21 if (r) errno = EIO; /* so we'll help it */ 21 if (r)
22 errno = EIO; /* so we'll help it */
22 if (f != stdin) 23 if (f != stdin)
23 return (r | fclose(f)); /* fclose does set errno on error */ 24 return (r | fclose(f)); /* fclose does set errno on error */
24 return r; 25 return r;
diff --git a/libbb/human_readable.c b/libbb/human_readable.c
index 8b22b0cb5..0b2eb777e 100644
--- a/libbb/human_readable.c
+++ b/libbb/human_readable.c
@@ -94,7 +94,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val,
94 94
95/* Convert unsigned long long value into compact 5-char representation. 95/* Convert unsigned long long value into compact 5-char representation.
96 * String is not terminated (buf[5] is untouched) */ 96 * String is not terminated (buf[5] is untouched) */
97void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) 97char* FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale)
98{ 98{
99 const char *fmt; 99 const char *fmt;
100 char c; 100 char c;
@@ -145,12 +145,13 @@ void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[5], const char *sca
145 buf[3] = "0123456789"[v]; 145 buf[3] = "0123456789"[v];
146 buf[4] = scale[idx]; /* typically scale = " kmgt..." */ 146 buf[4] = scale[idx]; /* typically scale = " kmgt..." */
147 } 147 }
148 return buf + 5;
148} 149}
149 150
150/* Convert unsigned long long value into compact 4-char 151/* Convert unsigned long long value into compact 4-char
151 * representation. Examples: "1234", "1.2k", " 27M", "123T" 152 * representation. Examples: "1234", "1.2k", " 27M", "123T"
152 * String is not terminated (buf[4] is untouched) */ 153 * String is not terminated (buf[4] is untouched) */
153void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) 154char* FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale)
154{ 155{
155 const char *fmt; 156 const char *fmt;
156 char c; 157 char c;
@@ -194,4 +195,5 @@ void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[4], const char *sca
194 buf[2] = "0123456789"[v]; 195 buf[2] = "0123456789"[v];
195 buf[3] = scale[idx]; /* typically scale = " kmgt..." */ 196 buf[3] = scale[idx]; /* typically scale = " kmgt..." */
196 } 197 }
198 return buf + 4;
197} 199}
diff --git a/libbb/in_ether.c b/libbb/in_ether.c
index dadadbafe..1de383bde 100644
--- a/libbb/in_ether.c
+++ b/libbb/in_ether.c
@@ -3,6 +3,7 @@
3 * Utility routines. 3 * Utility routines.
4 */ 4 */
5 5
6//kbuild:lib-$(CONFIG_ARP) += in_ether.o
6//kbuild:lib-$(CONFIG_IFCONFIG) += in_ether.o 7//kbuild:lib-$(CONFIG_IFCONFIG) += in_ether.o
7//kbuild:lib-$(CONFIG_IFENSLAVE) += in_ether.o 8//kbuild:lib-$(CONFIG_IFENSLAVE) += in_ether.o
8 9
diff --git a/libbb/inet_common.c b/libbb/inet_common.c
index 0f4fca1a2..b3e0802ee 100644
--- a/libbb/inet_common.c
+++ b/libbb/inet_common.c
@@ -175,8 +175,7 @@ int FAST_FUNC INET6_resolve(const char *name, struct sockaddr_in6 *sin6)
175 return -1; 175 return -1;
176 } 176 }
177 memcpy(sin6, ai->ai_addr, sizeof(*sin6)); 177 memcpy(sin6, ai->ai_addr, sizeof(*sin6));
178 if (ai) 178 freeaddrinfo(ai);
179 freeaddrinfo(ai);
180 return 0; 179 return 0;
181} 180}
182 181
diff --git a/libbb/nuke_str.c b/libbb/nuke_str.c
new file mode 100644
index 000000000..56b808bc7
--- /dev/null
+++ b/libbb/nuke_str.c
@@ -0,0 +1,21 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2008 Denys Vlasenko
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9
10//kbuild:lib-y += nuke_str.o
11
12#include "libbb.h"
13
14void FAST_FUNC nuke_str(char *str)
15{
16 if (str) {
17 while (*str)
18 *str++ = 0;
19 /* or: memset(str, 0, strlen(str)); - not as small as above */
20 }
21}
diff --git a/libbb/pw_encrypt_md5.c b/libbb/pw_encrypt_md5.c
index 889e09cab..1e52ecaea 100644
--- a/libbb/pw_encrypt_md5.c
+++ b/libbb/pw_encrypt_md5.c
@@ -86,7 +86,7 @@ md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned
86 86
87 /* Get the length of the salt including "$1$" */ 87 /* Get the length of the salt including "$1$" */
88 sl = 3; 88 sl = 3;
89 while (salt[sl] && salt[sl] != '$' && sl < (3 + 8)) 89 while (sl < (3 + 8) && salt[sl] && salt[sl] != '$')
90 sl++; 90 sl++;
91 91
92 /* Hash. the password first, since that is what is most unknown */ 92 /* Hash. the password first, since that is what is most unknown */
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index a70683241..e4ac6a002 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -140,15 +140,6 @@ int FAST_FUNC xopen(const char *pathname, int flags)
140 return xopen3(pathname, flags, 0666); 140 return xopen3(pathname, flags, 0666);
141} 141}
142 142
143/* Die if we can't open an existing file readonly with O_NONBLOCK
144 * and return the fd.
145 * Note that for ioctl O_RDONLY is sufficient.
146 */
147int FAST_FUNC xopen_nonblocking(const char *pathname)
148{
149 return xopen(pathname, O_RDONLY | O_NONBLOCK);
150}
151
152// Warn if we can't open a file and return a fd. 143// Warn if we can't open a file and return a fd.
153int FAST_FUNC open3_or_warn(const char *pathname, int flags, int mode) 144int FAST_FUNC open3_or_warn(const char *pathname, int flags, int mode)
154{ 145{
@@ -167,6 +158,32 @@ int FAST_FUNC open_or_warn(const char *pathname, int flags)
167 return open3_or_warn(pathname, flags, 0666); 158 return open3_or_warn(pathname, flags, 0666);
168} 159}
169 160
161/* Die if we can't open an existing file readonly with O_NONBLOCK
162 * and return the fd.
163 * Note that for ioctl O_RDONLY is sufficient.
164 */
165int FAST_FUNC xopen_nonblocking(const char *pathname)
166{
167 return xopen(pathname, O_RDONLY | O_NONBLOCK);
168}
169
170int FAST_FUNC xopen_as_uid_gid(const char *pathname, int flags, uid_t u, gid_t g)
171{
172 int fd;
173 uid_t old_euid = geteuid();
174 gid_t old_egid = getegid();
175
176 xsetegid(g);
177 xseteuid(u);
178
179 fd = xopen(pathname, flags);
180
181 xseteuid(old_euid);
182 xsetegid(old_egid);
183
184 return fd;
185}
186
170void FAST_FUNC xunlink(const char *pathname) 187void FAST_FUNC xunlink(const char *pathname)
171{ 188{
172 if (unlink(pathname)) 189 if (unlink(pathname))
@@ -351,6 +368,16 @@ void FAST_FUNC xsetuid(uid_t uid)
351 if (setuid(uid)) bb_perror_msg_and_die("setuid"); 368 if (setuid(uid)) bb_perror_msg_and_die("setuid");
352} 369}
353 370
371void FAST_FUNC xsetegid(gid_t egid)
372{
373 if (setegid(egid)) bb_perror_msg_and_die("setegid");
374}
375
376void FAST_FUNC xseteuid(uid_t euid)
377{
378 if (seteuid(euid)) bb_perror_msg_and_die("seteuid");
379}
380
354// Die if we can't chdir to a new path. 381// Die if we can't chdir to a new path.
355void FAST_FUNC xchdir(const char *path) 382void FAST_FUNC xchdir(const char *path)
356{ 383{
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c
index bc1d0e665..ea09f20b8 100644
--- a/libbb/xreadlink.c
+++ b/libbb/xreadlink.c
@@ -8,6 +8,12 @@
8 8
9#include "libbb.h" 9#include "libbb.h"
10 10
11/* some systems (eg Hurd) does not have MAXSYMLINKS definition,
12 * set it to some reasonable value if it isn't defined */
13#ifndef MAXSYMLINKS
14# define MAXSYMLINKS 20
15#endif
16
11/* 17/*
12 * NOTE: This function returns a malloced char* that you will have to free 18 * NOTE: This function returns a malloced char* that you will have to free
13 * yourself. 19 * yourself.
diff --git a/loginutils/adduser.c b/loginutils/adduser.c
index dc0244476..ef390adf8 100644
--- a/loginutils/adduser.c
+++ b/loginutils/adduser.c
@@ -162,9 +162,9 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
162 pw.pw_shell = (char *)get_shell_name(); 162 pw.pw_shell = (char *)get_shell_name();
163 pw.pw_dir = NULL; 163 pw.pw_dir = NULL;
164 164
165 /* at most two non-option args */ 165 /* at least one and at most two non-option args */
166 /* disable interactive passwd for system accounts */ 166 /* disable interactive passwd for system accounts */
167 opt_complementary = "?2:SD:u+"; 167 opt_complementary = "-1:?2:SD:u+";
168 if (sizeof(pw.pw_uid) == sizeof(int)) { 168 if (sizeof(pw.pw_uid) == sizeof(int)) {
169 opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid); 169 opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid);
170 } else { 170 } else {
diff --git a/loginutils/login.c b/loginutils/login.c
index 6ec8dc42e..a4b19ccfc 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -420,7 +420,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
420 * Note that reads (in no-echo mode) trash tty attributes. 420 * Note that reads (in no-echo mode) trash tty attributes.
421 * If we get interrupted by SIGALRM, we need to restore attrs. 421 * If we get interrupted by SIGALRM, we need to restore attrs.
422 */ 422 */
423 if (correct_password(pw)) 423 if (ask_and_check_password(pw) > 0)
424 break; 424 break;
425#endif /* ENABLE_PAM */ 425#endif /* ENABLE_PAM */
426 auth_failed: 426 auth_failed:
diff --git a/loginutils/passwd.c b/loginutils/passwd.c
index a7006f054..150908932 100644
--- a/loginutils/passwd.c
+++ b/loginutils/passwd.c
@@ -17,11 +17,6 @@
17#include <syslog.h> 17#include <syslog.h>
18#include <sys/resource.h> /* setrlimit */ 18#include <sys/resource.h> /* setrlimit */
19 19
20static void nuke_str(char *str)
21{
22 if (str) memset(str, 0, strlen(str));
23}
24
25static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo) 20static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo)
26{ 21{
27 char salt[MAX_PW_SALT_LEN]; 22 char salt[MAX_PW_SALT_LEN];
diff --git a/loginutils/su.c b/loginutils/su.c
index 2ec05e125..c51f26f70 100644
--- a/loginutils/su.c
+++ b/loginutils/su.c
@@ -93,7 +93,7 @@ int su_main(int argc UNUSED_PARAM, char **argv)
93 93
94 pw = xgetpwnam(opt_username); 94 pw = xgetpwnam(opt_username);
95 95
96 if (cur_uid == 0 || correct_password(pw)) { 96 if (cur_uid == 0 || ask_and_check_password(pw) > 0) {
97 if (ENABLE_FEATURE_SU_SYSLOG) 97 if (ENABLE_FEATURE_SU_SYSLOG)
98 syslog(LOG_NOTICE, "%c %s %s:%s", 98 syslog(LOG_NOTICE, "%c %s %s:%s",
99 '+', tty, old_user, opt_username); 99 '+', tty, old_user, opt_username);
diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c
index 65e638489..2a2909937 100644
--- a/loginutils/sulogin.c
+++ b/loginutils/sulogin.c
@@ -14,24 +14,12 @@
14#include "libbb.h" 14#include "libbb.h"
15#include <syslog.h> 15#include <syslog.h>
16 16
17//static void catchalarm(int UNUSED_PARAM junk)
18//{
19// exit(EXIT_FAILURE);
20//}
21
22
23int sulogin_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 17int sulogin_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
24int sulogin_main(int argc UNUSED_PARAM, char **argv) 18int sulogin_main(int argc UNUSED_PARAM, char **argv)
25{ 19{
26 char *cp;
27 int timeout = 0; 20 int timeout = 0;
28 struct passwd *pwd; 21 struct passwd *pwd;
29 const char *shell; 22 const char *shell;
30#if ENABLE_FEATURE_SHADOWPASSWDS
31 /* Using _r function to avoid pulling in static buffers */
32 char buffer[256];
33 struct spwd spw;
34#endif
35 23
36 logmode = LOGMODE_BOTH; 24 logmode = LOGMODE_BOTH;
37 openlog(applet_name, 0, LOG_AUTH); 25 openlog(applet_name, 0, LOG_AUTH);
@@ -62,43 +50,24 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv)
62 goto auth_error; 50 goto auth_error;
63 } 51 }
64 52
65#if ENABLE_FEATURE_SHADOWPASSWDS
66 {
67 /* getspnam_r may return 0 yet set result to NULL.
68 * At least glibc 2.4 does this. Be extra paranoid here. */
69 struct spwd *result = NULL;
70 int r = getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result);
71 if (r || !result) {
72 goto auth_error;
73 }
74 pwd->pw_passwd = result->sp_pwdp;
75 }
76#endif
77
78 while (1) { 53 while (1) {
79 char *encrypted;
80 int r; 54 int r;
81 55
82 /* cp points to a static buffer */ 56 r = ask_and_check_password_extended(pwd, timeout,
83 cp = bb_ask(STDIN_FILENO, timeout, 57 "Give root password for system maintenance\n"
84 "Give root password for system maintenance\n" 58 "(or type Control-D for normal startup):"
85 "(or type Control-D for normal startup):"); 59 );
86 if (!cp) { 60 if (r < 0) {
87 /* ^D, ^C, timeout, or read error */ 61 /* ^D, ^C, timeout, or read error */
88 bb_info_msg("Normal startup"); 62 bb_info_msg("Normal startup");
89 return 0; 63 return 0;
90 } 64 }
91 encrypted = pw_encrypt(cp, pwd->pw_passwd, 1); 65 if (r > 0) {
92 r = strcmp(encrypted, pwd->pw_passwd);
93 free(encrypted);
94 if (r == 0) {
95 break; 66 break;
96 } 67 }
97 bb_do_delay(LOGIN_FAIL_DELAY); 68 bb_do_delay(LOGIN_FAIL_DELAY);
98 bb_info_msg("Login incorrect"); 69 bb_info_msg("Login incorrect");
99 } 70 }
100 memset(cp, 0, strlen(cp));
101// signal(SIGALRM, SIG_DFL);
102 71
103 bb_info_msg("System Maintenance Mode"); 72 bb_info_msg("System Maintenance Mode");
104 73
diff --git a/loginutils/vlock.c b/loginutils/vlock.c
index 75af9390e..44b14e6bc 100644
--- a/loginutils/vlock.c
+++ b/loginutils/vlock.c
@@ -104,7 +104,7 @@ int vlock_main(int argc UNUSED_PARAM, char **argv)
104 /* "s" if -a, else "": */ "s" + !option_mask32, 104 /* "s" if -a, else "": */ "s" + !option_mask32,
105 pw->pw_name 105 pw->pw_name
106 ); 106 );
107 if (correct_password(pw)) { 107 if (ask_and_check_password(pw) > 0) {
108 break; 108 break;
109 } 109 }
110 bb_do_delay(LOGIN_FAIL_DELAY); 110 bb_do_delay(LOGIN_FAIL_DELAY);
diff --git a/miscutils/Config.src b/miscutils/Config.src
index b9fc196d8..1da9800bd 100644
--- a/miscutils/Config.src
+++ b/miscutils/Config.src
@@ -503,18 +503,6 @@ config READAHEAD
503 As readahead(2) blocks until each file has been read, it is best to 503 As readahead(2) blocks until each file has been read, it is best to
504 run this applet as a background job. 504 run this applet as a background job.
505 505
506config RFKILL
507 bool "rfkill"
508 default n # doesn't build on Ubuntu 9.04
509 select PLATFORM_LINUX
510 help
511 Enable/disable wireless devices.
512
513 rfkill list : list all wireless devices
514 rfkill list bluetooth : list all bluetooth devices
515 rfkill list 1 : list device corresponding to the given index
516 rfkill block|unblock wlan : block/unblock all wlan(wifi) devices
517
518config RUNLEVEL 506config RUNLEVEL
519 bool "runlevel" 507 bool "runlevel"
520 default y 508 default y
@@ -591,13 +579,6 @@ config VOLNAME
591 help 579 help
592 Prints a CD-ROM volume name. 580 Prints a CD-ROM volume name.
593 581
594config WALL
595 bool "wall"
596 default y
597 depends on FEATURE_UTMP
598 help
599 Write a message to all users that are logged in.
600
601config WATCHDOG 582config WATCHDOG
602 bool "watchdog" 583 bool "watchdog"
603 default y 584 default y
diff --git a/miscutils/Kbuild.src b/miscutils/Kbuild.src
index 8c498643b..9e164f16e 100644
--- a/miscutils/Kbuild.src
+++ b/miscutils/Kbuild.src
@@ -36,7 +36,6 @@ lib-$(CONFIG_MOUNTPOINT) += mountpoint.o
36lib-$(CONFIG_MT) += mt.o 36lib-$(CONFIG_MT) += mt.o
37lib-$(CONFIG_RAIDAUTORUN) += raidautorun.o 37lib-$(CONFIG_RAIDAUTORUN) += raidautorun.o
38lib-$(CONFIG_READAHEAD) += readahead.o 38lib-$(CONFIG_READAHEAD) += readahead.o
39lib-$(CONFIG_RFKILL) += rfkill.o
40lib-$(CONFIG_RUNLEVEL) += runlevel.o 39lib-$(CONFIG_RUNLEVEL) += runlevel.o
41lib-$(CONFIG_RX) += rx.o 40lib-$(CONFIG_RX) += rx.o
42lib-$(CONFIG_SETSID) += setsid.o 41lib-$(CONFIG_SETSID) += setsid.o
@@ -46,5 +45,4 @@ lib-$(CONFIG_TIME) += time.o
46lib-$(CONFIG_TIMEOUT) += timeout.o 45lib-$(CONFIG_TIMEOUT) += timeout.o
47lib-$(CONFIG_TTYSIZE) += ttysize.o 46lib-$(CONFIG_TTYSIZE) += ttysize.o
48lib-$(CONFIG_VOLNAME) += volname.o 47lib-$(CONFIG_VOLNAME) += volname.o
49lib-$(CONFIG_WALL) += wall.o
50lib-$(CONFIG_WATCHDOG) += watchdog.o 48lib-$(CONFIG_WATCHDOG) += watchdog.o
diff --git a/miscutils/chat.c b/miscutils/chat.c
index ce994f870..bd2abc24a 100644
--- a/miscutils/chat.c
+++ b/miscutils/chat.c
@@ -296,7 +296,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
296 full_write(record_fd, buf+buf_len, 1); 296 full_write(record_fd, buf+buf_len, 1);
297 } 297 }
298 // dump device input if ECHO ON 298 // dump device input if ECHO ON
299 if (echo > 0) { 299 if (echo) {
300// if (buf[buf_len] < ' ') { 300// if (buf[buf_len] < ' ') {
301// full_write(STDERR_FILENO, "^", 1); 301// full_write(STDERR_FILENO, "^", 1);
302// buf[buf_len] += '@'; 302// buf[buf_len] += '@';
diff --git a/miscutils/crontab.c b/miscutils/crontab.c
index 4731d8da6..aad242fd8 100644
--- a/miscutils/crontab.c
+++ b/miscutils/crontab.c
@@ -55,28 +55,6 @@ static void edit_file(const struct passwd *pas, const char *file)
55 bb_perror_msg_and_die("can't execute '%s'", ptr); 55 bb_perror_msg_and_die("can't execute '%s'", ptr);
56} 56}
57 57
58static int open_as_user(const struct passwd *pas, const char *file)
59{
60 pid_t pid;
61 char c;
62
63 pid = xvfork();
64 if (pid) { /* PARENT */
65 if (wait4pid(pid) == 0) {
66 /* exitcode 0: child says it can read */
67 return open(file, O_RDONLY);
68 }
69 return -1;
70 }
71
72 /* CHILD */
73 /* initgroups, setgid, setuid */
74 change_identity(pas);
75 /* We just try to read one byte. If it works, file is readable
76 * under this user. We signal that by exiting with 0. */
77 _exit(safe_read(xopen(file, O_RDONLY), &c, 1) < 0);
78}
79
80int crontab_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 58int crontab_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
81int crontab_main(int argc UNUSED_PARAM, char **argv) 59int crontab_main(int argc UNUSED_PARAM, char **argv)
82{ 60{
@@ -137,10 +115,7 @@ int crontab_main(int argc UNUSED_PARAM, char **argv)
137 if (!argv[0]) 115 if (!argv[0])
138 bb_show_usage(); 116 bb_show_usage();
139 if (NOT_LONE_DASH(argv[0])) { 117 if (NOT_LONE_DASH(argv[0])) {
140 src_fd = open_as_user(pas, argv[0]); 118 src_fd = xopen_as_uid_gid(argv[0], O_RDONLY, pas->pw_uid, pas->pw_gid);
141 if (src_fd < 0)
142 bb_error_msg_and_die("user %s cannot read %s",
143 pas->pw_name, argv[0]);
144 } 119 }
145 } 120 }
146 121
diff --git a/miscutils/devfsd.c b/miscutils/devfsd.c
index 24c953bac..96ffe0738 100644
--- a/miscutils/devfsd.c
+++ b/miscutils/devfsd.c
@@ -1083,21 +1083,23 @@ static int get_uid_gid(int flag, const char *string)
1083{ 1083{
1084 struct passwd *pw_ent; 1084 struct passwd *pw_ent;
1085 struct group *grp_ent; 1085 struct group *grp_ent;
1086 static const char *msg; 1086 const char *msg;
1087 1087
1088 if (ENABLE_DEVFSD_VERBOSE) 1088 if (isdigit(string[0]) || ((string[0] == '-') && isdigit(string[1])))
1089 msg = "user";
1090
1091 if (isdigit(string[0]) ||((string[0] == '-') && isdigit(string[1])))
1092 return atoi(string); 1089 return atoi(string);
1093 1090
1094 if (flag == UID && (pw_ent = getpwnam(string)) != NULL) 1091 if (flag == UID && (pw_ent = getpwnam(string)) != NULL)
1095 return pw_ent->pw_uid; 1092 return pw_ent->pw_uid;
1096 1093
1097 if (flag == GID && (grp_ent = getgrnam(string)) != NULL) 1094 if (ENABLE_DEVFSD_VERBOSE)
1098 return grp_ent->gr_gid; 1095 msg = "user";
1099 else if (ENABLE_DEVFSD_VERBOSE) 1096
1100 msg = "group"; 1097 if (flag == GID) {
1098 if ((grp_ent = getgrnam(string)) != NULL)
1099 return grp_ent->gr_gid;
1100 if (ENABLE_DEVFSD_VERBOSE)
1101 msg = "group";
1102 }
1101 1103
1102 if (ENABLE_DEVFSD_VERBOSE) 1104 if (ENABLE_DEVFSD_VERBOSE)
1103 msg_logger(LOG_ERR, "unknown %s: %s, defaulting to %cid=0", msg, string, msg[0]); 1105 msg_logger(LOG_ERR, "unknown %s: %s, defaulting to %cid=0", msg, string, msg[0]);
diff --git a/miscutils/hdparm.c b/miscutils/hdparm.c
index 69726ae72..f0e9c9d75 100644
--- a/miscutils/hdparm.c
+++ b/miscutils/hdparm.c
@@ -465,14 +465,14 @@ static void on_off(int value)
465static void print_flag_on_off(int get_arg, const char *s, unsigned long arg) 465static void print_flag_on_off(int get_arg, const char *s, unsigned long arg)
466{ 466{
467 if (get_arg) { 467 if (get_arg) {
468 printf(" setting %s to %ld", s, arg); 468 printf(" setting %s to %lu", s, arg);
469 on_off(arg); 469 on_off(arg);
470 } 470 }
471} 471}
472 472
473static void print_value_on_off(const char *str, unsigned long argp) 473static void print_value_on_off(const char *str, unsigned long argp)
474{ 474{
475 printf(" %s\t= %2ld", str, argp); 475 printf(" %s\t= %2lu", str, argp);
476 on_off(argp != 0); 476 on_off(argp != 0);
477} 477}
478 478
@@ -1509,7 +1509,7 @@ static void bus_state_value(unsigned value)
1509 else if (value == BUSSTATE_TRISTATE) 1509 else if (value == BUSSTATE_TRISTATE)
1510 printf(" (tristate)\n"); 1510 printf(" (tristate)\n");
1511 else 1511 else
1512 printf(" (unknown: %d)\n", value); 1512 printf(" (unknown: %u)\n", value);
1513} 1513}
1514#endif 1514#endif
1515 1515
@@ -1589,7 +1589,7 @@ static void interpret_xfermode(unsigned xfermode)
1589static void print_flag(int flag, const char *s, unsigned long value) 1589static void print_flag(int flag, const char *s, unsigned long value)
1590{ 1590{
1591 if (flag) 1591 if (flag)
1592 printf(" setting %s to %ld\n", s, value); 1592 printf(" setting %s to %lu\n", s, value);
1593} 1593}
1594 1594
1595static void process_dev(char *devname) 1595static void process_dev(char *devname)
diff --git a/miscutils/rfkill.c b/miscutils/rfkill.c
index 467197371..7411b6fc3 100644
--- a/miscutils/rfkill.c
+++ b/miscutils/rfkill.c
@@ -7,6 +7,23 @@
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//config:config RFKILL
11//config: bool "rfkill"
12//config: default n # doesn't build on Ubuntu 9.04
13//config: select PLATFORM_LINUX
14//config: help
15//config: Enable/disable wireless devices.
16//config:
17//config: rfkill list : list all wireless devices
18//config: rfkill list bluetooth : list all bluetooth devices
19//config: rfkill list 1 : list device corresponding to the given index
20//config: rfkill block|unblock wlan : block/unblock all wlan(wifi) devices
21//config:
22
23//applet:IF_RFKILL(APPLET(rfkill, BB_DIR_USR_SBIN, BB_SUID_DROP))
24
25//kbuild:lib-$(CONFIG_RFKILL) += rfkill.o
26
10//usage:#define rfkill_trivial_usage 27//usage:#define rfkill_trivial_usage
11//usage: "COMMAND [INDEX|TYPE]" 28//usage: "COMMAND [INDEX|TYPE]"
12//usage:#define rfkill_full_usage "\n\n" 29//usage:#define rfkill_full_usage "\n\n"
diff --git a/miscutils/wall.c b/miscutils/wall.c
index 762f53b72..bb709ee39 100644
--- a/miscutils/wall.c
+++ b/miscutils/wall.c
@@ -6,6 +6,18 @@
6 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7 */ 7 */
8 8
9//config:config WALL
10//config: bool "wall"
11//config: default y
12//config: depends on FEATURE_UTMP
13//config: help
14//config: Write a message to all users that are logged in.
15
16/* Needs to be run by root or be suid root - needs to write to /dev/TTY: */
17//applet:IF_WALL(APPLET(wall, BB_DIR_USR_BIN, BB_SUID_REQUIRE))
18
19//kbuild:lib-$(CONFIG_WALL) += wall.o
20
9//usage:#define wall_trivial_usage 21//usage:#define wall_trivial_usage
10//usage: "[FILE]" 22//usage: "[FILE]"
11//usage:#define wall_full_usage "\n\n" 23//usage:#define wall_full_usage "\n\n"
@@ -22,8 +34,15 @@ int wall_main(int argc UNUSED_PARAM, char **argv)
22{ 34{
23 struct utmp *ut; 35 struct utmp *ut;
24 char *msg; 36 char *msg;
25 int fd = argv[1] ? xopen(argv[1], O_RDONLY) : STDIN_FILENO; 37 int fd;
26 38
39 fd = STDIN_FILENO;
40 if (argv[1]) {
41 /* The applet is setuid.
42 * Access to the file must be under user's uid/gid.
43 */
44 fd = xopen_as_uid_gid(argv[1], O_RDONLY, getuid(), getgid());
45 }
27 msg = xmalloc_read(fd, NULL); 46 msg = xmalloc_read(fd, NULL);
28 if (ENABLE_FEATURE_CLEAN_UP && argv[1]) 47 if (ENABLE_FEATURE_CLEAN_UP && argv[1])
29 close(fd); 48 close(fd);
diff --git a/networking/Config.src b/networking/Config.src
index e1ae0c9d5..ca0ddcdd9 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -970,16 +970,18 @@ config FEATURE_WGET_LONG_OPTIONS
970 Support long options for the wget applet. 970 Support long options for the wget applet.
971 971
972config FEATURE_WGET_TIMEOUT 972config FEATURE_WGET_TIMEOUT
973 bool "Enable read timeout option -T SEC" 973 bool "Enable timeout option -T SEC"
974 default y 974 default y
975 depends on WGET 975 depends on WGET
976 help 976 help
977 Supports network read timeout for wget, so that wget will give 977 Supports network read and connect timeouts for wget,
978 up and timeout when reading network data, through the -T command 978 so that wget will give up and timeout, through the -T
979 line option. Currently only network data read timeout is 979 command line option.
980 supported (i.e., timeout is not applied to the DNS nor TCP 980
981 connection initialization). When FEATURE_WGET_LONG_OPTIONS is 981 Currently only connect and network data read timeout are
982 also enabled, the --timeout option will work in addition to -T. 982 supported (i.e., timeout is not applied to the DNS query). When
983 FEATURE_WGET_LONG_OPTIONS is also enabled, the --timeout option
984 will work in addition to -T.
983 985
984config ZCIP 986config ZCIP
985 bool "zcip" 987 bool "zcip"
diff --git a/networking/arp.c b/networking/arp.c
index 40d244116..e79b1b6a1 100644
--- a/networking/arp.c
+++ b/networking/arp.c
@@ -459,12 +459,12 @@ static int arp_show(char *name)
459 arp_disp(hostname, ip, type, flags, hwa, mask, dev); 459 arp_disp(hostname, ip, type, flags, hwa, mask, dev);
460 } 460 }
461 if (option_mask32 & ARP_OPT_v) 461 if (option_mask32 & ARP_OPT_v)
462 printf("Entries: %d\tSkipped: %d\tFound: %d\n", 462 printf("Entries: %u\tSkipped: %u\tFound: %u\n",
463 entries, entries - shown, shown); 463 entries, entries - shown, shown);
464 464
465 if (!shown) { 465 if (!shown) {
466 if (hw_set || host || device[0]) 466 if (hw_set || host || device[0])
467 printf("No match found in %d entries\n", entries); 467 printf("No match found in %u entries\n", entries);
468 } 468 }
469 if (ENABLE_FEATURE_CLEAN_UP) { 469 if (ENABLE_FEATURE_CLEAN_UP) {
470 free((char*)host); 470 free((char*)host);
diff --git a/networking/ether-wake.c b/networking/ether-wake.c
index 2d389ea30..c38547dda 100644
--- a/networking/ether-wake.c
+++ b/networking/ether-wake.c
@@ -62,17 +62,17 @@
62 * An alternative to needing 'root' is using a UDP broadcast socket, however 62 * An alternative to needing 'root' is using a UDP broadcast socket, however
63 * doing so only works with adapters configured for unicast+broadcast Rx 63 * doing so only works with adapters configured for unicast+broadcast Rx
64 * filter. That configuration consumes more power. 64 * filter. That configuration consumes more power.
65*/ 65 */
66 66
67//usage:#define ether_wake_trivial_usage 67//usage:#define ether_wake_trivial_usage
68//usage: "[-b] [-i iface] [-p aa:bb:cc:dd[:ee:ff]] MAC" 68//usage: "[-b] [-i IFACE] [-p aa:bb:cc:dd[:ee:ff]/a.b.c.d] MAC"
69//usage:#define ether_wake_full_usage "\n\n" 69//usage:#define ether_wake_full_usage "\n\n"
70//usage: "Send a magic packet to wake up sleeping machines.\n" 70//usage: "Send a magic packet to wake up sleeping machines.\n"
71//usage: "MAC must be a station address (00:11:22:33:44:55) or\n" 71//usage: "MAC must be a station address (00:11:22:33:44:55) or\n"
72//usage: "a hostname with a known 'ethers' entry.\n" 72//usage: "a hostname with a known 'ethers' entry.\n"
73//usage: "\n -b Send wake-up packet to the broadcast address" 73//usage: "\n -b Broadcast the packet"
74//usage: "\n -i iface Interface to use (default eth0)" 74//usage: "\n -i IFACE Interface to use (default eth0)"
75//usage: "\n -p pass Append four or six byte password PW to the packet" 75//usage: "\n -p PASSWORD Append four or six byte PASSWORD to the packet"
76 76
77#include "libbb.h" 77#include "libbb.h"
78#include <netpacket/packet.h> 78#include <netpacket/packet.h>
@@ -130,7 +130,8 @@ static void get_dest_addr(const char *hostid, struct ether_addr *eaddr)
130 } 130 }
131} 131}
132 132
133static int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast) 133#define PKT_HEADER_SIZE (20 + 16*6)
134static int fill_pkt_header(unsigned char *pkt, struct ether_addr *eaddr, int broadcast)
134{ 135{
135 int i; 136 int i;
136 unsigned char *station_addr = eaddr->ether_addr_octet; 137 unsigned char *station_addr = eaddr->ether_addr_octet;
@@ -153,7 +154,7 @@ static int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast)
153 memcpy(pkt, station_addr, 6); /* 20,26,32,... */ 154 memcpy(pkt, station_addr, 6); /* 20,26,32,... */
154 } 155 }
155 156
156 return 20 + 16*6; /* length of packet */ 157 return PKT_HEADER_SIZE; /* length of packet */
157} 158}
158 159
159static int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd) 160static int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd)
@@ -195,7 +196,7 @@ int ether_wake_main(int argc UNUSED_PARAM, char **argv)
195 int wol_passwd_sz = 0; 196 int wol_passwd_sz = 0;
196 int s; /* Raw socket */ 197 int s; /* Raw socket */
197 int pktsize; 198 int pktsize;
198 unsigned char outpack[1000]; 199 unsigned char outpack[PKT_HEADER_SIZE + 6 /* max passwd size */ + 16 /* paranoia */];
199 200
200 struct ether_addr eaddr; 201 struct ether_addr eaddr;
201 struct whereto_t whereto; /* who to wake up */ 202 struct whereto_t whereto; /* who to wake up */
@@ -217,7 +218,7 @@ int ether_wake_main(int argc UNUSED_PARAM, char **argv)
217 get_dest_addr(argv[optind], &eaddr); 218 get_dest_addr(argv[optind], &eaddr);
218 219
219 /* fill out the header of the packet */ 220 /* fill out the header of the packet */
220 pktsize = get_fill(outpack, &eaddr, flags /* & 1 OPT_BROADCAST */); 221 pktsize = fill_pkt_header(outpack, &eaddr, flags /* & 1 OPT_BROADCAST */);
221 222
222 bb_debug_dump_packet(outpack, pktsize); 223 bb_debug_dump_packet(outpack, pktsize);
223 224
diff --git a/networking/hostname.c b/networking/hostname.c
index d2516b5fb..b3e352242 100644
--- a/networking/hostname.c
+++ b/networking/hostname.c
@@ -106,7 +106,7 @@ int hostname_main(int argc UNUSED_PARAM, char **argv)
106 OPT_i = 0x4, 106 OPT_i = 0x4,
107 OPT_s = 0x8, 107 OPT_s = 0x8,
108 OPT_F = 0x10, 108 OPT_F = 0x10,
109 OPT_dfis = 0xf, 109 OPT_dfi = 0x7,
110 }; 110 };
111 111
112 unsigned opts; 112 unsigned opts;
@@ -134,7 +134,7 @@ int hostname_main(int argc UNUSED_PARAM, char **argv)
134 if (applet_name[0] == 'd') /* dnsdomainname? */ 134 if (applet_name[0] == 'd') /* dnsdomainname? */
135 opts = OPT_d; 135 opts = OPT_d;
136 136
137 if (opts & OPT_dfis) { 137 if (opts & OPT_dfi) {
138 /* Cases when we need full hostname (or its part) */ 138 /* Cases when we need full hostname (or its part) */
139 struct hostent *hp; 139 struct hostent *hp;
140 char *p; 140 char *p;
@@ -159,6 +159,9 @@ int hostname_main(int argc UNUSED_PARAM, char **argv)
159 bb_putchar('\n'); 159 bb_putchar('\n');
160 } 160 }
161 } 161 }
162 } else if (opts & OPT_s) {
163 strchrnul(buf, '.')[0] = '\0';
164 puts(buf);
162 } else if (opts & OPT_F) { 165 } else if (opts & OPT_F) {
163 /* Set the hostname */ 166 /* Set the hostname */
164 do_sethostname(hostname_str, 1); 167 do_sethostname(hostname_str, 1);
diff --git a/networking/httpd.c b/networking/httpd.c
index cef9b8baf..621d9cddc 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -1104,18 +1104,31 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1104 1104
1105 /* NB: breaking out of this loop jumps to log_and_exit() */ 1105 /* NB: breaking out of this loop jumps to log_and_exit() */
1106 out_cnt = 0; 1106 out_cnt = 0;
1107 pfd[FROM_CGI].fd = fromCgi_rd;
1108 pfd[FROM_CGI].events = POLLIN;
1109 pfd[TO_CGI].fd = toCgi_wr;
1107 while (1) { 1110 while (1) {
1108 memset(pfd, 0, sizeof(pfd)); 1111 /* Note: even pfd[0].events == 0 won't prevent
1109 1112 * revents == POLLHUP|POLLERR reports from closed stdin.
1110 pfd[FROM_CGI].fd = fromCgi_rd; 1113 * Setting fd to -1 works: */
1111 pfd[FROM_CGI].events = POLLIN; 1114 pfd[0].fd = -1;
1112 1115 pfd[0].events = POLLIN;
1113 if (toCgi_wr) { 1116 pfd[0].revents = 0; /* probably not needed, paranoia */
1114 pfd[TO_CGI].fd = toCgi_wr; 1117
1115 if (hdr_cnt > 0) { 1118 /* We always poll this fd, thus kernel always sets revents: */
1116 pfd[TO_CGI].events = POLLOUT; 1119 /*pfd[FROM_CGI].events = POLLIN; - moved out of loop */
1117 } else if (post_len > 0) { 1120 /*pfd[FROM_CGI].revents = 0; - not needed */
1118 pfd[0].events = POLLIN; 1121
1122 /* gcc-4.8.0 still doesnt fill two shorts with one insn :( */
1123 /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47059 */
1124 /* hopefully one day it will... */
1125 pfd[TO_CGI].events = POLLOUT;
1126 pfd[TO_CGI].revents = 0; /* needed! */
1127
1128 if (toCgi_wr && hdr_cnt <= 0) {
1129 if (post_len > 0) {
1130 /* Expect more POST data from network */
1131 pfd[0].fd = 0;
1119 } else { 1132 } else {
1120 /* post_len <= 0 && hdr_cnt <= 0: 1133 /* post_len <= 0 && hdr_cnt <= 0:
1121 * no more POST data to CGI, 1134 * no more POST data to CGI,
@@ -1127,7 +1140,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1127 } 1140 }
1128 1141
1129 /* Now wait on the set of sockets */ 1142 /* Now wait on the set of sockets */
1130 count = safe_poll(pfd, toCgi_wr ? TO_CGI+1 : FROM_CGI+1, -1); 1143 count = safe_poll(pfd, hdr_cnt > 0 ? TO_CGI+1 : FROM_CGI+1, -1);
1131 if (count <= 0) { 1144 if (count <= 0) {
1132#if 0 1145#if 0
1133 if (safe_waitpid(pid, &status, WNOHANG) <= 0) { 1146 if (safe_waitpid(pid, &status, WNOHANG) <= 0) {
@@ -1144,7 +1157,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
1144 } 1157 }
1145 1158
1146 if (pfd[TO_CGI].revents) { 1159 if (pfd[TO_CGI].revents) {
1147 /* hdr_cnt > 0 here due to the way pfd[TO_CGI].events set */ 1160 /* hdr_cnt > 0 here due to the way poll() called */
1148 /* Have data from peer and can write to CGI */ 1161 /* Have data from peer and can write to CGI */
1149 count = safe_write(toCgi_wr, hdr_ptr, hdr_cnt); 1162 count = safe_write(toCgi_wr, hdr_ptr, hdr_cnt);
1150 /* Doesn't happen, we dont use nonblocking IO here 1163 /* Doesn't happen, we dont use nonblocking IO here
diff --git a/networking/netstat.c b/networking/netstat.c
index c0c6ba501..f80b845bc 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -125,10 +125,10 @@ typedef enum {
125 */ 125 */
126#define ADDR_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ 126#define ADDR_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */
127#if ENABLE_FEATURE_NETSTAT_WIDE 127#if ENABLE_FEATURE_NETSTAT_WIDE
128# define FMT_NET_CONN_DATA "%s %6ld %6ld %-*s %-*s %-12s" 128# define FMT_NET_CONN_DATA "%s %6lu %6lu %-*s %-*s %-12s"
129# define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-*s %-*s State %s\n" 129# define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-*s %-*s State %s\n"
130#else 130#else
131# define FMT_NET_CONN_DATA "%s %6ld %6ld %-23s %-23s %-12s" 131# define FMT_NET_CONN_DATA "%s %6lu %6lu %-23s %-23s %-12s"
132# define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State %s\n" 132# define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State %s\n"
133#endif 133#endif
134 134
@@ -403,7 +403,7 @@ static int scan_inet_proc_line(struct inet_params *param, char *line)
403 "%*d: %32[0-9A-Fa-f]:%X " 403 "%*d: %32[0-9A-Fa-f]:%X "
404 "%32[0-9A-Fa-f]:%X %X " 404 "%32[0-9A-Fa-f]:%X %X "
405 "%lX:%lX %*X:%*X " 405 "%lX:%lX %*X:%*X "
406 "%*X %d %*d %ld ", 406 "%*X %d %*d %lu ",
407 local_addr, &param->local_port, 407 local_addr, &param->local_port,
408 rem_addr, &param->rem_port, &param->state, 408 rem_addr, &param->rem_port, &param->state,
409 &param->txq, &param->rxq, 409 &param->txq, &param->rxq,
@@ -611,7 +611,7 @@ static int FAST_FUNC unix_do_one(char *line)
611 strcat(ss_flags, "N "); 611 strcat(ss_flags, "N ");
612 strcat(ss_flags, "]"); 612 strcat(ss_flags, "]");
613 613
614 printf("%-5s %-6ld %-11s %-10s %-13s %6lu ", 614 printf("%-5s %-6lu %-11s %-10s %-13s %6lu ",
615 ss_proto, refcnt, ss_flags, ss_type, ss_state, inode 615 ss_proto, refcnt, ss_flags, ss_type, ss_state, inode
616 ); 616 );
617 617
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 99817e83b..ed83415b4 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -57,10 +57,10 @@
57 57
58 58
59/* Verbosity control (max level of -dddd options accepted). 59/* Verbosity control (max level of -dddd options accepted).
60 * max 5 is very talkative (and bloated). 2 is non-bloated, 60 * max 6 is very talkative (and bloated). 3 is non-bloated,
61 * production level setting. 61 * production level setting.
62 */ 62 */
63#define MAX_VERBOSE 2 63#define MAX_VERBOSE 3
64 64
65 65
66/* High-level description of the algorithm: 66/* High-level description of the algorithm:
@@ -90,12 +90,24 @@
90 * was hibernated, someone set totally wrong date, etc), 90 * was hibernated, someone set totally wrong date, etc),
91 * then the time is stepped, all datapoints are discarded, 91 * then the time is stepped, all datapoints are discarded,
92 * and we go back to steady state. 92 * and we go back to steady state.
93 *
94 * Made some changes to speed up re-syncing after our clock goes bad
95 * (tested with suspending my laptop):
96 * - if largish offset (>= STEP_THRESHOLD * 8 == 1 sec) is seen
97 * from a peer, schedule next query for this peer soon
98 * without drastically lowering poll interval for everybody.
99 * This makes us collect enough data for step much faster:
100 * e.g. at poll = 10 (1024 secs), step was done within 5 minutes
101 * after first reply which indicated that our clock is 14 seconds off.
102 * - on step, do not discard d_dispersion data of the existing datapoints,
103 * do not clear reachable_bits. This prevents discarding first ~8
104 * datapoints after the step.
93 */ 105 */
94 106
95#define RETRY_INTERVAL 5 /* on error, retry in N secs */ 107#define RETRY_INTERVAL 5 /* on error, retry in N secs */
96#define RESPONSE_INTERVAL 15 /* wait for reply up to N secs */ 108#define RESPONSE_INTERVAL 15 /* wait for reply up to N secs */
97#define INITIAL_SAMPLES 4 /* how many samples do we want for init */ 109#define INITIAL_SAMPLES 4 /* how many samples do we want for init */
98#define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this */ 110#define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this */
99 111
100/* Clock discipline parameters and constants */ 112/* Clock discipline parameters and constants */
101 113
@@ -109,6 +121,10 @@
109#define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */ 121#define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */
110#define BURSTPOLL 0 /* initial poll */ 122#define BURSTPOLL 0 /* initial poll */
111#define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ 123#define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */
124/* If we got largish offset from a peer, cap next query interval
125 * for this peer by this many seconds:
126 */
127#define BIGOFF_INTERVAL (1 << 6)
112/* If offset > discipline_jitter * POLLADJ_GATE, and poll interval is >= 2^BIGPOLL, 128/* If offset > discipline_jitter * POLLADJ_GATE, and poll interval is >= 2^BIGPOLL,
113 * then it is decreased _at once_. (If < 2^BIGPOLL, it will be decreased _eventually_). 129 * then it is decreased _at once_. (If < 2^BIGPOLL, it will be decreased _eventually_).
114 */ 130 */
@@ -334,7 +350,7 @@ struct globals {
334 350
335#define STATE_NSET 0 /* initial state, "nothing is set" */ 351#define STATE_NSET 0 /* initial state, "nothing is set" */
336//#define STATE_FSET 1 /* frequency set from file */ 352//#define STATE_FSET 1 /* frequency set from file */
337#define STATE_SPIK 2 /* spike detected */ 353//#define STATE_SPIK 2 /* spike detected */
338//#define STATE_FREQ 3 /* initial frequency */ 354//#define STATE_FREQ 3 /* initial frequency */
339#define STATE_SYNC 4 /* clock synchronized (normal operation) */ 355#define STATE_SYNC 4 /* clock synchronized (normal operation) */
340 uint8_t discipline_state; // doc calls it c.state 356 uint8_t discipline_state; // doc calls it c.state
@@ -367,6 +383,7 @@ static const int const_IPTOS_LOWDELAY = IPTOS_LOWDELAY;
367#define VERB3 if (MAX_VERBOSE >= 3 && G.verbose >= 3) 383#define VERB3 if (MAX_VERBOSE >= 3 && G.verbose >= 3)
368#define VERB4 if (MAX_VERBOSE >= 4 && G.verbose >= 4) 384#define VERB4 if (MAX_VERBOSE >= 4 && G.verbose >= 4)
369#define VERB5 if (MAX_VERBOSE >= 5 && G.verbose >= 5) 385#define VERB5 if (MAX_VERBOSE >= 5 && G.verbose >= 5)
386#define VERB6 if (MAX_VERBOSE >= 6 && G.verbose >= 6)
370 387
371 388
372static double LOG2D(int a) 389static double LOG2D(int a)
@@ -568,7 +585,7 @@ filter_datapoints(peer_t *p)
568 got_newest = 0; 585 got_newest = 0;
569 sum = 0; 586 sum = 0;
570 for (i = 0; i < NUM_DATAPOINTS; i++) { 587 for (i = 0; i < NUM_DATAPOINTS; i++) {
571 VERB4 { 588 VERB5 {
572 bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s", 589 bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s",
573 i, 590 i,
574 fdp[idx].d_offset, 591 fdp[idx].d_offset,
@@ -665,7 +682,7 @@ filter_datapoints(peer_t *p)
665 sum = SQRT(sum / NUM_DATAPOINTS); 682 sum = SQRT(sum / NUM_DATAPOINTS);
666 p->filter_jitter = sum > G_precision_sec ? sum : G_precision_sec; 683 p->filter_jitter = sum > G_precision_sec ? sum : G_precision_sec;
667 684
668 VERB3 bb_error_msg("filter offset:%+f disp:%f jitter:%f", 685 VERB4 bb_error_msg("filter offset:%+f disp:%f jitter:%f",
669 p->filter_offset, 686 p->filter_offset,
670 p->filter_dispersion, 687 p->filter_dispersion,
671 p->filter_jitter); 688 p->filter_jitter);
@@ -677,6 +694,18 @@ reset_peer_stats(peer_t *p, double offset)
677 int i; 694 int i;
678 bool small_ofs = fabs(offset) < 16 * STEP_THRESHOLD; 695 bool small_ofs = fabs(offset) < 16 * STEP_THRESHOLD;
679 696
697 /* Used to set p->filter_datapoint[i].d_dispersion = MAXDISP
698 * and clear reachable bits, but this proved to be too agressive:
699 * after step (tested with suspinding laptop for ~30 secs),
700 * this caused all previous data to be considered invalid,
701 * making us needing to collect full ~8 datapoins per peer
702 * after step in order to start trusting them.
703 * In turn, this was making poll interval decrease even after
704 * step was done. (Poll interval decreases already before step
705 * in this scenario, because we see large offsets and end up with
706 * no good peer to select).
707 */
708
680 for (i = 0; i < NUM_DATAPOINTS; i++) { 709 for (i = 0; i < NUM_DATAPOINTS; i++) {
681 if (small_ofs) { 710 if (small_ofs) {
682 p->filter_datapoint[i].d_recv_time += offset; 711 p->filter_datapoint[i].d_recv_time += offset;
@@ -690,17 +719,17 @@ reset_peer_stats(peer_t *p, double offset)
690 } else { 719 } else {
691 p->filter_datapoint[i].d_recv_time = G.cur_time; 720 p->filter_datapoint[i].d_recv_time = G.cur_time;
692 p->filter_datapoint[i].d_offset = 0; 721 p->filter_datapoint[i].d_offset = 0;
693 p->filter_datapoint[i].d_dispersion = MAXDISP; 722 /*p->filter_datapoint[i].d_dispersion = MAXDISP;*/
694 } 723 }
695 } 724 }
696 if (small_ofs) { 725 if (small_ofs) {
697 p->lastpkt_recv_time += offset; 726 p->lastpkt_recv_time += offset;
698 } else { 727 } else {
699 p->reachable_bits = 0; 728 /*p->reachable_bits = 0;*/
700 p->lastpkt_recv_time = G.cur_time; 729 p->lastpkt_recv_time = G.cur_time;
701 } 730 }
702 filter_datapoints(p); /* recalc p->filter_xxx */ 731 filter_datapoints(p); /* recalc p->filter_xxx */
703 VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); 732 VERB6 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time);
704} 733}
705 734
706static void 735static void
@@ -972,20 +1001,20 @@ fit(peer_t *p, double rd)
972{ 1001{
973 if ((p->reachable_bits & (p->reachable_bits-1)) == 0) { 1002 if ((p->reachable_bits & (p->reachable_bits-1)) == 0) {
974 /* One or zero bits in reachable_bits */ 1003 /* One or zero bits in reachable_bits */
975 VERB3 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted); 1004 VERB4 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted);
976 return 0; 1005 return 0;
977 } 1006 }
978#if 0 /* we filter out such packets earlier */ 1007#if 0 /* we filter out such packets earlier */
979 if ((p->lastpkt_status & LI_ALARM) == LI_ALARM 1008 if ((p->lastpkt_status & LI_ALARM) == LI_ALARM
980 || p->lastpkt_stratum >= MAXSTRAT 1009 || p->lastpkt_stratum >= MAXSTRAT
981 ) { 1010 ) {
982 VERB3 bb_error_msg("peer %s unfit for selection: bad status/stratum", p->p_dotted); 1011 VERB4 bb_error_msg("peer %s unfit for selection: bad status/stratum", p->p_dotted);
983 return 0; 1012 return 0;
984 } 1013 }
985#endif 1014#endif
986 /* rd is root_distance(p) */ 1015 /* rd is root_distance(p) */
987 if (rd > MAXDIST + FREQ_TOLERANCE * (1 << G.poll_exp)) { 1016 if (rd > MAXDIST + FREQ_TOLERANCE * (1 << G.poll_exp)) {
988 VERB3 bb_error_msg("peer %s unfit for selection: root distance too high", p->p_dotted); 1017 VERB4 bb_error_msg("peer %s unfit for selection: root distance too high", p->p_dotted);
989 return 0; 1018 return 0;
990 } 1019 }
991//TODO 1020//TODO
@@ -1025,7 +1054,7 @@ select_and_cluster(void)
1025 continue; 1054 continue;
1026 } 1055 }
1027 1056
1028 VERB4 bb_error_msg("interval: [%f %f %f] %s", 1057 VERB5 bb_error_msg("interval: [%f %f %f] %s",
1029 offset - rd, 1058 offset - rd,
1030 offset, 1059 offset,
1031 offset + rd, 1060 offset + rd,
@@ -1050,7 +1079,7 @@ select_and_cluster(void)
1050 } 1079 }
1051 num_candidates = num_points / 3; 1080 num_candidates = num_points / 3;
1052 if (num_candidates == 0) { 1081 if (num_candidates == 0) {
1053 VERB3 bb_error_msg("no valid datapoints, no peer selected"); 1082 VERB3 bb_error_msg("no valid datapoints%s", ", no peer selected");
1054 return NULL; 1083 return NULL;
1055 } 1084 }
1056//TODO: sorting does not seem to be done in reference code 1085//TODO: sorting does not seem to be done in reference code
@@ -1108,12 +1137,13 @@ select_and_cluster(void)
1108 break; 1137 break;
1109 num_falsetickers++; 1138 num_falsetickers++;
1110 if (num_falsetickers * 2 >= num_candidates) { 1139 if (num_falsetickers * 2 >= num_candidates) {
1111 VERB3 bb_error_msg("too many falsetickers:%d (candidates:%d), no peer selected", 1140 VERB3 bb_error_msg("falsetickers:%d, candidates:%d%s",
1112 num_falsetickers, num_candidates); 1141 num_falsetickers, num_candidates,
1142 ", no peer selected");
1113 return NULL; 1143 return NULL;
1114 } 1144 }
1115 } 1145 }
1116 VERB3 bb_error_msg("selected interval: [%f, %f]; candidates:%d falsetickers:%d", 1146 VERB4 bb_error_msg("selected interval: [%f, %f]; candidates:%d falsetickers:%d",
1117 low, high, num_candidates, num_falsetickers); 1147 low, high, num_candidates, num_falsetickers);
1118 1148
1119 /* Clustering */ 1149 /* Clustering */
@@ -1131,7 +1161,7 @@ select_and_cluster(void)
1131 survivor[num_survivors].p = p; 1161 survivor[num_survivors].p = p;
1132 /* x.opt_rd == root_distance(p); */ 1162 /* x.opt_rd == root_distance(p); */
1133 survivor[num_survivors].metric = MAXDIST * p->lastpkt_stratum + point[i].opt_rd; 1163 survivor[num_survivors].metric = MAXDIST * p->lastpkt_stratum + point[i].opt_rd;
1134 VERB4 bb_error_msg("survivor[%d] metric:%f peer:%s", 1164 VERB5 bb_error_msg("survivor[%d] metric:%f peer:%s",
1135 num_survivors, survivor[num_survivors].metric, p->p_dotted); 1165 num_survivors, survivor[num_survivors].metric, p->p_dotted);
1136 num_survivors++; 1166 num_survivors++;
1137 } 1167 }
@@ -1141,8 +1171,9 @@ select_and_cluster(void)
1141 * is acceptable. 1171 * is acceptable.
1142 */ 1172 */
1143 if (num_survivors < MIN_SELECTED) { 1173 if (num_survivors < MIN_SELECTED) {
1144 VERB3 bb_error_msg("num_survivors %d < %d, no peer selected", 1174 VERB3 bb_error_msg("survivors:%d%s",
1145 num_survivors, MIN_SELECTED); 1175 num_survivors,
1176 ", no peer selected");
1146 return NULL; 1177 return NULL;
1147 } 1178 }
1148 1179
@@ -1162,7 +1193,7 @@ select_and_cluster(void)
1162 double min_jitter = min_jitter; 1193 double min_jitter = min_jitter;
1163 1194
1164 if (num_survivors <= MIN_CLUSTERED) { 1195 if (num_survivors <= MIN_CLUSTERED) {
1165 VERB3 bb_error_msg("num_survivors %d <= %d, not discarding more", 1196 VERB4 bb_error_msg("num_survivors %d <= %d, not discarding more",
1166 num_survivors, MIN_CLUSTERED); 1197 num_survivors, MIN_CLUSTERED);
1167 break; 1198 break;
1168 } 1199 }
@@ -1188,11 +1219,11 @@ select_and_cluster(void)
1188 max_selection_jitter = selection_jitter_sq; 1219 max_selection_jitter = selection_jitter_sq;
1189 max_idx = i; 1220 max_idx = i;
1190 } 1221 }
1191 VERB5 bb_error_msg("survivor %d selection_jitter^2:%f", 1222 VERB6 bb_error_msg("survivor %d selection_jitter^2:%f",
1192 i, selection_jitter_sq); 1223 i, selection_jitter_sq);
1193 } 1224 }
1194 max_selection_jitter = SQRT(max_selection_jitter / num_survivors); 1225 max_selection_jitter = SQRT(max_selection_jitter / num_survivors);
1195 VERB4 bb_error_msg("max_selection_jitter (at %d):%f min_jitter:%f", 1226 VERB5 bb_error_msg("max_selection_jitter (at %d):%f min_jitter:%f",
1196 max_idx, max_selection_jitter, min_jitter); 1227 max_idx, max_selection_jitter, min_jitter);
1197 1228
1198 /* If the maximum selection jitter is less than the 1229 /* If the maximum selection jitter is less than the
@@ -1201,7 +1232,7 @@ select_and_cluster(void)
1201 * as well stop. 1232 * as well stop.
1202 */ 1233 */
1203 if (max_selection_jitter < min_jitter) { 1234 if (max_selection_jitter < min_jitter) {
1204 VERB3 bb_error_msg("max_selection_jitter:%f < min_jitter:%f, num_survivors:%d, not discarding more", 1235 VERB4 bb_error_msg("max_selection_jitter:%f < min_jitter:%f, num_survivors:%d, not discarding more",
1205 max_selection_jitter, min_jitter, num_survivors); 1236 max_selection_jitter, min_jitter, num_survivors);
1206 break; 1237 break;
1207 } 1238 }
@@ -1209,7 +1240,7 @@ select_and_cluster(void)
1209 /* Delete survivor[max_idx] from the list 1240 /* Delete survivor[max_idx] from the list
1210 * and go around again. 1241 * and go around again.
1211 */ 1242 */
1212 VERB5 bb_error_msg("dropping survivor %d", max_idx); 1243 VERB6 bb_error_msg("dropping survivor %d", max_idx);
1213 num_survivors--; 1244 num_survivors--;
1214 while (max_idx < num_survivors) { 1245 while (max_idx < num_survivors) {
1215 survivor[max_idx] = survivor[max_idx + 1]; 1246 survivor[max_idx] = survivor[max_idx + 1];
@@ -1251,7 +1282,7 @@ select_and_cluster(void)
1251 /* Starting from 1 is ok here */ 1282 /* Starting from 1 is ok here */
1252 for (i = 1; i < num_survivors; i++) { 1283 for (i = 1; i < num_survivors; i++) {
1253 if (G.last_update_peer == survivor[i].p) { 1284 if (G.last_update_peer == survivor[i].p) {
1254 VERB4 bb_error_msg("keeping old synced peer"); 1285 VERB5 bb_error_msg("keeping old synced peer");
1255 p = G.last_update_peer; 1286 p = G.last_update_peer;
1256 goto keep_old; 1287 goto keep_old;
1257 } 1288 }
@@ -1259,7 +1290,7 @@ select_and_cluster(void)
1259 } 1290 }
1260 G.last_update_peer = p; 1291 G.last_update_peer = p;
1261 keep_old: 1292 keep_old:
1262 VERB3 bb_error_msg("selected peer %s filter_offset:%+f age:%f", 1293 VERB4 bb_error_msg("selected peer %s filter_offset:%+f age:%f",
1263 p->p_dotted, 1294 p->p_dotted,
1264 p->filter_offset, 1295 p->filter_offset,
1265 G.cur_time - p->lastpkt_recv_time 1296 G.cur_time - p->lastpkt_recv_time
@@ -1278,7 +1309,7 @@ set_new_values(int disc_state, double offset, double recv_time)
1278 * of the last clock filter sample, which must be earlier than 1309 * of the last clock filter sample, which must be earlier than
1279 * the current time. 1310 * the current time.
1280 */ 1311 */
1281 VERB3 bb_error_msg("disc_state=%d last update offset=%f recv_time=%f", 1312 VERB4 bb_error_msg("disc_state=%d last update offset=%f recv_time=%f",
1282 disc_state, offset, recv_time); 1313 disc_state, offset, recv_time);
1283 G.discipline_state = disc_state; 1314 G.discipline_state = disc_state;
1284 G.last_update_offset = offset; 1315 G.last_update_offset = offset;
@@ -1316,8 +1347,8 @@ update_local_clock(peer_t *p)
1316 * an old sample or the same sample twice. 1347 * an old sample or the same sample twice.
1317 */ 1348 */
1318 if (recv_time <= G.last_update_recv_time) { 1349 if (recv_time <= G.last_update_recv_time) {
1319 VERB3 bb_error_msg("same or older datapoint: %f >= %f, not using it", 1350 VERB3 bb_error_msg("update from %s: same or older datapoint, not using it",
1320 G.last_update_recv_time, recv_time); 1351 p->p_dotted);
1321 return 0; /* "leave poll interval as is" */ 1352 return 0; /* "leave poll interval as is" */
1322 } 1353 }
1323 1354
@@ -1333,7 +1364,7 @@ update_local_clock(peer_t *p)
1333 if (G.discipline_state == STATE_FREQ) { 1364 if (G.discipline_state == STATE_FREQ) {
1334 /* Ignore updates until the stepout threshold */ 1365 /* Ignore updates until the stepout threshold */
1335 if (since_last_update < WATCH_THRESHOLD) { 1366 if (since_last_update < WATCH_THRESHOLD) {
1336 VERB3 bb_error_msg("measuring drift, datapoint ignored, %f sec remains", 1367 VERB4 bb_error_msg("measuring drift, datapoint ignored, %f sec remains",
1337 WATCH_THRESHOLD - since_last_update); 1368 WATCH_THRESHOLD - since_last_update);
1338 return 0; /* "leave poll interval as is" */ 1369 return 0; /* "leave poll interval as is" */
1339 } 1370 }
@@ -1347,10 +1378,21 @@ update_local_clock(peer_t *p)
1347 * offset exceeds the step threshold and when it does not. 1378 * offset exceeds the step threshold and when it does not.
1348 */ 1379 */
1349 if (abs_offset > STEP_THRESHOLD) { 1380 if (abs_offset > STEP_THRESHOLD) {
1381#if 0
1382 double remains;
1383
1384// This "spike state" seems to be useless, peer selection already drops
1385// occassional "bad" datapoints. If we are here, there were _many_
1386// large offsets. When a few first large offsets are seen,
1387// we end up in "no valid datapoints, no peer selected" state.
1388// Only when enough of them are seen (which means it's not a fluke),
1389// we end up here. Looks like _our_ clock is off.
1350 switch (G.discipline_state) { 1390 switch (G.discipline_state) {
1351 case STATE_SYNC: 1391 case STATE_SYNC:
1352 /* The first outlyer: ignore it, switch to SPIK state */ 1392 /* The first outlyer: ignore it, switch to SPIK state */
1353 VERB3 bb_error_msg("offset:%+f - spike detected", offset); 1393 VERB3 bb_error_msg("update from %s: offset:%+f, spike%s",
1394 p->p_dotted, offset,
1395 "");
1354 G.discipline_state = STATE_SPIK; 1396 G.discipline_state = STATE_SPIK;
1355 return -1; /* "decrease poll interval" */ 1397 return -1; /* "decrease poll interval" */
1356 1398
@@ -1358,13 +1400,16 @@ update_local_clock(peer_t *p)
1358 /* Ignore succeeding outlyers until either an inlyer 1400 /* Ignore succeeding outlyers until either an inlyer
1359 * is found or the stepout threshold is exceeded. 1401 * is found or the stepout threshold is exceeded.
1360 */ 1402 */
1361 if (since_last_update < WATCH_THRESHOLD) { 1403 remains = WATCH_THRESHOLD - since_last_update;
1362 VERB3 bb_error_msg("spike detected, datapoint ignored, %f sec remains", 1404 if (remains > 0) {
1363 WATCH_THRESHOLD - since_last_update); 1405 VERB3 bb_error_msg("update from %s: offset:%+f, spike%s",
1406 p->p_dotted, offset,
1407 ", datapoint ignored");
1364 return -1; /* "decrease poll interval" */ 1408 return -1; /* "decrease poll interval" */
1365 } 1409 }
1366 /* fall through: we need to step */ 1410 /* fall through: we need to step */
1367 } /* switch */ 1411 } /* switch */
1412#endif
1368 1413
1369 /* Step the time and clamp down the poll interval. 1414 /* Step the time and clamp down the poll interval.
1370 * 1415 *
@@ -1387,7 +1432,7 @@ update_local_clock(peer_t *p)
1387 * is always suppressed, even at the longer poll 1432 * is always suppressed, even at the longer poll
1388 * intervals. 1433 * intervals.
1389 */ 1434 */
1390 VERB3 bb_error_msg("stepping time by %+f; poll_exp=MINPOLL", offset); 1435 VERB4 bb_error_msg("stepping time by %+f; poll_exp=MINPOLL", offset);
1391 step_time(offset); 1436 step_time(offset);
1392 if (option_mask32 & OPT_q) { 1437 if (option_mask32 & OPT_q) {
1393 /* We were only asked to set time once. Done. */ 1438 /* We were only asked to set time once. Done. */
@@ -1412,7 +1457,7 @@ update_local_clock(peer_t *p)
1412 } else { /* abs_offset <= STEP_THRESHOLD */ 1457 } else { /* abs_offset <= STEP_THRESHOLD */
1413 1458
1414 if (G.poll_exp < MINPOLL && G.initial_poll_complete) { 1459 if (G.poll_exp < MINPOLL && G.initial_poll_complete) {
1415 VERB3 bb_error_msg("small offset:%+f, disabling burst mode", offset); 1460 VERB4 bb_error_msg("small offset:%+f, disabling burst mode", offset);
1416 G.polladj_count = 0; 1461 G.polladj_count = 0;
1417 G.poll_exp = MINPOLL; 1462 G.poll_exp = MINPOLL;
1418 } 1463 }
@@ -1441,7 +1486,7 @@ update_local_clock(peer_t *p)
1441#else 1486#else
1442 set_new_values(STATE_SYNC, offset, recv_time); 1487 set_new_values(STATE_SYNC, offset, recv_time);
1443#endif 1488#endif
1444 VERB3 bb_error_msg("transitioning to FREQ, datapoint ignored"); 1489 VERB4 bb_error_msg("transitioning to FREQ, datapoint ignored");
1445 return 0; /* "leave poll interval as is" */ 1490 return 0; /* "leave poll interval as is" */
1446 1491
1447#if 0 /* this is dead code for now */ 1492#if 0 /* this is dead code for now */
@@ -1510,7 +1555,7 @@ update_local_clock(peer_t *p)
1510 dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(G.cluster_jitter)); 1555 dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(G.cluster_jitter));
1511 dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time) + abs_offset, MINDISP); 1556 dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time) + abs_offset, MINDISP);
1512 G.rootdisp = p->lastpkt_rootdisp + dtemp; 1557 G.rootdisp = p->lastpkt_rootdisp + dtemp;
1513 VERB3 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted); 1558 VERB4 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted);
1514 1559
1515 /* We are in STATE_SYNC now, but did not do adjtimex yet. 1560 /* We are in STATE_SYNC now, but did not do adjtimex yet.
1516 * (Any other state does not reach this, they all return earlier) 1561 * (Any other state does not reach this, they all return earlier)
@@ -1530,13 +1575,13 @@ update_local_clock(peer_t *p)
1530 dtemp = SQUARE(dtemp); 1575 dtemp = SQUARE(dtemp);
1531 G.discipline_wander = SQRT(etemp + (dtemp - etemp) / AVG); 1576 G.discipline_wander = SQRT(etemp + (dtemp - etemp) / AVG);
1532 1577
1533 VERB3 bb_error_msg("discipline freq_drift=%.9f(int:%ld corr:%e) wander=%f", 1578 VERB4 bb_error_msg("discipline freq_drift=%.9f(int:%ld corr:%e) wander=%f",
1534 G.discipline_freq_drift, 1579 G.discipline_freq_drift,
1535 (long)(G.discipline_freq_drift * 65536e6), 1580 (long)(G.discipline_freq_drift * 65536e6),
1536 freq_drift, 1581 freq_drift,
1537 G.discipline_wander); 1582 G.discipline_wander);
1538#endif 1583#endif
1539 VERB3 { 1584 VERB4 {
1540 memset(&tmx, 0, sizeof(tmx)); 1585 memset(&tmx, 0, sizeof(tmx));
1541 if (adjtimex(&tmx) < 0) 1586 if (adjtimex(&tmx) < 0)
1542 bb_perror_msg_and_die("adjtimex"); 1587 bb_perror_msg_and_die("adjtimex");
@@ -1584,7 +1629,7 @@ update_local_clock(peer_t *p)
1584 /* NB: here kernel returns constant == G.poll_exp, not == G.poll_exp - 4. 1629 /* NB: here kernel returns constant == G.poll_exp, not == G.poll_exp - 4.
1585 * Not sure why. Perhaps it is normal. 1630 * Not sure why. Perhaps it is normal.
1586 */ 1631 */
1587 VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%+ld status:0x%x", 1632 VERB4 bb_error_msg("adjtimex:%d freq:%ld offset:%+ld status:0x%x",
1588 rc, tmx.freq, tmx.offset, tmx.status); 1633 rc, tmx.freq, tmx.offset, tmx.status);
1589 G.kernel_freq_drift = tmx.freq / 65536; 1634 G.kernel_freq_drift = tmx.freq / 65536;
1590 VERB2 bb_error_msg("update from:%s offset:%+f jitter:%f clock drift:%+.3fppm tc:%d", 1635 VERB2 bb_error_msg("update from:%s offset:%+f jitter:%f clock drift:%+.3fppm tc:%d",
@@ -1606,7 +1651,7 @@ retry_interval(void)
1606 interval = RETRY_INTERVAL; 1651 interval = RETRY_INTERVAL;
1607 r = random(); 1652 r = random();
1608 interval += r % (unsigned)(RETRY_INTERVAL / 4); 1653 interval += r % (unsigned)(RETRY_INTERVAL / 4);
1609 VERB3 bb_error_msg("chose retry interval:%u", interval); 1654 VERB4 bb_error_msg("chose retry interval:%u", interval);
1610 return interval; 1655 return interval;
1611} 1656}
1612static unsigned 1657static unsigned
@@ -1619,7 +1664,7 @@ poll_interval(int exponent)
1619 interval = 1 << exponent; 1664 interval = 1 << exponent;
1620 r = random(); 1665 r = random();
1621 interval += ((r & (interval-1)) >> 4) + ((r >> 8) & 1); /* + 1/16 of interval, max */ 1666 interval += ((r & (interval-1)) >> 4) + ((r >> 8) & 1); /* + 1/16 of interval, max */
1622 VERB3 bb_error_msg("chose poll interval:%u (poll_exp:%d exp:%d)", interval, G.poll_exp, exponent); 1667 VERB4 bb_error_msg("chose poll interval:%u (poll_exp:%d exp:%d)", interval, G.poll_exp, exponent);
1623 return interval; 1668 return interval;
1624} 1669}
1625static NOINLINE void 1670static NOINLINE void
@@ -1629,11 +1674,13 @@ recv_and_process_peer_pkt(peer_t *p)
1629 ssize_t size; 1674 ssize_t size;
1630 msg_t msg; 1675 msg_t msg;
1631 double T1, T2, T3, T4; 1676 double T1, T2, T3, T4;
1632 double dv; 1677 double dv, offset;
1633 unsigned interval; 1678 unsigned interval;
1634 datapoint_t *datapoint; 1679 datapoint_t *datapoint;
1635 peer_t *q; 1680 peer_t *q;
1636 1681
1682 offset = 0;
1683
1637 /* We can recvfrom here and check from.IP, but some multihomed 1684 /* We can recvfrom here and check from.IP, but some multihomed
1638 * ntp servers reply from their *other IP*. 1685 * ntp servers reply from their *other IP*.
1639 * TODO: maybe we should check at least what we can: from.port == 123? 1686 * TODO: maybe we should check at least what we can: from.port == 123?
@@ -1713,7 +1760,7 @@ recv_and_process_peer_pkt(peer_t *p)
1713 T4 = G.cur_time; 1760 T4 = G.cur_time;
1714 1761
1715 p->lastpkt_recv_time = T4; 1762 p->lastpkt_recv_time = T4;
1716 VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); 1763 VERB6 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time);
1717 1764
1718 /* The delay calculation is a special case. In cases where the 1765 /* The delay calculation is a special case. In cases where the
1719 * server and client clocks are running at different rates and 1766 * server and client clocks are running at different rates and
@@ -1737,13 +1784,13 @@ recv_and_process_peer_pkt(peer_t *p)
1737 p->datapoint_idx = p->reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0; 1784 p->datapoint_idx = p->reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0;
1738 datapoint = &p->filter_datapoint[p->datapoint_idx]; 1785 datapoint = &p->filter_datapoint[p->datapoint_idx];
1739 datapoint->d_recv_time = T4; 1786 datapoint->d_recv_time = T4;
1740 datapoint->d_offset = ((T2 - T1) + (T3 - T4)) / 2; 1787 datapoint->d_offset = offset = ((T2 - T1) + (T3 - T4)) / 2;
1741 datapoint->d_dispersion = LOG2D(msg.m_precision_exp) + G_precision_sec; 1788 datapoint->d_dispersion = LOG2D(msg.m_precision_exp) + G_precision_sec;
1742 if (!p->reachable_bits) { 1789 if (!p->reachable_bits) {
1743 /* 1st datapoint ever - replicate offset in every element */ 1790 /* 1st datapoint ever - replicate offset in every element */
1744 int i; 1791 int i;
1745 for (i = 0; i < NUM_DATAPOINTS; i++) { 1792 for (i = 0; i < NUM_DATAPOINTS; i++) {
1746 p->filter_datapoint[i].d_offset = datapoint->d_offset; 1793 p->filter_datapoint[i].d_offset = offset;
1747 } 1794 }
1748 } 1795 }
1749 1796
@@ -1751,7 +1798,7 @@ recv_and_process_peer_pkt(peer_t *p)
1751 if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { 1798 if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) {
1752 bb_error_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", 1799 bb_error_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x",
1753 p->p_dotted, 1800 p->p_dotted,
1754 datapoint->d_offset, 1801 offset,
1755 p->lastpkt_delay, 1802 p->lastpkt_delay,
1756 p->lastpkt_status, 1803 p->lastpkt_status,
1757 p->lastpkt_stratum, 1804 p->lastpkt_stratum,
@@ -1776,7 +1823,7 @@ recv_and_process_peer_pkt(peer_t *p)
1776 * drop poll interval one step down. 1823 * drop poll interval one step down.
1777 */ 1824 */
1778 if (fabs(q->filter_offset) >= POLLDOWN_OFFSET) { 1825 if (fabs(q->filter_offset) >= POLLDOWN_OFFSET) {
1779 VERB3 bb_error_msg("offset:%+f > POLLDOWN_OFFSET", q->filter_offset); 1826 VERB4 bb_error_msg("offset:%+f > POLLDOWN_OFFSET", q->filter_offset);
1780 goto poll_down; 1827 goto poll_down;
1781 } 1828 }
1782 } 1829 }
@@ -1798,11 +1845,11 @@ recv_and_process_peer_pkt(peer_t *p)
1798 G.polladj_count = 0; 1845 G.polladj_count = 0;
1799 if (G.poll_exp < MAXPOLL) { 1846 if (G.poll_exp < MAXPOLL) {
1800 G.poll_exp++; 1847 G.poll_exp++;
1801 VERB3 bb_error_msg("polladj: discipline_jitter:%f ++poll_exp=%d", 1848 VERB4 bb_error_msg("polladj: discipline_jitter:%f ++poll_exp=%d",
1802 G.discipline_jitter, G.poll_exp); 1849 G.discipline_jitter, G.poll_exp);
1803 } 1850 }
1804 } else { 1851 } else {
1805 VERB3 bb_error_msg("polladj: incr:%d", G.polladj_count); 1852 VERB4 bb_error_msg("polladj: incr:%d", G.polladj_count);
1806 } 1853 }
1807 } else { 1854 } else {
1808 G.polladj_count -= G.poll_exp * 2; 1855 G.polladj_count -= G.poll_exp * 2;
@@ -1824,11 +1871,11 @@ recv_and_process_peer_pkt(peer_t *p)
1824 if (pp->p_fd < 0) 1871 if (pp->p_fd < 0)
1825 pp->next_action_time -= (1 << G.poll_exp); 1872 pp->next_action_time -= (1 << G.poll_exp);
1826 } 1873 }
1827 VERB3 bb_error_msg("polladj: discipline_jitter:%f --poll_exp=%d", 1874 VERB4 bb_error_msg("polladj: discipline_jitter:%f --poll_exp=%d",
1828 G.discipline_jitter, G.poll_exp); 1875 G.discipline_jitter, G.poll_exp);
1829 } 1876 }
1830 } else { 1877 } else {
1831 VERB3 bb_error_msg("polladj: decr:%d", G.polladj_count); 1878 VERB4 bb_error_msg("polladj: decr:%d", G.polladj_count);
1832 } 1879 }
1833 } 1880 }
1834 } 1881 }
@@ -1836,6 +1883,20 @@ recv_and_process_peer_pkt(peer_t *p)
1836 /* Decide when to send new query for this peer */ 1883 /* Decide when to send new query for this peer */
1837 pick_normal_interval: 1884 pick_normal_interval:
1838 interval = poll_interval(0); 1885 interval = poll_interval(0);
1886 if (fabs(offset) >= STEP_THRESHOLD * 8 && interval > BIGOFF_INTERVAL) {
1887 /* If we are synced, offsets are less than STEP_THRESHOLD,
1888 * or at the very least not much larger than it.
1889 * Now we see a largish one.
1890 * Either this peer is feeling bad, or packet got corrupted,
1891 * or _our_ clock is wrong now and _all_ peers will show similar
1892 * largish offsets too.
1893 * I observed this with laptop suspend stopping clock.
1894 * In any case, it makes sense to make next request soonish:
1895 * cases 1 and 2: get a better datapoint,
1896 * case 3: allows to resync faster.
1897 */
1898 interval = BIGOFF_INTERVAL;
1899 }
1839 1900
1840 set_next_and_ret: 1901 set_next_and_ret:
1841 set_next(p, interval); 1902 set_next(p, interval);
diff --git a/networking/ping.c b/networking/ping.c
index f27e2143d..5d71fe8cc 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -168,9 +168,22 @@ create_icmp_socket(void)
168#endif 168#endif
169 sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */ 169 sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */
170 if (sock < 0) { 170 if (sock < 0) {
171 if (errno == EPERM) 171 if (errno != EPERM)
172 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 172 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
173 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket); 173#if defined(__linux__) || defined(__APPLE__)
174 /* We don't have root privileges. Try SOCK_DGRAM instead.
175 * Linux needs net.ipv4.ping_group_range for this to work.
176 * MacOSX allows ICMP_ECHO, ICMP_TSTAMP or ICMP_MASKREQ
177 */
178#if ENABLE_PING6
179 if (lsa->u.sa.sa_family == AF_INET6)
180 sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
181 else
182#endif
183 sock = socket(AF_INET, SOCK_DGRAM, 1); /* 1 == ICMP */
184 if (sock < 0)
185#endif
186 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
174 } 187 }
175 188
176 xmove_fd(sock, pingsock); 189 xmove_fd(sock, pingsock);
@@ -516,7 +529,7 @@ static void sendping6(int junk UNUSED_PARAM)
516 pkt->icmp6_id = myid; 529 pkt->icmp6_id = myid;
517 530
518 /*if (datalen >= 4)*/ 531 /*if (datalen >= 4)*/
519 *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); 532 *(bb__aliased_uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us();
520 533
521 //TODO? pkt->icmp_cksum = inet_cksum(...); 534 //TODO? pkt->icmp_cksum = inet_cksum(...);
522 535
diff --git a/networking/pscan.c b/networking/pscan.c
index 28005ad57..72ed8cdb5 100644
--- a/networking/pscan.c
+++ b/networking/pscan.c
@@ -157,7 +157,7 @@ int pscan_main(int argc UNUSED_PARAM, char **argv)
157 } 157 }
158 if (ENABLE_FEATURE_CLEAN_UP) free(lsap); 158 if (ENABLE_FEATURE_CLEAN_UP) free(lsap);
159 159
160 printf("%d closed, %d open, %d timed out (or blocked) ports\n", 160 printf("%u closed, %u open, %u timed out (or blocked) ports\n",
161 closed_ports, 161 closed_ports,
162 open_ports, 162 open_ports,
163 nports - (closed_ports + open_ports)); 163 nports - (closed_ports + open_ports));
diff --git a/networking/tc.c b/networking/tc.c
index b9a4d16cc..533f7c042 100644
--- a/networking/tc.c
+++ b/networking/tc.c
@@ -418,9 +418,6 @@ static int print_class(const struct sockaddr_nl *who UNUSED_PARAM,
418static int print_filter(const struct sockaddr_nl *who UNUSED_PARAM, 418static int print_filter(const struct sockaddr_nl *who UNUSED_PARAM,
419 struct nlmsghdr *hdr, void *arg UNUSED_PARAM) 419 struct nlmsghdr *hdr, void *arg UNUSED_PARAM)
420{ 420{
421 struct tcmsg *msg = NLMSG_DATA(hdr);
422 int len = hdr->nlmsg_len;
423 struct rtattr * tb[TCA_MAX+1];
424 return 0; 421 return 0;
425} 422}
426 423
diff --git a/networking/traceroute.c b/networking/traceroute.c
index 0c18d6c0c..97a7a19e0 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -791,7 +791,9 @@ static int
791common_traceroute_main(int op, char **argv) 791common_traceroute_main(int op, char **argv)
792{ 792{
793 int minpacket; 793 int minpacket;
794#ifdef IP_TOS
794 int tos = 0; 795 int tos = 0;
796#endif
795 int max_ttl = 30; 797 int max_ttl = 30;
796 int nprobes = 3; 798 int nprobes = 3;
797 int first_ttl = 1; 799 int first_ttl = 1;
@@ -838,8 +840,10 @@ common_traceroute_main(int op, char **argv)
838 if (op & OPT_IP_CHKSUM) 840 if (op & OPT_IP_CHKSUM)
839 bb_error_msg("warning: ip checksums disabled"); 841 bb_error_msg("warning: ip checksums disabled");
840#endif 842#endif
843#ifdef IP_TOS
841 if (op & OPT_TOS) 844 if (op & OPT_TOS)
842 tos = xatou_range(tos_str, 0, 255); 845 tos = xatou_range(tos_str, 0, 255);
846#endif
843 if (op & OPT_MAX_TTL) 847 if (op & OPT_MAX_TTL)
844 max_ttl = xatou_range(max_ttl_str, 1, 255); 848 max_ttl = xatou_range(max_ttl_str, 1, 255);
845 if (op & OPT_PORT) 849 if (op & OPT_PORT)
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 11b7b1f06..fe322db4f 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -62,6 +62,7 @@ const struct dhcp_optflag dhcp_optflags[] = {
62 { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */ 62 { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */
63 { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */ 63 { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */
64#endif 64#endif
65 { OPTION_STRING , 0xd1 }, /* DHCP_PXE_CONF_FILE */
65 { OPTION_6RD , 0xd4 }, /* DHCP_6RD */ 66 { OPTION_6RD , 0xd4 }, /* DHCP_6RD */
66 { OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ 67 { OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
67 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ 68 { OPTION_STRING , 0xfc }, /* DHCP_WPAD */
@@ -128,6 +129,7 @@ const char dhcp_option_strings[] ALIGN1 =
128 "vlanid" "\0" /* DHCP_VLAN_ID */ 129 "vlanid" "\0" /* DHCP_VLAN_ID */
129 "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */ 130 "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */
130#endif 131#endif
132 "pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */
131 "ip6rd" "\0" /* DHCP_6RD */ 133 "ip6rd" "\0" /* DHCP_6RD */
132 "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ 134 "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
133 "wpad" "\0" /* DHCP_WPAD */ 135 "wpad" "\0" /* DHCP_WPAD */
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 0e8e45fd2..5e70d609f 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -149,8 +149,9 @@ enum {
149//#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */ 149//#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */
150//#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */ 150//#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */
151//#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */ 151//#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */
152#define DHCP_VLAN_ID 0x84 /* 802.1P VLAN ID */ 152//#define DHCP_VLAN_ID 0x84 /* 802.1P VLAN ID */
153#define DHCP_VLAN_PRIORITY 0x85 /* 802.1Q VLAN priority */ 153//#define DHCP_VLAN_PRIORITY 0x85 /* 802.1Q VLAN priority */
154//#define DHCP_PXE_CONF_FILE 0xd1 /* RFC 5071 Configuration File */
154//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */ 155//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */
155//#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */ 156//#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */
156#define DHCP_END 0xff 157#define DHCP_END 0xff
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 53d8a5e08..8dee916d9 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -667,6 +667,15 @@ static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet)
667 client_config.ifindex); 667 client_config.ifindex);
668} 668}
669 669
670static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t server)
671{
672 if (server)
673 return udhcp_send_kernel_packet(packet,
674 ciaddr, CLIENT_PORT,
675 server, SERVER_PORT);
676 return raw_bcast_from_client_config_ifindex(packet);
677}
678
670/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ 679/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
671/* NOINLINE: limit stack usage in caller */ 680/* NOINLINE: limit stack usage in caller */
672static NOINLINE int send_discover(uint32_t xid, uint32_t requested) 681static NOINLINE int send_discover(uint32_t xid, uint32_t requested)
@@ -773,11 +782,7 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
773 add_client_options(&packet); 782 add_client_options(&packet);
774 783
775 bb_info_msg("Sending renew..."); 784 bb_info_msg("Sending renew...");
776 if (server) 785 return bcast_or_ucast(&packet, ciaddr, server);
777 return udhcp_send_kernel_packet(&packet,
778 ciaddr, CLIENT_PORT,
779 server, SERVER_PORT);
780 return raw_bcast_from_client_config_ifindex(&packet);
781} 786}
782 787
783#if ENABLE_FEATURE_UDHCPC_ARPING 788#if ENABLE_FEATURE_UDHCPC_ARPING
@@ -826,7 +831,11 @@ static int send_release(uint32_t server, uint32_t ciaddr)
826 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 831 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
827 832
828 bb_info_msg("Sending release..."); 833 bb_info_msg("Sending release...");
829 return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); 834 /* Note: normally we unicast here since "server" is not zero.
835 * However, there _are_ people who run "address-less" DHCP servers,
836 * and reportedly ISC dhcp client and Windows allow that.
837 */
838 return bcast_or_ucast(&packet, ciaddr, server);
830} 839}
831 840
832/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ 841/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
@@ -1648,14 +1657,19 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1648 * might work too. 1657 * might work too.
1649 * "Next server" and router are definitely wrong ones to use, though... 1658 * "Next server" and router are definitely wrong ones to use, though...
1650 */ 1659 */
1660/* We used to ignore pcakets without DHCP_SERVER_ID.
1661 * I've got user reports from people who run "address-less" servers.
1662 * They either supply DHCP_SERVER_ID of 0.0.0.0 or don't supply it at all.
1663 * They say ISC DHCP client supports this case.
1664 */
1665 server_addr = 0;
1651 temp = udhcp_get_option(&packet, DHCP_SERVER_ID); 1666 temp = udhcp_get_option(&packet, DHCP_SERVER_ID);
1652 if (!temp) { 1667 if (!temp) {
1653 bb_error_msg("no server ID, ignoring packet"); 1668 bb_error_msg("no server ID, using 0.0.0.0");
1654 continue; 1669 } else {
1655 /* still selecting - this server looks bad */ 1670 /* it IS unaligned sometimes, don't "optimize" */
1671 move_from_unaligned32(server_addr, temp);
1656 } 1672 }
1657 /* it IS unaligned sometimes, don't "optimize" */
1658 move_from_unaligned32(server_addr, temp);
1659 /*xid = packet.xid; - already is */ 1673 /*xid = packet.xid; - already is */
1660 requested_ip = packet.yiaddr; 1674 requested_ip = packet.yiaddr;
1661 1675
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c
index 33c9585cf..148f52551 100644
--- a/networking/udhcp/packet.c
+++ b/networking/udhcp/packet.c
@@ -143,8 +143,15 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
143 * 143 *
144 * In order to work with those buggy servers, 144 * In order to work with those buggy servers,
145 * we truncate packets after end option byte. 145 * we truncate packets after end option byte.
146 *
147 * However, RFC 1542 says "The IP Total Length and UDP Length
148 * must be large enough to contain the minimal BOOTP header of 300 octets".
149 * Thus, we retain enough padding to not go below 300 BOOTP bytes.
150 * Some devices have filters which drop DHCP packets shorter than that.
146 */ 151 */
147 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options); 152 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options);
153 if (padding > DHCP_SIZE - 300)
154 padding = DHCP_SIZE - 300;
148 155
149 packet.ip.protocol = IPPROTO_UDP; 156 packet.ip.protocol = IPPROTO_UDP;
150 packet.ip.saddr = source_nip; 157 packet.ip.saddr = source_nip;
@@ -215,6 +222,8 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
215 222
216 udhcp_dump_packet(dhcp_pkt); 223 udhcp_dump_packet(dhcp_pkt);
217 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options); 224 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options);
225 if (padding > DHCP_SIZE - 300)
226 padding = DHCP_SIZE - 300;
218 result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding); 227 result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding);
219 msg = "write"; 228 msg = "write";
220 ret_close: 229 ret_close:
diff --git a/networking/wget.c b/networking/wget.c
index 5dac2b500..d6c509edc 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -72,6 +72,7 @@ struct globals {
72 const char *user_agent; /* "User-Agent" header field */ 72 const char *user_agent; /* "User-Agent" header field */
73#if ENABLE_FEATURE_WGET_TIMEOUT 73#if ENABLE_FEATURE_WGET_TIMEOUT
74 unsigned timeout_seconds; 74 unsigned timeout_seconds;
75 bool connecting;
75#endif 76#endif
76 int output_fd; 77 int output_fd;
77 int o_flags; 78 int o_flags;
@@ -87,7 +88,9 @@ struct globals {
87#define G (*ptr_to_globals) 88#define G (*ptr_to_globals)
88#define INIT_G() do { \ 89#define INIT_G() do { \
89 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 90 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
90 IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) \ 91} while (0)
92#define FINI_G() do { \
93 FREE_PTR_TO_GLOBALS(); \
91} while (0) 94} while (0)
92 95
93 96
@@ -195,13 +198,27 @@ static char* sanitize_string(char *s)
195 return s; 198 return s;
196} 199}
197 200
201#if ENABLE_FEATURE_WGET_TIMEOUT
202static void alarm_handler(int sig UNUSED_PARAM)
203{
204 /* This is theoretically unsafe (uses stdio and malloc in signal handler) */
205 if (G.connecting)
206 bb_error_msg_and_die("download timed out");
207}
208#endif
209
198static FILE *open_socket(len_and_sockaddr *lsa) 210static FILE *open_socket(len_and_sockaddr *lsa)
199{ 211{
212 int fd;
200 FILE *fp; 213 FILE *fp;
201 214
215 IF_FEATURE_WGET_TIMEOUT(alarm(G.timeout_seconds); G.connecting = 1;)
216 fd = xconnect_stream(lsa);
217 IF_FEATURE_WGET_TIMEOUT(G.connecting = 0;)
218
202 /* glibc 2.4 seems to try seeking on it - ??! */ 219 /* glibc 2.4 seems to try seeking on it - ??! */
203 /* hopefully it understands what ESPIPE means... */ 220 /* hopefully it understands what ESPIPE means... */
204 fp = fdopen(xconnect_stream(lsa), "r+"); 221 fp = fdopen(fd, "r+");
205 if (fp == NULL) 222 if (fp == NULL)
206 bb_perror_msg_and_die(bb_msg_memory_exhausted); 223 bb_perror_msg_and_die(bb_msg_memory_exhausted);
207 224
@@ -209,6 +226,7 @@ static FILE *open_socket(len_and_sockaddr *lsa)
209} 226}
210 227
211/* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */ 228/* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */
229/* FIXME: does not respect FEATURE_WGET_TIMEOUT and -T N: */
212static char fgets_and_trim(FILE *fp) 230static char fgets_and_trim(FILE *fp)
213{ 231{
214 char c; 232 char c;
@@ -256,15 +274,22 @@ static void parse_url(const char *src_url, struct host_info *h)
256 free(h->allocated); 274 free(h->allocated);
257 h->allocated = url = xstrdup(src_url); 275 h->allocated = url = xstrdup(src_url);
258 276
259 if (strncmp(url, "http://", 7) == 0) { 277 if (strncmp(url, "ftp://", 6) == 0) {
260 h->port = bb_lookup_port("http", "tcp", 80);
261 h->host = url + 7;
262 h->is_ftp = 0;
263 } else if (strncmp(url, "ftp://", 6) == 0) {
264 h->port = bb_lookup_port("ftp", "tcp", 21); 278 h->port = bb_lookup_port("ftp", "tcp", 21);
265 h->host = url + 6; 279 h->host = url + 6;
266 h->is_ftp = 1; 280 h->is_ftp = 1;
267 } else 281 } else
282 if (strncmp(url, "http://", 7) == 0) {
283 h->host = url + 7;
284 http:
285 h->port = bb_lookup_port("http", "tcp", 80);
286 h->is_ftp = 0;
287 } else
288 if (!strstr(url, "//")) {
289 // GNU wget is user-friendly and falls back to http://
290 h->host = url;
291 goto http;
292 } else
268 bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url)); 293 bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url));
269 294
270 // FYI: 295 // FYI:
@@ -944,7 +969,10 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
944 969
945 INIT_G(); 970 INIT_G();
946 971
947 IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) 972#if ENABLE_FEATURE_WGET_TIMEOUT
973 G.timeout_seconds = 900;
974 signal(SIGALRM, alarm_handler);
975#endif
948 G.proxy_flag = "on"; /* use proxies if env vars are set */ 976 G.proxy_flag = "on"; /* use proxies if env vars are set */
949 G.user_agent = "Wget"; /* "User-Agent" header field */ 977 G.user_agent = "Wget"; /* "User-Agent" header field */
950 978
@@ -995,5 +1023,10 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
995 if (G.output_fd >= 0) 1023 if (G.output_fd >= 0)
996 xclose(G.output_fd); 1024 xclose(G.output_fd);
997 1025
1026#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_WGET_LONG_OPTIONS
1027 free(G.extra_headers);
1028#endif
1029 FINI_G();
1030
998 return EXIT_SUCCESS; 1031 return EXIT_SUCCESS;
999} 1032}
diff --git a/procps/kill.c b/procps/kill.c
index cd189bcd6..c5c7a8d72 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -60,7 +60,7 @@
60 * This is needed to avoid collision with kill -9 ... syntax 60 * This is needed to avoid collision with kill -9 ... syntax
61 */ 61 */
62 62
63int kill_main(int argc, char **argv) 63int kill_main(int argc UNUSED_PARAM, char **argv)
64{ 64{
65 char *arg; 65 char *arg;
66 pid_t pid; 66 pid_t pid;
@@ -79,10 +79,9 @@ int kill_main(int argc, char **argv)
79#endif 79#endif
80 80
81 /* Parse any options */ 81 /* Parse any options */
82 argc--;
83 arg = *++argv; 82 arg = *++argv;
84 83
85 if (argc < 1 || arg[0] != '-') { 84 if (!arg || arg[0] != '-') {
86 goto do_it_now; 85 goto do_it_now;
87 } 86 }
88 87
@@ -91,13 +90,14 @@ int kill_main(int argc, char **argv)
91 * echo "Died of SIG`kill -l $?`" 90 * echo "Died of SIG`kill -l $?`"
92 * We try to mimic what kill from coreutils-6.8 does */ 91 * We try to mimic what kill from coreutils-6.8 does */
93 if (arg[1] == 'l' && arg[2] == '\0') { 92 if (arg[1] == 'l' && arg[2] == '\0') {
94 if (argc == 1) { 93 arg = *++argv;
94 if (!arg) {
95 /* Print the whole signal list */ 95 /* Print the whole signal list */
96 print_signames(); 96 print_signames();
97 return 0; 97 return 0;
98 } 98 }
99 /* -l <sig list> */ 99 /* -l <sig list> */
100 while ((arg = *++argv)) { 100 do {
101 if (isdigit(arg[0])) { 101 if (isdigit(arg[0])) {
102 signo = bb_strtou(arg, NULL, 10); 102 signo = bb_strtou(arg, NULL, 10);
103 if (errno) { 103 if (errno) {
@@ -118,8 +118,8 @@ int kill_main(int argc, char **argv)
118 } 118 }
119 printf("%d\n", signo); 119 printf("%d\n", signo);
120 } 120 }
121 } 121 arg = *++argv;
122 /* If they specified -l, we are all done */ 122 } while (arg);
123 return EXIT_SUCCESS; 123 return EXIT_SUCCESS;
124 } 124 }
125 125
@@ -127,8 +127,7 @@ int kill_main(int argc, char **argv)
127 if (killall && arg[1] == 'q' && arg[2] == '\0') { 127 if (killall && arg[1] == 'q' && arg[2] == '\0') {
128 quiet = 1; 128 quiet = 1;
129 arg = *++argv; 129 arg = *++argv;
130 argc--; 130 if (!arg)
131 if (argc < 1)
132 bb_show_usage(); 131 bb_show_usage();
133 if (arg[0] != '-') 132 if (arg[0] != '-')
134 goto do_it_now; 133 goto do_it_now;
@@ -140,8 +139,7 @@ int kill_main(int argc, char **argv)
140 if (killall5 && arg[0] == 'o') 139 if (killall5 && arg[0] == 'o')
141 goto do_it_now; 140 goto do_it_now;
142 141
143 if (argc > 1 && arg[0] == 's' && arg[1] == '\0') { /* -s SIG? */ 142 if (argv[1] && arg[0] == 's' && arg[1] == '\0') { /* -s SIG? */
144 argc--;
145 arg = *++argv; 143 arg = *++argv;
146 } /* else it must be -SIG */ 144 } /* else it must be -SIG */
147 signo = get_signum(arg); 145 signo = get_signum(arg);
@@ -150,7 +148,6 @@ int kill_main(int argc, char **argv)
150 return EXIT_FAILURE; 148 return EXIT_FAILURE;
151 } 149 }
152 arg = *++argv; 150 arg = *++argv;
153 argc--;
154 151
155 do_it_now: 152 do_it_now:
156 pid = getpid(); 153 pid = getpid();
@@ -158,7 +155,8 @@ int kill_main(int argc, char **argv)
158 if (killall5) { 155 if (killall5) {
159 pid_t sid; 156 pid_t sid;
160 procps_status_t* p = NULL; 157 procps_status_t* p = NULL;
161 int ret = 0; 158 /* compat: exitcode 2 is "no one was signaled" */
159 int ret = 2;
162 160
163 /* Find out our session id */ 161 /* Find out our session id */
164 sid = getsid(pid); 162 sid = getsid(pid);
@@ -167,9 +165,10 @@ int kill_main(int argc, char **argv)
167 kill(-1, SIGSTOP); 165 kill(-1, SIGSTOP);
168 /* Signal all processes except those in our session */ 166 /* Signal all processes except those in our session */
169 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID)) != NULL) { 167 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID)) != NULL) {
170 int i; 168 char **args;
171 169
172 if (p->sid == (unsigned)sid 170 if (p->sid == (unsigned)sid
171 || p->sid == 0 /* compat: kernel thread, don't signal it */
173 || p->pid == (unsigned)pid 172 || p->pid == (unsigned)pid
174 || p->pid == 1 173 || p->pid == 1
175 ) { 174 ) {
@@ -178,18 +177,19 @@ int kill_main(int argc, char **argv)
178 177
179 /* All remaining args must be -o PID options. 178 /* All remaining args must be -o PID options.
180 * Check p->pid against them. */ 179 * Check p->pid against them. */
181 for (i = 0; i < argc; i++) { 180 args = argv;
181 while (*args) {
182 pid_t omit; 182 pid_t omit;
183 183
184 arg = argv[i]; 184 arg = *args++;
185 if (arg[0] != '-' || arg[1] != 'o') { 185 if (arg[0] != '-' || arg[1] != 'o') {
186 bb_error_msg("bad option '%s'", arg); 186 bb_error_msg("bad option '%s'", arg);
187 ret = 1; 187 ret = 1;
188 goto resume; 188 goto resume;
189 } 189 }
190 arg += 2; 190 arg += 2;
191 if (!arg[0] && argv[++i]) 191 if (!arg[0] && *args)
192 arg = argv[i]; 192 arg = *args++;
193 omit = bb_strtoi(arg, NULL, 10); 193 omit = bb_strtoi(arg, NULL, 10);
194 if (errno) { 194 if (errno) {
195 bb_error_msg("invalid number '%s'", arg); 195 bb_error_msg("invalid number '%s'", arg);
@@ -200,6 +200,7 @@ int kill_main(int argc, char **argv)
200 goto dont_kill; 200 goto dont_kill;
201 } 201 }
202 kill(p->pid, signo); 202 kill(p->pid, signo);
203 ret = 0;
203 dont_kill: ; 204 dont_kill: ;
204 } 205 }
205 resume: 206 resume:
@@ -210,14 +211,14 @@ int kill_main(int argc, char **argv)
210 } 211 }
211 212
212 /* Pid or name is required for kill/killall */ 213 /* Pid or name is required for kill/killall */
213 if (argc < 1) { 214 if (!arg) {
214 bb_error_msg("you need to specify whom to kill"); 215 bb_error_msg("you need to specify whom to kill");
215 return EXIT_FAILURE; 216 return EXIT_FAILURE;
216 } 217 }
217 218
218 if (killall) { 219 if (killall) {
219 /* Looks like they want to do a killall. Do that */ 220 /* Looks like they want to do a killall. Do that */
220 while (arg) { 221 do {
221 pid_t* pidList; 222 pid_t* pidList;
222 223
223 pidList = find_pid_by_name(arg); 224 pidList = find_pid_by_name(arg);
@@ -240,7 +241,7 @@ int kill_main(int argc, char **argv)
240 } 241 }
241 free(pidList); 242 free(pidList);
242 arg = *++argv; 243 arg = *++argv;
243 } 244 } while (arg);
244 return errors; 245 return errors;
245 } 246 }
246 247
diff --git a/procps/nmeter.c b/procps/nmeter.c
index 6a3b32743..5d5b83b8d 100644
--- a/procps/nmeter.c
+++ b/procps/nmeter.c
@@ -333,8 +333,7 @@ static void scale(ullong ul)
333 char buf[5]; 333 char buf[5];
334 334
335 /* see http://en.wikipedia.org/wiki/Tera */ 335 /* see http://en.wikipedia.org/wiki/Tera */
336 smart_ulltoa4(ul, buf, " kmgtpezy"); 336 smart_ulltoa4(ul, buf, " kmgtpezy")[0] = '\0';
337 buf[4] = '\0';
338 put(buf); 337 put(buf);
339} 338}
340 339
diff --git a/procps/pgrep.c b/procps/pgrep.c
index 8daf5b28a..1c7c7c48b 100644
--- a/procps/pgrep.c
+++ b/procps/pgrep.c
@@ -65,9 +65,9 @@ static void act(unsigned pid, char *cmd, int signo)
65{ 65{
66 if (pgrep) { 66 if (pgrep) {
67 if (option_mask32 & (1 << OPTBIT_L)) /* OPT_LIST */ 67 if (option_mask32 & (1 << OPTBIT_L)) /* OPT_LIST */
68 printf("%d %s\n", pid, cmd); 68 printf("%u %s\n", pid, cmd);
69 else 69 else
70 printf("%d\n", pid); 70 printf("%u\n", pid);
71 } else 71 } else
72 kill(pid, signo); 72 kill(pid, signo);
73} 73}
diff --git a/procps/powertop.c b/procps/powertop.c
index 71988a295..e3c29d1c3 100644
--- a/procps/powertop.c
+++ b/procps/powertop.c
@@ -627,7 +627,6 @@ static void show_timerstats(void)
627 int i, n = 0; 627 int i, n = 0;
628 char strbuf6[6]; 628 char strbuf6[6];
629 629
630 strbuf6[5] = '\0';
631 puts("\nTop causes for wakeups:"); 630 puts("\nTop causes for wakeups:");
632 for (i = 0; i < G.lines_cnt; i++) { 631 for (i = 0; i < G.lines_cnt; i++) {
633 if ((G.lines[i].count > 0 /*|| G.lines[i].disk_count > 0*/) 632 if ((G.lines[i].count > 0 /*|| G.lines[i].disk_count > 0*/)
@@ -639,7 +638,7 @@ static void show_timerstats(void)
639 /*char c = ' '; 638 /*char c = ' ';
640 if (G.lines[i].disk_count) 639 if (G.lines[i].disk_count)
641 c = 'D';*/ 640 c = 'D';*/
642 smart_ulltoa5(G.lines[i].count, strbuf6, " KMGTPEZY"); 641 smart_ulltoa5(G.lines[i].count, strbuf6, " KMGTPEZY")[0] = '\0';
643 printf(/*" %5.1f%% (%s)%c %s\n"*/ 642 printf(/*" %5.1f%% (%s)%c %s\n"*/
644 " %5.1f%% (%s) %s\n", 643 " %5.1f%% (%s) %s\n",
645 G.lines[i].count * 100.0 / G.lines_cumulative_count, 644 G.lines[i].count * 100.0 / G.lines_cumulative_count,
diff --git a/procps/ps.c b/procps/ps.c
index 0dfda2039..32563776d 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -299,8 +299,7 @@ static void put_lu(char *buf, int size, unsigned long u)
299 char buf4[5]; 299 char buf4[5];
300 300
301 /* see http://en.wikipedia.org/wiki/Tera */ 301 /* see http://en.wikipedia.org/wiki/Tera */
302 smart_ulltoa4(u, buf4, " mgtpezy"); 302 smart_ulltoa4(u, buf4, " mgtpezy")[0] = '\0';
303 buf4[4] = '\0';
304 sprintf(buf, "%.*s", size, buf4); 303 sprintf(buf, "%.*s", size, buf4);
305} 304}
306 305
@@ -750,8 +749,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
750#endif 749#endif
751 { 750 {
752 char buf6[6]; 751 char buf6[6];
753 smart_ulltoa5(p->vsz, buf6, " mgtpezy"); 752 smart_ulltoa5(p->vsz, buf6, " mgtpezy")[0] = '\0';
754 buf6[5] = '\0';
755#if ENABLE_FEATURE_PS_LONG 753#if ENABLE_FEATURE_PS_LONG
756 if (opts & OPT_l) { 754 if (opts & OPT_l) {
757 char bufr[6], stime_str[6]; 755 char bufr[6], stime_str[6];
@@ -762,8 +760,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
762 time_t start = now - elapsed; 760 time_t start = now - elapsed;
763 struct tm *tm = localtime(&start); 761 struct tm *tm = localtime(&start);
764 762
765 smart_ulltoa5(p->rss, bufr, " mgtpezy"); 763 smart_ulltoa5(p->rss, bufr, " mgtpezy")[0] = '\0';
766 bufr[5] = '\0';
767 764
768 if (p->tty_major == 136) 765 if (p->tty_major == 136)
769 /* It should be pts/N, not ptsN, but N > 9 766 /* It should be pts/N, not ptsN, but N > 9
diff --git a/procps/top.c b/procps/top.c
index abee69806..51f1c1aed 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -677,7 +677,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width)
677 if (s->vsz >= 100000) 677 if (s->vsz >= 100000)
678 sprintf(vsz_str_buf, "%6ldm", s->vsz/1024); 678 sprintf(vsz_str_buf, "%6ldm", s->vsz/1024);
679 else 679 else
680 sprintf(vsz_str_buf, "%7ld", s->vsz); 680 sprintf(vsz_str_buf, "%7lu", s->vsz);
681 /* PID PPID USER STAT VSZ %VSZ [%CPU] COMMAND */ 681 /* PID PPID USER STAT VSZ %VSZ [%CPU] COMMAND */
682 col = snprintf(line_buf, scr_width, 682 col = snprintf(line_buf, scr_width,
683 "\n" "%5u%6u %-8.8s %s%s" FMT 683 "\n" "%5u%6u %-8.8s %s%s" FMT
@@ -847,8 +847,7 @@ static void display_topmem_header(int scr_width, int *lines_rem_p)
847static void ulltoa6_and_space(unsigned long long ul, char buf[6]) 847static void ulltoa6_and_space(unsigned long long ul, char buf[6])
848{ 848{
849 /* see http://en.wikipedia.org/wiki/Tera */ 849 /* see http://en.wikipedia.org/wiki/Tera */
850 smart_ulltoa5(ul, buf, " mgtpezy"); 850 smart_ulltoa5(ul, buf, " mgtpezy")[0] = ' ';
851 buf[5] = ' ';
852} 851}
853 852
854static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width) 853static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width)
diff --git a/runit/chpst.c b/runit/chpst.c
index ed72c8b8c..71af29f66 100644
--- a/runit/chpst.c
+++ b/runit/chpst.c
@@ -236,7 +236,6 @@ int chpst_main(int argc UNUSED_PARAM, char **argv)
236{ 236{
237 struct bb_uidgid_t ugid; 237 struct bb_uidgid_t ugid;
238 char *set_user = set_user; /* for compiler */ 238 char *set_user = set_user; /* for compiler */
239 char *env_user = env_user;
240 char *env_dir = env_dir; 239 char *env_dir = env_dir;
241 char *root; 240 char *root;
242 char *nicestr; 241 char *nicestr;
@@ -264,7 +263,7 @@ int chpst_main(int argc UNUSED_PARAM, char **argv)
264 IF_CHPST("/:n:vP012"), 263 IF_CHPST("/:n:vP012"),
265 &limita, &limitc, &limitd, &limitf, &limitl, 264 &limita, &limitc, &limitd, &limitf, &limitl,
266 &limitm, &limito, &limitp, &limitr, &limits, &limitt, 265 &limitm, &limito, &limitp, &limitr, &limits, &limitt,
267 &set_user, &env_user, &env_dir 266 &set_user, &set_user, &env_dir
268 IF_CHPST(, &root, &nicestr)); 267 IF_CHPST(, &root, &nicestr));
269 argv += optind; 268 argv += optind;
270 if (opt & OPT_m) { // -m means -asld 269 if (opt & OPT_m) { // -m means -asld
@@ -292,7 +291,7 @@ int chpst_main(int argc UNUSED_PARAM, char **argv)
292 291
293 // envuidgid? 292 // envuidgid?
294 if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') { 293 if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') {
295 env_user = *argv++; 294 set_user = *argv++;
296 opt |= OPT_U; 295 opt |= OPT_U;
297 } 296 }
298 297
diff --git a/runit/runsv.c b/runit/runsv.c
index 3e1a3c8e5..d941e897d 100644
--- a/runit/runsv.c
+++ b/runit/runsv.c
@@ -33,7 +33,6 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33//usage:#define runsv_full_usage "\n\n" 33//usage:#define runsv_full_usage "\n\n"
34//usage: "Start and monitor a service and optionally an appendant log service" 34//usage: "Start and monitor a service and optionally an appendant log service"
35 35
36#include <sys/poll.h>
37#include <sys/file.h> 36#include <sys/file.h>
38#include "libbb.h" 37#include "libbb.h"
39#include "runit_lib.h" 38#include "runit_lib.h"
diff --git a/runit/runsvdir.c b/runit/runsvdir.c
index 32526cf4c..af7e75ba7 100644
--- a/runit/runsvdir.c
+++ b/runit/runsvdir.c
@@ -35,7 +35,6 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35//usage: "\n -P Put each runsv in a new session" 35//usage: "\n -P Put each runsv in a new session"
36//usage: "\n -s SCRIPT Run SCRIPT <signo> after signal is processed" 36//usage: "\n -s SCRIPT Run SCRIPT <signo> after signal is processed"
37 37
38#include <sys/poll.h>
39#include <sys/file.h> 38#include <sys/file.h>
40#include "libbb.h" 39#include "libbb.h"
41#include "runit_lib.h" 40#include "runit_lib.h"
diff --git a/runit/sv.c b/runit/sv.c
index 5b01c875c..825e9d45b 100644
--- a/runit/sv.c
+++ b/runit/sv.c
@@ -169,7 +169,6 @@ Exit Codes
169//usage: "pause, cont, hup, alarm, interrupt, quit, 1, 2, term, kill: send\n" 169//usage: "pause, cont, hup, alarm, interrupt, quit, 1, 2, term, kill: send\n"
170//usage: "STOP, CONT, HUP, ALRM, INT, QUIT, USR1, USR2, TERM, KILL signal to service" 170//usage: "STOP, CONT, HUP, ALRM, INT, QUIT, USR1, USR2, TERM, KILL signal to service"
171 171
172#include <sys/poll.h>
173#include <sys/file.h> 172#include <sys/file.h>
174#include "libbb.h" 173#include "libbb.h"
175#include "runit_lib.h" 174#include "runit_lib.h"
diff --git a/runit/svlogd.c b/runit/svlogd.c
index 8b8a6d858..c080b9acc 100644
--- a/runit/svlogd.c
+++ b/runit/svlogd.c
@@ -142,7 +142,6 @@ log message, you can use a pattern like this instead
142//usage: "\n""+,-PATTERN - (de)select line for logging" 142//usage: "\n""+,-PATTERN - (de)select line for logging"
143//usage: "\n""E,ePATTERN - (de)select line for stderr" 143//usage: "\n""E,ePATTERN - (de)select line for stderr"
144 144
145#include <sys/poll.h>
146#include <sys/file.h> 145#include <sys/file.h>
147#include "libbb.h" 146#include "libbb.h"
148#include "runit_lib.h" 147#include "runit_lib.h"
diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter
index 6db2a5e58..cb861b8e9 100755
--- a/scripts/bloat-o-meter
+++ b/scripts/bloat-o-meter
@@ -7,11 +7,14 @@
7# This software may be used and distributed according to the terms 7# This software may be used and distributed according to the terms
8# of the GNU General Public License, incorporated herein by reference. 8# of the GNU General Public License, incorporated herein by reference.
9 9
10import sys, os#, re 10import sys, os
11 11
12def usage(): 12def usage():
13 sys.stderr.write("usage: %s [-t] file1 file2\n" % sys.argv[0]) 13 sys.stderr.write("usage: %s [-t] file1 file2 [-- <readelf options>]\n"
14 sys.exit(-1) 14 % sys.argv[0])
15 sys.stderr.write("\t-t\tShow time spent on parsing/processing\n")
16 sys.stderr.write("\t--\tPass additional parameters to readelf\n")
17 sys.exit(1)
15 18
16f1, f2 = (None, None) 19f1, f2 = (None, None)
17flag_timing, dashes = (False, False) 20flag_timing, dashes = (False, False)
@@ -31,6 +34,8 @@ for f in sys.argv[1:]:
31 f1 = f 34 f1 = f
32 elif f2 is None: 35 elif f2 is None:
33 f2 = f 36 f2 = f
37 else:
38 usage()
34if flag_timing: 39if flag_timing:
35 import time 40 import time
36if f1 is None or f2 is None: 41if f1 is None or f2 is None:
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 1651390a6..38bae809a 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -150,7 +150,7 @@ HOSTCFLAGS_zconf.tab.o := -I$(src)
150HOSTLOADLIBES_qconf = $(KC_QT_LIBS) -ldl 150HOSTLOADLIBES_qconf = $(KC_QT_LIBS) -ldl
151HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK 151HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
152 152
153HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` 153HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -ldl
154HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ 154HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
155 -D LKC_DIRECT_LINK 155 -D LKC_DIRECT_LINK
156 156
diff --git a/scripts/mkconfigs b/scripts/mkconfigs
index db94fcc44..6a26fe1dd 100755
--- a/scripts/mkconfigs
+++ b/scripts/mkconfigs
@@ -65,11 +65,11 @@ static const char bbconfig_config_bz2[] ALIGN1 = {"
65 65
66grep -e '^# CONFIG_' -e '^CONFIG_' "$config" \ 66grep -e '^# CONFIG_' -e '^CONFIG_' "$config" \
67| bzip2 -1 | dd bs=2 skip=1 2>/dev/null \ 67| bzip2 -1 | dd bs=2 skip=1 2>/dev/null \
68| od -v -t x1 \ 68| od -v -b \
69| sed -e 's/^[^ ]*//' \ 69| sed -e 's/^[^ ]*//' \
70 -e 's/ //g' \ 70 -e 's/ //g' \
71 -e '/^$/d' \ 71 -e '/^$/d' \
72 -e 's/\(..\)/0x\1,/g' 72 -e 's/\(...\)/0\1,/g'
73 73
74echo "};" 74echo "};"
75echo "#endif" 75echo "#endif"
diff --git a/scripts/randomtest b/scripts/randomtest
index a102593d3..d2b26bc76 100755
--- a/scripts/randomtest
+++ b/scripts/randomtest
@@ -65,6 +65,7 @@ if test x"$LIBC" = x"uclibc"; then
65 | grep -v CONFIG_BUILD_LIBBUSYBOX \ 65 | grep -v CONFIG_BUILD_LIBBUSYBOX \
66 | grep -v CONFIG_PIE \ 66 | grep -v CONFIG_PIE \
67 \ 67 \
68 | grep -v CONFIG_FEATURE_TOUCH_NODEREF \
68 | grep -v CONFIG_FEATURE_2_4_MODULES \ 69 | grep -v CONFIG_FEATURE_2_4_MODULES \
69 >.config.new 70 >.config.new
70 mv .config.new .config 71 mv .config.new .config
@@ -72,6 +73,7 @@ if test x"$LIBC" = x"uclibc"; then
72 echo '# CONFIG_BUILD_LIBBUSYBOX is not set' >>.config 73 echo '# CONFIG_BUILD_LIBBUSYBOX is not set' >>.config
73 echo '# CONFIG_PIE is not set' >>.config 74 echo '# CONFIG_PIE is not set' >>.config
74 echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config 75 echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config
76 echo '# CONFIG_FEATURE_TOUCH_NODEREF is not set' >>.config
75fi 77fi
76 78
77# If STATIC, remove some things. 79# If STATIC, remove some things.
diff --git a/scripts/trylink b/scripts/trylink
index a8b0b2e03..e47169917 100755
--- a/scripts/trylink
+++ b/scripts/trylink
@@ -117,7 +117,7 @@ LDLIBS=`echo "$LDLIBS" | xargs -n1 | sort | uniq | xargs`
117# First link with all libs. If it fails, bail out 117# First link with all libs. If it fails, bail out
118echo "Trying libraries: $LDLIBS" 118echo "Trying libraries: $LDLIBS"
119# "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" 119# "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3"
120l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` 120l_list=`echo " $LDLIBS " | sed -e 's: \([^- ][^ ]*\): -l\1:g'`
121test "x$l_list" != "x" && l_list="$START_GROUP $l_list $END_GROUP" 121test "x$l_list" != "x" && l_list="$START_GROUP $l_list $END_GROUP"
122try $CC $CFLAGS $LDFLAGS \ 122try $CC $CFLAGS $LDFLAGS \
123 -o $EXE \ 123 -o $EXE \
@@ -141,7 +141,7 @@ while test "$LDLIBS"; do
141 for one in $LDLIBS; do 141 for one in $LDLIBS; do
142 without_one=`echo " $LDLIBS " | sed "s/ $one / /g" | xargs` 142 without_one=`echo " $LDLIBS " | sed "s/ $one / /g" | xargs`
143 # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" 143 # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3"
144 l_list=`echo "$without_one" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` 144 l_list=`echo " $without_one " | sed -e 's: \([^- ][^ ]*\): -l\1:g'`
145 test x"$l_list" != x"" && l_list="$START_GROUP $l_list $END_GROUP" 145 test x"$l_list" != x"" && l_list="$START_GROUP $l_list $END_GROUP"
146 $debug && echo "Trying -l options: '$l_list'" 146 $debug && echo "Trying -l options: '$l_list'"
147 try $CC $CFLAGS $LDFLAGS \ 147 try $CC $CFLAGS $LDFLAGS \
@@ -172,7 +172,7 @@ done
172 172
173# Make the binary with final, minimal list of libs 173# Make the binary with final, minimal list of libs
174echo "Final link with: ${LDLIBS:-<none>}" 174echo "Final link with: ${LDLIBS:-<none>}"
175l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` 175l_list=`echo " $LDLIBS " | sed -e 's: \([^- ][^ ]*\): -l\1:g'`
176test "x$l_list" != "x" && l_list="$START_GROUP $l_list $END_GROUP" 176test "x$l_list" != "x" && l_list="$START_GROUP $l_list $END_GROUP"
177# --verbose gives us gobs of info to stdout (e.g. linker script used) 177# --verbose gives us gobs of info to stdout (e.g. linker script used)
178if ! test -f busybox_ldscript; then 178if ! test -f busybox_ldscript; then
diff --git a/shell/ash.c b/shell/ash.c
index 6e6fc6a71..97c9589cc 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2348,7 +2348,7 @@ unsetvar(const char *s)
2348 free(vp); 2348 free(vp);
2349 INT_ON; 2349 INT_ON;
2350 } else { 2350 } else {
2351 setvar(s, 0, 0); 2351 setvar2(s, 0);
2352 vp->flags &= ~VEXPORT; 2352 vp->flags &= ~VEXPORT;
2353 } 2353 }
2354 ok: 2354 ok:
@@ -6698,7 +6698,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6698 6698
6699 switch (subtype) { 6699 switch (subtype) {
6700 case VSASSIGN: 6700 case VSASSIGN:
6701 setvar(varname, startp, 0); 6701 setvar2(varname, startp);
6702 amount = startp - expdest; 6702 amount = startp - expdest;
6703 STADJUST(amount, expdest); 6703 STADJUST(amount, expdest);
6704 return startp; 6704 return startp;
@@ -8960,7 +8960,7 @@ evalfor(union node *n, int flags)
8960 loopnest++; 8960 loopnest++;
8961 flags &= EV_TESTED; 8961 flags &= EV_TESTED;
8962 for (sp = arglist.list; sp; sp = sp->next) { 8962 for (sp = arglist.list; sp; sp = sp->next) {
8963 setvar(n->nfor.var, sp->text, 0); 8963 setvar2(n->nfor.var, sp->text);
8964 evaltree(n->nfor.body, flags); 8964 evaltree(n->nfor.body, flags);
8965 if (evalskip) { 8965 if (evalskip) {
8966 if (evalskip == SKIPCONT && --skipcount <= 0) { 8966 if (evalskip == SKIPCONT && --skipcount <= 0) {
@@ -9955,7 +9955,7 @@ evalcommand(union node *cmd, int flags)
9955 * '_' in 'vi' command mode during line editing... 9955 * '_' in 'vi' command mode during line editing...
9956 * However I implemented that within libedit itself. 9956 * However I implemented that within libedit itself.
9957 */ 9957 */
9958 setvar("_", lastarg, 0); 9958 setvar2("_", lastarg);
9959 } 9959 }
9960 popstackmark(&smark); 9960 popstackmark(&smark);
9961} 9961}
@@ -12777,7 +12777,6 @@ dotcmd(int argc, char **argv)
12777 * bash returns exitcode 1 instead. 12777 * bash returns exitcode 1 instead.
12778 */ 12778 */
12779 fullname = find_dot_file(argv[1]); 12779 fullname = find_dot_file(argv[1]);
12780
12781 argv += 2; 12780 argv += 2;
12782 argc -= 2; 12781 argc -= 2;
12783 if (argc) { /* argc > 0, argv[0] != NULL */ 12782 if (argc) { /* argc > 0, argv[0] != NULL */
@@ -13615,8 +13614,11 @@ init(void)
13615 } 13614 }
13616 13615
13617 if (!ENABLE_PLATFORM_MINGW32) 13616 if (!ENABLE_PLATFORM_MINGW32)
13618 setvar("PPID", utoa(getppid()), 0); 13617 setvar2("PPID", utoa(getppid()));
13619 13618#if ENABLE_ASH_BASH_COMPAT
13619 p = lookupvar("SHLVL");
13620 setvar2("SHLVL", utoa(p ? atoi(p) + 1 : 1));
13621#endif
13620 p = lookupvar("PWD"); 13622 p = lookupvar("PWD");
13621 if (p) { 13623 if (p) {
13622 if (*p != '/' || stat(p, &st1) || stat(".", &st2) 13624 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
@@ -13909,7 +13911,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13909 hp = lookupvar("HOME"); 13911 hp = lookupvar("HOME");
13910 if (hp) { 13912 if (hp) {
13911 hp = concat_path_file(hp, ".ash_history"); 13913 hp = concat_path_file(hp, ".ash_history");
13912 setvar("HISTFILE", hp, 0); 13914 setvar2("HISTFILE", hp);
13913 free((char*)hp); 13915 free((char*)hp);
13914 hp = lookupvar("HISTFILE"); 13916 hp = lookupvar("HISTFILE");
13915 } 13917 }
diff --git a/shell/hush.c b/shell/hush.c
index 912ecf15f..927193450 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1310,7 +1310,7 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1310 * backgrounds (i.e. stops) or kills all members of currently running 1310 * backgrounds (i.e. stops) or kills all members of currently running
1311 * pipe. 1311 * pipe.
1312 * 1312 *
1313 * Wait builtin in interruptible by signals for which user trap is set 1313 * Wait builtin is interruptible by signals for which user trap is set
1314 * or by SIGINT in interactive shell. 1314 * or by SIGINT in interactive shell.
1315 * 1315 *
1316 * Trap handlers will execute even within trap handlers. (right?) 1316 * Trap handlers will execute even within trap handlers. (right?)
@@ -1398,7 +1398,7 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1398 * for them - a bit like emulating kernel pending signal mask in userspace. 1398 * for them - a bit like emulating kernel pending signal mask in userspace.
1399 * We are interested in: signals which need to have special handling 1399 * We are interested in: signals which need to have special handling
1400 * as described above, and all signals which have traps set. 1400 * as described above, and all signals which have traps set.
1401 * Signals are rocorded in pending_set. 1401 * Signals are recorded in pending_set.
1402 * After each pipe execution, we extract any pending signals 1402 * After each pipe execution, we extract any pending signals
1403 * and act on them. 1403 * and act on them.
1404 * 1404 *
diff --git a/sysklogd/logread.c b/sysklogd/logread.c
index 2b6415f47..bea73d932 100644
--- a/sysklogd/logread.c
+++ b/sysklogd/logread.c
@@ -49,6 +49,7 @@ struct globals {
49 memcpy(SMrup, init_sem, sizeof(init_sem)); \ 49 memcpy(SMrup, init_sem, sizeof(init_sem)); \
50} while (0) 50} while (0)
51 51
52#if 0
52static void error_exit(const char *str) NORETURN; 53static void error_exit(const char *str) NORETURN;
53static void error_exit(const char *str) 54static void error_exit(const char *str)
54{ 55{
@@ -56,6 +57,10 @@ static void error_exit(const char *str)
56 shmdt(shbuf); 57 shmdt(shbuf);
57 bb_perror_msg_and_die(str); 58 bb_perror_msg_and_die(str);
58} 59}
60#else
61/* On Linux, shmdt is not mandatory on exit */
62# define error_exit(str) bb_perror_msg_and_die(str)
63#endif
59 64
60/* 65/*
61 * sem_up - up()'s a semaphore. 66 * sem_up - up()'s a semaphore.
@@ -68,7 +73,7 @@ static void sem_up(int semid)
68 73
69static void interrupted(int sig) 74static void interrupted(int sig)
70{ 75{
71 shmdt(shbuf); 76 /* shmdt(shbuf); - on Linux, shmdt is not mandatory on exit */
72 kill_myself_with_sig(sig); 77 kill_myself_with_sig(sig);
73} 78}
74 79
@@ -84,12 +89,12 @@ int logread_main(int argc UNUSED_PARAM, char **argv)
84 89
85 log_shmid = shmget(KEY_ID, 0, 0); 90 log_shmid = shmget(KEY_ID, 0, 0);
86 if (log_shmid == -1) 91 if (log_shmid == -1)
87 bb_perror_msg_and_die("can't find syslogd buffer"); 92 bb_perror_msg_and_die("can't %s syslogd buffer", "find");
88 93
89 /* Attach shared memory to our char* */ 94 /* Attach shared memory to our char* */
90 shbuf = shmat(log_shmid, NULL, SHM_RDONLY); 95 shbuf = shmat(log_shmid, NULL, SHM_RDONLY);
91 if (shbuf == NULL) 96 if (shbuf == NULL)
92 bb_perror_msg_and_die("can't access syslogd buffer"); 97 bb_perror_msg_and_die("can't %s syslogd buffer", "access");
93 98
94 log_semid = semget(KEY_ID, 0, 0); 99 log_semid = semget(KEY_ID, 0, 0);
95 if (log_semid == -1) 100 if (log_semid == -1)
@@ -121,7 +126,7 @@ int logread_main(int argc UNUSED_PARAM, char **argv)
121 shbuf_data = shbuf->data; /* pointer! */ 126 shbuf_data = shbuf->data; /* pointer! */
122 127
123 if (DEBUG) 128 if (DEBUG)
124 printf("cur:%d tail:%i size:%i\n", 129 printf("cur:%u tail:%u size:%u\n",
125 cur, shbuf_tail, shbuf_size); 130 cur, shbuf_tail, shbuf_size);
126 131
127 if (!follow) { 132 if (!follow) {
@@ -182,9 +187,10 @@ int logread_main(int argc UNUSED_PARAM, char **argv)
182 } 187 }
183 free(copy); 188 free(copy);
184#endif 189#endif
190 fflush_all();
185 } while (follow); 191 } while (follow);
186 192
187 shmdt(shbuf); 193 /* shmdt(shbuf); - on Linux, shmdt is not mandatory on exit */
188 194
189 fflush_stdout_and_exit(EXIT_SUCCESS); 195 fflush_stdout_and_exit(EXIT_SUCCESS);
190} 196}
diff --git a/testsuite/awk.tests b/testsuite/awk.tests
index 6af6072b8..132afc6a9 100755
--- a/testsuite/awk.tests
+++ b/testsuite/awk.tests
@@ -269,10 +269,31 @@ testing "awk FS assignment" "awk '{FS=\":\"; print \$1}'" \
269 "" \ 269 "" \
270 "a:b c:d\ne:f g:h" 270 "a:b c:d\ne:f g:h"
271 271
272optional FEATURE_AWK_LIBM
272testing "awk large integer" \ 273testing "awk large integer" \
273 "awk 'BEGIN{n=(2^31)-1; print n, int(n), n%1, ++n, int(n), n%1}'" \ 274 "awk 'BEGIN{n=(2^31)-1; print n, int(n), n%1, ++n, int(n), n%1}'" \
274 "2147483647 2147483647 0 2147483648 2147483648 0\n" \ 275 "2147483647 2147483647 0 2147483648 2147483648 0\n" \
275 "" "" 276 "" ""
277SKIP=
278
279testing "awk length(array)" \
280 "awk 'BEGIN{ A[1]=2; A[\"qwe\"]=\"asd\"; print length(A)}'" \
281 "2\n" \
282 "" ""
283
284testing "awk -f and ARGC" \
285 "awk -f - input" \
286 "re\n2\n" \
287 "do re mi\n" \
288 '{print $2; print ARGC;}' \
289
290optional FEATURE_AWK_GNU_EXTENSIONS
291testing "awk -e and ARGC" \
292 "awk -e '{print \$2; print ARGC;}' input" \
293 "re\n2\n" \
294 "do re mi\n" \
295 ""
296SKIP=
276 297
277# testing "description" "command" "result" "infile" "stdin" 298# testing "description" "command" "result" "infile" "stdin"
278 299
diff --git a/testsuite/date/date-works b/testsuite/date/date-works
index 901c485ec..35c24686c 100644
--- a/testsuite/date/date-works
+++ b/testsuite/date/date-works
@@ -31,9 +31,11 @@ dt=`busybox date -d '1999-1-2 3:4:5'`
31dt=`echo "$dt" | cut -b1-19` 31dt=`echo "$dt" | cut -b1-19`
32test x"$dt" = x"Sat Jan 2 03:04:05" 32test x"$dt" = x"Sat Jan 2 03:04:05"
33 33
34dt=`busybox date -d 01231133` 34# date (GNU coreutils) 8.17 doesn't accept 01231133 either:
35dt=`echo "$dt" | cut -b5-19` 35# date: invalid date '01231133'
36test x"$dt" = x"Jan 23 11:33:00" 36#dt=`busybox date -d 01231133`
37#dt=`echo "$dt" | cut -b5-19`
38#test x"$dt" = x"Jan 23 11:33:00"
37 39
38dt=`busybox date -d 200001231133` 40dt=`busybox date -d 200001231133`
39dt=`echo "$dt" | cut -b1-19` 41dt=`echo "$dt" | cut -b1-19`
diff --git a/testsuite/date/date-works-1 b/testsuite/date/date-works-1
index cb5cea2c5..4f53939ee 100644
--- a/testsuite/date/date-works-1
+++ b/testsuite/date/date-works-1
@@ -41,9 +41,9 @@ test x"$hdt" = x"$dt"
41# Avoiding using week day in this evaluation, as it's mostly different every year 41# Avoiding using week day in this evaluation, as it's mostly different every year
42# date (GNU coreutils) 6.10 reports: 42# date (GNU coreutils) 6.10 reports:
43# date: invalid date '01231133' 43# date: invalid date '01231133'
44dt=`busybox date -d 01231133 +%c` 44#dt=`busybox date -d 01231133 +%c`
45dt=`echo "$dt" | cut -b5-19` 45#dt=`echo "$dt" | cut -b5-19`
46test x"$dt" = x"Jan 23 11:33:00" 46#test x"$dt" = x"Jan 23 11:33:00"
47 47
48# date (GNU coreutils) 6.10 reports: 48# date (GNU coreutils) 6.10 reports:
49# date: invalid date '012311332000' 49# date: invalid date '012311332000'
diff --git a/testsuite/du/du-k-works b/testsuite/du/du-k-works
index 417b0daa5..213e9ba99 100644
--- a/testsuite/du/du-k-works
+++ b/testsuite/du/du-k-works
@@ -4,8 +4,10 @@ dd if=/dev/zero of=file1 bs=1k count=64 2>/dev/null
4dd if=/dev/zero of=file2 bs=1k count=16 2>/dev/null 4dd if=/dev/zero of=file2 bs=1k count=16 2>/dev/null
5# ext4 on images <512M gives 81kb 5# ext4 on images <512M gives 81kb
6# ext3 on images <512M gives 83kb 6# ext3 on images <512M gives 83kb
7# a bsd system reportedly gives 82kb
7test x"`busybox du -k .`" = x"80 ." \ 8test x"`busybox du -k .`" = x"80 ." \
8 -o x"`busybox du -k .`" = x"81 ." \ 9 -o x"`busybox du -k .`" = x"81 ." \
10 -o x"`busybox du -k .`" = x"82 ." \
9 -o x"`busybox du -k .`" = x"83 ." \ 11 -o x"`busybox du -k .`" = x"83 ." \
10 -o x"`busybox du -k .`" = x"84 ." \ 12 -o x"`busybox du -k .`" = x"84 ." \
11 -o x"`busybox du -k .`" = x"88 ." 13 -o x"`busybox du -k .`" = x"88 ."
diff --git a/testsuite/du/du-l-works b/testsuite/du/du-l-works
index 426ee891b..af87345db 100644
--- a/testsuite/du/du-l-works
+++ b/testsuite/du/du-l-works
@@ -6,6 +6,7 @@ dd if=/dev/zero of=file1 bs=1k count=64 2>/dev/null
6ln file1 file1.1 6ln file1 file1.1
7dd if=/dev/zero of=file2 bs=1k count=16 2>/dev/null 7dd if=/dev/zero of=file2 bs=1k count=16 2>/dev/null
8test x"`busybox du -l .`" = x"144 ." \ 8test x"`busybox du -l .`" = x"144 ." \
9 -o x"`busybox du -l .`" = x"146 ." \
9 -o x"`busybox du -l .`" = x"148 ." \ 10 -o x"`busybox du -l .`" = x"148 ." \
10 -o x"`busybox du -l .`" = x"152 ." \ 11 -o x"`busybox du -l .`" = x"152 ." \
11 -o x"`busybox du -l .`" = x"156 ." 12 -o x"`busybox du -l .`" = x"156 ."
diff --git a/testsuite/hostid/hostid-works b/testsuite/hostid/hostid-works
index bcfd717af..8c20bdfcc 100644
--- a/testsuite/hostid/hostid-works
+++ b/testsuite/hostid/hostid-works
@@ -1,8 +1,6 @@
1h=x$(busybox hostid) 1h=x$(busybox hostid)
2# Is $h a sequence of hex numbers? 2# Is $h a sequence of hex numbers?
3x="${h//[0123456789abcdef]/x}" 3case "$h" in
4x="${x//xxx/x}" 4 x*[!0-9a-f]*) false;;
5x="${x//xxx/x}" 5 *) true;;
6x="${x//xxx/x}" 6esac
7x="${x//xx/x}"
8test x"$x" = x"x"
diff --git a/testsuite/md5sum.tests b/testsuite/md5sum.tests
index 1068b083f..6c75b6d1c 100755
--- a/testsuite/md5sum.tests
+++ b/testsuite/md5sum.tests
@@ -30,13 +30,13 @@ result=`(
30n=0 30n=0
31while test $n -le 999; do 31while test $n -le 999; do
32 echo "$text" | head -c $n | "$sum" 32 echo "$text" | head -c $n | "$sum"
33 : $((n++)) 33 n=$(($n+1))
34done | "$sum" 34done | "$sum"
35)` 35)`
36 36
37if test x"$result" = x"$expected -"; then 37if test x"$result" = x"$expected -"; then
38 echo "PASS: $sum" 38 echo "PASS: $sum"
39 exit 0 39 exit 0
40fi 40fi
41 41
42echo "FAIL: $sum (r:$result exp:$expected)" 42echo "FAIL: $sum (r:$result exp:$expected)"
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index 2af1e4c97..9494ac2de 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -154,11 +154,9 @@ testing "sed selective matches insert newline" \
154testing "sed selective matches noinsert newline" \ 154testing "sed selective matches noinsert newline" \
155 "sed -ne 's/woo/bang/p' input -" "a bang\nb bang" "a woo\nb woo" \ 155 "sed -ne 's/woo/bang/p' input -" "a bang\nb bang" "a woo\nb woo" \
156 "c no\nd no" 156 "c no\nd no"
157test x"$SKIP_KNOWN_BUGS" = x"" && {
158testing "sed clusternewline" \ 157testing "sed clusternewline" \
159 "sed -e '/one/a 111' -e '/two/i 222' -e p input -" \ 158 "sed -e '/one/a 111' -e '/two/i 222' -e p input -" \
160 "one\none\n111\n222\ntwo\ntwo" "one" "two" 159 "one\none\n111\n222\ntwo\ntwo" "one" "two"
161}
162testing "sed subst+write" \ 160testing "sed subst+write" \
163 "sed -e 's/i/z/' -e 'woutputw' input -; $ECHO -n X; cat outputw" \ 161 "sed -e 's/i/z/' -e 'woutputw' input -; $ECHO -n X; cat outputw" \
164 "thzngy\nagaznXthzngy\nagazn" "thingy" "again" 162 "thzngy\nagaznXthzngy\nagazn" "thingy" "again"
diff --git a/testsuite/tar.tests b/testsuite/tar.tests
index 7927020c1..4929f4e49 100755
--- a/testsuite/tar.tests
+++ b/testsuite/tar.tests
@@ -15,6 +15,44 @@ mkdir tar.tempdir && cd tar.tempdir || exit 1
15 15
16# testing "test name" "script" "expected result" "file input" "stdin" 16# testing "test name" "script" "expected result" "file input" "stdin"
17 17
18testing "Empty file is not a tarball" '\
19tar xvf - 2>&1; echo $?
20' "\
21tar: short read
221
23" \
24"" ""
25SKIP=
26
27optional FEATURE_SEAMLESS_GZ
28# In NOMMU case, "invalid magic" message comes from gunzip child process.
29# Otherwise, it comes from tar.
30# Need to fix output up to avoid false positive.
31testing "Empty file is not a tarball.tar.gz" '\
32{ tar xvzf - 2>&1; echo $?; } | grep -Fv "invalid magic"
33' "\
34tar: short read
351
36" \
37"" ""
38SKIP=
39
40testing "Two zeroed blocks is a ('truncated') empty tarball" '\
41dd if=/dev/zero bs=512 count=2 2>/dev/null | tar xvf - 2>&1; echo $?
42' "\
430
44" \
45"" ""
46SKIP=
47
48testing "Twenty zeroed blocks is an empty tarball" '\
49dd if=/dev/zero bs=512 count=20 2>/dev/null | tar xvf - 2>&1; echo $?
50' "\
510
52" \
53"" ""
54SKIP=
55
18optional FEATURE_TAR_CREATE FEATURE_LS_SORTFILES 56optional FEATURE_TAR_CREATE FEATURE_LS_SORTFILES
19testing "tar hardlinks and repeated files" '\ 57testing "tar hardlinks and repeated files" '\
20rm -rf input_* test.tar 2>/dev/null 58rm -rf input_* test.tar 2>/dev/null
diff --git a/testsuite/testing.sh b/testsuite/testing.sh
index e7e64e58b..f5b756947 100644
--- a/testsuite/testing.sh
+++ b/testsuite/testing.sh
@@ -56,10 +56,10 @@ optional()
56{ 56{
57 SKIP= 57 SKIP=
58 while test "$1"; do 58 while test "$1"; do
59 if test x"${OPTIONFLAGS/*:$1:*/y}" != x"y"; then 59 case "${OPTIONFLAGS}" in
60 SKIP=1 60 *:$1:*) ;;
61 return 61 *) SKIP=1; return ;;
62 fi 62 esac
63 shift 63 shift
64 done 64 done
65} 65}
diff --git a/testsuite/which/which-uses-default-path b/testsuite/which/which-uses-default-path
index 63ceb9f8f..349583dcc 100644
--- a/testsuite/which/which-uses-default-path
+++ b/testsuite/which/which-uses-default-path
@@ -1,4 +1,4 @@
1BUSYBOX=$(type -p busybox) 1BUSYBOX=$(command -pv busybox)
2SAVED_PATH=$PATH 2SAVED_PATH=$PATH
3unset PATH 3unset PATH
4$BUSYBOX which ls 4$BUSYBOX which ls
diff --git a/util-linux/fdformat.c b/util-linux/fdformat.c
index b3e918fb0..6f49cec8f 100644
--- a/util-linux/fdformat.c
+++ b/util-linux/fdformat.c
@@ -72,7 +72,7 @@ int fdformat_main(int argc UNUSED_PARAM, char **argv)
72 /* original message was: "Could not determine current format type" */ 72 /* original message was: "Could not determine current format type" */
73 xioctl(fd, FDGETPRM, &param); 73 xioctl(fd, FDGETPRM, &param);
74 74
75 printf("%s-sided, %d tracks, %d sec/track. Total capacity %d kB\n", 75 printf("%s-sided, %u tracks, %u sec/track. Total capacity %d kB\n",
76 (param.head == 2) ? "Double" : "Single", 76 (param.head == 2) ? "Double" : "Single",
77 param.track, param.sect, param.size >> 1); 77 param.track, param.sect, param.size >> 1);
78 78
diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c
index f45f68af0..5786d5f7d 100644
--- a/util-linux/fdisk_gpt.c
+++ b/util-linux/fdisk_gpt.c
@@ -93,9 +93,7 @@ gpt_list_table(int xtra UNUSED_PARAM)
93 int i; 93 int i;
94 char numstr6[6]; 94 char numstr6[6];
95 95
96 numstr6[5] = '\0'; 96 smart_ulltoa5(total_number_of_sectors * sector_size, numstr6, " KMGTPEZY")[0] = '\0';
97
98 smart_ulltoa5(total_number_of_sectors * sector_size, numstr6, " KMGTPEZY");
99 printf("Disk %s: %llu sectors, %s\n", disk_device, 97 printf("Disk %s: %llu sectors, %s\n", disk_device,
100 (unsigned long long)total_number_of_sectors, 98 (unsigned long long)total_number_of_sectors,
101 numstr6); 99 numstr6);
@@ -113,7 +111,7 @@ gpt_list_table(int xtra UNUSED_PARAM)
113 gpt_partition *p = gpt_part(i); 111 gpt_partition *p = gpt_part(i);
114 if (p->lba_start) { 112 if (p->lba_start) {
115 smart_ulltoa5((1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start)) * sector_size, 113 smart_ulltoa5((1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start)) * sector_size,
116 numstr6, " KMGTPEZY"); 114 numstr6, " KMGTPEZY")[0] = '\0';
117 printf("%4u %15llu %15llu %11s %04x ", 115 printf("%4u %15llu %15llu %11s %04x ",
118 i + 1, 116 i + 1,
119 (unsigned long long)SWAP_LE64(p->lba_start), 117 (unsigned long long)SWAP_LE64(p->lba_start),
diff --git a/util-linux/fsck_minix.c b/util-linux/fsck_minix.c
index c1d1b2cc3..33767a1af 100644
--- a/util-linux/fsck_minix.c
+++ b/util-linux/fsck_minix.c
@@ -686,7 +686,7 @@ static void get_inode_common(unsigned nr, uint16_t i_mode)
686 total++; 686 total++;
687 if (!inode_count[nr]) { 687 if (!inode_count[nr]) {
688 if (!inode_in_use(nr)) { 688 if (!inode_in_use(nr)) {
689 printf("Inode %d is marked as 'unused', but it is used " 689 printf("Inode %u is marked as 'unused', but it is used "
690 "for file '%s'\n", nr, current_name); 690 "for file '%s'\n", nr, current_name);
691 if (OPT_repair) { 691 if (OPT_repair) {
692 if (ask("Mark as 'in use'", 1)) 692 if (ask("Mark as 'in use'", 1))
diff --git a/util-linux/fstrim.c b/util-linux/fstrim.c
new file mode 100644
index 000000000..675a02184
--- /dev/null
+++ b/util-linux/fstrim.c
@@ -0,0 +1,119 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * fstrim.c - discard the part (or whole) of mounted filesystem.
4 *
5 * 03 March 2012 - Malek Degachi <malek-degachi@laposte.net>
6 * Adapted for busybox from util-linux-2.12a.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */
10
11//config:config FSTRIM
12//config: bool "fstrim"
13//config: default y
14//config: select PLATFORM_LINUX
15//config: help
16//config: Discard unused blocks on a mounted filesystem.
17
18//applet:IF_FSTRIM(APPLET(fstrim, BB_DIR_SBIN, BB_SUID_DROP))
19
20//kbuild:lib-$(CONFIG_FSTRIM) += fstrim.o
21
22//usage:#define fstrim_trivial_usage
23//usage: "[OPTIONS] MOUNTPOINT"
24//usage:#define fstrim_full_usage "\n\n"
25//usage: IF_LONG_OPTS(
26//usage: " -o,--offset=OFFSET Offset in bytes to discard from"
27//usage: "\n -l,--length=LEN Bytes to discard"
28//usage: "\n -m,--minimum=MIN Minimum extent length"
29//usage: "\n -v,--verbose Print number of discarded bytes"
30//usage: )
31//usage: IF_NOT_LONG_OPTS(
32//usage: " -o OFFSET Offset in bytes to discard from"
33//usage: "\n -l LEN Bytes to discard"
34//usage: "\n -m MIN Minimum extent length"
35//usage: "\n -v, Print number of discarded bytes"
36//usage: )
37
38#include "libbb.h"
39#include <linux/fs.h>
40
41#ifndef FITRIM
42struct fstrim_range {
43 uint64_t start;
44 uint64_t len;
45 uint64_t minlen;
46};
47#define FITRIM _IOWR('X', 121, struct fstrim_range)
48#endif
49
50static const struct suffix_mult fstrim_sfx[] = {
51 { "KiB", 1024 },
52 { "kiB", 1024 },
53 { "K", 1024 },
54 { "k", 1024 },
55 { "MiB", 1048576 },
56 { "miB", 1048576 },
57 { "M", 1048576 },
58 { "m", 1048576 },
59 { "GiB", 1073741824 },
60 { "giB", 1073741824 },
61 { "G", 1073741824 },
62 { "g", 1073741824 },
63 { "KB", 1000 },
64 { "MB", 1000000 },
65 { "GB", 1000000000 },
66 { "", 0 }
67};
68
69int fstrim_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
70int fstrim_main(int argc UNUSED_PARAM, char **argv)
71{
72 struct fstrim_range range;
73 char *arg_o, *arg_l, *arg_m, *mp;
74 unsigned opts;
75 int fd;
76
77 enum {
78 OPT_o = (1 << 0),
79 OPT_l = (1 << 1),
80 OPT_m = (1 << 2),
81 OPT_v = (1 << 3),
82 };
83
84#if ENABLE_LONG_OPTS
85 static const char getopt_longopts[] ALIGN1 =
86 "offset\0" Required_argument "o"
87 "length\0" Required_argument "l"
88 "minimum\0" Required_argument "m"
89 "verbose\0" No_argument "v"
90 ;
91 applet_long_options = getopt_longopts;
92#endif
93
94 opt_complementary = "=1"; /* exactly one non-option arg: the mountpoint */
95 opts = getopt32(argv, "o:l:m:v", &arg_o, &arg_l, &arg_m);
96
97 memset(&range, 0, sizeof(range));
98 range.len = ULLONG_MAX;
99
100 if (opts & OPT_o)
101 range.start = xatoull_sfx(arg_o, fstrim_sfx);
102 if (opts & OPT_l)
103 range.len = xatoull_sfx(arg_l, fstrim_sfx);
104 if (opts & OPT_m)
105 range.minlen = xatoull_sfx(arg_m, fstrim_sfx);
106
107 mp = argv[optind];
108 if (find_block_device(mp)) {
109 fd = xopen_nonblocking(mp);
110 xioctl(fd, FITRIM, &range);
111 if (ENABLE_FEATURE_CLEAN_UP)
112 close(fd);
113
114 if (opts & OPT_v)
115 printf("%s: %llu bytes trimmed\n", mp, (unsigned long long)range.len);
116 return EXIT_SUCCESS;
117 }
118 return EXIT_FAILURE;
119}
diff --git a/util-linux/ipcs.c b/util-linux/ipcs.c
index 2668cafd4..67a25a8ef 100644
--- a/util-linux/ipcs.c
+++ b/util-linux/ipcs.c
@@ -166,10 +166,10 @@ static NOINLINE void do_shm(void)
166 case STATUS: 166 case STATUS:
167 printf("------ Shared Memory %s --------\n", "Status"); 167 printf("------ Shared Memory %s --------\n", "Status");
168 printf("segments allocated %d\n" 168 printf("segments allocated %d\n"
169 "pages allocated %ld\n" 169 "pages allocated %lu\n"
170 "pages resident %ld\n" 170 "pages resident %lu\n"
171 "pages swapped %ld\n" 171 "pages swapped %lu\n"
172 "Swap performance: %ld attempts\t%ld successes\n", 172 "Swap performance: %lu attempts\t%lu successes\n",
173 shm_info.used_ids, 173 shm_info.used_ids,
174 shm_info.shm_tot, 174 shm_info.shm_tot,
175 shm_info.shm_rss, 175 shm_info.shm_rss,
@@ -569,7 +569,7 @@ static void print_sem(int semid)
569 if (val < 0 || ncnt < 0 || zcnt < 0 || pid < 0) { 569 if (val < 0 || ncnt < 0 || zcnt < 0 || pid < 0) {
570 bb_perror_msg_and_die("semctl"); 570 bb_perror_msg_and_die("semctl");
571 } 571 }
572 printf("%-10d %-10d %-10d %-10d %-10d\n", i, val, ncnt, zcnt, pid); 572 printf("%-10u %-10d %-10d %-10d %-10d\n", i, val, ncnt, zcnt, pid);
573 } 573 }
574 bb_putchar('\n'); 574 bb_putchar('\n');
575} 575}
diff --git a/util-linux/mkfs_minix.c b/util-linux/mkfs_minix.c
index 49afd1176..d65a5161c 100644
--- a/util-linux/mkfs_minix.c
+++ b/util-linux/mkfs_minix.c
@@ -505,7 +505,7 @@ static void get_list_blocks(char *filename)
505 505
506 listfile = xfopen_for_read(filename); 506 listfile = xfopen_for_read(filename);
507 while (!feof(listfile)) { 507 while (!feof(listfile)) {
508 fscanf(listfile, "%ld\n", &blockno); 508 fscanf(listfile, "%lu\n", &blockno);
509 mark_zone(blockno); 509 mark_zone(blockno);
510 G.badblocks++; 510 G.badblocks++;
511 } 511 }
diff --git a/util-linux/readprofile.c b/util-linux/readprofile.c
index 974fe89c4..a64540464 100644
--- a/util-linux/readprofile.c
+++ b/util-linux/readprofile.c
@@ -152,7 +152,7 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv)
152 152
153 step = buf[0]; 153 step = buf[0];
154 if (optInfo) { 154 if (optInfo) {
155 printf("Sampling_step: %i\n", step); 155 printf("Sampling_step: %u\n", step);
156 return EXIT_SUCCESS; 156 return EXIT_SUCCESS;
157 } 157 }
158 158
@@ -219,10 +219,10 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv)
219 && (fn_len = next_add-fn_add) != 0 219 && (fn_len = next_add-fn_add) != 0
220 ) { 220 ) {
221 if (optVerbose) 221 if (optVerbose)
222 printf("%016llx %-40s %6i %8.4f\n", fn_add, 222 printf("%016llx %-40s %6u %8.4f\n", fn_add,
223 fn_name, this, this/(double)fn_len); 223 fn_name, this, this/(double)fn_len);
224 else 224 else
225 printf("%6i %-40s %8.4f\n", 225 printf("%6u %-40s %8.4f\n",
226 this, fn_name, this/(double)fn_len); 226 this, fn_name, this/(double)fn_len);
227 if (optSub) { 227 if (optSub) {
228 unsigned long long scan; 228 unsigned long long scan;
@@ -246,14 +246,14 @@ int readprofile_main(int argc UNUSED_PARAM, char **argv)
246 } 246 }
247 247
248 /* clock ticks, out of kernel text - probably modules */ 248 /* clock ticks, out of kernel text - probably modules */
249 printf("%6i %s\n", buf[len/sizeof(*buf)-1], "*unknown*"); 249 printf("%6u %s\n", buf[len/sizeof(*buf)-1], "*unknown*");
250 250
251 /* trailer */ 251 /* trailer */
252 if (optVerbose) 252 if (optVerbose)
253 printf("%016x %-40s %6i %8.4f\n", 253 printf("%016x %-40s %6u %8.4f\n",
254 0, "total", total, total/(double)(fn_add-add0)); 254 0, "total", total, total/(double)(fn_add-add0));
255 else 255 else
256 printf("%6i %-40s %8.4f\n", 256 printf("%6u %-40s %8.4f\n",
257 total, "total", total/(double)(fn_add-add0)); 257 total, "total", total/(double)(fn_add-add0));
258 258
259 fclose(map); 259 fclose(map);
diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c
index afad4ab8f..3f223343e 100644
--- a/util-linux/swaponoff.c
+++ b/util-linux/swaponoff.c
@@ -98,10 +98,10 @@ static int do_em_all(void)
98#if ENABLE_FEATURE_SWAPON_PRI 98#if ENABLE_FEATURE_SWAPON_PRI
99 char *p; 99 char *p;
100 g_flags = 0; /* each swap space might have different flags */ 100 g_flags = 0; /* each swap space might have different flags */
101 p = strstr(m->mnt_opts, "pri="); 101 p = hasmntopt(m, "pri");
102 if (p) { 102 if (p) {
103 /* Max allowed 32767 (==SWAP_FLAG_PRIO_MASK) */ 103 /* Max allowed 32767 (==SWAP_FLAG_PRIO_MASK) */
104 int swap_prio = MIN(bb_strtoull(p + 4 , NULL, 10), SWAP_FLAG_PRIO_MASK); 104 unsigned int swap_prio = MIN(bb_strtou(p + 4 , NULL, 10), SWAP_FLAG_PRIO_MASK);
105 /* We want to allow "NNNN,foo", thus errno == EINVAL is allowed too */ 105 /* We want to allow "NNNN,foo", thus errno == EINVAL is allowed too */
106 if (errno != ERANGE) { 106 if (errno != ERANGE) {
107 g_flags = SWAP_FLAG_PREFER | 107 g_flags = SWAP_FLAG_PREFER |
diff --git a/util-linux/volume_id/unused_msdos.c b/util-linux/volume_id/unused_msdos.c
index d2fc66caa..5ebaa3eef 100644
--- a/util-linux/volume_id/unused_msdos.c
+++ b/util-linux/volume_id/unused_msdos.c
@@ -176,7 +176,7 @@ int FAST_FUNC volume_id_probe_msdos_part_table(struct volume_id *id, uint64_t of
176 if (id->partition_count < 4) 176 if (id->partition_count < 4)
177 id->partition_count = 4; 177 id->partition_count = 4;
178 178
179 p = &id->partitions[id->partition_count]; 179// p = &id->partitions[id->partition_count];
180 180
181// if (is_raid(part[i].sys_ind)) 181// if (is_raid(part[i].sys_ind))
182// volume_id_set_usage_part(p, VOLUME_ID_RAID); 182// volume_id_set_usage_part(p, VOLUME_ID_RAID);