aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2011-01-04 19:56:15 +0700
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2011-01-04 19:56:15 +0700
commit5f6f2162512106adf120d4b528bb125e93e34429 (patch)
tree7d7449f755633c263be7125ad58d21cc3ca5b8a7
parent9db69882bee2d528d706d61d34ef7741122330be (diff)
parenta116552869db5e7793ae10968eb3c962c69b3d8c (diff)
downloadbusybox-w32-5f6f2162512106adf120d4b528bb125e93e34429.tar.gz
busybox-w32-5f6f2162512106adf120d4b528bb125e93e34429.tar.bz2
busybox-w32-5f6f2162512106adf120d4b528bb125e93e34429.zip
Merge remote-tracking branch 'upstream/master'
-rw-r--r--Config.in5
-rw-r--r--Makefile8
-rw-r--r--Makefile.flags2
-rw-r--r--archival/Kbuild.src5
-rw-r--r--archival/ar.c18
-rw-r--r--archival/bbunzip.c2
-rw-r--r--archival/bzip2.c20
-rw-r--r--archival/cpio.c107
-rw-r--r--archival/dpkg.c13
-rw-r--r--archival/dpkg_deb.c12
-rw-r--r--archival/gzip.c2
-rw-r--r--archival/libarchive/Kbuild.src (renamed from archival/libunarchive/Kbuild.src)2
-rw-r--r--archival/libarchive/bz/LICENSE (renamed from archival/bz/LICENSE)0
-rw-r--r--archival/libarchive/bz/README (renamed from archival/bz/README)0
-rw-r--r--archival/libarchive/bz/blocksort.c (renamed from archival/bz/blocksort.c)0
-rw-r--r--archival/libarchive/bz/bzlib.c (renamed from archival/bz/bzlib.c)6
-rw-r--r--archival/libarchive/bz/bzlib.h (renamed from archival/bz/bzlib.h)0
-rw-r--r--archival/libarchive/bz/bzlib_private.h (renamed from archival/bz/bzlib_private.h)0
-rw-r--r--archival/libarchive/bz/compress.c (renamed from archival/bz/compress.c)9
-rw-r--r--archival/libarchive/bz/huffman.c (renamed from archival/bz/huffman.c)0
-rw-r--r--archival/libarchive/data_align.c (renamed from archival/libunarchive/data_align.c)2
-rw-r--r--archival/libarchive/data_extract_all.c (renamed from archival/libunarchive/data_extract_all.c)2
-rw-r--r--archival/libarchive/data_extract_to_command.c (renamed from archival/libunarchive/data_extract_to_command.c)2
-rw-r--r--archival/libarchive/data_extract_to_stdout.c (renamed from archival/libunarchive/data_extract_to_stdout.c)2
-rw-r--r--archival/libarchive/data_skip.c (renamed from archival/libunarchive/data_skip.c)2
-rw-r--r--archival/libarchive/decompress_bunzip2.c (renamed from archival/libunarchive/decompress_bunzip2.c)426
-rw-r--r--archival/libarchive/decompress_uncompress.c (renamed from archival/libunarchive/decompress_uncompress.c)2
-rw-r--r--archival/libarchive/decompress_unlzma.c (renamed from archival/libunarchive/decompress_unlzma.c)2
-rw-r--r--archival/libarchive/decompress_unxz.c (renamed from archival/libunarchive/decompress_unxz.c)2
-rw-r--r--archival/libarchive/decompress_unzip.c (renamed from archival/libunarchive/decompress_unzip.c)2
-rw-r--r--archival/libarchive/filter_accept_all.c (renamed from archival/libunarchive/filter_accept_all.c)2
-rw-r--r--archival/libarchive/filter_accept_list.c (renamed from archival/libunarchive/filter_accept_list.c)2
-rw-r--r--archival/libarchive/filter_accept_list_reassign.c (renamed from archival/libunarchive/filter_accept_list_reassign.c)2
-rw-r--r--archival/libarchive/filter_accept_reject_list.c (renamed from archival/libunarchive/filter_accept_reject_list.c)2
-rw-r--r--archival/libarchive/find_list_entry.c (renamed from archival/libunarchive/find_list_entry.c)2
-rw-r--r--archival/libarchive/get_header_ar.c (renamed from archival/libunarchive/get_header_ar.c)2
-rw-r--r--archival/libarchive/get_header_cpio.c (renamed from archival/libunarchive/get_header_cpio.c)2
-rw-r--r--archival/libarchive/get_header_tar.c (renamed from archival/libunarchive/get_header_tar.c)2
-rw-r--r--archival/libarchive/get_header_tar_bz2.c (renamed from archival/libunarchive/get_header_tar_bz2.c)2
-rw-r--r--archival/libarchive/get_header_tar_gz.c (renamed from archival/libunarchive/get_header_tar_gz.c)2
-rw-r--r--archival/libarchive/get_header_tar_lzma.c (renamed from archival/libunarchive/get_header_tar_lzma.c)2
-rw-r--r--archival/libarchive/header_list.c (renamed from archival/libunarchive/header_list.c)2
-rw-r--r--archival/libarchive/header_skip.c (renamed from archival/libunarchive/header_skip.c)2
-rw-r--r--archival/libarchive/header_verbose_list.c (renamed from archival/libunarchive/header_verbose_list.c)2
-rw-r--r--archival/libarchive/init_handle.c (renamed from archival/libunarchive/init_handle.c)2
-rw-r--r--archival/libarchive/liblzo.h (renamed from archival/liblzo.h)0
-rw-r--r--archival/libarchive/lzo1x_1.c (renamed from archival/lzo1x_1.c)0
-rw-r--r--archival/libarchive/lzo1x_1o.c (renamed from archival/lzo1x_1o.c)0
-rw-r--r--archival/libarchive/lzo1x_9x.c (renamed from archival/lzo1x_9x.c)0
-rw-r--r--archival/libarchive/lzo1x_c.c (renamed from archival/lzo1x_c.c)0
-rw-r--r--archival/libarchive/lzo1x_d.c (renamed from archival/lzo1x_d.c)0
-rw-r--r--archival/libarchive/open_transformer.c (renamed from archival/libunarchive/open_transformer.c)4
-rw-r--r--archival/libarchive/seek_by_jump.c (renamed from archival/libunarchive/seek_by_jump.c)2
-rw-r--r--archival/libarchive/seek_by_read.c (renamed from archival/libunarchive/seek_by_read.c)2
-rw-r--r--archival/libarchive/unpack_ar_archive.c (renamed from archival/libunarchive/unpack_ar_archive.c)2
-rw-r--r--archival/libarchive/unxz/README (renamed from archival/libunarchive/unxz/README)0
-rw-r--r--archival/libarchive/unxz/xz.h (renamed from archival/libunarchive/unxz/xz.h)0
-rw-r--r--archival/libarchive/unxz/xz_config.h (renamed from archival/libunarchive/unxz/xz_config.h)0
-rw-r--r--archival/libarchive/unxz/xz_dec_bcj.c (renamed from archival/libunarchive/unxz/xz_dec_bcj.c)0
-rw-r--r--archival/libarchive/unxz/xz_dec_lzma2.c (renamed from archival/libunarchive/unxz/xz_dec_lzma2.c)0
-rw-r--r--archival/libarchive/unxz/xz_dec_stream.c (renamed from archival/libunarchive/unxz/xz_dec_stream.c)0
-rw-r--r--archival/libarchive/unxz/xz_lzma2.h (renamed from archival/libunarchive/unxz/xz_lzma2.h)0
-rw-r--r--archival/libarchive/unxz/xz_private.h (renamed from archival/libunarchive/unxz/xz_private.h)0
-rw-r--r--archival/libarchive/unxz/xz_stream.h (renamed from archival/libunarchive/unxz/xz_stream.h)0
-rw-r--r--archival/lzop.c2
-rw-r--r--archival/rpm.c2
-rw-r--r--archival/rpm2cpio.c2
-rw-r--r--archival/tar.c22
-rw-r--r--archival/unzip.c2
-rw-r--r--console-tools/kbd_mode.c4
-rw-r--r--console-tools/loadfont.c8
-rw-r--r--console-tools/reset.c12
-rw-r--r--console-tools/resize.c2
-rw-r--r--console-tools/showkey.c81
-rw-r--r--coreutils/Config.src7
-rw-r--r--coreutils/Kbuild.src1
-rw-r--r--coreutils/date.c8
-rw-r--r--coreutils/dd.c2
-rw-r--r--coreutils/ls.c415
-rw-r--r--coreutils/mv.c2
-rw-r--r--coreutils/nice.c6
-rw-r--r--coreutils/od.c4
-rw-r--r--coreutils/sort.c4
-rw-r--r--coreutils/stat.c7
-rw-r--r--coreutils/test.c11
-rw-r--r--coreutils/touch.c36
-rw-r--r--coreutils/tr.c8
-rw-r--r--coreutils/wc.c6
-rw-r--r--docs/keep_data_small.txt2
-rw-r--r--docs/new-applet-HOWTO.txt21
-rw-r--r--e2fsprogs/old_e2fsprogs/e2fsck.h2
-rw-r--r--editors/Config.src6
-rw-r--r--editors/Kbuild.src1
-rw-r--r--editors/awk.c14
-rw-r--r--editors/cmp.c9
-rw-r--r--editors/diff.c2
-rw-r--r--editors/patch.c336
-rw-r--r--editors/sed.c6
-rwxr-xr-xexamples/depmod.pl3
-rw-r--r--examples/var_service/README59
-rw-r--r--include/applets.src.h29
-rw-r--r--include/archive.h (renamed from include/unarchive.h)4
-rw-r--r--include/grp_.h2
-rw-r--r--include/libbb.h1
-rw-r--r--include/liblzo_interface.h (renamed from archival/liblzo_interface.h)0
-rw-r--r--include/platform.h2
-rw-r--r--include/pwd_.h2
-rw-r--r--include/rtc_.h4
-rw-r--r--include/usage.src.h255
-rw-r--r--include/volume_id.h1
-rw-r--r--init/bootchartd.c3
-rw-r--r--init/init.c291
-rw-r--r--libbb/Config.src2
-rw-r--r--libbb/Kbuild.src1
-rw-r--r--libbb/appletlib.c79
-rw-r--r--libbb/find_root_device.c9
-rw-r--r--libbb/getopt32.c2
-rw-r--r--libbb/hash_md5_sha.c8
-rw-r--r--libbb/lineedit.c99
-rw-r--r--libbb/procps.c2
-rw-r--r--libbb/pw_encrypt_sha.c56
-rw-r--r--libbb/read_printf.c2
-rw-r--r--libbb/simplify_path.c10
-rw-r--r--libbb/time.c12
-rw-r--r--libbb/u_signal_names.c68
-rw-r--r--libbb/unicode.c7
-rw-r--r--libbb/update_passwd.c2
-rw-r--r--libbb/xfuncs.c2
-rw-r--r--libpwdgrp/pwd_grp_internal.c4
-rw-r--r--loginutils/deluser.c107
-rw-r--r--loginutils/login.c11
-rw-r--r--loginutils/su.c12
-rw-r--r--mailutils/mail.c11
-rw-r--r--mailutils/mail.h18
-rw-r--r--mailutils/mime.c32
-rw-r--r--mailutils/popmaildir.c5
-rw-r--r--mailutils/sendmail.c64
-rw-r--r--miscutils/bbconfig.c4
-rw-r--r--miscutils/chat.c17
-rw-r--r--miscutils/chrt.c26
-rw-r--r--miscutils/conspy.c21
-rw-r--r--miscutils/less.c14
-rw-r--r--miscutils/ubi_attach_detach.c4
-rw-r--r--miscutils/watchdog.c2
-rw-r--r--modutils/modprobe.c136
-rw-r--r--modutils/rmmod.c4
-rw-r--r--networking/Config.src23
-rw-r--r--networking/Kbuild.src2
-rw-r--r--networking/arping.c4
-rw-r--r--networking/dnsd.c2
-rw-r--r--networking/httpd.c4
-rw-r--r--networking/ifupdown.c123
-rw-r--r--networking/inetd.c8
-rw-r--r--networking/ip.c4
-rw-r--r--networking/ipcalc.c6
-rw-r--r--networking/libiproute/ip_parse_common_args.c15
-rw-r--r--networking/libiproute/ipaddress.c10
-rw-r--r--networking/libiproute/iplink.c8
-rw-r--r--networking/libiproute/iproute.c17
-rw-r--r--networking/libiproute/iprule.c21
-rw-r--r--networking/libiproute/iptunnel.c10
-rw-r--r--networking/libiproute/libnetlink.c14
-rw-r--r--networking/libiproute/libnetlink.h10
-rw-r--r--networking/libiproute/ll_addr.c12
-rw-r--r--networking/libiproute/ll_map.c15
-rw-r--r--networking/libiproute/ll_proto.c12
-rw-r--r--networking/libiproute/ll_types.c12
-rw-r--r--networking/libiproute/rt_names.c12
-rw-r--r--networking/libiproute/rtm_map.c13
-rw-r--r--networking/libiproute/utils.c6
-rw-r--r--networking/libiproute/utils.h6
-rw-r--r--networking/nameif.c4
-rw-r--r--networking/nc_bloaty.c5
-rw-r--r--networking/netstat.c2
-rw-r--r--networking/ntpd.c6
-rw-r--r--networking/ntpd_simple.c2
-rw-r--r--networking/ping.c114
-rw-r--r--networking/slattach.c4
-rw-r--r--networking/tc.c2
-rw-r--r--networking/telnet.c172
-rw-r--r--networking/telnetd.c9
-rw-r--r--networking/udhcp/dhcpc.c4
-rw-r--r--networking/udhcp/dhcpd.c68
-rw-r--r--networking/vconfig.c4
-rw-r--r--networking/wget.c6
-rw-r--r--procps/Config.src13
-rw-r--r--procps/Kbuild.src1
-rw-r--r--procps/iostat.c10
-rw-r--r--procps/mpstat.c14
-rw-r--r--procps/nmeter.c50
-rw-r--r--procps/powertop.c113
-rw-r--r--procps/pstree.c406
-rw-r--r--procps/smemcap.c2
-rw-r--r--procps/sysctl.c2
-rw-r--r--runit/runsvdir.c7
-rw-r--r--scripts/Makefile.IMA4
-rw-r--r--scripts/basic/fixdep.c2
-rwxr-xr-xscripts/bloat-o-meter4
-rwxr-xr-xscripts/cleanup_printf2puts2
-rwxr-xr-xscripts/gen_build_files.sh103
-rwxr-xr-xscripts/individual129
-rwxr-xr-xscripts/mkdiff_obj27
-rwxr-xr-xscripts/randomtest.loop2
-rw-r--r--selinux/runcon.c3
-rw-r--r--selinux/sestatus.c8
-rw-r--r--shell/ash.c11
-rw-r--r--shell/ash_test/recho.c13
-rw-r--r--shell/ash_test/zecho.c5
-rw-r--r--shell/hush.c559
-rw-r--r--shell/hush_test/hush-misc/assignment3.right2
-rwxr-xr-xshell/hush_test/hush-misc/assignment3.tests5
-rw-r--r--shell/hush_test/hush-misc/pipefail.right40
-rwxr-xr-xshell/hush_test/hush-misc/pipefail.tests45
-rw-r--r--shell/hush_test/hush-parsing/comment1.right2
-rwxr-xr-xshell/hush_test/hush-parsing/comment1.tests2
-rw-r--r--shell/hush_test/hush-parsing/eol1.right1
-rwxr-xr-xshell/hush_test/hush-parsing/eol1.tests18
-rwxr-xr-xtestsuite/bunzip2.tests31
-rw-r--r--testsuite/date/date-@-works13
-rw-r--r--testsuite/du/du-h-works2
-rwxr-xr-xtestsuite/md5sum.tests5
-rwxr-xr-xtestsuite/patch.tests41
-rw-r--r--testsuite/testing.sh1
-rw-r--r--util-linux/Config.src7
-rw-r--r--util-linux/acpid.c11
-rw-r--r--util-linux/blkid.c9
-rw-r--r--util-linux/fbset.c6
-rw-r--r--util-linux/fdisk.c1
-rw-r--r--util-linux/hexdump.c12
-rw-r--r--util-linux/ipcrm.c7
-rw-r--r--util-linux/more.c15
-rw-r--r--util-linux/umount.c47
-rw-r--r--util-linux/volume_id/cramfs.c2
-rw-r--r--util-linux/volume_id/ext.c10
-rw-r--r--util-linux/volume_id/fat.c2
-rw-r--r--util-linux/volume_id/get_devname.c59
-rw-r--r--util-linux/volume_id/hfs.c2
-rw-r--r--util-linux/volume_id/iso9660.c2
-rw-r--r--util-linux/volume_id/jfs.c2
-rw-r--r--util-linux/volume_id/linux_raid.c2
-rw-r--r--util-linux/volume_id/linux_swap.c3
-rw-r--r--util-linux/volume_id/luks.c2
-rw-r--r--util-linux/volume_id/ntfs.c2
-rw-r--r--util-linux/volume_id/ocfs2.c2
-rw-r--r--util-linux/volume_id/reiserfs.c2
-rw-r--r--util-linux/volume_id/romfs.c2
-rw-r--r--util-linux/volume_id/sysv.c4
-rw-r--r--util-linux/volume_id/udf.c3
-rw-r--r--util-linux/volume_id/volume_id_internal.h4
-rw-r--r--util-linux/volume_id/xfs.c2
250 files changed, 3469 insertions, 2479 deletions
diff --git a/Config.in b/Config.in
index 273f2de38..50d825bfe 100644
--- a/Config.in
+++ b/Config.in
@@ -151,8 +151,9 @@ config INSTALL_NO_USR
151 default n 151 default n
152 depends on FEATURE_INSTALLER 152 depends on FEATURE_INSTALLER
153 help 153 help
154 Disable use of /usr. busybox --install will install applets 154 Disable use of /usr. busybox --install and "make install"
155 only to /bin and /sbin, never to /usr/bin or /usr/sbin. 155 will install applets only to /bin and /sbin,
156 never to /usr/bin or /usr/sbin.
156 157
157config LOCALE_SUPPORT 158config LOCALE_SUPPORT
158 bool "Enable locale support (system needs locale for this to work)" 159 bool "Enable locale support (system needs locale for this to work)"
diff --git a/Makefile b/Makefile
index aff2a7a55..74c8b34f9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
1VERSION = 1 1VERSION = 1
2PATCHLEVEL = 18 2PATCHLEVEL = 19
3SUBLEVEL = 0 3SUBLEVEL = 0
4EXTRAVERSION = .git 4EXTRAVERSION = .git
5NAME = Unnamed 5NAME = Unnamed
@@ -465,7 +465,7 @@ core-y := \
465 465
466libs-y := \ 466libs-y := \
467 archival/ \ 467 archival/ \
468 archival/libunarchive/ \ 468 archival/libarchive/ \
469 console-tools/ \ 469 console-tools/ \
470 coreutils/ \ 470 coreutils/ \
471 coreutils/libcoreutils/ \ 471 coreutils/libcoreutils/ \
@@ -1010,8 +1010,8 @@ $(mrproper-dirs):
1010mrproper: clean archmrproper $(mrproper-dirs) 1010mrproper: clean archmrproper $(mrproper-dirs)
1011 $(call cmd,rmdirs) 1011 $(call cmd,rmdirs)
1012 $(call cmd,rmfiles) 1012 $(call cmd,rmfiles)
1013 @find -name Config.src | sed 's/.src$$/.in/' | xargs -r rm -f 1013 @find . -name Config.src | sed 's/.src$$/.in/' | xargs -r rm -f
1014 @find -name Kbuild.src | sed 's/.src$$//' | xargs -r rm -f 1014 @find . -name Kbuild.src | sed 's/.src$$//' | xargs -r rm -f
1015 1015
1016# distclean 1016# distclean
1017# 1017#
diff --git a/Makefile.flags b/Makefile.flags
index 7122d9bd6..c7a805877 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -4,7 +4,7 @@
4 4
5BB_VER = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) 5BB_VER = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
6export BB_VER 6export BB_VER
7SKIP_STRIP = n 7SKIP_STRIP ?= n
8 8
9# -std=gnu99 needed for [U]LLONG_MAX on some systems 9# -std=gnu99 needed for [U]LLONG_MAX on some systems
10CPPFLAGS += $(call cc-option,-std=gnu99,) 10CPPFLAGS += $(call cc-option,-std=gnu99,)
diff --git a/archival/Kbuild.src b/archival/Kbuild.src
index a0edb123d..3466452f7 100644
--- a/archival/Kbuild.src
+++ b/archival/Kbuild.src
@@ -4,7 +4,7 @@
4# 4#
5# Licensed under GPLv2, see file LICENSE in this source tree. 5# Licensed under GPLv2, see file LICENSE in this source tree.
6 6
7libs-y += libunarchive/ 7libs-y += libarchive/
8 8
9lib-y:= 9lib-y:=
10 10
@@ -19,8 +19,7 @@ lib-$(CONFIG_RPM) += rpm.o
19lib-$(CONFIG_TAR) += tar.o 19lib-$(CONFIG_TAR) += tar.o
20lib-$(CONFIG_UNZIP) += unzip.o 20lib-$(CONFIG_UNZIP) += unzip.o
21 21
22lib-$(CONFIG_LZOP) += lzop.o lzo1x_1.o lzo1x_1o.o lzo1x_d.o bbunzip.o 22lib-$(CONFIG_LZOP) += lzop.o bbunzip.o
23lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o
24lib-$(CONFIG_GZIP) += gzip.o bbunzip.o 23lib-$(CONFIG_GZIP) += gzip.o bbunzip.o
25lib-$(CONFIG_BZIP2) += bzip2.o bbunzip.o 24lib-$(CONFIG_BZIP2) += bzip2.o bbunzip.o
26 25
diff --git a/archival/ar.c b/archival/ar.c
index 05556c6cb..a2e3306ac 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -18,7 +18,7 @@
18 */ 18 */
19 19
20#include "libbb.h" 20#include "libbb.h"
21#include "unarchive.h" 21#include "archive.h"
22#include "ar.h" 22#include "ar.h"
23 23
24#if ENABLE_FEATURE_AR_CREATE 24#if ENABLE_FEATURE_AR_CREATE
@@ -179,17 +179,17 @@ static void FAST_FUNC header_verbose_list_ar(const file_header_t *file_header)
179 ); 179 );
180} 180}
181 181
182#define AR_OPT_VERBOSE (1 << 0) 182#define AR_OPT_VERBOSE (1 << 0)
183#define AR_OPT_PRESERVE_DATE (1 << 1) 183#define AR_OPT_PRESERVE_DATE (1 << 1)
184/* "ar r" implies create, but warns about it. c suppresses warning. 184/* "ar r" implies create, but warns about it. c suppresses warning.
185 * bbox accepts but ignores it: */ 185 * bbox accepts but ignores it: */
186#define AR_OPT_CREATE (1 << 2) 186#define AR_OPT_CREATE (1 << 2)
187 187
188#define AR_CMD_PRINT (1 << 3) 188#define AR_CMD_PRINT (1 << 3)
189#define FIRST_CMD AR_CMD_PRINT 189#define FIRST_CMD AR_CMD_PRINT
190#define AR_CMD_LIST (1 << 4) 190#define AR_CMD_LIST (1 << 4)
191#define AR_CMD_EXTRACT (1 << 5) 191#define AR_CMD_EXTRACT (1 << 5)
192#define AR_CMD_INSERT (1 << 6) 192#define AR_CMD_INSERT (1 << 6)
193 193
194int ar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 194int ar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
195int ar_main(int argc UNUSED_PARAM, char **argv) 195int ar_main(int argc UNUSED_PARAM, char **argv)
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index a195434e4..0f89443e0 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -5,7 +5,7 @@
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#include "libbb.h" 7#include "libbb.h"
8#include "unarchive.h" 8#include "archive.h"
9 9
10enum { 10enum {
11 OPT_STDOUT = 1 << 0, 11 OPT_STDOUT = 1 << 0,
diff --git a/archival/bzip2.c b/archival/bzip2.c
index fdb8b9306..ab08ffc1a 100644
--- a/archival/bzip2.c
+++ b/archival/bzip2.c
@@ -8,7 +8,7 @@
8 */ 8 */
9 9
10#include "libbb.h" 10#include "libbb.h"
11#include "unarchive.h" 11#include "archive.h"
12 12
13#define CONFIG_BZIP2_FEATURE_SPEED 1 13#define CONFIG_BZIP2_FEATURE_SPEED 1
14 14
@@ -33,14 +33,14 @@
33/* Takes ~300 bytes, detects corruption caused by bad RAM etc */ 33/* Takes ~300 bytes, detects corruption caused by bad RAM etc */
34#define BZ_LIGHT_DEBUG 0 34#define BZ_LIGHT_DEBUG 0
35 35
36#include "bz/bzlib.h" 36#include "libarchive/bz/bzlib.h"
37 37
38#include "bz/bzlib_private.h" 38#include "libarchive/bz/bzlib_private.h"
39 39
40#include "bz/blocksort.c" 40#include "libarchive/bz/blocksort.c"
41#include "bz/bzlib.c" 41#include "libarchive/bz/bzlib.c"
42#include "bz/compress.c" 42#include "libarchive/bz/compress.c"
43#include "bz/huffman.c" 43#include "libarchive/bz/huffman.c"
44 44
45/* No point in being shy and having very small buffer here. 45/* No point in being shy and having very small buffer here.
46 * bzip2 internal buffers are much bigger anyway, hundreds of kbytes. 46 * bzip2 internal buffers are much bigger anyway, hundreds of kbytes.
@@ -128,10 +128,12 @@ IF_DESKTOP(long long) int FAST_FUNC compressStream(unpack_info_t *info UNUSED_PA
128 break; 128 break;
129 } 129 }
130 130
131#if ENABLE_FEATURE_CLEAN_UP 131 /* Can't be conditional on ENABLE_FEATURE_CLEAN_UP -
132 * we are called repeatedly
133 */
132 BZ2_bzCompressEnd(strm); 134 BZ2_bzCompressEnd(strm);
133 free(iobuf); 135 free(iobuf);
134#endif 136
135 return total; 137 return total;
136} 138}
137 139
diff --git a/archival/cpio.c b/archival/cpio.c
index a2d74dc79..c746a71fa 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -12,7 +12,37 @@
12 * 12 *
13 */ 13 */
14#include "libbb.h" 14#include "libbb.h"
15#include "unarchive.h" 15#include "archive.h"
16
17//usage:#define cpio_trivial_usage
18//usage: "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]")
19//usage: " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]")
20//usage: " [EXTR_FILE]..."
21//usage:#define cpio_full_usage "\n\n"
22//usage: "Extract or list files from a cpio archive"
23//usage: IF_FEATURE_CPIO_O(", or"
24//usage: "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)")
25//usage: " using file list on stdin"
26//usage: )
27//usage: "\n"
28//usage: "\nMain operation mode:"
29//usage: "\n -t List"
30//usage: "\n -i Extract EXTR_FILEs (or all)"
31//usage: IF_FEATURE_CPIO_O(
32//usage: "\n -o Create (requires -H newc)"
33//usage: )
34//usage: IF_FEATURE_CPIO_P(
35//usage: "\n -p DIR Copy files to DIR"
36//usage: )
37//usage: "\nOptions:"
38//usage: "\n -d Make leading directories"
39//usage: "\n -m Preserve mtime"
40//usage: "\n -v Verbose"
41//usage: "\n -u Overwrite"
42//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file"
43//usage: IF_FEATURE_CPIO_O(
44//usage: "\n -H newc Archive format"
45//usage: )
16 46
17/* GNU cpio 2.9 --help (abridged): 47/* GNU cpio 2.9 --help (abridged):
18 48
@@ -20,7 +50,7 @@
20 -t, --list List the archive 50 -t, --list List the archive
21 -i, --extract Extract files from an archive 51 -i, --extract Extract files from an archive
22 -o, --create Create the archive 52 -o, --create Create the archive
23 -p, --pass-through Copy-pass mode [was ist das?!] 53 -p, --pass-through Copy-pass mode
24 54
25 Options valid in any mode: 55 Options valid in any mode:
26 --block-size=SIZE I/O block size = SIZE * 512 bytes 56 --block-size=SIZE I/O block size = SIZE * 512 bytes
@@ -78,27 +108,28 @@
78 --sparse Write files with blocks of zeros as sparse files 108 --sparse Write files with blocks of zeros as sparse files
79 -u, --unconditional Replace all files unconditionally 109 -u, --unconditional Replace all files unconditionally
80 */ 110 */
111
81enum { 112enum {
82 CPIO_OPT_EXTRACT = (1 << 0), 113 OPT_EXTRACT = (1 << 0),
83 CPIO_OPT_TEST = (1 << 1), 114 OPT_TEST = (1 << 1),
84 CPIO_OPT_NUL_TERMINATED = (1 << 2), 115 OPT_NUL_TERMINATED = (1 << 2),
85 CPIO_OPT_UNCONDITIONAL = (1 << 3), 116 OPT_UNCONDITIONAL = (1 << 3),
86 CPIO_OPT_VERBOSE = (1 << 4), 117 OPT_VERBOSE = (1 << 4),
87 CPIO_OPT_CREATE_LEADING_DIR = (1 << 5), 118 OPT_CREATE_LEADING_DIR = (1 << 5),
88 CPIO_OPT_PRESERVE_MTIME = (1 << 6), 119 OPT_PRESERVE_MTIME = (1 << 6),
89 CPIO_OPT_DEREF = (1 << 7), 120 OPT_DEREF = (1 << 7),
90 CPIO_OPT_FILE = (1 << 8), 121 OPT_FILE = (1 << 8),
91 OPTBIT_FILE = 8, 122 OPTBIT_FILE = 8,
92 IF_FEATURE_CPIO_O(OPTBIT_CREATE ,) 123 IF_FEATURE_CPIO_O(OPTBIT_CREATE ,)
93 IF_FEATURE_CPIO_O(OPTBIT_FORMAT ,) 124 IF_FEATURE_CPIO_O(OPTBIT_FORMAT ,)
94 IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,) 125 IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,)
95 IF_LONG_OPTS( OPTBIT_QUIET ,) 126 IF_LONG_OPTS( OPTBIT_QUIET ,)
96 IF_LONG_OPTS( OPTBIT_2STDOUT ,) 127 IF_LONG_OPTS( OPTBIT_2STDOUT ,)
97 CPIO_OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0, 128 OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0,
98 CPIO_OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0, 129 OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0,
99 CPIO_OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0, 130 OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0,
100 CPIO_OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0, 131 OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0,
101 CPIO_OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0, 132 OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0,
102}; 133};
103 134
104#define OPTION_STR "it0uvdmLF:" 135#define OPTION_STR "it0uvdmLF:"
@@ -138,7 +169,7 @@ static NOINLINE int cpio_o(void)
138 char *line; 169 char *line;
139 struct stat st; 170 struct stat st;
140 171
141 line = (option_mask32 & CPIO_OPT_NUL_TERMINATED) 172 line = (option_mask32 & OPT_NUL_TERMINATED)
142 ? bb_get_chunk_from_file(stdin, NULL) 173 ? bb_get_chunk_from_file(stdin, NULL)
143 : xmalloc_fgetline(stdin); 174 : xmalloc_fgetline(stdin);
144 175
@@ -153,7 +184,7 @@ static NOINLINE int cpio_o(void)
153 free(line); 184 free(line);
154 continue; 185 continue;
155 } 186 }
156 if ((option_mask32 & CPIO_OPT_DEREF) 187 if ((option_mask32 & OPT_DEREF)
157 ? stat(name, &st) 188 ? stat(name, &st)
158 : lstat(name, &st) 189 : lstat(name, &st)
159 ) { 190 ) {
@@ -308,28 +339,24 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
308 /* -L makes sense only with -o or -p */ 339 /* -L makes sense only with -o or -p */
309 340
310#if !ENABLE_FEATURE_CPIO_O 341#if !ENABLE_FEATURE_CPIO_O
311 /* no parameters */
312 opt_complementary = "=0";
313 opt = getopt32(argv, OPTION_STR, &cpio_filename); 342 opt = getopt32(argv, OPTION_STR, &cpio_filename);
314 argv += optind; 343 argv += optind;
315 if (opt & CPIO_OPT_FILE) { /* -F */ 344 if (opt & OPT_FILE) { /* -F */
316 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); 345 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
317 } 346 }
318#else 347#else
319 /* _exactly_ one parameter for -p, thus <= 1 param if -p is allowed */
320 opt_complementary = ENABLE_FEATURE_CPIO_P ? "?1" : "=0";
321 opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt); 348 opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
322 argv += optind; 349 argv += optind;
323 if ((opt & (CPIO_OPT_FILE|CPIO_OPT_CREATE)) == CPIO_OPT_FILE) { /* -F without -o */ 350 if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) { /* -F without -o */
324 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); 351 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
325 } 352 }
326 if (opt & CPIO_OPT_PASSTHROUGH) { 353 if (opt & OPT_PASSTHROUGH) {
327 pid_t pid; 354 pid_t pid;
328 struct fd_pair pp; 355 struct fd_pair pp;
329 356
330 if (argv[0] == NULL) 357 if (argv[0] == NULL)
331 bb_show_usage(); 358 bb_show_usage();
332 if (opt & CPIO_OPT_CREATE_LEADING_DIR) 359 if (opt & OPT_CREATE_LEADING_DIR)
333 mkdir(argv[0], 0777); 360 mkdir(argv[0], 0777);
334 /* Crude existence check: 361 /* Crude existence check:
335 * close(xopen(argv[0], O_RDONLY | O_DIRECTORY)); 362 * close(xopen(argv[0], O_RDONLY | O_DIRECTORY));
@@ -361,15 +388,15 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
361 xchdir(*argv++); 388 xchdir(*argv++);
362 close(pp.wr); 389 close(pp.wr);
363 xmove_fd(pp.rd, STDIN_FILENO); 390 xmove_fd(pp.rd, STDIN_FILENO);
364 //opt &= ~CPIO_OPT_PASSTHROUGH; 391 //opt &= ~OPT_PASSTHROUGH;
365 opt |= CPIO_OPT_EXTRACT; 392 opt |= OPT_EXTRACT;
366 goto skip; 393 goto skip;
367 } 394 }
368 /* -o */ 395 /* -o */
369 if (opt & CPIO_OPT_CREATE) { 396 if (opt & OPT_CREATE) {
370 if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */ 397 if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */
371 bb_show_usage(); 398 bb_show_usage();
372 if (opt & CPIO_OPT_FILE) { 399 if (opt & OPT_FILE) {
373 xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); 400 xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
374 } 401 }
375 dump: 402 dump:
@@ -379,35 +406,35 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
379#endif 406#endif
380 407
381 /* One of either extract or test options must be given */ 408 /* One of either extract or test options must be given */
382 if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) { 409 if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) {
383 bb_show_usage(); 410 bb_show_usage();
384 } 411 }
385 412
386 if (opt & CPIO_OPT_TEST) { 413 if (opt & OPT_TEST) {
387 /* if both extract and test options are given, ignore extract option */ 414 /* if both extract and test options are given, ignore extract option */
388 opt &= ~CPIO_OPT_EXTRACT; 415 opt &= ~OPT_EXTRACT;
389 archive_handle->action_header = header_list; 416 archive_handle->action_header = header_list;
390 } 417 }
391 if (opt & CPIO_OPT_EXTRACT) { 418 if (opt & OPT_EXTRACT) {
392 archive_handle->action_data = data_extract_all; 419 archive_handle->action_data = data_extract_all;
393 if (opt & CPIO_OPT_2STDOUT) 420 if (opt & OPT_2STDOUT)
394 archive_handle->action_data = data_extract_to_stdout; 421 archive_handle->action_data = data_extract_to_stdout;
395 } 422 }
396 if (opt & CPIO_OPT_UNCONDITIONAL) { 423 if (opt & OPT_UNCONDITIONAL) {
397 archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD; 424 archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD;
398 archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER; 425 archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
399 } 426 }
400 if (opt & CPIO_OPT_VERBOSE) { 427 if (opt & OPT_VERBOSE) {
401 if (archive_handle->action_header == header_list) { 428 if (archive_handle->action_header == header_list) {
402 archive_handle->action_header = header_verbose_list; 429 archive_handle->action_header = header_verbose_list;
403 } else { 430 } else {
404 archive_handle->action_header = header_list; 431 archive_handle->action_header = header_list;
405 } 432 }
406 } 433 }
407 if (opt & CPIO_OPT_CREATE_LEADING_DIR) { 434 if (opt & OPT_CREATE_LEADING_DIR) {
408 archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS; 435 archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
409 } 436 }
410 if (opt & CPIO_OPT_PRESERVE_MTIME) { 437 if (opt & OPT_PRESERVE_MTIME) {
411 archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE; 438 archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
412 } 439 }
413 440
@@ -423,7 +450,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
423 continue; 450 continue;
424 451
425 if (archive_handle->cpio__blocks != (off_t)-1 452 if (archive_handle->cpio__blocks != (off_t)-1
426 && !(opt & CPIO_OPT_QUIET) 453 && !(opt & OPT_QUIET)
427 ) { 454 ) {
428 fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks); 455 fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
429 } 456 }
diff --git a/archival/dpkg.c b/archival/dpkg.c
index 508b4297b..c37ae3349 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -30,7 +30,7 @@
30 30
31#include "libbb.h" 31#include "libbb.h"
32#include <fnmatch.h> 32#include <fnmatch.h>
33#include "unarchive.h" 33#include "archive.h"
34 34
35/* note: if you vary hash_prime sizes be aware, 35/* note: if you vary hash_prime sizes be aware,
36 * 1) tweaking these will have a big effect on how much memory this program uses. 36 * 1) tweaking these will have a big effect on how much memory this program uses.
@@ -939,8 +939,8 @@ static int package_satisfies_dependency(int package, int depend_type)
939 return 0; 939 return 0;
940 940
941 switch (depend_type) { 941 switch (depend_type) {
942 case EDGE_PRE_DEPENDS: return get_status(status_num, 3) == search_name_hashtable("installed"); 942 case EDGE_PRE_DEPENDS: return get_status(status_num, 3) == search_name_hashtable("installed");
943 case EDGE_DEPENDS: return get_status(status_num, 1) == search_name_hashtable("install"); 943 case EDGE_DEPENDS: return get_status(status_num, 1) == search_name_hashtable("install");
944 } 944 }
945 return 0; 945 return 0;
946} 946}
@@ -967,7 +967,7 @@ static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count
967 conflicts[conflicts_num] = package_num; 967 conflicts[conflicts_num] = package_num;
968 conflicts_num++; 968 conflicts_num++;
969 /* add provides to conflicts list */ 969 /* add provides to conflicts list */
970 for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) { 970 for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) {
971 if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) { 971 if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) {
972 const int conflicts_package_num = search_package_hashtable( 972 const int conflicts_package_num = search_package_hashtable(
973 package_hashtable[package_num]->edge[j]->name, 973 package_hashtable[package_num]->edge[j]->name,
@@ -1067,12 +1067,13 @@ static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count
1067 1067
1068 if (package_edge->type == EDGE_OR_PRE_DEPENDS 1068 if (package_edge->type == EDGE_OR_PRE_DEPENDS
1069 || package_edge->type == EDGE_OR_DEPENDS 1069 || package_edge->type == EDGE_OR_DEPENDS
1070 ) { /* start an EDGE_OR_ list */ 1070 ) {
1071 /* start an EDGE_OR_ list */
1071 number_of_alternatives = package_edge->version; 1072 number_of_alternatives = package_edge->version;
1072 root_of_alternatives = package_edge; 1073 root_of_alternatives = package_edge;
1073 continue; 1074 continue;
1074 } 1075 }
1075 if (number_of_alternatives == 0) { /* not in the middle of an EDGE_OR_ list */ 1076 if (number_of_alternatives == 0) { /* not in the middle of an EDGE_OR_ list */
1076 number_of_alternatives = 1; 1077 number_of_alternatives = 1;
1077 root_of_alternatives = NULL; 1078 root_of_alternatives = NULL;
1078 } 1079 }
diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c
index 4c627e890..aee7b4cf5 100644
--- a/archival/dpkg_deb.c
+++ b/archival/dpkg_deb.c
@@ -5,13 +5,13 @@
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#include "libbb.h" 7#include "libbb.h"
8#include "unarchive.h" 8#include "archive.h"
9 9
10#define DPKG_DEB_OPT_CONTENTS 1 10#define DPKG_DEB_OPT_CONTENTS 1
11#define DPKG_DEB_OPT_CONTROL 2 11#define DPKG_DEB_OPT_CONTROL 2
12#define DPKG_DEB_OPT_FIELD 4 12#define DPKG_DEB_OPT_FIELD 4
13#define DPKG_DEB_OPT_EXTRACT 8 13#define DPKG_DEB_OPT_EXTRACT 8
14#define DPKG_DEB_OPT_EXTRACT_VERBOSE 16 14#define DPKG_DEB_OPT_EXTRACT_VERBOSE 16
15 15
16int dpkg_deb_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 16int dpkg_deb_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
17int dpkg_deb_main(int argc, char **argv) 17int dpkg_deb_main(int argc, char **argv)
diff --git a/archival/gzip.c b/archival/gzip.c
index b573ed6ab..feeddf58f 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -40,7 +40,7 @@ aa: 85.1% -- replaced with aa.gz
40*/ 40*/
41 41
42#include "libbb.h" 42#include "libbb.h"
43#include "unarchive.h" 43#include "archive.h"
44 44
45 45
46/* =========================================================================== 46/* ===========================================================================
diff --git a/archival/libunarchive/Kbuild.src b/archival/libarchive/Kbuild.src
index e92b4aad2..b0bc4e5aa 100644
--- a/archival/libunarchive/Kbuild.src
+++ b/archival/libarchive/Kbuild.src
@@ -48,6 +48,8 @@ lib-$(CONFIG_RPM) += open_transformer.o decompress_unzip.o
48lib-$(CONFIG_TAR) += get_header_tar.o 48lib-$(CONFIG_TAR) += get_header_tar.o
49lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o 49lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o
50lib-$(CONFIG_UNZIP) += decompress_unzip.o 50lib-$(CONFIG_UNZIP) += decompress_unzip.o
51lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o
52lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o
51lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o 53lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o
52lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_unzip.o get_header_tar_gz.o 54lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_unzip.o get_header_tar_gz.o
53lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o 55lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o
diff --git a/archival/bz/LICENSE b/archival/libarchive/bz/LICENSE
index da4346520..da4346520 100644
--- a/archival/bz/LICENSE
+++ b/archival/libarchive/bz/LICENSE
diff --git a/archival/bz/README b/archival/libarchive/bz/README
index fffd47b8a..fffd47b8a 100644
--- a/archival/bz/README
+++ b/archival/libarchive/bz/README
diff --git a/archival/bz/blocksort.c b/archival/libarchive/bz/blocksort.c
index f70c3701d..f70c3701d 100644
--- a/archival/bz/blocksort.c
+++ b/archival/libarchive/bz/blocksort.c
diff --git a/archival/bz/bzlib.c b/archival/libarchive/bz/bzlib.c
index 834179403..5f7db747a 100644
--- a/archival/bz/bzlib.c
+++ b/archival/libarchive/bz/bzlib.c
@@ -28,7 +28,7 @@ in the file LICENSE.
28 * 0.9.0a/b -- no changes in this file. 28 * 0.9.0a/b -- no changes in this file.
29 * 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). 29 * 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress().
30 * fixed bzWrite/bzRead to ignore zero-length requests. 30 * fixed bzWrite/bzRead to ignore zero-length requests.
31 * fixed bzread to correctly handle read requests after EOF. 31 * fixed bzread to correctly handle read requests after EOF.
32 * wrong parameter order in call to bzDecompressInit in 32 * wrong parameter order in call to bzDecompressInit in
33 * bzBuffToBuffDecompress. Fixed. 33 * bzBuffToBuffDecompress. Fixed.
34 */ 34 */
@@ -361,7 +361,6 @@ int BZ2_bzCompress(bz_stream *strm, int action)
361 361
362 362
363/*---------------------------------------------------*/ 363/*---------------------------------------------------*/
364#if ENABLE_FEATURE_CLEAN_UP
365static 364static
366void BZ2_bzCompressEnd(bz_stream *strm) 365void BZ2_bzCompressEnd(bz_stream *strm)
367{ 366{
@@ -372,9 +371,8 @@ void BZ2_bzCompressEnd(bz_stream *strm)
372 free(s->arr2); 371 free(s->arr2);
373 free(s->ftab); 372 free(s->ftab);
374 free(s->crc32table); 373 free(s->crc32table);
375 free(strm->state); 374 free(s);
376} 375}
377#endif
378 376
379 377
380/*---------------------------------------------------*/ 378/*---------------------------------------------------*/
diff --git a/archival/bz/bzlib.h b/archival/libarchive/bz/bzlib.h
index 1bb811c4a..1bb811c4a 100644
--- a/archival/bz/bzlib.h
+++ b/archival/libarchive/bz/bzlib.h
diff --git a/archival/bz/bzlib_private.h b/archival/libarchive/bz/bzlib_private.h
index 6430ce407..6430ce407 100644
--- a/archival/bz/bzlib_private.h
+++ b/archival/libarchive/bz/bzlib_private.h
diff --git a/archival/bz/compress.c b/archival/libarchive/bz/compress.c
index b9b0949a9..6f1c70a08 100644
--- a/archival/bz/compress.c
+++ b/archival/libarchive/bz/compress.c
@@ -134,15 +134,14 @@ void generateMTFValues(EState* s)
134 * holds the original block data. 134 * holds the original block data.
135 * 135 *
136 * The first thing to do is generate the MTF values, 136 * The first thing to do is generate the MTF values,
137 * and put them in 137 * and put them in ((uint16_t*)s->arr1)[0 .. s->nblock-1].
138 * ((uint16_t*)s->arr1)[0 .. s->nblock-1]. 138 *
139 * Because there are strictly fewer or equal MTF values 139 * Because there are strictly fewer or equal MTF values
140 * than block values, ptr values in this area are overwritten 140 * than block values, ptr values in this area are overwritten
141 * with MTF values only when they are no longer needed. 141 * with MTF values only when they are no longer needed.
142 * 142 *
143 * The final compressed bitstream is generated into the 143 * The final compressed bitstream is generated into the
144 * area starting at 144 * area starting at &((uint8_t*)s->arr2)[s->nblock]
145 * &((uint8_t*)s->arr2)[s->nblock]
146 * 145 *
147 * These storage aliases are set up in bzCompressInit(), 146 * These storage aliases are set up in bzCompressInit(),
148 * except for the last one, which is arranged in 147 * except for the last one, which is arranged in
@@ -459,7 +458,7 @@ void sendMTFValues(EState* s)
459 } 458 }
460 459
461 AssertH(nGroups < 8, 3002); 460 AssertH(nGroups < 8, 3002);
462 AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003); 461 AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003);
463 462
464 /*--- Compute MTF values for the selectors. ---*/ 463 /*--- Compute MTF values for the selectors. ---*/
465 { 464 {
diff --git a/archival/bz/huffman.c b/archival/libarchive/bz/huffman.c
index 676b1af66..676b1af66 100644
--- a/archival/bz/huffman.c
+++ b/archival/libarchive/bz/huffman.c
diff --git a/archival/libunarchive/data_align.c b/archival/libarchive/data_align.c
index 4e21a36b3..2e56fa8ff 100644
--- a/archival/libunarchive/data_align.c
+++ b/archival/libarchive/data_align.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary) 9void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary)
10{ 10{
diff --git a/archival/libunarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index 5fb1ab2ae..1b25c8bd6 100644
--- a/archival/libunarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) 9void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
10{ 10{
diff --git a/archival/libunarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c
index b54f7f215..2bbab7641 100644
--- a/archival/libunarchive/data_extract_to_command.c
+++ b/archival/libarchive/data_extract_to_command.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9enum { 9enum {
10 //TAR_FILETYPE, 10 //TAR_FILETYPE,
diff --git a/archival/libunarchive/data_extract_to_stdout.c b/archival/libarchive/data_extract_to_stdout.c
index ce0713ac4..91f3f3539 100644
--- a/archival/libunarchive/data_extract_to_stdout.c
+++ b/archival/libarchive/data_extract_to_stdout.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle) 9void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle)
10{ 10{
diff --git a/archival/libunarchive/data_skip.c b/archival/libarchive/data_skip.c
index 06b74399d..a055424e2 100644
--- a/archival/libunarchive/data_skip.c
+++ b/archival/libarchive/data_skip.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9void FAST_FUNC data_skip(archive_handle_t *archive_handle) 9void FAST_FUNC data_skip(archive_handle_t *archive_handle)
10{ 10{
diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c
index 22015683c..4e46e6849 100644
--- a/archival/libunarchive/decompress_bunzip2.c
+++ b/archival/libarchive/decompress_bunzip2.c
@@ -16,10 +16,21 @@
16 function, and various other tweaks. In (limited) tests, approximately 16 function, and various other tweaks. In (limited) tests, approximately
17 20% faster than bzcat on x86 and about 10% faster on arm. 17 20% faster than bzcat on x86 and about 10% faster on arm.
18 18
19 Note that about 2/3 of the time is spent in read_unzip() reversing 19 Note that about 2/3 of the time is spent in read_bunzip() reversing
20 the Burrows-Wheeler transformation. Much of that time is delay 20 the Burrows-Wheeler transformation. Much of that time is delay
21 resulting from cache misses. 21 resulting from cache misses.
22 22
23 (2010 update by vda: profiled "bzcat <84mbyte.bz2 >/dev/null"
24 on x86-64 CPU with L2 > 1M: get_next_block is hotter than read_bunzip:
25 %time seconds calls function
26 71.01 12.69 444 get_next_block
27 28.65 5.12 93065 read_bunzip
28 00.22 0.04 7736490 get_bits
29 00.11 0.02 47 dealloc_bunzip
30 00.00 0.00 93018 full_write
31 ...)
32
33
23 I would ask that anyone benefiting from this work, especially those 34 I would ask that anyone benefiting from this work, especially those
24 using it in commercial products, consider making a donation to my local 35 using it in commercial products, consider making a donation to my local
25 non-profit hospice organization (www.hospiceacadiana.com) in the name of 36 non-profit hospice organization (www.hospiceacadiana.com) in the name of
@@ -29,7 +40,7 @@
29 */ 40 */
30 41
31#include "libbb.h" 42#include "libbb.h"
32#include "unarchive.h" 43#include "archive.h"
33 44
34/* Constants for Huffman coding */ 45/* Constants for Huffman coding */
35#define MAX_GROUPS 6 46#define MAX_GROUPS 6
@@ -70,38 +81,41 @@ struct bunzip_data {
70 /* I/O tracking data (file handles, buffers, positions, etc.) */ 81 /* I/O tracking data (file handles, buffers, positions, etc.) */
71 unsigned inbufBitCount, inbufBits; 82 unsigned inbufBitCount, inbufBits;
72 int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/; 83 int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/;
73 unsigned char *inbuf /*,*outbuf*/; 84 uint8_t *inbuf /*,*outbuf*/;
74 85
75 /* State for interrupting output loop */ 86 /* State for interrupting output loop */
76 int writeCopies, writePos, writeRunCountdown, writeCount, writeCurrent; 87 int writeCopies, writePos, writeRunCountdown, writeCount;
88 int writeCurrent; /* actually a uint8_t */
77 89
78 /* The CRC values stored in the block header and calculated from the data */ 90 /* The CRC values stored in the block header and calculated from the data */
79 uint32_t headerCRC, totalCRC, writeCRC; 91 uint32_t headerCRC, totalCRC, writeCRC;
80 92
81 /* Intermediate buffer and its size (in bytes) */ 93 /* Intermediate buffer and its size (in bytes) */
82 unsigned *dbuf, dbufSize; 94 uint32_t *dbuf;
95 unsigned dbufSize;
83 96
84 /* For I/O error handling */ 97 /* For I/O error handling */
85 jmp_buf jmpbuf; 98 jmp_buf jmpbuf;
86 99
87 /* Big things go last (register-relative addressing can be larger for big offsets) */ 100 /* Big things go last (register-relative addressing can be larger for big offsets) */
88 uint32_t crc32Table[256]; 101 uint32_t crc32Table[256];
89 unsigned char selectors[32768]; /* nSelectors=15 bits */ 102 uint8_t selectors[32768]; /* nSelectors=15 bits */
90 struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */ 103 struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */
91}; 104};
92/* typedef struct bunzip_data bunzip_data; -- done in .h file */ 105/* typedef struct bunzip_data bunzip_data; -- done in .h file */
93 106
94 107
95/* Return the next nnn bits of input. All reads from the compressed input 108/* Return the next nnn bits of input. All reads from the compressed input
96 are done through this function. All reads are big endian */ 109 are done through this function. All reads are big endian */
97
98static unsigned get_bits(bunzip_data *bd, int bits_wanted) 110static unsigned get_bits(bunzip_data *bd, int bits_wanted)
99{ 111{
100 unsigned bits = 0; 112 unsigned bits = 0;
113 /* Cache bd->inbufBitCount in a CPU register (hopefully): */
114 int bit_count = bd->inbufBitCount;
101 115
102 /* If we need to get more data from the byte buffer, do so. (Loop getting 116 /* If we need to get more data from the byte buffer, do so. (Loop getting
103 one byte at a time to enforce endianness and avoid unaligned access.) */ 117 one byte at a time to enforce endianness and avoid unaligned access.) */
104 while ((int)(bd->inbufBitCount) < bits_wanted) { 118 while (bit_count < bits_wanted) {
105 119
106 /* If we need to read more data from file into byte buffer, do so */ 120 /* If we need to read more data from file into byte buffer, do so */
107 if (bd->inbufPos == bd->inbufCount) { 121 if (bd->inbufPos == bd->inbufCount) {
@@ -113,41 +127,47 @@ static unsigned get_bits(bunzip_data *bd, int bits_wanted)
113 } 127 }
114 128
115 /* Avoid 32-bit overflow (dump bit buffer to top of output) */ 129 /* Avoid 32-bit overflow (dump bit buffer to top of output) */
116 if (bd->inbufBitCount >= 24) { 130 if (bit_count >= 24) {
117 bits = bd->inbufBits & ((1 << bd->inbufBitCount) - 1); 131 bits = bd->inbufBits & ((1 << bit_count) - 1);
118 bits_wanted -= bd->inbufBitCount; 132 bits_wanted -= bit_count;
119 bits <<= bits_wanted; 133 bits <<= bits_wanted;
120 bd->inbufBitCount = 0; 134 bit_count = 0;
121 } 135 }
122 136
123 /* Grab next 8 bits of input from buffer. */ 137 /* Grab next 8 bits of input from buffer. */
124 bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; 138 bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
125 bd->inbufBitCount += 8; 139 bit_count += 8;
126 } 140 }
127 141
128 /* Calculate result */ 142 /* Calculate result */
129 bd->inbufBitCount -= bits_wanted; 143 bit_count -= bits_wanted;
130 bits |= (bd->inbufBits >> bd->inbufBitCount) & ((1 << bits_wanted) - 1); 144 bd->inbufBitCount = bit_count;
145 bits |= (bd->inbufBits >> bit_count) & ((1 << bits_wanted) - 1);
131 146
132 return bits; 147 return bits;
133} 148}
134 149
135/* Unpacks the next block and sets up for the inverse burrows-wheeler step. */ 150/* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */
136static int get_next_block(bunzip_data *bd) 151static int get_next_block(bunzip_data *bd)
137{ 152{
138 struct group_data *hufGroup; 153 struct group_data *hufGroup;
139 int dbufCount, nextSym, dbufSize, groupCount, *base, *limit, selector, 154 int dbufCount, dbufSize, groupCount, *base, *limit, selector,
140 i, j, k, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; 155 i, j, t, runPos, symCount, symTotal, nSelectors, byteCount[256];
141 unsigned char uc, symToByte[256], mtfSymbol[256], *selectors; 156 int runCnt = runCnt; /* for compiler */
142 unsigned *dbuf, origPtr; 157 uint8_t uc, symToByte[256], mtfSymbol[256], *selectors;
158 uint32_t *dbuf;
159 unsigned origPtr;
143 160
144 dbuf = bd->dbuf; 161 dbuf = bd->dbuf;
145 dbufSize = bd->dbufSize; 162 dbufSize = bd->dbufSize;
146 selectors = bd->selectors; 163 selectors = bd->selectors;
147 164
165/* In bbox, we are ok with aborting through setjmp which is set up in start_bunzip */
166#if 0
148 /* Reset longjmp I/O error handling */ 167 /* Reset longjmp I/O error handling */
149 i = setjmp(bd->jmpbuf); 168 i = setjmp(bd->jmpbuf);
150 if (i) return i; 169 if (i) return i;
170#endif
151 171
152 /* Read in header signature and CRC, then validate signature. 172 /* Read in header signature and CRC, then validate signature.
153 (last block signature means CRC is for whole file, return now) */ 173 (last block signature means CRC is for whole file, return now) */
@@ -169,16 +189,23 @@ static int get_next_block(bunzip_data *bd)
169 symbols to deal with, and writes a sparse bitfield indicating which 189 symbols to deal with, and writes a sparse bitfield indicating which
170 values were present. We make a translation table to convert the symbols 190 values were present. We make a translation table to convert the symbols
171 back to the corresponding bytes. */ 191 back to the corresponding bytes. */
172 t = get_bits(bd, 16);
173 symTotal = 0; 192 symTotal = 0;
174 for (i = 0; i < 16; i++) { 193 i = 0;
175 if (t & (1 << (15-i))) { 194 t = get_bits(bd, 16);
176 k = get_bits(bd, 16); 195 do {
177 for (j = 0; j < 16; j++) 196 if (t & (1 << 15)) {
178 if (k & (1 << (15-j))) 197 unsigned inner_map = get_bits(bd, 16);
179 symToByte[symTotal++] = (16*i) + j; 198 do {
199 if (inner_map & (1 << 15))
200 symToByte[symTotal++] = i;
201 inner_map <<= 1;
202 i++;
203 } while (i & 15);
204 i -= 16;
180 } 205 }
181 } 206 t <<= 1;
207 i += 16;
208 } while (i < 256);
182 209
183 /* How many different Huffman coding groups does this block use? */ 210 /* How many different Huffman coding groups does this block use? */
184 groupCount = get_bits(bd, 3); 211 groupCount = get_bits(bd, 3);
@@ -189,57 +216,63 @@ static int get_next_block(bunzip_data *bd)
189 group. Read in the group selector list, which is stored as MTF encoded 216 group. Read in the group selector list, which is stored as MTF encoded
190 bit runs. (MTF=Move To Front, as each value is used it's moved to the 217 bit runs. (MTF=Move To Front, as each value is used it's moved to the
191 start of the list.) */ 218 start of the list.) */
219 for (i = 0; i < groupCount; i++)
220 mtfSymbol[i] = i;
192 nSelectors = get_bits(bd, 15); 221 nSelectors = get_bits(bd, 15);
193 if (!nSelectors) return RETVAL_DATA_ERROR; 222 if (!nSelectors)
194 for (i = 0; i < groupCount; i++) mtfSymbol[i] = i; 223 return RETVAL_DATA_ERROR;
195 for (i = 0; i < nSelectors; i++) { 224 for (i = 0; i < nSelectors; i++) {
196 225 uint8_t tmp_byte;
197 /* Get next value */ 226 /* Get next value */
198 for (j = 0; get_bits(bd, 1); j++) 227 int n = 0;
199 if (j >= groupCount) return RETVAL_DATA_ERROR; 228 while (get_bits(bd, 1)) {
200 229 if (n >= groupCount) return RETVAL_DATA_ERROR;
230 n++;
231 }
201 /* Decode MTF to get the next selector */ 232 /* Decode MTF to get the next selector */
202 uc = mtfSymbol[j]; 233 tmp_byte = mtfSymbol[n];
203 for (;j;j--) mtfSymbol[j] = mtfSymbol[j-1]; 234 while (--n >= 0)
204 mtfSymbol[0] = selectors[i] = uc; 235 mtfSymbol[n + 1] = mtfSymbol[n];
236 mtfSymbol[0] = selectors[i] = tmp_byte;
205 } 237 }
206 238
207 /* Read the Huffman coding tables for each group, which code for symTotal 239 /* Read the Huffman coding tables for each group, which code for symTotal
208 literal symbols, plus two run symbols (RUNA, RUNB) */ 240 literal symbols, plus two run symbols (RUNA, RUNB) */
209 symCount = symTotal + 2; 241 symCount = symTotal + 2;
210 for (j = 0; j < groupCount; j++) { 242 for (j = 0; j < groupCount; j++) {
211 unsigned char length[MAX_SYMBOLS]; 243 uint8_t length[MAX_SYMBOLS];
212 /* 8 bits is ALMOST enough for temp[], see below */ 244 /* 8 bits is ALMOST enough for temp[], see below */
213 unsigned temp[MAX_HUFCODE_BITS+1]; 245 unsigned temp[MAX_HUFCODE_BITS+1];
214 int minLen, maxLen, pp; 246 int minLen, maxLen, pp, len_m1;
215 247
216 /* Read Huffman code lengths for each symbol. They're stored in 248 /* Read Huffman code lengths for each symbol. They're stored in
217 a way similar to mtf; record a starting value for the first symbol, 249 a way similar to mtf; record a starting value for the first symbol,
218 and an offset from the previous value for everys symbol after that. 250 and an offset from the previous value for every symbol after that.
219 (Subtracting 1 before the loop and then adding it back at the end is 251 (Subtracting 1 before the loop and then adding it back at the end is
220 an optimization that makes the test inside the loop simpler: symbol 252 an optimization that makes the test inside the loop simpler: symbol
221 length 0 becomes negative, so an unsigned inequality catches it.) */ 253 length 0 becomes negative, so an unsigned inequality catches it.) */
222 t = get_bits(bd, 5) - 1; 254 len_m1 = get_bits(bd, 5) - 1;
223 for (i = 0; i < symCount; i++) { 255 for (i = 0; i < symCount; i++) {
224 for (;;) { 256 for (;;) {
225 if ((unsigned)t > (MAX_HUFCODE_BITS-1)) 257 int two_bits;
258 if ((unsigned)len_m1 > (MAX_HUFCODE_BITS-1))
226 return RETVAL_DATA_ERROR; 259 return RETVAL_DATA_ERROR;
227 260
228 /* If first bit is 0, stop. Else second bit indicates whether 261 /* If first bit is 0, stop. Else second bit indicates whether
229 to increment or decrement the value. Optimization: grab 2 262 to increment or decrement the value. Optimization: grab 2
230 bits and unget the second if the first was 0. */ 263 bits and unget the second if the first was 0. */
231 k = get_bits(bd, 2); 264 two_bits = get_bits(bd, 2);
232 if (k < 2) { 265 if (two_bits < 2) {
233 bd->inbufBitCount++; 266 bd->inbufBitCount++;
234 break; 267 break;
235 } 268 }
236 269
237 /* Add one if second bit 1, else subtract 1. Avoids if/else */ 270 /* Add one if second bit 1, else subtract 1. Avoids if/else */
238 t += (((k+1) & 2) - 1); 271 len_m1 += (((two_bits+1) & 2) - 1);
239 } 272 }
240 273
241 /* Correct for the initial -1, to get the final symbol length */ 274 /* Correct for the initial -1, to get the final symbol length */
242 length[i] = t + 1; 275 length[i] = len_m1 + 1;
243 } 276 }
244 277
245 /* Find largest and smallest lengths in this group */ 278 /* Find largest and smallest lengths in this group */
@@ -265,17 +298,18 @@ static int get_next_block(bunzip_data *bd)
265 298
266 /* Note that minLen can't be smaller than 1, so we adjust the base 299 /* Note that minLen can't be smaller than 1, so we adjust the base
267 and limit array pointers so we're not always wasting the first 300 and limit array pointers so we're not always wasting the first
268 entry. We do this again when using them (during symbol decoding).*/ 301 entry. We do this again when using them (during symbol decoding). */
269 base = hufGroup->base - 1; 302 base = hufGroup->base - 1;
270 limit = hufGroup->limit - 1; 303 limit = hufGroup->limit - 1;
271 304
272 /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */ 305 /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */
273 pp = 0; 306 pp = 0;
274 for (i = minLen; i <= maxLen; i++) { 307 for (i = minLen; i <= maxLen; i++) {
308 int k;
275 temp[i] = limit[i] = 0; 309 temp[i] = limit[i] = 0;
276 for (t = 0; t < symCount; t++) 310 for (k = 0; k < symCount; k++)
277 if (length[t] == i) 311 if (length[k] == i)
278 hufGroup->permute[pp++] = t; 312 hufGroup->permute[pp++] = k;
279 } 313 }
280 314
281 /* Count symbols coded for at each bit length */ 315 /* Count symbols coded for at each bit length */
@@ -288,8 +322,10 @@ static int get_next_block(bunzip_data *bd)
288 * base[] (number of symbols to ignore at each bit length, which is 322 * base[] (number of symbols to ignore at each bit length, which is
289 * limit minus the cumulative count of symbols coded for already). */ 323 * limit minus the cumulative count of symbols coded for already). */
290 pp = t = 0; 324 pp = t = 0;
291 for (i = minLen; i < maxLen; i++) { 325 for (i = minLen; i < maxLen;) {
292 pp += temp[i]; 326 unsigned temp_i = temp[i];
327
328 pp += temp_i;
293 329
294 /* We read the largest possible symbol size and then unget bits 330 /* We read the largest possible symbol size and then unget bits
295 after determining how many we need, and those extra bits could 331 after determining how many we need, and those extra bits could
@@ -299,11 +335,11 @@ static int get_next_block(bunzip_data *bd)
299 don't affect the value>limit[length] comparison. */ 335 don't affect the value>limit[length] comparison. */
300 limit[i] = (pp << (maxLen - i)) - 1; 336 limit[i] = (pp << (maxLen - i)) - 1;
301 pp <<= 1; 337 pp <<= 1;
302 t += temp[i]; 338 t += temp_i;
303 base[i+1] = pp - t; 339 base[++i] = pp - t;
304 } 340 }
305 limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */
306 limit[maxLen] = pp + temp[maxLen] - 1; 341 limit[maxLen] = pp + temp[maxLen] - 1;
342 limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */
307 base[minLen] = 0; 343 base[minLen] = 0;
308 } 344 }
309 345
@@ -312,16 +348,17 @@ static int get_next_block(bunzip_data *bd)
312 and run length encoding, saving the result into dbuf[dbufCount++] = uc */ 348 and run length encoding, saving the result into dbuf[dbufCount++] = uc */
313 349
314 /* Initialize symbol occurrence counters and symbol Move To Front table */ 350 /* Initialize symbol occurrence counters and symbol Move To Front table */
315 memset(byteCount, 0, sizeof(byteCount)); /* smaller, maybe slower? */ 351 /*memset(byteCount, 0, sizeof(byteCount)); - smaller, but slower */
316 for (i = 0; i < 256; i++) { 352 for (i = 0; i < 256; i++) {
317 //byteCount[i] = 0; 353 byteCount[i] = 0;
318 mtfSymbol[i] = (unsigned char)i; 354 mtfSymbol[i] = (uint8_t)i;
319 } 355 }
320 356
321 /* Loop through compressed symbols. */ 357 /* Loop through compressed symbols. */
322 358
323 runPos = dbufCount = selector = 0; 359 runPos = dbufCount = selector = 0;
324 for (;;) { 360 for (;;) {
361 int nextSym;
325 362
326 /* Fetch next Huffman coding group from list. */ 363 /* Fetch next Huffman coding group from list. */
327 symCount = GROUP_SIZE - 1; 364 symCount = GROUP_SIZE - 1;
@@ -329,44 +366,49 @@ static int get_next_block(bunzip_data *bd)
329 hufGroup = bd->groups + selectors[selector++]; 366 hufGroup = bd->groups + selectors[selector++];
330 base = hufGroup->base - 1; 367 base = hufGroup->base - 1;
331 limit = hufGroup->limit - 1; 368 limit = hufGroup->limit - 1;
332 continue_this_group:
333 369
370 continue_this_group:
334 /* Read next Huffman-coded symbol. */ 371 /* Read next Huffman-coded symbol. */
335 372
336 /* Note: It is far cheaper to read maxLen bits and back up than it is 373 /* Note: It is far cheaper to read maxLen bits and back up than it is
337 to read minLen bits and then an additional bit at a time, testing 374 to read minLen bits and then add additional bit at a time, testing
338 as we go. Because there is a trailing last block (with file CRC), 375 as we go. Because there is a trailing last block (with file CRC),
339 there is no danger of the overread causing an unexpected EOF for a 376 there is no danger of the overread causing an unexpected EOF for a
340 valid compressed file. As a further optimization, we do the read 377 valid compressed file.
341 inline (falling back to a call to get_bits if the buffer runs
342 dry). The following (up to got_huff_bits:) is equivalent to
343 j = get_bits(bd, hufGroup->maxLen);
344 */ 378 */
345 while ((int)(bd->inbufBitCount) < hufGroup->maxLen) { 379 if (1) {
346 if (bd->inbufPos == bd->inbufCount) { 380 /* As a further optimization, we do the read inline
347 j = get_bits(bd, hufGroup->maxLen); 381 (falling back to a call to get_bits if the buffer runs dry).
348 goto got_huff_bits; 382 */
349 } 383 int new_cnt;
350 bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; 384 while ((new_cnt = bd->inbufBitCount - hufGroup->maxLen) < 0) {
351 bd->inbufBitCount += 8; 385 /* bd->inbufBitCount < hufGroup->maxLen */
352 }; 386 if (bd->inbufPos == bd->inbufCount) {
353 bd->inbufBitCount -= hufGroup->maxLen; 387 nextSym = get_bits(bd, hufGroup->maxLen);
354 j = (bd->inbufBits >> bd->inbufBitCount) & ((1 << hufGroup->maxLen) - 1); 388 goto got_huff_bits;
355 389 }
356 got_huff_bits: 390 bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++];
357 391 bd->inbufBitCount += 8;
358 /* Figure how how many bits are in next symbol and unget extras */ 392 };
393 bd->inbufBitCount = new_cnt; /* "bd->inbufBitCount -= hufGroup->maxLen;" */
394 nextSym = (bd->inbufBits >> new_cnt) & ((1 << hufGroup->maxLen) - 1);
395 got_huff_bits: ;
396 } else { /* unoptimized equivalent */
397 nextSym = get_bits(bd, hufGroup->maxLen);
398 }
399 /* Figure how many bits are in next symbol and unget extras */
359 i = hufGroup->minLen; 400 i = hufGroup->minLen;
360 while (j > limit[i]) ++i; 401 while (nextSym > limit[i]) ++i;
361 bd->inbufBitCount += (hufGroup->maxLen - i); 402 j = hufGroup->maxLen - i;
403 if (j < 0)
404 return RETVAL_DATA_ERROR;
405 bd->inbufBitCount += j;
362 406
363 /* Huffman decode value to get nextSym (with bounds checking) */ 407 /* Huffman decode value to get nextSym (with bounds checking) */
364 if (i > hufGroup->maxLen) 408 nextSym = (nextSym >> j) - base[i];
409 if ((unsigned)nextSym >= MAX_SYMBOLS)
365 return RETVAL_DATA_ERROR; 410 return RETVAL_DATA_ERROR;
366 j = (j >> (hufGroup->maxLen - i)) - base[i]; 411 nextSym = hufGroup->permute[nextSym];
367 if ((unsigned)j >= MAX_SYMBOLS)
368 return RETVAL_DATA_ERROR;
369 nextSym = hufGroup->permute[j];
370 412
371 /* We have now decoded the symbol, which indicates either a new literal 413 /* We have now decoded the symbol, which indicates either a new literal
372 byte, or a repeated run of the most recent literal byte. First, 414 byte, or a repeated run of the most recent literal byte. First,
@@ -375,9 +417,9 @@ static int get_next_block(bunzip_data *bd)
375 if ((unsigned)nextSym <= SYMBOL_RUNB) { /* RUNA or RUNB */ 417 if ((unsigned)nextSym <= SYMBOL_RUNB) { /* RUNA or RUNB */
376 418
377 /* If this is the start of a new run, zero out counter */ 419 /* If this is the start of a new run, zero out counter */
378 if (!runPos) { 420 if (runPos == 0) {
379 runPos = 1; 421 runPos = 1;
380 t = 0; 422 runCnt = 0;
381 } 423 }
382 424
383 /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at 425 /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at
@@ -387,7 +429,7 @@ static int get_next_block(bunzip_data *bd)
387 the basic or 0/1 method (except all bits 0, which would use no 429 the basic or 0/1 method (except all bits 0, which would use no
388 symbols, but a run of length 0 doesn't mean anything in this 430 symbols, but a run of length 0 doesn't mean anything in this
389 context). Thus space is saved. */ 431 context). Thus space is saved. */
390 t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ 432 runCnt += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */
391 if (runPos < dbufSize) runPos <<= 1; 433 if (runPos < dbufSize) runPos <<= 1;
392 goto end_of_huffman_loop; 434 goto end_of_huffman_loop;
393 } 435 }
@@ -396,13 +438,13 @@ static int get_next_block(bunzip_data *bd)
396 how many times to repeat the last literal, so append that many 438 how many times to repeat the last literal, so append that many
397 copies to our buffer of decoded symbols (dbuf) now. (The last 439 copies to our buffer of decoded symbols (dbuf) now. (The last
398 literal used is the one at the head of the mtfSymbol array.) */ 440 literal used is the one at the head of the mtfSymbol array.) */
399 if (runPos) { 441 if (runPos != 0) {
442 uint8_t tmp_byte;
443 if (dbufCount + runCnt >= dbufSize) return RETVAL_DATA_ERROR;
444 tmp_byte = symToByte[mtfSymbol[0]];
445 byteCount[tmp_byte] += runCnt;
446 while (--runCnt >= 0) dbuf[dbufCount++] = (uint32_t)tmp_byte;
400 runPos = 0; 447 runPos = 0;
401 if (dbufCount + t >= dbufSize) return RETVAL_DATA_ERROR;
402
403 uc = symToByte[mtfSymbol[0]];
404 byteCount[uc] += t;
405 while (t--) dbuf[dbufCount++] = uc;
406 } 448 }
407 449
408 /* Is this the terminating symbol? */ 450 /* Is this the terminating symbol? */
@@ -431,12 +473,12 @@ static int get_next_block(bunzip_data *bd)
431 473
432 /* We have our literal byte. Save it into dbuf. */ 474 /* We have our literal byte. Save it into dbuf. */
433 byteCount[uc]++; 475 byteCount[uc]++;
434 dbuf[dbufCount++] = (unsigned)uc; 476 dbuf[dbufCount++] = (uint32_t)uc;
435 477
436 /* Skip group initialization if we're not done with this group. Done 478 /* Skip group initialization if we're not done with this group. Done
437 * this way to avoid compiler warning. */ 479 * this way to avoid compiler warning. */
438 end_of_huffman_loop: 480 end_of_huffman_loop:
439 if (symCount--) goto continue_this_group; 481 if (--symCount >= 0) goto continue_this_group;
440 } 482 }
441 483
442 /* At this point, we've read all the Huffman-coded symbols (and repeated 484 /* At this point, we've read all the Huffman-coded symbols (and repeated
@@ -449,26 +491,28 @@ static int get_next_block(bunzip_data *bd)
449 /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */ 491 /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
450 j = 0; 492 j = 0;
451 for (i = 0; i < 256; i++) { 493 for (i = 0; i < 256; i++) {
452 k = j + byteCount[i]; 494 int tmp_count = j + byteCount[i];
453 byteCount[i] = j; 495 byteCount[i] = j;
454 j = k; 496 j = tmp_count;
455 } 497 }
456 498
457 /* Figure out what order dbuf would be in if we sorted it. */ 499 /* Figure out what order dbuf would be in if we sorted it. */
458 for (i = 0; i < dbufCount; i++) { 500 for (i = 0; i < dbufCount; i++) {
459 uc = (unsigned char)(dbuf[i] & 0xff); 501 uint8_t tmp_byte = (uint8_t)dbuf[i];
460 dbuf[byteCount[uc]] |= (i << 8); 502 int tmp_count = byteCount[tmp_byte];
461 byteCount[uc]++; 503 dbuf[tmp_count] |= (i << 8);
504 byteCount[tmp_byte] = tmp_count + 1;
462 } 505 }
463 506
464 /* Decode first byte by hand to initialize "previous" byte. Note that it 507 /* Decode first byte by hand to initialize "previous" byte. Note that it
465 doesn't get output, and if the first three characters are identical 508 doesn't get output, and if the first three characters are identical
466 it doesn't qualify as a run (hence writeRunCountdown=5). */ 509 it doesn't qualify as a run (hence writeRunCountdown=5). */
467 if (dbufCount) { 510 if (dbufCount) {
511 uint32_t tmp;
468 if ((int)origPtr >= dbufCount) return RETVAL_DATA_ERROR; 512 if ((int)origPtr >= dbufCount) return RETVAL_DATA_ERROR;
469 bd->writePos = dbuf[origPtr]; 513 tmp = dbuf[origPtr];
470 bd->writeCurrent = (unsigned char)(bd->writePos & 0xff); 514 bd->writeCurrent = (uint8_t)tmp;
471 bd->writePos >>= 8; 515 bd->writePos = (tmp >> 8);
472 bd->writeRunCountdown = 5; 516 bd->writeRunCountdown = 5;
473 } 517 }
474 bd->writeCount = dbufCount; 518 bd->writeCount = dbufCount;
@@ -476,70 +520,84 @@ static int get_next_block(bunzip_data *bd)
476 return RETVAL_OK; 520 return RETVAL_OK;
477} 521}
478 522
479/* Undo burrows-wheeler transform on intermediate buffer to produce output. 523/* Undo Burrows-Wheeler transform on intermediate buffer to produce output.
480 If start_bunzip was initialized with out_fd=-1, then up to len bytes of 524 If start_bunzip was initialized with out_fd=-1, then up to len bytes of
481 data are written to outbuf. Return value is number of bytes written or 525 data are written to outbuf. Return value is number of bytes written or
482 error (all errors are negative numbers). If out_fd!=-1, outbuf and len 526 error (all errors are negative numbers). If out_fd!=-1, outbuf and len
483 are ignored, data is written to out_fd and return is RETVAL_OK or error. 527 are ignored, data is written to out_fd and return is RETVAL_OK or error.
528
529 NB: read_bunzip returns < 0 on error, or the number of *unfilled* bytes
530 in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0.
531 (Why? This allows to get rid of one local variable)
484*/ 532*/
485int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) 533int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len)
486{ 534{
487 const unsigned *dbuf; 535 const uint32_t *dbuf;
488 int pos, current, previous, gotcount; 536 int pos, current, previous;
537 uint32_t CRC;
489 538
490 /* If last read was short due to end of file, return last block now */ 539 /* If we already have error/end indicator, return it */
491 if (bd->writeCount < 0) return bd->writeCount; 540 if (bd->writeCount < 0)
541 return bd->writeCount;
492 542
493 gotcount = 0;
494 dbuf = bd->dbuf; 543 dbuf = bd->dbuf;
544
545 /* Register-cached state (hopefully): */
495 pos = bd->writePos; 546 pos = bd->writePos;
496 current = bd->writeCurrent; 547 current = bd->writeCurrent;
548 CRC = bd->writeCRC; /* small loss on x86-32 (not enough regs), win on x86-64 */
497 549
498 /* We will always have pending decoded data to write into the output 550 /* We will always have pending decoded data to write into the output
499 buffer unless this is the very first call (in which case we haven't 551 buffer unless this is the very first call (in which case we haven't
500 Huffman-decoded a block into the intermediate buffer yet). */ 552 Huffman-decoded a block into the intermediate buffer yet). */
501 if (bd->writeCopies) { 553 if (bd->writeCopies) {
502 554
555 dec_writeCopies:
503 /* Inside the loop, writeCopies means extra copies (beyond 1) */ 556 /* Inside the loop, writeCopies means extra copies (beyond 1) */
504 --bd->writeCopies; 557 --bd->writeCopies;
505 558
506 /* Loop outputting bytes */ 559 /* Loop outputting bytes */
507 for (;;) { 560 for (;;) {
508 561
509 /* If the output buffer is full, snapshot state and return */ 562 /* If the output buffer is full, save cached state and return */
510 if (gotcount >= len) { 563 if (--len < 0) {
511 bd->writePos = pos; 564 /* Unlikely branch.
512 bd->writeCurrent = current; 565 * Use of "goto" instead of keeping code here
513 bd->writeCopies++; 566 * helps compiler to realize this. */
514 return len; 567 goto outbuf_full;
515 } 568 }
516 569
517 /* Write next byte into output buffer, updating CRC */ 570 /* Write next byte into output buffer, updating CRC */
518 outbuf[gotcount++] = current; 571 *outbuf++ = current;
519 bd->writeCRC = (bd->writeCRC << 8) 572 CRC = (CRC << 8) ^ bd->crc32Table[(CRC >> 24) ^ current];
520 ^ bd->crc32Table[(bd->writeCRC >> 24) ^ current];
521 573
522 /* Loop now if we're outputting multiple copies of this byte */ 574 /* Loop now if we're outputting multiple copies of this byte */
523 if (bd->writeCopies) { 575 if (bd->writeCopies) {
524 --bd->writeCopies; 576 /* Unlikely branch */
525 continue; 577 /*--bd->writeCopies;*/
578 /*continue;*/
579 /* Same, but (ab)using other existing --writeCopies operation
580 * (and this if() compiles into just test+branch pair): */
581 goto dec_writeCopies;
526 } 582 }
527 decode_next_byte: 583 decode_next_byte:
528 if (!bd->writeCount--) break; 584 if (--bd->writeCount < 0)
585 break; /* input block is fully consumed, need next one */
586
529 /* Follow sequence vector to undo Burrows-Wheeler transform */ 587 /* Follow sequence vector to undo Burrows-Wheeler transform */
530 previous = current; 588 previous = current;
531 pos = dbuf[pos]; 589 pos = dbuf[pos];
532 current = pos & 0xff; 590 current = (uint8_t)pos;
533 pos >>= 8; 591 pos >>= 8;
534 592
535 /* After 3 consecutive copies of the same byte, the 4th 593 /* After 3 consecutive copies of the same byte, the 4th
536 * is a repeat count. We count down from 4 instead 594 * is a repeat count. We count down from 4 instead
537 * of counting up because testing for non-zero is faster */ 595 * of counting up because testing for non-zero is faster */
538 if (--bd->writeRunCountdown) { 596 if (--bd->writeRunCountdown != 0) {
539 if (current != previous) 597 if (current != previous)
540 bd->writeRunCountdown = 4; 598 bd->writeRunCountdown = 4;
541 } else { 599 } else {
542 600 /* Unlikely branch */
543 /* We have a repeated run, this byte indicates the count */ 601 /* We have a repeated run, this byte indicates the count */
544 bd->writeCopies = current; 602 bd->writeCopies = current;
545 current = previous; 603 current = previous;
@@ -551,30 +609,42 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len)
551 /* Subtract the 1 copy we'd output anyway to get extras */ 609 /* Subtract the 1 copy we'd output anyway to get extras */
552 --bd->writeCopies; 610 --bd->writeCopies;
553 } 611 }
554 } 612 } /* for(;;) */
555 613
556 /* Decompression of this block completed successfully */ 614 /* Decompression of this input block completed successfully */
557 bd->writeCRC = ~bd->writeCRC; 615 bd->writeCRC = CRC = ~CRC;
558 bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ bd->writeCRC; 616 bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ CRC;
559 617
560 /* If this block had a CRC error, force file level CRC error. */ 618 /* If this block had a CRC error, force file level CRC error */
561 if (bd->writeCRC != bd->headerCRC) { 619 if (CRC != bd->headerCRC) {
562 bd->totalCRC = bd->headerCRC + 1; 620 bd->totalCRC = bd->headerCRC + 1;
563 return RETVAL_LAST_BLOCK; 621 return RETVAL_LAST_BLOCK;
564 } 622 }
565 } 623 }
566 624
567 /* Refill the intermediate buffer by Huffman-decoding next block of input */ 625 /* Refill the intermediate buffer by Huffman-decoding next block of input */
568 /* (previous is just a convenient unused temp variable here) */ 626 {
569 previous = get_next_block(bd); 627 int r = get_next_block(bd);
570 if (previous) { 628 if (r) { /* error/end */
571 bd->writeCount = previous; 629 bd->writeCount = r;
572 return (previous != RETVAL_LAST_BLOCK) ? previous : gotcount; 630 return (r != RETVAL_LAST_BLOCK) ? r : len;
631 }
573 } 632 }
574 bd->writeCRC = ~0; 633
634 CRC = ~0;
575 pos = bd->writePos; 635 pos = bd->writePos;
576 current = bd->writeCurrent; 636 current = bd->writeCurrent;
577 goto decode_next_byte; 637 goto decode_next_byte;
638
639 outbuf_full:
640 /* Output buffer is full, save cached state and return */
641 bd->writePos = pos;
642 bd->writeCurrent = current;
643 bd->writeCRC = CRC;
644
645 bd->writeCopies++;
646
647 return 0;
578} 648}
579 649
580/* Allocate the structure, read file header. If in_fd==-1, inbuf must contain 650/* Allocate the structure, read file header. If in_fd==-1, inbuf must contain
@@ -584,8 +654,8 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len)
584/* Because bunzip2 is used for help text unpacking, and because bb_show_usage() 654/* Because bunzip2 is used for help text unpacking, and because bb_show_usage()
585 should work for NOFORK applets too, we must be extremely careful to not leak 655 should work for NOFORK applets too, we must be extremely careful to not leak
586 any allocations! */ 656 any allocations! */
587int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *inbuf, 657int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd,
588 int len) 658 const void *inbuf, int len)
589{ 659{
590 bunzip_data *bd; 660 bunzip_data *bd;
591 unsigned i; 661 unsigned i;
@@ -606,9 +676,11 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *in
606 if (-1 == in_fd) { 676 if (-1 == in_fd) {
607 /* in this case, bd->inbuf is read-only */ 677 /* in this case, bd->inbuf is read-only */
608 bd->inbuf = (void*)inbuf; /* cast away const-ness */ 678 bd->inbuf = (void*)inbuf; /* cast away const-ness */
609 bd->inbufCount = len; 679 } else {
610 } else 680 bd->inbuf = (uint8_t*)(bd + 1);
611 bd->inbuf = (unsigned char *)(bd + 1); 681 memcpy(bd->inbuf, inbuf, len);
682 }
683 bd->inbufCount = len;
612 684
613 /* Init the CRC32 table (big endian) */ 685 /* Init the CRC32 table (big endian) */
614 crc32_filltable(bd->crc32Table, 1); 686 crc32_filltable(bd->crc32Table, 1);
@@ -632,7 +704,7 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *in
632 bd->dbufSize = 100000 * (i - h0); 704 bd->dbufSize = 100000 * (i - h0);
633 705
634 /* Cannot use xmalloc - may leak bd in NOFORK case! */ 706 /* Cannot use xmalloc - may leak bd in NOFORK case! */
635 bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(int)); 707 bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(bd->dbuf[0]));
636 if (!bd->dbuf) { 708 if (!bd->dbuf) {
637 free(bd); 709 free(bd);
638 xfunc_die(); 710 xfunc_die();
@@ -652,37 +724,63 @@ IF_DESKTOP(long long) int FAST_FUNC
652unpack_bz2_stream(int src_fd, int dst_fd) 724unpack_bz2_stream(int src_fd, int dst_fd)
653{ 725{
654 IF_DESKTOP(long long total_written = 0;) 726 IF_DESKTOP(long long total_written = 0;)
655 char *outbuf;
656 bunzip_data *bd; 727 bunzip_data *bd;
728 char *outbuf;
657 int i; 729 int i;
730 unsigned len;
658 731
659 outbuf = xmalloc(IOBUF_SIZE); 732 outbuf = xmalloc(IOBUF_SIZE);
660 i = start_bunzip(&bd, src_fd, NULL, 0); 733 len = 0;
661 if (!i) { 734 while (1) { /* "Process one BZ... stream" loop */
662 for (;;) { 735
663 i = read_bunzip(bd, outbuf, IOBUF_SIZE); 736 i = start_bunzip(&bd, src_fd, outbuf + 2, len);
664 if (i <= 0) break; 737
665 if (i != full_write(dst_fd, outbuf, i)) { 738 if (i == 0) {
666 i = RETVAL_SHORT_WRITE; 739 while (1) { /* "Produce some output bytes" loop */
667 break; 740 i = read_bunzip(bd, outbuf, IOBUF_SIZE);
741 if (i < 0) /* error? */
742 break;
743 i = IOBUF_SIZE - i; /* number of bytes produced */
744 if (i == 0) /* EOF? */
745 break;
746 if (i != full_write(dst_fd, outbuf, i)) {
747 bb_error_msg("short write");
748 i = RETVAL_SHORT_WRITE;
749 goto release_mem;
750 }
751 IF_DESKTOP(total_written += i;)
668 } 752 }
669 IF_DESKTOP(total_written += i;)
670 } 753 }
671 }
672
673 /* Check CRC and release memory */
674 754
675 if (i == RETVAL_LAST_BLOCK) { 755 if (i != RETVAL_LAST_BLOCK) {
756 bb_error_msg("bunzip error %d", i);
757 break;
758 }
676 if (bd->headerCRC != bd->totalCRC) { 759 if (bd->headerCRC != bd->totalCRC) {
677 bb_error_msg("CRC error"); 760 bb_error_msg("CRC error");
678 } else { 761 break;
679 i = RETVAL_OK;
680 } 762 }
681 } else if (i == RETVAL_SHORT_WRITE) { 763
682 bb_error_msg("short write"); 764 /* Successfully unpacked one BZ stream */
683 } else { 765 i = RETVAL_OK;
684 bb_error_msg("bunzip error %d", i); 766
767 /* Do we have "BZ..." after last processed byte?
768 * pbzip2 (parallelized bzip2) produces such files.
769 */
770 len = bd->inbufCount - bd->inbufPos;
771 memcpy(outbuf, &bd->inbuf[bd->inbufPos], len);
772 if (len < 2) {
773 if (safe_read(src_fd, outbuf + len, 2 - len) != 2 - len)
774 break;
775 len = 2;
776 }
777 if (*(uint16_t*)outbuf != BZIP2_MAGIC) /* "BZ"? */
778 break;
779 dealloc_bunzip(bd);
780 len -= 2;
685 } 781 }
782
783 release_mem:
686 dealloc_bunzip(bd); 784 dealloc_bunzip(bd);
687 free(outbuf); 785 free(outbuf);
688 786
diff --git a/archival/libunarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c
index 285b4efeb..44d894244 100644
--- a/archival/libunarchive/decompress_uncompress.c
+++ b/archival/libarchive/decompress_uncompress.c
@@ -25,7 +25,7 @@
25 */ 25 */
26 26
27#include "libbb.h" 27#include "libbb.h"
28#include "unarchive.h" 28#include "archive.h"
29 29
30 30
31/* Default input buffer size */ 31/* Default input buffer size */
diff --git a/archival/libunarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c
index 1a3a8f86b..a04714341 100644
--- a/archival/libunarchive/decompress_unlzma.c
+++ b/archival/libarchive/decompress_unlzma.c
@@ -9,7 +9,7 @@
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#include "libbb.h" 11#include "libbb.h"
12#include "unarchive.h" 12#include "archive.h"
13 13
14#if ENABLE_FEATURE_LZMA_FAST 14#if ENABLE_FEATURE_LZMA_FAST
15# define speed_inline ALWAYS_INLINE 15# define speed_inline ALWAYS_INLINE
diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c
index ca427231e..e90dfb06f 100644
--- a/archival/libunarchive/decompress_unxz.c
+++ b/archival/libarchive/decompress_unxz.c
@@ -10,7 +10,7 @@
10 * Licensed under GPLv2, see file LICENSE in this source tree. 10 * Licensed under GPLv2, see file LICENSE in this source tree.
11 */ 11 */
12#include "libbb.h" 12#include "libbb.h"
13#include "unarchive.h" 13#include "archive.h"
14 14
15#define XZ_FUNC FAST_FUNC 15#define XZ_FUNC FAST_FUNC
16#define XZ_EXTERN static 16#define XZ_EXTERN static
diff --git a/archival/libunarchive/decompress_unzip.c b/archival/libarchive/decompress_unzip.c
index cb8a3d737..a29eef837 100644
--- a/archival/libunarchive/decompress_unzip.c
+++ b/archival/libarchive/decompress_unzip.c
@@ -35,7 +35,7 @@
35 35
36#include <setjmp.h> 36#include <setjmp.h>
37#include "libbb.h" 37#include "libbb.h"
38#include "unarchive.h" 38#include "archive.h"
39 39
40typedef struct huft_t { 40typedef struct huft_t {
41 unsigned char e; /* number of extra bits or operation */ 41 unsigned char e; /* number of extra bits or operation */
diff --git a/archival/libunarchive/filter_accept_all.c b/archival/libarchive/filter_accept_all.c
index cb1f506c8..e69deb679 100644
--- a/archival/libunarchive/filter_accept_all.c
+++ b/archival/libarchive/filter_accept_all.c
@@ -6,7 +6,7 @@
6 */ 6 */
7 7
8#include "libbb.h" 8#include "libbb.h"
9#include "unarchive.h" 9#include "archive.h"
10 10
11/* Accept any non-null name, its not really a filter at all */ 11/* Accept any non-null name, its not really a filter at all */
12char FAST_FUNC filter_accept_all(archive_handle_t *archive_handle) 12char FAST_FUNC filter_accept_all(archive_handle_t *archive_handle)
diff --git a/archival/libunarchive/filter_accept_list.c b/archival/libarchive/filter_accept_list.c
index fe4414c85..a7640af79 100644
--- a/archival/libunarchive/filter_accept_list.c
+++ b/archival/libarchive/filter_accept_list.c
@@ -6,7 +6,7 @@
6 */ 6 */
7 7
8#include "libbb.h" 8#include "libbb.h"
9#include "unarchive.h" 9#include "archive.h"
10 10
11/* 11/*
12 * Accept names that are in the accept list, ignoring reject list. 12 * Accept names that are in the accept list, ignoring reject list.
diff --git a/archival/libunarchive/filter_accept_list_reassign.c b/archival/libarchive/filter_accept_list_reassign.c
index 891f58390..d80f71668 100644
--- a/archival/libunarchive/filter_accept_list_reassign.c
+++ b/archival/libarchive/filter_accept_list_reassign.c
@@ -6,7 +6,7 @@
6 */ 6 */
7 7
8#include "libbb.h" 8#include "libbb.h"
9#include "unarchive.h" 9#include "archive.h"
10 10
11/* Built and used only if ENABLE_DPKG || ENABLE_DPKG_DEB */ 11/* Built and used only if ENABLE_DPKG || ENABLE_DPKG_DEB */
12 12
diff --git a/archival/libunarchive/filter_accept_reject_list.c b/archival/libarchive/filter_accept_reject_list.c
index 89a5502d5..3e86cca65 100644
--- a/archival/libunarchive/filter_accept_reject_list.c
+++ b/archival/libarchive/filter_accept_reject_list.c
@@ -6,7 +6,7 @@
6 */ 6 */
7 7
8#include "libbb.h" 8#include "libbb.h"
9#include "unarchive.h" 9#include "archive.h"
10 10
11/* 11/*
12 * Accept names that are in the accept list and not in the reject list 12 * Accept names that are in the accept list and not in the reject list
diff --git a/archival/libunarchive/find_list_entry.c b/archival/libarchive/find_list_entry.c
index 5c0c85f09..5efd1af2e 100644
--- a/archival/libunarchive/find_list_entry.c
+++ b/archival/libarchive/find_list_entry.c
@@ -7,7 +7,7 @@
7 7
8#include <fnmatch.h> 8#include <fnmatch.h>
9#include "libbb.h" 9#include "libbb.h"
10#include "unarchive.h" 10#include "archive.h"
11 11
12/* Find a string in a shell pattern list */ 12/* Find a string in a shell pattern list */
13const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename) 13const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename)
diff --git a/archival/libunarchive/get_header_ar.c b/archival/libarchive/get_header_ar.c
index 6bfc6bc27..df603b111 100644
--- a/archival/libunarchive/get_header_ar.c
+++ b/archival/libarchive/get_header_ar.c
@@ -5,7 +5,7 @@
5 */ 5 */
6 6
7#include "libbb.h" 7#include "libbb.h"
8#include "unarchive.h" 8#include "archive.h"
9#include "ar.h" 9#include "ar.h"
10 10
11static unsigned read_num(const char *str, int base) 11static unsigned read_num(const char *str, int base)
diff --git a/archival/libunarchive/get_header_cpio.c b/archival/libarchive/get_header_cpio.c
index 8cd1096ba..3d99b492a 100644
--- a/archival/libunarchive/get_header_cpio.c
+++ b/archival/libarchive/get_header_cpio.c
@@ -5,7 +5,7 @@
5 */ 5 */
6 6
7#include "libbb.h" 7#include "libbb.h"
8#include "unarchive.h" 8#include "archive.h"
9 9
10typedef struct hardlinks_t { 10typedef struct hardlinks_t {
11 struct hardlinks_t *next; 11 struct hardlinks_t *next;
diff --git a/archival/libunarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index cf6487207..78b0ae25f 100644
--- a/archival/libunarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -12,7 +12,7 @@
12 */ 12 */
13 13
14#include "libbb.h" 14#include "libbb.h"
15#include "unarchive.h" 15#include "archive.h"
16 16
17typedef uint32_t aliased_uint32_t FIX_ALIASING; 17typedef uint32_t aliased_uint32_t FIX_ALIASING;
18typedef off_t aliased_off_t FIX_ALIASING; 18typedef off_t aliased_off_t FIX_ALIASING;
diff --git a/archival/libunarchive/get_header_tar_bz2.c b/archival/libarchive/get_header_tar_bz2.c
index 4ffc17086..60d32069f 100644
--- a/archival/libunarchive/get_header_tar_bz2.c
+++ b/archival/libarchive/get_header_tar_bz2.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle) 9char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle)
10{ 10{
diff --git a/archival/libunarchive/get_header_tar_gz.c b/archival/libarchive/get_header_tar_gz.c
index a9af22e0e..b09f8691c 100644
--- a/archival/libunarchive/get_header_tar_gz.c
+++ b/archival/libarchive/get_header_tar_gz.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) 9char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle)
10{ 10{
diff --git a/archival/libunarchive/get_header_tar_lzma.c b/archival/libarchive/get_header_tar_lzma.c
index 9876b3827..da08e0c72 100644
--- a/archival/libunarchive/get_header_tar_lzma.c
+++ b/archival/libarchive/get_header_tar_lzma.c
@@ -7,7 +7,7 @@
7 */ 7 */
8 8
9#include "libbb.h" 9#include "libbb.h"
10#include "unarchive.h" 10#include "archive.h"
11 11
12char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle) 12char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle)
13{ 13{
diff --git a/archival/libunarchive/header_list.c b/archival/libarchive/header_list.c
index 902d6ebe0..c4fc75f38 100644
--- a/archival/libunarchive/header_list.c
+++ b/archival/libarchive/header_list.c
@@ -3,7 +3,7 @@
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */ 4 */
5#include "libbb.h" 5#include "libbb.h"
6#include "unarchive.h" 6#include "archive.h"
7 7
8void FAST_FUNC header_list(const file_header_t *file_header) 8void FAST_FUNC header_list(const file_header_t *file_header)
9{ 9{
diff --git a/archival/libunarchive/header_skip.c b/archival/libarchive/header_skip.c
index 2af36ac9c..2bfc5253c 100644
--- a/archival/libunarchive/header_skip.c
+++ b/archival/libarchive/header_skip.c
@@ -3,7 +3,7 @@
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */ 4 */
5#include "libbb.h" 5#include "libbb.h"
6#include "unarchive.h" 6#include "archive.h"
7 7
8void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM) 8void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM)
9{ 9{
diff --git a/archival/libunarchive/header_verbose_list.c b/archival/libarchive/header_verbose_list.c
index d863e6a29..bc4e4154b 100644
--- a/archival/libunarchive/header_verbose_list.c
+++ b/archival/libarchive/header_verbose_list.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9void FAST_FUNC header_verbose_list(const file_header_t *file_header) 9void FAST_FUNC header_verbose_list(const file_header_t *file_header)
10{ 10{
diff --git a/archival/libunarchive/init_handle.c b/archival/libarchive/init_handle.c
index de7021f78..6644ea13b 100644
--- a/archival/libunarchive/init_handle.c
+++ b/archival/libarchive/init_handle.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9archive_handle_t* FAST_FUNC init_handle(void) 9archive_handle_t* FAST_FUNC init_handle(void)
10{ 10{
diff --git a/archival/liblzo.h b/archival/libarchive/liblzo.h
index 843997cb9..843997cb9 100644
--- a/archival/liblzo.h
+++ b/archival/libarchive/liblzo.h
diff --git a/archival/lzo1x_1.c b/archival/libarchive/lzo1x_1.c
index a88839846..a88839846 100644
--- a/archival/lzo1x_1.c
+++ b/archival/libarchive/lzo1x_1.c
diff --git a/archival/lzo1x_1o.c b/archival/libarchive/lzo1x_1o.c
index 3c61253e0..3c61253e0 100644
--- a/archival/lzo1x_1o.c
+++ b/archival/libarchive/lzo1x_1o.c
diff --git a/archival/lzo1x_9x.c b/archival/libarchive/lzo1x_9x.c
index 483205155..483205155 100644
--- a/archival/lzo1x_9x.c
+++ b/archival/libarchive/lzo1x_9x.c
diff --git a/archival/lzo1x_c.c b/archival/libarchive/lzo1x_c.c
index cc86f74b1..cc86f74b1 100644
--- a/archival/lzo1x_c.c
+++ b/archival/libarchive/lzo1x_c.c
diff --git a/archival/lzo1x_d.c b/archival/libarchive/lzo1x_d.c
index 348a85510..348a85510 100644
--- a/archival/lzo1x_d.c
+++ b/archival/libarchive/lzo1x_d.c
diff --git a/archival/libunarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index ed6a556bb..26ae565f5 100644
--- a/archival/libunarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -4,12 +4,12 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9/* transformer(), more than meets the eye */ 9/* transformer(), more than meets the eye */
10/* 10/*
11 * On MMU machine, the transform_prog is removed by macro magic 11 * On MMU machine, the transform_prog is removed by macro magic
12 * in include/unarchive.h. On NOMMU, transformer is removed. 12 * in include/archive.h. On NOMMU, transformer is removed.
13 */ 13 */
14void FAST_FUNC open_transformer(int fd, 14void FAST_FUNC open_transformer(int fd,
15 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd), 15 IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd),
diff --git a/archival/libunarchive/seek_by_jump.c b/archival/libarchive/seek_by_jump.c
index bda55e1b1..7c2c52ae1 100644
--- a/archival/libunarchive/seek_by_jump.c
+++ b/archival/libarchive/seek_by_jump.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9void FAST_FUNC seek_by_jump(int fd, off_t amount) 9void FAST_FUNC seek_by_jump(int fd, off_t amount)
10{ 10{
diff --git a/archival/libunarchive/seek_by_read.c b/archival/libarchive/seek_by_read.c
index 25b31365d..ad931a8de 100644
--- a/archival/libunarchive/seek_by_read.c
+++ b/archival/libarchive/seek_by_read.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8 8
9/* If we are reading through a pipe, or from stdin then we can't lseek, 9/* If we are reading through a pipe, or from stdin then we can't lseek,
10 * we must read and discard the data to skip over it. 10 * we must read and discard the data to skip over it.
diff --git a/archival/libunarchive/unpack_ar_archive.c b/archival/libarchive/unpack_ar_archive.c
index 4f68ba3d8..18dbfd54d 100644
--- a/archival/libunarchive/unpack_ar_archive.c
+++ b/archival/libarchive/unpack_ar_archive.c
@@ -4,7 +4,7 @@
4 */ 4 */
5 5
6#include "libbb.h" 6#include "libbb.h"
7#include "unarchive.h" 7#include "archive.h"
8#include "ar.h" 8#include "ar.h"
9 9
10void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive) 10void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive)
diff --git a/archival/libunarchive/unxz/README b/archival/libarchive/unxz/README
index c5972f6b8..c5972f6b8 100644
--- a/archival/libunarchive/unxz/README
+++ b/archival/libarchive/unxz/README
diff --git a/archival/libunarchive/unxz/xz.h b/archival/libarchive/unxz/xz.h
index c6c071c4a..c6c071c4a 100644
--- a/archival/libunarchive/unxz/xz.h
+++ b/archival/libarchive/unxz/xz.h
diff --git a/archival/libunarchive/unxz/xz_config.h b/archival/libarchive/unxz/xz_config.h
index 187e1cbed..187e1cbed 100644
--- a/archival/libunarchive/unxz/xz_config.h
+++ b/archival/libarchive/unxz/xz_config.h
diff --git a/archival/libunarchive/unxz/xz_dec_bcj.c b/archival/libarchive/unxz/xz_dec_bcj.c
index 09162b51f..09162b51f 100644
--- a/archival/libunarchive/unxz/xz_dec_bcj.c
+++ b/archival/libarchive/unxz/xz_dec_bcj.c
diff --git a/archival/libunarchive/unxz/xz_dec_lzma2.c b/archival/libarchive/unxz/xz_dec_lzma2.c
index da71cb4d4..da71cb4d4 100644
--- a/archival/libunarchive/unxz/xz_dec_lzma2.c
+++ b/archival/libarchive/unxz/xz_dec_lzma2.c
diff --git a/archival/libunarchive/unxz/xz_dec_stream.c b/archival/libarchive/unxz/xz_dec_stream.c
index bdcbf1ba3..bdcbf1ba3 100644
--- a/archival/libunarchive/unxz/xz_dec_stream.c
+++ b/archival/libarchive/unxz/xz_dec_stream.c
diff --git a/archival/libunarchive/unxz/xz_lzma2.h b/archival/libarchive/unxz/xz_lzma2.h
index 47f21afbc..47f21afbc 100644
--- a/archival/libunarchive/unxz/xz_lzma2.h
+++ b/archival/libarchive/unxz/xz_lzma2.h
diff --git a/archival/libunarchive/unxz/xz_private.h b/archival/libarchive/unxz/xz_private.h
index 145649a83..145649a83 100644
--- a/archival/libunarchive/unxz/xz_private.h
+++ b/archival/libarchive/unxz/xz_private.h
diff --git a/archival/libunarchive/unxz/xz_stream.h b/archival/libarchive/unxz/xz_stream.h
index 36f2a7cbf..36f2a7cbf 100644
--- a/archival/libunarchive/unxz/xz_stream.h
+++ b/archival/libarchive/unxz/xz_stream.h
diff --git a/archival/lzop.c b/archival/lzop.c
index acb34fe14..094e78cf9 100644
--- a/archival/lzop.c
+++ b/archival/lzop.c
@@ -26,7 +26,7 @@
26*/ 26*/
27 27
28#include "libbb.h" 28#include "libbb.h"
29#include "unarchive.h" 29#include "archive.h"
30#include "liblzo_interface.h" 30#include "liblzo_interface.h"
31 31
32/* lzo-2.03/src/lzo_ptr.h */ 32/* lzo-2.03/src/lzo_ptr.h */
diff --git a/archival/rpm.c b/archival/rpm.c
index 7b316a5b8..380226f9b 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -8,7 +8,7 @@
8 */ 8 */
9 9
10#include "libbb.h" 10#include "libbb.h"
11#include "unarchive.h" 11#include "archive.h"
12#include "rpm.h" 12#include "rpm.h"
13 13
14#define RPM_CHAR_TYPE 1 14#define RPM_CHAR_TYPE 1
diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c
index 70021d539..ce8cd2c2c 100644
--- a/archival/rpm2cpio.c
+++ b/archival/rpm2cpio.c
@@ -7,7 +7,7 @@
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10#include "unarchive.h" 10#include "archive.h"
11#include "rpm.h" 11#include "rpm.h"
12 12
13enum { rpm_fd = STDIN_FILENO }; 13enum { rpm_fd = STDIN_FILENO };
diff --git a/archival/tar.c b/archival/tar.c
index 1d6e63da0..150c6f393 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -23,9 +23,28 @@
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 25
26/* TODO: security with -C DESTDIR option can be enhanced.
27 * Consider tar file created via:
28 * $ tar cvf bug.tar anything.txt
29 * $ ln -s /tmp symlink
30 * $ tar --append -f bug.tar symlink
31 * $ rm symlink
32 * $ mkdir symlink
33 * $ tar --append -f bug.tar symlink/evil.py
34 *
35 * This will result in an archive which contains:
36 * $ tar --list -f bug.tar
37 * anything.txt
38 * symlink
39 * symlink/evil.py
40 *
41 * Untarring it puts evil.py in '/tmp' even if the -C DESTDIR is given.
42 * This doesn't feel right, and IIRC GNU tar doesn't do that.
43 */
44
26#include <fnmatch.h> 45#include <fnmatch.h>
27#include "libbb.h" 46#include "libbb.h"
28#include "unarchive.h" 47#include "archive.h"
29/* FIXME: Stop using this non-standard feature */ 48/* FIXME: Stop using this non-standard feature */
30#ifndef FNM_LEADING_DIR 49#ifndef FNM_LEADING_DIR
31# define FNM_LEADING_DIR 0 50# define FNM_LEADING_DIR 0
@@ -884,7 +903,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
884 /* Prepend '-' to the first argument if required */ 903 /* Prepend '-' to the first argument if required */
885 opt_complementary = "--:" // first arg is options 904 opt_complementary = "--:" // first arg is options
886 "tt:vv:" // count -t,-v 905 "tt:vv:" // count -t,-v
887 "?:" // bail out with usage instead of error return
888 "X::T::" // cumulative lists 906 "X::T::" // cumulative lists
889#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM 907#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
890 "\xff::" // cumulative lists for --exclude 908 "\xff::" // cumulative lists for --exclude
diff --git a/archival/unzip.c b/archival/unzip.c
index 204e34952..5d62c08cb 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -20,7 +20,7 @@
20 */ 20 */
21 21
22#include "libbb.h" 22#include "libbb.h"
23#include "unarchive.h" 23#include "archive.h"
24 24
25enum { 25enum {
26#if BB_BIG_ENDIAN 26#if BB_BIG_ENDIAN
diff --git a/console-tools/kbd_mode.c b/console-tools/kbd_mode.c
index 14f2ae516..1481d0dbb 100644
--- a/console-tools/kbd_mode.c
+++ b/console-tools/kbd_mode.c
@@ -16,9 +16,9 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv)
16{ 16{
17 enum { 17 enum {
18 SCANCODE = (1 << 0), 18 SCANCODE = (1 << 0),
19 ASCII = (1 << 1), 19 ASCII = (1 << 1),
20 MEDIUMRAW = (1 << 2), 20 MEDIUMRAW = (1 << 2),
21 UNICODE = (1 << 3), 21 UNICODE = (1 << 3),
22 }; 22 };
23 int fd; 23 int fd;
24 unsigned opt; 24 unsigned opt;
diff --git a/console-tools/loadfont.c b/console-tools/loadfont.c
index 3c77813b5..079626c20 100644
--- a/console-tools/loadfont.c
+++ b/console-tools/loadfont.c
@@ -136,7 +136,7 @@ static void do_loadfont(int fd, unsigned char *inbuf, int height, int width, int
136 * Example: 136 * Example:
137 * At the font position for a capital A-ring glyph, we 137 * At the font position for a capital A-ring glyph, we
138 * may have: 138 * may have:
139 * 00C5,212B,FFFE,0041,030A,FFFF 139 * 00C5,212B,FFFE,0041,030A,FFFF
140 * Some font positions may be described by sequences only, 140 * Some font positions may be described by sequences only,
141 * namely when there is no precomposed Unicode value for the glyph. 141 * namely when there is no precomposed Unicode value for the glyph.
142 */ 142 */
@@ -159,7 +159,7 @@ static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize,
159 int glyph; 159 int glyph;
160 uint16_t unicode; 160 uint16_t unicode;
161 161
162 maxct = tailsz; /* more than enough */ 162 maxct = tailsz; /* more than enough */
163 up = xmalloc(maxct * sizeof(*up)); 163 up = xmalloc(maxct * sizeof(*up));
164 164
165 for (glyph = 0; glyph < fontsize; glyph++) { 165 for (glyph = 0; glyph < fontsize; glyph++) {
@@ -255,10 +255,10 @@ static void do_load(int fd, unsigned char *buffer, size_t len)
255 } else 255 } else
256#endif 256#endif
257#if ENABLE_FEATURE_LOADFONT_RAW 257#if ENABLE_FEATURE_LOADFONT_RAW
258 if (len == 9780) { /* file with three code pages? */ 258 if (len == 9780) { /* file with three code pages? */
259 charsize = height = 16; 259 charsize = height = 16;
260 font += 40; 260 font += 40;
261 } else if ((len & 0377) == 0) { /* bare font */ 261 } else if ((len & 0377) == 0) { /* bare font */
262 charsize = height = len / 256; 262 charsize = height = len / 256;
263 } else 263 } else
264#endif 264#endif
diff --git a/console-tools/reset.c b/console-tools/reset.c
index 7dffdea18..1806ce742 100644
--- a/console-tools/reset.c
+++ b/console-tools/reset.c
@@ -8,11 +8,13 @@
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */ 9 */
10 10
11#include "libbb.h"
12
13/* BTW, which "standard" package has this utility? It doesn't seem 11/* BTW, which "standard" package has this utility? It doesn't seem
14 * to be ncurses, coreutils, console-tools... then what? */ 12 * to be ncurses, coreutils, console-tools... then what? */
15 13
14#include "libbb.h"
15
16#define ESC "\033"
17
16#if ENABLE_STTY 18#if ENABLE_STTY
17int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 19int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
18#endif 20#endif
@@ -26,15 +28,15 @@ int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
26 28
27 /* no options, no getopt */ 29 /* no options, no getopt */
28 30
29 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 31 if (/*isatty(STDIN_FILENO) &&*/ isatty(STDOUT_FILENO)) {
30 /* See 'man 4 console_codes' for details: 32 /* See 'man 4 console_codes' for details:
31 * "ESC c" -- Reset 33 * "ESC c" -- Reset
32 * "ESC ( K" -- Select user mapping 34 * "ESC ( K" -- Select user mapping
33 * "ESC [ J" -- Erase to the end of screen
34 * "ESC [ 0 m" -- Reset all display attributes 35 * "ESC [ 0 m" -- Reset all display attributes
36 * "ESC [ J" -- Erase to the end of screen
35 * "ESC [ ? 25 h" -- Make cursor visible 37 * "ESC [ ? 25 h" -- Make cursor visible
36 */ 38 */
37 printf("\033c\033(K\033[J\033[0m\033[?25h"); 39 printf(ESC"c" ESC"(K" ESC"[0m" ESC"[J" ESC"[?25h");
38 /* http://bugs.busybox.net/view.php?id=1414: 40 /* http://bugs.busybox.net/view.php?id=1414:
39 * people want it to reset echo etc: */ 41 * people want it to reset echo etc: */
40#if ENABLE_STTY 42#if ENABLE_STTY
diff --git a/console-tools/resize.c b/console-tools/resize.c
index 12e50a116..fdfe2a6a0 100644
--- a/console-tools/resize.c
+++ b/console-tools/resize.c
@@ -17,7 +17,7 @@ static void
17onintr(int sig UNUSED_PARAM) 17onintr(int sig UNUSED_PARAM)
18{ 18{
19 tcsetattr(STDERR_FILENO, TCSANOW, old_termios_p); 19 tcsetattr(STDERR_FILENO, TCSANOW, old_termios_p);
20 exit(EXIT_FAILURE); 20 _exit(EXIT_FAILURE);
21} 21}
22 22
23int resize_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 23int resize_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
diff --git a/console-tools/showkey.c b/console-tools/showkey.c
index 149ea6465..e7834f702 100644
--- a/console-tools/showkey.c
+++ b/console-tools/showkey.c
@@ -10,6 +10,20 @@
10#include "libbb.h" 10#include "libbb.h"
11#include <linux/kd.h> 11#include <linux/kd.h>
12 12
13
14struct globals {
15 int kbmode;
16 struct termios tio, tio0;
17};
18#define G (*ptr_to_globals)
19#define kbmode (G.kbmode)
20#define tio (G.tio)
21#define tio0 (G.tio0)
22#define INIT_G() do { \
23 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
24} while (0)
25
26
13// set raw tty mode 27// set raw tty mode
14// also used by microcom 28// also used by microcom
15// libbb candidates? 29// libbb candidates?
@@ -20,62 +34,38 @@ static void xget1(struct termios *t, struct termios *oldt)
20 cfmakeraw(t); 34 cfmakeraw(t);
21} 35}
22 36
23static void xset1(struct termios *tio) 37static void xset1(struct termios *t)
24{ 38{
25 int ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, tio); 39 int ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, t);
26 if (ret) { 40 if (ret) {
27 bb_perror_msg("can't tcsetattr for stdin"); 41 bb_perror_msg("can't tcsetattr for stdin");
28 } 42 }
29} 43}
30 44
31/*
32 * GLOBALS
33 */
34struct globals {
35 int kbmode;
36 struct termios tio, tio0;
37};
38#define G (*ptr_to_globals)
39#define kbmode (G.kbmode)
40#define tio (G.tio)
41#define tio0 (G.tio0)
42#define INIT_G() do { \
43 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
44} while (0)
45
46
47static void signal_handler(int signo)
48{
49 // restore keyboard and console settings
50 xset1(&tio0);
51 xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode);
52 // alarmed? -> exit 0
53 exit(SIGALRM == signo);
54}
55
56int showkey_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 45int showkey_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
57int showkey_main(int argc UNUSED_PARAM, char **argv) 46int showkey_main(int argc UNUSED_PARAM, char **argv)
58{ 47{
59 enum { 48 enum {
60 OPT_a = (1<<0), // display the decimal/octal/hex values of the keys 49 OPT_a = (1<<0), // display the decimal/octal/hex values of the keys
61 OPT_k = (1<<1), // display only the interpreted keycodes (default) 50 OPT_k = (1<<1), // display only the interpreted keycodes (default)
62 OPT_s = (1<<2), // display only the raw scan-codes 51 OPT_s = (1<<2), // display only the raw scan-codes
63 }; 52 };
64 53
54 INIT_G();
55
65 // FIXME: aks are all mutually exclusive 56 // FIXME: aks are all mutually exclusive
66 getopt32(argv, "aks"); 57 getopt32(argv, "aks");
67 58
68 INIT_G();
69
70 // get keyboard settings 59 // get keyboard settings
71 xioctl(STDIN_FILENO, KDGKBMODE, &kbmode); 60 xioctl(STDIN_FILENO, KDGKBMODE, &kbmode);
72 printf("kb mode was %s\n\nPress any keys. Program terminates %s\n\n", 61 printf("kb mode was %s\n\nPress any keys. Program terminates %s\n\n",
73 kbmode == K_RAW ? "RAW" : 62 kbmode == K_RAW ? "RAW" :
74 (kbmode == K_XLATE ? "XLATE" : 63 (kbmode == K_XLATE ? "XLATE" :
75 (kbmode == K_MEDIUMRAW ? "MEDIUMRAW" : 64 (kbmode == K_MEDIUMRAW ? "MEDIUMRAW" :
76 (kbmode == K_UNICODE ? "UNICODE" : "?UNKNOWN?"))) 65 (kbmode == K_UNICODE ? "UNICODE" : "UNKNOWN")))
77 , (option_mask32 & OPT_a) ? "when CTRL+D pressed" : "10s after last keypress" 66 , (option_mask32 & OPT_a) ? "on EOF (ctrl-D)" : "10s after last keypress"
78 ); 67 );
68
79 // prepare for raw mode 69 // prepare for raw mode
80 xget1(&tio, &tio0); 70 xget1(&tio, &tio0);
81 // put stdin in raw mode 71 // put stdin in raw mode
@@ -83,34 +73,37 @@ int showkey_main(int argc UNUSED_PARAM, char **argv)
83 73
84 if (option_mask32 & OPT_a) { 74 if (option_mask32 & OPT_a) {
85 unsigned char c; 75 unsigned char c;
76
86 // just read stdin char by char 77 // just read stdin char by char
87 while (1 == safe_read(STDIN_FILENO, &c, 1)) { 78 while (1 == read(STDIN_FILENO, &c, 1)) {
88 printf("%3u 0%03o 0x%02x\r\n", c, c, c); 79 printf("%3u 0%03o 0x%02x\r\n", c, c, c);
89 if (04 /*CTRL-D*/ == c) 80 if (04 /*CTRL-D*/ == c)
90 break; 81 break;
91 } 82 }
92 } else { 83 } else {
93 // we should exit on any signal
94 bb_signals(BB_FATAL_SIGS, signal_handler);
95 // set raw keyboard mode 84 // set raw keyboard mode
96 xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW)); 85 xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW));
97 86
87 // we should exit on any signal; signals should interrupt read
88 bb_signals_recursive_norestart(BB_FATAL_SIGS, record_signo);
89
98 // read and show scancodes 90 // read and show scancodes
99 while (1) { 91 while (!bb_got_signal) {
100 char buf[18]; 92 char buf[18];
101 int i, n; 93 int i, n;
94
102 // setup 10s watchdog 95 // setup 10s watchdog
103 alarm(10); 96 alarm(10);
104 // read scancodes 97 // read scancodes
105 n = read(STDIN_FILENO, buf, sizeof(buf)); 98 n = read(STDIN_FILENO, buf, sizeof(buf));
106 i = 0; 99 i = 0;
107 while (i < n) { 100 while (i < n) {
108 char c = buf[i];
109 // show raw scancodes ordered? ->
110 if (option_mask32 & OPT_s) { 101 if (option_mask32 & OPT_s) {
102 // show raw scancodes
111 printf("0x%02x ", buf[i++]); 103 printf("0x%02x ", buf[i++]);
112 // show interpreted scancodes (default) ? ->
113 } else { 104 } else {
105 // show interpreted scancodes (default)
106 char c = buf[i];
114 int kc; 107 int kc;
115 if (i+2 < n 108 if (i+2 < n
116 && (c & 0x7f) == 0 109 && (c & 0x7f) == 0
@@ -130,9 +123,9 @@ int showkey_main(int argc UNUSED_PARAM, char **argv)
130 } 123 }
131 } 124 }
132 125
133 // cleanup 126 // restore keyboard and console settings
134 signal_handler(SIGALRM); 127 xset1(&tio0);
128 xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode);
135 129
136 // should never be here!
137 return EXIT_SUCCESS; 130 return EXIT_SUCCESS;
138} 131}
diff --git a/coreutils/Config.src b/coreutils/Config.src
index adad4ba6d..b599f7999 100644
--- a/coreutils/Config.src
+++ b/coreutils/Config.src
@@ -664,13 +664,6 @@ config FEATURE_TEE_USE_BLOCK_IO
664 help 664 help
665 Enable this option for a faster tee, at expense of size. 665 Enable this option for a faster tee, at expense of size.
666 666
667config TOUCH
668 bool "touch"
669 default y
670 help
671 touch is used to create or change the access and/or
672 modification timestamp of specified files.
673
674config TRUE 667config TRUE
675 bool "true" 668 bool "true"
676 default y 669 default y
diff --git a/coreutils/Kbuild.src b/coreutils/Kbuild.src
index 630b048df..4ea0fa50a 100644
--- a/coreutils/Kbuild.src
+++ b/coreutils/Kbuild.src
@@ -74,7 +74,6 @@ lib-$(CONFIG_SYNC) += sync.o
74lib-$(CONFIG_TAC) += tac.o 74lib-$(CONFIG_TAC) += tac.o
75lib-$(CONFIG_TAIL) += tail.o 75lib-$(CONFIG_TAIL) += tail.o
76lib-$(CONFIG_TEE) += tee.o 76lib-$(CONFIG_TEE) += tee.o
77lib-$(CONFIG_TOUCH) += touch.o
78lib-$(CONFIG_TRUE) += true.o 77lib-$(CONFIG_TRUE) += true.o
79lib-$(CONFIG_TTY) += tty.o 78lib-$(CONFIG_TTY) += tty.o
80lib-$(CONFIG_UNAME) += uname.o 79lib-$(CONFIG_UNAME) += uname.o
diff --git a/coreutils/date.c b/coreutils/date.c
index eed4714f9..22d0a5327 100644
--- a/coreutils/date.c
+++ b/coreutils/date.c
@@ -250,6 +250,10 @@ int date_main(int argc UNUSED_PARAM, char **argv)
250 ts.tv_sec = statbuf.st_mtime; 250 ts.tv_sec = statbuf.st_mtime;
251#if ENABLE_FEATURE_DATE_NANO 251#if ENABLE_FEATURE_DATE_NANO
252 ts.tv_nsec = statbuf.st_mtim.tv_nsec; 252 ts.tv_nsec = statbuf.st_mtim.tv_nsec;
253 /* Some toolchains use .st_mtimensec instead of st_mtim.tv_nsec.
254 * If you need #define _SVID_SOURCE 1 to enable st_mtim.tv_nsec,
255 * drop a mail to project mailing list please
256 */
253#endif 257#endif
254 } else { 258 } else {
255#if ENABLE_FEATURE_DATE_NANO 259#if ENABLE_FEATURE_DATE_NANO
@@ -278,7 +282,9 @@ int date_main(int argc UNUSED_PARAM, char **argv)
278 } 282 }
279 283
280 /* Correct any day of week and day of year etc. fields */ 284 /* Correct any day of week and day of year etc. fields */
281 tm_time.tm_isdst = -1; /* Be sure to recheck dst */ 285 /* Be sure to recheck dst (but not if date is time_t format) */
286 if (date_str[0] != '@')
287 tm_time.tm_isdst = -1;
282 ts.tv_sec = validate_tm_time(date_str, &tm_time); 288 ts.tv_sec = validate_tm_time(date_str, &tm_time);
283 289
284 maybe_set_utc(opt); 290 maybe_set_utc(opt);
diff --git a/coreutils/dd.c b/coreutils/dd.c
index c22a39da7..da205ec69 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -24,7 +24,7 @@ static const struct suffix_mult dd_suffixes[] = {
24 { "b", 512 }, 24 { "b", 512 },
25 { "kD", 1000 }, 25 { "kD", 1000 },
26 { "k", 1024 }, 26 { "k", 1024 },
27 { "K", 1024 }, /* compat with coreutils dd */ 27 { "K", 1024 }, /* compat with coreutils dd */
28 { "MD", 1000000 }, 28 { "MD", 1000000 },
29 { "M", 1048576 }, 29 { "M", 1048576 },
30 { "GD", 1000000000 }, 30 { "GD", 1000000000 },
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 1a670201c..1afe28c8d 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -29,6 +29,71 @@
29 * [2009-03] 29 * [2009-03]
30 * ls sorts listing now, and supports almost all options. 30 * ls sorts listing now, and supports almost all options.
31 */ 31 */
32
33//usage:#define ls_trivial_usage
34//usage: "[-1AaCxd"
35//usage: IF_FEATURE_LS_FOLLOWLINKS("LH")
36//usage: IF_FEATURE_LS_RECURSIVE("R")
37//usage: IF_FEATURE_LS_FILETYPES("Fp") "lins"
38//usage: IF_FEATURE_LS_TIMESTAMPS("e")
39//usage: IF_FEATURE_HUMAN_READABLE("h")
40//usage: IF_FEATURE_LS_SORTFILES("rSXv")
41//usage: IF_FEATURE_LS_TIMESTAMPS("ctu")
42//usage: IF_SELINUX("kKZ") "]"
43//usage: IF_FEATURE_AUTOWIDTH(" -w WIDTH") " [FILE]..."
44//usage:#define ls_full_usage "\n\n"
45//usage: "List directory contents\n"
46//usage: "\nOptions:"
47//usage: "\n -1 List in a single column"
48//usage: "\n -A Don't list . and .."
49//usage: "\n -a Don't hide entries starting with ."
50//usage: "\n -C List by columns"
51//usage: "\n -x List by lines"
52//usage: "\n -d List directory entries instead of contents"
53//usage: IF_FEATURE_LS_FOLLOWLINKS(
54//usage: "\n -L Follow symlinks"
55//usage: "\n -H Follow symlinks on command line only"
56//usage: )
57//usage: IF_FEATURE_LS_RECURSIVE(
58//usage: "\n -R Recurse"
59//usage: )
60//usage: IF_FEATURE_LS_FILETYPES(
61//usage: "\n -F Append indicator (one of */=@|) to entries"
62//usage: "\n -p Append indicator (one of /=@|) to entries"
63//usage: )
64//usage: "\n -l Long listing format"
65//usage: "\n -i List inode numbers"
66//usage: "\n -n List numeric UIDs and GIDs instead of names"
67//usage: "\n -s List the size of each file, in blocks"
68//usage: IF_FEATURE_LS_TIMESTAMPS(
69//usage: "\n -e List full date and time"
70//usage: )
71//usage: IF_FEATURE_HUMAN_READABLE(
72//usage: "\n -h List sizes in human readable format (1K 243M 2G)"
73//usage: )
74//usage: IF_FEATURE_LS_SORTFILES(
75//usage: "\n -r Sort in reverse order"
76//usage: "\n -S Sort by file size"
77//usage: "\n -X Sort by extension"
78//usage: "\n -v Sort by version"
79//usage: )
80//usage: IF_FEATURE_LS_TIMESTAMPS(
81//usage: "\n -c With -l: sort by ctime"
82//usage: "\n -t With -l: sort by modification time"
83//usage: "\n -u With -l: sort by access time"
84//usage: )
85//usage: IF_SELINUX(
86//usage: "\n -k List security context"
87//usage: "\n -K List security context in long format"
88//usage: "\n -Z List security context and permission"
89//usage: )
90//usage: IF_FEATURE_AUTOWIDTH(
91//usage: "\n -w N Assume the terminal is N columns wide"
92//usage: )
93//usage: IF_FEATURE_LS_COLOR(
94//usage: "\n --color[={always,never,auto}] Control coloring"
95//usage: )
96
32#include "libbb.h" 97#include "libbb.h"
33#include "unicode.h" 98#include "unicode.h"
34 99
@@ -53,13 +118,12 @@
53 118
54enum { 119enum {
55TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ 120TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */
56COLUMN_GAP = 2, /* includes the file type char */
57 121
58/* what is the overall style of the listing */ 122SPLIT_DIR = 1,
59STYLE_COLUMNS = 1 << 21, /* fill columns */ 123SPLIT_FILE = 0,
60STYLE_LONG = 2 << 21, /* one record per line, extended info */ 124SPLIT_SUBDIR = 2,
61STYLE_SINGLE = 3 << 21, /* one record per line */ 125
62STYLE_MASK = STYLE_SINGLE, 126/* Bits in all_fmt: */
63 127
64/* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */ 128/* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */
65/* what file information will be listed */ 129/* what file information will be listed */
@@ -71,75 +135,74 @@ LIST_ID_NAME = 1 << 4,
71LIST_ID_NUMERIC = 1 << 5, 135LIST_ID_NUMERIC = 1 << 5,
72LIST_CONTEXT = 1 << 6, 136LIST_CONTEXT = 1 << 6,
73LIST_SIZE = 1 << 7, 137LIST_SIZE = 1 << 7,
74//LIST_DEV = 1 << 8, - unused, synonym to LIST_SIZE 138LIST_DATE_TIME = 1 << 8,
75LIST_DATE_TIME = 1 << 9, 139LIST_FULLTIME = 1 << 9,
76LIST_FULLTIME = 1 << 10, 140LIST_SYMLINK = 1 << 10,
77LIST_FILENAME = 1 << 11, 141LIST_FILETYPE = 1 << 11,
78LIST_SYMLINK = 1 << 12, 142LIST_EXEC = 1 << 12,
79LIST_FILETYPE = 1 << 13,
80LIST_EXEC = 1 << 14,
81LIST_MASK = (LIST_EXEC << 1) - 1, 143LIST_MASK = (LIST_EXEC << 1) - 1,
82 144
83/* what files will be displayed */ 145/* what files will be displayed */
84DISP_DIRNAME = 1 << 15, /* 2 or more items? label directories */ 146DISP_DIRNAME = 1 << 13, /* 2 or more items? label directories */
85DISP_HIDDEN = 1 << 16, /* show filenames starting with . */ 147DISP_HIDDEN = 1 << 14, /* show filenames starting with . */
86DISP_DOT = 1 << 17, /* show . and .. */ 148DISP_DOT = 1 << 15, /* show . and .. */
87DISP_NOLIST = 1 << 18, /* show directory as itself, not contents */ 149DISP_NOLIST = 1 << 16, /* show directory as itself, not contents */
88DISP_RECURSIVE = 1 << 19, /* show directory and everything below it */ 150DISP_RECURSIVE = 1 << 17, /* show directory and everything below it */
89DISP_ROWS = 1 << 20, /* print across rows */ 151DISP_ROWS = 1 << 18, /* print across rows */
90DISP_MASK = ((DISP_ROWS << 1) - 1) & ~(DISP_DIRNAME - 1), 152DISP_MASK = ((DISP_ROWS << 1) - 1) & ~(DISP_DIRNAME - 1),
91 153
92/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */ 154/* what is the overall style of the listing */
93SORT_FORWARD = 0, /* sort in reverse order */ 155STYLE_COLUMNAR = 1 << 19, /* many records per line */
94SORT_REVERSE = 1 << 27, /* sort in reverse order */ 156STYLE_LONG = 2 << 19, /* one record per line, extended info */
95 157STYLE_SINGLE = 3 << 19, /* one record per line */
96SORT_NAME = 0, /* sort by file name */ 158STYLE_MASK = STYLE_SINGLE,
97SORT_SIZE = 1 << 28, /* sort by file size */
98SORT_ATIME = 2 << 28, /* sort by last access time */
99SORT_CTIME = 3 << 28, /* sort by last change time */
100SORT_MTIME = 4 << 28, /* sort by last modification time */
101SORT_VERSION = 5 << 28, /* sort by version */
102SORT_EXT = 6 << 28, /* sort by file name extension */
103SORT_DIR = 7 << 28, /* sort by file or directory */
104SORT_MASK = (7 << 28) * ENABLE_FEATURE_LS_SORTFILES,
105 159
106/* which of the three times will be used */ 160/* which of the three times will be used */
107TIME_CHANGE = (1 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS, 161TIME_CHANGE = (1 << 21) * ENABLE_FEATURE_LS_TIMESTAMPS,
108TIME_ACCESS = (1 << 24) * ENABLE_FEATURE_LS_TIMESTAMPS, 162TIME_ACCESS = (1 << 22) * ENABLE_FEATURE_LS_TIMESTAMPS,
109TIME_MASK = (3 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS, 163TIME_MASK = (3 << 21) * ENABLE_FEATURE_LS_TIMESTAMPS,
110 164
111FOLLOW_LINKS = (1 << 25) * ENABLE_FEATURE_LS_FOLLOWLINKS, 165/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */
166SORT_REVERSE = 1 << 23,
112 167
113LS_DISP_HR = (1 << 26) * ENABLE_FEATURE_HUMAN_READABLE, 168SORT_NAME = 0, /* sort by file name */
169SORT_SIZE = 1 << 24, /* sort by file size */
170SORT_ATIME = 2 << 24, /* sort by last access time */
171SORT_CTIME = 3 << 24, /* sort by last change time */
172SORT_MTIME = 4 << 24, /* sort by last modification time */
173SORT_VERSION = 5 << 24, /* sort by version */
174SORT_EXT = 6 << 24, /* sort by file name extension */
175SORT_DIR = 7 << 24, /* sort by file or directory */
176SORT_MASK = (7 << 24) * ENABLE_FEATURE_LS_SORTFILES,
114 177
115LIST_SHORT = LIST_FILENAME,
116LIST_LONG = LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | LIST_SIZE | \ 178LIST_LONG = LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | LIST_SIZE | \
117 LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK, 179 LIST_DATE_TIME | LIST_SYMLINK,
118
119SPLIT_DIR = 1,
120SPLIT_FILE = 0,
121SPLIT_SUBDIR = 2,
122}; 180};
123 181
124/* "[-]Cadil1", POSIX mandated options, busybox always supports */ 182/* -Cadil1 Std options, busybox always supports */
125/* "[-]gnsx", POSIX non-mandated options, busybox always supports */ 183/* -gnsxA Std options, busybox always supports */
126/* "[-]Q" GNU option? busybox always supports */ 184/* -Q GNU option, busybox always supports */
127/* "[-]Ak" GNU options, busybox always supports */ 185/* -k SELinux option, busybox always supports (ignores if !SELinux) */
128/* "[-]FLRctur", POSIX mandated options, busybox optionally supports */ 186/* Std has -k which means "show sizes in kbytes" */
129/* "[-]p", POSIX non-mandated options, busybox optionally supports */ 187/* -FLHRctur Std options, busybox optionally supports */
130/* "[-]SXvThw", GNU options, busybox optionally supports */ 188/* -p Std option, busybox optionally supports */
131/* "[-]K", SELinux mandated options, busybox optionally supports */ 189/* Not fully compatible - we show not only '/' but other chars too */
132/* "[-]e", I think we made this one up */ 190/* -SXvhTw GNU options, busybox optionally supports */
191/* -T TABWIDTH is ignored (we don't use tabs on output) */
192/* -K SELinux mandated options, busybox optionally supports */
193/* -e I think we made this one up (looks similar to GNU --full-time) */
194/* Std opts we do not support: */
195/* -H Follow the links on command line only */
133static const char ls_options[] ALIGN1 = 196static const char ls_options[] ALIGN1 =
134 "Cadil1gnsxQAk" /* 13 opts, total 13 */ 197 "Cadil1gnsxQAk" /* 13 opts, total 13 */
135 IF_FEATURE_LS_TIMESTAMPS("cetu") /* 4, 17 */ 198 IF_FEATURE_LS_TIMESTAMPS("cetu") /* 4, 17 */
136 IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 21 */ 199 IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 21 */
137 IF_FEATURE_LS_FILETYPES("Fp") /* 2, 23 */ 200 IF_FEATURE_LS_FILETYPES("Fp") /* 2, 23 */
138 IF_FEATURE_LS_FOLLOWLINKS("L") /* 1, 24 */ 201 IF_FEATURE_LS_RECURSIVE("R") /* 1, 24 */
139 IF_FEATURE_LS_RECURSIVE("R") /* 1, 25 */ 202 IF_SELINUX("KZ") /* 2, 26 */
140 IF_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ 203 IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 28 */
141 IF_SELINUX("KZ") /* 2, 28 */ 204 IF_FEATURE_HUMAN_READABLE("h") /* 1, 29 */
142 IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 30 */ 205 IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 31 */
143 ; 206 ;
144enum { 207enum {
145 //OPT_C = (1 << 0), 208 //OPT_C = (1 << 0),
@@ -155,75 +218,88 @@ enum {
155 OPT_Q = (1 << 10), 218 OPT_Q = (1 << 10),
156 //OPT_A = (1 << 11), 219 //OPT_A = (1 << 11),
157 //OPT_k = (1 << 12), 220 //OPT_k = (1 << 12),
158 OPTBIT_color = 13
159 + 4 * ENABLE_FEATURE_LS_TIMESTAMPS
160 + 4 * ENABLE_FEATURE_LS_SORTFILES
161 + 2 * ENABLE_FEATURE_LS_FILETYPES
162 + 1 * ENABLE_FEATURE_LS_FOLLOWLINKS
163 + 1 * ENABLE_FEATURE_LS_RECURSIVE
164 + 1 * ENABLE_FEATURE_HUMAN_READABLE
165 + 2 * ENABLE_SELINUX
166 + 2 * ENABLE_FEATURE_AUTOWIDTH,
167 OPT_color = 1 << OPTBIT_color,
168};
169 221
170enum { 222 OPTBIT_c = 13,
171 LIST_MASK_TRIGGER = 0, 223 OPTBIT_e,
172 STYLE_MASK_TRIGGER = STYLE_MASK, 224 OPTBIT_t,
173 DISP_MASK_TRIGGER = DISP_ROWS, 225 OPTBIT_u,
174 SORT_MASK_TRIGGER = SORT_MASK, 226 OPTBIT_S = OPTBIT_c + 4 * ENABLE_FEATURE_LS_TIMESTAMPS,
227 OPTBIT_X, /* 18 */
228 OPTBIT_r,
229 OPTBIT_v,
230 OPTBIT_F = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES,
231 OPTBIT_p, /* 22 */
232 OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES,
233 OPTBIT_K = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE,
234 OPTBIT_Z, /* 25 */
235 OPTBIT_L = OPTBIT_K + 2 * ENABLE_SELINUX,
236 OPTBIT_H, /* 27 */
237 OPTBIT_h = OPTBIT_L + 1 * ENABLE_FEATURE_LS_FOLLOWLINKS,
238 OPTBIT_T = OPTBIT_h + 2 * ENABLE_FEATURE_HUMAN_READABLE,
239 OPTBIT_w, /* 30 */
240 OPTBIT_color = OPTBIT_T + 2 * ENABLE_FEATURE_AUTOWIDTH,
241
242 OPT_c = (1 << OPTBIT_c) * ENABLE_FEATURE_LS_TIMESTAMPS,
243 OPT_e = (1 << OPTBIT_e) * ENABLE_FEATURE_LS_TIMESTAMPS,
244 OPT_t = (1 << OPTBIT_t) * ENABLE_FEATURE_LS_TIMESTAMPS,
245 OPT_u = (1 << OPTBIT_u) * ENABLE_FEATURE_LS_TIMESTAMPS,
246 OPT_S = (1 << OPTBIT_S) * ENABLE_FEATURE_LS_SORTFILES,
247 OPT_X = (1 << OPTBIT_X) * ENABLE_FEATURE_LS_SORTFILES,
248 OPT_r = (1 << OPTBIT_r) * ENABLE_FEATURE_LS_SORTFILES,
249 OPT_v = (1 << OPTBIT_v) * ENABLE_FEATURE_LS_SORTFILES,
250 OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES,
251 OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES,
252 OPT_R = (1 << OPTBIT_R) * ENABLE_FEATURE_LS_RECURSIVE,
253 OPT_K = (1 << OPTBIT_K) * ENABLE_SELINUX,
254 OPT_Z = (1 << OPTBIT_Z) * ENABLE_SELINUX,
255 OPT_L = (1 << OPTBIT_L) * ENABLE_FEATURE_LS_FOLLOWLINKS,
256 OPT_H = (1 << OPTBIT_H) * ENABLE_FEATURE_LS_FOLLOWLINKS,
257 OPT_h = (1 << OPTBIT_h) * ENABLE_FEATURE_HUMAN_READABLE,
258 OPT_T = (1 << OPTBIT_T) * ENABLE_FEATURE_AUTOWIDTH,
259 OPT_w = (1 << OPTBIT_w) * ENABLE_FEATURE_AUTOWIDTH,
260 OPT_color = (1 << OPTBIT_color) * ENABLE_FEATURE_LS_COLOR,
175}; 261};
176 262
177/* TODO: simple toggles may be stored as OPT_xxx bits instead */ 263/* TODO: simple toggles may be stored as OPT_xxx bits instead */
178static const unsigned opt_flags[] = { 264static const uint32_t opt_flags[] = {
179 LIST_SHORT | STYLE_COLUMNS, /* C */ 265 STYLE_COLUMNAR, /* C */
180 DISP_HIDDEN | DISP_DOT, /* a */ 266 DISP_HIDDEN | DISP_DOT, /* a */
181 DISP_NOLIST, /* d */ 267 DISP_NOLIST, /* d */
182 LIST_INO, /* i */ 268 LIST_INO, /* i */
183 LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */ 269 LIST_LONG | STYLE_LONG, /* l */
184 LIST_SHORT | STYLE_SINGLE, /* 1 */ 270 STYLE_SINGLE, /* 1 */
185 0, /* g (don't show group) - handled via OPT_g */ 271 0, /* g (don't show owner) - handled via OPT_g */
186 LIST_ID_NUMERIC, /* n */ 272 LIST_ID_NUMERIC, /* n */
187 LIST_BLOCKS, /* s */ 273 LIST_BLOCKS, /* s */
188 DISP_ROWS, /* x */ 274 DISP_ROWS | STYLE_COLUMNAR, /* x */
189 0, /* Q (quote filename) - handled via OPT_Q */ 275 0, /* Q (quote filename) - handled via OPT_Q */
190 DISP_HIDDEN, /* A */ 276 DISP_HIDDEN, /* A */
191 ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */ 277 ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */
192#if ENABLE_FEATURE_LS_TIMESTAMPS 278#if ENABLE_FEATURE_LS_TIMESTAMPS
193 TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */ 279 TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */
194 LIST_FULLTIME, /* e */ 280 LIST_FULLTIME, /* e */
195 ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME, /* t */ 281 ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME, /* t */
196 TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME), /* u */ 282 TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME), /* u */
197#endif 283#endif
198#if ENABLE_FEATURE_LS_SORTFILES 284#if ENABLE_FEATURE_LS_SORTFILES
199 SORT_SIZE, /* S */ 285 SORT_SIZE, /* S */
200 SORT_EXT, /* X */ 286 SORT_EXT, /* X */
201 SORT_REVERSE, /* r */ 287 SORT_REVERSE, /* r */
202 SORT_VERSION, /* v */ 288 SORT_VERSION, /* v */
203#endif 289#endif
204#if ENABLE_FEATURE_LS_FILETYPES 290#if ENABLE_FEATURE_LS_FILETYPES
205 LIST_FILETYPE | LIST_EXEC, /* F */ 291 LIST_FILETYPE | LIST_EXEC, /* F */
206 LIST_FILETYPE, /* p */ 292 LIST_FILETYPE, /* p */
207#endif
208#if ENABLE_FEATURE_LS_FOLLOWLINKS
209 FOLLOW_LINKS, /* L */
210#endif 293#endif
211#if ENABLE_FEATURE_LS_RECURSIVE 294#if ENABLE_FEATURE_LS_RECURSIVE
212 DISP_RECURSIVE, /* R */ 295 DISP_RECURSIVE, /* R */
213#endif
214#if ENABLE_FEATURE_HUMAN_READABLE
215 LS_DISP_HR, /* h */
216#endif 296#endif
217#if ENABLE_SELINUX 297#if ENABLE_SELINUX
218 LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */ 298 LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */
219#endif
220#if ENABLE_SELINUX
221 LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */ 299 LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */
222#endif 300#endif
223 (1U<<31) 301 (1U << 31)
224 /* options after Z are not processed through opt_flags: 302 /* options after Z are not processed through opt_flags */
225 * T, w - ignored
226 */
227}; 303};
228 304
229 305
@@ -246,7 +322,6 @@ struct globals {
246 smallint exit_code; 322 smallint exit_code;
247 unsigned all_fmt; 323 unsigned all_fmt;
248#if ENABLE_FEATURE_AUTOWIDTH 324#if ENABLE_FEATURE_AUTOWIDTH
249 unsigned tabstops; // = COLUMN_GAP;
250 unsigned terminal_width; // = TERMINAL_WIDTH; 325 unsigned terminal_width; // = TERMINAL_WIDTH;
251#endif 326#endif
252#if ENABLE_FEATURE_LS_TIMESTAMPS 327#if ENABLE_FEATURE_LS_TIMESTAMPS
@@ -263,11 +338,9 @@ enum { show_color = 0 };
263#define exit_code (G.exit_code ) 338#define exit_code (G.exit_code )
264#define all_fmt (G.all_fmt ) 339#define all_fmt (G.all_fmt )
265#if ENABLE_FEATURE_AUTOWIDTH 340#if ENABLE_FEATURE_AUTOWIDTH
266# define tabstops (G.tabstops )
267# define terminal_width (G.terminal_width) 341# define terminal_width (G.terminal_width)
268#else 342#else
269enum { 343enum {
270 tabstops = COLUMN_GAP,
271 terminal_width = TERMINAL_WIDTH, 344 terminal_width = TERMINAL_WIDTH,
272}; 345};
273#endif 346#endif
@@ -275,7 +348,6 @@ enum {
275#define INIT_G() do { \ 348#define INIT_G() do { \
276 /* we have to zero it out because of NOEXEC */ \ 349 /* we have to zero it out because of NOEXEC */ \
277 memset(&G, 0, sizeof(G)); \ 350 memset(&G, 0, sizeof(G)); \
278 IF_FEATURE_AUTOWIDTH(tabstops = COLUMN_GAP;) \
279 IF_FEATURE_AUTOWIDTH(terminal_width = TERMINAL_WIDTH;) \ 351 IF_FEATURE_AUTOWIDTH(terminal_width = TERMINAL_WIDTH;) \
280 IF_FEATURE_LS_TIMESTAMPS(time(&current_time_t);) \ 352 IF_FEATURE_LS_TIMESTAMPS(time(&current_time_t);) \
281} while (0) 353} while (0)
@@ -287,7 +359,7 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f
287 struct dnode *cur; 359 struct dnode *cur;
288 IF_SELINUX(security_context_t sid = NULL;) 360 IF_SELINUX(security_context_t sid = NULL;)
289 361
290 if ((all_fmt & FOLLOW_LINKS) || force_follow) { 362 if ((option_mask32 & OPT_L) || force_follow) {
291#if ENABLE_SELINUX 363#if ENABLE_SELINUX
292 if (is_selinux_enabled()) { 364 if (is_selinux_enabled()) {
293 getfilecon(fullname, &sid); 365 getfilecon(fullname, &sid);
@@ -547,7 +619,7 @@ static unsigned calc_name_len(const char *name)
547 619
548 620
549/* Return the number of used columns. 621/* Return the number of used columns.
550 * Note that only STYLE_COLUMNS uses return value. 622 * Note that only STYLE_COLUMNAR uses return value.
551 * STYLE_SINGLE and STYLE_LONG don't care. 623 * STYLE_SINGLE and STYLE_LONG don't care.
552 * coreutils 7.2 also supports: 624 * coreutils 7.2 also supports:
553 * ls -b (--escape) = octal escapes (although it doesn't look like working) 625 * ls -b (--escape) = octal escapes (although it doesn't look like working)
@@ -581,7 +653,7 @@ static unsigned print_name(const char *name)
581} 653}
582 654
583/* Return the number of used columns. 655/* Return the number of used columns.
584 * Note that only STYLE_COLUMNS uses return value, 656 * Note that only STYLE_COLUMNAR uses return value,
585 * STYLE_SINGLE and STYLE_LONG don't care. 657 * STYLE_SINGLE and STYLE_LONG don't care.
586 */ 658 */
587static NOINLINE unsigned list_single(const struct dnode *dn) 659static NOINLINE unsigned list_single(const struct dnode *dn)
@@ -625,7 +697,7 @@ static NOINLINE unsigned list_single(const struct dnode *dn)
625 if (all_fmt & LIST_ID_NAME) { 697 if (all_fmt & LIST_ID_NAME) {
626 if (option_mask32 & OPT_g) { 698 if (option_mask32 & OPT_g) {
627 column += printf("%-8.8s ", 699 column += printf("%-8.8s ",
628 get_cached_username(dn->dstat.st_uid)); 700 get_cached_groupname(dn->dstat.st_gid));
629 } else { 701 } else {
630 column += printf("%-8.8s %-8.8s ", 702 column += printf("%-8.8s %-8.8s ",
631 get_cached_username(dn->dstat.st_uid), 703 get_cached_username(dn->dstat.st_uid),
@@ -635,19 +707,19 @@ static NOINLINE unsigned list_single(const struct dnode *dn)
635#endif 707#endif
636 if (all_fmt & LIST_ID_NUMERIC) { 708 if (all_fmt & LIST_ID_NUMERIC) {
637 if (option_mask32 & OPT_g) 709 if (option_mask32 & OPT_g)
638 column += printf("%-8u ", (int) dn->dstat.st_uid); 710 column += printf("%-8u ", (int) dn->dstat.st_gid);
639 else 711 else
640 column += printf("%-8u %-8u ", 712 column += printf("%-8u %-8u ",
641 (int) dn->dstat.st_uid, 713 (int) dn->dstat.st_uid,
642 (int) dn->dstat.st_gid); 714 (int) dn->dstat.st_gid);
643 } 715 }
644 if (all_fmt & (LIST_SIZE /*|LIST_DEV*/ )) { 716 if (all_fmt & LIST_SIZE) {
645 if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) { 717 if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) {
646 column += printf("%4u, %3u ", 718 column += printf("%4u, %3u ",
647 (int) major(dn->dstat.st_rdev), 719 (int) major(dn->dstat.st_rdev),
648 (int) minor(dn->dstat.st_rdev)); 720 (int) minor(dn->dstat.st_rdev));
649 } else { 721 } else {
650 if (all_fmt & LS_DISP_HR) { 722 if (option_mask32 & OPT_h) {
651 column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ", 723 column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ",
652 /* print st_size, show one fractional, use suffixes */ 724 /* print st_size, show one fractional, use suffixes */
653 make_human_readable_str(dn->dstat.st_size, 1, 0) 725 make_human_readable_str(dn->dstat.st_size, 1, 0)
@@ -689,20 +761,20 @@ static NOINLINE unsigned list_single(const struct dnode *dn)
689 freecon(dn->sid); 761 freecon(dn->sid);
690 } 762 }
691#endif 763#endif
692 if (all_fmt & LIST_FILENAME) { 764
693#if ENABLE_FEATURE_LS_COLOR 765#if ENABLE_FEATURE_LS_COLOR
694 if (show_color) { 766 if (show_color) {
695 info.st_mode = 0; /* for fgcolor() */ 767 info.st_mode = 0; /* for fgcolor() */
696 lstat(dn->fullname, &info); 768 lstat(dn->fullname, &info);
697 printf("\033[%u;%um", bold(info.st_mode), 769 printf("\033[%u;%um", bold(info.st_mode),
698 fgcolor(info.st_mode)); 770 fgcolor(info.st_mode));
699 } 771 }
700#endif 772#endif
701 column += print_name(dn->name); 773 column += print_name(dn->name);
702 if (show_color) { 774 if (show_color) {
703 printf("\033[0m"); 775 printf("\033[0m");
704 }
705 } 776 }
777
706 if (all_fmt & LIST_SYMLINK) { 778 if (all_fmt & LIST_SYMLINK) {
707 if (S_ISLNK(dn->dstat.st_mode) && lpath) { 779 if (S_ISLNK(dn->dstat.st_mode) && lpath) {
708 printf(" -> "); 780 printf(" -> ");
@@ -742,9 +814,9 @@ static NOINLINE unsigned list_single(const struct dnode *dn)
742static void showfiles(struct dnode **dn, unsigned nfiles) 814static void showfiles(struct dnode **dn, unsigned nfiles)
743{ 815{
744 unsigned i, ncols, nrows, row, nc; 816 unsigned i, ncols, nrows, row, nc;
745 unsigned column = 0; 817 unsigned column;
746 unsigned nexttab = 0; 818 unsigned nexttab;
747 unsigned column_width = 0; /* used only by STYLE_COLUMNS */ 819 unsigned column_width = 0; /* used only by STYLE_COLUMNAR */
748 820
749 if (all_fmt & STYLE_LONG) { /* STYLE_LONG or STYLE_SINGLE */ 821 if (all_fmt & STYLE_LONG) { /* STYLE_LONG or STYLE_SINGLE */
750 ncols = 1; 822 ncols = 1;
@@ -755,7 +827,7 @@ static void showfiles(struct dnode **dn, unsigned nfiles)
755 if (column_width < len) 827 if (column_width < len)
756 column_width = len; 828 column_width = len;
757 } 829 }
758 column_width += tabstops + 830 column_width += 1 +
759 IF_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + ) 831 IF_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + )
760 ((all_fmt & LIST_INO) ? 8 : 0) + 832 ((all_fmt & LIST_INO) ? 8 : 0) +
761 ((all_fmt & LIST_BLOCKS) ? 5 : 0); 833 ((all_fmt & LIST_BLOCKS) ? 5 : 0);
@@ -771,6 +843,8 @@ static void showfiles(struct dnode **dn, unsigned nfiles)
771 ncols = 1; 843 ncols = 1;
772 } 844 }
773 845
846 column = 0;
847 nexttab = 0;
774 for (row = 0; row < nrows; row++) { 848 for (row = 0; row < nrows; row++) {
775 for (nc = 0; nc < ncols; nc++) { 849 for (nc = 0; nc < ncols; nc++) {
776 /* reach into the array based on the column and row */ 850 /* reach into the array based on the column and row */
@@ -781,8 +855,8 @@ static void showfiles(struct dnode **dn, unsigned nfiles)
781 if (i < nfiles) { 855 if (i < nfiles) {
782 if (column > 0) { 856 if (column > 0) {
783 nexttab -= column; 857 nexttab -= column;
784 printf("%*s", nexttab, ""); 858 printf("%*s ", nexttab, "");
785 column += nexttab; 859 column += nexttab + 1;
786 } 860 }
787 nexttab = column + column_width; 861 nexttab = column + column_width;
788 column += list_single(dn[i]); 862 column += list_single(dn[i]);
@@ -835,12 +909,6 @@ static void showdirs(struct dnode **dn, int first)
835 struct dnode **subdnp; 909 struct dnode **subdnp;
836 struct dnode **dnd; 910 struct dnode **dnd;
837 911
838 /* Never happens:
839 if (dn == NULL || ndirs < 1) {
840 return;
841 }
842 */
843
844 for (; *dn; dn++) { 912 for (; *dn; dn++) {
845 if (all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) { 913 if (all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) {
846 if (!first) 914 if (!first)
@@ -981,8 +1049,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
981 1049
982 init_unicode(); 1050 init_unicode();
983 1051
984 all_fmt = LIST_SHORT | 1052 all_fmt = ENABLE_FEATURE_LS_SORTFILES * SORT_NAME;
985 (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD));
986 1053
987#if ENABLE_FEATURE_AUTOWIDTH 1054#if ENABLE_FEATURE_AUTOWIDTH
988 /* obtain the terminal width */ 1055 /* obtain the terminal width */
@@ -993,32 +1060,38 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
993 1060
994 /* process options */ 1061 /* process options */
995 IF_FEATURE_LS_COLOR(applet_long_options = ls_longopts;) 1062 IF_FEATURE_LS_COLOR(applet_long_options = ls_longopts;)
996#if ENABLE_FEATURE_AUTOWIDTH 1063 opt_complementary =
997 opt_complementary = "T+:w+"; /* -T N, -w N */ 1064 /* -e implies -l */
998 opt = getopt32(argv, ls_options, &tabstops, &terminal_width 1065 "el"
999 IF_FEATURE_LS_COLOR(, &color_opt)); 1066 /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html:
1000#else 1067 * in some pairs of opts, only last one takes effect:
1001 opt = getopt32(argv, ls_options IF_FEATURE_LS_COLOR(, &color_opt)); 1068 */
1002#endif 1069 IF_FEATURE_LS_TIMESTAMPS(IF_FEATURE_LS_SORTFILES(":t-S:S-t")) /* time/size */
1003 for (i = 0; opt_flags[i] != (1U<<31); i++) { 1070 // ":m-l:l-m" - we don't have -m
1071 IF_FEATURE_LS_FOLLOWLINKS(":H-L:L-H")
1072 ":C-xl:x-Cl:l-xC" /* bycols/bylines/long */
1073 ":C-1:1-C" /* bycols/oneline */
1074 ":x-1:1-x" /* bylines/oneline (not in SuS, but in GNU coreutils 8.4) */
1075 ":c-u:u-c" /* mtime/atime */
1076 /* -w NUM: */
1077 IF_FEATURE_AUTOWIDTH(":w+");
1078 opt = getopt32(argv, ls_options
1079 IF_FEATURE_AUTOWIDTH(, NULL, &terminal_width)
1080 IF_FEATURE_LS_COLOR(, &color_opt)
1081 );
1082 for (i = 0; opt_flags[i] != (1U << 31); i++) {
1004 if (opt & (1 << i)) { 1083 if (opt & (1 << i)) {
1005 unsigned flags = opt_flags[i]; 1084 uint32_t flags = opt_flags[i];
1006 1085
1007 if (flags & LIST_MASK_TRIGGER) 1086 if (flags & STYLE_MASK)
1008 all_fmt &= ~LIST_MASK;
1009 if (flags & STYLE_MASK_TRIGGER)
1010 all_fmt &= ~STYLE_MASK; 1087 all_fmt &= ~STYLE_MASK;
1011 if (flags & SORT_MASK_TRIGGER) 1088 if (flags & SORT_MASK)
1012 all_fmt &= ~SORT_MASK; 1089 all_fmt &= ~SORT_MASK;
1013 if (flags & DISP_MASK_TRIGGER)
1014 all_fmt &= ~DISP_MASK;
1015 if (flags & TIME_MASK) 1090 if (flags & TIME_MASK)
1016 all_fmt &= ~TIME_MASK; 1091 all_fmt &= ~TIME_MASK;
1092
1017 if (flags & LIST_CONTEXT) 1093 if (flags & LIST_CONTEXT)
1018 all_fmt |= STYLE_SINGLE; 1094 all_fmt |= STYLE_SINGLE;
1019 /* huh?? opt cannot be 'l' */
1020 //if (LS_DISP_HR && opt == 'l')
1021 // all_fmt &= ~LS_DISP_HR;
1022 all_fmt |= flags; 1095 all_fmt |= flags;
1023 } 1096 }
1024 } 1097 }
@@ -1058,14 +1131,14 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1058 all_fmt = (all_fmt & ~SORT_MASK) | SORT_ATIME; 1131 all_fmt = (all_fmt & ~SORT_MASK) | SORT_ATIME;
1059 } 1132 }
1060 if ((all_fmt & STYLE_MASK) != STYLE_LONG) /* only for long list */ 1133 if ((all_fmt & STYLE_MASK) != STYLE_LONG) /* only for long list */
1061 all_fmt &= ~(LIST_ID_NUMERIC|LIST_FULLTIME|LIST_ID_NAME|LIST_ID_NUMERIC); 1134 all_fmt &= ~(LIST_ID_NUMERIC|LIST_ID_NAME|LIST_FULLTIME);
1062 if (ENABLE_FEATURE_LS_USERNAME) 1135 if (ENABLE_FEATURE_LS_USERNAME)
1063 if ((all_fmt & STYLE_MASK) == STYLE_LONG && (all_fmt & LIST_ID_NUMERIC)) 1136 if ((all_fmt & STYLE_MASK) == STYLE_LONG && (all_fmt & LIST_ID_NUMERIC))
1064 all_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */ 1137 all_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */
1065 1138
1066 /* choose a display format */ 1139 /* choose a display format if one was not already specified by an option */
1067 if (!(all_fmt & STYLE_MASK)) 1140 if (!(all_fmt & STYLE_MASK))
1068 all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNS : STYLE_SINGLE); 1141 all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNAR : STYLE_SINGLE);
1069 1142
1070 argv += optind; 1143 argv += optind;
1071 if (!argv[0]) 1144 if (!argv[0])
@@ -1078,8 +1151,12 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1078 dn = NULL; 1151 dn = NULL;
1079 nfiles = 0; 1152 nfiles = 0;
1080 do { 1153 do {
1081 /* NB: follow links on command line unless -l or -s */ 1154 cur = my_stat(*argv, *argv,
1082 cur = my_stat(*argv, *argv, !(all_fmt & (STYLE_LONG|LIST_BLOCKS))); 1155 /* follow links on command line unless -l, -s or -F: */
1156 !((all_fmt & (STYLE_LONG|LIST_BLOCKS)) || (option_mask32 & OPT_F))
1157 /* ... or if -H: */
1158 || (option_mask32 & OPT_H)
1159 );
1083 argv++; 1160 argv++;
1084 if (!cur) 1161 if (!cur)
1085 continue; 1162 continue;
diff --git a/coreutils/mv.c b/coreutils/mv.c
index 245639bd0..399f391b2 100644
--- a/coreutils/mv.c
+++ b/coreutils/mv.c
@@ -92,7 +92,7 @@ int mv_main(int argc, char **argv)
92 || (flags & OPT_FILEUTILS_INTERACTIVE)) 92 || (flags & OPT_FILEUTILS_INTERACTIVE))
93 ) { 93 ) {
94 if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { 94 if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) {
95 goto RET_1; /* Ouch! fprintf failed! */ 95 goto RET_1; /* Ouch! fprintf failed! */
96 } 96 }
97 if (!bb_ask_confirmation()) { 97 if (!bb_ask_confirmation()) {
98 goto RET_0; 98 goto RET_0;
diff --git a/coreutils/nice.c b/coreutils/nice.c
index 6b8fce24d..35d6bf3d9 100644
--- a/coreutils/nice.c
+++ b/coreutils/nice.c
@@ -17,12 +17,12 @@ int nice_main(int argc, char **argv)
17 17
18 old_priority = getpriority(PRIO_PROCESS, 0); 18 old_priority = getpriority(PRIO_PROCESS, 0);
19 19
20 if (!*++argv) { /* No args, so (GNU) output current nice value. */ 20 if (!*++argv) { /* No args, so (GNU) output current nice value. */
21 printf("%d\n", old_priority); 21 printf("%d\n", old_priority);
22 fflush_stdout_and_exit(EXIT_SUCCESS); 22 fflush_stdout_and_exit(EXIT_SUCCESS);
23 } 23 }
24 24
25 adjustment = 10; /* Set default adjustment. */ 25 adjustment = 10; /* Set default adjustment. */
26 26
27 if (argv[0][0] == '-') { 27 if (argv[0][0] == '-') {
28 if (argv[0][1] == 'n') { /* -n */ 28 if (argv[0][1] == 'n') { /* -n */
@@ -32,7 +32,7 @@ int nice_main(int argc, char **argv)
32 } else { /* -NNN (NNN may be negative) == -n NNN */ 32 } else { /* -NNN (NNN may be negative) == -n NNN */
33 argv[0] += 1; argv--; argc++; 33 argv[0] += 1; argv--; argc++;
34 } 34 }
35 if (argc < 4) { /* Missing priority and/or utility! */ 35 if (argc < 4) { /* Missing priority and/or utility! */
36 bb_show_usage(); 36 bb_show_usage();
37 } 37 }
38 adjustment = xatoi_range(argv[1], INT_MIN/2, INT_MAX/2); 38 adjustment = xatoi_range(argv[1], INT_MIN/2, INT_MAX/2);
diff --git a/coreutils/od.c b/coreutils/od.c
index dcd693446..e62711671 100644
--- a/coreutils/od.c
+++ b/coreutils/od.c
@@ -4,7 +4,7 @@
4 * Based on code from util-linux v 2.11l 4 * Based on code from util-linux v 2.11l
5 * 5 *
6 * Copyright (c) 1990 6 * Copyright (c) 1990
7 * The Regents of the University of California. All rights reserved. 7 * The Regents of the University of California. All rights reserved.
8 * 8 *
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 *
@@ -174,7 +174,7 @@ int od_main(int argc, char **argv)
174 bb_dump_add(dumper, "\" \""); 174 bb_dump_add(dumper, "\" \"");
175 } 175 }
176 bb_dump_add(dumper, add_strings[(int)od_o2si[(p - od_opts)]]); 176 bb_dump_add(dumper, add_strings[(int)od_o2si[(p - od_opts)]]);
177 } else { /* P, p, s, w, or other unhandled */ 177 } else { /* P, p, s, w, or other unhandled */
178 bb_show_usage(); 178 bb_show_usage();
179 } 179 }
180 } 180 }
diff --git a/coreutils/sort.c b/coreutils/sort.c
index eccc2d437..3562464d1 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -52,8 +52,8 @@ enum {
52static char key_separator; 52static char key_separator;
53 53
54static struct sort_key { 54static struct sort_key {
55 struct sort_key *next_key; /* linked list */ 55 struct sort_key *next_key; /* linked list */
56 unsigned range[4]; /* start word, start char, end word, end char */ 56 unsigned range[4]; /* start word, start char, end word, end char */
57 unsigned flags; 57 unsigned flags;
58} *key_list; 58} *key_list;
59 59
diff --git a/coreutils/stat.c b/coreutils/stat.c
index b4e6f10fd..7351f5956 100644
--- a/coreutils/stat.c
+++ b/coreutils/stat.c
@@ -630,10 +630,9 @@ static bool do_stat(const char *filename, const char *format)
630# if ENABLE_SELINUX 630# if ENABLE_SELINUX
631 printf(" S_Context: %lc\n", *scontext); 631 printf(" S_Context: %lc\n", *scontext);
632# endif 632# endif
633 printf("Access: %s\n" "Modify: %s\n" "Change: %s\n", 633 printf("Access: %s\n", human_time(statbuf.st_atime));
634 human_time(statbuf.st_atime), 634 printf("Modify: %s\n", human_time(statbuf.st_mtime));
635 human_time(statbuf.st_mtime), 635 printf("Change: %s\n", human_time(statbuf.st_ctime));
636 human_time(statbuf.st_ctime));
637 } 636 }
638#endif /* FEATURE_STAT_FORMAT */ 637#endif /* FEATURE_STAT_FORMAT */
639 return 1; 638 return 1;
diff --git a/coreutils/test.c b/coreutils/test.c
index 1952337b3..3e9ab7c65 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -49,9 +49,9 @@
49 * state. */ 49 * state. */
50 50
51/* test(1) accepts the following grammar: 51/* test(1) accepts the following grammar:
52 oexpr ::= aexpr | aexpr "-o" oexpr ; 52 oexpr ::= aexpr | aexpr "-o" oexpr ;
53 aexpr ::= nexpr | nexpr "-a" aexpr ; 53 aexpr ::= nexpr | nexpr "-a" aexpr ;
54 nexpr ::= primary | "!" primary 54 nexpr ::= primary | "!" primary
55 primary ::= unary-operator operand 55 primary ::= unary-operator operand
56 | operand binary-operator operand 56 | operand binary-operator operand
57 | operand 57 | operand
@@ -901,7 +901,10 @@ int test_main(int argc, char **argv)
901 res = !oexpr(check_operator(*args)); 901 res = !oexpr(check_operator(*args));
902 902
903 if (*args != NULL && *++args != NULL) { 903 if (*args != NULL && *++args != NULL) {
904 /* TODO: example when this happens? */ 904 /* Examples:
905 * test 3 -lt 5 6
906 * test -t 1 2
907 */
905 bb_error_msg("%s: unknown operand", *args); 908 bb_error_msg("%s: unknown operand", *args);
906 res = 2; 909 res = 2;
907 } 910 }
diff --git a/coreutils/touch.c b/coreutils/touch.c
index afff36b4d..6c2b948e6 100644
--- a/coreutils/touch.c
+++ b/coreutils/touch.c
@@ -19,6 +19,35 @@
19 19
20#include "libbb.h" 20#include "libbb.h"
21 21
22//config:config TOUCH
23//config: bool "touch"
24//config: default y
25//config: help
26//config: touch is used to create or change the access and/or
27//config: modification timestamp of specified files.
28
29//applet:IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch))
30
31//kbuild:lib-$(CONFIG_TOUCH) += touch.o
32
33//usage:#define touch_trivial_usage
34//usage: "[-c]" IF_DESKTOP(" [-d DATE] [-r FILE]") " FILE [FILE]..."
35//usage:#define touch_full_usage "\n\n"
36//usage: "Update the last-modified date on the given FILE[s]\n"
37//usage: "\nOptions:"
38//usage: "\n -c Don't create files"
39//usage: IF_DESKTOP(
40//usage: "\n -d DT Date/time to use"
41//usage: "\n -r FILE Use FILE's date/time"
42//usage: )
43//usage:
44//usage:#define touch_example_usage
45//usage: "$ ls -l /tmp/foo\n"
46//usage: "/bin/ls: /tmp/foo: No such file or directory\n"
47//usage: "$ touch /tmp/foo\n"
48//usage: "$ ls -l /tmp/foo\n"
49//usage: "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n"
50
22/* This is a NOFORK applet. Be very careful! */ 51/* This is a NOFORK applet. Be very careful! */
23 52
24/* coreutils implements: 53/* coreutils implements:
@@ -91,9 +120,10 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
91 struct tm tm_time; 120 struct tm tm_time;
92 time_t t; 121 time_t t;
93 122
94 //time(&t); 123 //memset(&tm_time, 0, sizeof(tm_time));
95 //localtime_r(&t, &tm_time); 124 /* Better than memset: makes "HH:MM" dates meaningful */
96 memset(&tm_time, 0, sizeof(tm_time)); 125 time(&t);
126 localtime_r(&t, &tm_time);
97 parse_datestr(date_str, &tm_time); 127 parse_datestr(date_str, &tm_time);
98 128
99 /* Correct any day of week and day of year etc. fields */ 129 /* Correct any day of week and day of year etc. fields */
diff --git a/coreutils/tr.c b/coreutils/tr.c
index d6bc7d20a..21d77ef95 100644
--- a/coreutils/tr.c
+++ b/coreutils/tr.c
@@ -203,7 +203,7 @@ static unsigned expand(const char *arg, char **buffer_p)
203 buffer[pos++] = *arg; /* copy CHAR */ 203 buffer[pos++] = *arg; /* copy CHAR */
204 if (!arg[0] || arg[1] != '=' || arg[2] != ']') 204 if (!arg[0] || arg[1] != '=' || arg[2] != ']')
205 bb_show_usage(); 205 bb_show_usage();
206 arg += 3; /* skip CHAR=] */ 206 arg += 3; /* skip CHAR=] */
207 continue; 207 continue;
208 } 208 }
209 /* The rest of "[xyz..." cases is treated as normal 209 /* The rest of "[xyz..." cases is treated as normal
@@ -258,9 +258,9 @@ int tr_main(int argc UNUSED_PARAM, char **argv)
258 char *invec = vector + ASCII; 258 char *invec = vector + ASCII;
259 char *outvec = vector + ASCII * 2; 259 char *outvec = vector + ASCII * 2;
260 260
261#define TR_OPT_complement (3 << 0) 261#define TR_OPT_complement (3 << 0)
262#define TR_OPT_delete (1 << 2) 262#define TR_OPT_delete (1 << 2)
263#define TR_OPT_squeeze_reps (1 << 3) 263#define TR_OPT_squeeze_reps (1 << 3)
264 264
265 for (i = 0; i < ASCII; i++) { 265 for (i = 0; i < ASCII; i++) {
266 vector[i] = i; 266 vector[i] = i;
diff --git a/coreutils/wc.c b/coreutils/wc.c
index ecadae59b..fe3f274f8 100644
--- a/coreutils/wc.c
+++ b/coreutils/wc.c
@@ -153,7 +153,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv)
153 bb_simple_perror_msg(arg); 153 bb_simple_perror_msg(arg);
154 status = EXIT_FAILURE; 154 status = EXIT_FAILURE;
155 } 155 }
156 goto DO_EOF; /* Treat an EOF as '\r'. */ 156 goto DO_EOF; /* Treat an EOF as '\r'. */
157 } 157 }
158 158
159 /* Cater for -c and -m */ 159 /* Cater for -c and -m */
@@ -179,7 +179,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv)
179 */ 179 */
180 if (c == '\t') { 180 if (c == '\t') {
181 linepos = (linepos | 7) + 1; 181 linepos = (linepos | 7) + 1;
182 } else { /* '\n', '\r', '\f', or '\v' */ 182 } else { /* '\n', '\r', '\f', or '\v' */
183 DO_EOF: 183 DO_EOF:
184 if (linepos > counts[WC_LENGTH]) { 184 if (linepos > counts[WC_LENGTH]) {
185 counts[WC_LENGTH] = linepos; 185 counts[WC_LENGTH] = linepos;
@@ -230,7 +230,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv)
230 * effect of trashing the totals array after outputting it, but that's 230 * effect of trashing the totals array after outputting it, but that's
231 * irrelavent since we no longer need it. */ 231 * irrelavent since we no longer need it. */
232 if (num_files > 1) { 232 if (num_files > 1) {
233 num_files = 0; /* Make sure we don't get here again. */ 233 num_files = 0; /* Make sure we don't get here again. */
234 arg = "total"; 234 arg = "total";
235 pcounts = totals; 235 pcounts = totals;
236 --argv; 236 --argv;
diff --git a/docs/keep_data_small.txt b/docs/keep_data_small.txt
index 01c0d3c7b..21d732674 100644
--- a/docs/keep_data_small.txt
+++ b/docs/keep_data_small.txt
@@ -59,7 +59,7 @@ wait
59 Example 1 59 Example 1
60 60
61One example how to reduce global data usage is in 61One example how to reduce global data usage is in
62archival/libunarchive/decompress_unzip.c: 62archival/libarchive/decompress_unzip.c:
63 63
64/* This is somewhat complex-looking arrangement, but it allows 64/* This is somewhat complex-looking arrangement, but it allows
65 * to place decompressor state either in bss or in 65 * to place decompressor state either in bss or in
diff --git a/docs/new-applet-HOWTO.txt b/docs/new-applet-HOWTO.txt
index 2f237564d..bb29999cf 100644
--- a/docs/new-applet-HOWTO.txt
+++ b/docs/new-applet-HOWTO.txt
@@ -19,8 +19,7 @@ such as who you stole the code from and so forth. Also include the mini-GPL
19boilerplate. Be sure to name the main function <applet>_main instead of main. 19boilerplate. Be sure to name the main function <applet>_main instead of main.
20And be sure to put it in <applet>.c. Usage does not have to be taken care of by 20And be sure to put it in <applet>.c. Usage does not have to be taken care of by
21your applet. 21your applet.
22Make sure to #include "libbb.h" as the first include file in your applet so 22Make sure to #include "libbb.h" as the first include file in your applet.
23the bb_config.h and appropriate platform specific files are included properly.
24 23
25For a new applet mu, here is the code that would go in mu.c: 24For a new applet mu, here is the code that would go in mu.c:
26 25
@@ -99,14 +98,14 @@ int function(char *a)
99----end example code------ 98----end example code------
100 99
101Add <function_name>.o in the right alphabetically sorted place 100Add <function_name>.o in the right alphabetically sorted place
102in libbb/Kbuild. You should look at the conditional part of 101in libbb/Kbuild.src. You should look at the conditional part of
103libbb/Kbuild aswell. 102libbb/Kbuild.src as well.
104 103
105You should also try to find a suitable place in include/libbb.h for 104You should also try to find a suitable place in include/libbb.h for
106the function declaration. If not, add it somewhere anyway, with or without 105the function declaration. If not, add it somewhere anyway, with or without
107ifdefs to include or not. 106ifdefs to include or not.
108 107
109You can look at libbb/Config.in and try to find out if the function is 108You can look at libbb/Config.src and try to find out if the function is
110tunable and add it there if it is. 109tunable and add it there if it is.
111 110
112 111
@@ -118,11 +117,11 @@ Find the appropriate directory for your new applet.
118Make sure you find the appropriate places in the files, the applets are 117Make sure you find the appropriate places in the files, the applets are
119sorted alphabetically. 118sorted alphabetically.
120 119
121Add the applet to Kbuild in the chosen directory: 120Add the applet to Kbuild.src in the chosen directory:
122 121
123lib-$(CONFIG_MU) += mu.o 122lib-$(CONFIG_MU) += mu.o
124 123
125Add the applet to Config.in in the chosen directory: 124Add the applet to Config.src in the chosen directory:
126 125
127config MU 126config MU
128 bool "MU" 127 bool "MU"
@@ -134,7 +133,7 @@ config MU
134Usage String(s) 133Usage String(s)
135--------------- 134---------------
136 135
137Next, add usage information for you applet to include/usage.h. 136Next, add usage information for you applet to include/usage.src.h.
138This should look like the following: 137This should look like the following:
139 138
140 #define mu_trivial_usage \ 139 #define mu_trivial_usage \
@@ -149,17 +148,17 @@ This should look like the following:
149If your program supports flags, the flags should be mentioned on the first 148If your program supports flags, the flags should be mentioned on the first
150line (-[abcde]) and a detailed description of each flag should go in the 149line (-[abcde]) and a detailed description of each flag should go in the
151mu_full_usage section, one flag per line. (Numerous examples of this 150mu_full_usage section, one flag per line. (Numerous examples of this
152currently exist in usage.h.) 151currently exist in usage.src.h.)
153 152
154 153
155Header Files 154Header Files
156------------ 155------------
157 156
158Next, add an entry to include/applets.h. Be *sure* to keep the list 157Next, add an entry to include/applets.src.h. Be *sure* to keep the list
159in alphabetical order, or else it will break the binary-search lookup 158in alphabetical order, or else it will break the binary-search lookup
160algorithm in busybox.c and the Gods of BusyBox smite you. Yea, verily: 159algorithm in busybox.c and the Gods of BusyBox smite you. Yea, verily:
161 160
162Be sure to read the top of applets.h before adding your applet. 161Be sure to read the top of applets.src.h before adding your applet.
163 162
164 /* all programs above here are alphabetically "less than" 'mu' */ 163 /* all programs above here are alphabetically "less than" 'mu' */
165 IF_MU(APPLET(mu, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 164 IF_MU(APPLET(mu, _BB_DIR_USR_BIN, _BB_SUID_DROP))
diff --git a/e2fsprogs/old_e2fsprogs/e2fsck.h b/e2fsprogs/old_e2fsprogs/e2fsck.h
index fdfa2d84a..330209d69 100644
--- a/e2fsprogs/old_e2fsprogs/e2fsck.h
+++ b/e2fsprogs/old_e2fsprogs/e2fsck.h
@@ -629,7 +629,7 @@ struct e2fsck_struct {
629}; 629};
630 630
631 631
632#define tid_gt(x, y) ((x - y) > 0) 632#define tid_gt(x, y) ((x - y) > 0)
633 633
634static inline int tid_geq(tid_t x, tid_t y) 634static inline int tid_geq(tid_t x, tid_t y)
635{ 635{
diff --git a/editors/Config.src b/editors/Config.src
index fc824ccd5..201ee6eb9 100644
--- a/editors/Config.src
+++ b/editors/Config.src
@@ -60,12 +60,6 @@ config ED
60 Small, simple, evil. Part of SUSv3. If you're not already using 60 Small, simple, evil. Part of SUSv3. If you're not already using
61 this, you don't need it. 61 this, you don't need it.
62 62
63config PATCH
64 bool "patch"
65 default y
66 help
67 Apply a unified diff formatted patch.
68
69config SED 63config SED
70 bool "sed" 64 bool "sed"
71 default y 65 default y
diff --git a/editors/Kbuild.src b/editors/Kbuild.src
index 98128064d..2f23ae12f 100644
--- a/editors/Kbuild.src
+++ b/editors/Kbuild.src
@@ -11,6 +11,5 @@ lib-$(CONFIG_AWK) += awk.o
11lib-$(CONFIG_CMP) += cmp.o 11lib-$(CONFIG_CMP) += cmp.o
12lib-$(CONFIG_DIFF) += diff.o 12lib-$(CONFIG_DIFF) += diff.o
13lib-$(CONFIG_ED) += ed.o 13lib-$(CONFIG_ED) += ed.o
14lib-$(CONFIG_PATCH) += patch.o
15lib-$(CONFIG_SED) += sed.o 14lib-$(CONFIG_SED) += sed.o
16lib-$(CONFIG_VI) += vi.o 15lib-$(CONFIG_VI) += vi.o
diff --git a/editors/awk.c b/editors/awk.c
index 8bc56756c..2eeb9d77a 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -277,10 +277,10 @@ enum {
277 277
278/* tokens and their corresponding info values */ 278/* tokens and their corresponding info values */
279 279
280#define NTC "\377" /* switch to next token class (tc<<1) */ 280#define NTC "\377" /* switch to next token class (tc<<1) */
281#define NTCC '\377' 281#define NTCC '\377'
282 282
283#define OC_B OC_BUILTIN 283#define OC_B OC_BUILTIN
284 284
285static const char tokenlist[] ALIGN1 = 285static const char tokenlist[] ALIGN1 =
286 "\1(" NTC 286 "\1(" NTC
@@ -368,7 +368,7 @@ static const uint32_t tokeninfo[] = {
368 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), 368 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b),
369 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), 369 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
370 OC_GETLINE|SV|P(0), 370 OC_GETLINE|SV|P(0),
371 0, 0, 371 0, 0,
372 0, 372 0,
373 0 /* END */ 373 0 /* END */
374}; 374};
@@ -380,7 +380,7 @@ enum {
380 ORS, RS, RT, FILENAME, 380 ORS, RS, RT, FILENAME,
381 SUBSEP, F0, ARGIND, ARGC, 381 SUBSEP, F0, ARGIND, ARGC,
382 ARGV, ERRNO, FNR, NR, 382 ARGV, ERRNO, FNR, NR,
383 NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS 383 NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS
384}; 384};
385 385
386static const char vNames[] ALIGN1 = 386static const char vNames[] ALIGN1 =
@@ -2335,7 +2335,7 @@ static var *evaluate(node *op, var *res)
2335#define fnargs (G.evaluate__fnargs) 2335#define fnargs (G.evaluate__fnargs)
2336/* seed is initialized to 1 */ 2336/* seed is initialized to 1 */
2337#define seed (G.evaluate__seed) 2337#define seed (G.evaluate__seed)
2338#define sreg (G.evaluate__sreg) 2338#define sreg (G.evaluate__sreg)
2339 2339
2340 var *v1; 2340 var *v1;
2341 2341
@@ -2611,7 +2611,7 @@ static var *evaluate(node *op, var *res)
2611 rsm->F = popen(L.s, "r"); 2611 rsm->F = popen(L.s, "r");
2612 rsm->is_pipe = TRUE; 2612 rsm->is_pipe = TRUE;
2613 } else { 2613 } else {
2614 rsm->F = fopen_for_read(L.s); /* not xfopen! */ 2614 rsm->F = fopen_for_read(L.s); /* not xfopen! */
2615 } 2615 }
2616 } 2616 }
2617 } else { 2617 } else {
diff --git a/editors/cmp.c b/editors/cmp.c
index f495da7d2..f84a56e3e 100644
--- a/editors/cmp.c
+++ b/editors/cmp.c
@@ -33,8 +33,6 @@ int cmp_main(int argc UNUSED_PARAM, char **argv)
33 unsigned opt; 33 unsigned opt;
34 int retval = 0; 34 int retval = 0;
35 35
36 xfunc_error_retval = 2; /* 1 is returned if files are different. */
37
38 opt_complementary = "-1" 36 opt_complementary = "-1"
39 IF_DESKTOP(":?4") 37 IF_DESKTOP(":?4")
40 IF_NOT_DESKTOP(":?2") 38 IF_NOT_DESKTOP(":?2")
@@ -43,8 +41,6 @@ int cmp_main(int argc UNUSED_PARAM, char **argv)
43 argv += optind; 41 argv += optind;
44 42
45 filename1 = *argv; 43 filename1 = *argv;
46 fp1 = xfopen_stdin(filename1);
47
48 if (*++argv) { 44 if (*++argv) {
49 filename2 = *argv; 45 filename2 = *argv;
50 if (ENABLE_DESKTOP && *++argv) { 46 if (ENABLE_DESKTOP && *++argv) {
@@ -55,6 +51,10 @@ int cmp_main(int argc UNUSED_PARAM, char **argv)
55 } 51 }
56 } 52 }
57 53
54 xfunc_error_retval = 2; /* missing file results in exitcode 2 */
55 if (opt & CMP_OPT_s)
56 logmode = 0; /* -s suppresses open error messages */
57 fp1 = xfopen_stdin(filename1);
58 fp2 = xfopen_stdin(filename2); 58 fp2 = xfopen_stdin(filename2);
59 if (fp1 == fp2) { /* Paranoia check... stdin == stdin? */ 59 if (fp1 == fp2) { /* Paranoia check... stdin == stdin? */
60 /* Note that we don't bother reading stdin. Neither does gnu wc. 60 /* Note that we don't bother reading stdin. Neither does gnu wc.
@@ -63,6 +63,7 @@ int cmp_main(int argc UNUSED_PARAM, char **argv)
63 */ 63 */
64 return 0; 64 return 0;
65 } 65 }
66 logmode = LOGMODE_STDIO;
66 67
67 if (opt & CMP_OPT_l) 68 if (opt & CMP_OPT_l)
68 fmt = fmt_l_opt; 69 fmt = fmt_l_opt;
diff --git a/editors/diff.c b/editors/diff.c
index d9d709db6..cc7ba472e 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -230,7 +230,7 @@ static int search(const int *c, int k, int y, const struct cand *list)
230{ 230{
231 int i, j; 231 int i, j;
232 232
233 if (list[c[k]].y < y) /* quick look for typical case */ 233 if (list[c[k]].y < y) /* quick look for typical case */
234 return k + 1; 234 return k + 1;
235 235
236 for (i = 0, j = k + 1;;) { 236 for (i = 0, j = k + 1;;) {
diff --git a/editors/patch.c b/editors/patch.c
index 33ff8b569..9c6d967b9 100644
--- a/editors/patch.c
+++ b/editors/patch.c
@@ -1,8 +1,7 @@
1/* Adapted from toybox's patch. */
2
3/* vi: set sw=4 ts=4: 1/* vi: set sw=4 ts=4:
4 * 2 *
5 * patch.c - Apply a "universal" diff. 3 * Apply a "universal" diff.
4 * Adapted from toybox's patch implementation.
6 * 5 *
7 * Copyright 2007 Rob Landley <rob@landley.net> 6 * Copyright 2007 Rob Landley <rob@landley.net>
8 * 7 *
@@ -20,30 +19,45 @@
20 * -f force (no questions asked) 19 * -f force (no questions asked)
21 * -F fuzz (number, default 2) 20 * -F fuzz (number, default 2)
22 * [file] which file to patch 21 * [file] which file to patch
22 */
23
24//applet:IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_DROP))
25
26//kbuild:lib-$(CONFIG_PATCH) += patch.o
27
28//config:config PATCH
29//config: bool "patch"
30//config: default y
31//config: help
32//config: Apply a unified diff formatted patch.
33
34//usage:#define patch_trivial_usage
35//usage: "[OPTIONS] [ORIGFILE [PATCHFILE]]"
36//usage:#define patch_full_usage "\n\n"
37//usage: IF_LONG_OPTS(
38//usage: " -p,--strip N Strip N leading components from file names"
39//usage: "\n -i,--input DIFF Read DIFF instead of stdin"
40//usage: "\n -R,--reverse Reverse patch"
41//usage: "\n -N,--forward Ignore already applied patches"
42//usage: "\n --dry-run Don't actually change files"
43//usage: "\n -E,--remove-empty-files Remove output files if they become empty"
44//usage: )
45//usage: IF_NOT_LONG_OPTS(
46//usage: " -p N Strip N leading components from file names"
47//usage: "\n -i DIFF Read DIFF instead of stdin"
48//usage: "\n -R Reverse patch"
49//usage: "\n -N Ignore already applied patches"
50//usage: "\n -E Remove output files if they become empty"
51//usage: )
52//usage:
53//usage:#define patch_example_usage
54//usage: "$ patch -p1 < example.diff\n"
55//usage: "$ patch -p0 -i example.diff"
23 56
24USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"up#i:R", TOYFLAG_USR|TOYFLAG_BIN)) 57#include "libbb.h"
25
26config PATCH
27 bool "patch"
28 default y
29 help
30 usage: patch [-i file] [-p depth] [-Ru]
31
32 Apply a unified diff to one or more files.
33 58
34 -i Input file (defaults=stdin)
35 -p number of '/' to strip from start of file paths (default=all)
36 -R Reverse patch.
37 -u Ignored (only handles "unified" diffs)
38 59
39 This version of patch only handles unified diffs, and only modifies 60// libbb candidate?
40 a file when all all hunks to that file apply. Patch prints failed
41 hunks to stderr, and exits with nonzero status if any hunks fail.
42
43 A file compared against /dev/null (or with a date <= the epoch) is
44 created or deleted if -E or --remove-empty-files set.
45*/
46#include "libbb.h"
47 61
48struct double_list { 62struct double_list {
49 struct double_list *next; 63 struct double_list *next;
@@ -51,188 +65,55 @@ struct double_list {
51 char *data; 65 char *data;
52}; 66};
53 67
54// Return the first item from the list, advancing the list (which must be called
55// as &list)
56static
57void *TOY_llist_pop(void *list)
58{
59 // I'd use a void ** for the argument, and even accept the typecast in all
60 // callers as documentation you need the &, except the stupid compiler
61 // would then scream about type-punned pointers. Screw it.
62 void **llist = (void **)list;
63 void **next = (void **)*llist;
64 *llist = *next;
65
66 return (void *)next;
67}
68
69// Free all the elements of a linked list 68// Free all the elements of a linked list
70// if freeit!=NULL call freeit() on each element before freeing it. 69// Call freeit() on each element before freeing it.
71static 70static
72void TOY_llist_free(void *list, void (*freeit)(void *data)) 71void dlist_free(struct double_list *list, void (*freeit)(void *data))
73{ 72{
74 while (list) { 73 while (list) {
75 void *pop = TOY_llist_pop(&list); 74 void *pop = list;
76 if (freeit) freeit(pop); 75 list = list->next;
77 else free(pop); 76 freeit(pop);
78 77 // Bail out also if list is circular.
79 // End doubly linked list too. 78 if (list == pop) break;
80 if (list==pop) break;
81 } 79 }
82} 80}
83//Override bbox's names
84#define llist_pop TOY_llist_pop
85#define llist_free TOY_llist_free
86 81
87// Add an entry to the end off a doubly linked list 82// Add an entry before "list" element in (circular) doubly linked list
88static 83static
89struct double_list *dlist_add(struct double_list **list, char *data) 84struct double_list *dlist_add(struct double_list **list, char *data)
90{ 85{
91 struct double_list *line = xmalloc(sizeof(struct double_list)); 86 struct double_list *llist;
87 struct double_list *line = xmalloc(sizeof(*line));
92 88
93 line->data = data; 89 line->data = data;
94 if (*list) { 90 llist = *list;
95 line->next = *list; 91 if (llist) {
96 line->prev = (*list)->prev; 92 struct double_list *p;
97 (*list)->prev->next = line; 93 line->next = llist;
98 (*list)->prev = line; 94 p = line->prev = llist->prev;
99 } else *list = line->next = line->prev = line; 95 // (list is circular, we assume p is never NULL)
96 p->next = line;
97 llist->prev = line;
98 } else
99 *list = line->next = line->prev = line;
100 100
101 return line; 101 return line;
102} 102}
103 103
104// Ensure entire path exists.
105// If mode != -1 set permissions on newly created dirs.
106// Requires that path string be writable (for temporary null terminators).
107static
108void xmkpath(char *path, int mode)
109{
110 char *p, old;
111 mode_t mask;
112 int rc;
113 struct stat st;
114
115 for (p = path; ; p++) {
116 if (!*p || *p == '/') {
117 old = *p;
118 *p = rc = 0;
119 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
120 if (mode != -1) {
121 mask = umask(0);
122 rc = mkdir(path, mode);
123 umask(mask);
124 } else rc = mkdir(path, 0777);
125 }
126 *p = old;
127 if(rc) bb_perror_msg_and_die("mkpath '%s'", path);
128 }
129 if (!*p) break;
130 }
131}
132
133// Slow, but small.
134static
135char *get_rawline(int fd, long *plen, char end)
136{
137 char c, *buf = NULL;
138 long len = 0;
139
140 for (;;) {
141 if (1>read(fd, &c, 1)) break;
142 if (!(len & 63)) buf=xrealloc(buf, len+65);
143 if ((buf[len++]=c) == end) break;
144 }
145 if (buf) buf[len]=0;
146 if (plen) *plen = len;
147
148 return buf;
149}
150
151static
152char *get_line(int fd)
153{
154 long len;
155 char *buf = get_rawline(fd, &len, '\n');
156
157 if (buf && buf[--len]=='\n') buf[len]=0;
158
159 return buf;
160}
161
162// Copy the rest of in to out and close both files.
163static
164void xsendfile(int in, int out)
165{
166 long len;
167 char buf[4096];
168
169 if (in<0) return;
170 for (;;) {
171 len = safe_read(in, buf, 4096);
172 if (len<1) break;
173 xwrite(out, buf, len);
174 }
175}
176
177// Copy the rest of the data and replace the original with the copy.
178static
179void replace_tempfile(int fdin, int fdout, char **tempname)
180{
181 char *temp = xstrdup(*tempname);
182
183 temp[strlen(temp)-6]=0;
184 if (fdin != -1) {
185 xsendfile(fdin, fdout);
186 xclose(fdin);
187 }
188 xclose(fdout);
189 rename(*tempname, temp);
190 free(*tempname);
191 free(temp);
192 *tempname = NULL;
193}
194
195// Open a temporary file to copy an existing file into.
196static
197int copy_tempfile(int fdin, char *name, char **tempname)
198{
199 struct stat statbuf;
200 int fd;
201
202 *tempname = xasprintf("%sXXXXXX", name);
203 fd = xmkstemp(*tempname);
204
205 // Set permissions of output file
206 fstat(fdin, &statbuf);
207 fchmod(fd, statbuf.st_mode);
208
209 return fd;
210}
211
212// Abort the copy and delete the temporary file.
213static
214void delete_tempfile(int fdin, int fdout, char **tempname)
215{
216 close(fdin);
217 close(fdout);
218 unlink(*tempname);
219 free(*tempname);
220 *tempname = NULL;
221}
222
223
224 104
225struct globals { 105struct globals {
226 char *infile; 106 char *infile;
227 long prefix; 107 long prefix;
228 108
229 struct double_list *current_hunk; 109 struct double_list *current_hunk;
110
230 long oldline, oldlen, newline, newlen; 111 long oldline, oldlen, newline, newlen;
231 long linenum; 112 long linenum;
232 int context, state, filein, fileout, filepatch, hunknum; 113 int context, state, hunknum;
114 int filein, fileout;
233 char *tempname; 115 char *tempname;
234 116
235 // was toys.foo:
236 int exitval; 117 int exitval;
237}; 118};
238#define TT (*ptr_to_globals) 119#define TT (*ptr_to_globals)
@@ -263,7 +144,7 @@ struct globals {
263 144
264static void do_line(void *data) 145static void do_line(void *data)
265{ 146{
266 struct double_list *dlist = (struct double_list *)data; 147 struct double_list *dlist = data;
267 148
268 if (TT.state>1 && *dlist->data != TT.state) 149 if (TT.state>1 && *dlist->data != TT.state)
269 fdprintf(TT.state == 2 ? 2 : TT.fileout, 150 fdprintf(TT.state == 2 ? 2 : TT.fileout,
@@ -272,19 +153,35 @@ static void do_line(void *data)
272 if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data); 153 if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data);
273 154
274 free(dlist->data); 155 free(dlist->data);
275 free(data); 156 free(dlist);
276} 157}
277 158
278static void finish_oldfile(void) 159static void finish_oldfile(void)
279{ 160{
280 if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname); 161 if (TT.tempname) {
162 // Copy the rest of the data and replace the original with the copy.
163 char *temp;
164
165 if (TT.filein != -1) {
166 bb_copyfd_eof(TT.filein, TT.fileout);
167 xclose(TT.filein);
168 }
169 xclose(TT.fileout);
170
171 temp = xstrdup(TT.tempname);
172 temp[strlen(temp) - 6] = '\0';
173 rename(TT.tempname, temp);
174 free(temp);
175
176 free(TT.tempname);
177 TT.tempname = NULL;
178 }
281 TT.fileout = TT.filein = -1; 179 TT.fileout = TT.filein = -1;
282} 180}
283 181
284static void fail_hunk(void) 182static void fail_hunk(void)
285{ 183{
286 if (!TT.current_hunk) return; 184 if (!TT.current_hunk) return;
287 TT.current_hunk->prev->next = 0;
288 185
289 fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline); 186 fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline);
290 TT.exitval = 1; 187 TT.exitval = 1;
@@ -293,9 +190,17 @@ static void fail_hunk(void)
293 // this file and advance to next file. 190 // this file and advance to next file.
294 191
295 TT.state = 2; 192 TT.state = 2;
296 llist_free(TT.current_hunk, do_line); 193 TT.current_hunk->prev->next = NULL;
194 dlist_free(TT.current_hunk, do_line);
297 TT.current_hunk = NULL; 195 TT.current_hunk = NULL;
298 delete_tempfile(TT.filein, TT.fileout, &TT.tempname); 196
197 // Abort the copy and delete the temporary file.
198 close(TT.filein);
199 close(TT.fileout);
200 unlink(TT.tempname);
201 free(TT.tempname);
202 TT.tempname = NULL;
203
299 TT.state = 0; 204 TT.state = 0;
300} 205}
301 206
@@ -333,8 +238,8 @@ static int apply_one_hunk(void)
333 // complete hunk. 238 // complete hunk.
334 plist = TT.current_hunk; 239 plist = TT.current_hunk;
335 buf = NULL; 240 buf = NULL;
336 if (TT.context) for (;;) { 241 if (reverse ? TT.oldlen : TT.newlen) for (;;) {
337 char *data = get_line(TT.filein); 242 char *data = xmalloc_reads(TT.filein, NULL, NULL);
338 243
339 TT.linenum++; 244 TT.linenum++;
340 245
@@ -368,7 +273,9 @@ static int apply_one_hunk(void)
368 // File ended before we found a place for this hunk. 273 // File ended before we found a place for this hunk.
369 fail_hunk(); 274 fail_hunk();
370 goto done; 275 goto done;
371 } else if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data); 276 }
277
278 if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data);
372 check = dlist_add(&buf, data); 279 check = dlist_add(&buf, data);
373 280
374 // Compare this line with next expected line of hunk. 281 // Compare this line with next expected line of hunk.
@@ -390,7 +297,8 @@ static int apply_one_hunk(void)
390 fdprintf(2, "NOT: %s\n", plist->data); 297 fdprintf(2, "NOT: %s\n", plist->data);
391 298
392 TT.state = 3; 299 TT.state = 3;
393 check = llist_pop(&buf); 300 check = buf;
301 buf = buf->next;
394 check->prev->next = buf; 302 check->prev->next = buf;
395 buf->prev = check->prev; 303 buf->prev = check->prev;
396 do_line(check); 304 do_line(check);
@@ -398,8 +306,8 @@ static int apply_one_hunk(void)
398 306
399 // If we've reached the end of the buffer without confirming a 307 // If we've reached the end of the buffer without confirming a
400 // match, read more lines. 308 // match, read more lines.
401 if (check==buf) { 309 if (check == buf) {
402 buf = 0; 310 buf = NULL;
403 break; 311 break;
404 } 312 }
405 check = buf; 313 check = buf;
@@ -417,13 +325,13 @@ static int apply_one_hunk(void)
417out: 325out:
418 // We have a match. Emit changed data. 326 // We have a match. Emit changed data.
419 TT.state = "-+"[reverse ^ dummy_revert]; 327 TT.state = "-+"[reverse ^ dummy_revert];
420 llist_free(TT.current_hunk, do_line); 328 dlist_free(TT.current_hunk, do_line);
421 TT.current_hunk = NULL; 329 TT.current_hunk = NULL;
422 TT.state = 1; 330 TT.state = 1;
423done: 331done:
424 if (buf) { 332 if (buf) {
425 buf->prev->next = NULL; 333 buf->prev->next = NULL;
426 llist_free(buf, do_line); 334 dlist_free(buf, do_line);
427 } 335 }
428 336
429 return TT.state; 337 return TT.state;
@@ -444,6 +352,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
444 int reverse, state = 0; 352 int reverse, state = 0;
445 char *oldname = NULL, *newname = NULL; 353 char *oldname = NULL, *newname = NULL;
446 char *opt_p, *opt_i; 354 char *opt_p, *opt_i;
355 long oldlen = oldlen; /* for compiler */
356 long newlen = newlen; /* for compiler */
447 357
448 INIT_TT(); 358 INIT_TT();
449 359
@@ -453,10 +363,10 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
453 TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! 363 TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative!
454 TT.filein = TT.fileout = -1; 364 TT.filein = TT.fileout = -1;
455 if (opts & FLAG_INPUT) { 365 if (opts & FLAG_INPUT) {
456 TT.filepatch = xopen_stdin(opt_i); 366 xmove_fd(xopen_stdin(opt_i), STDIN_FILENO);
457 } else { 367 } else {
458 if (argv[0] && argv[1]) { 368 if (argv[0] && argv[1]) {
459 TT.filepatch = xopen_stdin(argv[1]); 369 xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO);
460 } 370 }
461 } 371 }
462 if (argv[0]) { 372 if (argv[0]) {
@@ -468,7 +378,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
468 for(;;) { 378 for(;;) {
469 char *patchline; 379 char *patchline;
470 380
471 patchline = get_line(TT.filepatch); 381 patchline = xmalloc_fgetline(stdin);
472 if (!patchline) break; 382 if (!patchline) break;
473 383
474 // Other versions of patch accept damaged patches, 384 // Other versions of patch accept damaged patches,
@@ -483,8 +393,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
483 if (*patchline==' ' || *patchline=='+' || *patchline=='-') { 393 if (*patchline==' ' || *patchline=='+' || *patchline=='-') {
484 dlist_add(&TT.current_hunk, patchline); 394 dlist_add(&TT.current_hunk, patchline);
485 395
486 if (*patchline != '+') TT.oldlen--; 396 if (*patchline != '+') oldlen--;
487 if (*patchline != '-') TT.newlen--; 397 if (*patchline != '-') newlen--;
488 398
489 // Context line? 399 // Context line?
490 if (*patchline==' ' && state==2) TT.context++; 400 if (*patchline==' ' && state==2) TT.context++;
@@ -492,7 +402,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
492 402
493 // If we've consumed all expected hunk lines, apply the hunk. 403 // If we've consumed all expected hunk lines, apply the hunk.
494 404
495 if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); 405 if (!oldlen && !newlen) state = apply_one_hunk();
496 continue; 406 continue;
497 } 407 }
498 fail_hunk(); 408 fail_hunk();
@@ -539,11 +449,14 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
539 449
540 // Read oldline[,oldlen] +newline[,newlen] 450 // Read oldline[,oldlen] +newline[,newlen]
541 451
542 TT.oldlen = TT.newlen = 1; 452 TT.oldlen = oldlen = TT.newlen = newlen = 1;
543 TT.oldline = strtol(s, &s, 10); 453 TT.oldline = strtol(s, &s, 10);
544 if (*s == ',') TT.oldlen=strtol(s+1, &s, 10); 454 if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10);
545 TT.newline = strtol(s+2, &s, 10); 455 TT.newline = strtol(s+2, &s, 10);
546 if (*s == ',') TT.newlen = strtol(s+1, &s, 10); 456 if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10);
457
458 if (oldlen < 1 && newlen < 1)
459 bb_error_msg_and_die("Really? %s", patchline);
547 460
548 TT.context = 0; 461 TT.context = 0;
549 state = 2; 462 state = 2;
@@ -553,8 +466,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
553 int oldsum, newsum, empty = 0; 466 int oldsum, newsum, empty = 0;
554 char *name; 467 char *name;
555 468
556 oldsum = TT.oldline + TT.oldlen; 469 oldsum = TT.oldline + oldlen;
557 newsum = TT.newline + TT.newlen; 470 newsum = TT.newline + newlen;
558 471
559 name = reverse ? oldname : newname; 472 name = reverse ? oldname : newname;
560 473
@@ -588,13 +501,15 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
588 } 501 }
589 // If we've got a file to open, do so. 502 // If we've got a file to open, do so.
590 } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { 503 } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) {
504 struct stat statbuf;
505
591 // If the old file was null, we're creating a new one. 506 // If the old file was null, we're creating a new one.
592 if (!strcmp(oldname, "/dev/null") || !oldsum) { 507 if (!strcmp(oldname, "/dev/null") || !oldsum) {
593 printf("creating %s\n", name); 508 printf("creating %s\n", name);
594 s = strrchr(name, '/'); 509 s = strrchr(name, '/');
595 if (s) { 510 if (s) {
596 *s = 0; 511 *s = 0;
597 xmkpath(name, -1); 512 bb_make_directory(name, -1, FILEUTILS_RECUR);
598 *s = '/'; 513 *s = '/';
599 } 514 }
600 TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); 515 TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR);
@@ -602,7 +517,13 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
602 printf("patching file %s\n", name); 517 printf("patching file %s\n", name);
603 TT.filein = xopen(name, O_RDONLY); 518 TT.filein = xopen(name, O_RDONLY);
604 } 519 }
605 TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname); 520
521 TT.tempname = xasprintf("%sXXXXXX", name);
522 TT.fileout = xmkstemp(TT.tempname);
523 // Set permissions of output file
524 fstat(TT.filein, &statbuf);
525 fchmod(TT.fileout, statbuf.st_mode);
526
606 TT.linenum = 0; 527 TT.linenum = 0;
607 TT.hunknum = 0; 528 TT.hunknum = 0;
608 } 529 }
@@ -620,7 +541,6 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
620 finish_oldfile(); 541 finish_oldfile();
621 542
622 if (ENABLE_FEATURE_CLEAN_UP) { 543 if (ENABLE_FEATURE_CLEAN_UP) {
623 close(TT.filepatch);
624 free(oldname); 544 free(oldname);
625 free(newname); 545 free(newname);
626 } 546 }
diff --git a/editors/sed.c b/editors/sed.c
index 964d0405e..b91acfb7f 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -117,9 +117,9 @@ struct globals {
117 char *add_cmd_line; 117 char *add_cmd_line;
118 118
119 struct pipeline { 119 struct pipeline {
120 char *buf; /* Space to hold string */ 120 char *buf; /* Space to hold string */
121 int idx; /* Space used */ 121 int idx; /* Space used */
122 int len; /* Space allocated */ 122 int len; /* Space allocated */
123 } pipeline; 123 } pipeline;
124} FIX_ALIASING; 124} FIX_ALIASING;
125#define G (*(struct globals*)&bb_common_bufsiz1) 125#define G (*(struct globals*)&bb_common_bufsiz1)
diff --git a/examples/depmod.pl b/examples/depmod.pl
index 8c6548d28..f324b121a 100755
--- a/examples/depmod.pl
+++ b/examples/depmod.pl
@@ -173,6 +173,9 @@ sub add_mod_deps
173 173
174 $depth .= " "; 174 $depth .= " ";
175 warn "${depth}loading deps of module: $this_module\n" if $verbose; 175 warn "${depth}loading deps of module: $this_module\n" if $verbose;
176 if (length($depth) > 50) {
177 die "too much recursion (circular dependencies in modules?)";
178 }
176 179
177 foreach my $md (keys %{$mod->{$this_module}}) { 180 foreach my $md (keys %{$mod->{$this_module}}) {
178 add_mod_deps ($depth, $mod, $mod2, $module, $md); 181 add_mod_deps ($depth, $mod, $mod2, $module, $md);
diff --git a/examples/var_service/README b/examples/var_service/README
new file mode 100644
index 000000000..06817c8bc
--- /dev/null
+++ b/examples/var_service/README
@@ -0,0 +1,59 @@
1In many cases, network configuration makes it necessary to run several daemons:
2dhcp, zeroconf, ppp, openvpn and such. They need to be controlled,
3and in many cases you also want to babysit them. runsvdir is a good tool for this.
4examples/var_service directory provides a few examples. It is meant to be used
5this way: copy it somewhere (say, /var/service) and run something like
6
7env - PATH=... <other vars=...> runsvdir /var/service &
8
9from one of system startup scripts. (Google "man runsvdir" and "man runsv"
10for more info about these tools).
11
12Some existing examples:
13
14var_service/dhcp_if -
15controls a udhcpc instance which provides dhpc-assigned IP
16address on interface named "if". Copy/rename this directory as needed to run
17udhcpc on other interfaces (var_service/dhcp_if/run script uses _foo suffix
18of the parent directory as interface name). When IP address is obtained or lost,
19var_service/dhcp_if/dhcp_handler is run. It saves new config data to
20/var/run/service/fw/dhcp_if.ipconf and (re)starts /var/service/fw service.
21This example can be used as a template for other dynamic network link services
22(ppp/vpn/zcip).
23
24var_service/ifplugd_if -
25watches link status of interface if. Downs and ups /var/service/dhcp_if
26service accordingly. In effect, it allows you to unplug/plug-to-different-network
27and have your IP properly re-negotiated at once.
28
29var_service/dhcp_if_pinger -
30Uses var_service/dhcp_if's data (/var/service/dhcp_if/dhcp_if.out file)
31to determine router IP. Pings it. If ping fails, restarts /var/service/dhcp_if
32service. Basically, an example of watchdog service for networks
33which are not reliable and need babysitting.
34
35var_service/fw -
36A *one-shot* service which reconfigures network based on current known state
37of ALL interfaces. Uses conf/*.ipconf (static config) and /var/run/service/fw/*.ipconf
38(dynamic config from dhcp/ppp/vpn/etc) to determine what to do.
39One-shot-ness of this service means that it shuts itself off after single run.
40IOW: it is not a constantly running daemon sort of thing.
41It starts, it configures the network, it shuts down, all done
42(unlike infamous NetworkManagers which sit in RAM forever, doing hell knows what).
43
44However, any dhcp/ppp/vpn or similar service can restart it anytime
45when it senses the change in network configuration.
46This even works while fw service runs: if dhcp signals fw to (re)start
47while fw runs, fw will not stop after its execution, but will re-execute once,
48picking up dhcp's new configuration.
49This is achieved very simply by having
50# Make ourself one-shot
51sv o .
52at the very beginning of fw/run script, not at the end.
53Therefore, any "sv u /var/run/service/fw" command by any other
54script "undoes" o(ne-shot) command if fw still runs, thus
55runsv will rerun it; or start it in a normal way if fw is not running.
56
57System administrators are expected to edit fw/run script, since
58network configuration needs are likely to be very complex and different
59for non-trivial installations.
diff --git a/include/applets.src.h b/include/applets.src.h
index 879dbf760..261ef2333 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -16,6 +16,8 @@ s - suid type:
16 and is run by non-root (applet_main() will not be called at all) 16 and is run by non-root (applet_main() will not be called at all)
17 _BB_SUID_DROP: will drop suid prior to applet_main() 17 _BB_SUID_DROP: will drop suid prior to applet_main()
18 _BB_SUID_MAYBE: neither of the above 18 _BB_SUID_MAYBE: neither of the above
19 (every instance of _BB_SUID_REQUIRE and _BB_SUID_MAYBE
20 needs to be justified in comment)
19*/ 21*/
20 22
21#if defined(PROTOTYPES) 23#if defined(PROTOTYPES)
@@ -56,6 +58,11 @@ s - suid type:
56# define APPLET_NOFORK(name,main,l,s,name2) { #name, #main, l, s, 1, 1 }, 58# define APPLET_NOFORK(name,main,l,s,name2) { #name, #main, l, s, 1, 1 },
57#endif 59#endif
58 60
61#if ENABLE_INSTALL_NO_USR
62# define _BB_DIR_USR_BIN _BB_DIR_BIN
63# define _BB_DIR_USR_SBIN _BB_DIR_SBIN
64#endif
65
59 66
60INSERT 67INSERT
61IF_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_DROP, test)) 68IF_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_DROP, test))
@@ -95,6 +102,7 @@ IF_COMM(APPLET(comm, _BB_DIR_USR_BIN, _BB_SUID_DROP))
95IF_CP(APPLET_NOEXEC(cp, cp, _BB_DIR_BIN, _BB_SUID_DROP, cp)) 102IF_CP(APPLET_NOEXEC(cp, cp, _BB_DIR_BIN, _BB_SUID_DROP, cp))
96IF_CPIO(APPLET(cpio, _BB_DIR_BIN, _BB_SUID_DROP)) 103IF_CPIO(APPLET(cpio, _BB_DIR_BIN, _BB_SUID_DROP))
97IF_CROND(APPLET(crond, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 104IF_CROND(APPLET(crond, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
105/* Needs to be run by root or be suid root - needs to change /var/spool/cron* files: */
98IF_CRONTAB(APPLET(crontab, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) 106IF_CRONTAB(APPLET(crontab, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE))
99IF_CRYPTPW(APPLET(cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 107IF_CRYPTPW(APPLET(cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP))
100IF_CUT(APPLET_NOEXEC(cut, cut, _BB_DIR_USR_BIN, _BB_SUID_DROP, cut)) 108IF_CUT(APPLET_NOEXEC(cut, cut, _BB_DIR_USR_BIN, _BB_SUID_DROP, cut))
@@ -110,6 +118,7 @@ IF_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
110IF_DIFF(APPLET(diff, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 118IF_DIFF(APPLET(diff, _BB_DIR_USR_BIN, _BB_SUID_DROP))
111IF_DIRNAME(APPLET_NOFORK(dirname, dirname, _BB_DIR_USR_BIN, _BB_SUID_DROP, dirname)) 119IF_DIRNAME(APPLET_NOFORK(dirname, dirname, _BB_DIR_USR_BIN, _BB_SUID_DROP, dirname))
112IF_DMESG(APPLET(dmesg, _BB_DIR_BIN, _BB_SUID_DROP)) 120IF_DMESG(APPLET(dmesg, _BB_DIR_BIN, _BB_SUID_DROP))
121/* Why _BB_SUID_REQUIRE? */
113IF_DNSD(APPLET(dnsd, _BB_DIR_USR_SBIN, _BB_SUID_REQUIRE)) 122IF_DNSD(APPLET(dnsd, _BB_DIR_USR_SBIN, _BB_SUID_REQUIRE))
114IF_HOSTNAME(APPLET_ODDNAME(dnsdomainname, hostname, _BB_DIR_BIN, _BB_SUID_DROP, dnsdomainname)) 123IF_HOSTNAME(APPLET_ODDNAME(dnsdomainname, hostname, _BB_DIR_BIN, _BB_SUID_DROP, dnsdomainname))
115IF_DOS2UNIX(APPLET_NOEXEC(dos2unix, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP, dos2unix)) 124IF_DOS2UNIX(APPLET_NOEXEC(dos2unix, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP, dos2unix))
@@ -137,6 +146,7 @@ IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_DROP, fdfl
137IF_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 146IF_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_DROP))
138IF_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_DROP)) 147IF_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_DROP))
139IF_FGCONSOLE(APPLET(fgconsole, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 148IF_FGCONSOLE(APPLET(fgconsole, _BB_DIR_USR_BIN, _BB_SUID_DROP))
149/* Benefits from suid root: better access to /dev/BLOCKDEVs: */
140IF_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE)) 150IF_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE))
141IF_FLASH_ERASEALL(APPLET(flash_eraseall, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 151IF_FLASH_ERASEALL(APPLET(flash_eraseall, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
142IF_FLASH_LOCK(APPLET_ODDNAME(flash_lock, flash_lock_unlock, _BB_DIR_USR_SBIN, _BB_SUID_DROP, flash_lock)) 152IF_FLASH_LOCK(APPLET_ODDNAME(flash_lock, flash_lock_unlock, _BB_DIR_USR_SBIN, _BB_SUID_DROP, flash_lock))
@@ -188,7 +198,9 @@ IF_IP(APPLET(ip, _BB_DIR_BIN, _BB_SUID_DROP))
188#endif 198#endif
189IF_IPADDR(APPLET(ipaddr, _BB_DIR_BIN, _BB_SUID_DROP)) 199IF_IPADDR(APPLET(ipaddr, _BB_DIR_BIN, _BB_SUID_DROP))
190IF_IPCALC(APPLET(ipcalc, _BB_DIR_BIN, _BB_SUID_DROP)) 200IF_IPCALC(APPLET(ipcalc, _BB_DIR_BIN, _BB_SUID_DROP))
201/* Why _BB_SUID_REQUIRE? On Fedora, it isn't suid root */
191IF_IPCRM(APPLET(ipcrm, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) 202IF_IPCRM(APPLET(ipcrm, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE))
203/* Why _BB_SUID_REQUIRE? On Fedora, it isn't suid root */
192IF_IPCS(APPLET(ipcs, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) 204IF_IPCS(APPLET(ipcs, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE))
193IF_IPLINK(APPLET(iplink, _BB_DIR_BIN, _BB_SUID_DROP)) 205IF_IPLINK(APPLET(iplink, _BB_DIR_BIN, _BB_SUID_DROP))
194IF_IPROUTE(APPLET(iproute, _BB_DIR_BIN, _BB_SUID_DROP)) 206IF_IPROUTE(APPLET(iproute, _BB_DIR_BIN, _BB_SUID_DROP))
@@ -209,6 +221,7 @@ IF_LOAD_POLICY(APPLET(load_policy, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
209IF_LOADFONT(APPLET(loadfont, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 221IF_LOADFONT(APPLET(loadfont, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
210IF_LOADKMAP(APPLET(loadkmap, _BB_DIR_SBIN, _BB_SUID_DROP)) 222IF_LOADKMAP(APPLET(loadkmap, _BB_DIR_SBIN, _BB_SUID_DROP))
211IF_LOGGER(APPLET(logger, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 223IF_LOGGER(APPLET(logger, _BB_DIR_USR_BIN, _BB_SUID_DROP))
224/* Needs to be run by root or be suid root - needs to change uid and gid: */
212IF_LOGIN(APPLET(login, _BB_DIR_BIN, _BB_SUID_REQUIRE)) 225IF_LOGIN(APPLET(login, _BB_DIR_BIN, _BB_SUID_REQUIRE))
213IF_LOGNAME(APPLET_NOFORK(logname, logname, _BB_DIR_USR_BIN, _BB_SUID_DROP, logname)) 226IF_LOGNAME(APPLET_NOFORK(logname, logname, _BB_DIR_USR_BIN, _BB_SUID_DROP, logname))
214IF_LOGREAD(APPLET(logread, _BB_DIR_SBIN, _BB_SUID_DROP)) 227IF_LOGREAD(APPLET(logread, _BB_DIR_SBIN, _BB_SUID_DROP))
@@ -245,6 +258,10 @@ IF_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP, mkp
245IF_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_DROP)) 258IF_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_DROP))
246IF_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_DROP)) 259IF_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_DROP))
247IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP)) 260IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP))
261/* On full-blown systems, requires suid for user mounts.
262 * But it's not unthinkable to have it available in non-suid flavor on some systems,
263 * for viewing mount table.
264 * Therefore we use _BB_SUID_MAYBE instead of _BB_SUID_REQUIRE: */
248IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP))) 265IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP)))
249IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP)) 266IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP))
250IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_DROP)) 267IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_DROP))
@@ -253,19 +270,16 @@ IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP))
253IF_NC(APPLET(nc, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 270IF_NC(APPLET(nc, _BB_DIR_USR_BIN, _BB_SUID_DROP))
254IF_NETSTAT(APPLET(netstat, _BB_DIR_BIN, _BB_SUID_DROP)) 271IF_NETSTAT(APPLET(netstat, _BB_DIR_BIN, _BB_SUID_DROP))
255IF_NICE(APPLET(nice, _BB_DIR_BIN, _BB_SUID_DROP)) 272IF_NICE(APPLET(nice, _BB_DIR_BIN, _BB_SUID_DROP))
256IF_NMETER(APPLET(nmeter, _BB_DIR_USR_BIN, _BB_SUID_DROP))
257IF_NOHUP(APPLET(nohup, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 273IF_NOHUP(APPLET(nohup, _BB_DIR_USR_BIN, _BB_SUID_DROP))
258IF_NSLOOKUP(APPLET(nslookup, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 274IF_NSLOOKUP(APPLET(nslookup, _BB_DIR_USR_BIN, _BB_SUID_DROP))
259IF_NTPD(APPLET(ntpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) 275IF_NTPD(APPLET(ntpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP))
260IF_OD(APPLET(od, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 276IF_OD(APPLET(od, _BB_DIR_USR_BIN, _BB_SUID_DROP))
261IF_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 277IF_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_DROP))
262//IF_PARSE(APPLET(parse, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 278//IF_PARSE(APPLET(parse, _BB_DIR_USR_BIN, _BB_SUID_DROP))
279/* Needs to be run by root or be suid root - needs to change /etc/{passwd,shadow}: */
263IF_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) 280IF_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE))
264IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_DROP))
265IF_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 281IF_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP))
266IF_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_DROP)) 282IF_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_DROP))
267IF_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE))
268IF_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_MAYBE))
269IF_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_DROP)) 283IF_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_DROP))
270IF_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_DROP)) 284IF_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_DROP))
271IF_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP, pkill)) 285IF_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP, pkill))
@@ -322,7 +336,7 @@ IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DR
322IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum)) 336IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum))
323IF_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 337IF_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_DROP))
324IF_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_DROP)) 338IF_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_DROP))
325/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */ 339/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells: */
326IF_SLEEP(APPLET(sleep, _BB_DIR_BIN, _BB_SUID_DROP)) 340IF_SLEEP(APPLET(sleep, _BB_DIR_BIN, _BB_SUID_DROP))
327IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, softlimit)) 341IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, softlimit))
328IF_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_DROP, sort)) 342IF_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_DROP, sort))
@@ -331,6 +345,7 @@ IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, _BB_DI
331IF_STAT(APPLET(stat, _BB_DIR_BIN, _BB_SUID_DROP)) 345IF_STAT(APPLET(stat, _BB_DIR_BIN, _BB_SUID_DROP))
332IF_STRINGS(APPLET(strings, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 346IF_STRINGS(APPLET(strings, _BB_DIR_USR_BIN, _BB_SUID_DROP))
333IF_STTY(APPLET(stty, _BB_DIR_BIN, _BB_SUID_DROP)) 347IF_STTY(APPLET(stty, _BB_DIR_BIN, _BB_SUID_DROP))
348/* Needs to be run by root or be suid root - needs to change uid and gid: */
334IF_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_REQUIRE)) 349IF_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_REQUIRE))
335IF_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_DROP)) 350IF_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_DROP))
336IF_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 351IF_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_DROP))
@@ -359,8 +374,8 @@ IF_TFTPD(APPLET(tftpd, _BB_DIR_USR_BIN, _BB_SUID_DROP))
359IF_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 374IF_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_DROP))
360IF_TIMEOUT(APPLET(timeout, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 375IF_TIMEOUT(APPLET(timeout, _BB_DIR_USR_BIN, _BB_SUID_DROP))
361IF_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 376IF_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_DROP))
362IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch))
363IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 377IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP))
378/* Needs socket(AF_INET, SOCK_RAW, IPPROTO_ICMP), therefore _BB_SUID_MAYBE: */
364IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) 379IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE))
365IF_TRACEROUTE6(APPLET(traceroute6, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) 380IF_TRACEROUTE6(APPLET(traceroute6, _BB_DIR_USR_BIN, _BB_SUID_MAYBE))
366IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true)) 381IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true))
@@ -387,8 +402,10 @@ IF_UUDECODE(APPLET(uudecode, _BB_DIR_USR_BIN, _BB_SUID_DROP))
387IF_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 402IF_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_DROP))
388IF_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) 403IF_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_DROP))
389IF_VI(APPLET(vi, _BB_DIR_BIN, _BB_SUID_DROP)) 404IF_VI(APPLET(vi, _BB_DIR_BIN, _BB_SUID_DROP))
405/* Needs to be run by root or be suid root - needs to change uid and gid: */
390IF_VLOCK(APPLET(vlock, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) 406IF_VLOCK(APPLET(vlock, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE))
391IF_VOLNAME(APPLET(volname, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 407IF_VOLNAME(APPLET(volname, _BB_DIR_USR_BIN, _BB_SUID_DROP))
408/* Needs to be run by root or be suid root - needs to write to /dev/TTY: */
392IF_WALL(APPLET(wall, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) 409IF_WALL(APPLET(wall, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE))
393IF_WATCH(APPLET(watch, _BB_DIR_BIN, _BB_SUID_DROP)) 410IF_WATCH(APPLET(watch, _BB_DIR_BIN, _BB_SUID_DROP))
394IF_WATCHDOG(APPLET(watchdog, _BB_DIR_SBIN, _BB_SUID_DROP)) 411IF_WATCHDOG(APPLET(watchdog, _BB_DIR_SBIN, _BB_SUID_DROP))
diff --git a/include/unarchive.h b/include/archive.h
index b55af6d9d..ba6d323e0 100644
--- a/include/unarchive.h
+++ b/include/archive.h
@@ -193,7 +193,9 @@ extern const llist_t *find_list_entry2(const llist_t *list, const char *filename
193 193
194/* A bit of bunzip2 internals are exposed for compressed help support: */ 194/* A bit of bunzip2 internals are exposed for compressed help support: */
195typedef struct bunzip_data bunzip_data; 195typedef struct bunzip_data bunzip_data;
196int start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *inbuf, int len) FAST_FUNC; 196int start_bunzip(bunzip_data **bdp, int in_fd, const void *inbuf, int len) FAST_FUNC;
197/* NB: read_bunzip returns < 0 on error, or the number of *unfilled* bytes
198 * in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0: */
197int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; 199int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC;
198void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; 200void dealloc_bunzip(bunzip_data *bd) FAST_FUNC;
199 201
diff --git a/include/grp_.h b/include/grp_.h
index 7a95f88a6..5c24d558a 100644
--- a/include/grp_.h
+++ b/include/grp_.h
@@ -18,7 +18,7 @@
18 02111-1307 USA. 18 02111-1307 USA.
19 */ 19 */
20/* 20/*
21 * POSIX Standard: 9.2.1 Group Database Access <grp.h> 21 * POSIX Standard: 9.2.1 Group Database Access <grp.h>
22 */ 22 */
23#ifndef BB_GRP_H 23#ifndef BB_GRP_H
24#define BB_GRP_H 1 24#define BB_GRP_H 1
diff --git a/include/libbb.h b/include/libbb.h
index 715f1e102..fdd920f3c 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1440,6 +1440,7 @@ typedef struct procps_status_t {
1440 char *argv0; 1440 char *argv0;
1441 char *exe; 1441 char *exe;
1442 IF_SELINUX(char *context;) 1442 IF_SELINUX(char *context;)
1443 IF_FEATURE_SHOW_THREADS(unsigned main_thread_pid;)
1443 /* Everything below must contain no ptrs to malloc'ed data: 1444 /* Everything below must contain no ptrs to malloc'ed data:
1444 * it is memset(0) for each process in procps_scan() */ 1445 * it is memset(0) for each process in procps_scan() */
1445 unsigned long vsz, rss; /* we round it to kbytes */ 1446 unsigned long vsz, rss; /* we round it to kbytes */
diff --git a/archival/liblzo_interface.h b/include/liblzo_interface.h
index 9a84c0b6b..9a84c0b6b 100644
--- a/archival/liblzo_interface.h
+++ b/include/liblzo_interface.h
diff --git a/include/platform.h b/include/platform.h
index 04fee8d03..5f49deb41 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -165,7 +165,7 @@
165# include <sex.h> 165# include <sex.h>
166#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ 166#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
167 || defined(__APPLE__) 167 || defined(__APPLE__)
168# include <sys/resource.h> /* rlimit */ 168# include <sys/resource.h> /* rlimit */
169# include <machine/endian.h> 169# include <machine/endian.h>
170# define bswap_64 __bswap64 170# define bswap_64 __bswap64
171# define bswap_32 __bswap32 171# define bswap_32 __bswap32
diff --git a/include/pwd_.h b/include/pwd_.h
index aa63ac940..e40b71dab 100644
--- a/include/pwd_.h
+++ b/include/pwd_.h
@@ -18,7 +18,7 @@
18 02111-1307 USA. */ 18 02111-1307 USA. */
19 19
20/* 20/*
21 * POSIX Standard: 9.2.2 User Database Access <pwd.h> 21 * POSIX Standard: 9.2.2 User Database Access <pwd.h>
22 */ 22 */
23 23
24#ifndef BB_PWD_H 24#ifndef BB_PWD_H
diff --git a/include/rtc_.h b/include/rtc_.h
index bd322c940..750fc20ec 100644
--- a/include/rtc_.h
+++ b/include/rtc_.h
@@ -35,9 +35,9 @@ struct linux_rtc_time {
35}; 35};
36 36
37struct linux_rtc_wkalrm { 37struct linux_rtc_wkalrm {
38 unsigned char enabled; /* 0 = alarm disabled, 1 = alarm enabled */ 38 unsigned char enabled; /* 0 = alarm disabled, 1 = alarm enabled */
39 unsigned char pending; /* 0 = alarm not pending, 1 = alarm pending */ 39 unsigned char pending; /* 0 = alarm not pending, 1 = alarm pending */
40 struct linux_rtc_time time; /* time the alarm is set to */ 40 struct linux_rtc_time time; /* time the alarm is set to */
41}; 41};
42 42
43/* 43/*
diff --git a/include/usage.src.h b/include/usage.src.h
index 6973c93ef..ea0e6a452 100644
--- a/include/usage.src.h
+++ b/include/usage.src.h
@@ -592,35 +592,6 @@ INSERT
592 "\n -i Prompt before overwrite" \ 592 "\n -i Prompt before overwrite" \
593 "\n -l,-s Create (sym)links" \ 593 "\n -l,-s Create (sym)links" \
594 594
595#define cpio_trivial_usage \
596 "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]") \
597 " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]")
598#define cpio_full_usage "\n\n" \
599 "Extract or list files from a cpio archive" \
600 IF_FEATURE_CPIO_O(", or" \
601 "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)") \
602 " using file list on stdin" \
603 ) \
604 "\n" \
605 "\nMain operation mode:" \
606 "\n -t List" \
607 "\n -i Extract" \
608 IF_FEATURE_CPIO_O( \
609 "\n -o Create (requires -H newc)" \
610 ) \
611 IF_FEATURE_CPIO_P( \
612 "\n -p DIR Copy files to DIR" \
613 ) \
614 "\nOptions:" \
615 "\n -d Make leading directories" \
616 "\n -m Preserve mtime" \
617 "\n -v Verbose" \
618 "\n -u Overwrite" \
619 "\n -F FILE Input (-t,-i,-p) or output (-o) file" \
620 IF_FEATURE_CPIO_O( \
621 "\n -H newc Archive format" \
622 ) \
623
624#define crond_trivial_usage \ 595#define crond_trivial_usage \
625 "-fbS -l N " IF_FEATURE_CROND_D("-d N ") "-L LOGFILE -c DIR" 596 "-fbS -l N " IF_FEATURE_CROND_D("-d N ") "-L LOGFILE -c DIR"
626#define crond_full_usage "\n\n" \ 597#define crond_full_usage "\n\n" \
@@ -1577,8 +1548,8 @@ INSERT
1577 "\n -c One-byte character display" \ 1548 "\n -c One-byte character display" \
1578 "\n -C Canonical hex+ASCII, 16 bytes per line" \ 1549 "\n -C Canonical hex+ASCII, 16 bytes per line" \
1579 "\n -d Two-byte decimal display" \ 1550 "\n -d Two-byte decimal display" \
1580 "\n -e FORMAT STRING" \ 1551 "\n -e FORMAT_STRING" \
1581 "\n -f FORMAT FILE" \ 1552 "\n -f FORMAT_FILE" \
1582 "\n -n LENGTH Interpret only LENGTH bytes of input" \ 1553 "\n -n LENGTH Interpret only LENGTH bytes of input" \
1583 "\n -o Two-byte octal display" \ 1554 "\n -o Two-byte octal display" \
1584 "\n -s OFFSET Skip OFFSET bytes" \ 1555 "\n -s OFFSET Skip OFFSET bytes" \
@@ -2044,9 +2015,6 @@ INSERT
2044#define linux64_trivial_usage NOUSAGE_STR 2015#define linux64_trivial_usage NOUSAGE_STR
2045#define linux64_full_usage "" 2016#define linux64_full_usage ""
2046 2017
2047#define linuxrc_trivial_usage NOUSAGE_STR
2048#define linuxrc_full_usage ""
2049
2050#define setarch_trivial_usage \ 2018#define setarch_trivial_usage \
2051 "personality PROG ARGS" 2019 "personality PROG ARGS"
2052#define setarch_full_usage "\n\n" \ 2020#define setarch_full_usage "\n\n" \
@@ -2176,67 +2144,6 @@ INSERT
2176 "\n -h Print banner page too" \ 2144 "\n -h Print banner page too" \
2177 "\n -V Verbose" \ 2145 "\n -V Verbose" \
2178 2146
2179#define ls_trivial_usage \
2180 "[-1Aa" IF_FEATURE_LS_TIMESTAMPS("c") "Cd" \
2181 IF_FEATURE_LS_TIMESTAMPS("e") IF_FEATURE_LS_FILETYPES("F") "iln" \
2182 IF_FEATURE_LS_FILETYPES("p") IF_FEATURE_LS_FOLLOWLINKS("L") \
2183 IF_FEATURE_LS_RECURSIVE("R") IF_FEATURE_LS_SORTFILES("rS") "s" \
2184 IF_FEATURE_AUTOWIDTH("T") IF_FEATURE_LS_TIMESTAMPS("tu") \
2185 IF_FEATURE_LS_SORTFILES("v") IF_FEATURE_AUTOWIDTH("w") "x" \
2186 IF_FEATURE_LS_SORTFILES("X") IF_FEATURE_HUMAN_READABLE("h") "k" \
2187 IF_SELINUX("K") "] [FILE]..."
2188#define ls_full_usage "\n\n" \
2189 "List directory contents\n" \
2190 "\nOptions:" \
2191 "\n -1 List in a single column" \
2192 "\n -A Don't list . and .." \
2193 "\n -a Don't hide entries starting with ." \
2194 "\n -C List by columns" \
2195 IF_FEATURE_LS_TIMESTAMPS( \
2196 "\n -c With -l: sort by ctime") \
2197 IF_FEATURE_LS_COLOR( \
2198 "\n --color[={always,never,auto}] Control coloring") \
2199 "\n -d List directory entries instead of contents" \
2200 IF_FEATURE_LS_TIMESTAMPS( \
2201 "\n -e List full date and time") \
2202 IF_FEATURE_LS_FILETYPES( \
2203 "\n -F Append indicator (one of */=@|) to entries") \
2204 "\n -i List inode numbers" \
2205 "\n -l Long listing format" \
2206 "\n -n List numeric UIDs and GIDs instead of names" \
2207 IF_FEATURE_LS_FILETYPES( \
2208 "\n -p Append indicator (one of /=@|) to entries") \
2209 IF_FEATURE_LS_FOLLOWLINKS( \
2210 "\n -L List entries pointed to by symlinks") \
2211 IF_FEATURE_LS_RECURSIVE( \
2212 "\n -R Recurse") \
2213 IF_FEATURE_LS_SORTFILES( \
2214 "\n -r Sort in reverse order") \
2215 IF_FEATURE_LS_SORTFILES( \
2216 "\n -S Sort by file size") \
2217 "\n -s List the size of each file, in blocks" \
2218 IF_FEATURE_AUTOWIDTH( \
2219 "\n -T N Assume tabstop every N columns") \
2220 IF_FEATURE_LS_TIMESTAMPS( \
2221 "\n -t With -l: sort by modification time") \
2222 IF_FEATURE_LS_TIMESTAMPS( \
2223 "\n -u With -l: sort by access time") \
2224 IF_FEATURE_LS_SORTFILES( \
2225 "\n -v Sort by version") \
2226 IF_FEATURE_AUTOWIDTH( \
2227 "\n -w N Assume the terminal is N columns wide") \
2228 "\n -x List by lines" \
2229 IF_FEATURE_LS_SORTFILES( \
2230 "\n -X Sort by extension") \
2231 IF_FEATURE_HUMAN_READABLE( \
2232 "\n -h List sizes in human readable format (1K 243M 2G)") \
2233 IF_SELINUX( \
2234 "\n -k List security context") \
2235 IF_SELINUX( \
2236 "\n -K List security context in long format") \
2237 IF_SELINUX( \
2238 "\n -Z List security context and permission") \
2239
2240#define lsattr_trivial_usage \ 2147#define lsattr_trivial_usage \
2241 "[-Radlv] [FILE]..." 2148 "[-Radlv] [FILE]..."
2242#define lsattr_full_usage "\n\n" \ 2149#define lsattr_full_usage "\n\n" \
@@ -2709,31 +2616,6 @@ INSERT
2709 " or\n" \ 2616 " or\n" \
2710 "$ nameif -c /etc/my_mactab_file\n" \ 2617 "$ nameif -c /etc/my_mactab_file\n" \
2711 2618
2712#define nmeter_trivial_usage \
2713 "format_string"
2714#define nmeter_full_usage "\n\n" \
2715 "Monitor system in real time\n\n" \
2716 "Format specifiers:\n" \
2717 " %Nc or %[cN] Monitor CPU. N - bar size, default 10\n" \
2718 " (displays: S:system U:user N:niced D:iowait I:irq i:softirq)\n" \
2719 " %[niface] Monitor network interface 'iface'\n" \
2720 " %m Monitor allocated memory\n" \
2721 " %[mf] Monitor free memory\n" \
2722 " %[mt] Monitor total memory\n" \
2723 " %s Monitor allocated swap\n" \
2724 " %f Monitor number of used file descriptors\n" \
2725 " %Ni Monitor total/specific IRQ rate\n" \
2726 " %x Monitor context switch rate\n" \
2727 " %p Monitor forks\n" \
2728 " %[pn] Monitor # of processes\n" \
2729 " %b Monitor block io\n" \
2730 " %Nt Show time (with N decimal points)\n" \
2731 " %Nd Milliseconds between updates (default:1000)\n" \
2732 " %r Print <cr> instead of <lf> at EOL" \
2733
2734#define nmeter_example_usage \
2735 "nmeter '%250d%t %20c int %i bio %b mem %m forks%p'"
2736
2737#define nohup_trivial_usage \ 2619#define nohup_trivial_usage \
2738 "PROG ARGS" 2620 "PROG ARGS"
2739#define nohup_full_usage "\n\n" \ 2621#define nohup_full_usage "\n\n" \
@@ -2820,29 +2702,6 @@ INSERT
2820 "\n -m Use MD5 encryption instead of DES" \ 2702 "\n -m Use MD5 encryption instead of DES" \
2821 ) 2703 )
2822 2704
2823#define patch_trivial_usage \
2824 "[OPTIONS] [ORIGFILE [PATCHFILE]]"
2825#define patch_full_usage "\n\n" \
2826 IF_LONG_OPTS( \
2827 " -p,--strip N Strip N leading components from file names" \
2828 "\n -i,--input DIFF Read DIFF instead of stdin" \
2829 "\n -R,--reverse Reverse patch" \
2830 "\n -N,--forward Ignore already applied patches" \
2831 "\n --dry-run Don't actually change files" \
2832 "\n -E,--remove-empty-files Remove output files if they become empty" \
2833 ) \
2834 IF_NOT_LONG_OPTS( \
2835 " -p N Strip N leading components from file names" \
2836 "\n -i DIFF Read DIFF instead of stdin" \
2837 "\n -R Reverse patch" \
2838 "\n -N Ignore already applied patches" \
2839 "\n -E Remove output files if they become empty" \
2840 )
2841
2842#define patch_example_usage \
2843 "$ patch -p1 < example.diff\n" \
2844 "$ patch -p0 -i example.diff"
2845
2846#define pgrep_trivial_usage \ 2705#define pgrep_trivial_usage \
2847 "[-flnovx] [-s SID|-P PPID|PATTERN]" 2706 "[-flnovx] [-s SID|-P PPID|PATTERN]"
2848#define pgrep_full_usage "\n\n" \ 2707#define pgrep_full_usage "\n\n" \
@@ -2885,61 +2744,6 @@ INSERT
2885 IF_FEATURE_PIDOF_OMIT( \ 2744 IF_FEATURE_PIDOF_OMIT( \
2886 "$ pidof /bin/sh -o %PPID\n20351 5950") 2745 "$ pidof /bin/sh -o %PPID\n20351 5950")
2887 2746
2888#if !ENABLE_FEATURE_FANCY_PING
2889#define ping_trivial_usage \
2890 "host"
2891#define ping_full_usage "\n\n" \
2892 "Send ICMP ECHO_REQUEST packets to network hosts"
2893#define ping6_trivial_usage \
2894 "host"
2895#define ping6_full_usage "\n\n" \
2896 "Send ICMP ECHO_REQUEST packets to network hosts"
2897#else
2898#define ping_trivial_usage \
2899 "[OPTIONS] HOST"
2900#define ping_full_usage "\n\n" \
2901 "Send ICMP ECHO_REQUEST packets to network hosts\n" \
2902 "\nOptions:" \
2903 "\n -4,-6 Force IP or IPv6 name resolution" \
2904 "\n -c CNT Send only CNT pings" \
2905 "\n -s SIZE Send SIZE data bytes in packets (default:56)" \
2906 "\n -I IFACE/IP Use interface or IP address as source" \
2907 "\n -W SEC Seconds to wait for the first response (default:10)" \
2908 "\n (after all -c CNT packets are sent)" \
2909 "\n -w SEC Seconds until ping exits (default:infinite)" \
2910 "\n (can exit earlier with -c CNT)" \
2911 "\n -q Quiet, only displays output at start" \
2912 "\n and when finished" \
2913
2914#define ping6_trivial_usage \
2915 "[OPTIONS] HOST"
2916#define ping6_full_usage "\n\n" \
2917 "Send ICMP ECHO_REQUEST packets to network hosts\n" \
2918 "\nOptions:" \
2919 "\n -c CNT Send only CNT pings" \
2920 "\n -s SIZE Send SIZE data bytes in packets (default:56)" \
2921 "\n -I IFACE/IP Use interface or IP address as source" \
2922 "\n -q Quiet, only displays output at start" \
2923 "\n and when finished" \
2924
2925#endif
2926#define ping_example_usage \
2927 "$ ping localhost\n" \
2928 "PING slag (127.0.0.1): 56 data bytes\n" \
2929 "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \
2930 "\n" \
2931 "--- debian ping statistics ---\n" \
2932 "1 packets transmitted, 1 packets received, 0% packet loss\n" \
2933 "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
2934#define ping6_example_usage \
2935 "$ ping6 ip6-localhost\n" \
2936 "PING ip6-localhost (::1): 56 data bytes\n" \
2937 "64 bytes from ::1: icmp6_seq=0 ttl=64 time=20.1 ms\n" \
2938 "\n" \
2939 "--- ip6-localhost ping statistics ---\n" \
2940 "1 packets transmitted, 1 packets received, 0% packet loss\n" \
2941 "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
2942
2943#define pipe_progress_trivial_usage NOUSAGE_STR 2747#define pipe_progress_trivial_usage NOUSAGE_STR
2944#define pipe_progress_full_usage "" 2748#define pipe_progress_full_usage ""
2945 2749
@@ -3378,36 +3182,6 @@ INSERT
3378#define selinuxenabled_trivial_usage NOUSAGE_STR 3182#define selinuxenabled_trivial_usage NOUSAGE_STR
3379#define selinuxenabled_full_usage "" 3183#define selinuxenabled_full_usage ""
3380 3184
3381#define sendmail_trivial_usage \
3382 "[OPTIONS] [RECIPIENT_EMAIL]..."
3383#define sendmail_full_usage "\n\n" \
3384 "Read email from stdin and send it\n" \
3385 "\nStandard options:" \
3386 "\n -t Read additional recipients from message body" \
3387 "\n -f sender Sender (required)" \
3388 "\n -o options Various options. -oi implied, others are ignored" \
3389 "\n -i -oi synonym. implied and ignored" \
3390 "\n" \
3391 "\nBusybox specific options:" \
3392 "\n -w seconds Network timeout" \
3393 "\n -H 'PROG ARGS' Run connection helper" \
3394 "\n Examples:" \
3395 "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp" \
3396 "\n -connect smtp.gmail.com:25' <email.txt" \
3397 "\n [4<username_and_passwd.txt | -au<username> -ap<password>]" \
3398 "\n -H 'exec openssl s_client -quiet -tls1" \
3399 "\n -connect smtp.gmail.com:465' <email.txt" \
3400 "\n [4<username_and_passwd.txt | -au<username> -ap<password>]" \
3401 "\n -S server[:port] Server" \
3402 "\n -au<username> Username for AUTH LOGIN" \
3403 "\n -ap<password> Password for AUTH LOGIN" \
3404 "\n -am<method> Authentication method. Ignored. LOGIN is implied" \
3405 "\n" \
3406 "\nOther options are silently ignored; -oi -t is implied" \
3407 IF_MAKEMIME( \
3408 "\nUse makemime applet to create message with attachments" \
3409 )
3410
3411#define seq_trivial_usage \ 3185#define seq_trivial_usage \
3412 "[-w] [-s SEP] [FIRST [INC]] LAST" 3186 "[-w] [-s SEP] [FIRST [INC]] LAST"
3413#define seq_full_usage "\n\n" \ 3187#define seq_full_usage "\n\n" \
@@ -3750,15 +3524,6 @@ INSERT
3750 "\n -g Print in stty-readable form" \ 3524 "\n -g Print in stty-readable form" \
3751 "\n [SETTING] See manpage" \ 3525 "\n [SETTING] See manpage" \
3752 3526
3753#define su_trivial_usage \
3754 "[OPTIONS] [-] [USERNAME]"
3755#define su_full_usage "\n\n" \
3756 "Change user id or become root\n" \
3757 "\nOptions:" \
3758 "\n -p,-m Preserve environment" \
3759 "\n -c CMD Command to pass to 'sh -c'" \
3760 "\n -s SH Shell to use instead of default shell" \
3761
3762#define sulogin_trivial_usage \ 3527#define sulogin_trivial_usage \
3763 "[-t N] [TTY]" 3528 "[-t N] [TTY]"
3764#define sulogin_full_usage "\n\n" \ 3529#define sulogin_full_usage "\n\n" \
@@ -4086,22 +3851,6 @@ INSERT
4086 "and display a screenful of them." \ 3851 "and display a screenful of them." \
4087//TODO: add options and keyboard commands 3852//TODO: add options and keyboard commands
4088 3853
4089#define touch_trivial_usage \
4090 "[-c] [-d DATE] [-r FILE] FILE [FILE]..."
4091#define touch_full_usage "\n\n" \
4092 "Update the last-modified date on the given FILE[s]\n" \
4093 "\nOptions:" \
4094 "\n -c Don't create files" \
4095 "\n -d DT Date/time to use" \
4096 "\n -r FILE Use FILE's date/time" \
4097
4098#define touch_example_usage \
4099 "$ ls -l /tmp/foo\n" \
4100 "/bin/ls: /tmp/foo: No such file or directory\n" \
4101 "$ touch /tmp/foo\n" \
4102 "$ ls -l /tmp/foo\n" \
4103 "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n"
4104
4105#define tr_trivial_usage \ 3854#define tr_trivial_usage \
4106 "[-cds] STRING1 [STRING2]" 3855 "[-cds] STRING1 [STRING2]"
4107#define tr_full_usage "\n\n" \ 3856#define tr_full_usage "\n\n" \
diff --git a/include/volume_id.h b/include/volume_id.h
index 77e874d40..4a78cd1e4 100644
--- a/include/volume_id.h
+++ b/include/volume_id.h
@@ -28,3 +28,4 @@ void display_uuid_cache(void);
28 * *fsname is replaced if device with such UUID or LABEL is found 28 * *fsname is replaced if device with such UUID or LABEL is found
29 */ 29 */
30int resolve_mount_spec(char **fsname); 30int resolve_mount_spec(char **fsname);
31int add_to_uuid_cache(const char *device);
diff --git a/init/bootchartd.c b/init/bootchartd.c
index 5a1b3e8e8..ac3f261c8 100644
--- a/init/bootchartd.c
+++ b/init/bootchartd.c
@@ -441,8 +441,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv)
441 pid_t pid = xvfork(); 441 pid_t pid = xvfork();
442 if (pid == 0) { /* child */ 442 if (pid == 0) { /* child */
443 argv += 2; 443 argv += 2;
444 execvp(argv[0], argv); 444 BB_EXECVP_or_die(argv);
445 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
446 } 445 }
447 /* parent */ 446 /* parent */
448 waitpid(pid, NULL, 0); 447 waitpid(pid, NULL, 0);
diff --git a/init/init.c b/init/init.c
index a7bbd5e64..a2cc3b5f5 100644
--- a/init/init.c
+++ b/init/init.c
@@ -108,138 +108,6 @@
108//config: Note that on Linux, init attempts to detect serial terminal and 108//config: Note that on Linux, init attempts to detect serial terminal and
109//config: sets TERM to "vt102" if one is found. 109//config: sets TERM to "vt102" if one is found.
110 110
111//usage:#define init_trivial_usage
112//usage: ""
113//usage:#define init_full_usage "\n\n"
114//usage: "Init is the parent of all processes"
115//usage:
116//usage:#define init_notes_usage
117//usage: "This version of init is designed to be run only by the kernel.\n"
118//usage: "\n"
119//usage: "BusyBox init doesn't support multiple runlevels. The runlevels field of\n"
120//usage: "the /etc/inittab file is completely ignored by BusyBox init. If you want\n"
121//usage: "runlevels, use sysvinit.\n"
122//usage: "\n"
123//usage: "BusyBox init works just fine without an inittab. If no inittab is found,\n"
124//usage: "it has the following default behavior:\n"
125//usage: "\n"
126//usage: " ::sysinit:/etc/init.d/rcS\n"
127//usage: " ::askfirst:/bin/sh\n"
128//usage: " ::ctrlaltdel:/sbin/reboot\n"
129//usage: " ::shutdown:/sbin/swapoff -a\n"
130//usage: " ::shutdown:/bin/umount -a -r\n"
131//usage: " ::restart:/sbin/init\n"
132//usage: "\n"
133//usage: "if it detects that /dev/console is _not_ a serial console, it will also run:\n"
134//usage: "\n"
135//usage: " tty2::askfirst:/bin/sh\n"
136//usage: " tty3::askfirst:/bin/sh\n"
137//usage: " tty4::askfirst:/bin/sh\n"
138//usage: "\n"
139//usage: "If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n"
140//usage: "\n"
141//usage: " <id>:<runlevels>:<action>:<process>\n"
142//usage: "\n"
143//usage: " <id>:\n"
144//usage: "\n"
145//usage: " WARNING: This field has a non-traditional meaning for BusyBox init!\n"
146//usage: " The id field is used by BusyBox init to specify the controlling tty for\n"
147//usage: " the specified process to run on. The contents of this field are\n"
148//usage: " appended to \"/dev/\" and used as-is. There is no need for this field to\n"
149//usage: " be unique, although if it isn't you may have strange results. If this\n"
150//usage: " field is left blank, the controlling tty is set to the console. Also\n"
151//usage: " note that if BusyBox detects that a serial console is in use, then only\n"
152//usage: " entries whose controlling tty is either the serial console or /dev/null\n"
153//usage: " will be run. BusyBox init does nothing with utmp. We don't need no\n"
154//usage: " stinkin' utmp.\n"
155//usage: "\n"
156//usage: " <runlevels>:\n"
157//usage: "\n"
158//usage: " The runlevels field is completely ignored.\n"
159//usage: "\n"
160//usage: " <action>:\n"
161//usage: "\n"
162//usage: " Valid actions include: sysinit, respawn, askfirst, wait,\n"
163//usage: " once, restart, ctrlaltdel, and shutdown.\n"
164//usage: "\n"
165//usage: " The available actions can be classified into two groups: actions\n"
166//usage: " that are run only once, and actions that are re-run when the specified\n"
167//usage: " process exits.\n"
168//usage: "\n"
169//usage: " Run only-once actions:\n"
170//usage: "\n"
171//usage: " 'sysinit' is the first item run on boot. init waits until all\n"
172//usage: " sysinit actions are completed before continuing. Following the\n"
173//usage: " completion of all sysinit actions, all 'wait' actions are run.\n"
174//usage: " 'wait' actions, like 'sysinit' actions, cause init to wait until\n"
175//usage: " the specified task completes. 'once' actions are asynchronous,\n"
176//usage: " therefore, init does not wait for them to complete. 'restart' is\n"
177//usage: " the action taken to restart the init process. By default this should\n"
178//usage: " simply run /sbin/init, but can be a script which runs pivot_root or it\n"
179//usage: " can do all sorts of other interesting things. The 'ctrlaltdel' init\n"
180//usage: " actions are run when the system detects that someone on the system\n"
181//usage: " console has pressed the CTRL-ALT-DEL key combination. Typically one\n"
182//usage: " wants to run 'reboot' at this point to cause the system to reboot.\n"
183//usage: " Finally the 'shutdown' action specifies the actions to taken when\n"
184//usage: " init is told to reboot. Unmounting filesystems and disabling swap\n"
185//usage: " is a very good here.\n"
186//usage: "\n"
187//usage: " Run repeatedly actions:\n"
188//usage: "\n"
189//usage: " 'respawn' actions are run after the 'once' actions. When a process\n"
190//usage: " started with a 'respawn' action exits, init automatically restarts\n"
191//usage: " it. Unlike sysvinit, BusyBox init does not stop processes from\n"
192//usage: " respawning out of control. The 'askfirst' actions acts just like\n"
193//usage: " respawn, except that before running the specified process it\n"
194//usage: " displays the line \"Please press Enter to activate this console.\"\n"
195//usage: " and then waits for the user to press enter before starting the\n"
196//usage: " specified process.\n"
197//usage: "\n"
198//usage: " Unrecognized actions (like initdefault) will cause init to emit an\n"
199//usage: " error message, and then go along with its business. All actions are\n"
200//usage: " run in the order they appear in /etc/inittab.\n"
201//usage: "\n"
202//usage: " <process>:\n"
203//usage: "\n"
204//usage: " Specifies the process to be executed and its command line.\n"
205//usage: "\n"
206//usage: "Example /etc/inittab file:\n"
207//usage: "\n"
208//usage: " # This is run first except when booting in single-user mode\n"
209//usage: " #\n"
210//usage: " ::sysinit:/etc/init.d/rcS\n"
211//usage: " \n"
212//usage: " # /bin/sh invocations on selected ttys\n"
213//usage: " #\n"
214//usage: " # Start an \"askfirst\" shell on the console (whatever that may be)\n"
215//usage: " ::askfirst:-/bin/sh\n"
216//usage: " # Start an \"askfirst\" shell on /dev/tty2-4\n"
217//usage: " tty2::askfirst:-/bin/sh\n"
218//usage: " tty3::askfirst:-/bin/sh\n"
219//usage: " tty4::askfirst:-/bin/sh\n"
220//usage: " \n"
221//usage: " # /sbin/getty invocations for selected ttys\n"
222//usage: " #\n"
223//usage: " tty4::respawn:/sbin/getty 38400 tty4\n"
224//usage: " tty5::respawn:/sbin/getty 38400 tty5\n"
225//usage: " \n"
226//usage: " \n"
227//usage: " # Example of how to put a getty on a serial line (for a terminal)\n"
228//usage: " #\n"
229//usage: " #::respawn:/sbin/getty -L ttyS0 9600 vt100\n"
230//usage: " #::respawn:/sbin/getty -L ttyS1 9600 vt100\n"
231//usage: " #\n"
232//usage: " # Example how to put a getty on a modem line\n"
233//usage: " #::respawn:/sbin/getty 57600 ttyS2\n"
234//usage: " \n"
235//usage: " # Stuff to do when restarting the init process\n"
236//usage: " ::restart:/sbin/init\n"
237//usage: " \n"
238//usage: " # Stuff to do before rebooting\n"
239//usage: " ::ctrlaltdel:/sbin/reboot\n"
240//usage: " ::shutdown:/bin/umount -a -r\n"
241//usage: " ::shutdown:/sbin/swapoff -a\n"
242
243#include "libbb.h" 111#include "libbb.h"
244#include <syslog.h> 112#include <syslog.h>
245#include <paths.h> 113#include <paths.h>
@@ -533,20 +401,22 @@ static void init_exec(const char *command)
533 char buf[COMMAND_SIZE + 6]; /* COMMAND_SIZE+strlen("exec ")+1 */ 401 char buf[COMMAND_SIZE + 6]; /* COMMAND_SIZE+strlen("exec ")+1 */
534 int dash = (command[0] == '-' /* maybe? && command[1] == '/' */); 402 int dash = (command[0] == '-' /* maybe? && command[1] == '/' */);
535 403
404 command += dash;
405
536 /* See if any special /bin/sh requiring characters are present */ 406 /* See if any special /bin/sh requiring characters are present */
537 if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { 407 if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
538 strcpy(buf, "exec "); 408 sprintf(buf, "exec %s", command); /* excluding "-" */
539 strcpy(buf + 5, command + dash); /* excluding "-" */
540 /* NB: LIBBB_DEFAULT_LOGIN_SHELL define has leading dash */ 409 /* NB: LIBBB_DEFAULT_LOGIN_SHELL define has leading dash */
541 cmd[0] = (char*)(LIBBB_DEFAULT_LOGIN_SHELL + !dash); 410 cmd[0] = (char*)(LIBBB_DEFAULT_LOGIN_SHELL + !dash);
542 cmd[1] = (char*)"-c"; 411 cmd[1] = (char*)"-c";
543 cmd[2] = buf; 412 cmd[2] = buf;
544 cmd[3] = NULL; 413 cmd[3] = NULL;
414 command = LIBBB_DEFAULT_LOGIN_SHELL + 1;
545 } else { 415 } else {
546 /* Convert command (char*) into cmd (char**, one word per string) */ 416 /* Convert command (char*) into cmd (char**, one word per string) */
547 char *word, *next; 417 char *word, *next;
548 int i = 0; 418 int i = 0;
549 next = strcpy(buf, command); /* including "-" */ 419 next = strcpy(buf, command - dash); /* command including "-" */
550 while ((word = strsep(&next, " \t")) != NULL) { 420 while ((word = strsep(&next, " \t")) != NULL) {
551 if (*word != '\0') { /* not two spaces/tabs together? */ 421 if (*word != '\0') { /* not two spaces/tabs together? */
552 cmd[i] = word; 422 cmd[i] = word;
@@ -557,14 +427,14 @@ static void init_exec(const char *command)
557 } 427 }
558 /* If we saw leading "-", it is interactive shell. 428 /* If we saw leading "-", it is interactive shell.
559 * Try harder to give it a controlling tty. 429 * Try harder to give it a controlling tty.
560 * And skip "-" in actual exec call. */ 430 */
561 if (dash) { 431 if (ENABLE_FEATURE_INIT_SCTTY && dash) {
562 /* _Attempt_ to make stdin a controlling tty. */ 432 /* _Attempt_ to make stdin a controlling tty. */
563 if (ENABLE_FEATURE_INIT_SCTTY) 433 ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/);
564 ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/);
565 } 434 }
566 BB_EXECVP(cmd[0] + dash, cmd); 435 /* Here command never contains the dash, cmd[0] might */
567 message(L_LOG | L_CONSOLE, "can't run '%s': %s", cmd[0], strerror(errno)); 436 BB_EXECVP(command, cmd);
437 message(L_LOG | L_CONSOLE, "can't run '%s': %s", command, strerror(errno));
568 /* returns if execvp fails */ 438 /* returns if execvp fails */
569} 439}
570 440
@@ -1095,9 +965,9 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1095 if (!DEBUG_INIT) { 965 if (!DEBUG_INIT) {
1096 /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ 966 /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
1097 if (getpid() != 1 967 if (getpid() != 1
1098 && (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc")) 968 && (!ENABLE_FEATURE_INITRD || applet_name[0] != 'l') /* not linuxrc? */
1099 ) { 969 ) {
1100 bb_show_usage(); 970 bb_error_msg_and_die("must be run as PID 1");
1101 } 971 }
1102#ifdef RB_DISABLE_CAD 972#ifdef RB_DISABLE_CAD
1103 /* Turn off rebooting via CTL-ALT-DEL - we get a 973 /* Turn off rebooting via CTL-ALT-DEL - we get a
@@ -1286,3 +1156,138 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1286 } 1156 }
1287 } /* while (1) */ 1157 } /* while (1) */
1288} 1158}
1159
1160//usage:#define linuxrc_trivial_usage NOUSAGE_STR
1161//usage:#define linuxrc_full_usage ""
1162
1163//usage:#define init_trivial_usage
1164//usage: ""
1165//usage:#define init_full_usage "\n\n"
1166//usage: "Init is the parent of all processes"
1167//usage:
1168//usage:#define init_notes_usage
1169//usage: "This version of init is designed to be run only by the kernel.\n"
1170//usage: "\n"
1171//usage: "BusyBox init doesn't support multiple runlevels. The runlevels field of\n"
1172//usage: "the /etc/inittab file is completely ignored by BusyBox init. If you want\n"
1173//usage: "runlevels, use sysvinit.\n"
1174//usage: "\n"
1175//usage: "BusyBox init works just fine without an inittab. If no inittab is found,\n"
1176//usage: "it has the following default behavior:\n"
1177//usage: "\n"
1178//usage: " ::sysinit:/etc/init.d/rcS\n"
1179//usage: " ::askfirst:/bin/sh\n"
1180//usage: " ::ctrlaltdel:/sbin/reboot\n"
1181//usage: " ::shutdown:/sbin/swapoff -a\n"
1182//usage: " ::shutdown:/bin/umount -a -r\n"
1183//usage: " ::restart:/sbin/init\n"
1184//usage: "\n"
1185//usage: "if it detects that /dev/console is _not_ a serial console, it will also run:\n"
1186//usage: "\n"
1187//usage: " tty2::askfirst:/bin/sh\n"
1188//usage: " tty3::askfirst:/bin/sh\n"
1189//usage: " tty4::askfirst:/bin/sh\n"
1190//usage: "\n"
1191//usage: "If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n"
1192//usage: "\n"
1193//usage: " <id>:<runlevels>:<action>:<process>\n"
1194//usage: "\n"
1195//usage: " <id>:\n"
1196//usage: "\n"
1197//usage: " WARNING: This field has a non-traditional meaning for BusyBox init!\n"
1198//usage: " The id field is used by BusyBox init to specify the controlling tty for\n"
1199//usage: " the specified process to run on. The contents of this field are\n"
1200//usage: " appended to \"/dev/\" and used as-is. There is no need for this field to\n"
1201//usage: " be unique, although if it isn't you may have strange results. If this\n"
1202//usage: " field is left blank, the controlling tty is set to the console. Also\n"
1203//usage: " note that if BusyBox detects that a serial console is in use, then only\n"
1204//usage: " entries whose controlling tty is either the serial console or /dev/null\n"
1205//usage: " will be run. BusyBox init does nothing with utmp. We don't need no\n"
1206//usage: " stinkin' utmp.\n"
1207//usage: "\n"
1208//usage: " <runlevels>:\n"
1209//usage: "\n"
1210//usage: " The runlevels field is completely ignored.\n"
1211//usage: "\n"
1212//usage: " <action>:\n"
1213//usage: "\n"
1214//usage: " Valid actions include: sysinit, respawn, askfirst, wait,\n"
1215//usage: " once, restart, ctrlaltdel, and shutdown.\n"
1216//usage: "\n"
1217//usage: " The available actions can be classified into two groups: actions\n"
1218//usage: " that are run only once, and actions that are re-run when the specified\n"
1219//usage: " process exits.\n"
1220//usage: "\n"
1221//usage: " Run only-once actions:\n"
1222//usage: "\n"
1223//usage: " 'sysinit' is the first item run on boot. init waits until all\n"
1224//usage: " sysinit actions are completed before continuing. Following the\n"
1225//usage: " completion of all sysinit actions, all 'wait' actions are run.\n"
1226//usage: " 'wait' actions, like 'sysinit' actions, cause init to wait until\n"
1227//usage: " the specified task completes. 'once' actions are asynchronous,\n"
1228//usage: " therefore, init does not wait for them to complete. 'restart' is\n"
1229//usage: " the action taken to restart the init process. By default this should\n"
1230//usage: " simply run /sbin/init, but can be a script which runs pivot_root or it\n"
1231//usage: " can do all sorts of other interesting things. The 'ctrlaltdel' init\n"
1232//usage: " actions are run when the system detects that someone on the system\n"
1233//usage: " console has pressed the CTRL-ALT-DEL key combination. Typically one\n"
1234//usage: " wants to run 'reboot' at this point to cause the system to reboot.\n"
1235//usage: " Finally the 'shutdown' action specifies the actions to taken when\n"
1236//usage: " init is told to reboot. Unmounting filesystems and disabling swap\n"
1237//usage: " is a very good here.\n"
1238//usage: "\n"
1239//usage: " Run repeatedly actions:\n"
1240//usage: "\n"
1241//usage: " 'respawn' actions are run after the 'once' actions. When a process\n"
1242//usage: " started with a 'respawn' action exits, init automatically restarts\n"
1243//usage: " it. Unlike sysvinit, BusyBox init does not stop processes from\n"
1244//usage: " respawning out of control. The 'askfirst' actions acts just like\n"
1245//usage: " respawn, except that before running the specified process it\n"
1246//usage: " displays the line \"Please press Enter to activate this console.\"\n"
1247//usage: " and then waits for the user to press enter before starting the\n"
1248//usage: " specified process.\n"
1249//usage: "\n"
1250//usage: " Unrecognized actions (like initdefault) will cause init to emit an\n"
1251//usage: " error message, and then go along with its business. All actions are\n"
1252//usage: " run in the order they appear in /etc/inittab.\n"
1253//usage: "\n"
1254//usage: " <process>:\n"
1255//usage: "\n"
1256//usage: " Specifies the process to be executed and its command line.\n"
1257//usage: "\n"
1258//usage: "Example /etc/inittab file:\n"
1259//usage: "\n"
1260//usage: " # This is run first except when booting in single-user mode\n"
1261//usage: " #\n"
1262//usage: " ::sysinit:/etc/init.d/rcS\n"
1263//usage: " \n"
1264//usage: " # /bin/sh invocations on selected ttys\n"
1265//usage: " #\n"
1266//usage: " # Start an \"askfirst\" shell on the console (whatever that may be)\n"
1267//usage: " ::askfirst:-/bin/sh\n"
1268//usage: " # Start an \"askfirst\" shell on /dev/tty2-4\n"
1269//usage: " tty2::askfirst:-/bin/sh\n"
1270//usage: " tty3::askfirst:-/bin/sh\n"
1271//usage: " tty4::askfirst:-/bin/sh\n"
1272//usage: " \n"
1273//usage: " # /sbin/getty invocations for selected ttys\n"
1274//usage: " #\n"
1275//usage: " tty4::respawn:/sbin/getty 38400 tty4\n"
1276//usage: " tty5::respawn:/sbin/getty 38400 tty5\n"
1277//usage: " \n"
1278//usage: " \n"
1279//usage: " # Example of how to put a getty on a serial line (for a terminal)\n"
1280//usage: " #\n"
1281//usage: " #::respawn:/sbin/getty -L ttyS0 9600 vt100\n"
1282//usage: " #::respawn:/sbin/getty -L ttyS1 9600 vt100\n"
1283//usage: " #\n"
1284//usage: " # Example how to put a getty on a modem line\n"
1285//usage: " #::respawn:/sbin/getty 57600 ttyS2\n"
1286//usage: " \n"
1287//usage: " # Stuff to do when restarting the init process\n"
1288//usage: " ::restart:/sbin/init\n"
1289//usage: " \n"
1290//usage: " # Stuff to do before rebooting\n"
1291//usage: " ::ctrlaltdel:/sbin/reboot\n"
1292//usage: " ::shutdown:/bin/umount -a -r\n"
1293//usage: " ::shutdown:/sbin/swapoff -a\n"
diff --git a/libbb/Config.src b/libbb/Config.src
index f6c7a11ea..85892d3fe 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -135,7 +135,7 @@ config FEATURE_NON_POSIX_CP
135 and create a regular file. This does not conform to POSIX, 135 and create a regular file. This does not conform to POSIX,
136 but prevents a symlink attack. 136 but prevents a symlink attack.
137 Similarly, "cp file device" will not send file's data 137 Similarly, "cp file device" will not send file's data
138 to the device. 138 to the device. (To do that, use "cat file >device")
139 139
140config FEATURE_VERBOSE_CP_MESSAGE 140config FEATURE_VERBOSE_CP_MESSAGE
141 bool "Give more precise messages when copy fails (cp, mv etc)" 141 bool "Give more precise messages when copy fails (cp, mv etc)"
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index e3866e456..b88fa8fe7 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -159,6 +159,7 @@ lib-$(CONFIG_RTCWAKE) += rtc.o
159 159
160lib-$(CONFIG_IOSTAT) += get_cpu_count.o 160lib-$(CONFIG_IOSTAT) += get_cpu_count.o
161lib-$(CONFIG_MPSTAT) += get_cpu_count.o 161lib-$(CONFIG_MPSTAT) += get_cpu_count.o
162lib-$(CONFIG_POWERTOP) += get_cpu_count.o
162 163
163# We shouldn't build xregcomp.c if we don't need it - this ensures we don't 164# We shouldn't build xregcomp.c if we don't need it - this ensures we don't
164# require regex.h to be in the include dir even if we don't need it thereby 165# require regex.h to be in the include dir even if we don't need it thereby
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 3b691f945..b1c772cf3 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -28,7 +28,11 @@
28 */ 28 */
29#include "busybox.h" 29#include "busybox.h"
30#include <assert.h> 30#include <assert.h>
31#include <malloc.h> 31#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
32 || defined(__APPLE__) \
33 )
34# include <malloc.h> /* for mallopt */
35#endif
32/* Try to pull in PAGE_SIZE */ 36/* Try to pull in PAGE_SIZE */
33#ifdef __linux__ 37#ifdef __linux__
34# include <sys/user.h> 38# include <sys/user.h>
@@ -66,7 +70,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
66#if ENABLE_FEATURE_COMPRESS_USAGE 70#if ENABLE_FEATURE_COMPRESS_USAGE
67 71
68static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; 72static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
69# include "unarchive.h" 73# include "archive.h"
70static const char *unpack_usage_messages(void) 74static const char *unpack_usage_messages(void)
71{ 75{
72 char *outbuf = NULL; 76 char *outbuf = NULL;
@@ -75,7 +79,7 @@ static const char *unpack_usage_messages(void)
75 79
76 i = start_bunzip(&bd, 80 i = start_bunzip(&bd,
77 /* src_fd: */ -1, 81 /* src_fd: */ -1,
78 /* inbuf: */ (void *)packed_usage, 82 /* inbuf: */ packed_usage,
79 /* len: */ sizeof(packed_usage)); 83 /* len: */ sizeof(packed_usage));
80 /* read_bunzip can longjmp to start_bunzip, and ultimately 84 /* read_bunzip can longjmp to start_bunzip, and ultimately
81 * end up here with i != 0 on read data errors! Not trivial */ 85 * end up here with i != 0 on read data errors! Not trivial */
@@ -103,14 +107,13 @@ void FAST_FUNC bb_show_usage(void)
103 if (ENABLE_SHOW_USAGE) { 107 if (ENABLE_SHOW_USAGE) {
104#ifdef SINGLE_APPLET_STR 108#ifdef SINGLE_APPLET_STR
105 /* Imagine that this applet is "true". Dont suck in printf! */ 109 /* Imagine that this applet is "true". Dont suck in printf! */
106 const char *p; 110 const char *usage_string = unpack_usage_messages();
107 const char *usage_string = p = unpack_usage_messages();
108 111
109 if (*p == '\b') { 112 if (*usage_string == '\b') {
110 full_write2_str("No help available.\n\n"); 113 full_write2_str("No help available.\n\n");
111 } else { 114 } else {
112 full_write2_str("Usage: "SINGLE_APPLET_STR" "); 115 full_write2_str("Usage: "SINGLE_APPLET_STR" ");
113 full_write2_str(p); 116 full_write2_str(usage_string);
114 full_write2_str("\n\n"); 117 full_write2_str("\n\n");
115 } 118 }
116 if (ENABLE_FEATURE_CLEAN_UP) 119 if (ENABLE_FEATURE_CLEAN_UP)
@@ -228,7 +231,7 @@ bool re_execed;
228 231
229IF_FEATURE_SUID(static uid_t ruid;) /* real uid */ 232IF_FEATURE_SUID(static uid_t ruid;) /* real uid */
230 233
231#if ENABLE_FEATURE_SUID_CONFIG 234# if ENABLE_FEATURE_SUID_CONFIG
232 235
233/* applets[] is const, so we have to define this "override" structure */ 236/* applets[] is const, so we have to define this "override" structure */
234static struct BB_suid_config { 237static struct BB_suid_config {
@@ -499,15 +502,15 @@ static void parse_config_file(void)
499 sct_head = sct; 502 sct_head = sct;
500 } 503 }
501} 504}
502#else 505# else
503static inline void parse_config_file(void) 506static inline void parse_config_file(void)
504{ 507{
505 IF_FEATURE_SUID(ruid = getuid();) 508 IF_FEATURE_SUID(ruid = getuid();)
506} 509}
507#endif /* FEATURE_SUID_CONFIG */ 510# endif /* FEATURE_SUID_CONFIG */
508 511
509 512
510#if ENABLE_FEATURE_SUID 513# if ENABLE_FEATURE_SUID
511static void check_suid(int applet_no) 514static void check_suid(int applet_no)
512{ 515{
513 gid_t rgid; /* real gid */ 516 gid_t rgid; /* real gid */
@@ -516,7 +519,7 @@ static void check_suid(int applet_no)
516 return; /* run by root - no need to check more */ 519 return; /* run by root - no need to check more */
517 rgid = getgid(); 520 rgid = getgid();
518 521
519#if ENABLE_FEATURE_SUID_CONFIG 522# if ENABLE_FEATURE_SUID_CONFIG
520 if (suid_cfg_readable) { 523 if (suid_cfg_readable) {
521 uid_t uid; 524 uid_t uid;
522 struct BB_suid_config *sct; 525 struct BB_suid_config *sct;
@@ -559,7 +562,7 @@ static void check_suid(int applet_no)
559 bb_perror_msg_and_die("setresuid"); 562 bb_perror_msg_and_die("setresuid");
560 return; 563 return;
561 } 564 }
562#if !ENABLE_FEATURE_SUID_CONFIG_QUIET 565# if !ENABLE_FEATURE_SUID_CONFIG_QUIET
563 { 566 {
564 static bool onetime = 0; 567 static bool onetime = 0;
565 568
@@ -568,9 +571,9 @@ static void check_suid(int applet_no)
568 fprintf(stderr, "Using fallback suid method\n"); 571 fprintf(stderr, "Using fallback suid method\n");
569 } 572 }
570 } 573 }
571#endif 574# endif
572 check_need_suid: 575 check_need_suid:
573#endif 576# endif
574 if (APPLET_SUID(applet_no) == _BB_SUID_REQUIRE) { 577 if (APPLET_SUID(applet_no) == _BB_SUID_REQUIRE) {
575 /* Real uid is not 0. If euid isn't 0 too, suid bit 578 /* Real uid is not 0. If euid isn't 0 too, suid bit
576 * is most probably not set on our executable */ 579 * is most probably not set on our executable */
@@ -581,25 +584,24 @@ static void check_suid(int applet_no)
581 xsetuid(ruid); 584 xsetuid(ruid);
582 } 585 }
583} 586}
584#else 587# else
585#define check_suid(x) ((void)0) 588# define check_suid(x) ((void)0)
586#endif /* FEATURE_SUID */ 589# endif /* FEATURE_SUID */
587 590
588 591
589#if ENABLE_FEATURE_INSTALLER 592# if ENABLE_FEATURE_INSTALLER
590static const char usr_bin [] ALIGN1 = "/usr/bin/"; 593static const char usr_bin [] ALIGN1 = "/usr/bin/";
591static const char usr_sbin[] ALIGN1 = "/usr/sbin/"; 594static const char usr_sbin[] ALIGN1 = "/usr/sbin/";
592static const char *const install_dir[] = { 595static const char *const install_dir[] = {
593 &usr_bin [8], /* "/" */ 596 &usr_bin [8], /* "/" */
594 &usr_bin [4], /* "/bin/" */ 597 &usr_bin [4], /* "/bin/" */
595 &usr_sbin[4] /* "/sbin/" */ 598 &usr_sbin[4] /* "/sbin/" */
596# if !ENABLE_INSTALL_NO_USR 599# if !ENABLE_INSTALL_NO_USR
597 ,usr_bin 600 ,usr_bin
598 ,usr_sbin 601 ,usr_sbin
599# endif 602# endif
600}; 603};
601 604
602
603/* create (sym)links for each applet */ 605/* create (sym)links for each applet */
604static void install_links(const char *busybox, int use_symbolic_links, 606static void install_links(const char *busybox, int use_symbolic_links,
605 char *custom_install_dir) 607 char *custom_install_dir)
@@ -629,9 +631,9 @@ static void install_links(const char *busybox, int use_symbolic_links,
629 free(fpc); 631 free(fpc);
630 } 632 }
631} 633}
632#else 634# else
633# define install_links(x,y,z) ((void)0) 635# define install_links(x,y,z) ((void)0)
634#endif 636# endif
635 637
636/* If we were called as "busybox..." */ 638/* If we were called as "busybox..." */
637static int busybox_main(char **argv) 639static int busybox_main(char **argv)
@@ -696,10 +698,10 @@ static int busybox_main(char **argv)
696 const char *a = applet_names; 698 const char *a = applet_names;
697 dup2(1, 2); 699 dup2(1, 2);
698 while (*a) { 700 while (*a) {
699#if ENABLE_FEATURE_INSTALLER 701# if ENABLE_FEATURE_INSTALLER
700 if (argv[1][6]) /* --list-path? */ 702 if (argv[1][6]) /* --list-path? */
701 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); 703 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
702#endif 704# endif
703 full_write2_str(a); 705 full_write2_str(a);
704 full_write2_str("\n"); 706 full_write2_str("\n");
705 i++; 707 i++;
@@ -772,7 +774,7 @@ void FAST_FUNC run_applet_and_exit(const char *name, char **argv)
772 int applet = find_applet_by_name(name); 774 int applet = find_applet_by_name(name);
773 if (applet >= 0) 775 if (applet >= 0)
774 run_applet_no_and_exit(applet, argv); 776 run_applet_no_and_exit(applet, argv);
775 if (!strncmp(name, "busybox", 7)) 777 if (strncmp(name, "busybox", 7) == 0)
776 exit(busybox_main(argv)); 778 exit(busybox_main(argv));
777} 779}
778 780
@@ -804,14 +806,6 @@ int main(int argc UNUSED_PARAM, char **argv)
804 mallopt(M_MMAP_THRESHOLD, 8 * PAGE_SIZE - 256); 806 mallopt(M_MMAP_THRESHOLD, 8 * PAGE_SIZE - 256);
805#endif 807#endif
806 808
807#if defined(SINGLE_APPLET_MAIN)
808 /* Only one applet is selected by the user! */
809 /* applet_names in this case is just "applet\0\0" */
810 lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv));
811 return SINGLE_APPLET_MAIN(argc, argv);
812#else
813 lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv));
814
815#if !BB_MMU 809#if !BB_MMU
816 /* NOMMU re-exec trick sets high-order bit in first byte of name */ 810 /* NOMMU re-exec trick sets high-order bit in first byte of name */
817 if (argv[0][0] & 0x80) { 811 if (argv[0][0] & 0x80) {
@@ -819,6 +813,19 @@ int main(int argc UNUSED_PARAM, char **argv)
819 argv[0][0] &= 0x7f; 813 argv[0][0] &= 0x7f;
820 } 814 }
821#endif 815#endif
816
817#if defined(SINGLE_APPLET_MAIN)
818 /* Only one applet is selected in .config */
819 if (argv[1] && strncmp(argv[0], "busybox", 7) == 0) {
820 /* "busybox <applet> <params>" should still work as expected */
821 argv++;
822 }
823 /* applet_names in this case is just "applet\0\0" */
824 lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv));
825 return SINGLE_APPLET_MAIN(argc, argv);
826#else
827 lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv));
828
822 applet_name = argv[0]; 829 applet_name = argv[0];
823 if (applet_name[0] == '-') 830 if (applet_name[0] == '-')
824 applet_name++; 831 applet_name++;
diff --git a/libbb/find_root_device.c b/libbb/find_root_device.c
index 32c86cea8..8436cd664 100644
--- a/libbb/find_root_device.c
+++ b/libbb/find_root_device.c
@@ -29,14 +29,15 @@ static char *find_block_device_in_dir(struct arena *ap)
29 char *retpath = NULL; 29 char *retpath = NULL;
30 int len, rem; 30 int len, rem;
31 31
32 dir = opendir(ap->devpath);
33 if (!dir)
34 return NULL;
35
36 len = strlen(ap->devpath); 32 len = strlen(ap->devpath);
37 rem = DEVNAME_MAX-2 - len; 33 rem = DEVNAME_MAX-2 - len;
38 if (rem <= 0) 34 if (rem <= 0)
39 return NULL; 35 return NULL;
36
37 dir = opendir(ap->devpath);
38 if (!dir)
39 return NULL;
40
40 ap->devpath[len++] = '/'; 41 ap->devpath[len++] = '/';
41 42
42 while ((entry = readdir(dir)) != NULL) { 43 while ((entry = readdir(dir)) != NULL) {
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index ab77755fc..187cb3a79 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -115,7 +115,7 @@ const char *opt_complementary
115 found. 115 found.
116 116
117 "ww" Adjacent double options have a counter associated which indicates 117 "ww" Adjacent double options have a counter associated which indicates
118 the number of occurences of the option. 118 the number of occurrences of the option.
119 For example the ps applet needs: 119 For example the ps applet needs:
120 if w is given once, GNU ps sets the width to 132, 120 if w is given once, GNU ps sets the width to 132,
121 if w is given more than once, it is "unlimited" 121 if w is given more than once, it is "unlimited"
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index e427f6080..b87d1dde8 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -158,11 +158,11 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
158 }; 158 };
159 static const char P_array[] ALIGN1 = { 159 static const char P_array[] ALIGN1 = {
160# if MD5_SIZE_VS_SPEED > 1 160# if MD5_SIZE_VS_SPEED > 1
161 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ 161 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
162# endif 162# endif
163 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ 163 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
164 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ 164 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
165 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ 165 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
166 }; 166 };
167#endif 167#endif
168 uint32_t *words = (void*) ctx->wbuffer; 168 uint32_t *words = (void*) ctx->wbuffer;
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 182dfac13..f9658711a 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -94,8 +94,10 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
94#endif 94#endif
95 95
96 96
97#define SEQ_CLEAR_TILL_END_OF_SCREEN "\033[J" 97#define ESC "\033"
98//#define SEQ_CLEAR_TILL_END_OF_LINE "\033[K" 98
99#define SEQ_CLEAR_TILL_END_OF_SCREEN ESC"[J"
100//#define SEQ_CLEAR_TILL_END_OF_LINE ESC"[K"
99 101
100 102
101enum { 103enum {
@@ -446,7 +448,7 @@ static void input_backward(unsigned num)
446 } while (--num); 448 } while (--num);
447 return; 449 return;
448 } 450 }
449 printf("\033[%uD", num); 451 printf(ESC"[%uD", num);
450 return; 452 return;
451 } 453 }
452 454
@@ -471,7 +473,7 @@ static void input_backward(unsigned num)
471 */ 473 */
472 unsigned sv_cursor; 474 unsigned sv_cursor;
473 /* go to 1st column; go up to first line */ 475 /* go to 1st column; go up to first line */
474 printf("\r" "\033[%uA", cmdedit_y); 476 printf("\r" ESC"[%uA", cmdedit_y);
475 cmdedit_y = 0; 477 cmdedit_y = 0;
476 sv_cursor = cursor; 478 sv_cursor = cursor;
477 put_prompt(); /* sets cursor to 0 */ 479 put_prompt(); /* sets cursor to 0 */
@@ -488,12 +490,12 @@ static void input_backward(unsigned num)
488 cmdedit_x = (width * cmdedit_y - num) % width; 490 cmdedit_x = (width * cmdedit_y - num) % width;
489 cmdedit_y -= lines_up; 491 cmdedit_y -= lines_up;
490 /* go to 1st column; go up */ 492 /* go to 1st column; go up */
491 printf("\r" "\033[%uA", lines_up); 493 printf("\r" ESC"[%uA", lines_up);
492 /* go to correct column. 494 /* go to correct column.
493 * xterm, konsole, Linux VT interpret 0 as 1 below! wow. 495 * xterm, konsole, Linux VT interpret 0 as 1 below! wow.
494 * need to *make sure* we skip it if cmdedit_x == 0 */ 496 * need to *make sure* we skip it if cmdedit_x == 0 */
495 if (cmdedit_x) 497 if (cmdedit_x)
496 printf("\033[%uC", cmdedit_x); 498 printf(ESC"[%uC", cmdedit_x);
497 } 499 }
498} 500}
499 501
@@ -501,7 +503,7 @@ static void input_backward(unsigned num)
501static void redraw(int y, int back_cursor) 503static void redraw(int y, int back_cursor)
502{ 504{
503 if (y > 0) /* up y lines */ 505 if (y > 0) /* up y lines */
504 printf("\033[%uA", y); 506 printf(ESC"[%uA", y);
505 bb_putchar('\r'); 507 bb_putchar('\r');
506 put_prompt(); 508 put_prompt();
507 put_till_end_and_adv_cursor(); 509 put_till_end_and_adv_cursor();
@@ -582,6 +584,12 @@ static void input_forward(void)
582 584
583#if ENABLE_FEATURE_TAB_COMPLETION 585#if ENABLE_FEATURE_TAB_COMPLETION
584 586
587//FIXME:
588//needs to be more clever: currently it thinks that "foo\ b<TAB>
589//matches the file named "foo bar", which is untrue.
590//Also, perhaps "foo b<TAB> needs to complete to "foo bar" <cursor>,
591//not "foo bar <cursor>...
592
585static void free_tab_completion_data(void) 593static void free_tab_completion_data(void)
586{ 594{
587 if (matches) { 595 if (matches) {
@@ -599,7 +607,7 @@ static void add_match(char *matched)
599 num_matches++; 607 num_matches++;
600} 608}
601 609
602#if ENABLE_FEATURE_USERNAME_COMPLETION 610# if ENABLE_FEATURE_USERNAME_COMPLETION
603/* Replace "~user/..." with "/homedir/...". 611/* Replace "~user/..." with "/homedir/...".
604 * The parameter is malloced, free it or return it 612 * The parameter is malloced, free it or return it
605 * unchanged if no user is matched. 613 * unchanged if no user is matched.
@@ -655,7 +663,7 @@ static NOINLINE unsigned complete_username(const char *ud)
655 663
656 return 1 + userlen; 664 return 1 + userlen;
657} 665}
658#endif /* FEATURE_USERNAME_COMPLETION */ 666# endif /* FEATURE_USERNAME_COMPLETION */
659 667
660enum { 668enum {
661 FIND_EXE_ONLY = 0, 669 FIND_EXE_ONLY = 0,
@@ -740,10 +748,10 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
740 pfind++; 748 pfind++;
741 /* dirbuf = ".../.../.../" */ 749 /* dirbuf = ".../.../.../" */
742 dirbuf = xstrndup(command, pfind - command); 750 dirbuf = xstrndup(command, pfind - command);
743#if ENABLE_FEATURE_USERNAME_COMPLETION 751# if ENABLE_FEATURE_USERNAME_COMPLETION
744 if (dirbuf[0] == '~') /* ~/... or ~user/... */ 752 if (dirbuf[0] == '~') /* ~/... or ~user/... */
745 dirbuf = username_path_completion(dirbuf); 753 dirbuf = username_path_completion(dirbuf);
746#endif 754# endif
747 path1[0] = dirbuf; 755 path1[0] = dirbuf;
748 } 756 }
749 pf_len = strlen(pfind); 757 pf_len = strlen(pfind);
@@ -1021,13 +1029,18 @@ static void showfiles(void)
1021 } 1029 }
1022} 1030}
1023 1031
1024static char *add_quote_for_spec_chars(char *found) 1032static const char *is_special_char(char c)
1033{
1034 return strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", c);
1035}
1036
1037static char *quote_special_chars(char *found)
1025{ 1038{
1026 int l = 0; 1039 int l = 0;
1027 char *s = xzalloc((strlen(found) + 1) * 2); 1040 char *s = xzalloc((strlen(found) + 1) * 2);
1028 1041
1029 while (*found) { 1042 while (*found) {
1030 if (strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", *found)) 1043 if (is_special_char(*found))
1031 s[l++] = '\\'; 1044 s[l++] = '\\';
1032 s[l++] = *found++; 1045 s[l++] = *found++;
1033 } 1046 }
@@ -1044,10 +1057,10 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1044 /* Length of string used for matching */ 1057 /* Length of string used for matching */
1045 unsigned match_pfx_len = match_pfx_len; 1058 unsigned match_pfx_len = match_pfx_len;
1046 int find_type; 1059 int find_type;
1047#if ENABLE_UNICODE_SUPPORT 1060# if ENABLE_UNICODE_SUPPORT
1048 /* cursor pos in command converted to multibyte form */ 1061 /* cursor pos in command converted to multibyte form */
1049 int cursor_mb; 1062 int cursor_mb;
1050#endif 1063# endif
1051 if (!(state->flags & TAB_COMPLETION)) 1064 if (!(state->flags & TAB_COMPLETION))
1052 return; 1065 return;
1053 1066
@@ -1074,9 +1087,9 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1074 * (we then also (ab)use this extra space later - see (**)) 1087 * (we then also (ab)use this extra space later - see (**))
1075 */ 1088 */
1076 match_buf = xmalloc(MAX_LINELEN * sizeof(int16_t)); 1089 match_buf = xmalloc(MAX_LINELEN * sizeof(int16_t));
1077#if !ENABLE_UNICODE_SUPPORT 1090# if !ENABLE_UNICODE_SUPPORT
1078 save_string(match_buf, cursor + 1); /* +1 for NUL */ 1091 save_string(match_buf, cursor + 1); /* +1 for NUL */
1079#else 1092# else
1080 { 1093 {
1081 CHAR_T wc = command_ps[cursor]; 1094 CHAR_T wc = command_ps[cursor];
1082 command_ps[cursor] = BB_NUL; 1095 command_ps[cursor] = BB_NUL;
@@ -1084,26 +1097,37 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1084 command_ps[cursor] = wc; 1097 command_ps[cursor] = wc;
1085 cursor_mb = strlen(match_buf); 1098 cursor_mb = strlen(match_buf);
1086 } 1099 }
1087#endif 1100# endif
1088 find_type = build_match_prefix(match_buf); 1101 find_type = build_match_prefix(match_buf);
1089 1102
1090 /* Free up any memory already allocated */ 1103 /* Free up any memory already allocated */
1091 free_tab_completion_data(); 1104 free_tab_completion_data();
1092 1105
1093#if ENABLE_FEATURE_USERNAME_COMPLETION 1106# if ENABLE_FEATURE_USERNAME_COMPLETION
1094 /* If the word starts with `~' and there is no slash in the word, 1107 /* If the word starts with ~ and there is no slash in the word,
1095 * then try completing this word as a username. */ 1108 * then try completing this word as a username. */
1096 if (state->flags & USERNAME_COMPLETION) 1109 if (state->flags & USERNAME_COMPLETION)
1097 if (match_buf[0] == '~' && strchr(match_buf, '/') == NULL) 1110 if (match_buf[0] == '~' && strchr(match_buf, '/') == NULL)
1098 match_pfx_len = complete_username(match_buf); 1111 match_pfx_len = complete_username(match_buf);
1099#endif 1112# endif
1100 /* Try to match a command in $PATH, or a directory, or a file */ 1113 /* If complete_username() did not match,
1114 * try to match a command in $PATH, or a directory, or a file */
1101 if (!matches) 1115 if (!matches)
1102 match_pfx_len = complete_cmd_dir_file(match_buf, find_type); 1116 match_pfx_len = complete_cmd_dir_file(match_buf, find_type);
1117
1118 /* Account for backslashes which will be inserted
1119 * by quote_special_chars() later */
1120 {
1121 const char *e = match_buf + strlen(match_buf);
1122 const char *s = e - match_pfx_len;
1123 while (s < e)
1124 if (is_special_char(*s++))
1125 match_pfx_len++;
1126 }
1127
1103 /* Remove duplicates */ 1128 /* Remove duplicates */
1104 if (matches) { 1129 if (matches) {
1105 unsigned i; 1130 unsigned i, n = 0;
1106 unsigned n = 0;
1107 qsort_string_vector(matches, num_matches); 1131 qsort_string_vector(matches, num_matches);
1108 for (i = 0; i < num_matches - 1; ++i) { 1132 for (i = 0; i < num_matches - 1; ++i) {
1109 //if (matches[i] && matches[i+1]) { /* paranoia */ 1133 //if (matches[i] && matches[i+1]) { /* paranoia */
@@ -1118,6 +1142,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1118 matches[n++] = matches[i]; 1142 matches[n++] = matches[i];
1119 num_matches = n; 1143 num_matches = n;
1120 } 1144 }
1145
1121 /* Did we find exactly one match? */ 1146 /* Did we find exactly one match? */
1122 if (num_matches != 1) { /* no */ 1147 if (num_matches != 1) { /* no */
1123 char *cp; 1148 char *cp;
@@ -1139,7 +1164,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1139 goto ret; /* no */ 1164 goto ret; /* no */
1140 } 1165 }
1141 *cp = '\0'; 1166 *cp = '\0';
1142 cp = add_quote_for_spec_chars(chosen_match); 1167 cp = quote_special_chars(chosen_match);
1143 free(chosen_match); 1168 free(chosen_match);
1144 chosen_match = cp; 1169 chosen_match = cp;
1145 len_found = strlen(chosen_match); 1170 len_found = strlen(chosen_match);
@@ -1147,7 +1172,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1147 /* Next <tab> is not a double-tab */ 1172 /* Next <tab> is not a double-tab */
1148 *lastWasTab = 0; 1173 *lastWasTab = 0;
1149 1174
1150 chosen_match = add_quote_for_spec_chars(matches[0]); 1175 chosen_match = quote_special_chars(matches[0]);
1151 len_found = strlen(chosen_match); 1176 len_found = strlen(chosen_match);
1152 if (chosen_match[len_found-1] != '/') { 1177 if (chosen_match[len_found-1] != '/') {
1153 chosen_match[len_found] = ' '; 1178 chosen_match[len_found] = ' ';
@@ -1155,7 +1180,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1155 } 1180 }
1156 } 1181 }
1157 1182
1158#if !ENABLE_UNICODE_SUPPORT 1183# if !ENABLE_UNICODE_SUPPORT
1159 /* Have space to place the match? */ 1184 /* Have space to place the match? */
1160 /* The result consists of three parts with these lengths: */ 1185 /* The result consists of three parts with these lengths: */
1161 /* cursor + (len_found - match_pfx_len) + (command_len - cursor) */ 1186 /* cursor + (len_found - match_pfx_len) + (command_len - cursor) */
@@ -1172,7 +1197,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1172 /* write out the matched command */ 1197 /* write out the matched command */
1173 redraw(cmdedit_y, command_len - pos); 1198 redraw(cmdedit_y, command_len - pos);
1174 } 1199 }
1175#else 1200# else
1176 { 1201 {
1177 /* Use 2nd half of match_buf as scratch space - see (**) */ 1202 /* Use 2nd half of match_buf as scratch space - see (**) */
1178 char *command = match_buf + MAX_LINELEN; 1203 char *command = match_buf + MAX_LINELEN;
@@ -1196,7 +1221,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1196 redraw(cmdedit_y, pos >= 0 ? pos : 0); 1221 redraw(cmdedit_y, pos >= 0 ? pos : 0);
1197 } 1222 }
1198 } 1223 }
1199#endif 1224# endif
1200 ret: 1225 ret:
1201 free(chosen_match); 1226 free(chosen_match);
1202 free(match_buf); 1227 free(match_buf);
@@ -1342,7 +1367,7 @@ static void save_history(char *str)
1342 int fd; 1367 int fd;
1343 int len, len2; 1368 int len, len2;
1344 1369
1345 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0666); 1370 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600);
1346 if (fd < 0) 1371 if (fd < 0)
1347 return; 1372 return;
1348 xlseek(fd, 0, SEEK_END); /* paranoia */ 1373 xlseek(fd, 0, SEEK_END); /* paranoia */
@@ -1357,10 +1382,8 @@ static void save_history(char *str)
1357 /* did we write so much that history file needs trimming? */ 1382 /* did we write so much that history file needs trimming? */
1358 state->cnt_history_in_file++; 1383 state->cnt_history_in_file++;
1359 if (state->cnt_history_in_file > MAX_HISTORY * 4) { 1384 if (state->cnt_history_in_file > MAX_HISTORY * 4) {
1360 FILE *fp;
1361 char *new_name; 1385 char *new_name;
1362 line_input_t *st_temp; 1386 line_input_t *st_temp;
1363 int i;
1364 1387
1365 /* we may have concurrently written entries from others. 1388 /* we may have concurrently written entries from others.
1366 * load them */ 1389 * load them */
@@ -1370,8 +1393,12 @@ static void save_history(char *str)
1370 1393
1371 /* write out temp file and replace hist_file atomically */ 1394 /* write out temp file and replace hist_file atomically */
1372 new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid()); 1395 new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid());
1373 fp = fopen_for_write(new_name); 1396 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1374 if (fp) { 1397 if (fd >= 0) {
1398 FILE *fp;
1399 int i;
1400
1401 fp = xfdopen_for_write(fd);
1375 for (i = 0; i < st_temp->cnt_history; i++) 1402 for (i = 0; i < st_temp->cnt_history; i++)
1376 fprintf(fp, "%s\n", st_temp->history[i]); 1403 fprintf(fp, "%s\n", st_temp->history[i]);
1377 fclose(fp); 1404 fclose(fp);
@@ -1634,7 +1661,7 @@ static void ask_terminal(void)
1634 pfd.events = POLLIN; 1661 pfd.events = POLLIN;
1635 if (safe_poll(&pfd, 1, 0) == 0) { 1662 if (safe_poll(&pfd, 1, 0) == 0) {
1636 S.sent_ESC_br6n = 1; 1663 S.sent_ESC_br6n = 1;
1637 fputs("\033" "[6n", stdout); 1664 fputs(ESC"[6n", stdout);
1638 fflush_all(); /* make terminal see it ASAP! */ 1665 fflush_all(); /* make terminal see it ASAP! */
1639 } 1666 }
1640} 1667}
@@ -2089,7 +2116,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2089 case CTRL('L'): 2116 case CTRL('L'):
2090 vi_case(CTRL('L')|VI_CMDMODE_BIT:) 2117 vi_case(CTRL('L')|VI_CMDMODE_BIT:)
2091 /* Control-l -- clear screen */ 2118 /* Control-l -- clear screen */
2092 printf("\033[H"); /* cursor to top,left */ 2119 printf(ESC"[H"); /* cursor to top,left */
2093 redraw(0, command_len - cursor); 2120 redraw(0, command_len - cursor);
2094 break; 2121 break;
2095#if MAX_HISTORY > 0 2122#if MAX_HISTORY > 0
diff --git a/libbb/procps.c b/libbb/procps.c
index ec43b221e..fcf86d9bb 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -303,6 +303,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
303 goto got_entry; 303 goto got_entry;
304 closedir(sp->task_dir); 304 closedir(sp->task_dir);
305 sp->task_dir = NULL; 305 sp->task_dir = NULL;
306 sp->main_thread_pid = 0;
306 } 307 }
307#endif 308#endif
308 entry = readdir(sp->dir); 309 entry = readdir(sp->dir);
@@ -322,6 +323,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
322 char task_dir[sizeof("/proc/%u/task") + sizeof(int)*3]; 323 char task_dir[sizeof("/proc/%u/task") + sizeof(int)*3];
323 sprintf(task_dir, "/proc/%u/task", pid); 324 sprintf(task_dir, "/proc/%u/task", pid);
324 sp->task_dir = xopendir(task_dir); 325 sp->task_dir = xopendir(task_dir);
326 sp->main_thread_pid = pid;
325 continue; 327 continue;
326 } 328 }
327#endif 329#endif
diff --git a/libbb/pw_encrypt_sha.c b/libbb/pw_encrypt_sha.c
index 070e0d442..8aeaacad6 100644
--- a/libbb/pw_encrypt_sha.c
+++ b/libbb/pw_encrypt_sha.c
@@ -3,7 +3,7 @@
3 */ 3 */
4 4
5/* Prefix for optional rounds specification. */ 5/* Prefix for optional rounds specification. */
6static const char str_rounds[] = "rounds=%u$"; 6static const char str_rounds[] ALIGN1 = "rounds=%u$";
7 7
8/* Maximum salt string length. */ 8/* Maximum salt string length. */
9#define SALT_LEN_MAX 16 9#define SALT_LEN_MAX 16
@@ -19,8 +19,8 @@ NOINLINE
19sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) 19sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
20{ 20{
21 void (*sha_begin)(void *ctx) FAST_FUNC; 21 void (*sha_begin)(void *ctx) FAST_FUNC;
22 void (*sha_hash)(const void *buffer, size_t len, void *ctx) FAST_FUNC; 22 void (*sha_hash)(void *ctx, const void *buffer, size_t len) FAST_FUNC;
23 void (*sha_end)(void *resbuf, void *ctx) FAST_FUNC; 23 void (*sha_end)(void *ctx, void *resbuf) FAST_FUNC;
24 int _32or64; 24 int _32or64;
25 25
26 char *result, *resptr; 26 char *result, *resptr;
@@ -103,40 +103,40 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
103 103
104 /* Add KEY, SALT. */ 104 /* Add KEY, SALT. */
105 sha_begin(&ctx); 105 sha_begin(&ctx);
106 sha_hash(key_data, key_len, &ctx); 106 sha_hash(&ctx, key_data, key_len);
107 sha_hash(salt_data, salt_len, &ctx); 107 sha_hash(&ctx, salt_data, salt_len);
108 108
109 /* Compute alternate SHA sum with input KEY, SALT, and KEY. 109 /* Compute alternate SHA sum with input KEY, SALT, and KEY.
110 The final result will be added to the first context. */ 110 The final result will be added to the first context. */
111 sha_begin(&alt_ctx); 111 sha_begin(&alt_ctx);
112 sha_hash(key_data, key_len, &alt_ctx); 112 sha_hash(&alt_ctx, key_data, key_len);
113 sha_hash(salt_data, salt_len, &alt_ctx); 113 sha_hash(&alt_ctx, salt_data, salt_len);
114 sha_hash(key_data, key_len, &alt_ctx); 114 sha_hash(&alt_ctx, key_data, key_len);
115 sha_end(alt_result, &alt_ctx); 115 sha_end(&alt_ctx, alt_result);
116 116
117 /* Add result of this to the other context. */ 117 /* Add result of this to the other context. */
118 /* Add for any character in the key one byte of the alternate sum. */ 118 /* Add for any character in the key one byte of the alternate sum. */
119 for (cnt = key_len; cnt > _32or64; cnt -= _32or64) 119 for (cnt = key_len; cnt > _32or64; cnt -= _32or64)
120 sha_hash(alt_result, _32or64, &ctx); 120 sha_hash(&ctx, alt_result, _32or64);
121 sha_hash(alt_result, cnt, &ctx); 121 sha_hash(&ctx, alt_result, cnt);
122 122
123 /* Take the binary representation of the length of the key and for every 123 /* Take the binary representation of the length of the key and for every
124 1 add the alternate sum, for every 0 the key. */ 124 1 add the alternate sum, for every 0 the key. */
125 for (cnt = key_len; cnt != 0; cnt >>= 1) 125 for (cnt = key_len; cnt != 0; cnt >>= 1)
126 if ((cnt & 1) != 0) 126 if ((cnt & 1) != 0)
127 sha_hash(alt_result, _32or64, &ctx); 127 sha_hash(&ctx, alt_result, _32or64);
128 else 128 else
129 sha_hash(key_data, key_len, &ctx); 129 sha_hash(&ctx, key_data, key_len);
130 130
131 /* Create intermediate result. */ 131 /* Create intermediate result. */
132 sha_end(alt_result, &ctx); 132 sha_end(&ctx, alt_result);
133 133
134 /* Start computation of P byte sequence. */ 134 /* Start computation of P byte sequence. */
135 /* For every character in the password add the entire password. */ 135 /* For every character in the password add the entire password. */
136 sha_begin(&alt_ctx); 136 sha_begin(&alt_ctx);
137 for (cnt = 0; cnt < key_len; ++cnt) 137 for (cnt = 0; cnt < key_len; ++cnt)
138 sha_hash(key_data, key_len, &alt_ctx); 138 sha_hash(&alt_ctx, key_data, key_len);
139 sha_end(temp_result, &alt_ctx); 139 sha_end(&alt_ctx, temp_result);
140 140
141 /* NB: past this point, raw key_data is not used anymore */ 141 /* NB: past this point, raw key_data is not used anymore */
142 142
@@ -153,8 +153,8 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
153 /* For every character in the password add the entire password. */ 153 /* For every character in the password add the entire password. */
154 sha_begin(&alt_ctx); 154 sha_begin(&alt_ctx);
155 for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt) 155 for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
156 sha_hash(salt_data, salt_len, &alt_ctx); 156 sha_hash(&alt_ctx, salt_data, salt_len);
157 sha_end(temp_result, &alt_ctx); 157 sha_end(&alt_ctx, temp_result);
158 158
159 /* NB: past this point, raw salt_data is not used anymore */ 159 /* NB: past this point, raw salt_data is not used anymore */
160 160
@@ -174,31 +174,31 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
174 174
175 /* Add key or last result. */ 175 /* Add key or last result. */
176 if ((cnt & 1) != 0) 176 if ((cnt & 1) != 0)
177 sha_hash(p_bytes, key_len, &ctx); 177 sha_hash(&ctx, p_bytes, key_len);
178 else 178 else
179 sha_hash(alt_result, _32or64, &ctx); 179 sha_hash(&ctx, alt_result, _32or64);
180 /* Add salt for numbers not divisible by 3. */ 180 /* Add salt for numbers not divisible by 3. */
181 if (cnt % 3 != 0) 181 if (cnt % 3 != 0)
182 sha_hash(s_bytes, salt_len, &ctx); 182 sha_hash(&ctx, s_bytes, salt_len);
183 /* Add key for numbers not divisible by 7. */ 183 /* Add key for numbers not divisible by 7. */
184 if (cnt % 7 != 0) 184 if (cnt % 7 != 0)
185 sha_hash(p_bytes, key_len, &ctx); 185 sha_hash(&ctx, p_bytes, key_len);
186 /* Add key or last result. */ 186 /* Add key or last result. */
187 if ((cnt & 1) != 0) 187 if ((cnt & 1) != 0)
188 sha_hash(alt_result, _32or64, &ctx); 188 sha_hash(&ctx, alt_result, _32or64);
189 else 189 else
190 sha_hash(p_bytes, key_len, &ctx); 190 sha_hash(&ctx, p_bytes, key_len);
191 191
192 sha_end(alt_result, &ctx); 192 sha_end(&ctx, alt_result);
193 } 193 }
194 194
195 /* Append encrypted password to result buffer */ 195 /* Append encrypted password to result buffer */
196//TODO: replace with something like 196//TODO: replace with something like
197// bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64); 197// bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64);
198#define b64_from_24bit(B2, B1, B0, N) \ 198#define b64_from_24bit(B2, B1, B0, N) \
199do { \ 199do { \
200 unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ 200 unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \
201 resptr = to64(resptr, w, N); \ 201 resptr = to64(resptr, w, N); \
202} while (0) 202} while (0)
203 if (is_sha512 == '5') { 203 if (is_sha512 == '5') {
204 unsigned i = 0; 204 unsigned i = 0;
diff --git a/libbb/read_printf.c b/libbb/read_printf.c
index 7ca3d68c3..8664bc625 100644
--- a/libbb/read_printf.c
+++ b/libbb/read_printf.c
@@ -15,7 +15,7 @@
15) 15)
16 16
17#if ZIPPED 17#if ZIPPED
18# include "unarchive.h" 18# include "archive.h"
19#endif 19#endif
20 20
21 21
diff --git a/libbb/simplify_path.c b/libbb/simplify_path.c
index 3818d32be..89dc5bdf2 100644
--- a/libbb/simplify_path.c
+++ b/libbb/simplify_path.c
@@ -15,17 +15,17 @@ char* FAST_FUNC bb_simplify_abs_path_inplace(char *start)
15 p = s = start; 15 p = s = start;
16 do { 16 do {
17 if (*p == '/') { 17 if (*p == '/') {
18 if (*s == '/') { /* skip duplicate (or initial) slash */ 18 if (*s == '/') { /* skip duplicate (or initial) slash */
19 continue; 19 continue;
20 } 20 }
21 if (*s == '.') { 21 if (*s == '.') {
22 if (s[1] == '/' || !s[1]) { /* remove extra '.' */ 22 if (s[1] == '/' || !s[1]) { /* remove extra '.' */
23 continue; 23 continue;
24 } 24 }
25 if ((s[1] == '.') && (s[2] == '/' || !s[2])) { 25 if ((s[1] == '.') && (s[2] == '/' || !s[2])) {
26 ++s; 26 ++s;
27 if (p > start) { 27 if (p > start) {
28 while (*--p != '/') /* omit previous dir */ 28 while (*--p != '/') /* omit previous dir */
29 continue; 29 continue;
30 } 30 }
31 continue; 31 continue;
@@ -35,8 +35,8 @@ char* FAST_FUNC bb_simplify_abs_path_inplace(char *start)
35 *++p = *s; 35 *++p = *s;
36 } while (*++s); 36 } while (*++s);
37 37
38 if ((p == start) || (*p != '/')) { /* not a trailing slash */ 38 if ((p == start) || (*p != '/')) { /* not a trailing slash */
39 ++p; /* so keep last character */ 39 ++p; /* so keep last character */
40 } 40 }
41 *p = '\0'; 41 *p = '\0';
42 return p; 42 return p;
diff --git a/libbb/time.c b/libbb/time.c
index 2a74d34c2..1eb2d75c2 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -93,6 +93,7 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
93 * 93 *
94 * This coincides with the format of "touch -t TIME" 94 * This coincides with the format of "touch -t TIME"
95 */ 95 */
96 unsigned cur_year = ptm->tm_year;
96 int len = strchrnul(date_str, '.') - date_str; 97 int len = strchrnul(date_str, '.') - date_str;
97 98
98 /* MM[.SS] */ 99 /* MM[.SS] */
@@ -133,6 +134,17 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
133 &end) >= 5) { 134 &end) >= 5) {
134 /* Adjust month from 1-12 to 0-11 */ 135 /* Adjust month from 1-12 to 0-11 */
135 ptm->tm_mon -= 1; 136 ptm->tm_mon -= 1;
137 if ((int)cur_year >= 50) { /* >= 1950 */
138 /* Adjust year: */
139 /* 1. Put it in the current century */
140 ptm->tm_year += (cur_year / 100) * 100;
141 /* 2. If too far in the past, +100 years */
142 if (ptm->tm_year < cur_year - 50)
143 ptm->tm_year += 100;
144 /* 3. If too far in the future, -100 years */
145 if (ptm->tm_year > cur_year + 50)
146 ptm->tm_year -= 100;
147 }
136 } else 148 } else
137 /* ccyymmddHHMM[.SS] */ 149 /* ccyymmddHHMM[.SS] */
138 if (len == 12 && sscanf(date_str, "%4u%2u%2u%2u%2u%c", 150 if (len == 12 && sscanf(date_str, "%4u%2u%2u%2u%2u%c",
diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c
index 9263859f5..8c78f5e20 100644
--- a/libbb/u_signal_names.c
+++ b/libbb/u_signal_names.c
@@ -7,6 +7,13 @@
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 FEATURE_RTMINMAX
11//config: bool "Support RTMIN[+n] and RTMAX[-n] signal names"
12//config: default y
13//config: help
14//config: Support RTMIN[+n] and RTMAX[-n] signal names
15//config: in kill, killall etc. This costs ~250 bytes.
16
10#include "libbb.h" 17#include "libbb.h"
11 18
12/* Believe it or not, but some arches have more than 32 SIGs! 19/* Believe it or not, but some arches have more than 32 SIGs!
@@ -117,6 +124,16 @@ static const char signals[][7] = {
117#ifdef SIGSYS 124#ifdef SIGSYS
118 [SIGSYS ] = "SYS", 125 [SIGSYS ] = "SYS",
119#endif 126#endif
127#if ENABLE_FEATURE_RTMINMAX
128# ifdef __SIGRTMIN
129 [__SIGRTMIN] = "RTMIN",
130# endif
131// This makes array about x2 bigger.
132// More compact approach is to special-case SIGRTMAX in print_signames()
133//# ifdef __SIGRTMAX
134// [__SIGRTMAX] = "RTMAX",
135//# endif
136#endif
120}; 137};
121 138
122// Convert signal name to number. 139// Convert signal name to number.
@@ -134,20 +151,54 @@ int FAST_FUNC get_signum(const char *name)
134 if (strcasecmp(name, signals[i]) == 0) 151 if (strcasecmp(name, signals[i]) == 0)
135 return i; 152 return i;
136 153
137#if ENABLE_DESKTOP && (defined(SIGIOT) || defined(SIGIO)) 154#if ENABLE_DESKTOP
155# if defined(SIGIOT) || defined(SIGIO)
138 /* SIGIO[T] are aliased to other names, 156 /* SIGIO[T] are aliased to other names,
139 * thus cannot be stored in the signals[] array. 157 * thus cannot be stored in the signals[] array.
140 * Need special code to recognize them */ 158 * Need special code to recognize them */
141 if ((name[0] | 0x20) == 'i' && (name[1] | 0x20) == 'o') { 159 if ((name[0] | 0x20) == 'i' && (name[1] | 0x20) == 'o') {
142#ifdef SIGIO 160# ifdef SIGIO
143 if (!name[2]) 161 if (!name[2])
144 return SIGIO; 162 return SIGIO;
145#endif 163# endif
146#ifdef SIGIOT 164# ifdef SIGIOT
147 if ((name[2] | 0x20) == 't' && !name[3]) 165 if ((name[2] | 0x20) == 't' && !name[3])
148 return SIGIOT; 166 return SIGIOT;
149#endif 167# endif
150 } 168 }
169# endif
170#endif
171
172#if ENABLE_FEATURE_RTMINMAX
173# if defined(SIGRTMIN) && defined(SIGRTMAX)
174/* libc may use some rt sigs for pthreads and therefore "remap" SIGRTMIN/MAX,
175 * but we want to use "raw" SIGRTMIN/MAX. Underscored names, if exist, provide
176 * them. If they don't exist, fall back to non-underscored ones: */
177# if !defined(__SIGRTMIN)
178# define __SIGRTMIN SIGRTMIN
179# endif
180# if !defined(__SIGRTMAX)
181# define __SIGRTMAX SIGRTMAX
182# endif
183 if (strncasecmp(name, "RTMIN", 5) == 0) {
184 if (!name[5])
185 return __SIGRTMIN;
186 if (name[5] == '+') {
187 i = bb_strtou(name + 6, NULL, 10);
188 if (!errno && i <= __SIGRTMAX - __SIGRTMIN)
189 return __SIGRTMIN + i;
190 }
191 }
192 else if (strncasecmp(name, "RTMAX", 5) == 0) {
193 if (!name[5])
194 return __SIGRTMAX;
195 if (name[5] == '-') {
196 i = bb_strtou(name + 6, NULL, 10);
197 if (!errno && i <= __SIGRTMAX - __SIGRTMIN)
198 return __SIGRTMAX - i;
199 }
200 }
201# endif
151#endif 202#endif
152 203
153 return -1; 204 return -1;
@@ -175,6 +226,11 @@ void FAST_FUNC print_signames(void)
175 for (signo = 1; signo < ARRAY_SIZE(signals); signo++) { 226 for (signo = 1; signo < ARRAY_SIZE(signals); signo++) {
176 const char *name = signals[signo]; 227 const char *name = signals[signo];
177 if (name[0]) 228 if (name[0])
178 puts(name); 229 printf("%2u) %s\n", signo, name);
179 } 230 }
231#if ENABLE_FEATURE_RTMINMAX
232# ifdef __SIGRTMAX
233 printf("%2u) %s\n", __SIGRTMAX, "RTMAX");
234# endif
235#endif
180} 236}
diff --git a/libbb/unicode.c b/libbb/unicode.c
index 70c6abe00..cf0c6bed9 100644
--- a/libbb/unicode.c
+++ b/libbb/unicode.c
@@ -1005,8 +1005,11 @@ static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char
1005 d++; 1005 d++;
1006 } 1006 }
1007 } 1007 }
1008 if (stats) 1008 if (stats) {
1009 stats->byte_count = stats->unicode_count = (d - dst); 1009 stats->byte_count = (d - dst);
1010 stats->unicode_count = (d - dst);
1011 stats->unicode_width = (d - dst);
1012 }
1010 return dst; 1013 return dst;
1011 } 1014 }
1012 1015
diff --git a/libbb/update_passwd.c b/libbb/update_passwd.c
index dc5029223..a30af6f72 100644
--- a/libbb/update_passwd.c
+++ b/libbb/update_passwd.c
@@ -58,7 +58,7 @@ static void check_selinux_update_passwd(const char *username)
58 6) delete a user from a group: update_passwd(FILE, GROUP, NULL, MEMBER) 58 6) delete a user from a group: update_passwd(FILE, GROUP, NULL, MEMBER)
59 only if CONFIG_FEATURE_DEL_USER_FROM_GROUP=y and member != NULL 59 only if CONFIG_FEATURE_DEL_USER_FROM_GROUP=y and member != NULL
60 60
61 7) change user's passord: update_passwd(FILE, USER, NEW_PASSWD, NULL) 61 7) change user's password: update_passwd(FILE, USER, NEW_PASSWD, NULL)
62 only if CONFIG_PASSWD=y and applet_name[0] == 'p' like in passwd 62 only if CONFIG_PASSWD=y and applet_name[0] == 'p' like in passwd
63 or if CONFIG_CHPASSWD=y and applet_name[0] == 'c' like in chpasswd 63 or if CONFIG_CHPASSWD=y and applet_name[0] == 'c' like in chpasswd
64 64
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 07504b75b..a02a504b0 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -234,7 +234,7 @@ static int wh_helper(int value, int def_val, const char *env_name, int *err)
234 char *s = getenv(env_name); 234 char *s = getenv(env_name);
235 if (s) { 235 if (s) {
236 value = atoi(s); 236 value = atoi(s);
237 /* If LINES/COLUMNS are set, pretent that there is 237 /* If LINES/COLUMNS are set, pretend that there is
238 * no error getting w/h, this prevents some ugly 238 * no error getting w/h, this prevents some ugly
239 * cursor tricks by our callers */ 239 * cursor tricks by our callers */
240 *err = 0; 240 *err = 0;
diff --git a/libpwdgrp/pwd_grp_internal.c b/libpwdgrp/pwd_grp_internal.c
index 04e436fae..d6483be84 100644
--- a/libpwdgrp/pwd_grp_internal.c
+++ b/libpwdgrp/pwd_grp_internal.c
@@ -37,12 +37,12 @@ int GETXXKEY_R_FUNC(GETXXKEY_R_KEYTYPE key,
37 while (1) { 37 while (1) {
38 rv = bb__pgsreader(GETXXKEY_R_PARSER, resultbuf, buffer, buflen, stream); 38 rv = bb__pgsreader(GETXXKEY_R_PARSER, resultbuf, buffer, buflen, stream);
39 if (!rv) { 39 if (!rv) {
40 if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */ 40 if (GETXXKEY_R_TEST(resultbuf)) { /* found key? */
41 *result = resultbuf; 41 *result = resultbuf;
42 break; 42 break;
43 } 43 }
44 } else { 44 } else {
45 if (rv == ENOENT) { /* end-of-file encountered. */ 45 if (rv == ENOENT) { /* EOF encountered */
46 rv = 0; 46 rv = 0;
47 } 47 }
48 break; 48 break;
diff --git a/loginutils/deluser.c b/loginutils/deluser.c
index 08ca266d0..47a10fe14 100644
--- a/loginutils/deluser.c
+++ b/loginutils/deluser.c
@@ -14,41 +14,90 @@
14int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 14int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
15int deluser_main(int argc, char **argv) 15int deluser_main(int argc, char **argv)
16{ 16{
17 if (argc != 2 17 /* User or group name */
18 && (!ENABLE_FEATURE_DEL_USER_FROM_GROUP 18 char *name;
19 || applet_name[3] != 'g' 19 /* Username (non-NULL only in "delgroup USER GROUP" case) */
20 || argc != 3) 20 char *member;
21 ) { 21 /* Name of passwd or group file */
22 bb_show_usage(); 22 const char *pfile;
23 } 23 /* Name of shadow or gshadow file */
24 const char *sfile;
25 /* Are we deluser or delgroup? */
26 int do_deluser = (ENABLE_DELUSER && (!ENABLE_DELGROUP || applet_name[3] == 'u'));
24 27
25 if (geteuid()) 28 if (geteuid() != 0)
26 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); 29 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
27 30
28 if (ENABLE_DELUSER && applet_name[3] == 'u') { 31 name = argv[1];
29 /* deluser USER */ 32 member = NULL;
30 if (update_passwd(bb_path_passwd_file, argv[1], NULL, NULL) < 0) 33
31 return EXIT_FAILURE; 34 switch (argc) {
32 if (ENABLE_FEATURE_SHADOWPASSWDS) 35 case 3:
33 if (update_passwd(bb_path_shadow_file, argv[1], NULL, NULL) < 0) 36 if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || do_deluser)
34 return EXIT_FAILURE; 37 break;
35 } else if (ENABLE_DELGROUP) { 38 /* It's "delgroup USER GROUP" */
36 /* delgroup ... */ 39 member = name;
37 if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || argc != 3) { 40 name = argv[2];
38 /* delgroup GROUP */ 41 /* Fallthrough */
39 if (update_passwd(bb_path_group_file, argv[1], NULL, NULL) < 0) 42
40 return EXIT_FAILURE; 43 case 2:
44 if (do_deluser) {
45 /* "deluser USER" */
46 xgetpwnam(name); /* bail out if USER is wrong */
47 pfile = bb_path_passwd_file;
41 if (ENABLE_FEATURE_SHADOWPASSWDS) 48 if (ENABLE_FEATURE_SHADOWPASSWDS)
42 if (update_passwd(bb_path_gshadow_file, argv[1], NULL, NULL) < 0) 49 sfile = bb_path_shadow_file;
43 return EXIT_FAILURE;
44 } else { 50 } else {
45 /* delgroup USER GROUP */ 51 struct group *gr;
46 if (update_passwd(bb_path_group_file, argv[2], NULL, argv[1]) < 0) 52 do_delgroup:
47 return EXIT_FAILURE; 53 /* "delgroup GROUP" or "delgroup USER GROUP" */
54 if (do_deluser < 0) { /* delgroup after deluser? */
55 gr = getgrnam(name);
56 if (!gr)
57 return EXIT_SUCCESS;
58 } else {
59 gr = xgetgrnam(name); /* bail out if GROUP is wrong */
60 }
61 if (!member) {
62 /* "delgroup GROUP" */
63 struct passwd *pw;
64 struct passwd pwent;
65 /* Check if the group is in use */
66#define passwd_buf bb_common_bufsiz1
67 while (!getpwent_r(&pwent, passwd_buf, sizeof(passwd_buf), &pw)) {
68 if (pwent.pw_gid == gr->gr_gid)
69 bb_error_msg_and_die("'%s' still has '%s' as their primary group!", pwent.pw_name, name);
70 }
71 //endpwent();
72 }
73 pfile = bb_path_group_file;
48 if (ENABLE_FEATURE_SHADOWPASSWDS) 74 if (ENABLE_FEATURE_SHADOWPASSWDS)
49 if (update_passwd(bb_path_gshadow_file, argv[2], NULL, argv[1]) < 0) 75 sfile = bb_path_gshadow_file;
50 return EXIT_FAILURE; 76 }
77
78 /* Modify pfile, then sfile */
79 do {
80 if (update_passwd(pfile, name, NULL, member) == -1)
81 return EXIT_FAILURE;
82 if (ENABLE_FEATURE_SHADOWPASSWDS) {
83 pfile = sfile;
84 sfile = NULL;
85 }
86 } while (ENABLE_FEATURE_SHADOWPASSWDS && pfile);
87
88 if (ENABLE_DELGROUP && do_deluser > 0) {
89 /* "deluser USER" also should try to delete
90 * same-named group. IOW: do "delgroup USER"
91 */
92// On debian deluser is a perl script that calls userdel.
93// From man userdel:
94// If USERGROUPS_ENAB is defined to yes in /etc/login.defs, userdel will
95// delete the group with the same name as the user.
96 do_deluser = -1;
97 goto do_delgroup;
51 } 98 }
99 return EXIT_SUCCESS;
52 } 100 }
53 return EXIT_SUCCESS; 101 /* Reached only if number of command line args is wrong */
102 bb_show_usage();
54} 103}
diff --git a/loginutils/login.c b/loginutils/login.c
index 9a624df9a..c285b45a1 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -217,6 +217,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
217 const char *failed_msg; 217 const char *failed_msg;
218 struct passwd pwdstruct; 218 struct passwd pwdstruct;
219 char pwdbuf[256]; 219 char pwdbuf[256];
220 char **pamenv;
220#endif 221#endif
221 222
222 username[0] = '\0'; 223 username[0] = '\0';
@@ -400,6 +401,16 @@ int login_main(int argc UNUSED_PARAM, char **argv)
400 (!(opt & LOGIN_OPT_p) * SETUP_ENV_CLEARENV) + SETUP_ENV_CHANGEENV, 401 (!(opt & LOGIN_OPT_p) * SETUP_ENV_CLEARENV) + SETUP_ENV_CHANGEENV,
401 pw); 402 pw);
402 403
404#if ENABLE_PAM
405 /* Modules such as pam_env will setup the PAM environment,
406 * which should be copied into the new environment. */
407 pamenv = pam_getenvlist(pamh);
408 if (pamenv) while (*pamenv) {
409 putenv(*pamenv);
410 pamenv++;
411 }
412#endif
413
403 motd(); 414 motd();
404 415
405 if (pw->pw_uid == 0) 416 if (pw->pw_uid == 0)
diff --git a/loginutils/su.c b/loginutils/su.c
index 5bec4bc8b..db303af6d 100644
--- a/loginutils/su.c
+++ b/loginutils/su.c
@@ -8,6 +8,16 @@
8#include "libbb.h" 8#include "libbb.h"
9#include <syslog.h> 9#include <syslog.h>
10 10
11//usage:#define su_trivial_usage
12//usage: "[OPTIONS] [-] [USER]"
13//usage:#define su_full_usage "\n\n"
14//usage: "Run shell under USER (by default, root)\n"
15//usage: "\nOptions:"
16//usage: "\n -,-l Clear environment, run shell as login shell"
17//usage: "\n -p,-m Do not set new $HOME, $SHELL, $USER, $LOGNAME"
18//usage: "\n -c CMD Command to pass to 'sh -c'"
19//usage: "\n -s SH Shell to use instead of user's default"
20
11#if ENABLE_FEATURE_SU_CHECKS_SHELLS 21#if ENABLE_FEATURE_SU_CHECKS_SHELLS
12/* Return 1 if SHELL is a restricted shell (one not returned by 22/* Return 1 if SHELL is a restricted shell (one not returned by
13 * getusershell), else 0, meaning it is a standard shell. */ 23 * getusershell), else 0, meaning it is a standard shell. */
@@ -42,7 +52,9 @@ int su_main(int argc UNUSED_PARAM, char **argv)
42 struct passwd *pw; 52 struct passwd *pw;
43 uid_t cur_uid = getuid(); 53 uid_t cur_uid = getuid();
44 const char *tty; 54 const char *tty;
55#if ENABLE_FEATURE_UTMP
45 char user_buf[64]; 56 char user_buf[64];
57#endif
46 const char *old_user; 58 const char *old_user;
47 59
48 flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); 60 flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell);
diff --git a/mailutils/mail.c b/mailutils/mail.c
index 9b4bebce5..44957016f 100644
--- a/mailutils/mail.c
+++ b/mailutils/mail.c
@@ -75,13 +75,16 @@ void FAST_FUNC launch_helper(const char **argv)
75 atexit(kill_helper); 75 atexit(kill_helper);
76} 76}
77 77
78const FAST_FUNC char *command(const char *fmt, const char *param) 78char* FAST_FUNC send_mail_command(const char *fmt, const char *param)
79{ 79{
80 const char *msg = fmt; 80 char *msg;
81 if (timeout) 81 if (timeout)
82 alarm(timeout); 82 alarm(timeout);
83 if (msg) { 83 msg = (char*)fmt;
84 if (fmt) {
84 msg = xasprintf(fmt, param); 85 msg = xasprintf(fmt, param);
86 if (verbose)
87 bb_error_msg("send:'%s'", msg);
85 printf("%s\r\n", msg); 88 printf("%s\r\n", msg);
86 } 89 }
87 fflush_all(); 90 fflush_all();
@@ -90,7 +93,7 @@ const FAST_FUNC char *command(const char *fmt, const char *param)
90 93
91// NB: parse_url can modify url[] (despite const), but only if '@' is there 94// NB: parse_url can modify url[] (despite const), but only if '@' is there
92/* 95/*
93static char FAST_FUNC *parse_url(char *url, char **user, char **pass) 96static char* FAST_FUNC parse_url(char *url, char **user, char **pass)
94{ 97{
95 // parse [user[:pass]@]host 98 // parse [user[:pass]@]host
96 // return host 99 // return host
diff --git a/mailutils/mail.h b/mailutils/mail.h
index e0048fbfa..d1d783055 100644
--- a/mailutils/mail.h
+++ b/mailutils/mail.h
@@ -1,7 +1,16 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * helper routines
4 *
5 * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
1 9
2struct globals { 10struct globals {
3 pid_t helper_pid; 11 pid_t helper_pid;
4 unsigned timeout; 12 unsigned timeout;
13 unsigned verbose;
5 unsigned opts; 14 unsigned opts;
6 char *user; 15 char *user;
7 char *pass; 16 char *pass;
@@ -12,6 +21,7 @@ struct globals {
12 21
13#define G (*ptr_to_globals) 22#define G (*ptr_to_globals)
14#define timeout (G.timeout ) 23#define timeout (G.timeout )
24#define verbose (G.verbose )
15#define opts (G.opts ) 25#define opts (G.opts )
16//#define user (G.user ) 26//#define user (G.user )
17//#define pass (G.pass ) 27//#define pass (G.pass )
@@ -26,9 +36,9 @@ struct globals {
26 36
27//char FAST_FUNC *parse_url(char *url, char **user, char **pass); 37//char FAST_FUNC *parse_url(char *url, char **user, char **pass);
28 38
29void FAST_FUNC launch_helper(const char **argv); 39void launch_helper(const char **argv) FAST_FUNC;
30void FAST_FUNC get_cred_or_die(int fd); 40void get_cred_or_die(int fd) FAST_FUNC;
31 41
32const FAST_FUNC char *command(const char *fmt, const char *param); 42char *send_mail_command(const char *fmt, const char *param) FAST_FUNC;
33 43
34void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol); 44void encode_base64(char *fname, const char *text, const char *eol) FAST_FUNC;
diff --git a/mailutils/mime.c b/mailutils/mime.c
index 682cf4536..1e393ed31 100644
--- a/mailutils/mime.c
+++ b/mailutils/mime.c
@@ -99,6 +99,28 @@ Content-Transfer-Encoding: 7bit
99...random junk added by mailing list robots and such... 99...random junk added by mailing list robots and such...
100*/ 100*/
101 101
102/* man makemime:
103
104 * -c TYPE: create a (non-multipart) MIME section with Content-Type: TYPE
105 * makemime -c TYPE [-e ENCODING] [-o OUTFILE] [-C CHARSET] [-N NAME] [-a HEADER...] FILE
106 * The -C option sets the MIME charset attribute for text/plain content.
107 * The -N option sets the name attribute for Content-Type:
108 * Encoding must be one of the following: 7bit, 8bit, quoted-printable, or base64.
109
110 * -m multipart/TYPE: create a multipart MIME collection with Content-Type: multipart/TYPE
111 * makemime -m multipart/TYPE [-e ENCODING] [-o OUTFILE] [-a HEADER...] FILE
112 * Type must be either "multipart/mixed", "multipart/alternative", or some other MIME multipart content type.
113 * Additionally, encoding can only be "7bit" or "8bit", and will default to "8bit" if not specified.
114 * Finally, filename must be a MIME-formatted section, NOT a regular file.
115 * The -m option creates an initial multipart MIME collection, that contains only one MIME section, taken from filename.
116 * The collection is written to standard output, or the pipe or to outputfile.
117
118 * -j FILE1: add a section to a multipart MIME collection
119 * makemime -j FILE1 [-o OUTFILE] FILE2
120 * FILE1 must be a MIME collection that was previously created by the -m option.
121 * FILE2 must be a MIME section that was previously created by the -c option.
122 * The -j options adds the MIME section in FILE2 to the MIME collection in FILE1.
123 */
102int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 124int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
103int makemime_main(int argc UNUSED_PARAM, char **argv) 125int makemime_main(int argc UNUSED_PARAM, char **argv)
104{ 126{
@@ -107,14 +129,14 @@ int makemime_main(int argc UNUSED_PARAM, char **argv)
107#define boundary opt_output 129#define boundary opt_output
108 130
109 enum { 131 enum {
110 OPT_c = 1 << 0, // Content-Type: 132 OPT_c = 1 << 0, // create (non-multipart) section
111 OPT_e = 1 << 1, // Content-Transfer-Encoding. Ignored. Assumed base64 133 OPT_e = 1 << 1, // Content-Transfer-Encoding. Ignored. Assumed base64
112 OPT_o = 1 << 2, // output to 134 OPT_o = 1 << 2, // output to
113 OPT_C = 1 << 3, // charset 135 OPT_C = 1 << 3, // charset
114 OPT_N = 1 << 4, // COMPAT 136 OPT_N = 1 << 4, // COMPAT
115 OPT_a = 1 << 5, // additional headers 137 OPT_a = 1 << 5, // additional headers
116 OPT_m = 1 << 6, // COMPAT 138 //OPT_m = 1 << 6, // create mutipart section
117 OPT_j = 1 << 7, // COMPAT 139 //OPT_j = 1 << 7, // join section to multipart section
118 }; 140 };
119 141
120 INIT_G(); 142 INIT_G();
@@ -122,8 +144,8 @@ int makemime_main(int argc UNUSED_PARAM, char **argv)
122 // parse options 144 // parse options
123 opt_complementary = "a::"; 145 opt_complementary = "a::";
124 opts = getopt32(argv, 146 opts = getopt32(argv,
125 "c:e:o:C:N:a:m:j:", 147 "c:e:o:C:N:a", //:m:j:",
126 &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers, NULL, NULL 148 &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL
127 ); 149 );
128 //argc -= optind; 150 //argc -= optind;
129 argv += optind; 151 argv += optind;
diff --git a/mailutils/popmaildir.c b/mailutils/popmaildir.c
index 77ec71129..6b733441f 100644
--- a/mailutils/popmaildir.c
+++ b/mailutils/popmaildir.c
@@ -14,9 +14,10 @@
14 14
15static void pop3_checkr(const char *fmt, const char *param, char **ret) 15static void pop3_checkr(const char *fmt, const char *param, char **ret)
16{ 16{
17 const char *msg = command(fmt, param); 17 char *msg = send_mail_command(fmt, param);
18 char *answer = xmalloc_fgetline(stdin); 18 char *answer = xmalloc_fgetline(stdin);
19 if (answer && '+' == answer[0]) { 19 if (answer && '+' == answer[0]) {
20 free(msg);
20 if (timeout) 21 if (timeout)
21 alarm(0); 22 alarm(0);
22 if (ret) { 23 if (ret) {
@@ -27,7 +28,7 @@ static void pop3_checkr(const char *fmt, const char *param, char **ret)
27 free(answer); 28 free(answer);
28 return; 29 return;
29 } 30 }
30 bb_error_msg_and_die("%s failed: %s", msg, answer); 31 bb_error_msg_and_die("%s failed, reply was: %s", msg, answer);
31} 32}
32 33
33static void pop3_check(const char *fmt, const char *param) 34static void pop3_check(const char *fmt, const char *param)
diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c
index ec97cf8af..8096288ef 100644
--- a/mailutils/sendmail.c
+++ b/mailutils/sendmail.c
@@ -6,6 +6,38 @@
6 * 6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree. 7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */ 8 */
9
10//usage:#define sendmail_trivial_usage
11//usage: "[OPTIONS] [RECIPIENT_EMAIL]..."
12//usage:#define sendmail_full_usage "\n\n"
13//usage: "Read email from stdin and send it\n"
14//usage: "\nStandard options:"
15//usage: "\n -t Read additional recipients from message body"
16//usage: "\n -f SENDER Sender (required)"
17//usage: "\n -o OPTIONS Various options. -oi implied, others are ignored"
18//usage: "\n -i -oi synonym. implied and ignored"
19//usage: "\n"
20//usage: "\nBusybox specific options:"
21//usage: "\n -v Verbose"
22//usage: "\n -w SECS Network timeout"
23//usage: "\n -H 'PROG ARGS' Run connection helper"
24//usage: "\n Examples:"
25//usage: "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp"
26//usage: "\n -connect smtp.gmail.com:25' <email.txt"
27//usage: "\n [4<username_and_passwd.txt | -au<username> -ap<password>]"
28//usage: "\n -H 'exec openssl s_client -quiet -tls1"
29//usage: "\n -connect smtp.gmail.com:465' <email.txt"
30//usage: "\n [4<username_and_passwd.txt | -au<username> -ap<password>]"
31//usage: "\n -S HOST[:PORT] Server"
32//usage: "\n -au<username> Username for AUTH LOGIN"
33//usage: "\n -ap<password> Password for AUTH LOGIN"
34//usage: "\n -am<method> Authentication method. Ignored. LOGIN is implied"
35//usage: "\n"
36//usage: "\nOther options are silently ignored; -oi -t is implied"
37//usage: IF_MAKEMIME(
38//usage: "\nUse makemime applet to create message with attachments"
39//usage: )
40
9#include "libbb.h" 41#include "libbb.h"
10#include "mail.h" 42#include "mail.h"
11 43
@@ -13,23 +45,35 @@
13// set to 0 to not limit 45// set to 0 to not limit
14#define MAX_HEADERS 256 46#define MAX_HEADERS 256
15 47
48static void send_r_n(const char *s)
49{
50 if (verbose)
51 bb_error_msg("send:'%s'", s);
52 printf("%s\r\n", s);
53}
54
16static int smtp_checkp(const char *fmt, const char *param, int code) 55static int smtp_checkp(const char *fmt, const char *param, int code)
17{ 56{
18 char *answer; 57 char *answer;
19 const char *msg = command(fmt, param); 58 char *msg = send_mail_command(fmt, param);
20 // read stdin 59 // read stdin
21 // if the string has a form \d\d\d- -- read next string. E.g. EHLO response 60 // if the string has a form NNN- -- read next string. E.g. EHLO response
22 // parse first bytes to a number 61 // parse first bytes to a number
23 // if code = -1 then just return this number 62 // if code = -1 then just return this number
24 // if code != -1 then checks whether the number equals the code 63 // if code != -1 then checks whether the number equals the code
25 // if not equal -> die saying msg 64 // if not equal -> die saying msg
26 while ((answer = xmalloc_fgetline(stdin)) != NULL) 65 while ((answer = xmalloc_fgetline(stdin)) != NULL) {
66 if (verbose)
67 bb_error_msg("recv:'%.*s' %d", (int)(strchrnul(answer, '\r') - answer), answer, verbose);
27 if (strlen(answer) <= 3 || '-' != answer[3]) 68 if (strlen(answer) <= 3 || '-' != answer[3])
28 break; 69 break;
70 free(answer);
71 }
29 if (answer) { 72 if (answer) {
30 int n = atoi(answer); 73 int n = atoi(answer);
31 if (timeout) 74 if (timeout)
32 alarm(0); 75 alarm(0);
76 free(msg);
33 free(answer); 77 free(answer);
34 if (-1 == code || n == code) 78 if (-1 == code || n == code)
35 return n; 79 return n;
@@ -86,6 +130,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
86 OPT_H = 1 << 5, // use external connection helper 130 OPT_H = 1 << 5, // use external connection helper
87 OPT_S = 1 << 6, // specify connection string 131 OPT_S = 1 << 6, // specify connection string
88 OPT_a = 1 << 7, // authentication tokens 132 OPT_a = 1 << 7, // authentication tokens
133 OPT_v = 1 << 8, // verbosity
89 }; 134 };
90 135
91 // init global variables 136 // init global variables
@@ -96,12 +141,13 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
96 G.fp0 = xfdopen_for_read(3); 141 G.fp0 = xfdopen_for_read(3);
97 142
98 // parse options 143 // parse options
99 // -f is required. -H and -S are mutually exclusive 144 // -v is a counter, -f is required. -H and -S are mutually exclusive, -a is a list
100 opt_complementary = "f:w+:H--S:S--H:a::"; 145 opt_complementary = "vv:f:w+:H--S:S--H:a::";
101 // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect 146 // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect
102 // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility, 147 // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility,
103 // it is still under development. 148 // it is still under development.
104 opts = getopt32(argv, "tf:o:iw:H:S:a::", &opt_from, NULL, &timeout, &opt_connect, &opt_connect, &list); 149 opts = getopt32(argv, "tf:o:iw:H:S:a::v", &opt_from, NULL,
150 &timeout, &opt_connect, &opt_connect, &list, &verbose);
105 //argc -= optind; 151 //argc -= optind;
106 argv += optind; 152 argv += optind;
107 153
@@ -214,7 +260,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
214 if ('.' == s[0] /*&& '\0' == s[1] */) 260 if ('.' == s[0] /*&& '\0' == s[1] */)
215 printf("."); 261 printf(".");
216 // dump read line 262 // dump read line
217 printf("%s\r\n", s); 263 send_r_n(s);
218 free(s); 264 free(s);
219 continue; 265 continue;
220 } 266 }
@@ -261,14 +307,14 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
261 goto bail; 307 goto bail;
262 // dump the headers 308 // dump the headers
263 while (list) { 309 while (list) {
264 printf("%s\r\n", (char *) llist_pop(&list)); 310 send_r_n((char *) llist_pop(&list));
265 } 311 }
266 // stop analyzing headers 312 // stop analyzing headers
267 code++; 313 code++;
268 // N.B. !s means: we read nothing, and nothing to be read in the future. 314 // N.B. !s means: we read nothing, and nothing to be read in the future.
269 // just dump empty line and break the loop 315 // just dump empty line and break the loop
270 if (!s) { 316 if (!s) {
271 puts("\r"); 317 send_r_n("");
272 break; 318 break;
273 } 319 }
274 // go dump message body 320 // go dump message body
diff --git a/miscutils/bbconfig.c b/miscutils/bbconfig.c
index 286077168..7c30669a3 100644
--- a/miscutils/bbconfig.c
+++ b/miscutils/bbconfig.c
@@ -4,7 +4,7 @@
4#include "libbb.h" 4#include "libbb.h"
5#include "bbconfigopts.h" 5#include "bbconfigopts.h"
6#if ENABLE_FEATURE_COMPRESS_BBCONFIG 6#if ENABLE_FEATURE_COMPRESS_BBCONFIG
7# include "unarchive.h" 7# include "archive.h"
8# include "bbconfigopts_bz2.h" 8# include "bbconfigopts_bz2.h"
9#endif 9#endif
10 10
@@ -15,7 +15,7 @@ int bbconfig_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
15 bunzip_data *bd; 15 bunzip_data *bd;
16 int i = start_bunzip(&bd, 16 int i = start_bunzip(&bd,
17 /* src_fd: */ -1, 17 /* src_fd: */ -1,
18 /* inbuf: */ (void *)bbconfig_config_bz2, 18 /* inbuf: */ bbconfig_config_bz2,
19 /* len: */ sizeof(bbconfig_config_bz2)); 19 /* len: */ sizeof(bbconfig_config_bz2));
20 /* read_bunzip can longjmp to start_bunzip, and ultimately 20 /* read_bunzip can longjmp to start_bunzip, and ultimately
21 * end up here with i != 0 on read data errors! Not trivial */ 21 * end up here with i != 0 on read data errors! Not trivial */
diff --git a/miscutils/chat.c b/miscutils/chat.c
index 8b151fda4..d8370a963 100644
--- a/miscutils/chat.c
+++ b/miscutils/chat.c
@@ -175,23 +175,24 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
175 llist_add_to_end(&aborts, arg); 175 llist_add_to_end(&aborts, arg);
176#if ENABLE_FEATURE_CHAT_CLR_ABORT 176#if ENABLE_FEATURE_CHAT_CLR_ABORT
177 } else if (DIR_CLR_ABORT == key) { 177 } else if (DIR_CLR_ABORT == key) {
178 llist_t *l;
178 // remove the string from abort conditions 179 // remove the string from abort conditions
179 // N.B. gotta refresh maximum length too... 180 // N.B. gotta refresh maximum length too...
180#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN 181# if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN
181 max_abort_len = 0; 182 max_abort_len = 0;
182#endif 183# endif
183 for (llist_t *l = aborts; l; l = l->link) { 184 for (l = aborts; l; l = l->link) {
184#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN 185# if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN
185 size_t len = strlen(l->data); 186 size_t len = strlen(l->data);
186#endif 187# endif
187 if (!strcmp(arg, l->data)) { 188 if (strcmp(arg, l->data) == 0) {
188 llist_unlink(&aborts, l); 189 llist_unlink(&aborts, l);
189 continue; 190 continue;
190 } 191 }
191#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN 192# if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN
192 if (len > max_abort_len) 193 if (len > max_abort_len)
193 max_abort_len = len; 194 max_abort_len = len;
194#endif 195# endif
195 } 196 }
196#endif 197#endif
197 } else if (DIR_TIMEOUT == key) { 198 } else if (DIR_TIMEOUT == key) {
diff --git a/miscutils/chrt.c b/miscutils/chrt.c
index c40277b39..1c6737a3c 100644
--- a/miscutils/chrt.c
+++ b/miscutils/chrt.c
@@ -53,23 +53,25 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
53 const char *current_new; 53 const char *current_new;
54 int policy = SCHED_RR; 54 int policy = SCHED_RR;
55 55
56 /* at least 1 arg; only one policy accepted */ 56 /* only one policy accepted */
57 opt_complementary = "-1:r--fo:f--ro:r--fo"; 57 opt_complementary = "r--fo:f--ro:o--rf";
58 opt = getopt32(argv, "+mprfo"); 58 opt = getopt32(argv, "+mprfo");
59 if (opt & OPT_m) { /* print min/max and exit */
60 show_min_max(SCHED_FIFO);
61 show_min_max(SCHED_RR);
62 show_min_max(SCHED_OTHER);
63 fflush_stdout_and_exit(EXIT_SUCCESS);
64 }
59 if (opt & OPT_r) 65 if (opt & OPT_r)
60 policy = SCHED_RR; 66 policy = SCHED_RR;
61 if (opt & OPT_f) 67 if (opt & OPT_f)
62 policy = SCHED_FIFO; 68 policy = SCHED_FIFO;
63 if (opt & OPT_o) 69 if (opt & OPT_o)
64 policy = SCHED_OTHER; 70 policy = SCHED_OTHER;
65 if (opt & OPT_m) { /* print min/max */
66 show_min_max(SCHED_FIFO);
67 show_min_max(SCHED_RR);
68 show_min_max(SCHED_OTHER);
69 fflush_stdout_and_exit(EXIT_SUCCESS);
70 }
71 71
72 argv += optind; 72 argv += optind;
73 if (!argv[0])
74 bb_show_usage();
73 if (opt & OPT_p) { 75 if (opt & OPT_p) {
74 pid_str = *argv++; 76 pid_str = *argv++;
75 if (*argv) { /* "-p <priority> <pid> [...]" */ 77 if (*argv) { /* "-p <priority> <pid> [...]" */
@@ -90,13 +92,13 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
90 print_rt_info: 92 print_rt_info:
91 pol = sched_getscheduler(pid); 93 pol = sched_getscheduler(pid);
92 if (pol < 0) 94 if (pol < 0)
93 bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', pid); 95 bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', (int)pid);
94 printf("pid %d's %s scheduling policy: %s\n", 96 printf("pid %d's %s scheduling policy: %s\n",
95 pid, current_new, policies[pol].name); 97 pid, current_new, policies[pol].name);
96 if (sched_getparam(pid, &sp)) 98 if (sched_getparam(pid, &sp))
97 bb_perror_msg_and_die("can't get pid %d's attributes", pid); 99 bb_perror_msg_and_die("can't get pid %d's attributes", (int)pid);
98 printf("pid %d's %s scheduling priority: %d\n", 100 printf("pid %d's %s scheduling priority: %d\n",
99 pid, current_new, sp.sched_priority); 101 (int)pid, current_new, sp.sched_priority);
100 if (!*argv) { 102 if (!*argv) {
101 /* Either it was just "-p <pid>", 103 /* Either it was just "-p <pid>",
102 * or it was "-p <priority> <pid>" and we came here 104 * or it was "-p <priority> <pid>" and we came here
@@ -115,7 +117,7 @@ int chrt_main(int argc UNUSED_PARAM, char **argv)
115 sp.sched_priority = xstrtou_range(priority, 0, policy != SCHED_OTHER ? 1 : 0, 99); 117 sp.sched_priority = xstrtou_range(priority, 0, policy != SCHED_OTHER ? 1 : 0, 99);
116 118
117 if (sched_setscheduler(pid, policy, &sp) < 0) 119 if (sched_setscheduler(pid, policy, &sp) < 0)
118 bb_perror_msg_and_die("can't %cet pid %d's policy", 's', pid); 120 bb_perror_msg_and_die("can't %cet pid %d's policy", 's', (int)pid);
119 121
120 if (!argv[0]) /* "-p <priority> <pid> [...]" */ 122 if (!argv[0]) /* "-p <priority> <pid> [...]" */
121 goto print_rt_info; 123 goto print_rt_info;
diff --git a/miscutils/conspy.c b/miscutils/conspy.c
index 01928b35f..723b4208a 100644
--- a/miscutils/conspy.c
+++ b/miscutils/conspy.c
@@ -43,6 +43,9 @@
43#include "libbb.h" 43#include "libbb.h"
44#include <sys/kd.h> 44#include <sys/kd.h>
45 45
46
47#define ESC "\033"
48
46struct screen_info { 49struct screen_info {
47 unsigned char lines, cols, cursor_x, cursor_y; 50 unsigned char lines, cols, cursor_x, cursor_y;
48}; 51};
@@ -70,7 +73,7 @@ struct globals {
70 unsigned col; 73 unsigned col;
71 unsigned line; 74 unsigned line;
72 smallint curoff; // unknown:0 cursor on:-1 cursor off:1 75 smallint curoff; // unknown:0 cursor on:-1 cursor off:1
73 char attrbuf[sizeof("\033[0;1;5;30;40m")]; 76 char attrbuf[sizeof(ESC"[0;1;5;30;40m")];
74 // remote console 77 // remote console
75 struct screen_info remote; 78 struct screen_info remote;
76 // saved local tty terminfo 79 // saved local tty terminfo
@@ -101,7 +104,7 @@ enum {
101static void clrscr(void) 104static void clrscr(void)
102{ 105{
103 // Home, clear till end of screen 106 // Home, clear till end of screen
104 fputs("\033[1;1H" "\033[J", stdout); 107 fputs(ESC"[1;1H" ESC"[J", stdout);
105 G.col = G.line = 0; 108 G.col = G.line = 0;
106} 109}
107 110
@@ -109,7 +112,7 @@ static void set_cursor(int state)
109{ 112{
110 if (G.curoff != state) { 113 if (G.curoff != state) {
111 G.curoff = state; 114 G.curoff = state;
112 fputs("\033[?25", stdout); 115 fputs(ESC"[?25", stdout);
113 bb_putchar("h?l"[1 + state]); 116 bb_putchar("h?l"[1 + state]);
114 } 117 }
115} 118}
@@ -119,7 +122,7 @@ static void gotoxy(int col, int line)
119 if (G.col != col || G.line != line) { 122 if (G.col != col || G.line != line) {
120 G.col = col; 123 G.col = col;
121 G.line = line; 124 G.line = line;
122 printf("\033[%u;%uH", line + 1, col + 1); 125 printf(ESC"[%u;%uH", line + 1, col + 1);
123 } 126 }
124} 127}
125 128
@@ -132,7 +135,7 @@ static void cleanup(int code)
132 } 135 }
133 // Reset attributes 136 // Reset attributes
134 if (!BW) 137 if (!BW)
135 fputs("\033[0m", stdout); 138 fputs(ESC"[0m", stdout);
136 bb_putchar('\n'); 139 bb_putchar('\n');
137 if (code > 1) 140 if (code > 1)
138 kill_myself_with_sig(code); 141 kill_myself_with_sig(code);
@@ -417,19 +420,19 @@ int conspy_main(int argc UNUSED_PARAM, char **argv)
417 420
418 if (G.remote.cursor_x < G.x) { 421 if (G.remote.cursor_x < G.x) {
419 G.x = G.remote.cursor_x; 422 G.x = G.remote.cursor_x;
420 i = 0; // force refresh 423 i = 0; // force refresh
421 } 424 }
422 if (nx > G.x) { 425 if (nx > G.x) {
423 G.x = nx; 426 G.x = nx;
424 i = 0; // force refresh 427 i = 0; // force refresh
425 } 428 }
426 if (G.remote.cursor_y < G.y) { 429 if (G.remote.cursor_y < G.y) {
427 G.y = G.remote.cursor_y; 430 G.y = G.remote.cursor_y;
428 i = 0; // force refresh 431 i = 0; // force refresh
429 } 432 }
430 if (ny > G.y) { 433 if (ny > G.y) {
431 G.y = ny; 434 G.y = ny;
432 i = 0; // force refresh 435 i = 0; // force refresh
433 } 436 }
434 } 437 }
435 438
diff --git a/miscutils/less.c b/miscutils/less.c
index 500059d2a..9e12c11a7 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -28,13 +28,15 @@
28#include "xregex.h" 28#include "xregex.h"
29#endif 29#endif
30 30
31
32#define ESC "\033"
31/* The escape codes for highlighted and normal text */ 33/* The escape codes for highlighted and normal text */
32#define HIGHLIGHT "\033[7m" 34#define HIGHLIGHT ESC"[7m"
33#define NORMAL "\033[0m" 35#define NORMAL ESC"[0m"
34/* The escape code to home and clear to the end of screen */ 36/* The escape code to home and clear to the end of screen */
35#define CLEAR "\033[H\033[J" 37#define CLEAR ESC"[H\033[J"
36/* The escape code to clear to the end of line */ 38/* The escape code to clear to the end of line */
37#define CLEAR_2_EOL "\033[K" 39#define CLEAR_2_EOL ESC"[K"
38 40
39enum { 41enum {
40/* Absolute max of lines eaten */ 42/* Absolute max of lines eaten */
@@ -165,12 +167,12 @@ static void set_tty_cooked(void)
165 top-left corner of the console */ 167 top-left corner of the console */
166static void move_cursor(int line, int row) 168static void move_cursor(int line, int row)
167{ 169{
168 printf("\033[%u;%uH", line, row); 170 printf(ESC"[%u;%uH", line, row);
169} 171}
170 172
171static void clear_line(void) 173static void clear_line(void)
172{ 174{
173 printf("\033[%u;0H" CLEAR_2_EOL, max_displayed_line + 2); 175 printf(ESC"[%u;0H" CLEAR_2_EOL, max_displayed_line + 2);
174} 176}
175 177
176static void print_hilite(const char *str) 178static void print_hilite(const char *str)
diff --git a/miscutils/ubi_attach_detach.c b/miscutils/ubi_attach_detach.c
index 18ffd4df2..b74d97b68 100644
--- a/miscutils/ubi_attach_detach.c
+++ b/miscutils/ubi_attach_detach.c
@@ -26,8 +26,8 @@
26#include "libbb.h" 26#include "libbb.h"
27#include <mtd/ubi-user.h> 27#include <mtd/ubi-user.h>
28 28
29#define OPTION_M (1 << 0) 29#define OPTION_M (1 << 0)
30#define OPTION_D (1 << 1) 30#define OPTION_D (1 << 1)
31 31
32#define do_attach (ENABLE_UBIATTACH && \ 32#define do_attach (ENABLE_UBIATTACH && \
33 (!ENABLE_UBIDETACH || (applet_name[3] == 'a'))) 33 (!ENABLE_UBIDETACH || (applet_name[3] == 'a')))
diff --git a/miscutils/watchdog.c b/miscutils/watchdog.c
index 36902a214..630782660 100644
--- a/miscutils/watchdog.c
+++ b/miscutils/watchdog.c
@@ -24,7 +24,7 @@ static void watchdog_shutdown(int sig UNUSED_PARAM)
24 write(3, &V, 1); /* Magic, see watchdog-api.txt in kernel */ 24 write(3, &V, 1); /* Magic, see watchdog-api.txt in kernel */
25 if (ENABLE_FEATURE_CLEAN_UP) 25 if (ENABLE_FEATURE_CLEAN_UP)
26 close(3); 26 close(3);
27 exit(EXIT_SUCCESS); 27 _exit(EXIT_SUCCESS);
28} 28}
29 29
30int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 30int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index a5cf4babf..73df39c6c 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -10,6 +10,20 @@
10 10
11//applet:IF_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP)) 11//applet:IF_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP))
12 12
13#include "libbb.h"
14#include "modutils.h"
15#include <sys/utsname.h>
16#include <fnmatch.h>
17
18//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
19#define DBG(...) ((void)0)
20
21/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t),
22 * we expect the full dependency list to be specified in modules.dep.
23 * Older versions would only export the direct dependency list.
24 */
25
26
13//usage:#if !ENABLE_MODPROBE_SMALL 27//usage:#if !ENABLE_MODPROBE_SMALL
14//usage:#define modprobe_notes_usage 28//usage:#define modprobe_notes_usage
15//usage: "modprobe can (un)load a stack of modules, passing each module options (when\n" 29//usage: "modprobe can (un)load a stack of modules, passing each module options (when\n"
@@ -72,9 +86,8 @@
72//usage: " from the command line\n" 86//usage: " from the command line\n"
73//usage: 87//usage:
74//usage:#define modprobe_trivial_usage 88//usage:#define modprobe_trivial_usage
75//usage: "[-alrqvs" 89//usage: "[-alrqvsD" IF_FEATURE_MODPROBE_BLACKLIST("b") "]"
76//usage: IF_FEATURE_MODPROBE_BLACKLIST("b") 90//usage: " MODULE [symbol=value]..."
77//usage: "] MODULE [symbol=value]..."
78//usage:#define modprobe_full_usage "\n\n" 91//usage:#define modprobe_full_usage "\n\n"
79//usage: "Options:" 92//usage: "Options:"
80//usage: "\n -a Load multiple MODULEs" 93//usage: "\n -a Load multiple MODULEs"
@@ -83,43 +96,50 @@
83//usage: "\n -q Quiet" 96//usage: "\n -q Quiet"
84//usage: "\n -v Verbose" 97//usage: "\n -v Verbose"
85//usage: "\n -s Log to syslog" 98//usage: "\n -s Log to syslog"
99//usage: "\n -D Show dependencies"
86//usage: IF_FEATURE_MODPROBE_BLACKLIST( 100//usage: IF_FEATURE_MODPROBE_BLACKLIST(
87//usage: "\n -b Apply blacklist to module names too" 101//usage: "\n -b Apply blacklist to module names too"
88//usage: ) 102//usage: )
89//usage:#endif /* !ENABLE_MODPROBE_SMALL */ 103//usage:#endif /* !ENABLE_MODPROBE_SMALL */
90 104
91#include "libbb.h"
92#include "modutils.h"
93#include <sys/utsname.h>
94#include <fnmatch.h>
95
96//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
97#define DBG(...) ((void)0)
98
99/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t),
100 * we expect the full dependency list to be specified in modules.dep.
101 * Older versions would only export the direct dependency list.
102 */
103
104/* Note that usage text doesn't document various 2.4 options 105/* Note that usage text doesn't document various 2.4 options
105 * we pull in through INSMOD_OPTS define */ 106 * we pull in through INSMOD_OPTS define */
106 107#define MODPROBE_OPTS "alrD" IF_FEATURE_MODPROBE_BLACKLIST("b")
107#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--ar:a--lr:r--al" 108/* -a and -D _are_ in fact compatible */
108#define MODPROBE_OPTS "alr" IF_FEATURE_MODPROBE_BLACKLIST("b") 109#define MODPROBE_COMPLEMENTARY ("q-v:v-q:l--arD:r--alD:a--lr:D--rl")
109//#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al"
110//#define MODPROBE_OPTS "acd:lnrt:C:" IF_FEATURE_MODPROBE_BLACKLIST("b") 110//#define MODPROBE_OPTS "acd:lnrt:C:" IF_FEATURE_MODPROBE_BLACKLIST("b")
111//#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al"
111enum { 112enum {
112 MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ 113 OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */
113 //MODPROBE_OPT_DUMP_ONLY= (INSMOD_OPT_UNUSED << x), /* c */ 114 //OPT_DUMP_ONLY = (INSMOD_OPT_UNUSED << x), /* c */
114 //MODPROBE_OPT_DIRNAME = (INSMOD_OPT_UNUSED << x), /* d */ 115 //OPT_DIRNAME = (INSMOD_OPT_UNUSED << x), /* d */
115 MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 1), /* l */ 116 OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 1), /* l */
116 //MODPROBE_OPT_SHOW_ONLY= (INSMOD_OPT_UNUSED << x), /* n */ 117 //OPT_SHOW_ONLY = (INSMOD_OPT_UNUSED << x), /* n */
117 MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 2), /* r */ 118 OPT_REMOVE = (INSMOD_OPT_UNUSED << 2), /* r */
118 //MODPROBE_OPT_RESTRICT = (INSMOD_OPT_UNUSED << x), /* t */ 119 //OPT_RESTRICT = (INSMOD_OPT_UNUSED << x), /* t */
119 //MODPROBE_OPT_VERONLY = (INSMOD_OPT_UNUSED << x), /* V */ 120 //OPT_VERONLY = (INSMOD_OPT_UNUSED << x), /* V */
120 //MODPROBE_OPT_CONFIGFILE=(INSMOD_OPT_UNUSED << x), /* C */ 121 //OPT_CONFIGFILE = (INSMOD_OPT_UNUSED << x), /* C */
121 MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 3) * ENABLE_FEATURE_MODPROBE_BLACKLIST, 122 OPT_SHOW_DEPS = (INSMOD_OPT_UNUSED << 3), /* D */
123 OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 4) * ENABLE_FEATURE_MODPROBE_BLACKLIST,
122}; 124};
125#if ENABLE_LONG_OPTS
126static const char modprobe_longopts[] ALIGN1 =
127 /* nobody asked for long opts (yet) */
128 // "all\0" No_argument "a"
129 // "list\0" No_argument "l"
130 // "remove\0" No_argument "r"
131 // "quiet\0" No_argument "q"
132 // "verbose\0" No_argument "v"
133 // "syslog\0" No_argument "s"
134 /* module-init-tools 3.11.1 has only long opt --show-depends
135 * but no short -D, we provide long opt for scripts which
136 * were written for 3.11.1: */
137 "show-depends\0" No_argument "D"
138 // IF_FEATURE_MODPROBE_BLACKLIST(
139 // "use-blacklist\0" No_argument "b"
140 // )
141 ;
142#endif
123 143
124#define MODULE_FLAG_LOADED 0x0001 144#define MODULE_FLAG_LOADED 0x0001
125#define MODULE_FLAG_NEED_DEPS 0x0002 145#define MODULE_FLAG_NEED_DEPS 0x0002
@@ -145,9 +165,13 @@ struct globals {
145 int num_unresolved_deps; 165 int num_unresolved_deps;
146 /* bool. "Did we have 'symbol:FOO' requested on cmdline?" */ 166 /* bool. "Did we have 'symbol:FOO' requested on cmdline?" */
147 smallint need_symbols; 167 smallint need_symbols;
168 struct utsname uts;
148} FIX_ALIASING; 169} FIX_ALIASING;
149#define G (*(struct globals*)&bb_common_bufsiz1) 170#define G (*(struct globals*)&bb_common_bufsiz1)
150#define INIT_G() do { } while (0) 171#define INIT_G() do { } while (0)
172struct BUG_G_too_big {
173 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
174};
151 175
152 176
153static int read_config(const char *path); 177static int read_config(const char *path);
@@ -202,7 +226,7 @@ static void add_probe(const char *name)
202 struct module_entry *m; 226 struct module_entry *m;
203 227
204 m = get_or_add_modentry(name); 228 m = get_or_add_modentry(name);
205 if (!(option_mask32 & MODPROBE_OPT_REMOVE) 229 if (!(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS))
206 && (m->flags & MODULE_FLAG_LOADED) 230 && (m->flags & MODULE_FLAG_LOADED)
207 ) { 231 ) {
208 DBG("skipping %s, it is already loaded", name); 232 DBG("skipping %s, it is already loaded", name);
@@ -353,8 +377,6 @@ static char *parse_and_add_kcmdline_module_options(char *options, const char *mo
353 */ 377 */
354static int do_modprobe(struct module_entry *m) 378static int do_modprobe(struct module_entry *m)
355{ 379{
356 struct module_entry *m2 = m2; /* for compiler */
357 char *fn, *options;
358 int rc, first; 380 int rc, first;
359 llist_t *l; 381 llist_t *l;
360 382
@@ -366,7 +388,7 @@ static int do_modprobe(struct module_entry *m)
366 } 388 }
367 DBG("do_modprob'ing %s", m->modname); 389 DBG("do_modprob'ing %s", m->modname);
368 390
369 if (!(option_mask32 & MODPROBE_OPT_REMOVE)) 391 if (!(option_mask32 & OPT_REMOVE))
370 m->deps = llist_rev(m->deps); 392 m->deps = llist_rev(m->deps);
371 393
372 for (l = m->deps; l != NULL; l = l->link) 394 for (l = m->deps; l != NULL; l = l->link)
@@ -375,11 +397,14 @@ static int do_modprobe(struct module_entry *m)
375 first = 1; 397 first = 1;
376 rc = 0; 398 rc = 0;
377 while (m->deps) { 399 while (m->deps) {
400 struct module_entry *m2;
401 char *fn, *options;
402
378 rc = 0; 403 rc = 0;
379 fn = llist_pop(&m->deps); /* we leak it */ 404 fn = llist_pop(&m->deps); /* we leak it */
380 m2 = get_or_add_modentry(fn); 405 m2 = get_or_add_modentry(fn);
381 406
382 if (option_mask32 & MODPROBE_OPT_REMOVE) { 407 if (option_mask32 & OPT_REMOVE) {
383 /* modprobe -r */ 408 /* modprobe -r */
384 if (m2->flags & MODULE_FLAG_LOADED) { 409 if (m2->flags & MODULE_FLAG_LOADED) {
385 rc = bb_delete_module(m2->modname, O_EXCL); 410 rc = bb_delete_module(m2->modname, O_EXCL);
@@ -399,16 +424,27 @@ static int do_modprobe(struct module_entry *m)
399 continue; 424 continue;
400 } 425 }
401 426
402 if (m2->flags & MODULE_FLAG_LOADED) {
403 DBG("%s is already loaded, skipping", fn);
404 continue;
405 }
406
407 options = m2->options; 427 options = m2->options;
408 m2->options = NULL; 428 m2->options = NULL;
409 options = parse_and_add_kcmdline_module_options(options, m2->modname); 429 options = parse_and_add_kcmdline_module_options(options, m2->modname);
410 if (m == m2) 430 if (m == m2)
411 options = gather_options_str(options, G.cmdline_mopts); 431 options = gather_options_str(options, G.cmdline_mopts);
432
433 if (option_mask32 & OPT_SHOW_DEPS) {
434 printf(options ? "insmod %s/%s/%s %s\n"
435 : "insmod %s/%s/%s\n",
436 CONFIG_DEFAULT_MODULES_DIR, G.uts.release, fn,
437 options);
438 free(options);
439 continue;
440 }
441
442 if (m2->flags & MODULE_FLAG_LOADED) {
443 DBG("%s is already loaded, skipping", fn);
444 free(options);
445 continue;
446 }
447
412 rc = bb_init_module(fn, options); 448 rc = bb_init_module(fn, options);
413 DBG("loaded %s '%s', rc:%d", fn, options, rc); 449 DBG("loaded %s '%s', rc:%d", fn, options, rc);
414 if (rc == EEXIST) 450 if (rc == EEXIST)
@@ -456,7 +492,7 @@ static void load_modules_dep(void)
456 492
457 /* Optimization... */ 493 /* Optimization... */
458 if ((m->flags & MODULE_FLAG_LOADED) 494 if ((m->flags & MODULE_FLAG_LOADED)
459 && !(option_mask32 & MODPROBE_OPT_REMOVE) 495 && !(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS))
460 ) { 496 ) {
461 DBG("skip deps of %s, it's already loaded", tokens[0]); 497 DBG("skip deps of %s, it's already loaded", tokens[0]);
462 continue; 498 continue;
@@ -477,21 +513,23 @@ static void load_modules_dep(void)
477int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 513int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
478int modprobe_main(int argc UNUSED_PARAM, char **argv) 514int modprobe_main(int argc UNUSED_PARAM, char **argv)
479{ 515{
480 struct utsname uts;
481 int rc; 516 int rc;
482 unsigned opt; 517 unsigned opt;
483 struct module_entry *me; 518 struct module_entry *me;
484 519
520 INIT_G();
521
522 IF_LONG_OPTS(applet_long_options = modprobe_longopts;)
485 opt_complementary = MODPROBE_COMPLEMENTARY; 523 opt_complementary = MODPROBE_COMPLEMENTARY;
486 opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS); 524 opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS);
487 argv += optind; 525 argv += optind;
488 526
489 /* Goto modules location */ 527 /* Goto modules location */
490 xchdir(CONFIG_DEFAULT_MODULES_DIR); 528 xchdir(CONFIG_DEFAULT_MODULES_DIR);
491 uname(&uts); 529 uname(&G.uts);
492 xchdir(uts.release); 530 xchdir(G.uts.release);
493 531
494 if (opt & MODPROBE_OPT_LIST_ONLY) { 532 if (opt & OPT_LIST_ONLY) {
495 char name[MODULE_NAME_LEN]; 533 char name[MODULE_NAME_LEN];
496 char *colon, *tokens[2]; 534 char *colon, *tokens[2];
497 parser_t *p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read); 535 parser_t *p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read);
@@ -521,7 +559,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
521 logmode = LOGMODE_SYSLOG; 559 logmode = LOGMODE_SYSLOG;
522 560
523 if (!argv[0]) { 561 if (!argv[0]) {
524 if (opt & MODPROBE_OPT_REMOVE) { 562 if (opt & OPT_REMOVE) {
525 /* "modprobe -r" (w/o params). 563 /* "modprobe -r" (w/o params).
526 * "If name is NULL, all unused modules marked 564 * "If name is NULL, all unused modules marked
527 * autoclean will be removed". 565 * autoclean will be removed".
@@ -541,7 +579,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
541 config_close(parser); 579 config_close(parser);
542 } 580 }
543 581
544 if (opt & (MODPROBE_OPT_INSERT_ALL | MODPROBE_OPT_REMOVE)) { 582 if (opt & (OPT_INSERT_ALL | OPT_REMOVE)) {
545 /* Each argument is a module name */ 583 /* Each argument is a module name */
546 do { 584 do {
547 DBG("adding module %s", *argv); 585 DBG("adding module %s", *argv);
@@ -575,7 +613,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
575 /* This is not an alias. Literal names are blacklisted 613 /* This is not an alias. Literal names are blacklisted
576 * only if '-b' is given. 614 * only if '-b' is given.
577 */ 615 */
578 if (!(opt & MODPROBE_OPT_BLACKLIST) 616 if (!(opt & OPT_BLACKLIST)
579 || !(me->flags & MODULE_FLAG_BLACKLISTED) 617 || !(me->flags & MODULE_FLAG_BLACKLISTED)
580 ) { 618 ) {
581 rc |= do_modprobe(me); 619 rc |= do_modprobe(me);
@@ -592,7 +630,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
592 m2 = get_or_add_modentry(realname); 630 m2 = get_or_add_modentry(realname);
593 if (!(m2->flags & MODULE_FLAG_BLACKLISTED) 631 if (!(m2->flags & MODULE_FLAG_BLACKLISTED)
594 && (!(m2->flags & MODULE_FLAG_LOADED) 632 && (!(m2->flags & MODULE_FLAG_LOADED)
595 || (opt & MODPROBE_OPT_REMOVE)) 633 || (opt & (OPT_REMOVE | OPT_SHOW_DEPS)))
596 ) { 634 ) {
597//TODO: we can pass "me" as 2nd param to do_modprobe, 635//TODO: we can pass "me" as 2nd param to do_modprobe,
598//and make do_modprobe emit more meaningful error messages 636//and make do_modprobe emit more meaningful error messages
diff --git a/modutils/rmmod.c b/modutils/rmmod.c
index dde77731f..2486511d7 100644
--- a/modutils/rmmod.c
+++ b/modutils/rmmod.c
@@ -35,9 +35,9 @@ int rmmod_main(int argc UNUSED_PARAM, char **argv)
35 /* Parse command line. */ 35 /* Parse command line. */
36 n = getopt32(argv, "wfas"); // -s ignored 36 n = getopt32(argv, "wfas"); // -s ignored
37 argv += optind; 37 argv += optind;
38 if (n & 1) // --wait 38 if (n & 1) // --wait
39 flags &= ~O_NONBLOCK; 39 flags &= ~O_NONBLOCK;
40 if (n & 2) // --force 40 if (n & 2) // --force
41 flags |= O_TRUNC; 41 flags |= O_TRUNC;
42 if (n & 4) { 42 if (n & 4) {
43 /* Unload _all_ unused modules via NULL delete_module() call */ 43 /* Unload _all_ unused modules via NULL delete_module() call */
diff --git a/networking/Config.src b/networking/Config.src
index 6dd7df754..274fcae3a 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -684,29 +684,6 @@ config FEATURE_NTPD_SERVER
684 Make ntpd usable as a NTP server. If you disable this option 684 Make ntpd usable as a NTP server. If you disable this option
685 ntpd will be usable only as a NTP client. 685 ntpd will be usable only as a NTP client.
686 686
687config PING
688 bool "ping"
689 default y
690 depends on PLATFORM_LINUX
691 help
692 ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to
693 elicit an ICMP ECHO_RESPONSE from a host or gateway.
694
695config PING6
696 bool "ping6"
697 default y
698 depends on FEATURE_IPV6 && PING
699 help
700 This will give you a ping that can talk IPv6.
701
702config FEATURE_FANCY_PING
703 bool "Enable fancy ping output"
704 default y
705 depends on PING
706 help
707 Make the output from the ping applet include statistics, and at the
708 same time provide full support for ICMP packets.
709
710config PSCAN 687config PSCAN
711 bool "pscan" 688 bool "pscan"
712 default y 689 default y
diff --git a/networking/Kbuild.src b/networking/Kbuild.src
index f41a2df70..944f27be1 100644
--- a/networking/Kbuild.src
+++ b/networking/Kbuild.src
@@ -30,8 +30,6 @@ lib-$(CONFIG_NC) += nc.o
30lib-$(CONFIG_NETSTAT) += netstat.o 30lib-$(CONFIG_NETSTAT) += netstat.o
31lib-$(CONFIG_NSLOOKUP) += nslookup.o 31lib-$(CONFIG_NSLOOKUP) += nslookup.o
32lib-$(CONFIG_NTPD) += ntpd.o 32lib-$(CONFIG_NTPD) += ntpd.o
33lib-$(CONFIG_PING) += ping.o
34lib-$(CONFIG_PING6) += ping.o
35lib-$(CONFIG_PSCAN) += pscan.o 33lib-$(CONFIG_PSCAN) += pscan.o
36lib-$(CONFIG_ROUTE) += route.o 34lib-$(CONFIG_ROUTE) += route.o
37lib-$(CONFIG_SLATTACH) += slattach.o 35lib-$(CONFIG_SLATTACH) += slattach.o
diff --git a/networking/arping.c b/networking/arping.c
index f2b12ed04..6f6b59cfb 100644
--- a/networking/arping.c
+++ b/networking/arping.c
@@ -1,10 +1,8 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * arping.c - Ping hosts by ARP requests/replies
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 * 4 *
7 * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 5 * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
8 * Busybox port: Nick Fedchik <nick@fedchik.org.ua> 6 * Busybox port: Nick Fedchik <nick@fedchik.org.ua>
9 */ 7 */
10 8
diff --git a/networking/dnsd.c b/networking/dnsd.c
index 92d4867aa..8ed31cea2 100644
--- a/networking/dnsd.c
+++ b/networking/dnsd.c
@@ -388,7 +388,7 @@ static int process_packet(struct dns_entry *conf_data,
388 query_len = strlen(query_string) + 1; 388 query_len = strlen(query_string) + 1;
389 /* may be unaligned! */ 389 /* may be unaligned! */
390 unaligned_type_class = (void *)(query_string + query_len); 390 unaligned_type_class = (void *)(query_string + query_len);
391 query_len += sizeof(unaligned_type_class); 391 query_len += sizeof(*unaligned_type_class);
392 /* where to append answer block */ 392 /* where to append answer block */
393 answb = (void *)(unaligned_type_class + 1); 393 answb = (void *)(unaligned_type_class + 1);
394 394
diff --git a/networking/httpd.c b/networking/httpd.c
index c174958e2..fa42d9850 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -231,7 +231,7 @@ struct globals {
231 int verbose; /* must be int (used by getopt32) */ 231 int verbose; /* must be int (used by getopt32) */
232 smallint flg_deny_all; 232 smallint flg_deny_all;
233 233
234 unsigned rmt_ip; /* used for IP-based allow/deny rules */ 234 unsigned rmt_ip; /* used for IP-based allow/deny rules */
235 time_t last_mod; 235 time_t last_mod;
236 char *rmt_ip_str; /* for $REMOTE_ADDR and $REMOTE_PORT */ 236 char *rmt_ip_str; /* for $REMOTE_ADDR and $REMOTE_PORT */
237 const char *bind_addr_or_port; 237 const char *bind_addr_or_port;
@@ -267,7 +267,7 @@ struct globals {
267#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 267#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
268 Htaccess *script_i; /* config script interpreters */ 268 Htaccess *script_i; /* config script interpreters */
269#endif 269#endif
270 char *iobuf; /* [IOBUF_SIZE] */ 270 char *iobuf; /* [IOBUF_SIZE] */
271#define hdr_buf bb_common_bufsiz1 271#define hdr_buf bb_common_bufsiz1
272 char *hdr_ptr; 272 char *hdr_ptr;
273 int hdr_cnt; 273 int hdr_cnt;
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 3cb1ec858..59df4e80f 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -164,7 +164,7 @@ static char *get_var(const char *id, size_t idlen, struct interface_defn_t *ifd)
164 return NULL; 164 return NULL;
165} 165}
166 166
167#if ENABLE_FEATURE_IFUPDOWN_IP 167# if ENABLE_FEATURE_IFUPDOWN_IP
168static int count_netmask_bits(const char *dotted_quad) 168static int count_netmask_bits(const char *dotted_quad)
169{ 169{
170// int result; 170// int result;
@@ -195,7 +195,7 @@ static int count_netmask_bits(const char *dotted_quad)
195 } 195 }
196 return result; 196 return result;
197} 197}
198#endif 198# endif
199 199
200static char *parse(const char *command, struct interface_defn_t *ifd) 200static char *parse(const char *command, struct interface_defn_t *ifd)
201{ 201{
@@ -258,17 +258,17 @@ static char *parse(const char *command, struct interface_defn_t *ifd)
258 varvalue = get_var(command, nextpercent - command, ifd); 258 varvalue = get_var(command, nextpercent - command, ifd);
259 259
260 if (varvalue) { 260 if (varvalue) {
261#if ENABLE_FEATURE_IFUPDOWN_IP 261# if ENABLE_FEATURE_IFUPDOWN_IP
262 /* "hwaddress <class> <address>": 262 /* "hwaddress <class> <address>":
263 * unlike ifconfig, ip doesnt want <class> 263 * unlike ifconfig, ip doesnt want <class>
264 * (usually "ether" keyword). Skip it. */ 264 * (usually "ether" keyword). Skip it. */
265 if (strncmp(command, "hwaddress", 9) == 0) { 265 if (strncmp(command, "hwaddress", 9) == 0) {
266 varvalue = skip_whitespace(skip_non_whitespace(varvalue)); 266 varvalue = skip_whitespace(skip_non_whitespace(varvalue));
267 } 267 }
268#endif 268# endif
269 addstr(&result, varvalue, strlen(varvalue)); 269 addstr(&result, varvalue, strlen(varvalue));
270 } else { 270 } else {
271#if ENABLE_FEATURE_IFUPDOWN_IP 271# if ENABLE_FEATURE_IFUPDOWN_IP
272 /* Sigh... Add a special case for 'ip' to convert from 272 /* Sigh... Add a special case for 'ip' to convert from
273 * dotted quad to bit count style netmasks. */ 273 * dotted quad to bit count style netmasks. */
274 if (strncmp(command, "bnmask", 6) == 0) { 274 if (strncmp(command, "bnmask", 6) == 0) {
@@ -284,7 +284,7 @@ static char *parse(const char *command, struct interface_defn_t *ifd)
284 } 284 }
285 } 285 }
286 } 286 }
287#endif 287# endif
288 okay[opt_depth - 1] = 0; 288 okay[opt_depth - 1] = 0;
289 } 289 }
290 290
@@ -329,56 +329,64 @@ static int execute(const char *command, struct interface_defn_t *ifd, execfn *ex
329 } 329 }
330 return 1; 330 return 1;
331} 331}
332#endif 332
333#endif /* FEATURE_IFUPDOWN_IPV4 || FEATURE_IFUPDOWN_IPV6 */
334
333 335
334#if ENABLE_FEATURE_IFUPDOWN_IPV6 336#if ENABLE_FEATURE_IFUPDOWN_IPV6
337
335static int FAST_FUNC loopback_up6(struct interface_defn_t *ifd, execfn *exec) 338static int FAST_FUNC loopback_up6(struct interface_defn_t *ifd, execfn *exec)
336{ 339{
337#if ENABLE_FEATURE_IFUPDOWN_IP 340# if ENABLE_FEATURE_IFUPDOWN_IP
338 int result; 341 int result;
339 result = execute("ip addr add ::1 dev %iface%", ifd, exec); 342 result = execute("ip addr add ::1 dev %iface%", ifd, exec);
340 result += execute("ip link set %iface% up", ifd, exec); 343 result += execute("ip link set %iface% up", ifd, exec);
341 return ((result == 2) ? 2 : 0); 344 return ((result == 2) ? 2 : 0);
342#else 345# else
343 return execute("ifconfig %iface% add ::1", ifd, exec); 346 return execute("ifconfig %iface% add ::1", ifd, exec);
344#endif 347# endif
345} 348}
346 349
347static int FAST_FUNC loopback_down6(struct interface_defn_t *ifd, execfn *exec) 350static int FAST_FUNC loopback_down6(struct interface_defn_t *ifd, execfn *exec)
348{ 351{
349#if ENABLE_FEATURE_IFUPDOWN_IP 352# if ENABLE_FEATURE_IFUPDOWN_IP
350 return execute("ip link set %iface% down", ifd, exec); 353 return execute("ip link set %iface% down", ifd, exec);
351#else 354# else
352 return execute("ifconfig %iface% del ::1", ifd, exec); 355 return execute("ifconfig %iface% del ::1", ifd, exec);
353#endif 356# endif
357}
358
359static int FAST_FUNC manual_up_down6(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM)
360{
361 return 1;
354} 362}
355 363
356static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec) 364static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec)
357{ 365{
358 int result; 366 int result;
359#if ENABLE_FEATURE_IFUPDOWN_IP 367# if ENABLE_FEATURE_IFUPDOWN_IP
360 result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec); 368 result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec);
361 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); 369 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
362 /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */ 370 /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */
363 result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec); 371 result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec);
364#else 372# else
365 result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec); 373 result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec);
366 result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec); 374 result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec);
367 result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec); 375 result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec);
368#endif 376# endif
369 return ((result == 3) ? 3 : 0); 377 return ((result == 3) ? 3 : 0);
370} 378}
371 379
372static int FAST_FUNC static_down6(struct interface_defn_t *ifd, execfn *exec) 380static int FAST_FUNC static_down6(struct interface_defn_t *ifd, execfn *exec)
373{ 381{
374#if ENABLE_FEATURE_IFUPDOWN_IP 382# if ENABLE_FEATURE_IFUPDOWN_IP
375 return execute("ip link set %iface% down", ifd, exec); 383 return execute("ip link set %iface% down", ifd, exec);
376#else 384# else
377 return execute("ifconfig %iface% down", ifd, exec); 385 return execute("ifconfig %iface% down", ifd, exec);
378#endif 386# endif
379} 387}
380 388
381#if ENABLE_FEATURE_IFUPDOWN_IP 389# if ENABLE_FEATURE_IFUPDOWN_IP
382static int FAST_FUNC v4tunnel_up(struct interface_defn_t *ifd, execfn *exec) 390static int FAST_FUNC v4tunnel_up(struct interface_defn_t *ifd, execfn *exec)
383{ 391{
384 int result; 392 int result;
@@ -394,14 +402,15 @@ static int FAST_FUNC v4tunnel_down(struct interface_defn_t * ifd, execfn * exec)
394{ 402{
395 return execute("ip tunnel del %iface%", ifd, exec); 403 return execute("ip tunnel del %iface%", ifd, exec);
396} 404}
397#endif 405# endif
398 406
399static const struct method_t methods6[] = { 407static const struct method_t methods6[] = {
400#if ENABLE_FEATURE_IFUPDOWN_IP 408# if ENABLE_FEATURE_IFUPDOWN_IP
401 { "v4tunnel", v4tunnel_up, v4tunnel_down, }, 409 { "v4tunnel" , v4tunnel_up , v4tunnel_down , },
402#endif 410# endif
403 { "static", static_up6, static_down6, }, 411 { "static" , static_up6 , static_down6 , },
404 { "loopback", loopback_up6, loopback_down6, }, 412 { "manual" , manual_up_down6 , manual_up_down6 , },
413 { "loopback" , loopback_up6 , loopback_down6 , },
405}; 414};
406 415
407static const struct address_family_t addr_inet6 = { 416static const struct address_family_t addr_inet6 = {
@@ -409,43 +418,46 @@ static const struct address_family_t addr_inet6 = {
409 ARRAY_SIZE(methods6), 418 ARRAY_SIZE(methods6),
410 methods6 419 methods6
411}; 420};
421
412#endif /* FEATURE_IFUPDOWN_IPV6 */ 422#endif /* FEATURE_IFUPDOWN_IPV6 */
413 423
424
414#if ENABLE_FEATURE_IFUPDOWN_IPV4 425#if ENABLE_FEATURE_IFUPDOWN_IPV4
426
415static int FAST_FUNC loopback_up(struct interface_defn_t *ifd, execfn *exec) 427static int FAST_FUNC loopback_up(struct interface_defn_t *ifd, execfn *exec)
416{ 428{
417#if ENABLE_FEATURE_IFUPDOWN_IP 429# if ENABLE_FEATURE_IFUPDOWN_IP
418 int result; 430 int result;
419 result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec); 431 result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec);
420 result += execute("ip link set %iface% up", ifd, exec); 432 result += execute("ip link set %iface% up", ifd, exec);
421 return ((result == 2) ? 2 : 0); 433 return ((result == 2) ? 2 : 0);
422#else 434# else
423 return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec); 435 return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec);
424#endif 436# endif
425} 437}
426 438
427static int FAST_FUNC loopback_down(struct interface_defn_t *ifd, execfn *exec) 439static int FAST_FUNC loopback_down(struct interface_defn_t *ifd, execfn *exec)
428{ 440{
429#if ENABLE_FEATURE_IFUPDOWN_IP 441# if ENABLE_FEATURE_IFUPDOWN_IP
430 int result; 442 int result;
431 result = execute("ip addr flush dev %iface%", ifd, exec); 443 result = execute("ip addr flush dev %iface%", ifd, exec);
432 result += execute("ip link set %iface% down", ifd, exec); 444 result += execute("ip link set %iface% down", ifd, exec);
433 return ((result == 2) ? 2 : 0); 445 return ((result == 2) ? 2 : 0);
434#else 446# else
435 return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec); 447 return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec);
436#endif 448# endif
437} 449}
438 450
439static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec) 451static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec)
440{ 452{
441 int result; 453 int result;
442#if ENABLE_FEATURE_IFUPDOWN_IP 454# if ENABLE_FEATURE_IFUPDOWN_IP
443 result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] " 455 result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] "
444 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec); 456 "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec);
445 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); 457 result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec);
446 result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec); 458 result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec);
447 return ((result == 3) ? 3 : 0); 459 return ((result == 3) ? 3 : 0);
448#else 460# else
449 /* ifconfig said to set iface up before it processes hw %hwaddress%, 461 /* ifconfig said to set iface up before it processes hw %hwaddress%,
450 * which then of course fails. Thus we run two separate ifconfig */ 462 * which then of course fails. Thus we run two separate ifconfig */
451 result = execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up", 463 result = execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up",
@@ -455,26 +467,26 @@ static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec)
455 ifd, exec); 467 ifd, exec);
456 result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec); 468 result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec);
457 return ((result == 3) ? 3 : 0); 469 return ((result == 3) ? 3 : 0);
458#endif 470# endif
459} 471}
460 472
461static int FAST_FUNC static_down(struct interface_defn_t *ifd, execfn *exec) 473static int FAST_FUNC static_down(struct interface_defn_t *ifd, execfn *exec)
462{ 474{
463 int result; 475 int result;
464#if ENABLE_FEATURE_IFUPDOWN_IP 476# if ENABLE_FEATURE_IFUPDOWN_IP
465 result = execute("ip addr flush dev %iface%", ifd, exec); 477 result = execute("ip addr flush dev %iface%", ifd, exec);
466 result += execute("ip link set %iface% down", ifd, exec); 478 result += execute("ip link set %iface% down", ifd, exec);
467#else 479# else
468 /* result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec); */ 480 /* result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec); */
469 /* Bringing the interface down deletes the routes in itself. 481 /* Bringing the interface down deletes the routes in itself.
470 Otherwise this fails if we reference 'gateway' when using this from dhcp_down */ 482 Otherwise this fails if we reference 'gateway' when using this from dhcp_down */
471 result = 1; 483 result = 1;
472 result += execute("ifconfig %iface% down", ifd, exec); 484 result += execute("ifconfig %iface% down", ifd, exec);
473#endif 485# endif
474 return ((result == 2) ? 2 : 0); 486 return ((result == 2) ? 2 : 0);
475} 487}
476 488
477#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP 489# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
478struct dhcp_client_t { 490struct dhcp_client_t {
479 const char *name; 491 const char *name;
480 const char *startcmd; 492 const char *startcmd;
@@ -500,21 +512,21 @@ static const struct dhcp_client_t ext_dhcp_clients[] = {
500 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", 512 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
501 }, 513 },
502}; 514};
503#endif /* ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCPC */ 515# endif /* FEATURE_IFUPDOWN_EXTERNAL_DHCPC */
504 516
505#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP 517# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
506static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec) 518static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
507{ 519{
508 unsigned i; 520 unsigned i;
509#if ENABLE_FEATURE_IFUPDOWN_IP 521# if ENABLE_FEATURE_IFUPDOWN_IP
510 /* ip doesn't up iface when it configures it (unlike ifconfig) */ 522 /* ip doesn't up iface when it configures it (unlike ifconfig) */
511 if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec)) 523 if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec))
512 return 0; 524 return 0;
513#else 525# else
514 /* needed if we have hwaddress on dhcp iface */ 526 /* needed if we have hwaddress on dhcp iface */
515 if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec)) 527 if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec))
516 return 0; 528 return 0;
517#endif 529# endif
518 for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) { 530 for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) {
519 if (exists_execable(ext_dhcp_clients[i].name)) 531 if (exists_execable(ext_dhcp_clients[i].name))
520 return execute(ext_dhcp_clients[i].startcmd, ifd, exec); 532 return execute(ext_dhcp_clients[i].startcmd, ifd, exec);
@@ -522,31 +534,31 @@ static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
522 bb_error_msg("no dhcp clients found"); 534 bb_error_msg("no dhcp clients found");
523 return 0; 535 return 0;
524} 536}
525#elif ENABLE_UDHCPC 537# elif ENABLE_UDHCPC
526static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec) 538static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
527{ 539{
528#if ENABLE_FEATURE_IFUPDOWN_IP 540# if ENABLE_FEATURE_IFUPDOWN_IP
529 /* ip doesn't up iface when it configures it (unlike ifconfig) */ 541 /* ip doesn't up iface when it configures it (unlike ifconfig) */
530 if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec)) 542 if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec))
531 return 0; 543 return 0;
532#else 544# else
533 /* needed if we have hwaddress on dhcp iface */ 545 /* needed if we have hwaddress on dhcp iface */
534 if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec)) 546 if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec))
535 return 0; 547 return 0;
536#endif 548# endif
537 return execute("udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid " 549 return execute("udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid "
538 "-i %iface%[[ -H %hostname%]][[ -c %client%]][[ -s %script%]][[ %udhcpc_opts%]]", 550 "-i %iface%[[ -H %hostname%]][[ -c %client%]][[ -s %script%]][[ %udhcpc_opts%]]",
539 ifd, exec); 551 ifd, exec);
540} 552}
541#else 553# else
542static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd UNUSED_PARAM, 554static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd UNUSED_PARAM,
543 execfn *exec UNUSED_PARAM) 555 execfn *exec UNUSED_PARAM)
544{ 556{
545 return 0; /* no dhcp support */ 557 return 0; /* no dhcp support */
546} 558}
547#endif 559# endif
548 560
549#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP 561# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP
550static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) 562static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
551{ 563{
552 int result = 0; 564 int result = 0;
@@ -569,7 +581,7 @@ static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
569 result += static_down(ifd, exec); 581 result += static_down(ifd, exec);
570 return ((result == 3) ? 3 : 0); 582 return ((result == 3) ? 3 : 0);
571} 583}
572#elif ENABLE_UDHCPC 584# elif ENABLE_UDHCPC
573static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) 585static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
574{ 586{
575 int result; 587 int result;
@@ -586,13 +598,13 @@ static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec)
586 result += static_down(ifd, exec); 598 result += static_down(ifd, exec);
587 return ((result == 3) ? 3 : 0); 599 return ((result == 3) ? 3 : 0);
588} 600}
589#else 601# else
590static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd UNUSED_PARAM, 602static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd UNUSED_PARAM,
591 execfn *exec UNUSED_PARAM) 603 execfn *exec UNUSED_PARAM)
592{ 604{
593 return 0; /* no dhcp support */ 605 return 0; /* no dhcp support */
594} 606}
595#endif 607# endif
596 608
597static int FAST_FUNC manual_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) 609static int FAST_FUNC manual_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM)
598{ 610{
@@ -644,7 +656,8 @@ static const struct address_family_t addr_inet = {
644 methods 656 methods
645}; 657};
646 658
647#endif /* if ENABLE_FEATURE_IFUPDOWN_IPV4 */ 659#endif /* FEATURE_IFUPDOWN_IPV4 */
660
648 661
649/* Returns pointer to the next word, or NULL. 662/* Returns pointer to the next word, or NULL.
650 * In 1st case, advances *buf to the word after this one. 663 * In 1st case, advances *buf to the word after this one.
diff --git a/networking/inetd.c b/networking/inetd.c
index 7030062b6..fb00c6cd7 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -295,7 +295,7 @@ struct globals {
295 struct rlimit rlim_ofile; 295 struct rlimit rlim_ofile;
296 servtab_t *serv_list; 296 servtab_t *serv_list;
297 int global_queuelen; 297 int global_queuelen;
298 int maxsock; /* max fd# in allsock, -1: unknown */ 298 int maxsock; /* max fd# in allsock, -1: unknown */
299 /* whenever maxsock grows, prev_maxsock is set to new maxsock, 299 /* whenever maxsock grows, prev_maxsock is set to new maxsock,
300 * but if maxsock is set to -1, prev_maxsock is not changed */ 300 * but if maxsock is set to -1, prev_maxsock is not changed */
301 int prev_maxsock; 301 int prev_maxsock;
@@ -778,6 +778,12 @@ static servtab_t *parse_one_line(void)
778 argc = 0; 778 argc = 0;
779 while ((arg = token[6+argc]) != NULL && argc < MAXARGV) 779 while ((arg = token[6+argc]) != NULL && argc < MAXARGV)
780 sep->se_argv[argc++] = xstrdup(arg); 780 sep->se_argv[argc++] = xstrdup(arg);
781 /* Some inetd.conf files have no argv's, not even argv[0].
782 * Fix them up.
783 * (Technically, programs can be execed with argv[0] = NULL,
784 * but many programs do not like that at all) */
785 if (argc == 0)
786 sep->se_argv[0] = xstrdup(sep->se_program);
781 787
782 /* catch mixups. "<service> stream udp ..." == wtf */ 788 /* catch mixups. "<service> stream udp ..." == wtf */
783 if (sep->se_socktype == SOCK_STREAM) { 789 if (sep->se_socktype == SOCK_STREAM) {
diff --git a/networking/ip.c b/networking/ip.c
index 7b1e2eb6a..350656cef 100644
--- a/networking/ip.c
+++ b/networking/ip.c
@@ -1,13 +1,11 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * "ip" utility frontend.
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 * 4 *
7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 * 6 *
9 * Changes: 7 * Changes:
10 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 8 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
11 * Bernhard Reutner-Fischer rewrote to use index_in_substr_array 9 * Bernhard Reutner-Fischer rewrote to use index_in_substr_array
12 */ 10 */
13 11
diff --git a/networking/ipcalc.c b/networking/ipcalc.c
index d4aa885c6..acbaa4ac5 100644
--- a/networking/ipcalc.c
+++ b/networking/ipcalc.c
@@ -15,9 +15,9 @@
15/* After libbb.h, because on some systems it needs other includes */ 15/* After libbb.h, because on some systems it needs other includes */
16#include <arpa/inet.h> 16#include <arpa/inet.h>
17 17
18#define CLASS_A_NETMASK ntohl(0xFF000000) 18#define CLASS_A_NETMASK ntohl(0xFF000000)
19#define CLASS_B_NETMASK ntohl(0xFFFF0000) 19#define CLASS_B_NETMASK ntohl(0xFFFF0000)
20#define CLASS_C_NETMASK ntohl(0xFFFFFF00) 20#define CLASS_C_NETMASK ntohl(0xFFFFFF00)
21 21
22static unsigned long get_netmask(unsigned long ipaddr) 22static unsigned long get_netmask(unsigned long ipaddr)
23{ 23{
diff --git a/networking/libiproute/ip_parse_common_args.c b/networking/libiproute/ip_parse_common_args.c
index bf01528c4..59c759b23 100644
--- a/networking/libiproute/ip_parse_common_args.c
+++ b/networking/libiproute/ip_parse_common_args.c
@@ -1,18 +1,15 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * ip.c "ip" utility frontend. 3 * This program is free software; you can redistribute it and/or
4 * 4 * modify it under the terms of the GNU General Public License
5 * This program is free software; you can redistribute it and/or 5 * as published by the Free Software Foundation; either version
6 * modify it under the terms of the GNU General Public License 6 * 2 of the License, or (at your option) any later version.
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11 * 7 *
8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
12 * 9 *
13 * Changes: 10 * Changes:
14 * 11 *
15 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 12 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
16 */ 13 */
17 14
18#include "ip_common.h" /* #include "libbb.h" is inside */ 15#include "ip_common.h" /* #include "libbb.h" is inside */
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index 1be03a6c3..397a8ee34 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -1,13 +1,11 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * ipaddress.c "ip address".
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 * 4 *
7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 * 6 *
9 * Changes: 7 * Changes:
10 * Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated 8 * Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated
11 */ 9 */
12 10
13#include <fnmatch.h> 11#include <fnmatch.h>
@@ -20,7 +18,7 @@
20 18
21#ifndef IFF_LOWER_UP 19#ifndef IFF_LOWER_UP
22/* from linux/if.h */ 20/* from linux/if.h */
23#define IFF_LOWER_UP 0x10000 /* driver signals L1 up*/ 21#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
24#endif 22#endif
25 23
26struct filter_t { 24struct filter_t {
@@ -365,7 +363,7 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
365 363
366struct nlmsg_list { 364struct nlmsg_list {
367 struct nlmsg_list *next; 365 struct nlmsg_list *next;
368 struct nlmsghdr h; 366 struct nlmsghdr h;
369}; 367};
370 368
371static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo) 369static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo)
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c
index c5ba294aa..82ab979a5 100644
--- a/networking/libiproute/iplink.c
+++ b/networking/libiproute/iplink.c
@@ -1,7 +1,5 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * iplink.c "ip link".
4 *
5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 3 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6 * 4 *
7 * 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.
@@ -296,9 +294,9 @@ static int do_change(char **argv, const unsigned rtm)
296 }; 294 };
297 struct rtnl_handle rth; 295 struct rtnl_handle rth;
298 struct { 296 struct {
299 struct nlmsghdr n; 297 struct nlmsghdr n;
300 struct ifinfomsg i; 298 struct ifinfomsg i;
301 char buf[1024]; 299 char buf[1024];
302 } req; 300 } req;
303 smalluint arg; 301 smalluint arg;
304 char *name_str = NULL, *link_str = NULL, *type_str = NULL, *dev_str = NULL; 302 char *name_str = NULL, *link_str = NULL, *type_str = NULL, *dev_str = NULL;
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c
index 1696e6a34..f6071b463 100644
--- a/networking/libiproute/iproute.c
+++ b/networking/libiproute/iproute.c
@@ -1,19 +1,16 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * iproute.c "ip route".
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 * 4 *
7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 *
9 * 6 *
10 * Changes: 7 * Changes:
11 * 8 *
12 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 9 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
13 * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized 10 * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
14 */ 11 */
15 12
16#include "ip_common.h" /* #include "libbb.h" is inside */ 13#include "ip_common.h" /* #include "libbb.h" is inside */
17#include "rt_names.h" 14#include "rt_names.h"
18#include "utils.h" 15#include "utils.h"
19 16
@@ -327,9 +324,9 @@ IF_FEATURE_IP_RULE(ARG_table,)
327 }; 324 };
328 struct rtnl_handle rth; 325 struct rtnl_handle rth;
329 struct { 326 struct {
330 struct nlmsghdr n; 327 struct nlmsghdr n;
331 struct rtmsg r; 328 struct rtmsg r;
332 char buf[1024]; 329 char buf[1024];
333 } req; 330 } req;
334 char mxbuf[256]; 331 char mxbuf[256];
335 struct rtattr * mxrta = (void*)mxbuf; 332 struct rtattr * mxrta = (void*)mxbuf;
@@ -791,8 +788,8 @@ static int iproute_get(char **argv)
791 } 788 }
792 req.r.rtm_dst_len = addr.bitlen; 789 req.r.rtm_dst_len = addr.bitlen;
793 } 790 }
794 argv++;
795 } 791 }
792 argv++;
796 } 793 }
797 794
798 if (req.r.rtm_dst_len == 0) { 795 if (req.r.rtm_dst_len == 0) {
diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c
index 3af6a83a8..dd3265c7c 100644
--- a/networking/libiproute/iprule.c
+++ b/networking/libiproute/iprule.c
@@ -1,18 +1,15 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * iprule.c "ip rule". 3 * This program is free software; you can redistribute it and/or
4 * 4 * modify it under the terms of the GNU General Public License
5 * This program is free software; you can redistribute it and/or 5 * as published by the Free Software Foundation; either version
6 * modify it under the terms of the GNU General Public License 6 * 2 of the License, or (at your option) any later version.
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11 * 7 *
8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
12 * 9 *
13 * Changes: 10 * Changes:
14 * 11 *
15 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 12 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
16 * initially integrated into busybox by Bernhard Reutner-Fischer 13 * initially integrated into busybox by Bernhard Reutner-Fischer
17 */ 14 */
18 15
@@ -191,9 +188,9 @@ static int iprule_modify(int cmd, char **argv)
191 bool table_ok = 0; 188 bool table_ok = 0;
192 struct rtnl_handle rth; 189 struct rtnl_handle rth;
193 struct { 190 struct {
194 struct nlmsghdr n; 191 struct nlmsghdr n;
195 struct rtmsg r; 192 struct rtmsg r;
196 char buf[1024]; 193 char buf[1024];
197 } req; 194 } req;
198 smalluint key; 195 smalluint key;
199 196
diff --git a/networking/libiproute/iptunnel.c b/networking/libiproute/iptunnel.c
index bce373d05..5942feafc 100644
--- a/networking/libiproute/iptunnel.c
+++ b/networking/libiproute/iptunnel.c
@@ -1,16 +1,14 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * iptunnel.c "ip tunnel"
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 * 4 *
7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 * 6 *
9 * Changes: 7 * Changes:
10 * 8 *
11 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 9 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
12 * Rani Assaf <rani@magic.metawire.com> 980930: do not allow key for ipip/sit 10 * Rani Assaf <rani@magic.metawire.com> 980930: do not allow key for ipip/sit
13 * Phil Karn <karn@ka9q.ampr.org> 990408: "pmtudisc" flag 11 * Phil Karn <karn@ka9q.ampr.org> 990408: "pmtudisc" flag
14 */ 12 */
15 13
16#include <netinet/ip.h> 14#include <netinet/ip.h>
diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c
index 8da80b2fc..7291ee2f1 100644
--- a/networking/libiproute/libnetlink.c
+++ b/networking/libiproute/libnetlink.c
@@ -1,7 +1,5 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * RTnetlink service routines.
4 *
5 * This program is free software; you can redistribute it and/or 3 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License 4 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 5 * as published by the Free Software Foundation; either version
@@ -74,8 +72,8 @@ int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, in
74 struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } }; 72 struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
75 struct msghdr msg = { 73 struct msghdr msg = {
76 (void*)&nladdr, sizeof(nladdr), 74 (void*)&nladdr, sizeof(nladdr),
77 iov, 2, 75 iov, 2,
78 NULL, 0, 76 NULL, 0,
79 0 77 0
80 }; 78 };
81 79
@@ -108,8 +106,8 @@ static int rtnl_dump_filter(struct rtnl_handle *rth,
108 106
109 struct msghdr msg = { 107 struct msghdr msg = {
110 (void*)&nladdr, sizeof(nladdr), 108 (void*)&nladdr, sizeof(nladdr),
111 &iov, 1, 109 &iov, 1,
112 NULL, 0, 110 NULL, 0,
113 0 111 0
114 }; 112 };
115 113
@@ -214,8 +212,8 @@ int FAST_FUNC rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
214 char *buf = xmalloc(8*1024); /* avoid big stack buffer */ 212 char *buf = xmalloc(8*1024); /* avoid big stack buffer */
215 struct msghdr msg = { 213 struct msghdr msg = {
216 (void*)&nladdr, sizeof(nladdr), 214 (void*)&nladdr, sizeof(nladdr),
217 &iov, 1, 215 &iov, 1,
218 NULL, 0, 216 NULL, 0,
219 0 217 0
220 }; 218 };
221 219
diff --git a/networking/libiproute/libnetlink.h b/networking/libiproute/libnetlink.h
index 4e4d5b7b9..51bee2d67 100644
--- a/networking/libiproute/libnetlink.h
+++ b/networking/libiproute/libnetlink.h
@@ -11,11 +11,11 @@
11PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 11PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
12 12
13struct rtnl_handle { 13struct rtnl_handle {
14 int fd; 14 int fd;
15 struct sockaddr_nl local; 15 struct sockaddr_nl local;
16 struct sockaddr_nl peer; 16 struct sockaddr_nl peer;
17 uint32_t seq; 17 uint32_t seq;
18 uint32_t dump; 18 uint32_t dump;
19}; 19};
20 20
21extern void xrtnl_open(struct rtnl_handle *rth) FAST_FUNC; 21extern void xrtnl_open(struct rtnl_handle *rth) FAST_FUNC;
diff --git a/networking/libiproute/ll_addr.c b/networking/libiproute/ll_addr.c
index c2c01305d..33a54ea6c 100644
--- a/networking/libiproute/ll_addr.c
+++ b/networking/libiproute/ll_addr.c
@@ -1,13 +1,11 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * ll_addr.c 3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version
6 * 2 of the License, or (at your option) any later version.
4 * 7 *
5 * This program is free software; you can redistribute it and/or 8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11 */ 9 */
12 10
13#include <net/if_arp.h> 11#include <net/if_arp.h>
diff --git a/networking/libiproute/ll_map.c b/networking/libiproute/ll_map.c
index 246b9e33a..27cd90f34 100644
--- a/networking/libiproute/ll_map.c
+++ b/networking/libiproute/ll_map.c
@@ -1,17 +1,14 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * ll_map.c 3 * This program is free software; you can redistribute it and/or
4 * 4 * modify it under the terms of the GNU General Public License
5 * This program is free software; you can redistribute it and/or 5 * as published by the Free Software Foundation; either version
6 * modify it under the terms of the GNU General Public License 6 * 2 of the License, or (at your option) any later version.
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11 * 7 *
8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
12 */ 9 */
13 10
14#include <net/if.h> /* struct ifreq and co. */ 11#include <net/if.h> /* struct ifreq and co. */
15 12
16#include "libbb.h" 13#include "libbb.h"
17#include "libnetlink.h" 14#include "libnetlink.h"
diff --git a/networking/libiproute/ll_proto.c b/networking/libiproute/ll_proto.c
index 1cd576f1d..04925ecf6 100644
--- a/networking/libiproute/ll_proto.c
+++ b/networking/libiproute/ll_proto.c
@@ -1,13 +1,11 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * ll_proto.c 3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version
6 * 2 of the License, or (at your option) any later version.
4 * 7 *
5 * This program is free software; you can redistribute it and/or 8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11 */ 9 */
12 10
13#include "libbb.h" 11#include "libbb.h"
diff --git a/networking/libiproute/ll_types.c b/networking/libiproute/ll_types.c
index 3861c2870..38b6c0516 100644
--- a/networking/libiproute/ll_types.c
+++ b/networking/libiproute/ll_types.c
@@ -1,13 +1,11 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * ll_types.c 3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version
6 * 2 of the License, or (at your option) any later version.
4 * 7 *
5 * This program is free software; you can redistribute it and/or 8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11 */ 9 */
12#include <arpa/inet.h> 10#include <arpa/inet.h>
13#include <linux/if_arp.h> 11#include <linux/if_arp.h>
diff --git a/networking/libiproute/rt_names.c b/networking/libiproute/rt_names.c
index 8dd16e3d3..c474ab903 100644
--- a/networking/libiproute/rt_names.c
+++ b/networking/libiproute/rt_names.c
@@ -1,13 +1,11 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * rt_names.c rtnetlink names DB. 3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version
6 * 2 of the License, or (at your option) any later version.
4 * 7 *
5 * This program is free software; you can redistribute it and/or 8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11 */ 9 */
12#include "libbb.h" 10#include "libbb.h"
13#include "rt_names.h" 11#include "rt_names.h"
diff --git a/networking/libiproute/rtm_map.c b/networking/libiproute/rtm_map.c
index 5e358e105..3bab53baf 100644
--- a/networking/libiproute/rtm_map.c
+++ b/networking/libiproute/rtm_map.c
@@ -1,14 +1,11 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * rtm_map.c 3 * This program is free software; you can redistribute it and/or
4 * 4 * modify it under the terms of the GNU General Public License
5 * This program is free software; you can redistribute it and/or 5 * as published by the Free Software Foundation; either version
6 * modify it under the terms of the GNU General Public License 6 * 2 of the License, or (at your option) any later version.
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11 * 7 *
8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
12 */ 9 */
13 10
14#include "libbb.h" 11#include "libbb.h"
diff --git a/networking/libiproute/utils.c b/networking/libiproute/utils.c
index 2b646f0ea..d32db8de5 100644
--- a/networking/libiproute/utils.c
+++ b/networking/libiproute/utils.c
@@ -1,14 +1,12 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * utils.c
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 * 4 *
7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 * 6 *
9 * Changes: 7 * Changes:
10 * 8 *
11 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 9 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
12 */ 10 */
13 11
14#include "libbb.h" 12#include "libbb.h"
diff --git a/networking/libiproute/utils.h b/networking/libiproute/utils.h
index ed03e785a..93c9d25d6 100644
--- a/networking/libiproute/utils.h
+++ b/networking/libiproute/utils.h
@@ -17,14 +17,14 @@ extern smallint oneline;
17extern char _SL_; 17extern char _SL_;
18 18
19#ifndef IPPROTO_ESP 19#ifndef IPPROTO_ESP
20#define IPPROTO_ESP 50 20#define IPPROTO_ESP 50
21#endif 21#endif
22#ifndef IPPROTO_AH 22#ifndef IPPROTO_AH
23#define IPPROTO_AH 51 23#define IPPROTO_AH 51
24#endif 24#endif
25 25
26#define SPRINT_BSIZE 64 26#define SPRINT_BSIZE 64
27#define SPRINT_BUF(x) char x[SPRINT_BSIZE] 27#define SPRINT_BUF(x) char x[SPRINT_BSIZE]
28 28
29extern void incomplete_command(void) NORETURN; 29extern void incomplete_command(void) NORETURN;
30 30
diff --git a/networking/nameif.c b/networking/nameif.c
index 45a3229f4..d02c2c11b 100644
--- a/networking/nameif.c
+++ b/networking/nameif.c
@@ -21,10 +21,10 @@
21#endif 21#endif
22 22
23/* Taken from linux/sockios.h */ 23/* Taken from linux/sockios.h */
24#define SIOCSIFNAME 0x8923 /* set interface name */ 24#define SIOCSIFNAME 0x8923 /* set interface name */
25 25
26/* Octets in one Ethernet addr, from <linux/if_ether.h> */ 26/* Octets in one Ethernet addr, from <linux/if_ether.h> */
27#define ETH_ALEN 6 27#define ETH_ALEN 6
28 28
29#ifndef ifr_newname 29#ifndef ifr_newname
30#define ifr_newname ifr_ifru.ifru_slave 30#define ifr_newname ifr_ifru.ifru_slave
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index 8594a67a6..e98a5dd5b 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -268,8 +268,7 @@ static int doexec(char **proggie)
268 dup2(0, 1); 268 dup2(0, 1);
269 /* dup2(0, 2); - do we *really* want this? NO! 269 /* dup2(0, 2); - do we *really* want this? NO!
270 * exec'ed prog can do it yourself, if needed */ 270 * exec'ed prog can do it yourself, if needed */
271 execvp(proggie[0], proggie); 271 BB_EXECVP_or_die(proggie);
272 bb_perror_msg_and_die("can't execute '%s'", proggie[0]);
273} 272}
274 273
275/* connect_w_timeout: 274/* connect_w_timeout:
@@ -766,7 +765,7 @@ int nc_main(int argc UNUSED_PARAM, char **argv)
766 getopt32(argv, "hnp:s:uvw:" IF_NC_SERVER("l") 765 getopt32(argv, "hnp:s:uvw:" IF_NC_SERVER("l")
767 IF_NC_EXTRA("i:o:z"), 766 IF_NC_EXTRA("i:o:z"),
768 &str_p, &str_s, &o_wait 767 &str_p, &str_s, &o_wait
769 IF_NC_EXTRA(, &str_i, &str_o, &o_verbose)); 768 IF_NC_EXTRA(, &str_i, &str_o), &o_verbose);
770 argv += optind; 769 argv += optind;
771#if ENABLE_NC_EXTRA 770#if ENABLE_NC_EXTRA
772 if (option_mask32 & OPT_i) /* line-interval time */ 771 if (option_mask32 & OPT_i) /* line-interval time */
diff --git a/networking/netstat.c b/networking/netstat.c
index 2a83af3ac..356fb53cb 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -699,7 +699,7 @@ int netstat_main(int argc UNUSED_PARAM, char **argv)
699 flags |= opt; 699 flags |= opt;
700 } 700 }
701 if (flags & (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) { 701 if (flags & (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) {
702 printf("Active Internet connections "); /* xxx */ 702 printf("Active Internet connections "); /* xxx */
703 703
704 if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED)) 704 if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED))
705 printf("(servers and established)"); 705 printf("(servers and established)");
diff --git a/networking/ntpd.c b/networking/ntpd.c
index b7bd239b5..8fe529edb 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -89,7 +89,7 @@
89//UNUSED: #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */ 89//UNUSED: #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */
90 90
91#define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */ 91#define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */
92#define BURSTPOLL 0 /* initial poll */ 92#define BURSTPOLL 0 /* initial poll */
93#define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ 93#define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */
94#define BIGPOLL 10 /* drop to lower poll at any trouble (10: 17 min) */ 94#define BIGPOLL 10 /* drop to lower poll at any trouble (10: 17 min) */
95#define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ 95#define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */
@@ -865,7 +865,7 @@ fit(peer_t *p, double rd)
865 VERB3 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted); 865 VERB3 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted);
866 return 0; 866 return 0;
867 } 867 }
868#if 0 /* we filter out such packets earlier */ 868#if 0 /* we filter out such packets earlier */
869 if ((p->lastpkt_status & LI_ALARM) == LI_ALARM 869 if ((p->lastpkt_status & LI_ALARM) == LI_ALARM
870 || p->lastpkt_stratum >= MAXSTRAT 870 || p->lastpkt_stratum >= MAXSTRAT
871 ) { 871 ) {
@@ -2110,7 +2110,7 @@ direct_freq(double fp_offset)
2110} 2110}
2111 2111
2112static void 2112static void
2113set_freq(double freq) /* frequency update */ 2113set_freq(double freq) /* frequency update */
2114{ 2114{
2115 char tbuf[80]; 2115 char tbuf[80];
2116 2116
diff --git a/networking/ntpd_simple.c b/networking/ntpd_simple.c
index 5905e54e9..4ad44e4f3 100644
--- a/networking/ntpd_simple.c
+++ b/networking/ntpd_simple.c
@@ -870,7 +870,7 @@ static NOINLINE void ntp_init(char **argv)
870 int prec = 0; 870 int prec = 0;
871 int b; 871 int b;
872# if 0 872# if 0
873 struct timespec tp; 873 struct timespec tp;
874 /* We can use sys_clock_getres but assuming 10ms tick should be fine */ 874 /* We can use sys_clock_getres but assuming 10ms tick should be fine */
875 clock_getres(CLOCK_REALTIME, &tp); 875 clock_getres(CLOCK_REALTIME, &tp);
876 tp.tv_sec = 0; 876 tp.tv_sec = 0;
diff --git a/networking/ping.c b/networking/ping.c
index 3aba4906e..366a98668 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -29,6 +29,93 @@
29#include <netinet/ip_icmp.h> 29#include <netinet/ip_icmp.h>
30#include "libbb.h" 30#include "libbb.h"
31 31
32//config:config PING
33//config: bool "ping"
34//config: default y
35//config: depends on PLATFORM_LINUX
36//config: help
37//config: ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to
38//config: elicit an ICMP ECHO_RESPONSE from a host or gateway.
39//config:
40//config:config PING6
41//config: bool "ping6"
42//config: default y
43//config: depends on FEATURE_IPV6 && PING
44//config: help
45//config: This will give you a ping that can talk IPv6.
46//config:
47//config:config FEATURE_FANCY_PING
48//config: bool "Enable fancy ping output"
49//config: default y
50//config: depends on PING
51//config: help
52//config: Make the output from the ping applet include statistics, and at the
53//config: same time provide full support for ICMP packets.
54
55/* Needs socket(AF_INET, SOCK_RAW, IPPROTO_ICMP), therefore _BB_SUID_MAYBE: */
56//applet:IF_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE))
57//applet:IF_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_MAYBE))
58
59//kbuild:lib-$(CONFIG_PING) += ping.o
60//kbuild:lib-$(CONFIG_PING6) += ping.o
61
62//usage:#if !ENABLE_FEATURE_FANCY_PING
63//usage:# define ping_trivial_usage
64//usage: "HOST"
65//usage:# define ping_full_usage "\n\n"
66//usage: "Send ICMP ECHO_REQUEST packets to network hosts"
67//usage:# define ping6_trivial_usage
68//usage: "HOST"
69//usage:# define ping6_full_usage "\n\n"
70//usage: "Send ICMP ECHO_REQUEST packets to network hosts"
71//usage:#else
72//usage:# define ping_trivial_usage
73//usage: "[OPTIONS] HOST"
74//usage:# define ping_full_usage "\n\n"
75//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n"
76//usage: "\nOptions:"
77//usage: "\n -4,-6 Force IP or IPv6 name resolution"
78//usage: "\n -c CNT Send only CNT pings"
79//usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)"
80//usage: "\n -t TTL Set TTL"
81//usage: "\n -I IFACE/IP Use interface or IP address as source"
82//usage: "\n -W SEC Seconds to wait for the first response (default:10)"
83//usage: "\n (after all -c CNT packets are sent)"
84//usage: "\n -w SEC Seconds until ping exits (default:infinite)"
85//usage: "\n (can exit earlier with -c CNT)"
86//usage: "\n -q Quiet, only displays output at start"
87//usage: "\n and when finished"
88//usage:
89//usage:# define ping6_trivial_usage
90//usage: "[OPTIONS] HOST"
91//usage:# define ping6_full_usage "\n\n"
92//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n"
93//usage: "\nOptions:"
94//usage: "\n -c CNT Send only CNT pings"
95//usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)"
96//usage: "\n -I IFACE/IP Use interface or IP address as source"
97//usage: "\n -q Quiet, only displays output at start"
98//usage: "\n and when finished"
99//usage:
100//usage:#endif
101//usage:
102//usage:#define ping_example_usage
103//usage: "$ ping localhost\n"
104//usage: "PING slag (127.0.0.1): 56 data bytes\n"
105//usage: "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n"
106//usage: "\n"
107//usage: "--- debian ping statistics ---\n"
108//usage: "1 packets transmitted, 1 packets received, 0% packet loss\n"
109//usage: "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
110//usage:#define ping6_example_usage
111//usage: "$ ping6 ip6-localhost\n"
112//usage: "PING ip6-localhost (::1): 56 data bytes\n"
113//usage: "64 bytes from ::1: icmp6_seq=0 ttl=64 time=20.1 ms\n"
114//usage: "\n"
115//usage: "--- ip6-localhost ping statistics ---\n"
116//usage: "1 packets transmitted, 1 packets received, 0% packet loss\n"
117//usage: "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
118
32#if ENABLE_PING6 119#if ENABLE_PING6
33# include <netinet/icmp6.h> 120# include <netinet/icmp6.h>
34/* I see RENUMBERED constants in bits/in.h - !!? 121/* I see RENUMBERED constants in bits/in.h - !!?
@@ -223,17 +310,18 @@ static int common_ping_main(sa_family_t af, char **argv)
223 310
224/* Full(er) version */ 311/* Full(er) version */
225 312
226#define OPT_STRING ("qvc:s:w:W:I:4" IF_PING6("6")) 313#define OPT_STRING ("qvc:s:t:w:W:I:4" IF_PING6("6"))
227enum { 314enum {
228 OPT_QUIET = 1 << 0, 315 OPT_QUIET = 1 << 0,
229 OPT_VERBOSE = 1 << 1, 316 OPT_VERBOSE = 1 << 1,
230 OPT_c = 1 << 2, 317 OPT_c = 1 << 2,
231 OPT_s = 1 << 3, 318 OPT_s = 1 << 3,
232 OPT_w = 1 << 4, 319 OPT_t = 1 << 4,
233 OPT_W = 1 << 5, 320 OPT_w = 1 << 5,
234 OPT_I = 1 << 6, 321 OPT_W = 1 << 6,
235 OPT_IPV4 = 1 << 7, 322 OPT_I = 1 << 7,
236 OPT_IPV6 = (1 << 8) * ENABLE_PING6, 323 OPT_IPV4 = 1 << 8,
324 OPT_IPV6 = (1 << 9) * ENABLE_PING6,
237}; 325};
238 326
239 327
@@ -244,6 +332,7 @@ struct globals {
244 len_and_sockaddr *source_lsa; 332 len_and_sockaddr *source_lsa;
245 unsigned datalen; 333 unsigned datalen;
246 unsigned pingcount; /* must be int-sized */ 334 unsigned pingcount; /* must be int-sized */
335 unsigned opt_ttl;
247 unsigned long ntransmitted, nreceived, nrepeats; 336 unsigned long ntransmitted, nreceived, nrepeats;
248 uint16_t myid; 337 uint16_t myid;
249 unsigned tmin, tmax; /* in us */ 338 unsigned tmin, tmax; /* in us */
@@ -275,6 +364,7 @@ struct globals {
275#define nreceived (G.nreceived ) 364#define nreceived (G.nreceived )
276#define nrepeats (G.nrepeats ) 365#define nrepeats (G.nrepeats )
277#define pingcount (G.pingcount ) 366#define pingcount (G.pingcount )
367#define opt_ttl (G.opt_ttl )
278#define myid (G.myid ) 368#define myid (G.myid )
279#define tmin (G.tmin ) 369#define tmin (G.tmin )
280#define tmax (G.tmax ) 370#define tmax (G.tmax )
@@ -586,6 +676,12 @@ static void ping4(len_and_sockaddr *lsa)
586 sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */ 676 sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */
587 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); 677 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt));
588 678
679 if (opt_ttl != 0) {
680 setsockopt(pingsock, IPPROTO_IP, IP_TTL, &opt_ttl, sizeof(opt_ttl));
681 /* above doesnt affect packets sent to bcast IP, so... */
682 setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, &opt_ttl, sizeof(opt_ttl));
683 }
684
589 signal(SIGINT, print_stats_and_exit); 685 signal(SIGINT, print_stats_and_exit);
590 686
591 /* start the ping's going ... */ 687 /* start the ping's going ... */
@@ -735,9 +831,9 @@ static int common_ping_main(int opt, char **argv)
735 831
736 INIT_G(); 832 INIT_G();
737 833
738 /* exactly one argument needed; -v and -q don't mix; -c NUM, -w NUM, -W NUM */ 834 /* exactly one argument needed; -v and -q don't mix; -c NUM, -t NUM, -w NUM, -W NUM */
739 opt_complementary = "=1:q--v:v--q:c+:w+:W+"; 835 opt_complementary = "=1:q--v:v--q:c+:t+:w+:W+";
740 opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &deadline, &timeout, &str_I); 836 opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I);
741 if (opt & OPT_s) 837 if (opt & OPT_s)
742 datalen = xatou16(str_s); // -s 838 datalen = xatou16(str_s); // -s
743 if (opt & OPT_I) { // -I 839 if (opt & OPT_I) { // -I
diff --git a/networking/slattach.c b/networking/slattach.c
index 921ec552d..71edd2f27 100644
--- a/networking/slattach.c
+++ b/networking/slattach.c
@@ -134,9 +134,9 @@ int slattach_main(int argc UNUSED_PARAM, char **argv)
134 int i, encap, opt; 134 int i, encap, opt;
135 struct termios state; 135 struct termios state;
136 const char *proto = "cslip"; 136 const char *proto = "cslip";
137 const char *extcmd; /* Command to execute after hangup */ 137 const char *extcmd; /* Command to execute after hangup */
138 const char *baud_str; 138 const char *baud_str;
139 int baud_code = -1; /* Line baud rate (system code) */ 139 int baud_code = -1; /* Line baud rate (system code) */
140 140
141 enum { 141 enum {
142 OPT_p_proto = 1 << 0, 142 OPT_p_proto = 1 << 0,
diff --git a/networking/tc.c b/networking/tc.c
index 9242741e4..2e2473a70 100644
--- a/networking/tc.c
+++ b/networking/tc.c
@@ -1,7 +1,5 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * "tc" utility frontend.
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 * 4 *
7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
diff --git a/networking/telnet.c b/networking/telnet.c
index 12d1970fa..f6fad684c 100644
--- a/networking/telnet.c
+++ b/networking/telnet.c
@@ -42,11 +42,13 @@ enum {
42 UF_ECHO = 0x01, 42 UF_ECHO = 0x01,
43 UF_SGA = 0x02, 43 UF_SGA = 0x02,
44 44
45 TS_0 = 1, 45 TS_NORMAL = 0,
46 TS_COPY = 1,
46 TS_IAC = 2, 47 TS_IAC = 2,
47 TS_OPT = 3, 48 TS_OPT = 3,
48 TS_SUB1 = 4, 49 TS_SUB1 = 4,
49 TS_SUB2 = 5, 50 TS_SUB2 = 5,
51 TS_CR = 6,
50}; 52};
51 53
52typedef unsigned char byte; 54typedef unsigned char byte;
@@ -83,13 +85,13 @@ struct globals {
83 }; \ 85 }; \
84} while (0) 86} while (0)
85 87
86/* Function prototypes */ 88
87static void rawmode(void); 89static void rawmode(void);
88static void cookmode(void); 90static void cookmode(void);
89static void do_linemode(void); 91static void do_linemode(void);
90static void will_charmode(void); 92static void will_charmode(void);
91static void telopt(byte c); 93static void telopt(byte c);
92static int subneg(byte c); 94static void subneg(byte c);
93 95
94static void iac_flush(void) 96static void iac_flush(void)
95{ 97{
@@ -170,24 +172,24 @@ static void handle_net_output(int len)
170 * So I implemented it. It's really useful for me. I hope that 172 * So I implemented it. It's really useful for me. I hope that
171 * other people will find it interesting too. 173 * other people will find it interesting too.
172 */ 174 */
173 175 byte outbuf[2 * DATABUFSIZE];
174 int i, j;
175 byte *p = (byte*)G.buf; 176 byte *p = (byte*)G.buf;
176 byte outbuf[4*DATABUFSIZE]; 177 int j = 0;
177 178
178 for (i = len, j = 0; i > 0; i--, p++) { 179 for (; len > 0; len--, p++) {
179 if (*p == 0x1d) { 180 byte c = *p;
181 if (c == 0x1d) {
180 con_escape(); 182 con_escape();
181 return; 183 return;
182 } 184 }
183 outbuf[j++] = *p; 185 outbuf[j++] = c;
184 if (*p == 0xff) 186 if (c == IAC)
185 outbuf[j++] = 0xff; 187 outbuf[j++] = c; /* IAC -> IAC IAC */
186 else if (*p == 0x0d) 188 else if (c == '\r')
187 outbuf[j++] = 0x00; 189 outbuf[j++] = '\0'; /* CR -> CR NUL */
188 } 190 }
189 if (j > 0) 191 if (j > 0)
190 write(netfd, outbuf, j); 192 full_write(netfd, outbuf, j);
191} 193}
192 194
193static void handle_net_input(int len) 195static void handle_net_input(int len)
@@ -198,25 +200,44 @@ static void handle_net_input(int len)
198 for (i = 0; i < len; i++) { 200 for (i = 0; i < len; i++) {
199 byte c = G.buf[i]; 201 byte c = G.buf[i];
200 202
201 if (G.telstate == 0) { /* most of the time state == 0 */ 203 if (G.telstate == TS_NORMAL) { /* most typical state */
202 if (c == IAC) { 204 if (c == IAC) {
203 cstart = i; 205 cstart = i;
204 G.telstate = TS_IAC; 206 G.telstate = TS_IAC;
205 } 207 }
208 else if (c == '\r') {
209 cstart = i + 1;
210 G.telstate = TS_CR;
211 }
212 /* No IACs were seen so far, no need to copy
213 * bytes within G.buf: */
206 continue; 214 continue;
207 } 215 }
216
208 switch (G.telstate) { 217 switch (G.telstate) {
209 case TS_0: 218 case TS_CR:
219 /* Prev char was CR. If cur one is NUL, ignore it.
220 * See RFC 1123 section 3.3.1 for discussion of telnet EOL handling.
221 */
222 G.telstate = TS_COPY;
223 if (c == '\0')
224 break;
225 /* else: fall through - need to handle CR IAC ... properly */
226
227 case TS_COPY: /* Prev char was ordinary */
228 /* Similar to NORMAL, but in TS_COPY we need to copy bytes */
210 if (c == IAC) 229 if (c == IAC)
211 G.telstate = TS_IAC; 230 G.telstate = TS_IAC;
212 else 231 else
213 G.buf[cstart++] = c; 232 G.buf[cstart++] = c;
233 if (c == '\r')
234 G.telstate = TS_CR;
214 break; 235 break;
215 236
216 case TS_IAC: 237 case TS_IAC: /* Prev char was IAC */
217 if (c == IAC) { /* IAC IAC -> 0xFF */ 238 if (c == IAC) { /* IAC IAC -> one IAC */
218 G.buf[cstart++] = c; 239 G.buf[cstart++] = c;
219 G.telstate = TS_0; 240 G.telstate = TS_COPY;
220 break; 241 break;
221 } 242 }
222 /* else */ 243 /* else */
@@ -228,34 +249,38 @@ static void handle_net_input(int len)
228 case DONT: 249 case DONT:
229 case WILL: 250 case WILL:
230 case WONT: 251 case WONT:
231 G.telwish = c; 252 G.telwish = c;
232 G.telstate = TS_OPT; 253 G.telstate = TS_OPT;
233 break; 254 break;
255 /* DATA MARK must be added later */
234 default: 256 default:
235 G.telstate = TS_0; /* DATA MARK must be added later */ 257 G.telstate = TS_COPY;
236 } 258 }
237 break; 259 break;
238 case TS_OPT: /* WILL, WONT, DO, DONT */ 260
261 case TS_OPT: /* Prev chars were IAC WILL/WONT/DO/DONT */
239 telopt(c); 262 telopt(c);
240 G.telstate = TS_0; 263 G.telstate = TS_COPY;
241 break; 264 break;
265
242 case TS_SUB1: /* Subnegotiation */ 266 case TS_SUB1: /* Subnegotiation */
243 case TS_SUB2: /* Subnegotiation */ 267 case TS_SUB2: /* Subnegotiation */
244 if (subneg(c)) 268 subneg(c); /* can change G.telstate */
245 G.telstate = TS_0;
246 break; 269 break;
247 } 270 }
248 } 271 }
249 if (G.telstate) { 272
273 if (G.telstate != TS_NORMAL) {
274 /* We had some IACs, or CR */
250 if (G.iaclen) 275 if (G.iaclen)
251 iac_flush(); 276 iac_flush();
252 if (G.telstate == TS_0) 277 if (G.telstate == TS_COPY) /* we aren't in the middle of IAC */
253 G.telstate = 0; 278 G.telstate = TS_NORMAL;
254 len = cstart; 279 len = cstart;
255 } 280 }
256 281
257 if (len) 282 if (len)
258 write(STDOUT_FILENO, G.buf, len); 283 full_write(STDOUT_FILENO, G.buf, len);
259} 284}
260 285
261static void put_iac(int c) 286static void put_iac(int c)
@@ -495,7 +520,7 @@ static void telopt(byte c)
495} 520}
496 521
497/* subnegotiation -- ignore all (except TTYPE,NAWS) */ 522/* subnegotiation -- ignore all (except TTYPE,NAWS) */
498static int subneg(byte c) 523static void subneg(byte c)
499{ 524{
500 switch (G.telstate) { 525 switch (G.telstate) {
501 case TS_SUB1: 526 case TS_SUB1:
@@ -513,12 +538,13 @@ static int subneg(byte c)
513#endif 538#endif
514 break; 539 break;
515 case TS_SUB2: 540 case TS_SUB2:
516 if (c == SE) 541 if (c == SE) {
517 return TRUE; 542 G.telstate = TS_COPY;
543 return;
544 }
518 G.telstate = TS_SUB1; 545 G.telstate = TS_SUB1;
519 /* break; */ 546 break;
520 } 547 }
521 return FALSE;
522} 548}
523 549
524static void rawmode(void) 550static void rawmode(void)
@@ -533,21 +559,13 @@ static void cookmode(void)
533 tcsetattr(0, TCSADRAIN, &G.termios_def); 559 tcsetattr(0, TCSADRAIN, &G.termios_def);
534} 560}
535 561
536/* poll gives smaller (-70 bytes) code */
537#define USE_POLL 1
538
539int telnet_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 562int telnet_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
540int telnet_main(int argc UNUSED_PARAM, char **argv) 563int telnet_main(int argc UNUSED_PARAM, char **argv)
541{ 564{
542 char *host; 565 char *host;
543 int port; 566 int port;
544 int len; 567 int len;
545#ifdef USE_POLL
546 struct pollfd ufds[2]; 568 struct pollfd ufds[2];
547#else
548 fd_set readfds;
549 int maxfd;
550#endif
551 569
552 INIT_G(); 570 INIT_G();
553 571
@@ -585,63 +603,39 @@ int telnet_main(int argc UNUSED_PARAM, char **argv)
585 603
586 signal(SIGINT, record_signo); 604 signal(SIGINT, record_signo);
587 605
588#ifdef USE_POLL 606 ufds[0].fd = STDIN_FILENO;
589 ufds[0].fd = 0; ufds[1].fd = netfd; 607 ufds[0].events = POLLIN;
590 ufds[0].events = ufds[1].events = POLLIN; 608 ufds[1].fd = netfd;
591#else 609 ufds[1].events = POLLIN;
592 FD_ZERO(&readfds);
593 FD_SET(STDIN_FILENO, &readfds);
594 FD_SET(netfd, &readfds);
595 maxfd = netfd + 1;
596#endif
597 610
598 while (1) { 611 while (1) {
599#ifndef USE_POLL 612 if (poll(ufds, 2, -1) < 0) {
600 fd_set rfds = readfds;
601
602 switch (select(maxfd, &rfds, NULL, NULL, NULL))
603#else
604 switch (poll(ufds, 2, -1))
605#endif
606 {
607 case 0:
608 /* timeout */
609 case -1:
610 /* error, ignore and/or log something, bay go to loop */ 613 /* error, ignore and/or log something, bay go to loop */
611 if (bb_got_signal) 614 if (bb_got_signal)
612 con_escape(); 615 con_escape();
613 else 616 else
614 sleep(1); 617 sleep(1);
615 break; 618 continue;
616 default: 619 }
617 620
618#ifdef USE_POLL 621// FIXME: reads can block. Need full bidirectional buffering.
619 if (ufds[0].revents)
620#else
621 if (FD_ISSET(STDIN_FILENO, &rfds))
622#endif
623 {
624 len = safe_read(STDIN_FILENO, G.buf, DATABUFSIZE);
625 if (len <= 0)
626 doexit(EXIT_SUCCESS);
627 TRACE(0, ("Read con: %d\n", len));
628 handle_net_output(len);
629 }
630 622
631#ifdef USE_POLL 623 if (ufds[0].revents) {
632 if (ufds[1].revents) 624 len = safe_read(STDIN_FILENO, G.buf, DATABUFSIZE);
633#else 625 if (len <= 0)
634 if (FD_ISSET(netfd, &rfds)) 626 doexit(EXIT_SUCCESS);
635#endif 627 TRACE(0, ("Read con: %d\n", len));
636 { 628 handle_net_output(len);
637 len = safe_read(netfd, G.buf, DATABUFSIZE); 629 }
638 if (len <= 0) { 630
639 full_write1_str("Connection closed by foreign host\r\n"); 631 if (ufds[1].revents) {
640 doexit(EXIT_FAILURE); 632 len = safe_read(netfd, G.buf, DATABUFSIZE);
641 } 633 if (len <= 0) {
642 TRACE(0, ("Read netfd (%d): %d\n", netfd, len)); 634 full_write1_str("Connection closed by foreign host\r\n");
643 handle_net_input(len); 635 doexit(EXIT_FAILURE);
644 } 636 }
637 TRACE(0, ("Read netfd (%d): %d\n", netfd, len));
638 handle_net_input(len);
645 } 639 }
646 } /* while (1) */ 640 } /* while (1) */
647} 641}
diff --git a/networking/telnetd.c b/networking/telnetd.c
index 5c011e15d..07c6a6a73 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -141,7 +141,7 @@ remove_iacs(struct tsession *ts, int *pnum_totty)
141 if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) { 141 if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) {
142 struct winsize ws; 142 struct winsize ws;
143 if ((ptr+8) >= end) 143 if ((ptr+8) >= end)
144 break; /* incomplete, can't process */ 144 break; /* incomplete, can't process */
145 ws.ws_col = (ptr[3] << 8) | ptr[4]; 145 ws.ws_col = (ptr[3] << 8) | ptr[4];
146 ws.ws_row = (ptr[5] << 8) | ptr[6]; 146 ws.ws_row = (ptr[5] << 8) | ptr[6];
147 ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); 147 ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws);
@@ -273,8 +273,8 @@ make_new_session(
273 static const char iacs_to_send[] ALIGN1 = { 273 static const char iacs_to_send[] ALIGN1 = {
274 IAC, DO, TELOPT_ECHO, 274 IAC, DO, TELOPT_ECHO,
275 IAC, DO, TELOPT_NAWS, 275 IAC, DO, TELOPT_NAWS,
276 /* This requires telnetd.ctrlSQ.patch (incomplete) */ 276 /* This requires telnetd.ctrlSQ.patch (incomplete) */
277 /* IAC, DO, TELOPT_LFLOW, */ 277 /*IAC, DO, TELOPT_LFLOW,*/
278 IAC, WILL, TELOPT_ECHO, 278 IAC, WILL, TELOPT_ECHO,
279 IAC, WILL, TELOPT_SGA 279 IAC, WILL, TELOPT_SGA
280 }; 280 };
@@ -314,6 +314,8 @@ make_new_session(
314 /* Restore default signal handling ASAP */ 314 /* Restore default signal handling ASAP */
315 bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); 315 bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL);
316 316
317 pid = getpid();
318
317 if (ENABLE_FEATURE_UTMP) { 319 if (ENABLE_FEATURE_UTMP) {
318 len_and_sockaddr *lsa = get_peer_lsa(sock); 320 len_and_sockaddr *lsa = get_peer_lsa(sock);
319 char *hostname = NULL; 321 char *hostname = NULL;
@@ -335,7 +337,6 @@ make_new_session(
335 xopen(tty_name, O_RDWR); /* becomes our ctty */ 337 xopen(tty_name, O_RDWR); /* becomes our ctty */
336 xdup2(0, 1); 338 xdup2(0, 1);
337 xdup2(0, 2); 339 xdup2(0, 2);
338 pid = getpid();
339 tcsetpgrp(0, pid); /* switch this tty's process group to us */ 340 tcsetpgrp(0, pid); /* switch this tty's process group to us */
340 341
341 /* The pseudo-terminal allocated to the client is configured to operate 342 /* The pseudo-terminal allocated to the client is configured to operate
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 78aabedf2..7e5ab61fd 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -926,6 +926,10 @@ static void client_background(void)
926//usage: "\n -v Verbose" 926//usage: "\n -v Verbose"
927//usage: ) 927//usage: )
928//usage: ) 928//usage: )
929//usage: "\nSignals:"
930//usage: "\n USR1 Renew current lease"
931//usage: "\n USR2 Release current lease"
932
929 933
930int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 934int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
931int udhcpc_main(int argc UNUSED_PARAM, char **argv) 935int udhcpc_main(int argc UNUSED_PARAM, char **argv)
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index a015cf038..6fb48a19a 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -133,7 +133,10 @@ static uint32_t select_lease_time(struct dhcp_packet *packet)
133 133
134/* We got a DHCP DISCOVER. Send an OFFER. */ 134/* We got a DHCP DISCOVER. Send an OFFER. */
135/* NOINLINE: limit stack usage in caller */ 135/* NOINLINE: limit stack usage in caller */
136static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease) 136static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
137 uint32_t static_lease_nip,
138 struct dyn_lease *lease,
139 uint8_t *requested_ip_opt)
137{ 140{
138 struct dhcp_packet packet; 141 struct dhcp_packet packet;
139 uint32_t lease_time_sec; 142 uint32_t lease_time_sec;
@@ -147,7 +150,6 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_l
147 if (!static_lease_nip) { 150 if (!static_lease_nip) {
148 /* We have no static lease for client's chaddr */ 151 /* We have no static lease for client's chaddr */
149 uint32_t req_nip; 152 uint32_t req_nip;
150 uint8_t *req_ip_opt;
151 const char *p_host_name; 153 const char *p_host_name;
152 154
153 if (lease) { 155 if (lease) {
@@ -158,9 +160,9 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_l
158 packet.yiaddr = lease->lease_nip; 160 packet.yiaddr = lease->lease_nip;
159 } 161 }
160 /* Or: if client has requested an IP */ 162 /* Or: if client has requested an IP */
161 else if ((req_ip_opt = udhcp_get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL 163 else if (requested_ip_opt != NULL
162 /* (read IP) */ 164 /* (read IP) */
163 && (move_from_unaligned32(req_nip, req_ip_opt), 1) 165 && (move_from_unaligned32(req_nip, requested_ip_opt), 1)
164 /* and the IP is in the lease range */ 166 /* and the IP is in the lease range */
165 && ntohl(req_nip) >= server_config.start_ip 167 && ntohl(req_nip) >= server_config.start_ip
166 && ntohl(req_nip) <= server_config.end_ip 168 && ntohl(req_nip) <= server_config.end_ip
@@ -283,16 +285,12 @@ struct dyn_lease *g_leases;
283int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 285int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
284int udhcpd_main(int argc UNUSED_PARAM, char **argv) 286int udhcpd_main(int argc UNUSED_PARAM, char **argv)
285{ 287{
286 fd_set rfds;
287 int server_socket = -1, retval, max_sock; 288 int server_socket = -1, retval, max_sock;
288 struct dhcp_packet packet;
289 uint8_t *state; 289 uint8_t *state;
290 uint32_t static_lease_nip;
291 unsigned timeout_end; 290 unsigned timeout_end;
292 unsigned num_ips; 291 unsigned num_ips;
293 unsigned opt; 292 unsigned opt;
294 struct option_set *option; 293 struct option_set *option;
295 struct dyn_lease *lease, fake_lease;
296 IF_FEATURE_UDHCP_PORT(char *str_P;) 294 IF_FEATURE_UDHCP_PORT(char *str_P;)
297 295
298#if ENABLE_FEATURE_UDHCP_PORT 296#if ENABLE_FEATURE_UDHCP_PORT
@@ -372,11 +370,15 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
372 370
373 timeout_end = monotonic_sec() + server_config.auto_time; 371 timeout_end = monotonic_sec() + server_config.auto_time;
374 while (1) { /* loop until universe collapses */ 372 while (1) { /* loop until universe collapses */
373 fd_set rfds;
374 struct dhcp_packet packet;
375 int bytes; 375 int bytes;
376 struct timeval tv; 376 struct timeval tv;
377 uint8_t *server_id_opt; 377 uint8_t *server_id_opt;
378 uint8_t *requested_opt; 378 uint8_t *requested_ip_opt;
379 uint32_t requested_nip = requested_nip; /* for compiler */ 379 uint32_t requested_nip = requested_nip; /* for compiler */
380 uint32_t static_lease_nip;
381 struct dyn_lease *lease, fake_lease;
380 382
381 if (server_socket < 0) { 383 if (server_socket < 0) {
382 server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, 384 server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
@@ -443,6 +445,18 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
443 continue; 445 continue;
444 } 446 }
445 447
448 /* Get SERVER_ID if present */
449 server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID);
450 if (server_id_opt) {
451 uint32_t server_id_network_order;
452 move_from_unaligned32(server_id_network_order, server_id_opt);
453 if (server_id_network_order != server_config.server_nip) {
454 /* client talks to somebody else */
455 log1("server ID doesn't match, ignoring");
456 continue;
457 }
458 }
459
446 /* Look for a static/dynamic lease */ 460 /* Look for a static/dynamic lease */
447 static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr); 461 static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr);
448 if (static_lease_nip) { 462 if (static_lease_nip) {
@@ -455,20 +469,10 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
455 lease = find_lease_by_mac(packet.chaddr); 469 lease = find_lease_by_mac(packet.chaddr);
456 } 470 }
457 471
458 /* Get REQUESTED_IP and SERVER_ID if present */ 472 /* Get REQUESTED_IP if present */
459 server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID); 473 requested_ip_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP);
460 if (server_id_opt) { 474 if (requested_ip_opt) {
461 uint32_t server_id_net; 475 move_from_unaligned32(requested_nip, requested_ip_opt);
462 move_from_unaligned32(server_id_net, server_id_opt);
463 if (server_id_net != server_config.server_nip) {
464 /* client talks to somebody else */
465 log1("server ID doesn't match, ignoring");
466 continue;
467 }
468 }
469 requested_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP);
470 if (requested_opt) {
471 move_from_unaligned32(requested_nip, requested_opt);
472 } 476 }
473 477
474 switch (state[0]) { 478 switch (state[0]) {
@@ -476,7 +480,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
476 case DHCPDISCOVER: 480 case DHCPDISCOVER:
477 log1("Received DISCOVER"); 481 log1("Received DISCOVER");
478 482
479 send_offer(&packet, static_lease_nip, lease); 483 send_offer(&packet, static_lease_nip, lease, requested_ip_opt);
480 break; 484 break;
481 485
482 case DHCPREQUEST: 486 case DHCPREQUEST:
@@ -567,7 +571,7 @@ o DHCPREQUEST generated during REBINDING state:
567 A DHCP server MAY extend a client's lease only if it has local 571 A DHCP server MAY extend a client's lease only if it has local
568 administrative authority to do so. 572 administrative authority to do so.
569*/ 573*/
570 if (!requested_opt) { 574 if (!requested_ip_opt) {
571 requested_nip = packet.ciaddr; 575 requested_nip = packet.ciaddr;
572 if (requested_nip == 0) { 576 if (requested_nip == 0) {
573 log1("no requested IP and no ciaddr, ignoring"); 577 log1("no requested IP and no ciaddr, ignoring");
@@ -580,11 +584,15 @@ o DHCPREQUEST generated during REBINDING state:
580 send_ACK(&packet, lease->lease_nip); 584 send_ACK(&packet, lease->lease_nip);
581 break; 585 break;
582 } 586 }
583 if (server_id_opt) { 587 /* No lease for this MAC, or lease IP != requested IP */
584 /* client was talking specifically to us. 588
585 * "No, we don't have this IP for you". */ 589 if (server_id_opt /* client is in SELECTING state */
590 || requested_ip_opt /* client is in INIT-REBOOT state */
591 ) {
592 /* "No, we don't have this IP for you" */
586 send_NAK(&packet); 593 send_NAK(&packet);
587 } 594 } /* else: client is in RENEWING or REBINDING, do not answer */
595
588 break; 596 break;
589 597
590 case DHCPDECLINE: 598 case DHCPDECLINE:
@@ -603,7 +611,7 @@ o DHCPREQUEST generated during REBINDING state:
603 */ 611 */
604 log1("Received DECLINE"); 612 log1("Received DECLINE");
605 if (server_id_opt 613 if (server_id_opt
606 && requested_opt 614 && requested_ip_opt
607 && lease /* chaddr matches this lease */ 615 && lease /* chaddr matches this lease */
608 && requested_nip == lease->lease_nip 616 && requested_nip == lease->lease_nip
609 ) { 617 ) {
diff --git a/networking/vconfig.c b/networking/vconfig.c
index 1f574d2ad..13c65ad78 100644
--- a/networking/vconfig.c
+++ b/networking/vconfig.c
@@ -47,8 +47,8 @@ struct vlan_ioctl_args {
47 short vlan_qos; 47 short vlan_qos;
48}; 48};
49 49
50#define VLAN_GROUP_ARRAY_LEN 4096 50#define VLAN_GROUP_ARRAY_LEN 4096
51#define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */ 51#define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */
52 52
53/* On entry, table points to the length of the current string 53/* On entry, table points to the length of the current string
54 * plus NUL terminator plus data length for the subsequent entry. 54 * plus NUL terminator plus data length for the subsequent entry.
diff --git a/networking/wget.c b/networking/wget.c
index 5b0907e11..16594c9bf 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -6,7 +6,7 @@
6 * Licensed under GPLv2, see file LICENSE in this source tree. 6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 * 7 *
8 * Copyright (C) 2010 Bradley M. Kuhn <bkuhn@ebb.org> 8 * Copyright (C) 2010 Bradley M. Kuhn <bkuhn@ebb.org>
9 * Kuhn's copyrights are licensed GPLv2-or-later. File as a whole remains GPLv2. 9 * Kuhn's copyrights are licensed GPLv2-or-later. File as a whole remains GPLv2.
10 */ 10 */
11#include "libbb.h" 11#include "libbb.h"
12 12
@@ -48,7 +48,7 @@ struct BUG_G_too_big {
48/* Must match option string! */ 48/* Must match option string! */
49enum { 49enum {
50 WGET_OPT_CONTINUE = (1 << 0), 50 WGET_OPT_CONTINUE = (1 << 0),
51 WGET_OPT_SPIDER = (1 << 1), 51 WGET_OPT_SPIDER = (1 << 1),
52 WGET_OPT_QUIET = (1 << 2), 52 WGET_OPT_QUIET = (1 << 2),
53 WGET_OPT_OUTNAME = (1 << 3), 53 WGET_OPT_OUTNAME = (1 << 3),
54 WGET_OPT_PREFIX = (1 << 4), 54 WGET_OPT_PREFIX = (1 << 4),
@@ -786,7 +786,7 @@ However, in real world it was observed that some web servers
786*/ 786*/
787 case 204: 787 case 204:
788 break; 788 break;
789 case 300: /* redirection */ 789 case 300: /* redirection */
790 case 301: 790 case 301:
791 case 302: 791 case 302:
792 case 303: 792 case 303:
diff --git a/procps/Config.src b/procps/Config.src
index 1ff6dfd30..cf664eeb2 100644
--- a/procps/Config.src
+++ b/procps/Config.src
@@ -46,12 +46,6 @@ config KILLALL5
46 default y 46 default y
47 depends on KILL 47 depends on KILL
48 48
49config NMETER
50 bool "nmeter"
51 default y
52 help
53 Prints selected system stats continuously, one line per update.
54
55config PGREP 49config PGREP
56 bool "pgrep" 50 bool "pgrep"
57 default y 51 default y
@@ -192,11 +186,12 @@ config FEATURE_TOPMEM
192 Enable 's' in top (gives lots of memory info). 186 Enable 's' in top (gives lots of memory info).
193 187
194config FEATURE_SHOW_THREADS 188config FEATURE_SHOW_THREADS
195 bool "Support for showing threads in ps/top" 189 bool "Support for showing threads in ps/pstree/top"
196 default y 190 default y
197 depends on PS || TOP 191 depends on PS || TOP || PSTREE
198 help 192 help
199 Enables ps -T option and 'h' command in top 193 Enables the ps -T option, showing of threads in pstree,
194 and 'h' command in top.
200 195
201config UPTIME 196config UPTIME
202 bool "uptime" 197 bool "uptime"
diff --git a/procps/Kbuild.src b/procps/Kbuild.src
index 791d65670..89b1cc094 100644
--- a/procps/Kbuild.src
+++ b/procps/Kbuild.src
@@ -11,7 +11,6 @@ lib-$(CONFIG_FREE) += free.o
11lib-$(CONFIG_FUSER) += fuser.o 11lib-$(CONFIG_FUSER) += fuser.o
12lib-$(CONFIG_KILL) += kill.o 12lib-$(CONFIG_KILL) += kill.o
13lib-$(CONFIG_ASH) += kill.o # used for built-in kill by ash 13lib-$(CONFIG_ASH) += kill.o # used for built-in kill by ash
14lib-$(CONFIG_NMETER) += nmeter.o
15lib-$(CONFIG_PGREP) += pgrep.o 14lib-$(CONFIG_PGREP) += pgrep.o
16lib-$(CONFIG_PKILL) += pgrep.o 15lib-$(CONFIG_PKILL) += pgrep.o
17lib-$(CONFIG_PIDOF) += pidof.o 16lib-$(CONFIG_PIDOF) += pidof.o
diff --git a/procps/iostat.c b/procps/iostat.c
index 5d829861e..a9ff13a05 100644
--- a/procps/iostat.c
+++ b/procps/iostat.c
@@ -18,14 +18,14 @@
18//config: Report CPU and I/O statistics 18//config: Report CPU and I/O statistics
19 19
20#include "libbb.h" 20#include "libbb.h"
21#include <sys/utsname.h> /* Need struct utsname */ 21#include <sys/utsname.h> /* Need struct utsname */
22 22
23//#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) 23//#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
24#define debug(fmt, ...) ((void)0) 24#define debug(fmt, ...) ((void)0)
25 25
26#define MAX_DEVICE_NAME 12 26#define MAX_DEVICE_NAME 12
27#define CURRENT 0 27#define CURRENT 0
28#define LAST 1 28#define LAST 1
29 29
30#if 1 30#if 1
31typedef unsigned long long cputime_t; 31typedef unsigned long long cputime_t;
@@ -327,7 +327,7 @@ static void do_disk_statistics(cputime_t itv)
327 int i = 0; 327 int i = 0;
328 char buf[128]; 328 char buf[128];
329 unsigned major, minor; 329 unsigned major, minor;
330 unsigned long wr_ops, dummy; /* %*lu for suppres the conversion wouldn't work */ 330 unsigned long wr_ops, dummy; /* %*lu for suppress the conversion wouldn't work */
331 unsigned long long rd_sec_or_wr_ops; 331 unsigned long long rd_sec_or_wr_ops;
332 unsigned long long rd_sec_or_dummy, wr_sec_or_dummy, wr_sec; 332 unsigned long long rd_sec_or_dummy, wr_sec_or_dummy, wr_sec;
333 struct stats_dev sd; 333 struct stats_dev sd;
diff --git a/procps/mpstat.c b/procps/mpstat.c
index f1a0b00b8..25efedf62 100644
--- a/procps/mpstat.c
+++ b/procps/mpstat.c
@@ -18,7 +18,7 @@
18//config: Per-processor statistics 18//config: Per-processor statistics
19 19
20#include "libbb.h" 20#include "libbb.h"
21#include <sys/utsname.h> /* struct utsname */ 21#include <sys/utsname.h> /* struct utsname */
22 22
23//#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) 23//#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
24#define debug(fmt, ...) ((void)0) 24#define debug(fmt, ...) ((void)0)
@@ -634,7 +634,7 @@ static void get_irqs_from_interrupts(const char *fname,
634 while (irq < irqs_per_cpu) { 634 while (irq < irqs_per_cpu) {
635 /* Number of interrupts per CPU has changed */ 635 /* Number of interrupts per CPU has changed */
636 ic = &per_cpu_stats[current][irq]; 636 ic = &per_cpu_stats[current][irq];
637 ic->irq_name[0] = '\0'; /* False interrupt */ 637 ic->irq_name[0] = '\0'; /* False interrupt */
638 irq++; 638 irq++;
639 } 639 }
640} 640}
@@ -820,7 +820,7 @@ static int get_irqcpu_nr(const char *f, int max_irqs)
820 unsigned irq; 820 unsigned irq;
821 821
822 fp = fopen_for_read(f); 822 fp = fopen_for_read(f);
823 if (!fp) /* No interrupts file */ 823 if (!fp) /* No interrupts file */
824 return 0; 824 return 0;
825 825
826 linelen = INTERRUPTS_LINE + 16 * G.cpu_nr; 826 linelen = INTERRUPTS_LINE + 16 * G.cpu_nr;
@@ -858,10 +858,10 @@ int mpstat_main(int UNUSED_PARAM argc, char **argv)
858 char *opt_set_cpu; 858 char *opt_set_cpu;
859 int i, opt; 859 int i, opt;
860 enum { 860 enum {
861 OPT_ALL = 1 << 0, /* -A */ 861 OPT_ALL = 1 << 0, /* -A */
862 OPT_INTS = 1 << 1, /* -I */ 862 OPT_INTS = 1 << 1, /* -I */
863 OPT_SETCPU = 1 << 2, /* -P */ 863 OPT_SETCPU = 1 << 2, /* -P */
864 OPT_UTIL = 1 << 3, /* -u */ 864 OPT_UTIL = 1 << 3, /* -u */
865 }; 865 };
866 866
867 /* Dont buffer data if redirected to a pipe */ 867 /* Dont buffer data if redirected to a pipe */
diff --git a/procps/nmeter.c b/procps/nmeter.c
index 7836a90d5..ac019eb53 100644
--- a/procps/nmeter.c
+++ b/procps/nmeter.c
@@ -6,6 +6,40 @@
6 * Contact me: vda.linux@googlemail.com 6 * Contact me: vda.linux@googlemail.com
7 */ 7 */
8 8
9//config:config NMETER
10//config: bool "nmeter"
11//config: default y
12//config: help
13//config: Prints selected system stats continuously, one line per update.
14
15//applet:IF_NMETER(APPLET(nmeter, _BB_DIR_USR_BIN, _BB_SUID_DROP))
16
17//kbuild:lib-$(CONFIG_NMETER) += nmeter.o
18
19//usage:#define nmeter_trivial_usage
20//usage: "[-d MSEC] FORMAT_STRING"
21//usage:#define nmeter_full_usage "\n\n"
22//usage: "Monitor system in real time"
23//usage: "\n"
24//usage: "\n -d MSEC Milliseconds between updates (default:1000)"
25//usage: "\n"
26//usage: "\nFormat specifiers:"
27//usage: "\n %Nc or %[cN] Monitor CPU. N - bar size (default:10)"
28//usage: "\n (displays: S:system U:user N:niced D:iowait I:irq i:softirq)"
29//usage: "\n %[niface] Monitor network interface 'iface'"
30//usage: "\n %m Monitor allocated memory"
31//usage: "\n %[mf] Monitor free memory"
32//usage: "\n %[mt] Monitor total memory"
33//usage: "\n %s Monitor allocated swap"
34//usage: "\n %f Monitor number of used file descriptors"
35//usage: "\n %Ni Monitor total/specific IRQ rate"
36//usage: "\n %x Monitor context switch rate"
37//usage: "\n %p Monitor forks"
38//usage: "\n %[pn] Monitor # of processes"
39//usage: "\n %b Monitor block io"
40//usage: "\n %Nt Show time (with N decimal points)"
41//usage: "\n %r Print <cr> instead of <lf> at EOL"
42
9//TODO: 43//TODO:
10// simplify code 44// simplify code
11// /proc/locks 45// /proc/locks
@@ -769,6 +803,7 @@ static void FAST_FUNC collect_info(s_stat *s)
769 803
770typedef s_stat* init_func(const char *param); 804typedef s_stat* init_func(const char *param);
771 805
806// Deprecated %NNNd is to be removed, -d MSEC supersedes it
772static const char options[] ALIGN1 = "ncmsfixptbdr"; 807static const char options[] ALIGN1 = "ncmsfixptbdr";
773static init_func *const init_functions[] = { 808static init_func *const init_functions[] = {
774 init_if, 809 init_if,
@@ -792,23 +827,28 @@ int nmeter_main(int argc UNUSED_PARAM, char **argv)
792 s_stat *first = NULL; 827 s_stat *first = NULL;
793 s_stat *last = NULL; 828 s_stat *last = NULL;
794 s_stat *s; 829 s_stat *s;
830 char *opt_d;
795 char *cur, *prev; 831 char *cur, *prev;
796 832
797 INIT_G(); 833 INIT_G();
798 834
799 xchdir("/proc"); 835 xchdir("/proc");
800 836
801 if (!argv[1])
802 bb_show_usage();
803
804 if (open_read_close("version", buf, sizeof(buf)-1) > 0) { 837 if (open_read_close("version", buf, sizeof(buf)-1) > 0) {
805 buf[sizeof(buf)-1] = '\0'; 838 buf[sizeof(buf)-1] = '\0';
806 is26 = (strstr(buf, " 2.4.") == NULL); 839 is26 = (strstr(buf, " 2.4.") == NULL);
807 } 840 }
808 841
809 // Can use argv[1] directly, but this will mess up 842 if (getopt32(argv, "d:", &opt_d))
843 init_delay(opt_d);
844 argv += optind;
845
846 if (!argv[0])
847 bb_show_usage();
848
849 // Can use argv[0] directly, but this will mess up
810 // parameters as seen by e.g. ps. Making a copy... 850 // parameters as seen by e.g. ps. Making a copy...
811 cur = xstrdup(argv[1]); 851 cur = xstrdup(argv[0]);
812 while (1) { 852 while (1) {
813 char *param, *p; 853 char *param, *p;
814 prev = cur; 854 prev = cur;
diff --git a/procps/powertop.c b/procps/powertop.c
index 250da817b..2f977a03b 100644
--- a/procps/powertop.c
+++ b/procps/powertop.c
@@ -169,7 +169,7 @@ static void read_cstate_counts(ullong *usage, ullong *duration)
169 if (len < 3 || len > BIG_SYSNAME_LEN) 169 if (len < 3 || len > BIG_SYSNAME_LEN)
170 continue; 170 continue;
171 171
172 sprintf(buf, "/proc/acpi/processor/%s/power", d->d_name); 172 sprintf(buf, "%s/%s/power", "/proc/acpi/processor", d->d_name);
173 fp = fopen_for_read(buf); 173 fp = fopen_for_read(buf);
174 if (!fp) 174 if (!fp)
175 continue; 175 continue;
@@ -321,31 +321,18 @@ static void process_irq_counts(void)
321 /* 0: 143646045 153901007 IO-APIC-edge timer 321 /* 0: 143646045 153901007 IO-APIC-edge timer
322 * ^ 322 * ^
323 */ 323 */
324 *p = '\0';
324 /* Deal with non-maskable interrupts -- make up fake numbers */ 325 /* Deal with non-maskable interrupts -- make up fake numbers */
325 nr = -1; 326 nr = index_in_strings("NMI\0RES\0CAL\0TLB\0TRM\0THR\0SPU\0", buf);
326 if (buf[0] != ' ' && !isdigit(buf[0])) { 327 if (nr >= 0) {
327//TODO: optimize 328 nr += 20000;
328 if (strncmp(buf, "NMI:", 4) == 0)
329 nr = 20000;
330 if (strncmp(buf, "RES:", 4) == 0)
331 nr = 20001;
332 if (strncmp(buf, "CAL:", 4) == 0)
333 nr = 20002;
334 if (strncmp(buf, "TLB:", 4) == 0)
335 nr = 20003;
336 if (strncmp(buf, "TRM:", 4) == 0)
337 nr = 20004;
338 if (strncmp(buf, "THR:", 4) == 0)
339 nr = 20005;
340 if (strncmp(buf, "SPU:", 4) == 0)
341 nr = 20006;
342 } else { 329 } else {
343 /* bb_strtou doesn't eat leading spaces, using strtoul */ 330 /* bb_strtou doesn't eat leading spaces, using strtoul */
331 errno = 0;
344 nr = strtoul(buf, NULL, 10); 332 nr = strtoul(buf, NULL, 10);
333 if (errno)
334 continue;
345 } 335 }
346 if (nr == -1)
347 continue;
348
349 p++; 336 p++;
350 /* 0: 143646045 153901007 IO-APIC-edge timer 337 /* 0: 143646045 153901007 IO-APIC-edge timer
351 * ^ 338 * ^
@@ -412,6 +399,7 @@ static NOINLINE int process_timer_stats(void)
412 buf[0] = '\0'; 399 buf[0] = '\0';
413 totalticks = 0; 400 totalticks = 0;
414 401
402 n = 0;
415 fp = NULL; 403 fp = NULL;
416 if (!G.cant_enable_timer_stats) 404 if (!G.cant_enable_timer_stats)
417 fp = fopen_for_read("/proc/timer_stats"); 405 fp = fopen_for_read("/proc/timer_stats");
@@ -430,33 +418,41 @@ static NOINLINE int process_timer_stats(void)
430 while (fgets(buf, sizeof(buf), fp)) { 418 while (fgets(buf, sizeof(buf), fp)) {
431 const char *count, *process, *func; 419 const char *count, *process, *func;
432 char *p; 420 char *p;
433 int cnt; 421 int idx;
422 unsigned cnt;
434 423
435 count = skip_whitespace(buf); 424 count = skip_whitespace(buf);
436 p = strchr(count, ','); 425 p = strchr(count, ',');
437 if (!p) 426 if (!p)
438 continue; 427 continue;
439 *p++ = '\0'; 428 *p++ = '\0';
440 if (strcmp(strchrnul(count, ' '), " total events") == 0) 429 cnt = bb_strtou(count, NULL, 10);
430 if (strcmp(skip_non_whitespace(count), " total events") == 0) {
431#if ENABLE_FEATURE_POWERTOP_PROCIRQ
432 n = cnt / G.total_cpus;
433 if (n > 0 && n < G.interrupt_0) {
434 sprintf(line, " <interrupt> : %s", "extra timer interrupt");
435 save_line(line, G.interrupt_0 - n);
436 }
437#endif
441 break; 438 break;
442 p = skip_whitespace(p); /* points to pid */ 439 }
443 440 if (strchr(count, 'D'))
444/* Find char ' ', then eat remaining spaces */ 441 continue; /* deferred */
445#define ADVANCE(p) do { \ 442 p = skip_whitespace(p); /* points to pid now */
446 (p) = strchr((p), ' '); \ 443 process = NULL;
447 if (!(p)) \ 444 get_func_name:
448 continue; \ 445 p = strchr(p, ' ');
449 *(p) = '\0'; \ 446 if (!p)
450 (p)++; \ 447 continue;
451 (p) = skip_whitespace(p); \ 448 *p++ = '\0';
452} while (0) 449 p = skip_whitespace(p);
453 /* Get process name */ 450 if (process == NULL) {
454 ADVANCE(p); 451 process = p;
455 process = p; 452 goto get_func_name;
456 /* Get function */ 453 }
457 ADVANCE(p);
458 func = p; 454 func = p;
459#undef ADVANCE 455
460 //if (strcmp(process, "swapper") == 0 456 //if (strcmp(process, "swapper") == 0
461 // && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0 457 // && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0
462 //) { 458 //) {
@@ -471,45 +467,26 @@ static NOINLINE int process_timer_stats(void)
471 //if (strcmp(process, "powertop") == 0) 467 //if (strcmp(process, "powertop") == 0)
472 // continue; 468 // continue;
473 469
474 if (strcmp(process, "insmod") == 0) 470 idx = index_in_strings("insmod\0modprobe\0swapper\0", process);
475 process = "[kernel module]"; 471 if (idx != -1) {
476 if (strcmp(process, "modprobe") == 0) 472 process = idx < 2 ? "[kernel module]" : "<kernel core>";
477 process = "[kernel module]"; 473 }
478 if (strcmp(process, "swapper") == 0)
479 process = "<kernel core>";
480 474
481 strchrnul(p, '\n')[0] = '\0'; 475 strchrnul(p, '\n')[0] = '\0';
482 476
483 { 477 // 46D\01136\0kondemand/1\0do_dbs_timer (delayed_work_timer_fn)
484 char *tmp; 478 // ^ ^ ^
485 cnt = bb_strtoull(count, &tmp, 10); 479 // count process func
486 p = tmp;
487 }
488 while (*p != '\0') {
489 if (*p++ == 'D') /* deferred */
490 goto skip;
491 }
492 480
493 //if (strchr(process, '[')) 481 //if (strchr(process, '['))
494 sprintf(line, "%15.15s : %s", process, func); 482 sprintf(line, "%15.15s : %s", process, func);
495 //else 483 //else
496 // sprintf(line, "%s", process); 484 // sprintf(line, "%s", process);
497 save_line(line, cnt); 485 save_line(line, cnt);
498 skip: ;
499 } 486 }
500 fclose(fp); 487 fclose(fp);
501 } 488 }
502 489
503 n = 0;
504#if ENABLE_FEATURE_POWERTOP_PROCIRQ
505 if (strstr(buf, "total events")) {
506 n = bb_strtoull(buf, NULL, 10) / G.total_cpus;
507 if (n > 0 && n < G.interrupt_0) {
508 sprintf(line, " <interrupt> : %s", "extra timer interrupt");
509 save_line(line, G.interrupt_0 - n);
510 }
511 }
512#endif
513 return n; 490 return n;
514} 491}
515 492
@@ -566,7 +543,7 @@ static NOINLINE void print_intel_cstates(void)
566 if (!isdigit(d->d_name[3])) 543 if (!isdigit(d->d_name[3]))
567 continue; 544 continue;
568 545
569 len = sprintf(fname, "/sys/devices/system/cpu/%s/cpuidle", d->d_name); 546 len = sprintf(fname, "%s/%s/cpuidle", "/sys/devices/system/cpu", d->d_name);
570 dir = opendir(fname); 547 dir = opendir(fname);
571 if (!dir) 548 if (!dir)
572 continue; 549 continue;
@@ -635,7 +612,7 @@ static NOINLINE void print_intel_cstates(void)
635 bb_putchar('\n'); 612 bb_putchar('\n');
636} 613}
637#else 614#else
638# define print_intel_cstates(void) ((void)0) 615# define print_intel_cstates() ((void)0)
639#endif 616#endif
640 617
641static void show_timerstats(void) 618static void show_timerstats(void)
diff --git a/procps/pstree.c b/procps/pstree.c
new file mode 100644
index 000000000..180d0939a
--- /dev/null
+++ b/procps/pstree.c
@@ -0,0 +1,406 @@
1/*
2 * pstree.c - display process tree
3 *
4 * Copyright (C) 1993-2002 Werner Almesberger
5 * Copyright (C) 2002-2009 Craig Small
6 * Copyright (C) 2010 Lauri Kasanen
7 *
8 * Based on pstree (PSmisc) 22.13.
9 *
10 * Licensed under GPLv2, see file LICENSE in this source tree.
11 */
12
13//config:config PSTREE
14//config: bool "pstree"
15//config: default y
16//config: help
17//config: Display a tree of processes.
18
19//applet:IF_PSTREE(APPLET(pstree, _BB_DIR_USR_BIN, _BB_SUID_DROP))
20
21//kbuild:lib-$(CONFIG_PSTREE) += pstree.o
22
23//usage:#define pstree_trivial_usage
24//usage: "[-p] [PID|USER]"
25//usage:#define pstree_full_usage "\n\n"
26//usage: "Display process tree, optionally start from USER or PID\n"
27//usage: "\nOptions:"
28//usage: "\n -p Show pids"
29
30#include "libbb.h"
31
32#define PROC_BASE "/proc"
33
34#define OPT_PID (1 << 0)
35
36struct child;
37
38typedef struct proc {
39 char comm[COMM_LEN + 1];
40// char flags; - unused, delete?
41 pid_t pid;
42 uid_t uid;
43 struct child *children;
44 struct proc *parent;
45 struct proc *next;
46} PROC;
47
48/* For flags above */
49//#define PFLAG_THREAD 0x01
50
51typedef struct child {
52 PROC *child;
53 struct child *next;
54} CHILD;
55
56#define empty_2 " "
57#define branch_2 "|-"
58#define vert_2 "| "
59#define last_2 "`-"
60#define single_3 "---"
61#define first_3 "-+-"
62
63struct globals {
64 /* 0-based. IOW: the number of chars we printed on current line */
65 unsigned cur_x;
66 unsigned output_width;
67
68 /* The buffers will be dynamically increased in size as needed */
69 unsigned capacity;
70 unsigned *width;
71 uint8_t *more;
72
73 PROC *list;
74
75 smallint dumped; /* used by dump_by_user */
76};
77#define G (*ptr_to_globals)
78#define INIT_G() do { \
79 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
80} while (0)
81
82
83/*
84 * Allocates additional buffer space for width and more as needed.
85 * The first call will allocate the first buffer.
86 *
87 * bufindex the index that will be used after the call to this function.
88 */
89static void ensure_buffer_capacity(int bufindex)
90{
91 if (bufindex >= G.capacity) {
92 G.capacity += 0x100;
93 G.width = xrealloc(G.width, G.capacity * sizeof(G.width[0]));
94 G.more = xrealloc(G.more, G.capacity * sizeof(G.more[0]));
95 }
96}
97
98/* NB: this function is never called with "bad" chars
99 * (control chars or chars >= 0x7f)
100 */
101static void out_char(char c)
102{
103 G.cur_x++;
104 if (G.cur_x > G.output_width)
105 return;
106 if (G.cur_x == G.output_width)
107 c = '+';
108 putchar(c);
109}
110
111/* NB: this function is never called with "bad" chars
112 * (control chars or chars >= 0x7f)
113 */
114static void out_string(const char *str)
115{
116 while (*str)
117 out_char(*str++);
118}
119
120static void out_newline(void)
121{
122 putchar('\n');
123 G.cur_x = 0;
124}
125
126static PROC *find_proc(pid_t pid)
127{
128 PROC *walk;
129
130 for (walk = G.list; walk; walk = walk->next)
131 if (walk->pid == pid)
132 break;
133
134 return walk;
135}
136
137static PROC *new_proc(const char *comm, pid_t pid, uid_t uid)
138{
139 PROC *new = xzalloc(sizeof(*new));
140
141 strcpy(new->comm, comm);
142 new->pid = pid;
143 new->uid = uid;
144 new->next = G.list;
145
146 G.list = new;
147 return G.list;
148}
149
150static void add_child(PROC *parent, PROC *child)
151{
152 CHILD *new, **walk;
153 int cmp;
154
155 new = xmalloc(sizeof(*new));
156
157 new->child = child;
158 for (walk = &parent->children; *walk; walk = &(*walk)->next) {
159 cmp = strcmp((*walk)->child->comm, child->comm);
160 if (cmp > 0)
161 break;
162 if (cmp == 0 && (*walk)->child->uid > child->uid)
163 break;
164 }
165 new->next = *walk;
166 *walk = new;
167}
168
169static void add_proc(const char *comm, pid_t pid, pid_t ppid,
170 uid_t uid /*, char isthread*/)
171{
172 PROC *this, *parent;
173
174 this = find_proc(pid);
175 if (!this)
176 this = new_proc(comm, pid, uid);
177 else {
178 strcpy(this->comm, comm);
179 this->uid = uid;
180 }
181
182 if (pid == ppid)
183 ppid = 0;
184// if (isthread)
185// this->flags |= PFLAG_THREAD;
186
187 parent = find_proc(ppid);
188 if (!parent)
189 parent = new_proc("?", ppid, 0);
190
191 add_child(parent, this);
192 this->parent = parent;
193}
194
195static int tree_equal(const PROC *a, const PROC *b)
196{
197 const CHILD *walk_a, *walk_b;
198
199 if (strcmp(a->comm, b->comm) != 0)
200 return 0;
201 if ((option_mask32 /*& OPT_PID*/) && a->pid != b->pid)
202 return 0;
203
204 for (walk_a = a->children, walk_b = b->children;
205 walk_a && walk_b;
206 walk_a = walk_a->next, walk_b = walk_b->next
207 ) {
208 if (!tree_equal(walk_a->child, walk_b->child))
209 return 0;
210 }
211
212 return !(walk_a || walk_b);
213}
214
215static int out_args(const char *mystr)
216{
217 const char *here;
218 int strcount = 0;
219 char tmpstr[5];
220
221 for (here = mystr; *here; here++) {
222 if (*here == '\\') {
223 out_string("\\\\");
224 strcount += 2;
225 } else if (*here >= ' ' && *here < 0x7f) {
226 out_char(*here);
227 strcount++;
228 } else {
229 sprintf(tmpstr, "\\%03o", (unsigned char) *here);
230 out_string(tmpstr);
231 strcount += 4;
232 }
233 }
234
235 return strcount;
236}
237
238static void
239dump_tree(PROC *current, int level, int rep, int leaf, int last, int closing)
240{
241 CHILD *walk, *next, **scan;
242 int lvl, i, add, offset, count, comm_len, first;
243 char tmp[sizeof(int)*3 + 4];
244
245 if (!current)
246 return;
247
248 if (!leaf) {
249 for (lvl = 0; lvl < level; lvl++) {
250 i = G.width[lvl] + 1;
251 while (--i >= 0)
252 out_char(' ');
253
254 if (lvl == level - 1) {
255 if (last) {
256 out_string(last_2);
257 } else {
258 out_string(branch_2);
259 }
260 } else {
261 if (G.more[lvl + 1]) {
262 out_string(vert_2);
263 } else {
264 out_string(empty_2);
265 }
266 }
267 }
268 }
269
270 add = 0;
271 if (rep > 1) {
272 add += sprintf(tmp, "%d*[", rep);
273 out_string(tmp);
274 }
275 comm_len = out_args(current->comm);
276 if (option_mask32 /*& OPT_PID*/) {
277 comm_len += sprintf(tmp, "(%d)", (int)current->pid);
278 out_string(tmp);
279 }
280 offset = G.cur_x;
281
282 if (!current->children) {
283 while (closing--)
284 out_char(']');
285 out_newline();
286 }
287 ensure_buffer_capacity(level);
288 G.more[level] = !last;
289
290 G.width[level] = comm_len + G.cur_x - offset + add;
291 if (G.cur_x >= G.output_width) {
292 //out_string(first_3); - why? it won't print anything
293 //out_char('+');
294 out_newline();
295 return;
296 }
297
298 first = 1;
299 for (walk = current->children; walk; walk = next) {
300 count = 0;
301 next = walk->next;
302 scan = &walk->next;
303 while (*scan) {
304 if (!tree_equal(walk->child, (*scan)->child))
305 scan = &(*scan)->next;
306 else {
307 if (next == *scan)
308 next = (*scan)->next;
309 count++;
310 *scan = (*scan)->next;
311 }
312 }
313 if (first) {
314 out_string(next ? first_3 : single_3);
315 first = 0;
316 }
317
318 dump_tree(walk->child, level + 1, count + 1,
319 walk == current->children, !next,
320 closing + (count ? 1 : 0));
321 }
322}
323
324static void dump_by_user(PROC *current, uid_t uid)
325{
326 const CHILD *walk;
327
328 if (!current)
329 return;
330
331 if (current->uid == uid) {
332 if (G.dumped)
333 putchar('\n');
334 dump_tree(current, 0, 1, 1, 1, 0);
335 G.dumped = 1;
336 return;
337 }
338 for (walk = current->children; walk; walk = walk->next)
339 dump_by_user(walk->child, uid);
340}
341
342static void handle_thread(const char *comm, pid_t pid, pid_t ppid, uid_t uid)
343{
344 char threadname[COMM_LEN + 2];
345 sprintf(threadname, "{%.*s}", COMM_LEN - 2, comm);
346 add_proc(threadname, pid, ppid, uid/*, 1*/);
347}
348
349static void mread_proc(void)
350{
351 procps_status_t *p = NULL;
352 pid_t parent = 0;
353 int flags = PSSCAN_COMM | PSSCAN_PID | PSSCAN_PPID | PSSCAN_UIDGID | PSSCAN_TASKS;
354
355 while ((p = procps_scan(p, flags)) != NULL) {
356#if ENABLE_FEATURE_SHOW_THREADS
357 if (p->pid != p->main_thread_pid)
358 handle_thread(p->comm, p->pid, parent, p->uid);
359 else
360#endif
361 {
362 add_proc(p->comm, p->pid, p->ppid, p->uid/*, 0*/);
363 parent = p->pid;
364 }
365 }
366}
367
368int pstree_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
369int pstree_main(int argc UNUSED_PARAM, char **argv)
370{
371 pid_t pid = 1;
372 long uid = 0;
373
374 INIT_G();
375
376 get_terminal_width_height(0, &G.output_width, NULL);
377
378 opt_complementary = "?1";
379 getopt32(argv, "p");
380 argv += optind;
381
382 if (argv[0]) {
383 if (argv[0][0] >= '0' && argv[0][0] <= '9') {
384 pid = xatoi(argv[0]);
385 } else {
386 uid = xuname2uid(argv[0]);
387 }
388 }
389
390 mread_proc();
391
392 if (!uid)
393 dump_tree(find_proc(pid), 0, 1, 1, 1, 0);
394 else {
395 dump_by_user(find_proc(1), uid);
396 if (!G.dumped) {
397 bb_error_msg_and_die("no processes found");
398 }
399 }
400
401 if (ENABLE_FEATURE_CLEAN_UP) {
402 free(G.width);
403 free(G.more);
404 }
405 return 0;
406}
diff --git a/procps/smemcap.c b/procps/smemcap.c
index 196c91f54..200df6795 100644
--- a/procps/smemcap.c
+++ b/procps/smemcap.c
@@ -20,7 +20,7 @@
20//config: a memory usage statistic tool. 20//config: a memory usage statistic tool.
21 21
22#include "libbb.h" 22#include "libbb.h"
23#include "unarchive.h" 23#include "archive.h"
24 24
25struct fileblock { 25struct fileblock {
26 struct fileblock *next; 26 struct fileblock *next;
diff --git a/procps/sysctl.c b/procps/sysctl.c
index 20b372c54..aba966e7f 100644
--- a/procps/sysctl.c
+++ b/procps/sysctl.c
@@ -91,7 +91,7 @@ static int sysctl_act_on_setting(char *setting)
91 retval = EXIT_FAILURE; 91 retval = EXIT_FAILURE;
92 goto end; 92 goto end;
93 } 93 }
94 value = cptr + 1; /* point to the value in name=value */ 94 value = cptr + 1; /* point to the value in name=value */
95 if (setting == cptr || !*value) { 95 if (setting == cptr || !*value) {
96 bb_error_msg("error: malformed setting '%s'", outname); 96 bb_error_msg("error: malformed setting '%s'", outname);
97 retval = EXIT_FAILURE; 97 retval = EXIT_FAILURE;
diff --git a/runit/runsvdir.c b/runit/runsvdir.c
index e77eeff04..166664237 100644
--- a/runit/runsvdir.c
+++ b/runit/runsvdir.c
@@ -312,8 +312,11 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv)
312 last_mtime = s.st_mtime; 312 last_mtime = s.st_mtime;
313 last_dev = s.st_dev; 313 last_dev = s.st_dev;
314 last_ino = s.st_ino; 314 last_ino = s.st_ino;
315 //if (now <= mtime) 315 /* if the svdir changed this very second, wait until the
316 // sleep(1); 316 * next second, because we won't be able to detect more
317 * changes within this second */
318 while (time(NULL) == last_mtime)
319 usleep(100000);
317 need_rescan = do_rescan(); 320 need_rescan = do_rescan();
318 while (fchdir(curdir) == -1) { 321 while (fchdir(curdir) == -1) {
319 warn2_cannot("change directory, pausing", ""); 322 warn2_cannot("change directory, pausing", "");
diff --git a/scripts/Makefile.IMA b/scripts/Makefile.IMA
index 11ae39eae..a62618ae0 100644
--- a/scripts/Makefile.IMA
+++ b/scripts/Makefile.IMA
@@ -85,8 +85,8 @@ lib-y:=
85include archival/Kbuild 85include archival/Kbuild
86lib-all-y += $(patsubst %,archival/%,$(sort $(lib-y))) 86lib-all-y += $(patsubst %,archival/%,$(sort $(lib-y)))
87lib-y:= 87lib-y:=
88include archival/libunarchive/Kbuild 88include archival/libarchive/Kbuild
89lib-all-y += $(patsubst %,archival/libunarchive/%,$(sort $(lib-y))) 89lib-all-y += $(patsubst %,archival/libarchive/%,$(sort $(lib-y)))
90lib-y:= 90lib-y:=
91include applets/Kbuild 91include applets/Kbuild
92lib-all-y += $(patsubst %,applets/%,$(sort $(lib-y))) 92lib-all-y += $(patsubst %,applets/%,$(sort $(lib-y)))
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 1a5b10f84..f27a17984 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -329,7 +329,7 @@ void parse_dep_file(void *map, size_t len)
329 clear_config(); 329 clear_config();
330 330
331 while (m < end) { 331 while (m < end) {
332 while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) 332 while (m < end && (*m == ' ' || *m == '\\' || *m == '\n' || *m == '\r'))
333 m++; 333 m++;
334 p = m; 334 p = m;
335 while (p < end && *p != ' ') p++; 335 while (p < end && *p != ' ') p++;
diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter
index 95cbbe6b8..91374c1ca 100755
--- a/scripts/bloat-o-meter
+++ b/scripts/bloat-o-meter
@@ -63,7 +63,7 @@ def getsizes(file):
63 else: 63 else:
64 sym[name] = {"addr" : value, "size": size} 64 sym[name] = {"addr" : value, "size": size}
65 lut[(value, size)] = 0 65 lut[(value, size)] = 0
66 for addr, sz in alias.iterkeys(): 66 for addr, sz in iter(alias.keys()):
67 # If the non-GLOBAL sym has an implementation elsewhere then 67 # If the non-GLOBAL sym has an implementation elsewhere then
68 # it's an alias, disregard it. 68 # it's an alias, disregard it.
69 if not (addr, sz) in lut: 69 if not (addr, sz) in lut:
@@ -92,7 +92,7 @@ if flag_timing:
92grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0 92grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
93delta, common = [], {} 93delta, common = [], {}
94 94
95for name in old.iterkeys(): 95for name in iter(old.keys()):
96 if name in new: 96 if name in new:
97 common[name] = 1 97 common[name] = 1
98 98
diff --git a/scripts/cleanup_printf2puts b/scripts/cleanup_printf2puts
index 446152e12..00193a842 100755
--- a/scripts/cleanup_printf2puts
+++ b/scripts/cleanup_printf2puts
@@ -3,7 +3,7 @@
3# Processes current directory recursively: 3# Processes current directory recursively:
4# printf("abc\n") -> puts("abc"). Beware of fprintf etc... 4# printf("abc\n") -> puts("abc"). Beware of fprintf etc...
5 5
6# BTW, gcc 4.1.2 already does tha same! Can't believe it... 6# BTW, gcc 4.1.2 already does the same! Can't believe it...
7 7
8grep -lr 'printf\([^%%]*\\n"\)' . | grep '.[ch]$' | xargs -n1 \ 8grep -lr 'printf\([^%%]*\\n"\)' . | grep '.[ch]$' | xargs -n1 \
9 sed -e 's/\([^A-Za-z0-9_]\)printf(\( *"[^%]*\)\\n")/\1puts(\2")/' -i 9 sed -e 's/\([^A-Za-z0-9_]\)printf(\( *"[^%]*\)\\n")/\1puts(\2")/' -i
diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh
index 09a95b507..03831f501 100755
--- a/scripts/gen_build_files.sh
+++ b/scripts/gen_build_files.sh
@@ -9,43 +9,58 @@ mkdir include 2>/dev/null
9 9
10srctree="$1" 10srctree="$1"
11 11
12status() { printf ' %-8s%s\n' "$1" "$2"; }
13gen() { status "GEN" "$@"; }
14chk() { status "CHK" "$@"; }
15
16generate()
17{
18 local src="$1" dst="$2" header="$3" insert="$4"
19 #chk "${dst}"
20 (
21 # Need to use printf: different shells have inconsistent
22 # rules re handling of "\n" in echo params,
23 # and ${insert} definitely contains "\n".
24 # Therefore, echo "${header}" would not work:
25 printf "%s\n" "${header}"
26 if grep -qs '^INSERT$' "${src}"; then
27 sed -n '1,/^INSERT$/p' "${src}"
28 printf "%s\n" "${insert}"
29 sed -n '/^INSERT$/,$p' "${src}"
30 else
31 if [ -n "${insert}" ]; then
32 printf "%s\n" "ERROR: INSERT line missing in: ${src}" 1>&2
33 fi
34 cat "${src}"
35 fi
36 ) | sed '/^INSERT$/d' > "${dst}.tmp"
37 if ! cmp -s "${dst}" "${dst}.tmp"; then
38 gen "${dst}"
39 mv "${dst}.tmp" "${dst}"
40 else
41 rm -f "${dst}.tmp"
42 fi
43}
44
12# (Re)generate include/applets.h 45# (Re)generate include/applets.h
13src="$srctree/include/applets.src.h"
14dst="include/applets.h"
15s=`sed -n 's@^//applet:@@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` 46s=`sed -n 's@^//applet:@@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c`
16old=`cat "$dst" 2>/dev/null` 47generate \
17# Why "IFS='' read -r REPLY"?? 48 "$srctree/include/applets.src.h" \
18# This atrocity is needed to read lines without mangling. 49 "include/applets.h" \
19# IFS='' prevents whitespace trimming, 50 "/* DO NOT EDIT. This file is generated from applets.src.h */" \
20# -r suppresses backslash handling. 51 "${s}"
21new=`echo "/* DO NOT EDIT. This file is generated from applets.src.h */"
22while IFS='' read -r REPLY; do
23 test x"$REPLY" = x"INSERT" && REPLY="$s"
24 printf "%s\n" "$REPLY"
25done <"$src"`
26if test x"$new" != x"$old"; then
27 echo " GEN $dst"
28 printf "%s\n" "$new" >"$dst"
29fi
30 52
31# (Re)generate include/usage.h 53# (Re)generate include/usage.h
32src="$srctree/include/usage.src.h"
33dst="include/usage.h"
34# We add line continuation backslash after each line, 54# We add line continuation backslash after each line,
35# and insert empty line before each line which doesn't start 55# and insert empty line before each line which doesn't start
36# with space or tab 56# with space or tab
37# (note: we need to use \\\\ because of ``) 57# (note: we need to use \\\\ because of ``)
38s=`sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\\\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\\\@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` 58s=`sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\\\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\\\@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c`
39old=`cat "$dst" 2>/dev/null` 59generate \
40new=`echo "/* DO NOT EDIT. This file is generated from usage.src.h */" 60 "$srctree/include/usage.src.h" \
41while IFS='' read -r REPLY; do 61 "include/usage.h" \
42 test x"$REPLY" = x"INSERT" && REPLY="$s" 62 "/* DO NOT EDIT. This file is generated from usage.src.h */" \
43 printf "%s\n" "$REPLY" 63 "${s}"
44done <"$src"`
45if test x"$new" != x"$old"; then
46 echo " GEN $dst"
47 printf "%s\n" "$new" >"$dst"
48fi
49 64
50# (Re)generate */Kbuild and */Config.in 65# (Re)generate */Kbuild and */Config.in
51{ cd -- "$srctree" && find . -type d; } | while read -r d; do 66{ cd -- "$srctree" && find . -type d; } | while read -r d; do
@@ -55,40 +70,24 @@ fi
55 dst="$d/Kbuild" 70 dst="$d/Kbuild"
56 if test -f "$src"; then 71 if test -f "$src"; then
57 mkdir -p -- "$d" 2>/dev/null 72 mkdir -p -- "$d" 2>/dev/null
58 #echo " CHK $dst"
59 73
60 s=`sed -n 's@^//kbuild:@@p' -- "$srctree/$d"/*.c` 74 s=`sed -n 's@^//kbuild:@@p' -- "$srctree/$d"/*.c`
61 75 generate \
62 old=`cat "$dst" 2>/dev/null` 76 "${src}" "${dst}" \
63 new=`echo "# DO NOT EDIT. This file is generated from Kbuild.src" 77 "# DO NOT EDIT. This file is generated from Kbuild.src" \
64 while IFS='' read -r REPLY; do 78 "${s}"
65 test x"$REPLY" = x"INSERT" && REPLY="$s"
66 printf "%s\n" "$REPLY"
67 done <"$src"`
68 if test x"$new" != x"$old"; then
69 echo " GEN $dst"
70 printf "%s\n" "$new" >"$dst"
71 fi
72 fi 79 fi
73 80
74 src="$srctree/$d/Config.src" 81 src="$srctree/$d/Config.src"
75 dst="$d/Config.in" 82 dst="$d/Config.in"
76 if test -f "$src"; then 83 if test -f "$src"; then
77 mkdir -p -- "$d" 2>/dev/null 84 mkdir -p -- "$d" 2>/dev/null
78 #echo " CHK $dst"
79 85
80 s=`sed -n 's@^//config:@@p' -- "$srctree/$d"/*.c` 86 s=`sed -n 's@^//config:@@p' -- "$srctree/$d"/*.c`
81 87 generate \
82 old=`cat "$dst" 2>/dev/null` 88 "${src}" "${dst}" \
83 new=`echo "# DO NOT EDIT. This file is generated from Config.src" 89 "# DO NOT EDIT. This file is generated from Config.src" \
84 while IFS='' read -r REPLY; do 90 "${s}"
85 test x"$REPLY" = x"INSERT" && REPLY="$s"
86 printf "%s\n" "$REPLY"
87 done <"$src"`
88 if test x"$new" != x"$old"; then
89 echo " GEN $dst"
90 printf "%s\n" "$new" >"$dst"
91 fi
92 fi 91 fi
93done 92done
94 93
diff --git a/scripts/individual b/scripts/individual
deleted file mode 100755
index e93ca5552..000000000
--- a/scripts/individual
+++ /dev/null
@@ -1,129 +0,0 @@
1#!/bin/sh
2
3# Compile individual versions of each busybox applet.
4
5if [ $# -eq 0 ]
6then
7
8# Clear out the build directory. (Make clean should do this instead of here.)
9
10rm -rf build
11mkdir build
12
13# Make our prerequisites.
14
15make busybox.links include/bb_config.h $(pwd)/{libbb/libbb.a,archival/libunarchive/libunarchive.a,coreutils/libcoreutils/libcoreutils.a,networking/libiproute/libiproute.a}
16
17else
18# Could very well be that we want to build an individual applet but have no
19# 'build' dir yet..
20
21test -d ./build || mkdir build
22
23fi
24
25# About 3/5 of the applets build from one .c file (with the same name as the
26# corresponding applet), and all it needs to link against. However, to build
27# them all we need more than that.
28
29# Figure out which applets need extra libraries added to their command line.
30
31function substithing()
32{
33 if [ "${1/ $3 //}" != "$1" ]
34 then
35 echo $2
36 fi
37}
38
39function extra_libraries()
40{
41 # gzip needs gunzip.c (when gunzip is enabled, anyway).
42 substithing " gzip " "archival/gunzip.c archival/uncompress.c" "$1"
43
44 # init needs init_shared.c
45 substithing " init " "init/init_shared.c" "$1"
46
47 # ifconfig needs interface.c
48 substithing " ifconfig " "networking/interface.c" "$1"
49
50 # Applets that need libunarchive.a
51 substithing " ar bunzip2 unlzma cpio dpkg gunzip rpm2cpio rpm tar uncompress unzip dpkg_deb gzip " "archival/libunarchive/libunarchive.a" "$1"
52
53 # Applets that need libcoreutils.a
54 substithing " cp mv " "coreutils/libcoreutils/libcoreutils.a" "$1"
55
56 # Applets that need libiproute.a
57 substithing " ip " "networking/libiproute/libiproute.a" "$1"
58
59 # What needs -libm?
60 substithing " awk dc " "-lm" "$1"
61
62 # What needs -lcrypt?
63 substithing " httpd vlock " "-lcrypt" "$1"
64}
65
66# Query applets.h to figure out which applets need special treatment
67
68strange_names=`sed -rn -e 's/\#.*//' -e 's/.*APPLET_NOUSAGE\(([^,]*),([^,]*),.*/\1 \2/p' -e 's/.*APPLET_ODDNAME\(([^,]*),([^,]*),.*, *([^)]*).*/\1 \2@\3/p' include/applets.h`
69
70function bonkname()
71{
72 while [ $# -gt 0 ]
73 do
74 if [ "$APPLET" == "$1" ]
75 then
76 APPFILT="${2/@*/}"
77 if [ "${APPFILT}" == "$2" ]
78 then
79 HELPNAME='"nousage\n"' # These should be _fixed_.
80 else
81 HELPNAME="${2/*@/}"_full_usage
82 fi
83 break
84 fi
85 shift 2
86 done
87#echo APPLET=${APPLET} APPFILT=${APPFILT} HELPNAME=${HELPNAME} 2=${2}
88}
89
90# Iterate through every name in busybox.links
91
92function buildit ()
93{
94 export APPLET="$1"
95 export APPFILT=${APPLET}
96 export HELPNAME=${APPLET}_full_usage
97
98 bonkname $strange_names
99
100 j=`find archival console-tools coreutils debianutils editors findutils init loginutils miscutils modutils networking procps shell sysklogd util-linux -name "${APPFILT}.c"`
101 if [ -z "$j" ]
102 then
103 echo no file for $APPLET
104 else
105 echo "Building $APPLET"
106 gcc -Os -o build/$APPLET applets/individual.c $j \
107 `extra_libraries $APPFILT` libbb/libbb.a -Iinclude \
108 -DBUILD_INDIVIDUAL \
109 '-Drun_applet_and_exit(...)' '-Dfind_applet_by_name(...)=0' \
110 -DAPPLET_main=${APPFILT}_main -DAPPLET_full_usage=${HELPNAME}
111 if [ $? -ne 0 ];
112 then
113 echo "Failed $APPLET"
114 fi
115 fi
116}
117
118if [ $# -eq 0 ]
119then
120 for APPLET in `sed 's .*/ ' busybox.links`
121 do
122 buildit "$APPLET"
123 done
124else
125 buildit "$1"
126fi
127
128
129strip build/*
diff --git a/scripts/mkdiff_obj b/scripts/mkdiff_obj
index a6ec5e602..307474874 100755
--- a/scripts/mkdiff_obj
+++ b/scripts/mkdiff_obj
@@ -1,28 +1,35 @@
1#!/bin/sh 1#!/bin/sh
2 2
3usage() {
4 echo "Usage: ${0##*/} DIR1 DIR2"
5 echo
6 echo "Compares all object files recursivelty found in DIR1 and DIR2."
7 echo "Prints diff of their disassembly."
8 echo
9 exit $1
10}
11
3filter() { 12filter() {
4 # sed removes " address: " prefixes which mess up diff 13 # sed removes " address: " prefixes which mess up diff
5 sed $'s/^\\(\t*\\)[ ]*[0-9a-f][0-9a-f]*:[ \t]*/\\1/' \ 14 sed $'s/^\\(\t*\\)[ ]*[0-9a-f][0-9a-f]*:[ \t]*/\\1/' \
6 | sed 's/__GI_//g' 15 | sed 's/__GI_//g'
7} 16}
8 17
9test -d "$1" || exit 1 18test -d "$1" || usage 1
10test -d "$2" || exit 1 19test -d "$2" || usage 1
11 20
12{ 21{
13 ( 22 (
14 cd "$1" || exit 1 23 cd "$1" || exit 1
15 find -name '*.o' -o -name '*.os' # -o -name '*.so' 24 find -name '*.o' # -o -name '*.os' # -o -name '*.so'
16 ) 25 )
17 ( 26 (
18 cd "$2" || exit 1 27 cd "$2" || exit 1
19 find -name '*.o' -o -name '*.os' # -o -name '*.so' 28 find -name '*.o' # -o -name '*.os' # -o -name '*.so'
20 ) 29 )
21} | sed 's:^\./::' | sort | uniq | \ 30} | sed 's:^\./::' | sort | uniq | \
22tee LST | \
23( 31(
24IFS='' 32while IFS='' read -r oname; do
25while read -r oname; do
26 if ! test -f "$1/$oname"; then 33 if ! test -f "$1/$oname"; then
27 echo "Only $2/$oname" 34 echo "Only $2/$oname"
28 continue 35 continue
@@ -32,8 +39,8 @@ while read -r oname; do
32 continue 39 continue
33 fi 40 fi
34 diff -q -- "$1/$oname" "$2/$oname" >/dev/null && continue 41 diff -q -- "$1/$oname" "$2/$oname" >/dev/null && continue
35 (cd "$1"; objdump -dr "$oname" | filter >"$oname.disasm") 42 (cd "$1" && { size "$oname"; objdump -dr "$oname" | filter; } >"$oname.disasm")
36 (cd "$2"; objdump -dr "$oname" | filter >"$oname.disasm") 43 (cd "$2" && { size "$oname"; objdump -dr "$oname" | filter; } >"$oname.disasm")
37 diff -u "$1/$oname.disasm" "$2/$oname.disasm" 44 diff -u -- "$1/$oname.disasm" "$2/$oname.disasm"
38done 45done
39) 46)
diff --git a/scripts/randomtest.loop b/scripts/randomtest.loop
index 311536df8..2c8a9bd35 100755
--- a/scripts/randomtest.loop
+++ b/scripts/randomtest.loop
@@ -4,7 +4,7 @@ test -d "$1" || { echo "'$1' is not a directory"; exit 1; }
4test -x "$1/scripts/randomtest" || { echo "No scripts/randomtest in '$1'"; exit 1; } 4test -x "$1/scripts/randomtest" || { echo "No scripts/randomtest in '$1'"; exit 1; }
5 5
6export LIBC="uclibc" 6export LIBC="uclibc"
7export CROSS_COMPILER_PREFIX="i486-linux-uclibc-" 7export CROSS_COMPILER_PREFIX="i686-"
8export MAKEOPTS="-j9" 8export MAKEOPTS="-j9"
9 9
10cnt=0 10cnt=0
diff --git a/selinux/runcon.c b/selinux/runcon.c
index b70a5e396..54349b25c 100644
--- a/selinux/runcon.c
+++ b/selinux/runcon.c
@@ -132,6 +132,5 @@ int runcon_main(int argc UNUSED_PARAM, char **argv)
132 bb_error_msg_and_die("can't set up security context '%s'", 132 bb_error_msg_and_die("can't set up security context '%s'",
133 context_str(con)); 133 context_str(con));
134 134
135 execvp(argv[0], argv); 135 BB_EXECVP_or_die(argv);
136 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
137} 136}
diff --git a/selinux/sestatus.c b/selinux/sestatus.c
index 7fb2b470b..aa12e806c 100644
--- a/selinux/sestatus.c
+++ b/selinux/sestatus.c
@@ -12,10 +12,10 @@
12 12
13extern char *selinux_mnt; 13extern char *selinux_mnt;
14 14
15#define OPT_VERBOSE (1 << 0) 15#define OPT_VERBOSE (1 << 0)
16#define OPT_BOOLEAN (1 << 1) 16#define OPT_BOOLEAN (1 << 1)
17 17
18#define COL_FMT "%-31s " 18#define COL_FMT "%-31s "
19 19
20static void display_boolean(void) 20static void display_boolean(void)
21{ 21{
@@ -151,7 +151,7 @@ int sestatus_main(int argc UNUSED_PARAM, char **argv)
151 const char *pol_path; 151 const char *pol_path;
152 int rc; 152 int rc;
153 153
154 opt_complementary = "?0"; /* no arguments are required. */ 154 opt_complementary = "?0"; /* no arguments are required. */
155 opts = getopt32(argv, "vb"); 155 opts = getopt32(argv, "vb");
156 156
157 /* SELinux status: line */ 157 /* SELinux status: line */
diff --git a/shell/ash.c b/shell/ash.c
index ccf4288a9..f7baf2b3b 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -57,7 +57,9 @@
57#include <sys/times.h> 57#include <sys/times.h>
58 58
59#include "shell_common.h" 59#include "shell_common.h"
60#include "math.h" 60#if ENABLE_SH_MATH_SUPPORT
61# include "math.h"
62#endif
61#if ENABLE_ASH_RANDOM_SUPPORT 63#if ENABLE_ASH_RANDOM_SUPPORT
62# include "random.h" 64# include "random.h"
63#else 65#else
@@ -5834,6 +5836,11 @@ static struct arglist exparg;
5834/* 5836/*
5835 * Our own itoa(). 5837 * Our own itoa().
5836 */ 5838 */
5839#if !ENABLE_SH_MATH_SUPPORT
5840/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5841typedef long arith_t;
5842# define ARITH_FMT "%ld"
5843#endif
5837static int 5844static int
5838cvtnum(arith_t num) 5845cvtnum(arith_t num)
5839{ 5846{
@@ -13648,7 +13655,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13648 } 13655 }
13649 } 13656 }
13650#endif 13657#endif
13651 if (/* argv[0] && */ argv[0][0] == '-') 13658 if (argv[0] && argv[0][0] == '-')
13652 isloginsh = 1; 13659 isloginsh = 1;
13653 if (isloginsh) { 13660 if (isloginsh) {
13654 state = 1; 13661 state = 1;
diff --git a/shell/ash_test/recho.c b/shell/ash_test/recho.c
index fb48d9c48..42a5feafd 100644
--- a/shell/ash_test/recho.c
+++ b/shell/ash_test/recho.c
@@ -29,12 +29,9 @@
29 29
30void strprint(); 30void strprint();
31 31
32int 32int main(int argc, char **argv)
33main(argc, argv)
34int argc;
35char **argv;
36{ 33{
37 register int i; 34 int i;
38 35
39 for (i = 1; i < argc; i++) { 36 for (i = 1; i < argc; i++) {
40 printf("argv[%d] = <", i); 37 printf("argv[%d] = <", i);
@@ -44,11 +41,9 @@ char **argv;
44 exit(EXIT_SUCCESS); 41 exit(EXIT_SUCCESS);
45} 42}
46 43
47void 44void strprint(char *str)
48strprint(str)
49char *str;
50{ 45{
51 register unsigned char *s; 46 unsigned char *s;
52 47
53 for (s = (unsigned char *)str; s && *s; s++) { 48 for (s = (unsigned char *)str; s && *s; s++) {
54 if (*s < ' ') { 49 if (*s < ' ') {
diff --git a/shell/ash_test/zecho.c b/shell/ash_test/zecho.c
index bf876f641..cbaa59b81 100644
--- a/shell/ash_test/zecho.c
+++ b/shell/ash_test/zecho.c
@@ -21,10 +21,7 @@
21#include <stdio.h> 21#include <stdio.h>
22#include <stdlib.h> 22#include <stdlib.h>
23 23
24int 24int main(int argc, char **argv)
25main(argc, argv)
26int argc;
27char **argv;
28{ 25{
29 argv++; 26 argv++;
30 27
diff --git a/shell/hush.c b/shell/hush.c
index 9dd30c436..a771e9cd9 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -82,7 +82,11 @@
82 * aaa 82 * aaa
83 */ 83 */
84#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ 84#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
85#include <malloc.h> /* for malloc_trim */ 85#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
86 || defined(__APPLE__) \
87 )
88# include <malloc.h> /* for malloc_trim */
89#endif
86#include <glob.h> 90#include <glob.h>
87/* #include <dmalloc.h> */ 91/* #include <dmalloc.h> */
88#if ENABLE_HUSH_CASE 92#if ENABLE_HUSH_CASE
@@ -245,9 +249,15 @@
245//config: msh is deprecated and will be removed, please migrate to hush. 249//config: msh is deprecated and will be removed, please migrate to hush.
246//config: 250//config:
247 251
248//usage:#define hush_trivial_usage NOUSAGE_STR 252/* -i (interactive) and -s (read stdin) are also accepted,
253 * but currently do nothing, therefore aren't shown in help.
254 * NOMMU-specific options are not meant to be used by users,
255 * therefore we don't show them either.
256 */
257//usage:#define hush_trivial_usage
258//usage: "[-nx] [-c SCRIPT]"
249//usage:#define hush_full_usage "" 259//usage:#define hush_full_usage ""
250//usage:#define msh_trivial_usage NOUSAGE_STR 260//usage:#define msh_trivial_usage hush_trivial_usage
251//usage:#define msh_full_usage "" 261//usage:#define msh_full_usage ""
252//usage:#define sh_trivial_usage NOUSAGE_STR 262//usage:#define sh_trivial_usage NOUSAGE_STR
253//usage:#define sh_full_usage "" 263//usage:#define sh_full_usage ""
@@ -507,6 +517,7 @@ struct command {
507# define CMD_FUNCDEF 3 517# define CMD_FUNCDEF 3
508#endif 518#endif
509 519
520 smalluint cmd_exitcode;
510 /* if non-NULL, this "command" is { list }, ( list ), or a compound statement */ 521 /* if non-NULL, this "command" is { list }, ( list ), or a compound statement */
511 struct pipe *group; 522 struct pipe *group;
512#if !BB_MMU 523#if !BB_MMU
@@ -542,7 +553,6 @@ struct command {
542#define IS_NULL_CMD(cmd) \ 553#define IS_NULL_CMD(cmd) \
543 (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects) 554 (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects)
544 555
545
546struct pipe { 556struct pipe {
547 struct pipe *next; 557 struct pipe *next;
548 int num_cmds; /* total number of commands in pipe */ 558 int num_cmds; /* total number of commands in pipe */
@@ -637,6 +647,53 @@ struct function {
637#endif 647#endif
638 648
639 649
650/* set -/+o OPT support. (TODO: make it optional)
651 * bash supports the following opts:
652 * allexport off
653 * braceexpand on
654 * emacs on
655 * errexit off
656 * errtrace off
657 * functrace off
658 * hashall on
659 * histexpand off
660 * history on
661 * ignoreeof off
662 * interactive-comments on
663 * keyword off
664 * monitor on
665 * noclobber off
666 * noexec off
667 * noglob off
668 * nolog off
669 * notify off
670 * nounset off
671 * onecmd off
672 * physical off
673 * pipefail off
674 * posix off
675 * privileged off
676 * verbose off
677 * vi off
678 * xtrace off
679 */
680static const char o_opt_strings[] ALIGN1 =
681 "pipefail\0"
682 "noexec\0"
683#if ENABLE_HUSH_MODE_X
684 "xtrace\0"
685#endif
686 ;
687enum {
688 OPT_O_PIPEFAIL,
689 OPT_O_NOEXEC,
690#if ENABLE_HUSH_MODE_X
691 OPT_O_XTRACE,
692#endif
693 NUM_OPT_O
694};
695
696
640/* "Globals" within this file */ 697/* "Globals" within this file */
641/* Sorted roughly by size (smaller offsets == smaller code) */ 698/* Sorted roughly by size (smaller offsets == smaller code) */
642struct globals { 699struct globals {
@@ -679,6 +736,12 @@ struct globals {
679#else 736#else
680# define G_saved_tty_pgrp 0 737# define G_saved_tty_pgrp 0
681#endif 738#endif
739 char o_opt[NUM_OPT_O];
740#if ENABLE_HUSH_MODE_X
741# define G_x_mode (G.o_opt[OPT_O_XTRACE])
742#else
743# define G_x_mode 0
744#endif
682 smallint flag_SIGINT; 745 smallint flag_SIGINT;
683#if ENABLE_HUSH_LOOPS 746#if ENABLE_HUSH_LOOPS
684 smallint flag_break_continue; 747 smallint flag_break_continue;
@@ -690,13 +753,6 @@ struct globals {
690 */ 753 */
691 smallint flag_return_in_progress; 754 smallint flag_return_in_progress;
692#endif 755#endif
693 smallint n_mode;
694#if ENABLE_HUSH_MODE_X
695 smallint x_mode;
696# define G_x_mode (G.x_mode)
697#else
698# define G_x_mode 0
699#endif
700 smallint exiting; /* used to prevent EXIT trap recursion */ 756 smallint exiting; /* used to prevent EXIT trap recursion */
701 /* These four support $?, $#, and $1 */ 757 /* These four support $?, $#, and $1 */
702 smalluint last_exitcode; 758 smalluint last_exitcode;
@@ -875,7 +931,7 @@ static const struct built_in_command bltins2[] = {
875 */ 931 */
876#if HUSH_DEBUG 932#if HUSH_DEBUG
877/* prevent disasters with G.debug_indent < 0 */ 933/* prevent disasters with G.debug_indent < 0 */
878# define indent() fprintf(stderr, "%*s", (G.debug_indent * 2) & 0xff, "") 934# define indent() fdprintf(2, "%*s", (G.debug_indent * 2) & 0xff, "")
879# define debug_enter() (G.debug_indent++) 935# define debug_enter() (G.debug_indent++)
880# define debug_leave() (G.debug_indent--) 936# define debug_leave() (G.debug_indent--)
881#else 937#else
@@ -885,56 +941,56 @@ static const struct built_in_command bltins2[] = {
885#endif 941#endif
886 942
887#ifndef debug_printf 943#ifndef debug_printf
888# define debug_printf(...) (indent(), fprintf(stderr, __VA_ARGS__)) 944# define debug_printf(...) (indent(), fdprintf(2, __VA_ARGS__))
889#endif 945#endif
890 946
891#ifndef debug_printf_parse 947#ifndef debug_printf_parse
892# define debug_printf_parse(...) (indent(), fprintf(stderr, __VA_ARGS__)) 948# define debug_printf_parse(...) (indent(), fdprintf(2, __VA_ARGS__))
893#endif 949#endif
894 950
895#ifndef debug_printf_exec 951#ifndef debug_printf_exec
896#define debug_printf_exec(...) (indent(), fprintf(stderr, __VA_ARGS__)) 952#define debug_printf_exec(...) (indent(), fdprintf(2, __VA_ARGS__))
897#endif 953#endif
898 954
899#ifndef debug_printf_env 955#ifndef debug_printf_env
900# define debug_printf_env(...) (indent(), fprintf(stderr, __VA_ARGS__)) 956# define debug_printf_env(...) (indent(), fdprintf(2, __VA_ARGS__))
901#endif 957#endif
902 958
903#ifndef debug_printf_jobs 959#ifndef debug_printf_jobs
904# define debug_printf_jobs(...) (indent(), fprintf(stderr, __VA_ARGS__)) 960# define debug_printf_jobs(...) (indent(), fdprintf(2, __VA_ARGS__))
905# define DEBUG_JOBS 1 961# define DEBUG_JOBS 1
906#else 962#else
907# define DEBUG_JOBS 0 963# define DEBUG_JOBS 0
908#endif 964#endif
909 965
910#ifndef debug_printf_expand 966#ifndef debug_printf_expand
911# define debug_printf_expand(...) (indent(), fprintf(stderr, __VA_ARGS__)) 967# define debug_printf_expand(...) (indent(), fdprintf(2, __VA_ARGS__))
912# define DEBUG_EXPAND 1 968# define DEBUG_EXPAND 1
913#else 969#else
914# define DEBUG_EXPAND 0 970# define DEBUG_EXPAND 0
915#endif 971#endif
916 972
917#ifndef debug_printf_varexp 973#ifndef debug_printf_varexp
918# define debug_printf_varexp(...) (indent(), fprintf(stderr, __VA_ARGS__)) 974# define debug_printf_varexp(...) (indent(), fdprintf(2, __VA_ARGS__))
919#endif 975#endif
920 976
921#ifndef debug_printf_glob 977#ifndef debug_printf_glob
922# define debug_printf_glob(...) (indent(), fprintf(stderr, __VA_ARGS__)) 978# define debug_printf_glob(...) (indent(), fdprintf(2, __VA_ARGS__))
923# define DEBUG_GLOB 1 979# define DEBUG_GLOB 1
924#else 980#else
925# define DEBUG_GLOB 0 981# define DEBUG_GLOB 0
926#endif 982#endif
927 983
928#ifndef debug_printf_list 984#ifndef debug_printf_list
929# define debug_printf_list(...) (indent(), fprintf(stderr, __VA_ARGS__)) 985# define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__))
930#endif 986#endif
931 987
932#ifndef debug_printf_subst 988#ifndef debug_printf_subst
933# define debug_printf_subst(...) (indent(), fprintf(stderr, __VA_ARGS__)) 989# define debug_printf_subst(...) (indent(), fdprintf(2, __VA_ARGS__))
934#endif 990#endif
935 991
936#ifndef debug_printf_clean 992#ifndef debug_printf_clean
937# define debug_printf_clean(...) (indent(), fprintf(stderr, __VA_ARGS__)) 993# define debug_printf_clean(...) (indent(), fdprintf(2, __VA_ARGS__))
938# define DEBUG_CLEAN 1 994# define DEBUG_CLEAN 1
939#else 995#else
940# define DEBUG_CLEAN 0 996# define DEBUG_CLEAN 0
@@ -944,9 +1000,9 @@ static const struct built_in_command bltins2[] = {
944static void debug_print_strings(const char *prefix, char **vv) 1000static void debug_print_strings(const char *prefix, char **vv)
945{ 1001{
946 indent(); 1002 indent();
947 fprintf(stderr, "%s:\n", prefix); 1003 fdprintf(2, "%s:\n", prefix);
948 while (*vv) 1004 while (*vv)
949 fprintf(stderr, " '%s'\n", *vv++); 1005 fdprintf(2, " '%s'\n", *vv++);
950} 1006}
951#else 1007#else
952# define debug_print_strings(prefix, vv) ((void)0) 1008# define debug_print_strings(prefix, vv) ((void)0)
@@ -1378,6 +1434,22 @@ static void hush_exit(int exitcode)
1378 builtin_eval(argv); 1434 builtin_eval(argv);
1379 } 1435 }
1380 1436
1437#if ENABLE_FEATURE_CLEAN_UP
1438 {
1439 struct variable *cur_var;
1440 if (G.cwd != bb_msg_unknown)
1441 free((char*)G.cwd);
1442 cur_var = G.top_var;
1443 while (cur_var) {
1444 struct variable *tmp = cur_var;
1445 if (!cur_var->max_len)
1446 free(cur_var->varstr);
1447 cur_var = cur_var->next;
1448 free(tmp);
1449 }
1450 }
1451#endif
1452
1381#if ENABLE_HUSH_JOB 1453#if ENABLE_HUSH_JOB
1382 fflush_all(); 1454 fflush_all();
1383 sigexit(- (exitcode & 0xff)); 1455 sigexit(- (exitcode & 0xff));
@@ -2120,22 +2192,22 @@ static void debug_print_list(const char *prefix, o_string *o, int n)
2120 int i = 0; 2192 int i = 0;
2121 2193
2122 indent(); 2194 indent();
2123 fprintf(stderr, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n", 2195 fdprintf(2, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n",
2124 prefix, list, n, string_start, o->length, o->maxlen, 2196 prefix, list, n, string_start, o->length, o->maxlen,
2125 !!(o->o_expflags & EXP_FLAG_GLOB), 2197 !!(o->o_expflags & EXP_FLAG_GLOB),
2126 o->has_quoted_part, 2198 o->has_quoted_part,
2127 !!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); 2199 !!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
2128 while (i < n) { 2200 while (i < n) {
2129 indent(); 2201 indent();
2130 fprintf(stderr, " list[%d]=%d '%s' %p\n", i, (int)list[i], 2202 fdprintf(2, " list[%d]=%d '%s' %p\n", i, (int)(uintptr_t)list[i],
2131 o->data + (int)list[i] + string_start, 2203 o->data + (int)(uintptr_t)list[i] + string_start,
2132 o->data + (int)list[i] + string_start); 2204 o->data + (int)(uintptr_t)list[i] + string_start);
2133 i++; 2205 i++;
2134 } 2206 }
2135 if (n) { 2207 if (n) {
2136 const char *p = o->data + (int)list[n - 1] + string_start; 2208 const char *p = o->data + (int)(uintptr_t)list[n - 1] + string_start;
2137 indent(); 2209 indent();
2138 fprintf(stderr, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data)); 2210 fdprintf(2, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data));
2139 } 2211 }
2140} 2212}
2141#else 2213#else
@@ -2583,6 +2655,94 @@ static void free_pipe_list(struct pipe *pi)
2583 2655
2584/*** Parsing routines ***/ 2656/*** Parsing routines ***/
2585 2657
2658#ifndef debug_print_tree
2659static void debug_print_tree(struct pipe *pi, int lvl)
2660{
2661 static const char *const PIPE[] = {
2662 [PIPE_SEQ] = "SEQ",
2663 [PIPE_AND] = "AND",
2664 [PIPE_OR ] = "OR" ,
2665 [PIPE_BG ] = "BG" ,
2666 };
2667 static const char *RES[] = {
2668 [RES_NONE ] = "NONE" ,
2669# if ENABLE_HUSH_IF
2670 [RES_IF ] = "IF" ,
2671 [RES_THEN ] = "THEN" ,
2672 [RES_ELIF ] = "ELIF" ,
2673 [RES_ELSE ] = "ELSE" ,
2674 [RES_FI ] = "FI" ,
2675# endif
2676# if ENABLE_HUSH_LOOPS
2677 [RES_FOR ] = "FOR" ,
2678 [RES_WHILE] = "WHILE",
2679 [RES_UNTIL] = "UNTIL",
2680 [RES_DO ] = "DO" ,
2681 [RES_DONE ] = "DONE" ,
2682# endif
2683# if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
2684 [RES_IN ] = "IN" ,
2685# endif
2686# if ENABLE_HUSH_CASE
2687 [RES_CASE ] = "CASE" ,
2688 [RES_CASE_IN ] = "CASE_IN" ,
2689 [RES_MATCH] = "MATCH",
2690 [RES_CASE_BODY] = "CASE_BODY",
2691 [RES_ESAC ] = "ESAC" ,
2692# endif
2693 [RES_XXXX ] = "XXXX" ,
2694 [RES_SNTX ] = "SNTX" ,
2695 };
2696 static const char *const CMDTYPE[] = {
2697 "{}",
2698 "()",
2699 "[noglob]",
2700# if ENABLE_HUSH_FUNCTIONS
2701 "func()",
2702# endif
2703 };
2704
2705 int pin, prn;
2706
2707 pin = 0;
2708 while (pi) {
2709 fdprintf(2, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "",
2710 pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]);
2711 prn = 0;
2712 while (prn < pi->num_cmds) {
2713 struct command *command = &pi->cmds[prn];
2714 char **argv = command->argv;
2715
2716 fdprintf(2, "%*s cmd %d assignment_cnt:%d",
2717 lvl*2, "", prn,
2718 command->assignment_cnt);
2719 if (command->group) {
2720 fdprintf(2, " group %s: (argv=%p)%s%s\n",
2721 CMDTYPE[command->cmd_type],
2722 argv
2723# if !BB_MMU
2724 , " group_as_string:", command->group_as_string
2725# else
2726 , "", ""
2727# endif
2728 );
2729 debug_print_tree(command->group, lvl+1);
2730 prn++;
2731 continue;
2732 }
2733 if (argv) while (*argv) {
2734 fdprintf(2, " '%s'", *argv);
2735 argv++;
2736 }
2737 fdprintf(2, "\n");
2738 prn++;
2739 }
2740 pi = pi->next;
2741 pin++;
2742 }
2743}
2744#endif /* debug_print_tree */
2745
2586static struct pipe *new_pipe(void) 2746static struct pipe *new_pipe(void)
2587{ 2747{
2588 struct pipe *pi; 2748 struct pipe *pi;
@@ -3972,15 +4132,16 @@ static struct pipe *parse_stream(char **pstring,
3972 goto parse_error; 4132 goto parse_error;
3973 } 4133 }
3974 if (ch == '\n') { 4134 if (ch == '\n') {
3975#if ENABLE_HUSH_CASE 4135 /* Is this a case when newline is simply ignored?
3976 /* "case ... in <newline> word) ..." - 4136 * Some examples:
3977 * newlines are ignored (but ';' wouldn't be) */ 4137 * "cmd | <newline> cmd ..."
3978 if (ctx.command->argv == NULL 4138 * "case ... in <newline> word) ..."
3979 && ctx.ctx_res_w == RES_MATCH 4139 */
4140 if (IS_NULL_CMD(ctx.command)
4141 && dest.length == 0 && !dest.has_quoted_part
3980 ) { 4142 ) {
3981 continue; 4143 continue;
3982 } 4144 }
3983#endif
3984 /* Treat newline as a command separator. */ 4145 /* Treat newline as a command separator. */
3985 done_pipe(&ctx, PIPE_SEQ); 4146 done_pipe(&ctx, PIPE_SEQ);
3986 debug_printf_parse("heredoc_cnt:%d\n", heredoc_cnt); 4147 debug_printf_parse("heredoc_cnt:%d\n", heredoc_cnt);
@@ -4112,6 +4273,31 @@ static struct pipe *parse_stream(char **pstring,
4112 if (parse_redirect(&ctx, redir_fd, redir_style, input)) 4273 if (parse_redirect(&ctx, redir_fd, redir_style, input))
4113 goto parse_error; 4274 goto parse_error;
4114 continue; /* back to top of while (1) */ 4275 continue; /* back to top of while (1) */
4276 case '#':
4277 if (dest.length == 0 && !dest.has_quoted_part) {
4278 /* skip "#comment" */
4279 while (1) {
4280 ch = i_peek(input);
4281 if (ch == EOF || ch == '\n')
4282 break;
4283 i_getch(input);
4284 /* note: we do not add it to &ctx.as_string */
4285 }
4286 nommu_addchr(&ctx.as_string, '\n');
4287 continue; /* back to top of while (1) */
4288 }
4289 break;
4290 case '\\':
4291 if (next == '\n') {
4292 /* It's "\<newline>" */
4293#if !BB_MMU
4294 /* Remove trailing '\' from ctx.as_string */
4295 ctx.as_string.data[--ctx.as_string.length] = '\0';
4296#endif
4297 ch = i_getch(input); /* eat it */
4298 continue; /* back to top of while (1) */
4299 }
4300 break;
4115 } 4301 }
4116 4302
4117 if (dest.o_assignment == MAYBE_ASSIGNMENT 4303 if (dest.o_assignment == MAYBE_ASSIGNMENT
@@ -4126,19 +4312,8 @@ static struct pipe *parse_stream(char **pstring,
4126 /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ 4312 /* Note: nommu_addchr(&ctx.as_string, ch) is already done */
4127 4313
4128 switch (ch) { 4314 switch (ch) {
4129 case '#': 4315 case '#': /* non-comment #: "echo a#b" etc */
4130 if (dest.length == 0) { 4316 o_addQchr(&dest, ch);
4131 while (1) {
4132 ch = i_peek(input);
4133 if (ch == EOF || ch == '\n')
4134 break;
4135 i_getch(input);
4136 /* note: we do not add it to &ctx.as_string */
4137 }
4138 nommu_addchr(&ctx.as_string, '\n');
4139 } else {
4140 o_addQchr(&dest, ch);
4141 }
4142 break; 4317 break;
4143 case '\\': 4318 case '\\':
4144 if (next == EOF) { 4319 if (next == EOF) {
@@ -4146,21 +4321,14 @@ static struct pipe *parse_stream(char **pstring,
4146 xfunc_die(); 4321 xfunc_die();
4147 } 4322 }
4148 ch = i_getch(input); 4323 ch = i_getch(input);
4149 if (ch != '\n') { 4324 /* note: ch != '\n' (that case does not reach this place) */
4150 o_addchr(&dest, '\\'); 4325 o_addchr(&dest, '\\');
4151 /*nommu_addchr(&ctx.as_string, '\\'); - already done */ 4326 /*nommu_addchr(&ctx.as_string, '\\'); - already done */
4152 o_addchr(&dest, ch); 4327 o_addchr(&dest, ch);
4153 nommu_addchr(&ctx.as_string, ch); 4328 nommu_addchr(&ctx.as_string, ch);
4154 /* Example: echo Hello \2>file 4329 /* Example: echo Hello \2>file
4155 * we need to know that word 2 is quoted */ 4330 * we need to know that word 2 is quoted */
4156 dest.has_quoted_part = 1; 4331 dest.has_quoted_part = 1;
4157 }
4158#if !BB_MMU
4159 else {
4160 /* It's "\<newline>". Remove trailing '\' from ctx.as_string */
4161 ctx.as_string.data[--ctx.as_string.length] = '\0';
4162 }
4163#endif
4164 break; 4332 break;
4165 case '$': 4333 case '$':
4166 if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) { 4334 if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) {
@@ -4366,7 +4534,9 @@ static struct pipe *parse_stream(char **pstring,
4366 expand_string_to_string(str) 4534 expand_string_to_string(str)
4367#endif 4535#endif
4368static char *expand_string_to_string(const char *str, int do_unbackslash); 4536static char *expand_string_to_string(const char *str, int do_unbackslash);
4537#if ENABLE_HUSH_TICK
4369static int process_command_subs(o_string *dest, const char *s); 4538static int process_command_subs(o_string *dest, const char *s);
4539#endif
4370 4540
4371/* expand_strvec_to_strvec() takes a list of strings, expands 4541/* expand_strvec_to_strvec() takes a list of strings, expands
4372 * all variable references within and returns a pointer to 4542 * all variable references within and returns a pointer to
@@ -6309,48 +6479,57 @@ static int checkjobs(struct pipe *fg_pipe)
6309#endif 6479#endif
6310 /* Were we asked to wait for fg pipe? */ 6480 /* Were we asked to wait for fg pipe? */
6311 if (fg_pipe) { 6481 if (fg_pipe) {
6312 for (i = 0; i < fg_pipe->num_cmds; i++) { 6482 i = fg_pipe->num_cmds;
6483 while (--i >= 0) {
6313 debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid); 6484 debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid);
6314 if (fg_pipe->cmds[i].pid != childpid) 6485 if (fg_pipe->cmds[i].pid != childpid)
6315 continue; 6486 continue;
6316 if (dead) { 6487 if (dead) {
6488 int ex;
6317 fg_pipe->cmds[i].pid = 0; 6489 fg_pipe->cmds[i].pid = 0;
6318 fg_pipe->alive_cmds--; 6490 fg_pipe->alive_cmds--;
6319 if (i == fg_pipe->num_cmds - 1) { 6491 ex = WEXITSTATUS(status);
6320 /* last process gives overall exitstatus */ 6492 /* bash prints killer signal's name for *last*
6321 rcode = WEXITSTATUS(status); 6493 * process in pipe (prints just newline for SIGINT).
6322 /* bash prints killer signal's name for *last* 6494 * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT)
6323 * process in pipe (prints just newline for SIGINT). 6495 */
6324 * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) 6496 if (WIFSIGNALED(status)) {
6325 */ 6497 int sig = WTERMSIG(status);
6326 if (WIFSIGNALED(status)) { 6498 if (i == fg_pipe->num_cmds-1)
6327 int sig = WTERMSIG(status);
6328 printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); 6499 printf("%s\n", sig == SIGINT ? "" : get_signame(sig));
6329 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? 6500 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here?
6330 * Maybe we need to use sig | 128? */ 6501 * Maybe we need to use sig | 128? */
6331 rcode = sig + 128; 6502 ex = sig + 128;
6332 }
6333 IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;)
6334 } 6503 }
6504 fg_pipe->cmds[i].cmd_exitcode = ex;
6335 } else { 6505 } else {
6336 fg_pipe->cmds[i].is_stopped = 1; 6506 fg_pipe->cmds[i].is_stopped = 1;
6337 fg_pipe->stopped_cmds++; 6507 fg_pipe->stopped_cmds++;
6338 } 6508 }
6339 debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n", 6509 debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n",
6340 fg_pipe->alive_cmds, fg_pipe->stopped_cmds); 6510 fg_pipe->alive_cmds, fg_pipe->stopped_cmds);
6341 if (fg_pipe->alive_cmds - fg_pipe->stopped_cmds <= 0) { 6511 if (fg_pipe->alive_cmds == fg_pipe->stopped_cmds) {
6342 /* All processes in fg pipe have exited or stopped */ 6512 /* All processes in fg pipe have exited or stopped */
6513 i = fg_pipe->num_cmds;
6514 while (--i >= 0) {
6515 rcode = fg_pipe->cmds[i].cmd_exitcode;
6516 /* usually last process gives overall exitstatus,
6517 * but with "set -o pipefail", last *failed* process does */
6518 if (G.o_opt[OPT_O_PIPEFAIL] == 0 || rcode != 0)
6519 break;
6520 }
6521 IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;)
6343/* Note: *non-interactive* bash does not continue if all processes in fg pipe 6522/* Note: *non-interactive* bash does not continue if all processes in fg pipe
6344 * are stopped. Testcase: "cat | cat" in a script (not on command line!) 6523 * are stopped. Testcase: "cat | cat" in a script (not on command line!)
6345 * and "killall -STOP cat" */ 6524 * and "killall -STOP cat" */
6346 if (G_interactive_fd) { 6525 if (G_interactive_fd) {
6347#if ENABLE_HUSH_JOB 6526#if ENABLE_HUSH_JOB
6348 if (fg_pipe->alive_cmds) 6527 if (fg_pipe->alive_cmds != 0)
6349 insert_bg_job(fg_pipe); 6528 insert_bg_job(fg_pipe);
6350#endif 6529#endif
6351 return rcode; 6530 return rcode;
6352 } 6531 }
6353 if (!fg_pipe->alive_cmds) 6532 if (fg_pipe->alive_cmds == 0)
6354 return rcode; 6533 return rcode;
6355 } 6534 }
6356 /* There are still running processes in the fg pipe */ 6535 /* There are still running processes in the fg pipe */
@@ -6436,7 +6615,7 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe)
6436 * subshell: ( list ) [&] 6615 * subshell: ( list ) [&]
6437 */ 6616 */
6438#if !ENABLE_HUSH_MODE_X 6617#if !ENABLE_HUSH_MODE_X
6439#define redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel, char argv_expanded) \ 6618#define redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel, argv_expanded) \
6440 redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel) 6619 redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel)
6441#endif 6620#endif
6442static int redirect_and_varexp_helper(char ***new_env_p, 6621static int redirect_and_varexp_helper(char ***new_env_p,
@@ -6821,94 +7000,6 @@ static NOINLINE int run_pipe(struct pipe *pi)
6821 return -1; 7000 return -1;
6822} 7001}
6823 7002
6824#ifndef debug_print_tree
6825static void debug_print_tree(struct pipe *pi, int lvl)
6826{
6827 static const char *const PIPE[] = {
6828 [PIPE_SEQ] = "SEQ",
6829 [PIPE_AND] = "AND",
6830 [PIPE_OR ] = "OR" ,
6831 [PIPE_BG ] = "BG" ,
6832 };
6833 static const char *RES[] = {
6834 [RES_NONE ] = "NONE" ,
6835# if ENABLE_HUSH_IF
6836 [RES_IF ] = "IF" ,
6837 [RES_THEN ] = "THEN" ,
6838 [RES_ELIF ] = "ELIF" ,
6839 [RES_ELSE ] = "ELSE" ,
6840 [RES_FI ] = "FI" ,
6841# endif
6842# if ENABLE_HUSH_LOOPS
6843 [RES_FOR ] = "FOR" ,
6844 [RES_WHILE] = "WHILE",
6845 [RES_UNTIL] = "UNTIL",
6846 [RES_DO ] = "DO" ,
6847 [RES_DONE ] = "DONE" ,
6848# endif
6849# if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE
6850 [RES_IN ] = "IN" ,
6851# endif
6852# if ENABLE_HUSH_CASE
6853 [RES_CASE ] = "CASE" ,
6854 [RES_CASE_IN ] = "CASE_IN" ,
6855 [RES_MATCH] = "MATCH",
6856 [RES_CASE_BODY] = "CASE_BODY",
6857 [RES_ESAC ] = "ESAC" ,
6858# endif
6859 [RES_XXXX ] = "XXXX" ,
6860 [RES_SNTX ] = "SNTX" ,
6861 };
6862 static const char *const CMDTYPE[] = {
6863 "{}",
6864 "()",
6865 "[noglob]",
6866# if ENABLE_HUSH_FUNCTIONS
6867 "func()",
6868# endif
6869 };
6870
6871 int pin, prn;
6872
6873 pin = 0;
6874 while (pi) {
6875 fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "",
6876 pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]);
6877 prn = 0;
6878 while (prn < pi->num_cmds) {
6879 struct command *command = &pi->cmds[prn];
6880 char **argv = command->argv;
6881
6882 fprintf(stderr, "%*s cmd %d assignment_cnt:%d",
6883 lvl*2, "", prn,
6884 command->assignment_cnt);
6885 if (command->group) {
6886 fprintf(stderr, " group %s: (argv=%p)%s%s\n",
6887 CMDTYPE[command->cmd_type],
6888 argv
6889# if !BB_MMU
6890 , " group_as_string:", command->group_as_string
6891# else
6892 , "", ""
6893# endif
6894 );
6895 debug_print_tree(command->group, lvl+1);
6896 prn++;
6897 continue;
6898 }
6899 if (argv) while (*argv) {
6900 fprintf(stderr, " '%s'", *argv);
6901 argv++;
6902 }
6903 fprintf(stderr, "\n");
6904 prn++;
6905 }
6906 pi = pi->next;
6907 pin++;
6908 }
6909}
6910#endif /* debug_print_tree */
6911
6912/* NB: called by pseudo_exec, and therefore must not modify any 7003/* NB: called by pseudo_exec, and therefore must not modify any
6913 * global data until exec/_exit (we can be a child after vfork!) */ 7004 * global data until exec/_exit (we can be a child after vfork!) */
6914static int run_list(struct pipe *pi) 7005static int run_list(struct pipe *pi)
@@ -6938,27 +7029,30 @@ static int run_list(struct pipe *pi)
6938 7029
6939#if ENABLE_HUSH_LOOPS 7030#if ENABLE_HUSH_LOOPS
6940 /* Check syntax for "for" */ 7031 /* Check syntax for "for" */
6941 for (struct pipe *cpipe = pi; cpipe; cpipe = cpipe->next) { 7032 {
6942 if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN) 7033 struct pipe *cpipe;
6943 continue; 7034 for (cpipe = pi; cpipe; cpipe = cpipe->next) {
6944 /* current word is FOR or IN (BOLD in comments below) */ 7035 if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN)
6945 if (cpipe->next == NULL) { 7036 continue;
6946 syntax_error("malformed for"); 7037 /* current word is FOR or IN (BOLD in comments below) */
6947 debug_leave(); 7038 if (cpipe->next == NULL) {
6948 debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); 7039 syntax_error("malformed for");
6949 return 1; 7040 debug_leave();
6950 } 7041 debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level);
6951 /* "FOR v; do ..." and "for v IN a b; do..." are ok */ 7042 return 1;
6952 if (cpipe->next->res_word == RES_DO) 7043 }
6953 continue; 7044 /* "FOR v; do ..." and "for v IN a b; do..." are ok */
6954 /* next word is not "do". It must be "in" then ("FOR v in ...") */ 7045 if (cpipe->next->res_word == RES_DO)
6955 if (cpipe->res_word == RES_IN /* "for v IN a b; not_do..."? */ 7046 continue;
6956 || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */ 7047 /* next word is not "do". It must be "in" then ("FOR v in ...") */
6957 ) { 7048 if (cpipe->res_word == RES_IN /* "for v IN a b; not_do..."? */
6958 syntax_error("malformed for"); 7049 || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */
6959 debug_leave(); 7050 ) {
6960 debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); 7051 syntax_error("malformed for");
6961 return 1; 7052 debug_leave();
7053 debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level);
7054 return 1;
7055 }
6962 } 7056 }
6963 } 7057 }
6964#endif 7058#endif
@@ -7241,7 +7335,7 @@ static int run_and_free_list(struct pipe *pi)
7241{ 7335{
7242 int rcode = 0; 7336 int rcode = 0;
7243 debug_printf_exec("run_and_free_list entered\n"); 7337 debug_printf_exec("run_and_free_list entered\n");
7244 if (!G.n_mode) { 7338 if (!G.o_opt[OPT_O_NOEXEC]) {
7245 debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); 7339 debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds);
7246 rcode = run_list(pi); 7340 rcode = run_list(pi);
7247 } 7341 }
@@ -7339,13 +7433,41 @@ static void set_fatal_handlers(void)
7339} 7433}
7340#endif 7434#endif
7341 7435
7342static int set_mode(const char cstate, const char mode) 7436static int set_mode(int state, char mode, const char *o_opt)
7343{ 7437{
7344 int state = (cstate == '-' ? 1 : 0); 7438 int idx;
7345 switch (mode) { 7439 switch (mode) {
7346 case 'n': G.n_mode = state; break; 7440 case 'n':
7347 case 'x': IF_HUSH_MODE_X(G_x_mode = state;) break; 7441 G.o_opt[OPT_O_NOEXEC] = state;
7348 default: return EXIT_FAILURE; 7442 break;
7443 case 'x':
7444 IF_HUSH_MODE_X(G_x_mode = state;)
7445 break;
7446 case 'o':
7447 if (!o_opt) {
7448 /* "set -+o" without parameter.
7449 * in bash, set -o produces this output:
7450 * pipefail off
7451 * and set +o:
7452 * set +o pipefail
7453 * We always use the second form.
7454 */
7455 const char *p = o_opt_strings;
7456 idx = 0;
7457 while (*p) {
7458 printf("set %co %s\n", (G.o_opt[idx] ? '-' : '+'), p);
7459 idx++;
7460 p += strlen(p) + 1;
7461 }
7462 break;
7463 }
7464 idx = index_in_strings(o_opt_strings, o_opt);
7465 if (idx >= 0) {
7466 G.o_opt[idx] = state;
7467 break;
7468 }
7469 default:
7470 return EXIT_FAILURE;
7349 } 7471 }
7350 return EXIT_SUCCESS; 7472 return EXIT_SUCCESS;
7351} 7473}
@@ -7357,7 +7479,7 @@ int hush_main(int argc, char **argv)
7357 unsigned builtin_argc; 7479 unsigned builtin_argc;
7358 char **e; 7480 char **e;
7359 struct variable *cur_var; 7481 struct variable *cur_var;
7360 struct variable shell_ver; 7482 struct variable *shell_ver;
7361 7483
7362 INIT_G(); 7484 INIT_G();
7363 if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */ 7485 if (EXIT_SUCCESS) /* if EXIT_SUCCESS == 0, it is already done */
@@ -7366,17 +7488,17 @@ int hush_main(int argc, char **argv)
7366 G.argv0_for_re_execing = argv[0]; 7488 G.argv0_for_re_execing = argv[0];
7367#endif 7489#endif
7368 /* Deal with HUSH_VERSION */ 7490 /* Deal with HUSH_VERSION */
7369 memset(&shell_ver, 0, sizeof(shell_ver)); 7491 shell_ver = xzalloc(sizeof(*shell_ver));
7370 shell_ver.flg_export = 1; 7492 shell_ver->flg_export = 1;
7371 shell_ver.flg_read_only = 1; 7493 shell_ver->flg_read_only = 1;
7372 /* Code which handles ${var<op>...} needs writable values for all variables, 7494 /* Code which handles ${var<op>...} needs writable values for all variables,
7373 * therefore we xstrdup: */ 7495 * therefore we xstrdup: */
7374 shell_ver.varstr = xstrdup(hush_version_str), 7496 shell_ver->varstr = xstrdup(hush_version_str);
7375 G.top_var = &shell_ver;
7376 /* Create shell local variables from the values 7497 /* Create shell local variables from the values
7377 * currently living in the environment */ 7498 * currently living in the environment */
7378 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); 7499 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
7379 unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ 7500 unsetenv("HUSH_VERSION"); /* in case it exists in initial env */
7501 G.top_var = shell_ver;
7380 cur_var = G.top_var; 7502 cur_var = G.top_var;
7381 e = environ; 7503 e = environ;
7382 if (e) while (*e) { 7504 if (e) while (*e) {
@@ -7391,8 +7513,8 @@ int hush_main(int argc, char **argv)
7391 e++; 7513 e++;
7392 } 7514 }
7393 /* (Re)insert HUSH_VERSION into env (AFTER we scanned the env!) */ 7515 /* (Re)insert HUSH_VERSION into env (AFTER we scanned the env!) */
7394 debug_printf_env("putenv '%s'\n", shell_ver.varstr); 7516 debug_printf_env("putenv '%s'\n", shell_ver->varstr);
7395 putenv(shell_ver.varstr); 7517 putenv(shell_ver->varstr);
7396 7518
7397 /* Export PWD */ 7519 /* Export PWD */
7398 set_pwd_var(/*exp:*/ 1); 7520 set_pwd_var(/*exp:*/ 1);
@@ -7585,7 +7707,7 @@ int hush_main(int argc, char **argv)
7585#endif 7707#endif
7586 case 'n': 7708 case 'n':
7587 case 'x': 7709 case 'x':
7588 if (set_mode('-', opt) == 0) /* no error */ 7710 if (set_mode(1, opt, NULL) == 0) /* no error */
7589 break; 7711 break;
7590 default: 7712 default:
7591#ifndef BB_VER 7713#ifndef BB_VER
@@ -7752,18 +7874,6 @@ int hush_main(int argc, char **argv)
7752 parse_and_run_file(stdin); 7874 parse_and_run_file(stdin);
7753 7875
7754 final_return: 7876 final_return:
7755#if ENABLE_FEATURE_CLEAN_UP
7756 if (G.cwd != bb_msg_unknown)
7757 free((char*)G.cwd);
7758 cur_var = G.top_var->next;
7759 while (cur_var) {
7760 struct variable *tmp = cur_var;
7761 if (!cur_var->max_len)
7762 free(cur_var->varstr);
7763 cur_var = cur_var->next;
7764 free(tmp);
7765 }
7766#endif
7767 hush_exit(G.last_exitcode); 7877 hush_exit(G.last_exitcode);
7768} 7878}
7769 7879
@@ -8375,15 +8485,18 @@ static int FAST_FUNC builtin_set(char **argv)
8375 } 8485 }
8376 8486
8377 do { 8487 do {
8378 if (!strcmp(arg, "--")) { 8488 if (strcmp(arg, "--") == 0) {
8379 ++argv; 8489 ++argv;
8380 goto set_argv; 8490 goto set_argv;
8381 } 8491 }
8382 if (arg[0] != '+' && arg[0] != '-') 8492 if (arg[0] != '+' && arg[0] != '-')
8383 break; 8493 break;
8384 for (n = 1; arg[n]; ++n) 8494 for (n = 1; arg[n]; ++n) {
8385 if (set_mode(arg[0], arg[n])) 8495 if (set_mode((arg[0] == '-'), arg[n], argv[1]))
8386 goto error; 8496 goto error;
8497 if (arg[n] == 'o' && argv[1])
8498 argv++;
8499 }
8387 } while ((arg = *++argv) != NULL); 8500 } while ((arg = *++argv) != NULL);
8388 /* Now argv[0] is 1st argument */ 8501 /* Now argv[0] is 1st argument */
8389 8502
diff --git a/shell/hush_test/hush-misc/assignment3.right b/shell/hush_test/hush-misc/assignment3.right
new file mode 100644
index 000000000..0f02d7cbc
--- /dev/null
+++ b/shell/hush_test/hush-misc/assignment3.right
@@ -0,0 +1,2 @@
1Done:0
2abc=123
diff --git a/shell/hush_test/hush-misc/assignment3.tests b/shell/hush_test/hush-misc/assignment3.tests
new file mode 100755
index 000000000..790129be1
--- /dev/null
+++ b/shell/hush_test/hush-misc/assignment3.tests
@@ -0,0 +1,5 @@
1# This must be interpreted as assignments
2a=1 b\
3=2 c=3
4echo Done:$?
5echo abc=$a$b$c
diff --git a/shell/hush_test/hush-misc/pipefail.right b/shell/hush_test/hush-misc/pipefail.right
new file mode 100644
index 000000000..5845d8939
--- /dev/null
+++ b/shell/hush_test/hush-misc/pipefail.right
@@ -0,0 +1,40 @@
1Default:
2true | true:
30
41
5true | false:
61
70
8false | true:
90
101
11exit 2 | exit 3 | exit 4:
124
130
14Pipefail on:
15true | true:
160
171
18true | false:
191
200
21false | true:
221
230
24exit 2 | exit 3 | exit 4:
254
260
27Pipefail off:
28true | true:
290
301
31true | false:
321
330
34false | true:
350
361
37exit 2 | exit 3 | exit 4:
384
390
40Done
diff --git a/shell/hush_test/hush-misc/pipefail.tests b/shell/hush_test/hush-misc/pipefail.tests
new file mode 100755
index 000000000..9df841861
--- /dev/null
+++ b/shell/hush_test/hush-misc/pipefail.tests
@@ -0,0 +1,45 @@
1echo Default:
2echo "true | true:"
3 true | true; echo $?
4! true | true; echo $?
5echo "true | false:"
6 true | false; echo $?
7! true | false; echo $?
8echo "false | true:"
9 false | true; echo $?
10! false | true; echo $?
11echo "exit 2 | exit 3 | exit 4:"
12 exit 2 | exit 3 | exit 4; echo $?
13! exit 2 | exit 3 | exit 4; echo $?
14
15echo Pipefail on:
16set -o pipefail
17echo "true | true:"
18 true | true; echo $?
19! true | true; echo $?
20echo "true | false:"
21 true | false; echo $?
22! true | false; echo $?
23echo "false | true:"
24 false | true; echo $?
25! false | true; echo $?
26echo "exit 2 | exit 3 | exit 4:"
27 exit 2 | exit 3 | exit 4; echo $?
28! exit 2 | exit 3 | exit 4; echo $?
29
30echo Pipefail off:
31set +o pipefail
32echo "true | true:"
33 true | true; echo $?
34! true | true; echo $?
35echo "true | false:"
36 true | false; echo $?
37! true | false; echo $?
38echo "false | true:"
39 false | true; echo $?
40! false | true; echo $?
41echo "exit 2 | exit 3 | exit 4:"
42 exit 2 | exit 3 | exit 4; echo $?
43! exit 2 | exit 3 | exit 4; echo $?
44
45echo Done
diff --git a/shell/hush_test/hush-parsing/comment1.right b/shell/hush_test/hush-parsing/comment1.right
new file mode 100644
index 000000000..a102b1d4e
--- /dev/null
+++ b/shell/hush_test/hush-parsing/comment1.right
@@ -0,0 +1,2 @@
1Nothing:
2String: #should-be-echoed
diff --git a/shell/hush_test/hush-parsing/comment1.tests b/shell/hush_test/hush-parsing/comment1.tests
new file mode 100755
index 000000000..d268860ff
--- /dev/null
+++ b/shell/hush_test/hush-parsing/comment1.tests
@@ -0,0 +1,2 @@
1echo Nothing: #should-not-be-echoed
2echo String: ""#should-be-echoed
diff --git a/shell/hush_test/hush-parsing/eol1.right b/shell/hush_test/hush-parsing/eol1.right
new file mode 100644
index 000000000..31c896f62
--- /dev/null
+++ b/shell/hush_test/hush-parsing/eol1.right
@@ -0,0 +1 @@
Done:0
diff --git a/shell/hush_test/hush-parsing/eol1.tests b/shell/hush_test/hush-parsing/eol1.tests
new file mode 100755
index 000000000..f1b55e8b8
--- /dev/null
+++ b/shell/hush_test/hush-parsing/eol1.tests
@@ -0,0 +1,18 @@
1# bug was that we treated <newline> as ';' in this line:
2true || echo foo |
3echo BAD1 | cat
4
5# variation on the same theme
6true || echo foo |
7# comment
8echo BAD2 | cat
9
10# variation on the same theme
11true || echo foo |
12
13echo BAD3 | cat
14
15# this should error out, but currently works in hush:
16#true || echo foo |;
17
18echo Done:$?
diff --git a/testsuite/bunzip2.tests b/testsuite/bunzip2.tests
index 827aee867..fcfce1a31 100755
--- a/testsuite/bunzip2.tests
+++ b/testsuite/bunzip2.tests
@@ -463,6 +463,24 @@ $ECHO -ne "\x40\xa0\x00\x8b\x12\xe8\xfb\xb7\x27\xaa\xd3\x36\x0c\xfc\xe1\x40"
463$ECHO -ne "\x01\xff\x8b\xb9\x22\x9c\x28\x48\x5f\xa5\xca\xf3\x80" 463$ECHO -ne "\x01\xff\x8b\xb9\x22\x9c\x28\x48\x5f\xa5\xca\xf3\x80"
464} 464}
465 465
466pbzip_4m_zeros() {
467$ECHO -ne "\x42\x5a\x68\x31\x31\x41\x59\x26\x53\x59\x63\xe3\xec\xa2\x00\x06"
468$ECHO -ne "\xe4\xc1\x00\xc0\x00\x02\x00\x00\x08\x20\x00\x30\xcc\x09\xaa\x69"
469$ECHO -ne "\x94\xa1\x36\xa9\x28\x4f\x17\x72\x45\x38\x50\x90\x63\xe3\xec\xa2"
470$ECHO -ne "\x42\x5a\x68\x31\x31\x41\x59\x26\x53\x59\x63\xe3\xec\xa2\x00\x06"
471$ECHO -ne "\xe4\xc1\x00\xc0\x00\x02\x00\x00\x08\x20\x00\x30\xcc\x09\xaa\x69"
472$ECHO -ne "\x94\xa1\x36\xa9\x28\x4f\x17\x72\x45\x38\x50\x90\x63\xe3\xec\xa2"
473$ECHO -ne "\x42\x5a\x68\x31\x31\x41\x59\x26\x53\x59\x63\xe3\xec\xa2\x00\x06"
474$ECHO -ne "\xe4\xc1\x00\xc0\x00\x02\x00\x00\x08\x20\x00\x30\xcc\x09\xaa\x69"
475$ECHO -ne "\x94\xa1\x36\xa9\x28\x4f\x17\x72\x45\x38\x50\x90\x63\xe3\xec\xa2"
476$ECHO -ne "\x42\x5a\x68\x31\x31\x41\x59\x26\x53\x59\x63\xe3\xec\xa2\x00\x06"
477$ECHO -ne "\xe4\xc1\x00\xc0\x00\x02\x00\x00\x08\x20\x00\x30\xcc\x09\xaa\x69"
478$ECHO -ne "\x94\xa1\x36\xa9\x28\x4f\x17\x72\x45\x38\x50\x90\x63\xe3\xec\xa2"
479$ECHO -ne "\x42\x5a\x68\x31\x31\x41\x59\x26\x53\x59\xc9\xb5\x21\xef\x00\x04"
480$ECHO -ne "\x8d\x40\x20\xc0\x00\x01\x00\x00\x08\x20\x00\x30\xcc\x05\x29\xa6"
481$ECHO -ne "\x4a\x11\xb1\x4a\x11\xe2\xee\x48\xa7\x0a\x12\x19\x36\xa4\x3d\xe0"
482}
483
466prep() { 484prep() {
467 rm -f t* 485 rm -f t*
468 hello_$ext >t1.$ext 486 hello_$ext >t1.$ext
@@ -520,9 +538,18 @@ if test "${0##*/}" = "bunzip2.tests"; then
520 if test1_bz2 | ${bb}bunzip2 >/dev/null \ 538 if test1_bz2 | ${bb}bunzip2 >/dev/null \
521 && test "`test1_bz2 | ${bb}bunzip2 | md5sum`" = "61bbeee4be9c6f110a71447f584fda7b -" 539 && test "`test1_bz2 | ${bb}bunzip2 | md5sum`" = "61bbeee4be9c6f110a71447f584fda7b -"
522 then 540 then
523 echo "PASS: $unpack: test bz2 file" 541 echo "PASS: $unpack: test_bz2 file"
542 else
543 echo "FAIL: $unpack: test_bz2 file"
544 FAILCOUNT=$((FAILCOUNT + 1))
545 fi
546
547 if pbzip_4m_zeros | ${bb}bunzip2 >/dev/null \
548 && test "`pbzip_4m_zeros | ${bb}bunzip2 | md5sum`" = "b5cfa9d6c8febd618f91ac2843d50a1c -"
549 then
550 echo "PASS: $unpack: pbzip_4m_zeros file"
524 else 551 else
525 echo "FAIL: $unpack: test bz2 file" 552 echo "FAIL: $unpack: pbzip_4m_zeros file"
526 FAILCOUNT=$((FAILCOUNT + 1)) 553 FAILCOUNT=$((FAILCOUNT + 1))
527 fi 554 fi
528fi 555fi
diff --git a/testsuite/date/date-@-works b/testsuite/date/date-@-works
new file mode 100644
index 000000000..03b4c7f03
--- /dev/null
+++ b/testsuite/date/date-@-works
@@ -0,0 +1,13 @@
1# Tests for time_t value (unix time format)
2
3# Just before DST switched off
4test x"Sun Oct 31 03:59:59 EEST 2010" = x"`TZ=EET-2EEST,M3.5.0/3,M10.5.0/4 busybox date -d @1288486799`"
5
6# Just after DST switched off
7test x"Sun Oct 31 03:00:01 EET 2010" = x"`TZ=EET-2EEST,M3.5.0/3,M10.5.0/4 busybox date -d @1288486801`"
8
9# Just before DST switched on
10test x"Sun Mar 28 02:59:59 EET 2010" = x"`TZ=EET-2EEST,M3.5.0/3,M10.5.0/4 busybox date -d @1269737999`"
11
12# Just after DST switched on
13test x"Sun Mar 28 04:00:01 EEST 2010" = x"`TZ=EET-2EEST,M3.5.0/3,M10.5.0/4 busybox date -d @1269738001`"
diff --git a/testsuite/du/du-h-works b/testsuite/du/du-h-works
index c18433c29..1c77b6552 100644
--- a/testsuite/du/du-h-works
+++ b/testsuite/du/du-h-works
@@ -1,4 +1,4 @@
1# FEATURE: CONFIG_FEATURE_HUMAN_READABLE 1# FEATURE: CONFIG_FEATURE_HUMAN_READABLE
2 2
3dd if=/dev/zero of=file bs=1M count=1 2>/dev/null 3dd if=/dev/zero of=file bs=1M count=1 2>/dev/null
4test x"`busybox du -h .`" = x"1.0M ." 4test x"`busybox du -h file`" = x"1.0M file"
diff --git a/testsuite/md5sum.tests b/testsuite/md5sum.tests
index 35ec67cb4..1068b083f 100755
--- a/testsuite/md5sum.tests
+++ b/testsuite/md5sum.tests
@@ -18,6 +18,11 @@ fi
18sum="$1" 18sum="$1"
19expected="$2" 19expected="$2"
20 20
21test -f "$bindir/.config" && . "$bindir/.config"
22
23test x"$CONFIG_FEATURE_FANCY_HEAD" != x"y" \
24&& { echo "SKIPPED: $sum"; exit 0; }
25
21text="The quick brown fox jumps over the lazy dog" 26text="The quick brown fox jumps over the lazy dog"
22text=`yes "$text" | head -c 9999` 27text=`yes "$text" | head -c 9999`
23 28
diff --git a/testsuite/patch.tests b/testsuite/patch.tests
index e482304f6..c604b9c1d 100755
--- a/testsuite/patch.tests
+++ b/testsuite/patch.tests
@@ -75,7 +75,7 @@ zxc
75testing "patch detects already applied hunk" \ 75testing "patch detects already applied hunk" \
76 'patch 2>&1; echo $?; cat input' \ 76 'patch 2>&1; echo $?; cat input' \
77"\ 77"\
78Possibly reversed hunk 1 at 2 78Possibly reversed hunk 1 at 4
79Hunk 1 FAILED 1/1. 79Hunk 1 FAILED 1/1.
80 abc 80 abc
81+def 81+def
@@ -103,7 +103,7 @@ def
103testing "patch detects already applied hunk at the EOF" \ 103testing "patch detects already applied hunk at the EOF" \
104 'patch 2>&1; echo $?; cat input' \ 104 'patch 2>&1; echo $?; cat input' \
105"\ 105"\
106Possibly reversed hunk 1 at 3 106Possibly reversed hunk 1 at 4
107Hunk 1 FAILED 1/1. 107Hunk 1 FAILED 1/1.
108 abc 108 abc
109 123 109 123
@@ -175,6 +175,43 @@ abc
175 123 175 123
176" \ 176" \
177 177
178# testing "test name" "command(s)" "expected result" "file input" "stdin"
179testing "patch at the beginning" \
180 'patch 2>&1; cat input' \
181"\
182patching file input
183111changed
184444
185555
186666
187777
188888
189999
190" \
191"\
192111
193222
194333
195444
196555
197666
198777
199888
200999
201" \
202"\
203--- input
204+++ input
205@@ -1,6 +1,4 @@
206-111
207-222
208-333
209+111changed
210 444
211 555
212 666
213" \
214
178rm input.orig 2>/dev/null 215rm input.orig 2>/dev/null
179 216
180exit $FAILCOUNT 217exit $FAILCOUNT
diff --git a/testsuite/testing.sh b/testsuite/testing.sh
index c7c9ca6af..e7e64e58b 100644
--- a/testsuite/testing.sh
+++ b/testsuite/testing.sh
@@ -87,6 +87,7 @@ testing()
87 87
88 $ECHO -ne "$3" > expected 88 $ECHO -ne "$3" > expected
89 $ECHO -ne "$4" > input 89 $ECHO -ne "$4" > input
90 [ -z "$VERBOSE" ] || echo ======================
90 [ -z "$VERBOSE" ] || echo "echo -ne '$4' >input" 91 [ -z "$VERBOSE" ] || echo "echo -ne '$4' >input"
91 [ -z "$VERBOSE" ] || echo "echo -ne '$5' | $2" 92 [ -z "$VERBOSE" ] || echo "echo -ne '$5' | $2"
92 $ECHO -ne "$5" | eval "$2" > actual 93 $ECHO -ne "$5" | eval "$2" > actual
diff --git a/util-linux/Config.src b/util-linux/Config.src
index c71b4de38..dbf2b0d85 100644
--- a/util-linux/Config.src
+++ b/util-linux/Config.src
@@ -40,6 +40,13 @@ config BLKID
40 WARNING: 40 WARNING:
41 With all submodules selected, it will add ~8k to busybox. 41 With all submodules selected, it will add ~8k to busybox.
42 42
43config FEATURE_BLKID_TYPE
44 bool "Print filesystem type"
45 default n
46 depends on BLKID
47 help
48 Show TYPE="filesystem type"
49
43config DMESG 50config DMESG
44 bool "dmesg" 51 bool "dmesg"
45 default y 52 default y
diff --git a/util-linux/acpid.c b/util-linux/acpid.c
index 0b227a8ae..ce4c98ebe 100644
--- a/util-linux/acpid.c
+++ b/util-linux/acpid.c
@@ -16,9 +16,9 @@ enum {
16 OPT_e = (1 << 2), 16 OPT_e = (1 << 2),
17 OPT_f = (1 << 3), 17 OPT_f = (1 << 3),
18 OPT_l = (1 << 4), 18 OPT_l = (1 << 4),
19 OPT_p = (1 << 5) * ENABLE_FEATURE_PIDFILE, 19 OPT_a = (1 << 5),
20 OPT_a = (1 << 6), 20 OPT_M = (1 << 6),
21 OPT_M = (1 << 7), 21 OPT_p = (1 << 7) * ENABLE_FEATURE_PIDFILE,
22}; 22};
23 23
24struct acpi_event { 24struct acpi_event {
@@ -199,8 +199,9 @@ int acpid_main(int argc UNUSED_PARAM, char **argv)
199 INIT_G(); 199 INIT_G();
200 200
201 opt_complementary = "df:e--e"; 201 opt_complementary = "df:e--e";
202 opts = getopt32(argv, "c:de:fl:p:a:M:" IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"), 202 opts = getopt32(argv, "c:de:fl:a:M:" IF_FEATURE_PIDFILE("p:") IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
203 &opt_dir, &opt_input, &opt_logfile, &opt_pidfile, &opt_action, &opt_map 203 &opt_dir, &opt_input, &opt_logfile, &opt_action, &opt_map
204 IF_FEATURE_PIDFILE(, &opt_pidfile)
204 IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL) 205 IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL)
205 ); 206 );
206 207
diff --git a/util-linux/blkid.c b/util-linux/blkid.c
index 4ce44b144..fe88fb31d 100644
--- a/util-linux/blkid.c
+++ b/util-linux/blkid.c
@@ -10,9 +10,16 @@
10#include "libbb.h" 10#include "libbb.h"
11#include "volume_id.h" 11#include "volume_id.h"
12 12
13//TODO: extend to take BLOCKDEV args, and show TYPE="fstype"
14
13int blkid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 15int blkid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
14int blkid_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 16int blkid_main(int argc UNUSED_PARAM, char **argv)
15{ 17{
18 while (*++argv) {
19 /* Note: bogus device names don't cause any error messages */
20 add_to_uuid_cache(*argv);
21 }
22
16 display_uuid_cache(); 23 display_uuid_cache();
17 return 0; 24 return 0;
18} 25}
diff --git a/util-linux/fbset.c b/util-linux/fbset.c
index 07c8f55d1..77cc1fc12 100644
--- a/util-linux/fbset.c
+++ b/util-linux/fbset.c
@@ -26,7 +26,7 @@ enum {
26 26
27struct fb_bitfield { 27struct fb_bitfield {
28 uint32_t offset; /* beginning of bitfield */ 28 uint32_t offset; /* beginning of bitfield */
29 uint32_t length; /* length of bitfield */ 29 uint32_t length; /* length of bitfield */
30 uint32_t msb_right; /* !=0: Most significant bit is right */ 30 uint32_t msb_right; /* !=0: Most significant bit is right */
31}; 31};
32struct fb_var_screeninfo { 32struct fb_var_screeninfo {
@@ -52,7 +52,7 @@ struct fb_var_screeninfo {
52 uint32_t height; /* height of picture in mm */ 52 uint32_t height; /* height of picture in mm */
53 uint32_t width; /* width of picture in mm */ 53 uint32_t width; /* width of picture in mm */
54 54
55 uint32_t accel_flags; /* acceleration flags (hints) */ 55 uint32_t accel_flags; /* acceleration flags (hints) */
56 56
57 /* Timing: All values in pixclocks, except pixclock (of course) */ 57 /* Timing: All values in pixclocks, except pixclock (of course) */
58 uint32_t pixclock; /* pixel clock in ps (pico seconds) */ 58 uint32_t pixclock; /* pixel clock in ps (pico seconds) */
@@ -317,7 +317,7 @@ static int read_mode_db(struct fb_var_screeninfo *base, const char *fn,
317 } 317 }
318 case 4: 318 case 4:
319 case 5: 319 case 5:
320 case 6: { 320 case 6: {
321 static const uint32_t syncs[] = {FB_SYNC_VERT_HIGH_ACT, FB_SYNC_HOR_HIGH_ACT, FB_SYNC_COMP_HIGH_ACT}; 321 static const uint32_t syncs[] = {FB_SYNC_VERT_HIGH_ACT, FB_SYNC_HOR_HIGH_ACT, FB_SYNC_COMP_HIGH_ACT};
322 ss(&base->sync, syncs[i-4], p, "low"); 322 ss(&base->sync, syncs[i-4], p, "low");
323//bb_info_msg("SYNC[%s]", p); 323//bb_info_msg("SYNC[%s]", p);
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c
index 3f2e0d3ae..02785ab85 100644
--- a/util-linux/fdisk.c
+++ b/util-linux/fdisk.c
@@ -662,6 +662,7 @@ STATIC_OSF void bsd_select(void);
662STATIC_OSF void xbsd_print_disklabel(int); 662STATIC_OSF void xbsd_print_disklabel(int);
663#include "fdisk_osf.c" 663#include "fdisk_osf.c"
664 664
665STATIC_GPT void gpt_list_table(int xtra);
665#include "fdisk_gpt.c" 666#include "fdisk_gpt.c"
666 667
667#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL 668#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
diff --git a/util-linux/hexdump.c b/util-linux/hexdump.c
index 8c4d521ab..a38fe05e7 100644
--- a/util-linux/hexdump.c
+++ b/util-linux/hexdump.c
@@ -4,7 +4,7 @@
4 * Based on code from util-linux v 2.11l 4 * Based on code from util-linux v 2.11l
5 * 5 *
6 * Copyright (c) 1989 6 * Copyright (c) 1989
7 * The Regents of the University of California. All rights reserved. 7 * The Regents of the University of California. All rights reserved.
8 * 8 *
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 */
@@ -32,11 +32,11 @@ static void bb_dump_addfile(dumper_t *dumper, char *name)
32} 32}
33 33
34static const char *const add_strings[] = { 34static const char *const add_strings[] = {
35 "\"%07.7_ax \" 16/1 \"%03o \" \"\\n\"", /* b */ 35 "\"%07.7_ax \" 16/1 \"%03o \" \"\\n\"", /* b */
36 "\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"", /* c */ 36 "\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"", /* c */
37 "\"%07.7_ax \" 8/2 \" %05u \" \"\\n\"", /* d */ 37 "\"%07.7_ax \" 8/2 \" %05u \" \"\\n\"", /* d */
38 "\"%07.7_ax \" 8/2 \" %06o \" \"\\n\"", /* o */ 38 "\"%07.7_ax \" 8/2 \" %06o \" \"\\n\"", /* o */
39 "\"%07.7_ax \" 8/2 \" %04x \" \"\\n\"", /* x */ 39 "\"%07.7_ax \" 8/2 \" %04x \" \"\\n\"", /* x */
40}; 40};
41 41
42static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\""; 42static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\"";
diff --git a/util-linux/ipcrm.c b/util-linux/ipcrm.c
index 731216c06..e597ed637 100644
--- a/util-linux/ipcrm.c
+++ b/util-linux/ipcrm.c
@@ -40,7 +40,7 @@ typedef enum type_id {
40 MSG 40 MSG
41} type_id; 41} type_id;
42 42
43static int remove_ids(type_id type, int argc, char **argv) 43static int remove_ids(type_id type, char **argv)
44{ 44{
45 unsigned long id; 45 unsigned long id;
46 int nb_errors = 0; 46 int nb_errors = 0;
@@ -48,7 +48,7 @@ static int remove_ids(type_id type, int argc, char **argv)
48 48
49 arg.val = 0; 49 arg.val = 0;
50 50
51 while (argc) { 51 while (argv[0]) {
52 id = bb_strtoul(argv[0], NULL, 10); 52 id = bb_strtoul(argv[0], NULL, 10);
53 if (errno || id > INT_MAX) { 53 if (errno || id > INT_MAX) {
54 bb_error_msg("invalid id: %s", argv[0]); 54 bb_error_msg("invalid id: %s", argv[0]);
@@ -67,7 +67,6 @@ static int remove_ids(type_id type, int argc, char **argv)
67 nb_errors++; 67 nb_errors++;
68 } 68 }
69 } 69 }
70 argc--;
71 argv++; 70 argv++;
72 } 71 }
73 72
@@ -109,7 +108,7 @@ int ipcrm_main(int argc, char **argv)
109 else if (w == 'e') 108 else if (w == 'e')
110 what = SEM; 109 what = SEM;
111 110
112 if (remove_ids(what, argc-2, &argv[2])) 111 if (remove_ids(what, &argv[2]))
113 fflush_stdout_and_exit(EXIT_FAILURE); 112 fflush_stdout_and_exit(EXIT_FAILURE);
114 printf("resource(s) deleted\n"); 113 printf("resource(s) deleted\n");
115 return 0; 114 return 0;
diff --git a/util-linux/more.c b/util-linux/more.c
index 1fd6f9ee8..c424a0e4b 100644
--- a/util-linux/more.c
+++ b/util-linux/more.c
@@ -29,16 +29,20 @@ struct globals {
29#define new_settings (G.new_settings ) 29#define new_settings (G.new_settings )
30#define cin_fileno (G.cin_fileno ) 30#define cin_fileno (G.cin_fileno )
31 31
32#define setTermSettings(fd, argp) do { \ 32#define setTermSettings(fd, argp) \
33 if (ENABLE_FEATURE_USE_TERMIOS) tcsetattr(fd, TCSANOW, argp); \ 33do { \
34 } while (0) 34 if (ENABLE_FEATURE_USE_TERMIOS) \
35 tcsetattr(fd, TCSANOW, argp); \
36} while (0)
35#define getTermSettings(fd, argp) tcgetattr(fd, argp) 37#define getTermSettings(fd, argp) tcgetattr(fd, argp)
36 38
37static void gotsig(int sig UNUSED_PARAM) 39static void gotsig(int sig UNUSED_PARAM)
38{ 40{
39 bb_putchar('\n'); 41 /* bb_putchar_stderr doesn't use stdio buffering,
42 * therefore it is safe in signal handler */
43 bb_putchar_stderr('\n');
40 setTermSettings(cin_fileno, &initial_settings); 44 setTermSettings(cin_fileno, &initial_settings);
41 exit(EXIT_FAILURE); 45 _exit(EXIT_FAILURE);
42} 46}
43 47
44#define CONVERTED_TAB_SIZE 8 48#define CONVERTED_TAB_SIZE 8
@@ -187,6 +191,7 @@ int more_main(int argc UNUSED_PARAM, char **argv)
187 } 191 }
188 /* My small mind cannot fathom backspaces and UTF-8 */ 192 /* My small mind cannot fathom backspaces and UTF-8 */
189 putchar(c); 193 putchar(c);
194 die_if_ferror_stdout(); /* if tty was destroyed (closed xterm, etc) */
190 } 195 }
191 fclose(file); 196 fclose(file);
192 fflush_all(); 197 fflush_all();
diff --git a/util-linux/umount.c b/util-linux/umount.c
index 78c603856..5597d9eba 100644
--- a/util-linux/umount.c
+++ b/util-linux/umount.c
@@ -9,39 +9,10 @@
9 */ 9 */
10#include <mntent.h> 10#include <mntent.h>
11#include <sys/mount.h> 11#include <sys/mount.h>
12/* Make sure we have all the new mount flags we actually try to use. */
13#ifndef MS_BIND
14# define MS_BIND (1 << 12)
15#endif
16#ifndef MS_MOVE
17# define MS_MOVE (1 << 13)
18#endif
19#ifndef MS_RECURSIVE
20# define MS_RECURSIVE (1 << 14)
21#endif
22#ifndef MS_SILENT
23# define MS_SILENT (1 << 15)
24#endif
25/* The shared subtree stuff, which went in around 2.6.15. */
26#ifndef MS_UNBINDABLE
27# define MS_UNBINDABLE (1 << 17)
28#endif
29#ifndef MS_PRIVATE
30# define MS_PRIVATE (1 << 18)
31#endif
32#ifndef MS_SLAVE
33# define MS_SLAVE (1 << 19)
34#endif
35#ifndef MS_SHARED
36# define MS_SHARED (1 << 20)
37#endif
38#ifndef MS_RELATIME
39# define MS_RELATIME (1 << 21)
40#endif
41#include "libbb.h" 12#include "libbb.h"
42 13
43
44#if defined(__dietlibc__) 14#if defined(__dietlibc__)
15// TODO: This does not belong here.
45/* 16.12.2006, Sampo Kellomaki (sampo@iki.fi) 16/* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
46 * dietlibc-0.30 does not have implementation of getmntent_r() */ 17 * dietlibc-0.30 does not have implementation of getmntent_r() */
47static struct mntent *getmntent_r(FILE* stream, struct mntent* result, 18static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
@@ -54,23 +25,17 @@ static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
54 25
55/* ignored: -v -d -t -i */ 26/* ignored: -v -d -t -i */
56#define OPTION_STRING "fldnra" "vdt:i" 27#define OPTION_STRING "fldnra" "vdt:i"
57#define OPT_FORCE (1 << 0) 28#define OPT_FORCE (1 << 0) // Same as MNT_FORCE
58#define OPT_LAZY (1 << 1) 29#define OPT_LAZY (1 << 1) // Same as MNT_DETACH
59#define OPT_FREELOOP (1 << 2) 30#define OPT_FREELOOP (1 << 2)
60#define OPT_NO_MTAB (1 << 3) 31#define OPT_NO_MTAB (1 << 3)
61#define OPT_REMOUNT (1 << 4) 32#define OPT_REMOUNT (1 << 4)
62#define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? (1 << 5) : 0) 33#define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? (1 << 5) : 0)
63 34
64// These constants from linux/fs.h must match OPT_FORCE and OPT_LAZY,
65// otherwise "doForce" trick below won't work!
66//#define MNT_FORCE 0x00000001 /* Attempt to forcibly umount */
67//#define MNT_DETACH 0x00000002 /* Just detach from the tree */
68
69int umount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 35int umount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
70int umount_main(int argc UNUSED_PARAM, char **argv) 36int umount_main(int argc UNUSED_PARAM, char **argv)
71{ 37{
72 int doForce; 38 int doForce;
73 char *const buf = xmalloc(4096); /* reducing stack usage */
74 struct mntent me; 39 struct mntent me;
75 FILE *fp; 40 FILE *fp;
76 char *fstype = NULL; 41 char *fstype = NULL;
@@ -85,6 +50,9 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
85 opt = getopt32(argv, OPTION_STRING, &fstype); 50 opt = getopt32(argv, OPTION_STRING, &fstype);
86 //argc -= optind; 51 //argc -= optind;
87 argv += optind; 52 argv += optind;
53
54 // MNT_FORCE and MNT_DETACH (from linux/fs.h) must match
55 // OPT_FORCE and OPT_LAZY, otherwise this trick won't work:
88 doForce = MAX((opt & OPT_FORCE), (opt & OPT_LAZY)); 56 doForce = MAX((opt & OPT_FORCE), (opt & OPT_LAZY));
89 57
90 /* Get a list of mount points from mtab. We read them all in now mostly 58 /* Get a list of mount points from mtab. We read them all in now mostly
@@ -101,7 +69,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
101 if (opt & OPT_ALL) 69 if (opt & OPT_ALL)
102 bb_error_msg_and_die("can't open '%s'", bb_path_mtab_file); 70 bb_error_msg_and_die("can't open '%s'", bb_path_mtab_file);
103 } else { 71 } else {
104 while (getmntent_r(fp, &me, buf, 4096)) { 72 while (getmntent_r(fp, &me, bb_common_bufsiz1, sizeof(bb_common_bufsiz1))) {
105 /* Match fstype if passed */ 73 /* Match fstype if passed */
106 if (!match_fstype(&me, fstype)) 74 if (!match_fstype(&me, fstype))
107 continue; 75 continue;
@@ -203,7 +171,6 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
203 free(mtl); 171 free(mtl);
204 mtl = m; 172 mtl = m;
205 } 173 }
206 free(buf);
207 } 174 }
208 175
209 return status; 176 return status;
diff --git a/util-linux/volume_id/cramfs.c b/util-linux/volume_id/cramfs.c
index b84a6f0b2..28e997043 100644
--- a/util-linux/volume_id/cramfs.c
+++ b/util-linux/volume_id/cramfs.c
@@ -51,7 +51,7 @@ int FAST_FUNC volume_id_probe_cramfs(struct volume_id *id /*,uint64_t off*/)
51 volume_id_set_label_string(id, cs->name, 16); 51 volume_id_set_label_string(id, cs->name, 16);
52 52
53// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 53// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
54// id->type = "cramfs"; 54 IF_FEATURE_BLKID_TYPE(id->type = "cramfs";)
55 return 0; 55 return 0;
56 } 56 }
57 57
diff --git a/util-linux/volume_id/ext.c b/util-linux/volume_id/ext.c
index 80c217f98..b5194a7b5 100644
--- a/util-linux/volume_id/ext.c
+++ b/util-linux/volume_id/ext.c
@@ -65,10 +65,12 @@ int FAST_FUNC volume_id_probe_ext(struct volume_id *id /*,uint64_t off*/)
65 volume_id_set_uuid(id, es->uuid, UUID_DCE); 65 volume_id_set_uuid(id, es->uuid, UUID_DCE);
66 dbg("ext: label '%s' uuid '%s'", id->label, id->uuid); 66 dbg("ext: label '%s' uuid '%s'", id->label, id->uuid);
67 67
68// if ((le32_to_cpu(es->feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) 68#if ENABLE_FEATURE_BLKID_TYPE
69// id->type = "ext3"; 69 if ((le32_to_cpu(es->feature_compat) & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0)
70// else 70 id->type = "ext3";
71// id->type = "ext2"; 71 else
72 id->type = "ext2";
73#endif
72 74
73 return 0; 75 return 0;
74} 76}
diff --git a/util-linux/volume_id/fat.c b/util-linux/volume_id/fat.c
index b0f427c74..904fbb201 100644
--- a/util-linux/volume_id/fat.c
+++ b/util-linux/volume_id/fat.c
@@ -332,7 +332,7 @@ int FAST_FUNC volume_id_probe_vfat(struct volume_id *id /*,uint64_t fat_partitio
332 332
333 ret: 333 ret:
334// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 334// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
335// id->type = "vfat"; 335 IF_FEATURE_BLKID_TYPE(id->type = "vfat";)
336 336
337 return 0; 337 return 0;
338} 338}
diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c
index bf32e6a8c..7c9930543 100644
--- a/util-linux/volume_id/get_devname.c
+++ b/util-linux/volume_id/get_devname.c
@@ -19,14 +19,22 @@ static struct uuidCache_s {
19 char *device; 19 char *device;
20 char *label; 20 char *label;
21 char *uc_uuid; /* prefix makes it easier to grep for */ 21 char *uc_uuid; /* prefix makes it easier to grep for */
22 IF_FEATURE_BLKID_TYPE(const char *type;)
22} *uuidCache; 23} *uuidCache;
23 24
25#if !ENABLE_FEATURE_BLKID_TYPE
26#define get_label_uuid(fd, label, uuid, type) \
27 get_label_uuid(fd, label, uuid)
28#define uuidcache_addentry(device, label, uuid, type) \
29 uuidcache_addentry(device, label, uuid)
30#endif
31
24/* Returns !0 on error. 32/* Returns !0 on error.
25 * Otherwise, returns malloc'ed strings for label and uuid 33 * Otherwise, returns malloc'ed strings for label and uuid
26 * (and they can't be NULL, although they can be ""). 34 * (and they can't be NULL, although they can be "").
27 * NB: closes fd. */ 35 * NB: closes fd. */
28static int 36static int
29get_label_uuid(int fd, char **label, char **uuid) 37get_label_uuid(int fd, char **label, char **uuid, const char **type)
30{ 38{
31 int rv = 1; 39 int rv = 1;
32 uint64_t size; 40 uint64_t size;
@@ -44,7 +52,12 @@ get_label_uuid(int fd, char **label, char **uuid)
44 if (vid->label[0] != '\0' || vid->uuid[0] != '\0') { 52 if (vid->label[0] != '\0' || vid->uuid[0] != '\0') {
45 *label = xstrndup(vid->label, sizeof(vid->label)); 53 *label = xstrndup(vid->label, sizeof(vid->label));
46 *uuid = xstrndup(vid->uuid, sizeof(vid->uuid)); 54 *uuid = xstrndup(vid->uuid, sizeof(vid->uuid));
55#if ENABLE_FEATURE_BLKID_TYPE
56 *type = vid->type;
57 dbg("found label '%s', uuid '%s', type '%s'", *label, *uuid, *type);
58#else
47 dbg("found label '%s', uuid '%s'", *label, *uuid); 59 dbg("found label '%s', uuid '%s'", *label, *uuid);
60#endif
48 rv = 0; 61 rv = 0;
49 } 62 }
50 ret: 63 ret:
@@ -54,7 +67,7 @@ get_label_uuid(int fd, char **label, char **uuid)
54 67
55/* NB: we take ownership of (malloc'ed) label and uuid */ 68/* NB: we take ownership of (malloc'ed) label and uuid */
56static void 69static void
57uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uuid) 70uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uuid, const char *type)
58{ 71{
59 struct uuidCache_s *last; 72 struct uuidCache_s *last;
60 73
@@ -72,6 +85,7 @@ uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uu
72 last->device = device; 85 last->device = device;
73 last->label = label; 86 last->label = label;
74 last->uc_uuid = uuid; 87 last->uc_uuid = uuid;
88 IF_FEATURE_BLKID_TYPE(last->type = type;)
75} 89}
76 90
77/* If get_label_uuid() on device_name returns success, 91/* If get_label_uuid() on device_name returns success,
@@ -83,10 +97,6 @@ uuidcache_check_device(const char *device,
83 void *userData UNUSED_PARAM, 97 void *userData UNUSED_PARAM,
84 int depth UNUSED_PARAM) 98 int depth UNUSED_PARAM)
85{ 99{
86 char *uuid = uuid; /* for compiler */
87 char *label = label;
88 int fd;
89
90 /* note: this check rejects links to devices, among other nodes */ 100 /* note: this check rejects links to devices, among other nodes */
91 if (!S_ISBLK(statbuf->st_mode)) 101 if (!S_ISBLK(statbuf->st_mode))
92 return TRUE; 102 return TRUE;
@@ -99,21 +109,15 @@ uuidcache_check_device(const char *device,
99 if (major(statbuf->st_rdev) == 2) 109 if (major(statbuf->st_rdev) == 2)
100 return TRUE; 110 return TRUE;
101 111
102 fd = open(device, O_RDONLY); 112 add_to_uuid_cache(device);
103 if (fd < 0)
104 return TRUE;
105 113
106 /* get_label_uuid() closes fd in all cases (success & failure) */
107 if (get_label_uuid(fd, &label, &uuid) == 0) {
108 /* uuidcache_addentry() takes ownership of all three params */
109 uuidcache_addentry(xstrdup(device), /*ma, mi,*/ label, uuid);
110 }
111 return TRUE; 114 return TRUE;
112} 115}
113 116
114static void 117static void
115uuidcache_init(void) 118uuidcache_init(void)
116{ 119{
120 dbg("DBG: uuidCache=%x, uuidCache");
117 if (uuidCache) 121 if (uuidCache)
118 return; 122 return;
119 123
@@ -223,11 +227,38 @@ void display_uuid_cache(void)
223 printf(" LABEL=\"%s\"", u->label); 227 printf(" LABEL=\"%s\"", u->label);
224 if (u->uc_uuid[0]) 228 if (u->uc_uuid[0])
225 printf(" UUID=\"%s\"", u->uc_uuid); 229 printf(" UUID=\"%s\"", u->uc_uuid);
230#if ENABLE_FEATURE_BLKID_TYPE
231 if (u->type)
232 printf(" TYPE=\"%s\"", u->type);
233#endif
226 bb_putchar('\n'); 234 bb_putchar('\n');
227 u = u->next; 235 u = u->next;
228 } 236 }
229} 237}
230 238
239int add_to_uuid_cache(const char *device)
240{
241 char *uuid = uuid; /* for compiler */
242 char *label = label;
243#if ENABLE_FEATURE_BLKID_TYPE
244 const char *type = type;
245#endif
246 int fd;
247
248 fd = open(device, O_RDONLY);
249 if (fd < 0)
250 return 0;
251
252 /* get_label_uuid() closes fd in all cases (success & failure) */
253 if (get_label_uuid(fd, &label, &uuid, &type) == 0) {
254 /* uuidcache_addentry() takes ownership of all four params */
255 uuidcache_addentry(xstrdup(device), /*ma, mi,*/ label, uuid, type);
256 return 1;
257 }
258 return 0;
259}
260
261
231/* Used by mount and findfs */ 262/* Used by mount and findfs */
232 263
233char *get_devname_from_label(const char *spec) 264char *get_devname_from_label(const char *spec)
diff --git a/util-linux/volume_id/hfs.c b/util-linux/volume_id/hfs.c
index cf7585138..f3f19dba7 100644
--- a/util-linux/volume_id/hfs.c
+++ b/util-linux/volume_id/hfs.c
@@ -195,7 +195,7 @@ int FAST_FUNC volume_id_probe_hfs_hfsplus(struct volume_id *id /*,uint64_t off*/
195 195
196 volume_id_set_uuid(id, hfs->finder_info.id, UUID_HFS); 196 volume_id_set_uuid(id, hfs->finder_info.id, UUID_HFS);
197// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 197// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
198// id->type = "hfs"; 198 IF_FEATURE_BLKID_TYPE(id->type = "hfs";)
199 199
200 return 0; 200 return 0;
201 201
diff --git a/util-linux/volume_id/iso9660.c b/util-linux/volume_id/iso9660.c
index 1519de496..1d7693a9c 100644
--- a/util-linux/volume_id/iso9660.c
+++ b/util-linux/volume_id/iso9660.c
@@ -114,7 +114,7 @@ int FAST_FUNC volume_id_probe_iso9660(struct volume_id *id /*,uint64_t off*/)
114 114
115 found: 115 found:
116// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 116// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
117// id->type = "iso9660"; 117 IF_FEATURE_BLKID_TYPE(id->type = "iso9660";)
118 118
119 return 0; 119 return 0;
120} 120}
diff --git a/util-linux/volume_id/jfs.c b/util-linux/volume_id/jfs.c
index eb7a44872..5333af2c3 100644
--- a/util-linux/volume_id/jfs.c
+++ b/util-linux/volume_id/jfs.c
@@ -54,7 +54,7 @@ int FAST_FUNC volume_id_probe_jfs(struct volume_id *id /*,uint64_t off*/)
54 volume_id_set_uuid(id, js->uuid, UUID_DCE); 54 volume_id_set_uuid(id, js->uuid, UUID_DCE);
55 55
56// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 56// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
57// id->type = "jfs"; 57 IF_FEATURE_BLKID_TYPE(id->type = "jfs";)
58 58
59 return 0; 59 return 0;
60} 60}
diff --git a/util-linux/volume_id/linux_raid.c b/util-linux/volume_id/linux_raid.c
index e1c86369d..761e54f9f 100644
--- a/util-linux/volume_id/linux_raid.c
+++ b/util-linux/volume_id/linux_raid.c
@@ -75,7 +75,7 @@ int FAST_FUNC volume_id_probe_linux_raid(struct volume_id *id /*,uint64_t off*/,
75 75
76 dbg("found raid signature"); 76 dbg("found raid signature");
77// volume_id_set_usage(id, VOLUME_ID_RAID); 77// volume_id_set_usage(id, VOLUME_ID_RAID);
78// id->type = "linux_raid_member"; 78 IF_FEATURE_BLKID_TYPE(id->type = "linux_raid_member";)
79 79
80 return 0; 80 return 0;
81} 81}
diff --git a/util-linux/volume_id/linux_swap.c b/util-linux/volume_id/linux_swap.c
index 574354611..62d588522 100644
--- a/util-linux/volume_id/linux_swap.c
+++ b/util-linux/volume_id/linux_swap.c
@@ -55,6 +55,7 @@ int FAST_FUNC volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/)
55 if (memcmp(buf, "SWAPSPACE2", 10) == 0 55 if (memcmp(buf, "SWAPSPACE2", 10) == 0
56 || memcmp(buf, "S1SUSPEND", 9) == 0 56 || memcmp(buf, "S1SUSPEND", 9) == 0
57 || memcmp(buf, "S2SUSPEND", 9) == 0 57 || memcmp(buf, "S2SUSPEND", 9) == 0
58 || memcmp(buf, "LINHIB0001", 10) == 0
58 || memcmp(buf, "ULSUSPEND", 9) == 0 59 || memcmp(buf, "ULSUSPEND", 9) == 0
59 ) { 60 ) {
60 sw = volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2)); 61 sw = volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2));
@@ -72,7 +73,7 @@ int FAST_FUNC volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/)
72 73
73found: 74found:
74// volume_id_set_usage(id, VOLUME_ID_OTHER); 75// volume_id_set_usage(id, VOLUME_ID_OTHER);
75// id->type = "swap"; 76 IF_FEATURE_BLKID_TYPE(id->type = "swap";)
76 77
77 return 0; 78 return 0;
78} 79}
diff --git a/util-linux/volume_id/luks.c b/util-linux/volume_id/luks.c
index 8ab09e381..f9b376672 100644
--- a/util-linux/volume_id/luks.c
+++ b/util-linux/volume_id/luks.c
@@ -94,7 +94,7 @@ int FAST_FUNC volume_id_probe_luks(struct volume_id *id /*,uint64_t off*/)
94 94
95// volume_id_set_usage(id, VOLUME_ID_CRYPTO); 95// volume_id_set_usage(id, VOLUME_ID_CRYPTO);
96 volume_id_set_uuid(id, header->uuid, UUID_DCE_STRING); 96 volume_id_set_uuid(id, header->uuid, UUID_DCE_STRING);
97// id->type = "crypto_LUKS"; 97 IF_FEATURE_BLKID_TYPE(id->type = "crypto_LUKS";)
98 98
99 return 0; 99 return 0;
100} 100}
diff --git a/util-linux/volume_id/ntfs.c b/util-linux/volume_id/ntfs.c
index 17b1fe8b3..547f141c9 100644
--- a/util-linux/volume_id/ntfs.c
+++ b/util-linux/volume_id/ntfs.c
@@ -188,7 +188,7 @@ int FAST_FUNC volume_id_probe_ntfs(struct volume_id *id /*,uint64_t off*/)
188 188
189 found: 189 found:
190// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 190// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
191// id->type = "ntfs"; 191 IF_FEATURE_BLKID_TYPE(id->type = "ntfs";)
192 192
193 return 0; 193 return 0;
194} 194}
diff --git a/util-linux/volume_id/ocfs2.c b/util-linux/volume_id/ocfs2.c
index e6c455965..fcdb15192 100644
--- a/util-linux/volume_id/ocfs2.c
+++ b/util-linux/volume_id/ocfs2.c
@@ -101,6 +101,6 @@ int FAST_FUNC volume_id_probe_ocfs2(struct volume_id *id /*,uint64_t off*/)
101 volume_id_set_label_string(id, os->s_label, OCFS2_MAX_VOL_LABEL_LEN < VOLUME_ID_LABEL_SIZE ? 101 volume_id_set_label_string(id, os->s_label, OCFS2_MAX_VOL_LABEL_LEN < VOLUME_ID_LABEL_SIZE ?
102 OCFS2_MAX_VOL_LABEL_LEN : VOLUME_ID_LABEL_SIZE); 102 OCFS2_MAX_VOL_LABEL_LEN : VOLUME_ID_LABEL_SIZE);
103 volume_id_set_uuid(id, os->s_uuid, UUID_DCE); 103 volume_id_set_uuid(id, os->s_uuid, UUID_DCE);
104// id->type = "ocfs2"; 104 IF_FEATURE_BLKID_TYPE(id->type = "ocfs2";)
105 return 0; 105 return 0;
106} 106}
diff --git a/util-linux/volume_id/reiserfs.c b/util-linux/volume_id/reiserfs.c
index 3120b29a0..67b4a1877 100644
--- a/util-linux/volume_id/reiserfs.c
+++ b/util-linux/volume_id/reiserfs.c
@@ -107,7 +107,7 @@ int FAST_FUNC volume_id_probe_reiserfs(struct volume_id *id /*,uint64_t off*/)
107 107
108 found: 108 found:
109// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 109// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
110// id->type = "reiserfs"; 110 IF_FEATURE_BLKID_TYPE(id->type = "reiserfs";)
111 111
112 return 0; 112 return 0;
113} 113}
diff --git a/util-linux/volume_id/romfs.c b/util-linux/volume_id/romfs.c
index 228e77a41..15653bedf 100644
--- a/util-linux/volume_id/romfs.c
+++ b/util-linux/volume_id/romfs.c
@@ -47,7 +47,7 @@ int FAST_FUNC volume_id_probe_romfs(struct volume_id *id /*,uint64_t off*/)
47 } 47 }
48 48
49// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 49// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
50// id->type = "romfs"; 50 IF_FEATURE_BLKID_TYPE(id->type = "romfs";)
51 return 0; 51 return 0;
52 } 52 }
53 53
diff --git a/util-linux/volume_id/sysv.c b/util-linux/volume_id/sysv.c
index e0fa20a8c..6eb96464d 100644
--- a/util-linux/volume_id/sysv.c
+++ b/util-linux/volume_id/sysv.c
@@ -99,7 +99,7 @@ int FAST_FUNC volume_id_probe_sysv(struct volume_id *id /*,uint64_t off*/)
99 if (vs->s_magic == cpu_to_le32(SYSV_MAGIC) || vs->s_magic == cpu_to_be32(SYSV_MAGIC)) { 99 if (vs->s_magic == cpu_to_le32(SYSV_MAGIC) || vs->s_magic == cpu_to_be32(SYSV_MAGIC)) {
100// volume_id_set_label_raw(id, vs->s_fname, 6); 100// volume_id_set_label_raw(id, vs->s_fname, 6);
101 volume_id_set_label_string(id, vs->s_fname, 6); 101 volume_id_set_label_string(id, vs->s_fname, 6);
102// id->type = "sysv"; 102 IF_FEATURE_BLKID_TYPE(id->type = "sysv");
103 goto found; 103 goto found;
104 } 104 }
105 } 105 }
@@ -112,7 +112,7 @@ int FAST_FUNC volume_id_probe_sysv(struct volume_id *id /*,uint64_t off*/)
112 if (xs->s_magic == cpu_to_le32(XENIX_MAGIC) || xs->s_magic == cpu_to_be32(XENIX_MAGIC)) { 112 if (xs->s_magic == cpu_to_le32(XENIX_MAGIC) || xs->s_magic == cpu_to_be32(XENIX_MAGIC)) {
113// volume_id_set_label_raw(id, xs->s_fname, 6); 113// volume_id_set_label_raw(id, xs->s_fname, 6);
114 volume_id_set_label_string(id, xs->s_fname, 6); 114 volume_id_set_label_string(id, xs->s_fname, 6);
115// id->type = "xenix"; 115 IF_FEATURE_BLKID_TYPE(id->type = "xenix";)
116 goto found; 116 goto found;
117 } 117 }
118 } 118 }
diff --git a/util-linux/volume_id/udf.c b/util-linux/volume_id/udf.c
index dd2573171..cd63c8d8a 100644
--- a/util-linux/volume_id/udf.c
+++ b/util-linux/volume_id/udf.c
@@ -167,7 +167,6 @@ anchor:
167 167
168 found: 168 found:
169// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 169// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
170// id->type = "udf"; 170 IF_FEATURE_BLKID_TYPE(id->type = "udf";)
171
172 return 0; 171 return 0;
173} 172}
diff --git a/util-linux/volume_id/volume_id_internal.h b/util-linux/volume_id/volume_id_internal.h
index 9b808ff6b..1c64046e5 100644
--- a/util-linux/volume_id/volume_id_internal.h
+++ b/util-linux/volume_id/volume_id_internal.h
@@ -80,7 +80,9 @@ struct volume_id {
80// char type_version[VOLUME_ID_FORMAT_SIZE]; 80// char type_version[VOLUME_ID_FORMAT_SIZE];
81// smallint usage_id; 81// smallint usage_id;
82// const char *usage; 82// const char *usage;
83// const char *type; 83#if ENABLE_FEATURE_BLKID_TYPE
84 const char *type;
85#endif
84}; 86};
85 87
86struct volume_id* FAST_FUNC volume_id_open_node(int fd); 88struct volume_id* FAST_FUNC volume_id_open_node(int fd);
diff --git a/util-linux/volume_id/xfs.c b/util-linux/volume_id/xfs.c
index 1017d077b..84746020e 100644
--- a/util-linux/volume_id/xfs.c
+++ b/util-linux/volume_id/xfs.c
@@ -54,7 +54,7 @@ int FAST_FUNC volume_id_probe_xfs(struct volume_id *id /*,uint64_t off*/)
54 volume_id_set_uuid(id, xs->uuid, UUID_DCE); 54 volume_id_set_uuid(id, xs->uuid, UUID_DCE);
55 55
56// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); 56// volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
57// id->type = "xfs"; 57 IF_FEATURE_BLKID_TYPE(id->type = "xfs";)
58 58
59 return 0; 59 return 0;
60} 60}