aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Kondik <steve@cyngn.com>2016-09-26 05:28:18 -0700
committerSteve Kondik <steve@cyngn.com>2016-09-26 05:40:17 -0700
commitb5e7cfb667a1dc94add27762e518a4ca3bc24157 (patch)
tree68f8a8ba5b1af182227cf3ba52989ef3221b252a
parent00a7af60ddbe98baa838326809f9b7293929c8b8 (diff)
parenta31c4a356fd541cdaf455bba9e723e6bdb01f8ea (diff)
downloadandroid_external_toybox-b5e7cfb667a1dc94add27762e518a4ca3bc24157.tar.gz
android_external_toybox-b5e7cfb667a1dc94add27762e518a4ca3bc24157.tar.bz2
android_external_toybox-b5e7cfb667a1dc94add27762e518a4ca3bc24157.zip
Merge branch 'master' of https://android.googlesource.com/platform/external/toybox into cm-14.0cm-14.0
Change-Id: I30f7024dc0b625c2a0b34907a640052592c3f8c1
-rw-r--r--.config14
-rw-r--r--Android.mk26
-rw-r--r--Config.in6
-rw-r--r--Makefile1
-rw-r--r--generated/config.h28
-rw-r--r--generated/flags.h446
-rw-r--r--generated/globals.h135
-rw-r--r--generated/help.h80
-rw-r--r--generated/newtoys.h46
-rw-r--r--generated/tags.h32
-rw-r--r--lib/args.c1
-rw-r--r--lib/help.c29
-rw-r--r--lib/lib.c218
-rw-r--r--lib/lib.h43
-rw-r--r--lib/llist.c29
-rw-r--r--lib/lsm.h2
-rw-r--r--lib/password.c2
-rw-r--r--lib/toyflags.h3
-rw-r--r--lib/xwrap.c104
-rw-r--r--main.c8
-rwxr-xr-xscripts/genconfig.sh2
-rwxr-xr-xscripts/make.sh171
-rw-r--r--scripts/mkflags.c21
-rw-r--r--scripts/runtest.sh8
-rwxr-xr-xtests/chattr.test7
-rwxr-xr-xtests/cmp.test6
-rw-r--r--tests/date.test8
-rwxr-xr-xtests/dd.test16
-rw-r--r--tests/file.test4
-rwxr-xr-xtests/getfattr.test21
-rwxr-xr-xtests/grep.test34
-rwxr-xr-xtests/md5sum.test8
-rwxr-xr-xtests/pgrep.test4
-rwxr-xr-xtests/pkill.test11
-rwxr-xr-xtests/printf.test6
-rwxr-xr-xtests/sed.test74
-rwxr-xr-xtests/setfattr.test21
-rwxr-xr-xtests/wc.test13
-rw-r--r--tests/xxd.test2
-rw-r--r--toys/android/load_policy.c5
-rw-r--r--toys/android/log.c58
-rw-r--r--toys/android/sendevent.c37
-rw-r--r--toys/android/start.c61
-rw-r--r--toys/example/test_human_readable.c2
-rw-r--r--toys/example/test_many_options.c2
-rw-r--r--toys/example/test_scankey.c2
-rw-r--r--toys/lsb/md5sum.c210
-rw-r--r--toys/net/README1
-rw-r--r--toys/net/ifconfig.c (renamed from toys/other/ifconfig.c)0
-rw-r--r--toys/net/netcat.c (renamed from toys/other/netcat.c)0
-rw-r--r--toys/net/netstat.c383
-rw-r--r--toys/net/rfkill.c (renamed from toys/other/rfkill.c)2
-rw-r--r--toys/net/tunctl.c53
-rw-r--r--toys/other/blockdev.c2
-rw-r--r--toys/other/fsfreeze.c2
-rw-r--r--toys/other/fsync.c4
-rw-r--r--toys/other/insmod.c2
-rw-r--r--toys/other/lspci.c6
-rw-r--r--toys/other/makedevs.c6
-rw-r--r--toys/other/nsenter.c3
-rw-r--r--toys/other/oneit.c6
-rw-r--r--toys/other/pwdx.c14
-rw-r--r--toys/other/setfattr.c47
-rw-r--r--toys/other/shred.c2
-rw-r--r--toys/other/stat.c128
-rw-r--r--toys/other/sysctl.c2
-rw-r--r--toys/other/timeout.c3
-rw-r--r--toys/other/truncate.c6
-rw-r--r--toys/other/xxd.c19
-rw-r--r--toys/pending/arp.c2
-rw-r--r--toys/pending/chrt.c92
-rw-r--r--toys/pending/crond.c5
-rw-r--r--toys/pending/crontab.c9
-rw-r--r--toys/pending/dd.c422
-rw-r--r--toys/pending/dhcp.c4
-rw-r--r--toys/pending/dumpleases.c2
-rw-r--r--toys/pending/getfattr.c95
-rw-r--r--toys/pending/getty.c2
-rw-r--r--toys/pending/klogd.c2
-rw-r--r--toys/pending/last.c2
-rw-r--r--toys/pending/lsof.c4
-rw-r--r--toys/pending/mdev.c2
-rw-r--r--toys/pending/modprobe.c4
-rw-r--r--toys/pending/netstat.c664
-rw-r--r--toys/pending/openvt.c2
-rw-r--r--toys/pending/sulogin.c2
-rw-r--r--toys/pending/tftp.c2
-rw-r--r--toys/posix/chgrp.c4
-rw-r--r--toys/posix/cmp.c12
-rw-r--r--toys/posix/comm.c3
-rw-r--r--toys/posix/cp.c30
-rw-r--r--toys/posix/cut.c8
-rw-r--r--toys/posix/echo.c5
-rw-r--r--toys/posix/false.c2
-rw-r--r--toys/posix/file.c (renamed from toys/pending/file.c)168
-rw-r--r--toys/posix/find.c12
-rw-r--r--toys/posix/grep.c21
-rw-r--r--toys/posix/id.c4
-rw-r--r--toys/posix/ls.c89
-rw-r--r--toys/posix/nohup.c2
-rw-r--r--toys/posix/patch.c20
-rw-r--r--toys/posix/printf.c11
-rw-r--r--toys/posix/ps.c292
-rw-r--r--toys/posix/sed.c99
-rw-r--r--toys/posix/tail.c4
-rw-r--r--toys/posix/tee.c4
-rw-r--r--toys/posix/touch.c2
-rw-r--r--toys/posix/true.c4
-rw-r--r--toys/posix/uudecode.c2
-rw-r--r--toys/posix/uuencode.c2
-rw-r--r--toys/posix/wc.c73
-rw-r--r--www/code.html61
-rw-r--r--[-rwxr-xr-x]www/design.html54
-rwxr-xr-xwww/faq.html42
-rwxr-xr-xwww/roadmap.html25
115 files changed, 3167 insertions, 1963 deletions
diff --git a/.config b/.config
index b83ec1f4..0459e0a3 100644
--- a/.config
+++ b/.config
@@ -43,6 +43,7 @@ CONFIG_ECHO=y
CONFIG_ENV=y
CONFIG_EXPAND=y
CONFIG_FALSE=y
+CONFIG_FILE=y
CONFIG_FIND=y
CONFIG_GREP=y
CONFIG_EGREP=y
@@ -115,6 +116,7 @@ CONFIG_ARP=y
# CONFIG_BOOTCHARTD is not set
# CONFIG_BRCTL is not set
# CONFIG_COMPRESS is not set
+CONFIG_CHRT=y
# CONFIG_GZIP is not set
# CONFIG_GZIP_D is not set
# CONFIG_DECOMPRESS is not set
@@ -135,6 +137,7 @@ CONFIG_FILE=y
# CONFIG_FOLD is not set
# CONFIG_FSCK is not set
CONFIG_FTPGET=y
+CONFIG_GETFATTR=y
# CONFIG_GETTY is not set
# CONFIG_GROUPADD is not set
# CONFIG_GROUPDEL is not set
@@ -167,6 +170,7 @@ CONFIG_ROUTE=y
# CONFIG_SH is not set
# CONFIG_EXIT is not set
# CONFIG_CD is not set
+CONFIG_SETFATTR=y
# CONFIG_SULOGIN is not set
# CONFIG_SYSLOGD is not set
CONFIG_TAR=y
@@ -266,6 +270,7 @@ CONFIG_NPROC=y
CONFIG_TASKSET=y
CONFIG_TIMEOUT=y
CONFIG_TRUNCATE=y
+CONFIG_TUNCTL=y
CONFIG_UPTIME=y
CONFIG_USLEEP=y
CONFIG_VCONFIG=y
@@ -283,6 +288,10 @@ CONFIG_HOSTNAME=y
CONFIG_KILLALL=y
CONFIG_MD5SUM=y
CONFIG_SHA1SUM=y
+CONFIG_SHA224SUM=y
+CONFIG_SHA256SUM=y
+CONFIG_SHA384SUM=y
+CONFIG_SHA512SUM=y
CONFIG_MKNOD=y
CONFIG_MKNOD_Z=y
CONFIG_MKTEMP=y
@@ -311,10 +320,14 @@ CONFIG_UMOUNT=y
CONFIG_GETENFORCE=y
CONFIG_GETPROP=y
CONFIG_LOAD_POLICY=y
+CONFIG_LOG=y
CONFIG_RESTORECON=y
CONFIG_RUNCON=y
+CONFIG_SENDEVENT=y
CONFIG_SETENFORCE=y
CONFIG_SETPROP=y
+CONFIG_START=y
+CONFIG_STOP=y
#
#
@@ -332,6 +345,7 @@ CONFIG_TOYBOX_FLOAT=y
CONFIG_TOYBOX_HELP=y
CONFIG_TOYBOX_HELP_DASHDASH=y
CONFIG_TOYBOX_I18N=y
+CONFIG_TOYBOX_LIBCRYPTO=y
# CONFIG_TOYBOX_FREE is not set
CONFIG_TOYBOX_NORECURSE=y
# CONFIG_TOYBOX_DEBUG is not set
diff --git a/Android.mk b/Android.mk
index e9db5802..5840f132 100644
--- a/Android.mk
+++ b/Android.mk
@@ -56,8 +56,7 @@ common_cflags += -DTOYBOX_VERSION='"$(toybox_version)"'
# To add a toy:
#
-# make menuconfig
-# # (Select the toy you want to add.)
+# Edit .config to enable the toy you want to add.
# make clean && make # Regenerate the generated files.
# # Edit LOCAL_SRC_FILES below to add the toy.
# # If you just want to use it as "toybox x" rather than "x", you can stop now.
@@ -82,10 +81,13 @@ LOCAL_SRC_FILES := \
toys/android/getenforce.c \
toys/android/getprop.c \
toys/android/load_policy.c \
+ toys/android/log.c \
toys/android/restorecon.c \
toys/android/runcon.c \
+ toys/android/sendevent.c \
toys/android/setenforce.c \
toys/android/setprop.c \
+ toys/android/start.c \
toys/lsb/dmesg.c \
toys/lsb/hostname.c \
toys/lsb/killall.c \
@@ -97,6 +99,11 @@ LOCAL_SRC_FILES := \
toys/lsb/seq.c \
toys/lsb/sync.c \
toys/lsb/umount.c \
+ toys/net/ifconfig.c \
+ toys/net/netcat.c \
+ toys/net/netstat.c \
+ toys/net/rfkill.c \
+ toys/net/tunctl.c \
toys/other/acpi.c \
toys/other/base64.c \
toys/other/blkid.c \
@@ -113,7 +120,6 @@ LOCAL_SRC_FILES := \
toys/other/fsfreeze.c \
toys/other/help.c \
toys/other/hwclock.c \
- toys/other/ifconfig.c \
toys/other/inotifyd.c \
toys/other/insmod.c \
toys/other/ionice.c \
@@ -127,7 +133,6 @@ LOCAL_SRC_FILES := \
toys/other/modinfo.c \
toys/other/mountpoint.c \
toys/other/nbd_client.c \
- toys/other/netcat.c \
toys/other/partprobe.c \
toys/other/pivot_root.c \
toys/other/pmap.c \
@@ -138,8 +143,8 @@ LOCAL_SRC_FILES := \
toys/other/realpath.c \
toys/other/reset.c \
toys/other/rev.c \
- toys/other/rfkill.c \
toys/other/rmmod.c \
+ toys/other/setfattr.c \
toys/other/setsid.c \
toys/other/stat.c \
toys/other/swapoff.c \
@@ -157,16 +162,16 @@ LOCAL_SRC_FILES := \
toys/other/xxd.c \
toys/other/yes.c \
toys/pending/arp.c \
+ toys/pending/chrt.c \
toys/pending/dd.c \
toys/pending/diff.c \
toys/pending/expr.c \
toys/pending/fdisk.c \
- toys/pending/file.c \
toys/pending/ftpget.c \
+ toys/pending/getfattr.c \
toys/pending/host.c \
toys/pending/lsof.c \
toys/pending/more.c \
- toys/pending/netstat.c \
toys/pending/resize.c \
toys/pending/route.c \
toys/pending/tar.c \
@@ -195,6 +200,7 @@ LOCAL_SRC_FILES := \
toys/posix/env.c \
toys/posix/expand.c \
toys/posix/false.c \
+ toys/posix/file.c \
toys/posix/find.c \
toys/posix/grep.c \
toys/posix/head.c \
@@ -236,7 +242,7 @@ LOCAL_SRC_FILES := \
LOCAL_CFLAGS := $(common_cflags)
LOCAL_CLANG := true
-LOCAL_STATIC_LIBRARIES := libselinux
+LOCAL_STATIC_LIBRARIES := libselinux libcrypto_static
# This doesn't actually prevent us from dragging in libc++ at runtime
# because libnetd_client.so is C++.
@@ -262,7 +268,7 @@ include $(BUILD_HOST_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := main.c
LOCAL_STATIC_LIBRARIES := libtoybox
-LOCAL_SHARED_LIBRARIES := libcutils libselinux
+LOCAL_SHARED_LIBRARIES := libcutils libselinux libcrypto
LOCAL_CFLAGS := $(common_cflags)
LOCAL_CXX_STL := none
LOCAL_CLANG := true
@@ -316,6 +322,6 @@ LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_STEM := toybox
LOCAL_PACK_MODULE_RELOCATIONS := false
-LOCAL_STATIC_LIBRARIES := libc libtoybox libcutils libselinux libmincrypt liblog
+LOCAL_STATIC_LIBRARIES := libc libtoybox libcutils libselinux libcrypto_static liblog
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
diff --git a/Config.in b/Config.in
index 3c560f80..76b2ef1d 100644
--- a/Config.in
+++ b/Config.in
@@ -62,6 +62,12 @@ config TOYBOX_SMACK
endchoice
+config TOYBOX_LIBCRYPTO
+ bool "Use libcrypto (OpenSSL/BoringSSL)"
+ default n
+ help
+ Use faster hash functions out of exteral -lcrypto library.
+
config TOYBOX_FLOAT
bool "Floating point support"
default y
diff --git a/Makefile b/Makefile
index 711d6247..6c5dd0d4 100644
--- a/Makefile
+++ b/Makefile
@@ -55,6 +55,7 @@ change:
clean::
rm -rf toybox generated change .singleconfig*
+# If singlemake was in generated/ "make clean; make test_ls" wouldn't work.
distclean: clean
rm -f toybox_old .config* .singlemake
diff --git a/generated/config.h b/generated/config.h
index ec72aa08..236afcb5 100644
--- a/generated/config.h
+++ b/generated/config.h
@@ -70,6 +70,8 @@
#define USE_EXPAND(...) __VA_ARGS__
#define CFG_FALSE 1
#define USE_FALSE(...) __VA_ARGS__
+#define CFG_FILE 1
+#define USE_FILE(...) __VA_ARGS__
#define CFG_FIND 1
#define USE_FIND(...) __VA_ARGS__
#define CFG_GREP 1
@@ -206,6 +208,8 @@
#define USE_BRCTL(...)
#define CFG_COMPRESS 0
#define USE_COMPRESS(...)
+#define CFG_CHRT 1
+#define USE_CHRT(...) __VA_ARGS__
#define CFG_GZIP 0
#define USE_GZIP(...)
#define CFG_GZIP_D 0
@@ -246,6 +250,8 @@
#define USE_FSCK(...)
#define CFG_FTPGET 1
#define USE_FTPGET(...) __VA_ARGS__
+#define CFG_GETFATTR 1
+#define USE_GETFATTR(...) __VA_ARGS__
#define CFG_GETTY 0
#define USE_GETTY(...)
#define CFG_GROUPADD 0
@@ -310,6 +316,8 @@
#define USE_EXIT(...)
#define CFG_CD 0
#define USE_CD(...)
+#define CFG_SETFATTR 1
+#define USE_SETFATTR(...) __VA_ARGS__
#define CFG_SULOGIN 0
#define USE_SULOGIN(...)
#define CFG_SYSLOGD 0
@@ -500,6 +508,8 @@
#define USE_TIMEOUT(...) __VA_ARGS__
#define CFG_TRUNCATE 1
#define USE_TRUNCATE(...) __VA_ARGS__
+#define CFG_TUNCTL 1
+#define USE_TUNCTL(...) __VA_ARGS__
#define CFG_UPTIME 1
#define USE_UPTIME(...) __VA_ARGS__
#define CFG_USLEEP 1
@@ -526,6 +536,14 @@
#define USE_MD5SUM(...) __VA_ARGS__
#define CFG_SHA1SUM 1
#define USE_SHA1SUM(...) __VA_ARGS__
+#define CFG_SHA224SUM 1
+#define USE_SHA224SUM(...) __VA_ARGS__
+#define CFG_SHA256SUM 1
+#define USE_SHA256SUM(...) __VA_ARGS__
+#define CFG_SHA384SUM 1
+#define USE_SHA384SUM(...) __VA_ARGS__
+#define CFG_SHA512SUM 1
+#define USE_SHA512SUM(...) __VA_ARGS__
#define CFG_MKNOD 1
#define USE_MKNOD(...) __VA_ARGS__
#define CFG_MKNOD_Z 1
@@ -566,14 +584,22 @@
#define USE_GETPROP(...) __VA_ARGS__
#define CFG_LOAD_POLICY 1
#define USE_LOAD_POLICY(...) __VA_ARGS__
+#define CFG_LOG 1
+#define USE_LOG(...) __VA_ARGS__
#define CFG_RESTORECON 1
#define USE_RESTORECON(...) __VA_ARGS__
#define CFG_RUNCON 1
#define USE_RUNCON(...) __VA_ARGS__
+#define CFG_SENDEVENT 1
+#define USE_SENDEVENT(...) __VA_ARGS__
#define CFG_SETENFORCE 1
#define USE_SETENFORCE(...) __VA_ARGS__
#define CFG_SETPROP 1
#define USE_SETPROP(...) __VA_ARGS__
+#define CFG_START 1
+#define USE_START(...) __VA_ARGS__
+#define CFG_STOP 1
+#define USE_STOP(...) __VA_ARGS__
#define CFG_TOYBOX 1
#define USE_TOYBOX(...) __VA_ARGS__
#define CFG_TOYBOX_SUID 1
@@ -592,6 +618,8 @@
#define USE_TOYBOX_HELP_DASHDASH(...) __VA_ARGS__
#define CFG_TOYBOX_I18N 1
#define USE_TOYBOX_I18N(...) __VA_ARGS__
+#define CFG_TOYBOX_LIBCRYPTO 1
+#define USE_TOYBOX_LIBCRYPTO(...) __VA_ARGS__
#define CFG_TOYBOX_FREE 0
#define USE_TOYBOX_FREE(...)
#define CFG_TOYBOX_NORECURSE 1
diff --git a/generated/flags.h b/generated/flags.h
index fb0e4f31..a8293889 100644
--- a/generated/flags.h
+++ b/generated/flags.h
@@ -41,7 +41,7 @@
// arping <1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]
#undef OPTSTR_arping
-#define OPTSTR_arping 0
+#define OPTSTR_arping "<1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]"
#ifdef CLEANUP_arping
#undef CLEANUP_arping
#undef FOR_arping
@@ -78,7 +78,7 @@
// blkid
#undef OPTSTR_blkid
-#define OPTSTR_blkid 0
+#define OPTSTR_blkid 0
#ifdef CLEANUP_blkid
#undef CLEANUP_blkid
#undef FOR_blkid
@@ -105,7 +105,7 @@
// bootchartd
#undef OPTSTR_bootchartd
-#define OPTSTR_bootchartd 0
+#define OPTSTR_bootchartd 0
#ifdef CLEANUP_bootchartd
#undef CLEANUP_bootchartd
#undef FOR_bootchartd
@@ -113,7 +113,7 @@
// brctl <1
#undef OPTSTR_brctl
-#define OPTSTR_brctl 0
+#define OPTSTR_brctl "<1"
#ifdef CLEANUP_brctl
#undef CLEANUP_brctl
#undef FOR_brctl
@@ -121,7 +121,7 @@
// bunzip2 cftkv
#undef OPTSTR_bunzip2
-#define OPTSTR_bunzip2 0
+#define OPTSTR_bunzip2 "cftkv"
#ifdef CLEANUP_bunzip2
#undef CLEANUP_bunzip2
#undef FOR_bunzip2
@@ -134,7 +134,7 @@
// bzcat
#undef OPTSTR_bzcat
-#define OPTSTR_bzcat 0
+#define OPTSTR_bzcat 0
#ifdef CLEANUP_bzcat
#undef CLEANUP_bzcat
#undef FOR_bzcat
@@ -162,7 +162,7 @@
// catv vte
#undef OPTSTR_catv
-#define OPTSTR_catv 0
+#define OPTSTR_catv "vte"
#ifdef CLEANUP_catv
#undef CLEANUP_catv
#undef FOR_catv
@@ -173,7 +173,7 @@
// cd
#undef OPTSTR_cd
-#define OPTSTR_cd 0
+#define OPTSTR_cd 0
#ifdef CLEANUP_cd
#undef CLEANUP_cd
#undef FOR_cd
@@ -181,7 +181,7 @@
// chattr
#undef OPTSTR_chattr
-#define OPTSTR_chattr 0
+#define OPTSTR_chattr 0
#ifdef CLEANUP_chattr
#undef CLEANUP_chattr
#undef FOR_chattr
@@ -232,9 +232,25 @@
#undef FOR_chroot
#endif
+// chrt mp#bfiorR[!bfior] mp#bfiorR[!bfior]
+#undef OPTSTR_chrt
+#define OPTSTR_chrt "mp#bfiorR[!bfior]"
+#ifdef CLEANUP_chrt
+#undef CLEANUP_chrt
+#undef FOR_chrt
+#undef FLAG_R
+#undef FLAG_r
+#undef FLAG_o
+#undef FLAG_i
+#undef FLAG_f
+#undef FLAG_b
+#undef FLAG_p
+#undef FLAG_m
+#endif
+
// chvt <1
#undef OPTSTR_chvt
-#define OPTSTR_chvt 0
+#define OPTSTR_chvt "<1"
#ifdef CLEANUP_chvt
#undef CLEANUP_chvt
#undef FOR_chvt
@@ -255,15 +271,15 @@
// clear
#undef OPTSTR_clear
-#define OPTSTR_clear 0
+#define OPTSTR_clear 0
#ifdef CLEANUP_clear
#undef CLEANUP_clear
#undef FOR_clear
#endif
-// cmp <2>2ls <2>2ls
+// cmp <2>2ls[!ls] <2>2ls[!ls]
#undef OPTSTR_cmp
-#define OPTSTR_cmp "<2>2ls"
+#define OPTSTR_cmp "<2>2ls[!ls]"
#ifdef CLEANUP_cmp
#undef CLEANUP_cmp
#undef FOR_cmp
@@ -284,7 +300,7 @@
// compress zcd9lrg[-cd][!zgLr]
#undef OPTSTR_compress
-#define OPTSTR_compress 0
+#define OPTSTR_compress "zcd9lrg[-cd][!zgLr]"
#ifdef CLEANUP_compress
#undef CLEANUP_compress
#undef FOR_compress
@@ -299,7 +315,7 @@
// count
#undef OPTSTR_count
-#define OPTSTR_count 0
+#define OPTSTR_count 0
#ifdef CLEANUP_count
#undef CLEANUP_count
#undef FOR_count
@@ -352,7 +368,7 @@
// crond fbSl#<0=8d#<0L:c:[-bf][-LS][-ld]
#undef OPTSTR_crond
-#define OPTSTR_crond 0
+#define OPTSTR_crond "fbSl#<0=8d#<0L:c:[-bf][-LS][-ld]"
#ifdef CLEANUP_crond
#undef CLEANUP_crond
#undef FOR_crond
@@ -367,7 +383,7 @@
// crontab c:u:elr[!elr]
#undef OPTSTR_crontab
-#define OPTSTR_crontab 0
+#define OPTSTR_crontab "c:u:elr[!elr]"
#ifdef CLEANUP_crontab
#undef CLEANUP_crontab
#undef FOR_crontab
@@ -406,7 +422,7 @@
// dd
#undef OPTSTR_dd
-#define OPTSTR_dd 0
+#define OPTSTR_dd 0
#ifdef CLEANUP_dd
#undef CLEANUP_dd
#undef FOR_dd
@@ -414,7 +430,7 @@
// deallocvt >1
#undef OPTSTR_deallocvt
-#define OPTSTR_deallocvt 0
+#define OPTSTR_deallocvt ">1"
#ifdef CLEANUP_deallocvt
#undef CLEANUP_deallocvt
#undef FOR_deallocvt
@@ -436,7 +452,7 @@
// dhcp V:H:F:x*r:O*A#<0=20T#<0=3t#<0=3s:p:i:SBRCaovqnbf
#undef OPTSTR_dhcp
-#define OPTSTR_dhcp 0
+#define OPTSTR_dhcp "V:H:F:x*r:O*A#<0=20T#<0=3t#<0=3s:p:i:SBRCaovqnbf"
#ifdef CLEANUP_dhcp
#undef CLEANUP_dhcp
#undef FOR_dhcp
@@ -467,7 +483,7 @@
// dhcp6 r:A#<0T#<0t#<0s:p:i:SRvqnbf
#undef OPTSTR_dhcp6
-#define OPTSTR_dhcp6 0
+#define OPTSTR_dhcp6 "r:A#<0T#<0t#<0s:p:i:SRvqnbf"
#ifdef CLEANUP_dhcp6
#undef CLEANUP_dhcp6
#undef FOR_dhcp6
@@ -489,7 +505,7 @@
// dhcpd >1P#<0>65535fi:S46[!46]
#undef OPTSTR_dhcpd
-#define OPTSTR_dhcpd 0
+#define OPTSTR_dhcpd ">1P#<0>65535fi:S46[!46]"
#ifdef CLEANUP_dhcpd
#undef CLEANUP_dhcpd
#undef FOR_dhcpd
@@ -563,7 +579,7 @@
// dos2unix
#undef OPTSTR_dos2unix
-#define OPTSTR_dos2unix 0
+#define OPTSTR_dos2unix 0
#ifdef CLEANUP_dos2unix
#undef CLEANUP_dos2unix
#undef FOR_dos2unix
@@ -591,7 +607,7 @@
// dumpleases >0arf:[!ar]
#undef OPTSTR_dumpleases
-#define OPTSTR_dumpleases 0
+#define OPTSTR_dumpleases ">0arf:[!ar]"
#ifdef CLEANUP_dumpleases
#undef CLEANUP_dumpleases
#undef FOR_dumpleases
@@ -612,7 +628,7 @@
// eject >1stT[!tT]
#undef OPTSTR_eject
-#define OPTSTR_eject 0
+#define OPTSTR_eject ">1stT[!tT]"
#ifdef CLEANUP_eject
#undef CLEANUP_eject
#undef FOR_eject
@@ -633,7 +649,7 @@
// exit
#undef OPTSTR_exit
-#define OPTSTR_exit 0
+#define OPTSTR_exit 0
#ifdef CLEANUP_exit
#undef CLEANUP_exit
#undef FOR_exit
@@ -650,7 +666,7 @@
// expr
#undef OPTSTR_expr
-#define OPTSTR_expr 0
+#define OPTSTR_expr 0
#ifdef CLEANUP_expr
#undef CLEANUP_expr
#undef FOR_expr
@@ -658,7 +674,7 @@
// factor
#undef OPTSTR_factor
-#define OPTSTR_factor 0
+#define OPTSTR_factor 0
#ifdef CLEANUP_factor
#undef CLEANUP_factor
#undef FOR_factor
@@ -675,7 +691,7 @@
// false
#undef OPTSTR_false
-#define OPTSTR_false 0
+#define OPTSTR_false 0
#ifdef CLEANUP_false
#undef CLEANUP_false
#undef FOR_false
@@ -695,12 +711,14 @@
#undef FLAG_C
#endif
-// file <1 <1
+// file <1hL[!hL] <1hL[!hL]
#undef OPTSTR_file
-#define OPTSTR_file "<1"
+#define OPTSTR_file "<1hL[!hL]"
#ifdef CLEANUP_file
#undef CLEANUP_file
#undef FOR_file
+#undef FLAG_L
+#undef FLAG_h
#endif
// find ?^HL[-HL] ?^HL[-HL]
@@ -727,7 +745,7 @@
// fold bsuw#<1
#undef OPTSTR_fold
-#define OPTSTR_fold 0
+#define OPTSTR_fold "bsuw#<1"
#ifdef CLEANUP_fold
#undef CLEANUP_fold
#undef FOR_fold
@@ -761,7 +779,7 @@
// fsck ?t:ANPRTVsC#
#undef OPTSTR_fsck
-#define OPTSTR_fsck 0
+#define OPTSTR_fsck "?t:ANPRTVsC#"
#ifdef CLEANUP_fsck
#undef CLEANUP_fsck
#undef FOR_fsck
@@ -796,7 +814,7 @@
// fsync <1d
#undef OPTSTR_fsync
-#define OPTSTR_fsync 0
+#define OPTSTR_fsync "<1d"
#ifdef CLEANUP_fsync
#undef CLEANUP_fsync
#undef FOR_fsync
@@ -824,6 +842,17 @@
#undef FOR_getenforce
#endif
+// getfattr dhn: dhn:
+#undef OPTSTR_getfattr
+#define OPTSTR_getfattr "dhn:"
+#ifdef CLEANUP_getfattr
+#undef CLEANUP_getfattr
+#undef FOR_getfattr
+#undef FLAG_n
+#undef FLAG_h
+#undef FLAG_d
+#endif
+
// getprop >2Z >2Z
#undef OPTSTR_getprop
#define OPTSTR_getprop ">2Z"
@@ -835,7 +864,7 @@
// getty <2t#<0H:I:l:f:iwnmLh
#undef OPTSTR_getty
-#define OPTSTR_getty 0
+#define OPTSTR_getty "<2t#<0H:I:l:f:iwnmLh"
#ifdef CLEANUP_getty
#undef CLEANUP_getty
#undef FOR_getty
@@ -887,7 +916,7 @@
// groupadd <1>2g#<0S
#undef OPTSTR_groupadd
-#define OPTSTR_groupadd 0
+#define OPTSTR_groupadd "<1>2g#<0S"
#ifdef CLEANUP_groupadd
#undef CLEANUP_groupadd
#undef FOR_groupadd
@@ -897,7 +926,7 @@
// groupdel <1>2
#undef OPTSTR_groupdel
-#define OPTSTR_groupdel 0
+#define OPTSTR_groupdel "<1>2"
#ifdef CLEANUP_groupdel
#undef CLEANUP_groupdel
#undef FOR_groupdel
@@ -905,7 +934,7 @@
// groups
#undef OPTSTR_groups
-#define OPTSTR_groups 0
+#define OPTSTR_groups 0
#ifdef CLEANUP_groups
#undef CLEANUP_groups
#undef FOR_groups
@@ -913,7 +942,7 @@
// gunzip cflqStv
#undef OPTSTR_gunzip
-#define OPTSTR_gunzip 0
+#define OPTSTR_gunzip "cflqStv"
#ifdef CLEANUP_gunzip
#undef CLEANUP_gunzip
#undef FOR_gunzip
@@ -928,7 +957,7 @@
// gzip d19dcflqStvgLRz[!gLRz]
#undef OPTSTR_gzip
-#define OPTSTR_gzip 0
+#define OPTSTR_gzip "d19dcflqStvgLRz[!gLRz]"
#ifdef CLEANUP_gzip
#undef CLEANUP_gzip
#undef FOR_gzip
@@ -960,7 +989,7 @@
// hello
#undef OPTSTR_hello
-#define OPTSTR_hello 0
+#define OPTSTR_hello 0
#ifdef CLEANUP_hello
#undef CLEANUP_hello
#undef FOR_hello
@@ -978,7 +1007,7 @@
// hexedit <1>1r
#undef OPTSTR_hexedit
-#define OPTSTR_hexedit 0
+#define OPTSTR_hexedit "<1>1r"
#ifdef CLEANUP_hexedit
#undef CLEANUP_hexedit
#undef FOR_hexedit
@@ -998,7 +1027,7 @@
// hostid >0
#undef OPTSTR_hostid
-#define OPTSTR_hostid 0
+#define OPTSTR_hostid ">0"
#ifdef CLEANUP_hostid
#undef CLEANUP_hostid
#undef FOR_hostid
@@ -1039,7 +1068,7 @@
// iconv cst:f:
#undef OPTSTR_iconv
-#define OPTSTR_iconv 0
+#define OPTSTR_iconv "cst:f:"
#ifdef CLEANUP_iconv
#undef CLEANUP_iconv
#undef FOR_iconv
@@ -1074,7 +1103,7 @@
// init
#undef OPTSTR_init
-#define OPTSTR_init 0
+#define OPTSTR_init 0
#ifdef CLEANUP_init
#undef CLEANUP_init
#undef FOR_init
@@ -1156,7 +1185,7 @@
// ip
#undef OPTSTR_ip
-#define OPTSTR_ip 0
+#define OPTSTR_ip 0
#ifdef CLEANUP_ip
#undef CLEANUP_ip
#undef FOR_ip
@@ -1164,7 +1193,7 @@
// ipcrm m*M*s*S*q*Q*
#undef OPTSTR_ipcrm
-#define OPTSTR_ipcrm 0
+#define OPTSTR_ipcrm "m*M*s*S*q*Q*"
#ifdef CLEANUP_ipcrm
#undef CLEANUP_ipcrm
#undef FOR_ipcrm
@@ -1178,7 +1207,7 @@
// ipcs acptulsqmi#
#undef OPTSTR_ipcs
-#define OPTSTR_ipcs 0
+#define OPTSTR_ipcs "acptulsqmi#"
#ifdef CLEANUP_ipcs
#undef CLEANUP_ipcs
#undef FOR_ipcs
@@ -1219,7 +1248,7 @@
// killall5 ?o*ls: [!lo][!ls]
#undef OPTSTR_killall5
-#define OPTSTR_killall5 0
+#define OPTSTR_killall5 "?o*ls: [!lo][!ls]"
#ifdef CLEANUP_killall5
#undef CLEANUP_killall5
#undef FOR_killall5
@@ -1230,7 +1259,7 @@
// klogd c#<1>8n
#undef OPTSTR_klogd
-#define OPTSTR_klogd 0
+#define OPTSTR_klogd "c#<1>8n"
#ifdef CLEANUP_klogd
#undef CLEANUP_klogd
#undef FOR_klogd
@@ -1240,7 +1269,7 @@
// last f:W
#undef OPTSTR_last
-#define OPTSTR_last 0
+#define OPTSTR_last "f:W"
#ifdef CLEANUP_last
#undef CLEANUP_last
#undef FOR_last
@@ -1250,7 +1279,7 @@
// link <2>2
#undef OPTSTR_link
-#define OPTSTR_link 0
+#define OPTSTR_link "<2>2"
#ifdef CLEANUP_link
#undef CLEANUP_link
#undef FOR_link
@@ -1276,9 +1305,19 @@
#undef FOR_load_policy
#endif
+// log <1p:t: <1p:t:
+#undef OPTSTR_log
+#define OPTSTR_log "<1p:t:"
+#ifdef CLEANUP_log
+#undef CLEANUP_log
+#undef FOR_log
+#undef FLAG_t
+#undef FLAG_p
+#endif
+
// logger st:p:
#undef OPTSTR_logger
-#define OPTSTR_logger 0
+#define OPTSTR_logger "st:p:"
#ifdef CLEANUP_logger
#undef CLEANUP_logger
#undef FOR_logger
@@ -1289,7 +1328,7 @@
// login >1f:ph:
#undef OPTSTR_login
-#define OPTSTR_login 0
+#define OPTSTR_login ">1f:ph:"
#ifdef CLEANUP_login
#undef CLEANUP_login
#undef FOR_login
@@ -1378,7 +1417,7 @@
// lsmod
#undef OPTSTR_lsmod
-#define OPTSTR_lsmod 0
+#define OPTSTR_lsmod 0
#ifdef CLEANUP_lsmod
#undef CLEANUP_lsmod
#undef FOR_lsmod
@@ -1410,7 +1449,7 @@
// lsusb
#undef OPTSTR_lsusb
-#define OPTSTR_lsusb 0
+#define OPTSTR_lsusb 0
#ifdef CLEANUP_lsusb
#undef CLEANUP_lsusb
#undef FOR_lsusb
@@ -1425,18 +1464,19 @@
#undef FLAG_d
#endif
-// md5sum b b
+// md5sum bc*[!bc] bc*[!bc]
#undef OPTSTR_md5sum
-#define OPTSTR_md5sum "b"
+#define OPTSTR_md5sum "bc*[!bc]"
#ifdef CLEANUP_md5sum
#undef CLEANUP_md5sum
#undef FOR_md5sum
+#undef FLAG_c
#undef FLAG_b
#endif
// mdev s
#undef OPTSTR_mdev
-#define OPTSTR_mdev 0
+#define OPTSTR_mdev "s"
#ifdef CLEANUP_mdev
#undef CLEANUP_mdev
#undef FOR_mdev
@@ -1445,7 +1485,7 @@
// mix c:d:l#r#
#undef OPTSTR_mix
-#define OPTSTR_mix 0
+#define OPTSTR_mix "c:d:l#r#"
#ifdef CLEANUP_mix
#undef CLEANUP_mix
#undef FOR_mix
@@ -1469,7 +1509,7 @@
// mke2fs <1>2g:Fnqm#N#i#b#
#undef OPTSTR_mke2fs
-#define OPTSTR_mke2fs 0
+#define OPTSTR_mke2fs "<1>2g:Fnqm#N#i#b#"
#ifdef CLEANUP_mke2fs
#undef CLEANUP_mke2fs
#undef FOR_mke2fs
@@ -1506,7 +1546,7 @@
// mkpasswd >2S:m:P#=0<0
#undef OPTSTR_mkpasswd
-#define OPTSTR_mkpasswd 0
+#define OPTSTR_mkpasswd ">2S:m:P#=0<0"
#ifdef CLEANUP_mkpasswd
#undef CLEANUP_mkpasswd
#undef FOR_mkpasswd
@@ -1552,7 +1592,7 @@
// modprobe alrqvsDb
#undef OPTSTR_modprobe
-#define OPTSTR_modprobe 0
+#define OPTSTR_modprobe "alrqvsDb"
#ifdef CLEANUP_modprobe
#undef CLEANUP_modprobe
#undef FOR_modprobe
@@ -1568,7 +1608,7 @@
// more
#undef OPTSTR_more
-#define OPTSTR_more 0
+#define OPTSTR_more 0
#ifdef CLEANUP_more
#undef CLEANUP_more
#undef FOR_more
@@ -1704,7 +1744,7 @@
// nsenter <1F(no-fork)t#<1(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);
#undef OPTSTR_nsenter
-#define OPTSTR_nsenter 0
+#define OPTSTR_nsenter "<1F(no-fork)t#<1(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);"
#ifdef CLEANUP_nsenter
#undef CLEANUP_nsenter
#undef FOR_nsenter
@@ -1748,7 +1788,7 @@
// oneit ^<1nc:p3[!pn]
#undef OPTSTR_oneit
-#define OPTSTR_oneit 0
+#define OPTSTR_oneit "^<1nc:p3[!pn]"
#ifdef CLEANUP_oneit
#undef CLEANUP_oneit
#undef FOR_oneit
@@ -1760,7 +1800,7 @@
// openvt c#<1>63sw
#undef OPTSTR_openvt
-#define OPTSTR_openvt 0
+#define OPTSTR_openvt "c#<1>63sw"
#ifdef CLEANUP_openvt
#undef CLEANUP_openvt
#undef FOR_openvt
@@ -1779,7 +1819,7 @@
// passwd >1a:dlu
#undef OPTSTR_passwd
-#define OPTSTR_passwd 0
+#define OPTSTR_passwd ">1a:dlu"
#ifdef CLEANUP_passwd
#undef CLEANUP_passwd
#undef FOR_passwd
@@ -1799,9 +1839,9 @@
#undef FLAG_d
#endif
-// patch ulp#i:R xulp#i:R
+// patch (dry-run)d:ulp#i:R (dry-run)xd:ulp#i:R
#undef OPTSTR_patch
-#define OPTSTR_patch "ulp#i:R"
+#define OPTSTR_patch "(dry-run)d:ulp#i:R"
#ifdef CLEANUP_patch
#undef CLEANUP_patch
#undef FOR_patch
@@ -1810,7 +1850,9 @@
#undef FLAG_p
#undef FLAG_l
#undef FLAG_u
+#undef FLAG_d
#undef FLAG_x
+#undef FLAG_dry_run
#endif
// pgrep ?cld:u*U*t*s*P*g*G*fnovxL:[-no] ?cld:u*U*t*s*P*g*G*fnovxL:[-no]
@@ -1849,7 +1891,7 @@
// ping <1>1t#<0>255c#<0s#<0>65535I:W#<0w#<0q46[-46]
#undef OPTSTR_ping
-#define OPTSTR_ping 0
+#define OPTSTR_ping "<1>1t#<0>255c#<0s#<0>65535I:W#<0w#<0q46[-46]"
#ifdef CLEANUP_ping
#undef CLEANUP_ping
#undef FOR_ping
@@ -1872,9 +1914,9 @@
#undef FOR_pivot_root
#endif
-// pkill Vu*U*t*s*P*g*G*fnovxl:[-no] Vu*U*t*s*P*g*G*fnovxl:[-no]
+// pkill ?Vu*U*t*s*P*g*G*fnovxl:[-no] ?Vu*U*t*s*P*g*G*fnovxl:[-no]
#undef OPTSTR_pkill
-#define OPTSTR_pkill "Vu*U*t*s*P*g*G*fnovxl:[-no]"
+#define OPTSTR_pkill "?Vu*U*t*s*P*g*G*fnovxl:[-no]"
#ifdef CLEANUP_pkill
#undef CLEANUP_pkill
#undef FOR_pkill
@@ -1922,9 +1964,9 @@
#undef FOR_printf
#endif
-// ps k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae] k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae]
+// ps k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO] k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]
#undef OPTSTR_ps
-#define OPTSTR_ps "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae]"
+#define OPTSTR_ps "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]"
#ifdef CLEANUP_ps
#undef CLEANUP_ps
#undef FOR_ps
@@ -1976,7 +2018,7 @@
// readahead
#undef OPTSTR_readahead
-#define OPTSTR_readahead 0
+#define OPTSTR_readahead 0
#ifdef CLEANUP_readahead
#undef CLEANUP_readahead
#undef FOR_readahead
@@ -2004,7 +2046,7 @@
// reboot fn
#undef OPTSTR_reboot
-#define OPTSTR_reboot 0
+#define OPTSTR_reboot "fn"
#ifdef CLEANUP_reboot
#undef CLEANUP_reboot
#undef FOR_reboot
@@ -2026,7 +2068,7 @@
// reset
#undef OPTSTR_reset
-#define OPTSTR_reset 0
+#define OPTSTR_reset 0
#ifdef CLEANUP_reset
#undef CLEANUP_reset
#undef FOR_reset
@@ -2059,7 +2101,7 @@
// rev
#undef OPTSTR_rev
-#define OPTSTR_rev 0
+#define OPTSTR_rev 0
#ifdef CLEANUP_rev
#undef CLEANUP_rev
#undef FOR_rev
@@ -2138,6 +2180,14 @@
#undef FLAG_version
#endif
+// sendevent <4>4 <4>4
+#undef OPTSTR_sendevent
+#define OPTSTR_sendevent "<4>4"
+#ifdef CLEANUP_sendevent
+#undef CLEANUP_sendevent
+#undef FOR_sendevent
+#endif
+
// seq <1>3?f:s:w[!fw] <1>3?f:s:w[!fw]
#undef OPTSTR_seq
#define OPTSTR_seq "<1>3?f:s:w[!fw]"
@@ -2157,6 +2207,18 @@
#undef FOR_setenforce
#endif
+// setfattr hn:|v:x:|[!xv] hn:|v:x:|[!xv]
+#undef OPTSTR_setfattr
+#define OPTSTR_setfattr "hn:|v:x:|[!xv]"
+#ifdef CLEANUP_setfattr
+#undef CLEANUP_setfattr
+#undef FOR_setfattr
+#undef FLAG_x
+#undef FLAG_v
+#undef FLAG_n
+#undef FLAG_h
+#endif
+
// setprop <2>2 <2>2
#undef OPTSTR_setprop
#define OPTSTR_setprop "<2>2"
@@ -2176,7 +2238,7 @@
// sh c:i
#undef OPTSTR_sh
-#define OPTSTR_sh 0
+#define OPTSTR_sh "c:i"
#ifdef CLEANUP_sh
#undef CLEANUP_sh
#undef FOR_sh
@@ -2184,18 +2246,19 @@
#undef FLAG_c
#endif
-// sha1sum b b
+// sha1sum bc*[!bc] bc*[!bc]
#undef OPTSTR_sha1sum
-#define OPTSTR_sha1sum "b"
+#define OPTSTR_sha1sum "bc*[!bc]"
#ifdef CLEANUP_sha1sum
#undef CLEANUP_sha1sum
#undef FOR_sha1sum
+#undef FLAG_c
#undef FLAG_b
#endif
// shred <1zxus#<1n#<1o#<0f
#undef OPTSTR_shred
-#define OPTSTR_shred 0
+#define OPTSTR_shred "<1zxus#<1n#<1o#<0f"
#ifdef CLEANUP_shred
#undef CLEANUP_shred
#undef FOR_shred
@@ -2210,7 +2273,7 @@
// skeleton (walrus)(blubber):;(also):e@d*c#b:a
#undef OPTSTR_skeleton
-#define OPTSTR_skeleton 0
+#define OPTSTR_skeleton "(walrus)(blubber):;(also):e@d*c#b:a"
#ifdef CLEANUP_skeleton
#undef CLEANUP_skeleton
#undef FOR_skeleton
@@ -2226,7 +2289,7 @@
// skeleton_alias b#dq
#undef OPTSTR_skeleton_alias
-#define OPTSTR_skeleton_alias 0
+#define OPTSTR_skeleton_alias "b#dq"
#ifdef CLEANUP_skeleton_alias
#undef CLEANUP_skeleton_alias
#undef FOR_skeleton_alias
@@ -2281,17 +2344,34 @@
#undef FLAG_a
#endif
-// stat <1c:tf <1c:tf
+// start
+#undef OPTSTR_start
+#define OPTSTR_start 0
+#ifdef CLEANUP_start
+#undef CLEANUP_start
+#undef FOR_start
+#endif
+
+// stat <1c:fLt <1c:fLt
#undef OPTSTR_stat
-#define OPTSTR_stat "<1c:tf"
+#define OPTSTR_stat "<1c:fLt"
#ifdef CLEANUP_stat
#undef CLEANUP_stat
#undef FOR_stat
-#undef FLAG_f
#undef FLAG_t
+#undef FLAG_L
+#undef FLAG_f
#undef FLAG_c
#endif
+// stop
+#undef OPTSTR_stop
+#define OPTSTR_stop 0
+#ifdef CLEANUP_stop
+#undef CLEANUP_stop
+#undef FOR_stop
+#endif
+
// strings an#=4<1fo an#=4<1fo
#undef OPTSTR_strings
#define OPTSTR_strings "an#=4<1fo"
@@ -2306,7 +2386,7 @@
// su lmpc:s:
#undef OPTSTR_su
-#define OPTSTR_su 0
+#define OPTSTR_su "lmpc:s:"
#ifdef CLEANUP_su
#undef CLEANUP_su
#undef FOR_su
@@ -2319,7 +2399,7 @@
// sulogin t#<0=0
#undef OPTSTR_sulogin
-#define OPTSTR_sulogin 0
+#define OPTSTR_sulogin "t#<0=0"
#ifdef CLEANUP_sulogin
#undef CLEANUP_sulogin
#undef FOR_sulogin
@@ -2346,7 +2426,7 @@
// switch_root <2c:h
#undef OPTSTR_switch_root
-#define OPTSTR_switch_root 0
+#define OPTSTR_switch_root "<2c:h"
#ifdef CLEANUP_switch_root
#undef CLEANUP_switch_root
#undef FOR_switch_root
@@ -2356,7 +2436,7 @@
// sync
#undef OPTSTR_sync
-#define OPTSTR_sync 0
+#define OPTSTR_sync 0
#ifdef CLEANUP_sync
#undef CLEANUP_sync
#undef FOR_sync
@@ -2380,7 +2460,7 @@
// syslogd >0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD
#undef OPTSTR_syslogd
-#define OPTSTR_syslogd 0
+#define OPTSTR_syslogd ">0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD"
#ifdef CLEANUP_syslogd
#undef CLEANUP_syslogd
#undef FOR_syslogd
@@ -2402,7 +2482,7 @@
// tac
#undef OPTSTR_tac
-#define OPTSTR_tac 0
+#define OPTSTR_tac 0
#ifdef CLEANUP_tac
#undef CLEANUP_tac
#undef FOR_tac
@@ -2475,7 +2555,7 @@
// tcpsvd ^<3c#=30<1C:b#=20<0u:l:hEv
#undef OPTSTR_tcpsvd
-#define OPTSTR_tcpsvd 0
+#define OPTSTR_tcpsvd "^<3c#=30<1C:b#=20<0u:l:hEv"
#ifdef CLEANUP_tcpsvd
#undef CLEANUP_tcpsvd
#undef FOR_tcpsvd
@@ -2509,7 +2589,7 @@
// telnetd w#<0b:p#<0>65535=23f:l:FSKi[!wi]
#undef OPTSTR_telnetd
-#define OPTSTR_telnetd 0
+#define OPTSTR_telnetd "w#<0b:p#<0>65535=23f:l:FSKi[!wi]"
#ifdef CLEANUP_telnetd
#undef CLEANUP_telnetd
#undef FOR_telnetd
@@ -2526,7 +2606,7 @@
// test
#undef OPTSTR_test
-#define OPTSTR_test 0
+#define OPTSTR_test 0
#ifdef CLEANUP_test
#undef CLEANUP_test
#undef FOR_test
@@ -2534,7 +2614,7 @@
// test_human_readable <1>1ibs
#undef OPTSTR_test_human_readable
-#define OPTSTR_test_human_readable 0
+#define OPTSTR_test_human_readable "<1>1ibs"
#ifdef CLEANUP_test_human_readable
#undef CLEANUP_test_human_readable
#undef FOR_test_human_readable
@@ -2545,7 +2625,7 @@
// test_many_options ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba
#undef OPTSTR_test_many_options
-#define OPTSTR_test_many_options 0
+#define OPTSTR_test_many_options "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba"
#ifdef CLEANUP_test_many_options
#undef CLEANUP_test_many_options
#undef FOR_test_many_options
@@ -2605,7 +2685,7 @@
// test_scankey
#undef OPTSTR_test_scankey
-#define OPTSTR_test_scankey 0
+#define OPTSTR_test_scankey 0
#ifdef CLEANUP_test_scankey
#undef CLEANUP_test_scankey
#undef FOR_test_scankey
@@ -2613,7 +2693,7 @@
// tftp <1b#<8>65464r:l:g|p|[!gp]
#undef OPTSTR_tftp
-#define OPTSTR_tftp 0
+#define OPTSTR_tftp "<1b#<8>65464r:l:g|p|[!gp]"
#ifdef CLEANUP_tftp
#undef CLEANUP_tftp
#undef FOR_tftp
@@ -2626,7 +2706,7 @@
// tftpd rcu:l
#undef OPTSTR_tftpd
-#define OPTSTR_tftpd 0
+#define OPTSTR_tftpd "rcu:l"
#ifdef CLEANUP_tftpd
#undef CLEANUP_tftpd
#undef FOR_tftpd
@@ -2656,9 +2736,9 @@
#undef FLAG_v
#endif
-// top >0mHk*o*p*u*s#<1=9d#=3<1n#<1bq >0mHk*o*p*u*s#<1=9d#=3<1n#<1bq
+// top >0mO*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO] >0mO*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO]
#undef OPTSTR_top
-#define OPTSTR_top ">0mHk*o*p*u*s#<1=9d#=3<1n#<1bq"
+#define OPTSTR_top ">0mO*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO]"
#ifdef CLEANUP_top
#undef CLEANUP_top
#undef FOR_top
@@ -2672,6 +2752,7 @@
#undef FLAG_o
#undef FLAG_k
#undef FLAG_H
+#undef FLAG_O
#undef FLAG_m
#endif
@@ -2692,7 +2773,7 @@
// toybox
#undef OPTSTR_toybox
-#define OPTSTR_toybox 0
+#define OPTSTR_toybox 0
#ifdef CLEANUP_toybox
#undef CLEANUP_toybox
#undef FOR_toybox
@@ -2740,7 +2821,7 @@
// true
#undef OPTSTR_true
-#define OPTSTR_true 0
+#define OPTSTR_true 0
#ifdef CLEANUP_true
#undef CLEANUP_true
#undef FOR_true
@@ -2765,6 +2846,18 @@
#undef FLAG_s
#endif
+// tunctl <1>1t|d|u:T[!td] <1>1t|d|u:T[!td]
+#undef OPTSTR_tunctl
+#define OPTSTR_tunctl "<1>1t|d|u:T[!td]"
+#ifdef CLEANUP_tunctl
+#undef CLEANUP_tunctl
+#undef FOR_tunctl
+#undef FLAG_T
+#undef FLAG_u
+#undef FLAG_d
+#undef FLAG_t
+#endif
+
// ulimit >1P#<1SHavutsrRqpnmlifedc[-SH][!apvutsrRqnmlifedc] >1P#<1SHavutsrRqpnmlifedc[-SH][!apvutsrRqnmlifedc]
#undef OPTSTR_ulimit
#define OPTSTR_ulimit ">1P#<1SHavutsrRqpnmlifedc[-SH][!apvutsrRqnmlifedc]"
@@ -2843,7 +2936,7 @@
// unix2dos
#undef OPTSTR_unix2dos
-#define OPTSTR_unix2dos 0
+#define OPTSTR_unix2dos 0
#ifdef CLEANUP_unix2dos
#undef CLEANUP_unix2dos
#undef FOR_unix2dos
@@ -2851,7 +2944,7 @@
// unlink <1>1
#undef OPTSTR_unlink
-#define OPTSTR_unlink 0
+#define OPTSTR_unlink "<1>1"
#ifdef CLEANUP_unlink
#undef CLEANUP_unlink
#undef FOR_unlink
@@ -2859,7 +2952,7 @@
// unshare <1^f(fork);r(map-root-user);i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);
#undef OPTSTR_unshare
-#define OPTSTR_unshare 0
+#define OPTSTR_unshare "<1^f(fork);r(map-root-user);i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);"
#ifdef CLEANUP_unshare
#undef CLEANUP_unshare
#undef FOR_unshare
@@ -2883,7 +2976,7 @@
// uptime
#undef OPTSTR_uptime
-#define OPTSTR_uptime 0
+#define OPTSTR_uptime 0
#ifdef CLEANUP_uptime
#undef CLEANUP_uptime
#undef FOR_uptime
@@ -2891,7 +2984,7 @@
// useradd <1>2u#<0G:s:g:h:SDH
#undef OPTSTR_useradd
-#define OPTSTR_useradd 0
+#define OPTSTR_useradd "<1>2u#<0G:s:g:h:SDH"
#ifdef CLEANUP_useradd
#undef CLEANUP_useradd
#undef FOR_useradd
@@ -2907,7 +3000,7 @@
// userdel <1>1r
#undef OPTSTR_userdel
-#define OPTSTR_userdel 0
+#define OPTSTR_userdel "<1>1r"
#ifdef CLEANUP_userdel
#undef CLEANUP_userdel
#undef FOR_userdel
@@ -2924,7 +3017,7 @@
// uudecode >1o:
#undef OPTSTR_uudecode
-#define OPTSTR_uudecode 0
+#define OPTSTR_uudecode ">1o:"
#ifdef CLEANUP_uudecode
#undef CLEANUP_uudecode
#undef FOR_uudecode
@@ -2933,7 +3026,7 @@
// uuencode <1>2m
#undef OPTSTR_uuencode
-#define OPTSTR_uuencode 0
+#define OPTSTR_uuencode "<1>2m"
#ifdef CLEANUP_uuencode
#undef CLEANUP_uuencode
#undef FOR_uuencode
@@ -2950,7 +3043,7 @@
// vi <1>1
#undef OPTSTR_vi
-#define OPTSTR_vi 0
+#define OPTSTR_vi "<1>1"
#ifdef CLEANUP_vi
#undef CLEANUP_vi
#undef FOR_vi
@@ -2967,7 +3060,7 @@
// w
#undef OPTSTR_w
-#define OPTSTR_w 0
+#define OPTSTR_w 0
#ifdef CLEANUP_w
#undef CLEANUP_w
#undef FOR_w
@@ -2984,9 +3077,9 @@
#undef FLAG_n
#endif
-// wc mcwl[!cm] mcwl[!cm]
+// wc mcwl mcwl
#undef OPTSTR_wc
-#define OPTSTR_wc "mcwl[!cm]"
+#define OPTSTR_wc "mcwl"
#ifdef CLEANUP_wc
#undef CLEANUP_wc
#undef FOR_wc
@@ -2998,7 +3091,7 @@
// wget f:
#undef OPTSTR_wget
-#define OPTSTR_wget 0
+#define OPTSTR_wget "f:"
#ifdef CLEANUP_wget
#undef CLEANUP_wget
#undef FOR_wget
@@ -3016,7 +3109,7 @@
// who a
#undef OPTSTR_who
-#define OPTSTR_who 0
+#define OPTSTR_who "a"
#ifdef CLEANUP_who
#undef CLEANUP_who
#undef FOR_who
@@ -3041,12 +3134,13 @@
#undef FLAG_I
#endif
-// xxd >1c#<1>4096=16l#g#<1=2pr >1c#<1>4096=16l#g#<1=2pr
+// xxd >1c#<1>4096=16l#g#<1=2prs#[!rs] >1c#<1>4096=16l#g#<1=2prs#[!rs]
#undef OPTSTR_xxd
-#define OPTSTR_xxd ">1c#<1>4096=16l#g#<1=2pr"
+#define OPTSTR_xxd ">1c#<1>4096=16l#g#<1=2prs#[!rs]"
#ifdef CLEANUP_xxd
#undef CLEANUP_xxd
#undef FOR_xxd
+#undef FLAG_s
#undef FLAG_r
#undef FLAG_p
#undef FLAG_g
@@ -3056,7 +3150,7 @@
// xzcat
#undef OPTSTR_xzcat
-#define OPTSTR_xzcat 0
+#define OPTSTR_xzcat 0
#ifdef CLEANUP_xzcat
#undef CLEANUP_xzcat
#undef FOR_xzcat
@@ -3064,7 +3158,7 @@
// yes
#undef OPTSTR_yes
-#define OPTSTR_yes 0
+#define OPTSTR_yes 0
#ifdef CLEANUP_yes
#undef CLEANUP_yes
#undef FOR_yes
@@ -3072,7 +3166,7 @@
// zcat
#undef OPTSTR_zcat
-#define OPTSTR_zcat 0
+#define OPTSTR_zcat 0
#ifdef CLEANUP_zcat
#undef CLEANUP_zcat
#undef FOR_zcat
@@ -3262,6 +3356,20 @@
#endif
#endif
+#ifdef FOR_chrt
+#ifndef TT
+#define TT this.chrt
+#endif
+#define FLAG_R (1<<0)
+#define FLAG_r (1<<1)
+#define FLAG_o (1<<2)
+#define FLAG_i (1<<3)
+#define FLAG_f (1<<4)
+#define FLAG_b (1<<5)
+#define FLAG_p (1<<6)
+#define FLAG_m (1<<7)
+#endif
+
#ifdef FOR_chvt
#ifndef TT
#define TT this.chvt
@@ -3659,6 +3767,8 @@
#ifndef TT
#define TT this.file
#endif
+#define FLAG_L (1<<0)
+#define FLAG_h (1<<1)
#endif
#ifdef FOR_find
@@ -3760,6 +3870,15 @@
#endif
#endif
+#ifdef FOR_getfattr
+#ifndef TT
+#define TT this.getfattr
+#endif
+#define FLAG_n (1<<0)
+#define FLAG_h (1<<1)
+#define FLAG_d (1<<2)
+#endif
+
#ifdef FOR_getprop
#ifndef TT
#define TT this.getprop
@@ -4138,6 +4257,14 @@
#endif
#endif
+#ifdef FOR_log
+#ifndef TT
+#define TT this.log
+#endif
+#define FLAG_t (1<<0)
+#define FLAG_p (1<<1)
+#endif
+
#ifdef FOR_logger
#ifndef TT
#define TT this.logger
@@ -4269,7 +4396,8 @@
#ifndef TT
#define TT this.md5sum
#endif
-#define FLAG_b (1<<0)
+#define FLAG_c (1<<0)
+#define FLAG_b (1<<1)
#endif
#ifdef FOR_mdev
@@ -4588,7 +4716,9 @@
#define FLAG_p (1<<2)
#define FLAG_l (1<<3)
#define FLAG_u (1<<4)
-#define FLAG_x (FORCED_FLAG<<5)
+#define FLAG_d (1<<5)
+#define FLAG_x (FORCED_FLAG<<6)
+#define FLAG_dry_run (1<<7)
#endif
#ifdef FOR_pgrep
@@ -4862,6 +4992,12 @@
#define FLAG_version (1<<6)
#endif
+#ifdef FOR_sendevent
+#ifndef TT
+#define TT this.sendevent
+#endif
+#endif
+
#ifdef FOR_seq
#ifndef TT
#define TT this.seq
@@ -4877,6 +5013,16 @@
#endif
#endif
+#ifdef FOR_setfattr
+#ifndef TT
+#define TT this.setfattr
+#endif
+#define FLAG_x (1<<0)
+#define FLAG_v (1<<1)
+#define FLAG_n (1<<2)
+#define FLAG_h (1<<3)
+#endif
+
#ifdef FOR_setprop
#ifndef TT
#define TT this.setprop
@@ -4902,7 +5048,8 @@
#ifndef TT
#define TT this.sha1sum
#endif
-#define FLAG_b (1<<0)
+#define FLAG_c (1<<0)
+#define FLAG_b (1<<1)
#endif
#ifdef FOR_shred
@@ -4981,13 +5128,26 @@
#define FLAG_a (1<<2)
#endif
+#ifdef FOR_start
+#ifndef TT
+#define TT this.start
+#endif
+#endif
+
#ifdef FOR_stat
#ifndef TT
#define TT this.stat
#endif
-#define FLAG_f (1<<0)
-#define FLAG_t (1<<1)
-#define FLAG_c (1<<2)
+#define FLAG_t (1<<0)
+#define FLAG_L (1<<1)
+#define FLAG_f (1<<2)
+#define FLAG_c (1<<3)
+#endif
+
+#ifdef FOR_stop
+#ifndef TT
+#define TT this.stop
+#endif
#endif
#ifdef FOR_strings
@@ -5318,7 +5478,8 @@
#define FLAG_o (1<<7)
#define FLAG_k (1<<8)
#define FLAG_H (1<<9)
-#define FLAG_m (1<<10)
+#define FLAG_O (1<<10)
+#define FLAG_m (1<<11)
#endif
#ifdef FOR_touch
@@ -5397,6 +5558,16 @@
#define FLAG_s (1<<0)
#endif
+#ifdef FOR_tunctl
+#ifndef TT
+#define TT this.tunctl
+#endif
+#define FLAG_T (1<<0)
+#define FLAG_u (1<<1)
+#define FLAG_d (1<<2)
+#define FLAG_t (1<<3)
+#endif
+
#ifdef FOR_ulimit
#ifndef TT
#define TT this.ulimit
@@ -5631,11 +5802,12 @@
#ifndef TT
#define TT this.xxd
#endif
-#define FLAG_r (1<<0)
-#define FLAG_p (1<<1)
-#define FLAG_g (1<<2)
-#define FLAG_l (1<<3)
-#define FLAG_c (1<<4)
+#define FLAG_s (1<<0)
+#define FLAG_r (1<<1)
+#define FLAG_p (1<<2)
+#define FLAG_g (1<<3)
+#define FLAG_l (1<<4)
+#define FLAG_c (1<<5)
#endif
#ifdef FOR_xzcat
diff --git a/generated/globals.h b/generated/globals.h
index bfeccaae..9766963a 100644
--- a/generated/globals.h
+++ b/generated/globals.h
@@ -6,6 +6,13 @@ struct getprop_data {
struct selabel_handle *handle;
};
+// toys/android/log.c
+
+struct log_data {
+ char *tag;
+ char *pri;
+};
+
// toys/example/hello.c
struct hello_data {
@@ -59,6 +66,11 @@ struct killall_data {
// toys/lsb/md5sum.c
struct md5sum_data {
+ struct arg_list *c;
+
+ int sawline;
+
+ // Crypto variables blanked after summing
unsigned state[5];
unsigned oldstate[5];
uint64_t count;
@@ -127,6 +139,35 @@ struct umount_data {
char *types;
};
+// toys/net/ifconfig.c
+
+struct ifconfig_data {
+ int sockfd;
+};
+
+// toys/net/netcat.c
+
+struct netcat_data {
+ char *filename; // -f read from filename instead of network
+ long quit_delay; // -q Exit after EOF from stdin after # seconds.
+ char *source_address; // -s Bind to a specific source address.
+ long port; // -p Bind to a specific source port.
+ long wait; // -w Wait # seconds for a connection.
+};
+
+// toys/net/netstat.c
+
+struct netstat_data {
+ struct num_cache *inodes;
+ int wpad;
+};;
+
+// toys/net/tunctl.c
+
+struct tunctl_data {
+ char *user;
+};
+
// toys/other/acpi.c
struct acpi_data {
@@ -185,12 +226,6 @@ struct hwclock_data {
int utc;
};
-// toys/other/ifconfig.c
-
-struct ifconfig_data {
- int sockfd;
-};
-
// toys/other/ionice.c
struct ionice_data {
@@ -268,16 +303,6 @@ struct modinfo_data {
long mod;
};
-// toys/other/netcat.c
-
-struct netcat_data {
- char *filename; // -f read from filename instead of network
- long quit_delay; // -q Exit after EOF from stdin after # seconds.
- char *source_address; // -s Bind to a specific source address.
- long port; // -p Bind to a specific source port.
- long wait; // -w Wait # seconds for a connection.
-};
-
// toys/other/nsenter.c
struct nsenter_data {
@@ -291,6 +316,12 @@ struct oneit_data {
char *console;
};
+// toys/other/setfattr.c
+
+struct setfattr_data {
+ char *x, *v, *n;
+};
+
// toys/other/shred.c
struct shred_data {
@@ -310,8 +341,8 @@ struct stat_data {
struct stat st;
struct statfs sf;
} stat;
- struct passwd *user_name;
- struct group *group_name;
+ char *file, *pattern;
+ int patlen;
};
// toys/other/swapon.c
@@ -352,6 +383,7 @@ struct truncate_data {
// toys/other/xxd.c
struct xxd_data {
+ long s;
long g;
long l;
long c;
@@ -400,6 +432,12 @@ struct brctl_data {
int sockfd;
};
+// toys/pending/chrt.c
+
+struct chrt_data {
+ long pid;
+};
+
// toys/pending/compress.c
struct compress_data {
@@ -443,8 +481,18 @@ struct crontab_data {
// toys/pending/dd.c
struct dd_data {
- int sig;
-};
+ int show_xfer;
+ int show_records;
+ unsigned long long bytes, c_count, in_full, in_part, out_full, out_part;
+ struct timeval start;
+ struct {
+ char *name;
+ int fd;
+ unsigned char *buff, *bp;
+ long sz, count;
+ unsigned long long offset;
+ } in, out;
+};;
// toys/pending/dhcp.c
@@ -516,12 +564,6 @@ struct fdisk_data {
long cylinders;
};
-// toys/pending/file.c
-
-struct file_data {
- int max_name_len;
-};
-
// toys/pending/fold.c
struct fold_data {
@@ -557,6 +599,12 @@ struct ftpget_data {
char buf[sizeof(struct sockaddr_storage)];
};
+// toys/pending/getfattr.c
+
+struct getfattr_data {
+ char *n;
+};
+
// toys/pending/getty.c
struct getty_data {
@@ -702,13 +750,6 @@ struct more_data {
int cin_fd;
};
-// toys/pending/netstat.c
-
-struct netstat_data {
- char current_name[21];
- int some_process_unidentified;
-};;
-
// toys/pending/openvt.c
struct openvt_data {
@@ -1025,6 +1066,12 @@ struct expand_data {
unsigned tabcount, *tab;
};
+// toys/posix/file.c
+
+struct file_data {
+ int max_name_len;
+};
+
// toys/posix/find.c
struct find_data {
@@ -1076,7 +1123,7 @@ struct ls_data {
unsigned screen_width;
int nl_title;
- char uid_buf[12], gid_buf[12], *escmore;
+ char *escmore;
};
// toys/posix/mkdir.c
@@ -1142,6 +1189,7 @@ struct paste_data {
struct patch_data {
char *infile;
long prefix;
+ char *dir;
struct double_list *current_hunk;
long oldline, oldlen, newline, newlen;
@@ -1175,8 +1223,9 @@ struct ps_data {
struct arg_list *p;
struct arg_list *o;
struct arg_list *k;
+ struct arg_list *O;
} top;
- struct{
+ struct {
char *L;
struct arg_list *G;
struct arg_list *g;
@@ -1197,6 +1246,7 @@ struct ps_data {
struct sysinfo si;
#endif
struct ptr_len gg, GG, pp, PP, ss, tt, uu, UU;
+ struct dirtree *threadparent;
unsigned width, height;
dev_t tty;
void *fields, *kfields;
@@ -1304,7 +1354,7 @@ struct uudecode_data {
// toys/posix/wc.c
struct wc_data {
- unsigned long totals[3];
+ unsigned long totals[4];
};
// toys/posix/xargs.c
@@ -1322,6 +1372,7 @@ struct xargs_data {
extern union global_union {
struct getprop_data getprop;
+ struct log_data log;
struct hello_data hello;
struct skeleton_data skeleton;
struct dmesg_data dmesg;
@@ -1336,6 +1387,10 @@ extern union global_union {
struct seq_data seq;
struct su_data su;
struct umount_data umount;
+ struct ifconfig_data ifconfig;
+ struct netcat_data netcat;
+ struct netstat_data netstat;
+ struct tunctl_data tunctl;
struct acpi_data acpi;
struct base64_data base64;
struct blockdev_data blockdev;
@@ -1344,7 +1399,6 @@ extern union global_union {
struct free_data free;
struct hexedit_data hexedit;
struct hwclock_data hwclock;
- struct ifconfig_data ifconfig;
struct ionice_data ionice;
struct login_data login;
struct losetup_data losetup;
@@ -1354,9 +1408,9 @@ extern union global_union {
struct mkpasswd_data mkpasswd;
struct mkswap_data mkswap;
struct modinfo_data modinfo;
- struct netcat_data netcat;
struct nsenter_data nsenter;
struct oneit_data oneit;
+ struct setfattr_data setfattr;
struct shred_data shred;
struct stat_data stat;
struct swapon_data swapon;
@@ -1368,6 +1422,7 @@ extern union global_union {
struct arping_data arping;
struct bootchartd_data bootchartd;
struct brctl_data brctl;
+ struct chrt_data chrt;
struct compress_data compress;
struct crond_data crond;
struct crontab_data crontab;
@@ -1379,10 +1434,10 @@ extern union global_union {
struct dumpleases_data dumpleases;
struct expr_data expr;
struct fdisk_data fdisk;
- struct file_data file;
struct fold_data fold;
struct fsck_data fsck;
struct ftpget_data ftpget;
+ struct getfattr_data getfattr;
struct getty_data getty;
struct groupadd_data groupadd;
struct host_data host;
@@ -1397,7 +1452,6 @@ extern union global_union {
struct mke2fs_data mke2fs;
struct modprobe_data modprobe;
struct more_data more;
- struct netstat_data netstat;
struct openvt_data openvt;
struct ping_data ping;
struct route_data route;
@@ -1428,6 +1482,7 @@ extern union global_union {
struct du_data du;
struct env_data env;
struct expand_data expand;
+ struct file_data file;
struct find_data find;
struct grep_data grep;
struct head_data head;
diff --git a/generated/help.h b/generated/help.h
index bf20e956..d5be45e8 100644
--- a/generated/help.h
+++ b/generated/help.h
@@ -18,6 +18,8 @@
#define HELP_toybox_float "Include floating point support infrastructure and commands that\nrequire it.\n\n"
+#define HELP_toybox_libcrypto "Use faster hash functions out of exteral -lcrypto library.\n\n"
+
#define HELP_toybox_smack "Include SMACK options in commands like ls for systems like Tizen.\n\n\n"
#define HELP_toybox_selinux "Include SELinux options in commands such as ls, and add\nSELinux-specific commands such as chcon to the Android menu.\n\n"
@@ -28,14 +30,22 @@
#define HELP_toybox "usage: toybox [--long | --version | [command] [arguments...]]\n\nWith no arguments, shows available commands. First argument is\nname of a command to run, followed by any arguments to that command.\n\n--long Show path to each command\n--version Show toybox version\n\nTo install command symlinks, try:\n for i in $(/bin/toybox --long); do ln -s /bin/toybox $i; done\n\n"
+#define HELP_stop "usage: stop [SERVICE...]\n\nStop the given system service, or netd/surfaceflinger/zygotes.\n\n"
+
+#define HELP_start "usage: start [SERVICE...]\n\nStarts the given system service, or netd/surfaceflinger/zygotes.\n\n"
+
#define HELP_setprop "usage: setprop NAME VALUE\n\nSets an Android system property.\n\n"
#define HELP_setenforce "usage: setenforce [enforcing|permissive|1|0]\n\nSets whether SELinux is enforcing (1) or permissive (0).\n\n"
+#define HELP_sendevent "usage: sendevent DEVICE TYPE CODE VALUE\n\nSends a Linux input event.\n\n"
+
#define HELP_runcon "usage: runcon CONTEXT COMMAND [ARGS...]\n\nRun a command in a specified security context.\n\n"
#define HELP_restorecon "usage: restorecon [-D] [-F] [-R] [-n] [-v] FILE...\n\nRestores the default security contexts for the given files.\n\n-D apply to /data/data too\n-F force reset\n-R recurse into directories\n-n don't make any changes; useful with -v to see what would change\n-v verbose: show any changes\n\n"
+#define HELP_log "usage: log [-p PRI] [-t TAG] MESSAGE...\n\nLogs message to logcat.\n\n-p use the given priority instead of INFO:\n d: DEBUG e: ERROR f: FATAL i: INFO v: VERBOSE w: WARN s: SILENT\n-t use the given tag instead of \"log\"\n\n"
+
#define HELP_load_policy "usage: load_policy FILE\n\nLoad the specified policy file.\n\n"
#define HELP_getprop "usage: getprop [NAME [DEFAULT]]\n\nGets an Android system property, or lists them all.\n\n"
@@ -74,9 +84,17 @@
#define HELP_mknod "usage: mknod [-Z CONTEXT] ... [-m MODE] NAME TYPE [MAJOR MINOR]\n\nCreate a special file NAME with a given type. TYPE is b for block device,\nc or u for character device, p for named pipe (which ignores MAJOR/MINOR).\n-Z Set security context to created file\n-m Mode (file permissions) of new device, in octal or u+x format\n"
-#define HELP_sha1sum "usage: sha1sum [FILE]...\n\ncalculate sha1 hash for each input file, reading from stdin if none.\nOutput one hash (20 hex digits) for each input file, followed by\nfilename.\n\n-b brief (hash only, no filename)\n\n"
+#define HELP_sha512sum "See sha1sum\n\n"
-#define HELP_md5sum "usage: md5sum [FILE]...\n\nCalculate md5 hash for each input file, reading from stdin if none.\nOutput one hash (16 hex digits) for each input file, followed by\nfilename.\n\n-b brief (hash only, no filename)\n\n"
+#define HELP_sha384sum "See sha1sum\n\n"
+
+#define HELP_sha256sum "See sha1sum\n\n"
+
+#define HELP_sha224sum "See sha1sum\n\n"
+
+#define HELP_sha1sum "usage: sha?sum [-b] [-c FILE] [FILE]...\n\ncalculate sha hash for each input file, reading from stdin if none. Output\none hash (40 hex digits for sha1, 56 for sha224, 64 for sha256, 96 for sha384,\nand 128 for sha512) for each input file, followed by filename.\n\n-b brief (hash only, no filename)\n-c Check each line of FILE is the same hash+filename we'd output.\n\n"
+
+#define HELP_md5sum "usage: md5sum [-b] [-c FILE] [FILE]...\n\nCalculate md5 hash for each input file, reading from stdin if none.\nOutput one hash (32 hex digits) for each input file, followed by filename.\n\n-b brief (hash only, no filename)\n-c Check each line of FILE is the same hash+filename we'd output.\n\n"
#define HELP_killall "usage: killall [-l] [-iqv] [-SIGNAL|-s SIGNAL] PROCESS_NAME...\n\nSend a signal (default: TERM) to all processes with the given names.\n\n-i ask for confirmation before killing\n-l print list of all available signals\n-q don't print any warnings or error messages\n-s send SIGNAL instead of SIGTERM\n-v report if the signal was successfully sent\n\n"
@@ -84,9 +102,19 @@
#define HELP_dmesg "usage: dmesg [-c] [-r|-t] [-n LEVEL] [-s SIZE]\n\nPrint or control the kernel ring buffer.\n\n-c Clear the ring buffer after printing\n-n Set kernel logging LEVEL (1-9)\n-r Raw output (with <level markers>)\n-s Show the last SIZE many bytes\n-t Don't print kernel's timestamps\n\n"
+#define HELP_tunctl "usage: tunctl [-dtT] [-u USER] NAME\n\nCreate and delete tun/tap virtual ethernet devices.\n\n-T Use tap (ethernet frames) instead of tun (ip packets)\n-d Delete tun/tap device\n-t Create tun/tap device\n-u Set owner (user who can read/write device without root access)\n\n\n"
+
+#define HELP_rfkill "Usage: rfkill COMMAND [DEVICE]\n\nEnable/disable wireless devices.\n\nCommands:\nlist [DEVICE] List current state\nblock DEVICE Disable device\nunblock DEVICE Enable device\n\nDEVICE is an index number, or one of:\nall, wlan(wifi), bluetooth, uwb(ultrawideband), wimax, wwan, gps, fm.\n\n"
+
+#define HELP_netstat "usage: netstat [-pWrxwutneal]\n\nDisplay networking information. Default is netsat -tuwx\n\n-r routing table\n-a all sockets (not just connected)\n-l listening server sockets\n-t TCP sockets\n-u UDP sockets\n-w raw sockets\n-x unix sockets\n-e extended info\n-n don't resolve names\n-W wide display\n-p PID/Program name of sockets\n\n"
+
+#define HELP_netcat "usage: netcat [-tu] [-lL COMMAND...] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}\n\n-L listen for multiple incoming connections (server mode).\n-f use FILENAME (ala /dev/ttyS0) instead of network\n-l listen for one incoming connection.\n-p local port number\n-q SECONDS quit this many seconds after EOF on stdin.\n-s local ipv4 address\n-t allocate tty (must come before -l or -L)\n-w SECONDS timeout for connection\n\nUse \"stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho\" with\nnetcat -f to connect to a serial port.\n\nThe command line after -l or -L is executed to handle each incoming\nconnection. If none, the connection is forwarded to stdin/stdout.\n\nFor a quick-and-dirty server, try something like:\nnetcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l\n"
+
+#define HELP_ifconfig "usage: ifconfig [-a] [INTERFACE [ACTION...]]\n\nDisplay or configure network interface.\n\nWith no arguments, display active interfaces. First argument is interface\nto operate on, one argument by itself displays that interface.\n\n-a Show all interfaces, not just active ones\n\nAdditional arguments are actions to perform on the interface:\n\nADDRESS[/NETMASK] - set IPv4 address (1.2.3.4/5)\ndefault - unset ipv4 address\nadd|del ADDRESS[/PREFIXLEN] - add/remove IPv6 address (1111::8888/128)\nup - enable interface\ndown - disable interface\n\nnetmask|broadcast|pointopoint ADDRESS - set more IPv4 characteristics\nhw ether|infiniband ADDRESS - set LAN hardware address (AA:BB:CC...)\ntxqueuelen LEN - number of buffered packets before output blocks\nmtu LEN - size of outgoing packets (Maximum Transmission Unit)\n\nFlags you can set on an interface (or -remove by prefixing with -):\narp - don't use Address Resolution Protocol to map LAN routes\npromisc - don't discard packets that aren't to this LAN hardware address\nmulticast - force interface into multicast mode if the driver doesn't\nallmulti - promisc for multicast packets\n\nObsolete fields included for historical purposes:\nirq|io_addr|mem_start ADDR - micromanage obsolete hardware\noutfill|keepalive INTEGER - SLIP analog dialup line quality monitoring\nmetric INTEGER - added to Linux 0.9.10 with comment \"never used\", still true\n\n"
+
#define HELP_yes "usage: yes [args...]\n\nRepeatedly output line until killed. If no args, output 'y'.\n\n\n"
-#define HELP_xxd "usage: xxd [-c n] [-g n] [-l n] [-p] [-r] [file]\n\nHexdump a file to stdout. If no file is listed, copy from stdin.\nFilename \"-\" is a synonym for stdin.\n\n-c n Show n bytes per line (default 16).\n-g n Group bytes by adding a ' ' every n bytes (default 2).\n-l n Limit of n bytes before stopping (default is no limit).\n-p Plain hexdump (30 bytes/line, no grouping).\n-r Reverse operation: turn a hexdump into a binary file.\n\n"
+#define HELP_xxd "usage: xxd [-c n] [-g n] [-l n] [-p] [-r] [-s n] [file]\n\nHexdump a file to stdout. If no file is listed, copy from stdin.\nFilename \"-\" is a synonym for stdin.\n\n-c n Show n bytes per line (default 16).\n-g n Group bytes by adding a ' ' every n bytes (default 2).\n-l n Limit of n bytes before stopping (default is no limit).\n-p Plain hexdump (30 bytes/line, no grouping).\n-r Reverse operation: turn a hexdump into a binary file.\n-s n Skip to offset n.\n\n"
#define HELP_which "usage: which [-a] filename ...\n\nSearch $PATH for executable files matching filename(s).\n\n-a Show all matches\n\n"
@@ -118,15 +146,15 @@
#define HELP_swapoff "usage: swapoff swapregion\n\nDisable swapping on a given swapregion.\n\n"
-#define HELP_stat "usage: stat [-f] [-t] [-c FORMAT] FILE...\n\nDisplay status of files or filesystems.\n\n-f display filesystem status instead of file status\n-c Output specified FORMAT string instead of default\n-t Display info in terse form\n\nThe valid format escape sequences for files:\n%a Access bits (octal) |%A Access bits (flags)|%b Blocks allocated\n%B Bytes per block |%d Device ID (dec) |%D Device ID (hex)\n%f All mode bits (hex) |%F File type |%g Group ID\n%G Group name |%h Hard links |%i Inode\n%n Filename |%N Long filename |%o I/O block size\n%s Size (bytes) |%u User ID |%U User name\n%x Access time |%X Access unix time |%y File write time\n%Y File write unix time|%z Dir change time |%Z Dir change unix time\n\nThe valid format escape sequences for filesystems:\n%a Available blocks |%b Total blocks |%c Total inodes\n%d Free inodes |%f Free blocks |%i File system ID\n%l Max filename length |%n File name |%s Fragment size\n%S Best transfer size |%t Filesystem type |%T Filesystem type name\n\n"
+#define HELP_stat "usage: stat [-tfL] [-c FORMAT] FILE...\n\nDisplay status of files or filesystems.\n\n-c Output specified FORMAT string instead of default\n-f display filesystem status instead of file status\n-L Follow symlinks\n-t terse (-c \"%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\")\n (with -f = -c \"%n %i %l %t %s %S %b %f %a %c %d\")\n\nThe valid format escape sequences for files:\n%a Access bits (octal) |%A Access bits (flags)|%b Size/512\n%B Bytes per %b (512) |%d Device ID (dec) |%D Device ID (hex)\n%f All mode bits (hex) |%F File type |%g Group ID\n%G Group name |%h Hard links |%i Inode\n%m Mount point |%n Filename |%N Long filename\n%o I/O block size |%s Size (bytes) |%t Devtype major (hex)\n%T Devtype minor (hex) |%u User ID |%U User name\n%x Access time |%X Access unix time |%y File write time\n%Y File write unix time|%z Dir change time |%Z Dir change unix time\n\nThe valid format escape sequences for filesystems:\n%a Available blocks |%b Total blocks |%c Total inodes\n%d Free inodes |%f Free blocks |%i File system ID\n%l Max filename length |%n File name |%s Fragment size\n%S Best transfer size |%t FS type (hex) |%T FS type (driver name)\n\n"
#define HELP_shred "usage: shred [-fuz] [-n COUNT] [-s SIZE] FILE...\n\nSecurely delete a file by overwriting its contents with random data.\n\n-f Force (chmod if necessary)\n-n COUNT Random overwrite iterations (default 1)\n-o OFFSET Start at OFFSET\n-s SIZE Use SIZE instead of detecting file size\n-u unlink (actually delete file when done)\n-x Use exact size (default without -s rounds up to next 4k)\n-z zero at end\n\nNote: data journaling filesystems render this command useless, you must\noverwrite all free space (fill up disk) to erase old data on those.\n\n"
#define HELP_setsid "usage: setsid [-t] command [args...]\n\nRun process in a new session.\n\n-t Grab tty (become foreground process, receiving keyboard signals)\n\n"
-#define HELP_rmmod "usage: rmmod [-wf] [MODULE]\n\nUnload the module named MODULE from the Linux kernel.\n-f Force unload of a module\n-w Wait until the module is no longer used.\n\n\n"
+#define HELP_setfattr "usage: setfattr [-h] [-x|-n NAME] [-v VALUE] FILE...\n\nWrite POSIX extended attributes.\n\n-h Do not dereference symlink.\n-n Set given attribute.\n-x Remove given attribute.\n-v Set value for attribute -n (default is empty).\n\n"
-#define HELP_rfkill "Usage: rfkill COMMAND [DEVICE]\n\nEnable/disable wireless devices.\n\nCommands:\nlist [DEVICE] List current state\nblock DEVICE Disable device\nunblock DEVICE Enable device\n\nDEVICE is an index number, or one of:\nall, wlan(wifi), bluetooth, uwb(ultrawideband), wimax, wwan, gps, fm.\n\n"
+#define HELP_rmmod "usage: rmmod [-wf] [MODULE]\n\nUnload the module named MODULE from the Linux kernel.\n-f Force unload of a module\n-w Wait until the module is no longer used.\n\n\n"
#define HELP_rev "usage: rev [FILE...]\n\nOutput each line reversed, when no files are given stdin is used.\n\n"
@@ -156,8 +184,6 @@
#define HELP_unshare "usage: unshare [-imnpuUr] COMMAND...\n\nCreate new container namespace(s) for this process and its children, so\nsome attribute is not shared with the parent process.\n\n-f Fork command in the background (--fork)\n-i SysV IPC (message queues, semaphores, shared memory) (--ipc)\n-m Mount/unmount tree (--mount)\n-n Network address, sockets, routing, iptables (--net)\n-p Process IDs and init (--pid)\n-r Become root (map current euid/egid to 0/0, implies -U) (--map-root-user)\n-u Host and domain names (--uts)\n-U UIDs, GIDs, capabilities (--user)\n\nA namespace allows a set of processes to have a different view of the\nsystem than other sets of processes.\n\n"
-#define HELP_netcat "usage: netcat [-tu] [-lL COMMAND...] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}\n\n-L listen for multiple incoming connections (server mode).\n-f use FILENAME (ala /dev/ttyS0) instead of network\n-l listen for one incoming connection.\n-p local port number\n-q SECONDS quit this many seconds after EOF on stdin.\n-s local ipv4 address\n-t allocate tty (must come before -l or -L)\n-w SECONDS timeout for connection\n\nUse \"stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho\" with\nnetcat -f to connect to a serial port.\n\nThe command line after -l or -L is executed to handle each incoming\nconnection. If none, the connection is forwarded to stdin/stdout.\n\nFor a quick-and-dirty server, try something like:\nnetcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l\n"
-
#define HELP_nbd_client "usage: nbd-client [-ns] HOST PORT DEVICE\n\n-n Do not fork into background\n-s nbd swap support (lock server into memory)\n\n"
#define HELP_mountpoint "usage: mountpoint [-q] [-d] directory\n mountpoint [-q] [-x] device\n\n-q Be quiet, return zero if directory is a mountpoint\n-d Print major/minor device number of the directory\n-x Print major/minor device number of the block device\n\n"
@@ -194,8 +220,6 @@
#define HELP_inotifyd "usage: inotifyd PROG FILE[:MASK] ...\n\nWhen a filesystem event matching MASK occurs to a FILE, run PROG as:\n\n PROG EVENTS FILE [DIRFILE]\n\nIf PROG is \"-\" events are sent to stdout.\n\nThis file is:\n a accessed c modified e metadata change w closed (writable)\n r opened D deleted M moved 0 closed (unwritable)\n u unmounted o overflow x unwatchable\n\nA file in this directory is:\n m moved in y moved out n created d deleted\n\nWhen x event happens for all FILEs, inotifyd exits (after waiting for PROG).\n\n"
-#define HELP_ifconfig "usage: ifconfig [-a] [INTERFACE [ACTION...]]\n\nDisplay or configure network interface.\n\nWith no arguments, display active interfaces. First argument is interface\nto operate on, one argument by itself displays that interface.\n\n-a Show all interfaces, not just active ones\n\nAdditional arguments are actions to perform on the interface:\n\nADDRESS[/NETMASK] - set IPv4 address (1.2.3.4/5)\ndefault - unset ipv4 address\nadd|del ADDRESS[/PREFIXLEN] - add/remove IPv6 address (1111::8888/128)\nup - enable interface\ndown - disable interface\n\nnetmask|broadcast|pointopoint ADDRESS - set more IPv4 characteristics\nhw ether|infiniband ADDRESS - set LAN hardware address (AA:BB:CC...)\ntxqueuelen LEN - number of buffered packets before output blocks\nmtu LEN - size of outgoing packets (Maximum Transmission Unit)\n\nFlags you can set on an interface (or -remove by prefixing with -):\narp - don't use Address Resolution Protocol to map LAN routes\npromisc - don't discard packets that aren't to this LAN hardware address\nmulticast - force interface into multicast mode if the driver doesn't\nallmulti - promisc for multicast packets\n\nObsolete fields included for historical purposes:\nirq|io_addr|mem_start ADDR - micromanage obsolete hardware\noutfill|keepalive INTEGER - SLIP analog dialup line quality monitoring\nmetric INTEGER - added to Linux 0.9.10 with comment \"never used\", still true\n\n"
-
#define HELP_hwclock "usage: hwclock [-rswtluf]\n\n-f FILE Use specified device file instead of /dev/rtc (--rtc)\n-l Hardware clock uses localtime (--localtime)\n-r Show hardware clock time (--show)\n-s Set system time from hardware clock (--hctosys)\n-t Set the system time based on the current timezone (--systz)\n-u Hardware clock uses UTC (--utc)\n-w Set hardware clock from system time (--systohc)\n\n"
#define HELP_hostid "usage: hostid\n\nPrint the numeric identifier for the current host.\n\n"
@@ -260,10 +284,10 @@
#define HELP_useradd "usage: useradd [-SDH] [-h DIR] [-s SHELL] [-G GRP] [-g NAME] [-u UID] USER [GROUP]\n\nCreate new user, or add USER to GROUP\n\n-D Don't assign a password\n-g NAME Real name\n-G GRP Add user to existing group\n-h DIR Home directory\n-H Don't create home directory\n-s SHELL Login shell\n-S Create a system user\n-u UID User id\n\n"
-#define HELP_traceroute "usage: traceroute [-46FUIldnvr] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]\n[-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE] [-z PAUSE_MSEC] HOST [BYTES]\n\ntraceroute6 [-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES][-s SRC_IP] [-t TOS] [-w WAIT_SEC]\n [-i IFACE] HOST [BYTES]\n\nTrace the route to HOST\n\n-4,-6 Force IP or IPv6 name resolution\n-F Set the don't fragment bit (supports IPV4 only)\n-U Use UDP datagrams instead of ICMP ECHO (supports IPV4 only)\n-I Use ICMP ECHO instead of UDP datagrams (supports IPV4 only)\n-l Display the TTL value of the returned packet (supports IPV4 only)\n-d Set SO_DEBUG options to socket\n-n Print numeric addresses\n-v verbose\n-r Bypass routing tables, send directly to HOST\n-m Max time-to-live (max number of hops)(RANGE 1 to 255)\n-p Base UDP port number used in probes(default 33434)(RANGE 1 to 65535)\n-q Number of probes per TTL (default 3)(RANGE 1 to 255)\n-s IP address to use as the source address\n-t Type-of-service in probe packets (default 0)(RANGE 0 to 255)\n-w Time in seconds to wait for a response (default 3)(RANGE 0 to 86400)\n-g Loose source route gateway (8 max) (supports IPV4 only)\n-z Pause Time in milisec (default 0)(RANGE 0 to 86400) (supports IPV4 only)\n-f Start from the 1ST_TTL hop (instead from 1)(RANGE 1 to 255) (supports IPV4 only)\n-i Specify a network interface to operate with\n\n"
-
#define HELP_tr "usage: tr [-cds] SET1 [SET2]\n\nTranslate, squeeze, or delete characters from stdin, writing to stdout\n\n-c/-C Take complement of SET1\n-d Delete input characters coded SET1\n-s Squeeze multiple output characters of SET2 into one character\n\n"
+#define HELP_traceroute "usage: traceroute [-46FUIldnvr] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]\n[-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE] [-z PAUSE_MSEC] HOST [BYTES]\n\ntraceroute6 [-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES][-s SRC_IP] [-t TOS] [-w WAIT_SEC]\n [-i IFACE] HOST [BYTES]\n\nTrace the route to HOST\n\n-4,-6 Force IP or IPv6 name resolution\n-F Set the don't fragment bit (supports IPV4 only)\n-U Use UDP datagrams instead of ICMP ECHO (supports IPV4 only)\n-I Use ICMP ECHO instead of UDP datagrams (supports IPV4 only)\n-l Display the TTL value of the returned packet (supports IPV4 only)\n-d Set SO_DEBUG options to socket\n-n Print numeric addresses\n-v verbose\n-r Bypass routing tables, send directly to HOST\n-m Max time-to-live (max number of hops)(RANGE 1 to 255)\n-p Base UDP port number used in probes(default 33434)(RANGE 1 to 65535)\n-q Number of probes per TTL (default 3)(RANGE 1 to 255)\n-s IP address to use as the source address\n-t Type-of-service in probe packets (default 0)(RANGE 0 to 255)\n-w Time in seconds to wait for a response (default 3)(RANGE 0 to 86400)\n-g Loose source route gateway (8 max) (supports IPV4 only)\n-z Pause Time in milisec (default 0)(RANGE 0 to 86400) (supports IPV4 only)\n-f Start from the 1ST_TTL hop (instead from 1)(RANGE 1 to 255) (supports IPV4 only)\n-i Specify a network interface to operate with\n\n"
+
#define HELP_tftpd "usage: tftpd [-cr] [-u USER] [DIR]\n\nTransfer file from/to tftp server.\n\n-r read only\n-c Allow file creation via upload\n-u run as USER\n-l Log to syslog (inetd mode requires this)\n\n"
#define HELP_tftp "usage: tftp [OPTIONS] HOST [PORT]\n\nTransfer file from/to tftp server.\n\n-l FILE Local FILE\n-r FILE Remote FILE\n-g Get file\n-p Put file\n-b SIZE Transfer blocks of SIZE octets(8 <= SIZE <= 65464)\n\n"
@@ -298,8 +322,6 @@
#define HELP_openvt "usage: openvt [-c N] [-sw] [command [command_options]]\n\nstart a program on a new virtual terminal (VT)\n\n-c N Use VT N\n-s Switch to new VT\n-w Wait for command to exit\n\nif -sw used together, switch back to originating VT when command completes\n\n"
-#define HELP_netstat "usage: netstat [-pWrxwutneal]\n\nDisplay networking information.\n\n-r Display routing table.\n-a Display all sockets (Default: Connected).\n-l Display listening server sockets.\n-t Display TCP sockets.\n-u Display UDP sockets.\n-w Display Raw sockets.\n-x Display Unix sockets.\n-e Display other/more information.\n-n Don't resolve names.\n-W Wide Display.\n-p Display PID/Program name for sockets.\n\n"
-
#define HELP_more "usage: more [FILE...]\n\nView FILE(s) (or stdin) one screenful at a time.\n\n"
#define HELP_modprobe "usage: modprobe [-alrqvsDb] MODULE [symbol=value][...]\n\nmodprobe utility - inserts modules and dependencies.\n\n-a Load multiple MODULEs\n-l List (MODULE is a pattern)\n-r Remove MODULE (stacks) or do autoclean\n-q Quiet\n-v Verbose\n-s Log to syslog\n-D Show dependencies\n-b Apply blacklist to module names too\n\n"
@@ -344,14 +366,14 @@
#define HELP_getty "usage: getty [OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]\n\n-h Enable hardware RTS/CTS flow control\n-L Set CLOCAL (ignore Carrier Detect state)\n-m Get baud rate from modem's CONNECT status message\n-n Don't prompt for login name\n-w Wait for CR or LF before sending /etc/issue\n-i Don't display /etc/issue\n-f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue\n-l LOGIN Invoke LOGIN instead of /bin/login\n-t SEC Terminate after SEC if no login name is read\n-I INITSTR Send INITSTR before anything else\n-H HOST Log HOST into the utmp file as the hostname\n\n"
+#define HELP_getfattr "usage: getfattr [-d] [-h] [-n NAME] FILE...\n\nRead POSIX extended attributes.\n\n-d Show values as well as names.\n-h Do not dereference symbolic links.\n-n Show only attributes with the given name.\n\n"
+
#define HELP_ftpget "usage: ftpget [-cv] [-u USER -p PASSWORD -P PORT] HOST_NAME [LOCAL_FILENAME] REMOTE_FILENAME\nusage: ftpput [-v] [-u USER -p PASSWORD -P PORT] HOST_NAME [REMOTE_FILENAME] LOCAL_FILENAME\n\nftpget - Get a remote file from FTP.\nftpput - Upload a local file on remote machine through FTP.\n\n-c Continue previous transfer.\n-v Verbose.\n-u User name.\n-p Password.\n-P Port Number (default 21).\n\n"
#define HELP_fsck "usage: fsck [-ANPRTV] [-C FD] [-t FSTYPE] [FS_OPTS] [BLOCKDEV]...\n\nCheck and repair filesystems\n\n-A Walk /etc/fstab and check all filesystems\n-N Don't execute, just show what would be done\n-P With -A, check filesystems in parallel\n-R With -A, skip the root filesystem\n-T Don't show title on startup\n-V Verbose\n-C n Write status information to specified filedescriptor\n-t TYPE List of filesystem types to check\n\n\n"
#define HELP_fold "usage: fold [-bsu] [-w WIDTH] [FILE...]\n\nFolds (wraps) or unfolds ascii text by adding or removing newlines.\nDefault line width is 80 columns for folding and infinite for unfolding.\n\n-b Fold based on bytes instead of columns\n-s Fold/unfold at whitespace boundaries if possible\n-u Unfold text (and refold if -w is given)\n-w Set lines to WIDTH columns or bytes\n\n"
-#define HELP_file "usage: file [file...]\n\nExamine the given files and describe their content types.\n\n"
-
#define HELP_fdisk "usage: fdisk [-lu] [-C CYLINDERS] [-H HEADS] [-S SECTORS] [-b SECTSZ] DISK\n\nChange partition table\n\n-u Start and End are in sectors (instead of cylinders)\n-l Show partition table for each DISK, then exit\n-b size sector size (512, 1024, 2048 or 4096)\n-C CYLINDERS Set number of cylinders/heads/sectors\n-H HEADS\n-S SECTORS\n\n"
#define HELP_expr "usage: expr ARG1 OPERATOR ARG2...\n\nEvaluate expression and print result. For example, \"expr 1 + 2\".\n\nThe supported operators are (grouped from highest to lowest priority):\n\n ( ) : * / % + - != <= < >= > = & |\n\nEach constant and operator must be a separate command line argument.\nAll operators are infix, meaning they expect a constant (or expression\nthat resolves to a constant) on each side of the operator. Operators of\nthe same priority (within each group above) are evaluated left to right.\nParentheses may be used (as separate arguments) to elevate the priority\nof expressions.\n\nCalling expr from a command shell requires a lot of \\( or '*' escaping\nto avoid interpreting shell control characters.\n\nThe & and | operators are logical (not bitwise) and may operate on\nstrings (a blank string is \"false\"). Comparison operators may also\noperate on strings (alphabetical sort).\n\nConstants may be strings or integers. Comparison, logical, and regex\noperators may operate on strings (a blank string is \"false\"), other\noperators require integers.\n\n"
@@ -362,11 +384,11 @@
#define HELP_dhcpd "usage: dhcpd [-46fS] [-i IFACE] [-P N] [CONFFILE]\n\n -f Run in foreground\n -i Interface to use\n -S Log to syslog too\n -P N Use port N (default ipv4 67, ipv6 547)\n -4, -6 Run as a DHCPv4 or DHCPv6 server\n\n"
-#define HELP_dhcp6 "usage: dhcp6 [-fbnqvR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n\n Configure network dynamicaly using DHCP.\n\n -i Interface to use (default eth0)\n -p Create pidfile\n -s Run PROG at DHCP events\n -t Send up to N Solicit packets\n -T Pause between packets (default 3 seconds)\n -A Wait N seconds after failure (default 20)\n -f Run in foreground\n -b Background if lease is not obtained\n -n Exit if lease is not obtained\n -q Exit after obtaining lease\n -R Release IP on exit\n -S Log to syslog too\n -r Request this IP address\n -v Verbose\n\n Signals:\n USR1 Renew current lease\n USR2 Release current lease\n\n"
-
#define HELP_dhcp "usage: dhcp [-fbnqvoCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL] [-O OPT]\n\n Configure network dynamicaly using DHCP.\n\n -i Interface to use (default eth0)\n -p Create pidfile\n -s Run PROG at DHCP events (default /usr/share/dhcp/default.script)\n -B Request broadcast replies\n -t Send up to N discover packets\n -T Pause between packets (default 3 seconds)\n -A Wait N seconds after failure (default 20)\n -f Run in foreground\n -b Background if lease is not obtained\n -n Exit if lease is not obtained\n -q Exit after obtaining lease\n -R Release IP on exit\n -S Log to syslog too\n -a Use arping to validate offered address\n -O Request option OPT from server (cumulative)\n -o Don't request any options (unless -O is given)\n -r Request this IP address\n -x OPT:VAL Include option OPT in sent packets (cumulative)\n -F Ask server to update DNS mapping for NAME\n -H Send NAME as client hostname (default none)\n -V VENDOR Vendor identifier (default 'toybox VERSION')\n -C Don't send MAC as client identifier\n -v Verbose\n\n Signals:\n USR1 Renew current lease\n USR2 Release current lease\n\n\n"
-#define HELP_dd "usage: dd [if=FILE] [of=FILE] [ibs=N] [obs=N] [bs=N] [count=N] [skip=N]\n [seek=N] [conv=notrunc|noerror|sync|fsync]\n\nOptions:\nif=FILE Read from FILE instead of stdin\nof=FILE Write to FILE instead of stdout\nbs=N Read and write N bytes at a time\nibs=N Read N bytes at a time\nobs=N Write N bytes at a time\ncount=N Copy only N input blocks\nskip=N Skip N input blocks\nseek=N Skip N output blocks\nconv=notrunc Don't truncate output file\nconv=noerror Continue after read errors\nconv=sync Pad blocks with zeros\nconv=fsync Physically write data out before finishing\n\nNumbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\nMD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)\nCopy a file, converting and formatting according to the operands.\n\n"
+#define HELP_dhcp6 "usage: dhcp6 [-fbnqvR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n\n Configure network dynamicaly using DHCP.\n\n -i Interface to use (default eth0)\n -p Create pidfile\n -s Run PROG at DHCP events\n -t Send up to N Solicit packets\n -T Pause between packets (default 3 seconds)\n -A Wait N seconds after failure (default 20)\n -f Run in foreground\n -b Background if lease is not obtained\n -n Exit if lease is not obtained\n -q Exit after obtaining lease\n -R Release IP on exit\n -S Log to syslog too\n -r Request this IP address\n -v Verbose\n\n Signals:\n USR1 Renew current lease\n USR2 Release current lease\n\n"
+
+#define HELP_dd "usage: dd [if=FILE] [of=FILE] [ibs=N] [obs=N] [bs=N] [count=N] [skip=N]\n [seek=N] [conv=notrunc|noerror|sync|fsync] [status=noxfer|none]\n\nOptions:\nif=FILE Read from FILE instead of stdin\nof=FILE Write to FILE instead of stdout\nbs=N Read and write N bytes at a time\nibs=N Read N bytes at a time\nobs=N Write N bytes at a time\ncount=N Copy only N input blocks\nskip=N Skip N input blocks\nseek=N Skip N output blocks\nconv=notrunc Don't truncate output file\nconv=noerror Continue after read errors\nconv=sync Pad blocks with zeros\nconv=fsync Physically write data out before finishing\nstatus=noxfer Don't show transfer rate\nstatus=none Don't show transfer rate or records in/out\n\nNumbers may be suffixed by c (*1), w (*2), b (*512), kD (*1000), k (*1024),\nMD (*1000*1000), M (*1024*1024), GD (*1000*1000*1000) or G (*1024*1024*1024).\n\n"
#define HELP_crontab "usage: crontab [-u user] FILE\n [-u user] [-e | -l | -r]\n [-c dir]\n\nFiles used to schedule the execution of programs.\n\n-c crontab dir\n-e edit user's crontab\n-l list user's crontab\n-r delete user's crontab\n-u user\nFILE Replace crontab by FILE ('-': stdin)\n\n"
@@ -384,6 +406,8 @@
#define HELP_compress "usage: compress [-zgLR19] [FILE]\n\nCompress or decompress file (or stdin) using \"deflate\" algorithm.\n\n-1 min compression\n-9 max compression (default)\n-g gzip (default)\n-L zlib\n-R raw\n-z zip\n\n"
+#define HELP_chrt "usage: chrt [-m] [-p PID] [POLICY PRIO] [COMMAND [ARGS...]]\n\nGet/set a process' real-time (scheduling) attributes.\n\n-p Apply to given pid\n-R Set SCHED_RESET_ON_FORK\n-m Show min/max priorities available\n\nPolicies:\n -b SCHED_BATCH -f SCHED_FIFO -i SCHED_IDLE\n -o SCHED_OTHER -r SCHED_RR\n\n"
+
#define HELP_brctl "usage: brctl COMMAND [BRIDGE [INTERFACE]]\n\nManage ethernet bridges\n\nCommands:\nshow Show a list of bridges\naddbr BRIDGE Create BRIDGE\ndelbr BRIDGE Delete BRIDGE\naddif BRIDGE IFACE Add IFACE to BRIDGE\ndelif BRIDGE IFACE Delete IFACE from BRIDGE\nsetageing BRIDGE TIME Set ageing time\nsetfd BRIDGE TIME Set bridge forward delay\nsethello BRIDGE TIME Set hello time\nsetmaxage BRIDGE TIME Set max message age\nsetpathcost BRIDGE PORT COST Set path cost\nsetportprio BRIDGE PORT PRIO Set port priority\nsetbridgeprio BRIDGE PRIO Set bridge priority\nstp BRIDGE [1/yes/on|0/no/off] STP on/off\n\n"
#define HELP_bootchartd "usage: bootchartd {start [PROG ARGS]}|stop|init\n\nCreate /var/log/bootlog.tgz with boot chart data\n\nstart: start background logging; with PROG, run PROG,\n then kill logging with USR1\nstop: send USR1 to all bootchartd processes\ninit: start background logging; stop when getty/xdm is seen\n (for init scripts)\n\nUnder PID 1: as init, then exec $bootchart_init, /init, /sbin/init\n\n"
@@ -446,21 +470,21 @@
#define HELP_pwd "usage: pwd [-L|-P]\n\nPrint working (current) directory.\n\n-L Use shell's path from $PWD (when applicable)\n-P Print cannonical absolute path\n\n"
-#define HELP_pkill "usage: pkill [-l SIGNAL] [PATTERN]\n\n-l SIGNAL to send\n-V verbose\n\n"
+#define HELP_pkill "usage: pkill [-SIGNAL|-l SIGNAL] [PATTERN]\n\n-l Send SIGNAL (default SIGTERM)\n-V verbose\n\n"
-#define HELP_pgrep "usage: pgrep [-Lcfnovx] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,] [-d DELIM] [-L SIGNAL] [PATTERN]\n\nSearch for process(es). PATTERN is an extended regular expression checked\nagainst command names.\n-G Match real Group ID(s)\n-L Send SIGNAL instead of printing name\n-P Match Parent Process ID(s)\n-U Match real User ID(s)\n-c Show only count of matches\n-d Use DELIM instead of newline\n-f Check full command line for PATTERN\n-g Match Process Group(s) (0 is current user)\n-l Show command name\n-n Newest match only\n-o Oldest match only\n-s Match Session ID(s) (0 for current)\n-t Match Terminal(s)\n-u Match effective User ID(s)\n-v Negate the match\n-x Match whole command (not substring)\n"
+#define HELP_pgrep "usage: pgrep [-cL] [-d DELIM] [-L SIGNAL] [PATTERN]\n\nSearch for process(es). PATTERN is an extended regular expression checked\nagainst command names.\n\n-c Show only count of matches\n-d Use DELIM instead of newline\n-L Send SIGNAL instead of printing name\n-l Show command name\n\n"
-#define HELP_top_common "usage: COMMON [-bq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]\n\n-b Batch mode (no tty)\n-d Delay SECONDS between each cycle (default 3)\n-n Exit after NUMBER iterations\n-p Show these PIDs\n-u Show these USERs\n-q Quiet (no header lines)\n\nCursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force\nupdate, R to reverse sort, Q to exit.\n\n"
+#define HELP_top_common "usage: * [-bfnoqvx] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]\n\n-G Match real Group ID(s)\n-P Match Parent Process ID(s)\n-U Match real User ID(s)\n-b Batch mode (no tty)\n-d Delay SECONDS between each cycle (default 3)\n-f Check full command line for PATTERN\n-g Match Process Group(s) (0 is current user)\n-n Exit after NUMBER iterations\n-n Newest match only\n-o Oldest match only\n-p Show these PIDs\n-q Quiet (no header lines)\n-s Match Session ID(s) (0 for current)\n-t Match Terminal(s)\n-u Match effective User ID(s)\n-u Show these USERs\n-v Negate the match\n-x Match whole command (not substring)\n\nCursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force\nupdate, R to reverse sort, Q to exit.\n"
#define HELP_iotop "usage: iotop [-AaKO]\n\nRank processes by I/O.\n\n-A All I/O, not just disk\n-a Accumulated I/O (not percentage)\n-K Kilobytes\n-k Fallback sort FIELDS (default -[D]IO,-ETIME,-PID)\n-O Only show processes doing I/O\n-o Show FIELDS (default PID,PR,USER,[D]READ,[D]WRITE,SWAP,[D]IO,COMM)\n-s Sort by field number (0-X, default 6)\n\n"
-#define HELP_top "usage: top [-H] [-k FIELD,] [-o FIELD,] [-s SORT]\n\nShow process activity in real time.\n\n-H Show threads\n-k Fallback sort FIELDS (default -S,-%CPU,-ETIME,-PID)\n-o Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)\n-s Sort by field number (1-X, default 9)\n\n"
+#define HELP_top "usage: top [-H] [-k FIELD,] [-o FIELD,] [-s SORT]\n\nShow process activity in real time.\n\n-H Show threads\n-k Fallback sort FIELDS (default -S,-%CPU,-ETIME,-PID)\n-o Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)\n-O Add FIELDS (replacing PR,NI,VIRT,RES,SHR,S from default)\n-s Sort by field number (1-X, default 9)\n\n"
-#define HELP_ps "usage: ps [-AadefLlnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]\n\nList processes.\n\nWhich processes to show (selections may be comma separated lists):\n\n-A All processes\n-a Processes with terminals that aren't session leaders\n-d All processes that aren't session leaders\n-e Same as -A\n-g Belonging to GROUPs\n-G Belonging to real GROUPs (before sgid)\n-p PIDs (--pid)\n-P Parent PIDs (--ppid)\n-s In session IDs\n-t Attached to selected TTYs\n-T Show threads\n-u Owned by USERs\n-U Owned by real USERs (before suid)\n\nOutput modifiers:\n\n-k Sort FIELDs in +increasing or -decreasting order (--sort)\n-M Measure field widths (expanding as necessary)\n-n Show numeric USER and GROUP\n-w Wide output (don't truncate at terminal width)\n\nWhich FIELDs to show. (Default = -o PID,TTY,TIME,CMD)\n\n-f Full listing (-o USER:8=UID,PID,PPID,C,STIME,TTY,TIME,CMD)\n-l Long listing (-o F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD)\n-o Output FIELDs instead of defaults, each with optional :size and =title\n-O Add FIELDS to defaults\n-Z Include LABEL\n\nAvailable -o FIELDs:\n\n ADDR Instruction pointer ARGS Command line (argv[] -path)\n BIT Is this process 32 or 64 bits\n CMD COMM, or ARGS with -f CMDLINE Command line (argv[])\n COMM Original command name COMMAND Original command path\n CPU Which processor running on ETIME Elapsed time since PID start\n F Flags (1=FORKNOEXEC 4=SUPERPRIV) GID Group id\n GROUP Group name LABEL Security label\n MAJFL Major page faults MINFL Minor page faults\n NAME Command name (argv[0]) NI Niceness (lower is faster)\n PCPU Percentage of CPU time used PCY Android scheduling policy\n PGID Process Group ID\n PID Process ID PPID Parent Process ID\n PRI Priority (higher is faster) PSR Processor last executed on\n RGID Real (before sgid) group ID RGROUP Real (before sgid) group name\n RSS Resident Set Size (pages in use) RTPRIO Realtime priority\n RUID Real (before suid) user ID RUSER Real (before suid) user name\n S Process state:\n R (running) S (sleeping) D (device I/O) T (stopped) t (traced)\n Z (zombie) X (deader) x (dead) K (wakekill) W (waking)\n SCHED Scheduling policy (0=other, 1=fifo, 2=rr, 3=batch, 4=iso, 5=idle)\n STAT Process state (S) plus:\n < high priority N low priority L locked memory\n s session leader + foreground l multithreaded\n STIME Start time of process in hh:mm (size :19 shows yyyy-mm-dd hh:mm:ss)\n SZ Memory Size (4k pages needed to completely swap out process)\n TCNT Thread count TID Thread ID\n TIME CPU time consumed TTY Controlling terminal\n UID User id USER User name\n VSZ Virtual memory size (1k units) %VSZ VSZ as % of physical memory\n WCHAN Waiting in kernel for\n\n"
+#define HELP_ps "usage: ps [-AadefLlnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]\n\nList processes.\n\nWhich processes to show (selections may be comma separated lists):\n\n-A All processes\n-a Processes with terminals that aren't session leaders\n-d All processes that aren't session leaders\n-e Same as -A\n-g Belonging to GROUPs\n-G Belonging to real GROUPs (before sgid)\n-p PIDs (--pid)\n-P Parent PIDs (--ppid)\n-s In session IDs\n-t Attached to selected TTYs\n-T Show threads\n-u Owned by USERs\n-U Owned by real USERs (before suid)\n\nOutput modifiers:\n\n-k Sort FIELDs in +increasing or -decreasting order (--sort)\n-M Measure field widths (expanding as necessary)\n-n Show numeric USER and GROUP\n-w Wide output (don't truncate at terminal width)\n\nWhich FIELDs to show. (Default = -o PID,TTY,TIME,CMD)\n\n-f Full listing (-o USER:8=UID,PID,PPID,C,STIME,TTY,TIME,ARGS=CMD)\n-l Long listing (-o F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD)\n-o Output FIELDs instead of defaults, each with optional :size and =title\n-O Add FIELDS to defaults\n-Z Include LABEL\n\nCommand line -o fields:\n\n ARGS CMDLINE minus initial path CMD Command (thread) name (stat[2])\n CMDLINE Command line (argv[]) COMM Command filename (/proc/$PID/exe)\n COMMAND Command file (/proc/$PID/exe) NAME Process name (argv[0] of $PID)\n\nProcess attribute -o FIELDs:\n\n ADDR Instruction pointer BIT Is this process 32 or 64 bits\n CPU Which processor running on ETIME Elapsed time since PID start\n F Flags (1=FORKNOEXEC 4=SUPERPRIV) GID Group id\n GROUP Group name LABEL Security label\n MAJFL Major page faults MINFL Minor page faults\n NI Niceness (lower is faster)\n PCPU Percentage of CPU time used PCY Android scheduling policy\n PGID Process Group ID\n PID Process ID PPID Parent Process ID\n PRI Priority (higher is faster) PSR Processor last executed on\n RGID Real (before sgid) group ID RGROUP Real (before sgid) group name\n RSS Resident Set Size (pages in use) RTPRIO Realtime priority\n RUID Real (before suid) user ID RUSER Real (before suid) user name\n S Process state:\n R (running) S (sleeping) D (device I/O) T (stopped) t (traced)\n Z (zombie) X (deader) x (dead) K (wakekill) W (waking)\n SCHED Scheduling policy (0=other, 1=fifo, 2=rr, 3=batch, 4=iso, 5=idle)\n STAT Process state (S) plus:\n < high priority N low priority L locked memory\n s session leader + foreground l multithreaded\n STIME Start time of process in hh:mm (size :19 shows yyyy-mm-dd hh:mm:ss)\n SZ Memory Size (4k pages needed to completely swap out process)\n TCNT Thread count TID Thread ID\n TIME CPU time consumed TTY Controlling terminal\n UID User id USER User name\n VSZ Virtual memory size (1k units) %VSZ VSZ as % of physical memory\n WCHAN What are we waiting in kernel for\n\n"
#define HELP_printf "usage: printf FORMAT [ARGUMENT...]\n\nFormat and print ARGUMENT(s) according to FORMAT, using C printf syntax\n(% escapes for cdeEfgGiosuxX, \\ escapes for abefnrtv0 or \\OCTAL or \\xHEX).\n\n"
-#define HELP_patch "usage: patch [-i file] [-p depth] [-Ru]\n\nApply a unified diff to one or more files.\n\n-i Input file (defaults=stdin)\n-l Loose match (ignore whitespace)\n-p Number of '/' to strip from start of file paths (default=all)\n-R Reverse patch.\n-u Ignored (only handles \"unified\" diffs)\n\nThis version of patch only handles unified diffs, and only modifies\na file when all all hunks to that file apply. Patch prints failed\nhunks to stderr, and exits with nonzero status if any hunks fail.\n\nA file compared against /dev/null (or with a date <= the epoch) is\ncreated/deleted as appropriate.\n\n"
+#define HELP_patch "usage: patch [-d DIR] [-i file] [-p depth] [-Rlu] [--dry-run]\n\nApply a unified diff to one or more files.\n\n-d modify files in DIR\n-i Input file (defaults=stdin)\n-l Loose match (ignore whitespace)\n-p Number of '/' to strip from start of file paths (default=all)\n-R Reverse patch.\n-u Ignored (only handles \"unified\" diffs)\n--dry-run Don't change files, just confirm patch applies\n\nThis version of patch only handles unified diffs, and only modifies\na file when all all hunks to that file apply. Patch prints failed\nhunks to stderr, and exits with nonzero status if any hunks fail.\n\nA file compared against /dev/null (or with a date <= the epoch) is\ncreated/deleted as appropriate.\n\n"
#define HELP_paste "usage: paste [-s] [-d list] [file...]\n\nReplace newlines in files.\n\n-d list list of delimiters to separate lines\n-s process files sequentially instead of in parallel\n\nBy default print corresponding lines separated by <tab>.\n\n"
@@ -478,9 +502,9 @@
#define HELP_mkdir "usage: mkdir [-vp] [-m mode] [dirname...]\n\nCreate one or more directories.\n\n-m set permissions of directory to mode.\n-p make parent directories as needed.\n-v verbose\n\n"
-#define HELP_ls_color "--color device=yellow symlink=turquoise/red dir=blue socket=purple\n files: exe=green suid=red suidfile=redback stickydir=greenback\n =auto means detect if output is a tty.\n\nusage: ls --color[=auto] [-ACFHLRSZacdfhiklmnpqrstux1] [directory...]\n\nlist files\n\nwhat to show:\n-a all files including .hidden -b escape nongraphic chars\n-c use ctime for timestamps -d directory, not contents\n-i inode number -k block sizes in kilobytes\n-p put a '/' after dir names -q unprintable chars as '?'\n-s size (in blocks) -u use access time for timestamps\n-A list all files but . and .. -H follow command line symlinks\n-L follow symlinks -R recursively list files in subdirs\n-F append /dir *exe @sym |FIFO -Z security context\n\noutput formats:\n-1 list one file per line -C columns (sorted vertically)\n-g like -l but no owner -h human readable sizes\n-l long (show full details) -m comma separated\n-n like -l but numeric uid/gid -o like -l but no group\n-x columns (horizontal sort)\n\nsorting (default is alphabetical):\n-f unsorted -r reverse -t timestamp -S size\n"
+#define HELP_ls_color "--color device=yellow symlink=turquoise/red dir=blue socket=purple\n files: exe=green suid=red suidfile=redback stickydir=greenback\n =auto means detect if output is a tty.\n\nusage: ls --color[=auto] [-ACFHLRSZacdfhiklmnpqrstux1] [directory...]\n\nlist files\n\nwhat to show:\n-a all files including .hidden -b escape nongraphic chars\n-c use ctime for timestamps -d directory, not contents\n-i inode number -p put a '/' after dir names\n-q unprintable chars as '?' -s storage used (1024 byte units)\n-u use access time for timestamps -A list all files but . and ..\n-H follow command line symlinks -L follow symlinks\n-R recursively list in subdirs -F append /dir *exe @sym |FIFO\n-Z security context\n\noutput formats:\n-1 list one file per line -C columns (sorted vertically)\n-g like -l but no owner -h human readable sizes\n-l long (show full details) -m comma separated\n-n like -l but numeric uid/gid -o like -l but no group\n-x columns (horizontal sort)\n\nsorting (default is alphabetical):\n-f unsorted -r reverse -t timestamp -S size\n"
-#define HELP_ls "usage: ls --color[=auto] [-ACFHLRSZacdfhiklmnpqrstux1] [directory...]\n\nlist files\n\nwhat to show:\n-a all files including .hidden -b escape nongraphic chars\n-c use ctime for timestamps -d directory, not contents\n-i inode number -k block sizes in kilobytes\n-p put a '/' after dir names -q unprintable chars as '?'\n-s size (in blocks) -u use access time for timestamps\n-A list all files but . and .. -H follow command line symlinks\n-L follow symlinks -R recursively list files in subdirs\n-F append /dir *exe @sym |FIFO -Z security context\n\noutput formats:\n-1 list one file per line -C columns (sorted vertically)\n-g like -l but no owner -h human readable sizes\n-l long (show full details) -m comma separated\n-n like -l but numeric uid/gid -o like -l but no group\n-x columns (horizontal sort)\n\nsorting (default is alphabetical):\n-f unsorted -r reverse -t timestamp -S size\n--color device=yellow symlink=turquoise/red dir=blue socket=purple\n files: exe=green suid=red suidfile=redback stickydir=greenback\n =auto means detect if output is a tty.\n\n"
+#define HELP_ls "usage: ls --color[=auto] [-ACFHLRSZacdfhiklmnpqrstux1] [directory...]\n\nlist files\n\nwhat to show:\n-a all files including .hidden -b escape nongraphic chars\n-c use ctime for timestamps -d directory, not contents\n-i inode number -p put a '/' after dir names\n-q unprintable chars as '?' -s storage used (1024 byte units)\n-u use access time for timestamps -A list all files but . and ..\n-H follow command line symlinks -L follow symlinks\n-R recursively list in subdirs -F append /dir *exe @sym |FIFO\n-Z security context\n\noutput formats:\n-1 list one file per line -C columns (sorted vertically)\n-g like -l but no owner -h human readable sizes\n-l long (show full details) -m comma separated\n-n like -l but numeric uid/gid -o like -l but no group\n-x columns (horizontal sort)\n\nsorting (default is alphabetical):\n-f unsorted -r reverse -t timestamp -S size\n--color device=yellow symlink=turquoise/red dir=blue socket=purple\n files: exe=green suid=red suidfile=redback stickydir=greenback\n =auto means detect if output is a tty.\n\n"
#define HELP_ln "usage: ln [-sfnv] [FROM...] TO\n\nCreate a link between FROM and TO.\nWith only one argument, create link in current directory.\n\n-s Create a symbolic link\n-f Force the creation of the link, even if TO already exists\n-n Symlink at destination treated as file\n-v Verbose\n\n"
@@ -504,6 +528,8 @@
#define HELP_find "usage: find [-HL] [DIR...] [<options>]\n\nSearch directories for matching files.\nDefault: search \".\" match all -print all matches.\n\n-H Follow command line symlinks -L Follow all symlinks\n\nMatch filters:\n-name PATTERN filename with wildcards -iname case insensitive -name\n-path PATTERN path name with wildcards -ipath case insensitive -path\n-user UNAME belongs to user UNAME -nouser user ID not known\n-group GROUP belongs to group GROUP -nogroup group ID not known\n-perm [-/]MODE permissions (-=min /=any) -prune ignore contents of dir\n-size N[c] 512 byte blocks (c=bytes) -xdev only this filesystem\n-links N hardlink count -atime N accessed N days ago\n-ctime N created N days ago -mtime N modified N days ago\n-newer FILE newer mtime than FILE -mindepth # at least # dirs down\n-depth ignore contents of dir -maxdepth # at most # dirs down\n-inum N inode number N -empty empty files and dirs\n-type [bcdflps] (block, char, dir, file, symlink, pipe, socket)\n\nNumbers N may be prefixed by a - (less than) or + (greater than):\n\nCombine matches with:\n!, -a, -o, ( ) not, and, or, group expressions\n\nActions:\n-print Print match with newline -print0 Print match with null\n-exec Run command with path -execdir Run command in file's dir\n-ok Ask before exec -okdir Ask before execdir\n-delete Remove matching file/dir\n\nCommands substitute \"{}\" with matched file. End with \";\" to run each file,\nor \"+\" (next argument after \"{}\") to collect and run with multiple files.\n\n"
+#define HELP_file "usage: file [-hL] [file...]\n\nExamine the given files and describe their content types.\n\n-h don't follow symlinks (default)\n-L follow symlinks\n\n"
+
#define HELP_false "Return nonzero.\n\n"
#define HELP_expand "usage: expand [-t TABLIST] [FILE...]\n\nExpand tabs to spaces according to tabstops.\n\n-t TABLIST\n\nSpecify tab stops, either a single number instead of the default 8,\nor a comma separated list of increasing numbers representing tabstop\npositions (absolute, not increments) with each additional tab beyound\nthat becoming one space.\n\n"
diff --git a/generated/newtoys.h b/generated/newtoys.h
index 3ac584a2..385fc909 100644
--- a/generated/newtoys.h
+++ b/generated/newtoys.h
@@ -1,7 +1,7 @@
USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT))
USE_SH(OLDTOY(-sh, sh, 0))
USE_SH(OLDTOY(-toysh, sh, 0))
-USE_TRUE(OLDTOY(:, true, TOYFLAG_NOFORK))
+USE_TRUE(OLDTOY(:, true, TOYFLAG_NOFORK|TOYFLAG_NOHELP))
USE_ACPI(NEWTOY(acpi, "abctV", TOYFLAG_USR|TOYFLAG_BIN))
USE_GROUPADD(OLDTOY(addgroup, groupadd, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
USE_USERADD(OLDTOY(adduser, useradd, TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
@@ -25,10 +25,11 @@ USE_CHGRP(NEWTOY(chgrp, "<2hPLHRfv[-HLP]", TOYFLAG_BIN))
USE_CHMOD(NEWTOY(chmod, "<2?vRf[-vf]", TOYFLAG_BIN))
USE_CHOWN(OLDTOY(chown, chgrp, TOYFLAG_BIN))
USE_CHROOT(NEWTOY(chroot, "^<1", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_CHRT(NEWTOY(chrt, "mp#bfiorR[!bfior]", TOYFLAG_USR|TOYFLAG_SBIN))
USE_CHVT(NEWTOY(chvt, "<1", TOYFLAG_USR|TOYFLAG_BIN))
USE_CKSUM(NEWTOY(cksum, "HIPLN", TOYFLAG_BIN))
USE_CLEAR(NEWTOY(clear, NULL, TOYFLAG_USR|TOYFLAG_BIN))
-USE_CMP(NEWTOY(cmp, "<2>2ls", TOYFLAG_USR|TOYFLAG_BIN))
+USE_CMP(NEWTOY(cmp, "<2>2ls[!ls]", TOYFLAG_USR|TOYFLAG_BIN))
USE_COMM(NEWTOY(comm, "<2>2321", TOYFLAG_USR|TOYFLAG_BIN))
USE_COMPRESS(NEWTOY(compress, "zcd9lrg[-cd][!zgLr]", TOYFLAG_USR|TOYFLAG_BIN))
USE_COUNT(NEWTOY(count, NULL, TOYFLAG_USR|TOYFLAG_BIN))
@@ -61,10 +62,10 @@ USE_EXPAND(NEWTOY(expand, "t*", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
USE_EXPR(NEWTOY(expr, NULL, TOYFLAG_USR|TOYFLAG_BIN))
USE_FACTOR(NEWTOY(factor, 0, TOYFLAG_USR|TOYFLAG_BIN))
USE_FALLOCATE(NEWTOY(fallocate, ">1l#|", TOYFLAG_USR|TOYFLAG_BIN))
-USE_FALSE(NEWTOY(false, NULL, TOYFLAG_BIN))
+USE_FALSE(NEWTOY(false, NULL, TOYFLAG_BIN|TOYFLAG_NOHELP))
USE_FDISK(NEWTOY(fdisk, "C#<0H#<0S#<0b#<512ul", TOYFLAG_SBIN))
USE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN))
-USE_FILE(NEWTOY(file, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_FILE(NEWTOY(file, "<1hL[!hL]", TOYFLAG_USR|TOYFLAG_BIN))
USE_FIND(NEWTOY(find, "?^HL[-HL]", TOYFLAG_USR|TOYFLAG_BIN))
USE_FLOCK(NEWTOY(flock, "<1>1nsux[-sux]", TOYFLAG_USR|TOYFLAG_BIN))
USE_FOLD(NEWTOY(fold, "bsuw#<1", TOYFLAG_USR|TOYFLAG_BIN))
@@ -77,6 +78,7 @@ USE_FSYNC(NEWTOY(fsync, "<1d", TOYFLAG_BIN))
USE_FTPGET(NEWTOY(ftpget, "<2cvu:p:P#<0=21>65535", TOYFLAG_BIN))
USE_FTPGET(OLDTOY(ftpput, ftpget, TOYFLAG_BIN))
USE_GETENFORCE(NEWTOY(getenforce, ">0", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_GETFATTR(NEWTOY(getfattr, "dhn:", TOYFLAG_USR|TOYFLAG_BIN))
USE_GETPROP(NEWTOY(getprop, ">2Z", TOYFLAG_USR|TOYFLAG_SBIN))
USE_GETTY(NEWTOY(getty, "<2t#<0H:I:l:f:iwnmLh",TOYFLAG_SBIN))
USE_GREP(NEWTOY(grep, "C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
@@ -120,6 +122,7 @@ USE_LAST(NEWTOY(last, "f:W", TOYFLAG_BIN))
USE_LINK(NEWTOY(link, "<2>2", TOYFLAG_USR|TOYFLAG_BIN))
USE_LN(NEWTOY(ln, "<1vnfs", TOYFLAG_BIN))
USE_LOAD_POLICY(NEWTOY(load_policy, "<1>1", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_LOG(NEWTOY(log, "<1p:t:", TOYFLAG_USR|TOYFLAG_SBIN))
USE_LOGGER(NEWTOY(logger, "st:p:", TOYFLAG_USR|TOYFLAG_BIN))
USE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
USE_LOGNAME(NEWTOY(logname, ">0", TOYFLAG_USR|TOYFLAG_BIN))
@@ -131,7 +134,7 @@ USE_LSOF(NEWTOY(lsof, "lp*t", TOYFLAG_USR|TOYFLAG_BIN))
USE_LSPCI(NEWTOY(lspci, "emkn"USE_LSPCI_TEXT("@i:"), TOYFLAG_USR|TOYFLAG_BIN))
USE_LSUSB(NEWTOY(lsusb, NULL, TOYFLAG_USR|TOYFLAG_BIN))
USE_MAKEDEVS(NEWTOY(makedevs, "<1>1d:", TOYFLAG_USR|TOYFLAG_BIN))
-USE_MD5SUM(NEWTOY(md5sum, "b", TOYFLAG_USR|TOYFLAG_BIN))
+USE_MD5SUM(NEWTOY(md5sum, "bc*[!bc]", TOYFLAG_USR|TOYFLAG_BIN))
USE_MDEV(NEWTOY(mdev, "s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK))
USE_MIX(NEWTOY(mix, "c:d:l#r#", TOYFLAG_USR|TOYFLAG_BIN))
USE_MKDIR(NEWTOY(mkdir, "<1"USE_MKDIR_Z("Z:")"vpm:", TOYFLAG_BIN|TOYFLAG_UMASK))
@@ -163,17 +166,17 @@ USE_OPENVT(NEWTOY(openvt, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
USE_PARTPROBE(NEWTOY(partprobe, "<1", TOYFLAG_SBIN))
USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
USE_PASTE(NEWTOY(paste, "d:s", TOYFLAG_BIN))
-USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"ulp#i:R", TOYFLAG_USR|TOYFLAG_BIN))
+USE_PATCH(NEWTOY(patch, "(dry-run)"USE_TOYBOX_DEBUG("x")"d:ulp#i:R", TOYFLAG_USR|TOYFLAG_BIN))
USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
USE_PIDOF(NEWTOY(pidof, "<1so:", TOYFLAG_BIN))
USE_PING(NEWTOY(ping, "<1>1t#<0>255c#<0s#<0>65535I:W#<0w#<0q46[-46]", TOYFLAG_ROOTONLY|TOYFLAG_USR|TOYFLAG_BIN))
USE_PIVOT_ROOT(NEWTOY(pivot_root, "<2>2", TOYFLAG_SBIN))
-USE_PKILL(NEWTOY(pkill, "Vu*U*t*s*P*g*G*fnovxl:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_PKILL(NEWTOY(pkill, "?Vu*U*t*s*P*g*G*fnovxl:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
USE_PMAP(NEWTOY(pmap, "<1xq", TOYFLAG_BIN))
USE_REBOOT(OLDTOY(poweroff, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
USE_PRINTENV(NEWTOY(printenv, "0(null)", TOYFLAG_USR|TOYFLAG_BIN))
USE_PRINTF(NEWTOY(printf, "<1?^", TOYFLAG_USR|TOYFLAG_BIN))
-USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
USE_PWD(NEWTOY(pwd, ">0LP[-LP]", TOYFLAG_BIN))
USE_PWDX(NEWTOY(pwdx, "<1a", TOYFLAG_USR|TOYFLAG_BIN))
USE_READAHEAD(NEWTOY(readahead, NULL, TOYFLAG_BIN))
@@ -192,19 +195,27 @@ USE_RMMOD(NEWTOY(rmmod, "<1wf", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
USE_ROUTE(NEWTOY(route, "?neA:", TOYFLAG_BIN))
USE_RUNCON(NEWTOY(runcon, "<2", TOYFLAG_USR|TOYFLAG_SBIN))
USE_SED(NEWTOY(sed, "(version)e*f*inEr[+Er]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_SENDEVENT(NEWTOY(sendevent, "<4>4", TOYFLAG_USR|TOYFLAG_SBIN))
USE_SEQ(NEWTOY(seq, "<1>3?f:s:w[!fw]", TOYFLAG_USR|TOYFLAG_BIN))
USE_SETENFORCE(NEWTOY(setenforce, "<1>1", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_SETFATTR(NEWTOY(setfattr, "hn:|v:x:|[!xv]", TOYFLAG_USR|TOYFLAG_BIN))
USE_SETPROP(NEWTOY(setprop, "<2>2", TOYFLAG_USR|TOYFLAG_SBIN))
USE_SETSID(NEWTOY(setsid, "^<1t", TOYFLAG_USR|TOYFLAG_BIN))
USE_SH(NEWTOY(sh, "c:i", TOYFLAG_BIN))
-USE_SHA1SUM(NEWTOY(sha1sum, "b", TOYFLAG_USR|TOYFLAG_BIN))
+USE_SHA1SUM(NEWTOY(sha1sum, "bc*[!bc]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_SHA224SUM(OLDTOY(sha224sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))
+USE_SHA256SUM(OLDTOY(sha256sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))
+USE_SHA384SUM(OLDTOY(sha384sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))
+USE_SHA512SUM(OLDTOY(sha512sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))
USE_SHRED(NEWTOY(shred, "<1zxus#<1n#<1o#<0f", TOYFLAG_USR|TOYFLAG_BIN))
USE_SKELETON(NEWTOY(skeleton, "(walrus)(blubber):;(also):e@d*c#b:a", TOYFLAG_USR|TOYFLAG_BIN))
USE_SKELETON_ALIAS(NEWTOY(skeleton_alias, "b#dq", TOYFLAG_USR|TOYFLAG_BIN))
USE_SLEEP(NEWTOY(sleep, "<1", TOYFLAG_BIN))
USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")USE_SORT_BIG("S:T:m" "o:k*t:xbMcszdfi") "run", TOYFLAG_USR|TOYFLAG_BIN))
USE_SPLIT(NEWTOY(split, ">2a#<1=2>9b#<1l#<1", TOYFLAG_USR|TOYFLAG_BIN))
-USE_STAT(NEWTOY(stat, "<1c:tf", TOYFLAG_BIN))
+USE_START(NEWTOY(start, "", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_STAT(NEWTOY(stat, "<1c:fLt", TOYFLAG_BIN))
+USE_STOP(NEWTOY(stop, "", TOYFLAG_USR|TOYFLAG_SBIN))
USE_STRINGS(NEWTOY(strings, "an#=4<1fo", TOYFLAG_USR|TOYFLAG_BIN))
USE_SU(NEWTOY(su, "lmpc:s:", TOYFLAG_BIN|TOYFLAG_ROOTONLY))
USE_SULOGIN(NEWTOY(sulogin, "t#<0=0", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
@@ -223,22 +234,23 @@ USE_TEE(NEWTOY(tee, "ia", TOYFLAG_USR|TOYFLAG_BIN))
USE_TELNET(NEWTOY(telnet, "<1>2", TOYFLAG_BIN))
USE_TELNETD(NEWTOY(telnetd, "w#<0b:p#<0>65535=23f:l:FSKi[!wi]", TOYFLAG_USR|TOYFLAG_BIN))
USE_TEST(NEWTOY(test, NULL, TOYFLAG_USR|TOYFLAG_BIN))
-USE_TEST_HUMAN_READABLE(NEWTOY(test_human_readable, "<1>1ibs", 0))
-USE_TEST_MANY_OPTIONS(NEWTOY(test_many_options, "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba", TOYFLAG_USR|TOYFLAG_BIN))
-USE_TEST_SCANKEY(NEWTOY(test_scankey, 0, 0))
+USE_TEST_HUMAN_READABLE(NEWTOY(test_human_readable, "<1>1ibs", TOYFLAG_BIN))
+USE_TEST_MANY_OPTIONS(NEWTOY(test_many_options, "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba", TOYFLAG_BIN))
+USE_TEST_SCANKEY(NEWTOY(test_scankey, 0, TOYFLAG_BIN))
USE_TFTP(NEWTOY(tftp, "<1b#<8>65464r:l:g|p|[!gp]", TOYFLAG_USR|TOYFLAG_BIN))
USE_TFTPD(NEWTOY(tftpd, "rcu:l", TOYFLAG_BIN))
USE_TIME(NEWTOY(time, "<1^p", TOYFLAG_USR|TOYFLAG_BIN))
USE_TIMEOUT(NEWTOY(timeout, "<2^vk:s: ", TOYFLAG_BIN))
-USE_TOP(NEWTOY(top, ">0m" "Hk*o*p*u*s#<1=9d#=3<1n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_TOP(NEWTOY(top, ">0m" "O*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
USE_TOUCH(NEWTOY(touch, "acd:mr:t:h[!dtr]", TOYFLAG_BIN))
USE_SH(OLDTOY(toysh, sh, TOYFLAG_BIN))
USE_TR(NEWTOY(tr, "^>2<1Ccsd[+cC]", TOYFLAG_USR|TOYFLAG_BIN))
USE_TRACEROUTE(NEWTOY(traceroute, "<1>2i:f#<1>255=1z#<0>86400=0g*w#<0>86400=5t#<0>255=0s:q#<1>255=3p#<1>65535=33434m#<1>255=30rvndlIUF64", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
USE_TRACEROUTE(OLDTOY(traceroute6,traceroute, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
-USE_TRUE(NEWTOY(true, NULL, TOYFLAG_BIN))
+USE_TRUE(NEWTOY(true, NULL, TOYFLAG_BIN|TOYFLAG_NOHELP))
USE_TRUNCATE(NEWTOY(truncate, "<1s:|c", TOYFLAG_BIN))
USE_TTY(NEWTOY(tty, "s", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TUNCTL(NEWTOY(tunctl, "<1>1t|d|u:T[!td]", TOYFLAG_USR|TOYFLAG_BIN))
USE_TCPSVD(OLDTOY(udpsvd, tcpsvd, TOYFLAG_USR|TOYFLAG_BIN))
USE_ULIMIT(NEWTOY(ulimit, ">1P#<1SHavutsrRqpnmlifedc[-SH][!apvutsrRqnmlifedc]", TOYFLAG_USR|TOYFLAG_BIN))
USE_UMOUNT(NEWTOY(umount, "ndDflrat*v[!na]", TOYFLAG_BIN|TOYFLAG_STAYROOT))
@@ -258,13 +270,13 @@ USE_VI(NEWTOY(vi, "<1>1", TOYFLAG_USR|TOYFLAG_BIN))
USE_VMSTAT(NEWTOY(vmstat, ">2n", TOYFLAG_BIN))
USE_W(NEWTOY(w, NULL, TOYFLAG_USR|TOYFLAG_BIN))
USE_WATCH(NEWTOY(watch, "^<1n#<0=2te", TOYFLAG_USR|TOYFLAG_BIN))
-USE_WC(NEWTOY(wc, USE_TOYBOX_I18N("m")"cwl[!cm]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_WC(NEWTOY(wc, "mcwl", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
USE_WGET(NEWTOY(wget, "f:", TOYFLAG_USR|TOYFLAG_BIN))
USE_WHICH(NEWTOY(which, "<1a", TOYFLAG_USR|TOYFLAG_BIN))
USE_WHO(NEWTOY(who, "a", TOYFLAG_USR|TOYFLAG_BIN))
USE_WHOAMI(OLDTOY(whoami, logname, TOYFLAG_USR|TOYFLAG_BIN))
USE_XARGS(NEWTOY(xargs, "^I:E:L#ptxrn#<1s#0", TOYFLAG_USR|TOYFLAG_BIN))
-USE_XXD(NEWTOY(xxd, ">1c#<1>4096=16l#g#<1=2pr", TOYFLAG_USR|TOYFLAG_BIN))
+USE_XXD(NEWTOY(xxd, ">1c#<1>4096=16l#g#<1=2prs#[!rs]", TOYFLAG_USR|TOYFLAG_BIN))
USE_XZCAT(NEWTOY(xzcat, NULL, TOYFLAG_USR|TOYFLAG_BIN))
USE_YES(NEWTOY(yes, NULL, TOYFLAG_USR|TOYFLAG_BIN))
USE_ZCAT(NEWTOY(zcat, 0, TOYFLAG_USR|TOYFLAG_BIN))
diff --git a/generated/tags.h b/generated/tags.h
index 69d3d641..31e77736 100644
--- a/generated/tags.h
+++ b/generated/tags.h
@@ -46,22 +46,22 @@
#define _PS_TCNT (1<<17)
#define PS_BIT 18
#define _PS_BIT (1<<18)
-#define PS_COMM 19
-#define _PS_COMM (1<<19)
-#define PS_TTY 20
-#define _PS_TTY (1<<20)
-#define PS_WCHAN 21
-#define _PS_WCHAN (1<<21)
-#define PS_LABEL 22
-#define _PS_LABEL (1<<22)
-#define PS_COMMAND 23
-#define _PS_COMMAND (1<<23)
-#define PS_CMDLINE 24
-#define _PS_CMDLINE (1<<24)
-#define PS_ARGS 25
-#define _PS_ARGS (1<<25)
-#define PS_NAME 26
-#define _PS_NAME (1<<26)
+#define PS_TTY 19
+#define _PS_TTY (1<<19)
+#define PS_WCHAN 20
+#define _PS_WCHAN (1<<20)
+#define PS_LABEL 21
+#define _PS_LABEL (1<<21)
+#define PS_COMM 22
+#define _PS_COMM (1<<22)
+#define PS_NAME 23
+#define _PS_NAME (1<<23)
+#define PS_COMMAND 24
+#define _PS_COMMAND (1<<24)
+#define PS_CMDLINE 25
+#define _PS_CMDLINE (1<<25)
+#define PS_ARGS 26
+#define _PS_ARGS (1<<26)
#define PS_CMD 27
#define _PS_CMD (1<<27)
#define PS_UID 28
diff --git a/lib/args.c b/lib/args.c
index 1f42cdde..e6378beb 100644
--- a/lib/args.c
+++ b/lib/args.c
@@ -360,6 +360,7 @@ void parse_optflaglist(struct getoptflagstate *gof)
if (!opt) break;
if (bits&(1<<i)) opt->dex[idx] |= bits&~(1<<i);
} else {
+ if (*options==1) break;
if (CFG_TOYBOX_DEBUG && !opt)
error_exit("[] unknown target %c", *options);
if (opt->c == *options) {
diff --git a/lib/help.c b/lib/help.c
index 9ff575bc..d0185678 100644
--- a/lib/help.c
+++ b/lib/help.c
@@ -2,15 +2,16 @@
#include "toys.h"
-#if !CFG_TOYBOX_HELP
-void show_help(FILE *out) {;}
-#else
#include "generated/help.h"
#undef NEWTOY
#undef OLDTOY
#define NEWTOY(name,opt,flags) HELP_##name "\0"
+#if CFG_TOYBOX
#define OLDTOY(name,oldname,flags) "\xff" #oldname "\0"
+#else
+#define OLDTOY(name, oldname, flags) HELP_##oldname "\0"
+#endif
static char *help_data =
#include "generated/newtoys.h"
;
@@ -20,19 +21,15 @@ void show_help(FILE *out)
int i = toys.which-toy_list;
char *s;
- for (;;) {
- s = help_data;
- while (i--) s += strlen(s) + 1;
- // If it's an alias, restart search for real name
- if (*s != 255) break;
- if (!CFG_TOYBOX) {
- s = xmprintf("See %s --help\n", ++s);
-
- break;
+ if (CFG_TOYBOX_HELP) {
+ for (;;) {
+ s = help_data;
+ while (i--) s += strlen(s) + 1;
+ // If it's an alias, restart search for real name
+ if (*s != 255) break;
+ i = toy_find(++s)-toy_list;
}
- i = toy_find(++s)-toy_list;
- }
- fprintf(out, "%s", s);
+ fprintf(out, "%s", s);
+ }
}
-#endif
diff --git a/lib/lib.c b/lib/lib.c
index 0df45bf9..fe85cbed 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -273,16 +273,16 @@ struct string_list *find_in_path(char *path, char *filename)
return rlist;
}
-long estrtol(char *str, char **end, int base)
+long long estrtol(char *str, char **end, int base)
{
errno = 0;
- return strtol(str, end, base);
+ return strtoll(str, end, base);
}
-long xstrtol(char *str, char **end, int base)
+long long xstrtol(char *str, char **end, int base)
{
- long l = estrtol(str, end, base);
+ long long l = estrtol(str, end, base);
if (errno) perror_exit_raw(str);
@@ -291,31 +291,32 @@ long xstrtol(char *str, char **end, int base)
// atol() with the kilo/mega/giga/tera/peta/exa extensions.
// (zetta and yotta don't fit in 64 bits.)
-long atolx(char *numstr)
+long long atolx(char *numstr)
{
- char *c, *suffixes="cbkmgtpe", *end;
- long val;
+ char *c = numstr, *suffixes="cbkmgtpe", *end;
+ long long val;
val = xstrtol(numstr, &c, 0);
- if (*c) {
- if (c != numstr && (end = strchr(suffixes, tolower(*c)))) {
- int shift = end-suffixes-2;
- if (shift >= 0) val *= 1024L<<(shift*10);
- } else {
- while (isspace(*c)) c++;
- if (*c) error_exit("not integer: %s", numstr);
+ if (c != numstr && *c && (end = strchr(suffixes, tolower(*c)))) {
+ int shift = end-suffixes-2;
+
+ if (shift >= 0) {
+ if (toupper(*++c)=='d') do val *= 1000; while (shift--);
+ else val *= 1024LL<<(shift*10);
}
}
+ while (isspace(*c)) c++;
+ if (c==numstr || *c) error_exit("not integer: %s", numstr);
return val;
}
-long atolx_range(char *numstr, long low, long high)
+long long atolx_range(char *numstr, long long low, long long high)
{
- long val = atolx(numstr);
+ long long val = atolx(numstr);
- if (val < low) error_exit("%ld < %ld", val, low);
- if (val > high) error_exit("%ld > %ld", val, high);
+ if (val < low) error_exit("%lld < %lld", val, low);
+ if (val > high) error_exit("%lld > %lld", val, high);
return val;
}
@@ -444,7 +445,8 @@ off_t fdlength(int fd)
// Read contents of file as a single nul-terminated string.
// measure file size if !len, allocate buffer if !buf
-// note: for existing buffers use len = size-1, will set buf[len] = 0
+// Existing buffers need len in *plen
+// Returns amount of data read in *plen
char *readfileat(int dirfd, char *name, char *ibuf, off_t *plen)
{
off_t len, rlen;
@@ -545,16 +547,20 @@ void poke(void *ptr, uint64_t val, int size)
}
// Iterate through an array of files, opening each one and calling a function
-// on that filehandle and name. The special filename "-" means stdin if
-// flags is O_RDONLY, stdout otherwise. An empty argument list calls
+// on that filehandle and name. The special filename "-" means stdin if
+// flags is O_RDONLY, stdout otherwise. An empty argument list calls
// function() on just stdin/stdout.
//
// Note: pass O_CLOEXEC to automatically close filehandles when function()
-// returns, otherwise filehandles must be closed by function()
-void loopfiles_rw(char **argv, int flags, int permissions, int failok,
+// returns, otherwise filehandles must be closed by function().
+// pass WARN_ONLY to produce warning messages about files it couldn't
+// open/create, and skip them. Otherwise function is called with fd -1.
+void loopfiles_rw(char **argv, int flags, int permissions,
void (*function)(int fd, char *name))
{
- int fd;
+ int fd, failok = !(flags&WARN_ONLY);
+
+ flags &= ~WARN_ONLY;
// If no arguments, read from stdin.
if (!*argv) function((flags & O_ACCMODE) != O_RDONLY ? 1 : 0, "-");
@@ -562,20 +568,20 @@ void loopfiles_rw(char **argv, int flags, int permissions, int failok,
// Filename "-" means read from stdin.
// Inability to open a file prints a warning, but doesn't exit.
- if (!strcmp(*argv, "-")) fd=0;
- else if (0>(fd = open(*argv, flags, permissions)) && !failok) {
+ if (!strcmp(*argv, "-")) fd = 0;
+ else if (0>(fd = notstdio(open(*argv, flags, permissions))) && !failok) {
perror_msg_raw(*argv);
continue;
}
function(fd, *argv);
- if (flags & O_CLOEXEC) close(fd);
+ if ((flags & O_CLOEXEC) && fd) close(fd);
} while (*++argv);
}
-// Call loopfiles_rw with O_RDONLY|O_CLOEXEC and !failok (common case).
+// Call loopfiles_rw with O_RDONLY|O_CLOEXEC|WARN_ONLY (common case)
void loopfiles(char **argv, void (*function)(int fd, char *name))
{
- loopfiles_rw(argv, O_RDONLY|O_CLOEXEC, 0, 0, function);
+ loopfiles_rw(argv, O_RDONLY|O_CLOEXEC|WARN_ONLY, 0, function);
}
// Slow, but small.
@@ -1006,7 +1012,7 @@ int qstrcmp(const void *a, const void *b)
void create_uuid(char *uuid)
{
// Read 128 random bits
- int fd = xopen("/dev/urandom", O_RDONLY);
+ int fd = xopenro("/dev/urandom");
xreadall(fd, uuid, 16);
close(fd);
@@ -1074,3 +1080,155 @@ int dev_makedev(int major, int minor)
{
return (minor&0xff)|((major&0xfff)<<8)|((minor&0xfff00)<<12);
}
+
+// Return cached passwd entries.
+struct passwd *bufgetpwuid(uid_t uid)
+{
+ struct pwuidbuf_list {
+ struct pwuidbuf_list *next;
+ struct passwd pw;
+ } *list;
+ struct passwd *temp;
+ static struct pwuidbuf_list *pwuidbuf;
+
+ for (list = pwuidbuf; list; list = list->next)
+ if (list->pw.pw_uid == uid) return &(list->pw);
+
+ list = xmalloc(512);
+ list->next = pwuidbuf;
+
+ errno = getpwuid_r(uid, &list->pw, sizeof(*list)+(char *)list,
+ 512-sizeof(*list), &temp);
+ if (!temp) {
+ free(list);
+
+ return 0;
+ }
+ pwuidbuf = list;
+
+ return &list->pw;
+}
+
+// Return cached passwd entries.
+struct group *bufgetgrgid(gid_t gid)
+{
+ struct grgidbuf_list {
+ struct grgidbuf_list *next;
+ struct group gr;
+ } *list;
+ struct group *temp;
+ static struct grgidbuf_list *grgidbuf;
+
+ for (list = grgidbuf; list; list = list->next)
+ if (list->gr.gr_gid == gid) return &(list->gr);
+
+ list = xmalloc(512);
+ list->next = grgidbuf;
+
+ errno = getgrgid_r(gid, &list->gr, sizeof(*list)+(char *)list,
+ 512-sizeof(*list), &temp);
+ if (!temp) {
+ free(list);
+
+ return 0;
+ }
+ grgidbuf = list;
+
+ return &list->gr;
+}
+
+// Always null terminates, returns 0 for failure, len for success
+int readlinkat0(int dirfd, char *path, char *buf, int len)
+{
+ if (!len) return 0;
+
+ len = readlinkat(dirfd, path, buf, len-1);
+ if (len<1) return 0;
+ buf[len] = 0;
+
+ return len;
+}
+
+int readlink0(char *path, char *buf, int len)
+{
+ return readlinkat0(AT_FDCWD, path, buf, len);
+}
+
+// Do regex matching handling embedded NUL bytes in string (hence extra len
+// argument). Note that neither the pattern nor the match can currently include
+// NUL bytes (even with wildcards) and string must be null terminated at
+// string[len]. But this can find a match after the first NUL.
+int regexec0(regex_t *preg, char *string, long len, int nmatch,
+ regmatch_t pmatch[], int eflags)
+{
+ char *s = string;
+
+ for (;;) {
+ long ll = 0;
+ int rc;
+
+ while (len && !*s) {
+ s++;
+ len--;
+ }
+ while (s[ll] && ll<len) ll++;
+
+ rc = regexec(preg, s, nmatch, pmatch, eflags);
+ if (!rc) {
+ for (rc = 0; rc<nmatch && pmatch[rc].rm_so!=-1; rc++) {
+ pmatch[rc].rm_so += s-string;
+ pmatch[rc].rm_eo += s-string;
+ }
+
+ return 0;
+ }
+ if (ll==len) return rc;
+
+ s += ll;
+ len -= ll;
+ }
+}
+
+// Return user name or string representation of number, returned buffer
+// lasts until next call.
+char *getusername(uid_t uid)
+{
+ struct passwd *pw = bufgetpwuid(uid);
+ static char unum[12];
+
+ sprintf(unum, "%u", (unsigned)uid);
+ return pw ? pw->pw_name : unum;
+}
+
+// Return group name or string representation of number, returned buffer
+// lasts until next call.
+char *getgroupname(gid_t gid)
+{
+ struct group *gr = bufgetgrgid(gid);
+ static char gnum[12];
+
+ sprintf(gnum, "%u", (unsigned)gid);
+ return gr ? gr->gr_name : gnum;
+}
+
+// Iterate over lines in file, calling function. Function can write 0 to
+// the line pointer if they want to keep it, or 1 to terminate processing,
+// otherwise line is freed. Passed file descriptor is closed at the end.
+void do_lines(int fd, void (*call)(char **pline, long len))
+{
+ FILE *fp = fd ? xfdopen(fd, "r") : stdin;
+
+ for (;;) {
+ char *line = 0;
+ ssize_t len;
+
+ len = getline(&line, (void *)&len, fp);
+ if (len > 0) {
+ call(&line, len);
+ if (line == (void *)1) break;
+ free(line);
+ } else break;
+ }
+
+ if (fd) fclose(fp);
+}
diff --git a/lib/lib.h b/lib/lib.h
index 798f1829..0ca764ef 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -34,6 +34,12 @@ struct double_list {
char *data;
};
+struct num_cache {
+ struct num_cache *next;
+ long long num;
+ char data[];
+};
+
void llist_free_arg(void *node);
void llist_free_double(void *node);
void llist_traverse(void *list, void (*using)(void *node));
@@ -42,6 +48,9 @@ void *dlist_pop(void *list); // actually struct double_list **list
void dlist_add_nomalloc(struct double_list **list, struct double_list *new);
struct double_list *dlist_add(struct double_list **list, char *data);
void *dlist_terminate(void *list);
+struct num_cache *get_num_cache(struct num_cache *cache, long long num);
+struct num_cache *add_num_cache(struct num_cache **cache, long long num,
+ void *data, int len);
// args.c
void get_optflags(void);
@@ -93,6 +102,11 @@ struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node));
void show_help(FILE *out);
+// Tell xopen and friends to print warnings but return -1 as necessary
+// The largest O_BLAH flag so far is arch/alpha's O_PATH at 0x800000 so
+// plenty of headroom.
+#define WARN_ONLY (1<<31)
+
// xwrap.c
void xstrncpy(char *dest, char *src, size_t size);
void xstrncat(char *dest, char *src, size_t size);
@@ -121,9 +135,14 @@ void xaccess(char *path, int flags);
void xunlink(char *path);
int xcreate(char *path, int flags, int mode);
int xopen(char *path, int flags);
+int xcreate_stdio(char *path, int flags, int mode);
+int xopen_stdio(char *path, int flags);
+int openro(char *path, int flags);
+int xopenro(char *path);
void xpipe(int *pp);
void xclose(int fd);
int xdup(int fd);
+int notstdio(int fd);
FILE *xfdopen(int fd, char *mode);
FILE *xfopen(char *path, char *mode);
size_t xread(int fd, void *buf, size_t len);
@@ -141,8 +160,8 @@ struct passwd *xgetpwuid(uid_t uid);
struct group *xgetgrgid(gid_t gid);
struct passwd *xgetpwnam(char *name);
struct group *xgetgrnam(char *name);
-struct passwd *xgetpwnamid(char *user);
-struct group *xgetgrnamid(char *group);
+unsigned xgetuid(char *name);
+unsigned xgetgid(char *name);
void xsetuser(struct passwd *pwd);
char *xreadlink(char *name);
long xparsetime(char *arg, long units, long *fraction);
@@ -175,10 +194,10 @@ int64_t peek_be(void *ptr, unsigned size);
int64_t peek(void *ptr, unsigned size);
void poke(void *ptr, uint64_t val, int size);
struct string_list *find_in_path(char *path, char *filename);
-long estrtol(char *str, char **end, int base);
-long xstrtol(char *str, char **end, int base);
-long atolx(char *c);
-long atolx_range(char *numstr, long low, long high);
+long long estrtol(char *str, char **end, int base);
+long long xstrtol(char *str, char **end, int base);
+long long atolx(char *c);
+long long atolx_range(char *numstr, long long low, long long high);
int stridx(char *haystack, char needle);
char *strlower(char *s);
char *strafter(char *haystack, char *needle);
@@ -186,7 +205,7 @@ char *chomp(char *s);
int unescape(char c);
int strstart(char **a, char *b);
off_t fdlength(int fd);
-void loopfiles_rw(char **argv, int flags, int permissions, int failok,
+void loopfiles_rw(char **argv, int flags, int permissions,
void (*function)(int fd, char *name));
void loopfiles(char **argv, void (*function)(int fd, char *name));
void xsendfile(int in, int out);
@@ -205,6 +224,15 @@ char *strnstr(char *line, char *str);
int dev_minor(int dev);
int dev_major(int dev);
int dev_makedev(int major, int minor);
+struct passwd *bufgetpwuid(uid_t uid);
+struct group *bufgetgrgid(gid_t gid);
+int readlinkat0(int dirfd, char *path, char *buf, int len);
+int readlink0(char *path, char *buf, int len);
+int regexec0(regex_t *preg, char *string, long len, int nmatch,
+ regmatch_t pmatch[], int eflags);
+char *getusername(uid_t uid);
+char *getgroupname(gid_t gid);
+void do_lines(int fd, void (*call)(char **pline, long len));
#define HR_SPACE 1 // Space between number and units
#define HR_B 2 // Use "B" for single byte units
@@ -280,6 +308,7 @@ struct mtab_list *xgetmountlist(char *path);
// signal
void generic_signal(int signal);
+void exit_signal(int signal);
void sigatexit(void *handler);
int sig_to_num(char *pidstr);
char *num_to_sig(int sig);
diff --git a/lib/llist.c b/lib/llist.c
index 6b4b8f2c..dbb5352a 100644
--- a/lib/llist.c
+++ b/lib/llist.c
@@ -99,3 +99,32 @@ void *dlist_terminate(void *list)
return end;
}
+
+// Find num in cache
+struct num_cache *get_num_cache(struct num_cache *cache, long long num)
+{
+ while (cache) {
+ if (num==cache->num) return cache;
+ cache = cache->next;
+ }
+
+ return 0;
+}
+
+// Uniquely add num+data to cache. Updates *cache, returns pointer to existing
+// entry if it was already there.
+struct num_cache *add_num_cache(struct num_cache **cache, long long num,
+ void *data, int len)
+{
+ struct num_cache *old = get_num_cache(*cache, num);
+
+ if (old) return old;
+
+ old = xzalloc(sizeof(struct num_cache)+len);
+ old->next = *cache;
+ old->num = num;
+ memcpy(old->data, data, len);
+ *cache = old;
+
+ return 0;
+}
diff --git a/lib/lsm.h b/lib/lsm.h
index 3a5b7ebf..e21d424b 100644
--- a/lib/lsm.h
+++ b/lib/lsm.h
@@ -23,7 +23,9 @@
#include <sys/smack.h>
#include <linux/xattr.h>
#else
+#ifndef XATTR_NAME_SMACK
#define XATTR_NAME_SMACK 0
+#endif
//ssize_t fgetxattr (int fd, char *name, void *value, size_t size);
#define smack_smackfs_path(...) (-1)
#define smack_new_label_from_self(...) (-1)
diff --git a/lib/password.c b/lib/password.c
index bf13c441..eab2d669 100644
--- a/lib/password.c
+++ b/lib/password.c
@@ -24,7 +24,7 @@ int get_salt(char *salt, char *algo)
if (al[i].id) s += sprintf(s, "$%c$", '0'+al[i].id);
// Read appropriate number of random bytes for salt
- i = xopen("/dev/urandom", O_RDONLY);
+ i = xopenro("/dev/urandom");
xreadall(i, libbuf, ((len*6)+7)/8);
close(i);
diff --git a/lib/toyflags.h b/lib/toyflags.h
index 963295cc..e809901d 100644
--- a/lib/toyflags.h
+++ b/lib/toyflags.h
@@ -25,3 +25,6 @@
// Call setlocale to listen to environment variables.
// This invalidates sprintf("%.*s", size, string) as a valid length constraint.
#define TOYFLAG_LOCALE (1<<8)
+
+// Suppress default --help processing
+#define TOYFLAG_NOHELP (1<<9)
diff --git a/lib/xwrap.c b/lib/xwrap.c
index 36a601c5..66972f2b 100644
--- a/lib/xwrap.c
+++ b/lib/xwrap.c
@@ -318,17 +318,20 @@ void xunlink(char *path)
}
// Die unless we can open/create a file, returning file descriptor.
-int xcreate(char *path, int flags, int mode)
+// The meaning of O_CLOEXEC is reversed (it defaults on, pass it to disable)
+// and WARN_ONLY tells us not to exit.
+int xcreate_stdio(char *path, int flags, int mode)
{
- int fd = open(path, flags^O_CLOEXEC, mode);
- if (fd == -1) perror_exit_raw(path);
+ int fd = open(path, (flags^O_CLOEXEC)&~WARN_ONLY, mode);
+
+ if (fd == -1) ((mode&WARN_ONLY) ? perror_msg_raw : perror_exit_raw)(path);
return fd;
}
// Die unless we can open a file, returning file descriptor.
-int xopen(char *path, int flags)
+int xopen_stdio(char *path, int flags)
{
- return xcreate(path, flags, 0);
+ return xcreate_stdio(path, flags, 0);
}
void xpipe(int *pp)
@@ -350,6 +353,49 @@ int xdup(int fd)
return fd;
}
+// Move file descriptor above stdin/stdout/stderr, using /dev/null to consume
+// old one. (We should never be called with stdin/stdout/stderr closed, but...)
+int notstdio(int fd)
+{
+ if (fd<0) return fd;
+
+ while (fd<3) {
+ int fd2 = xdup(fd);
+
+ close(fd);
+ xopen_stdio("/dev/null", O_RDWR);
+ fd = fd2;
+ }
+
+ return fd;
+}
+
+// Create a file but don't return stdin/stdout/stderr
+int xcreate(char *path, int flags, int mode)
+{
+ return notstdio(xcreate_stdio(path, flags, mode));
+}
+
+// Open a file descriptor NOT in stdin/stdout/stderr
+int xopen(char *path, int flags)
+{
+ return notstdio(xopen_stdio(path, flags));
+}
+
+// Open read only, treating "-" as a synonym for stdin, defaulting to warn only
+int openro(char *path, int flags)
+{
+ if (!strcmp(path, "-")) return 0;
+
+ return xopen(path, flags^WARN_ONLY);
+}
+
+// Open read only, treating "-" as a synonym for stdin.
+int xopenro(char *path)
+{
+ return openro(path, O_RDONLY|WARN_ONLY);
+}
+
FILE *xfdopen(int fd, char *mode)
{
FILE *f = fdopen(fd, mode);
@@ -419,7 +465,7 @@ char *xabspath(char *path, int exact)
{
struct string_list *todo, *done = 0;
int try = 9999, dirfd = open("/", 0);;
- char buf[4096], *ret;
+ char *ret;
// If this isn't an absolute path, start with cwd.
if (*path != '/') {
@@ -450,7 +496,7 @@ char *xabspath(char *path, int exact)
} else continue;
// Is this a symlink?
- } else len=readlinkat(dirfd, new->str, buf, 4096);
+ } else len = readlinkat(dirfd, new->str, libbuf, sizeof(libbuf));
if (len>4095) goto error;
if (len<1) {
@@ -474,8 +520,8 @@ char *xabspath(char *path, int exact)
}
// If this symlink is to an absolute path, discard existing resolved path
- buf[len] = 0;
- if (*buf == '/') {
+ libbuf[len] = 0;
+ if (*libbuf == '/') {
llist_traverse(done, free);
done=0;
close(dirfd);
@@ -484,7 +530,7 @@ char *xabspath(char *path, int exact)
free(new);
// prepend components of new path. Note symlink to "/" will leave new NULL
- tail = splitpath(buf, &new);
+ tail = splitpath(libbuf, &new);
// symlink to "/" will return null and leave tail alone
if (new) {
@@ -554,36 +600,32 @@ struct group *xgetgrgid(gid_t gid)
return group;
}
-struct passwd *xgetpwnamid(char *user)
+unsigned xgetuid(char *name)
{
- struct passwd *up = getpwnam(user);
- uid_t uid;
+ struct passwd *up = getpwnam(name);
+ char *s = 0;
+ long uid;
- if (!up) {
- char *s = 0;
+ if (up) return up->pw_uid;
- uid = estrtol(user, &s, 10);
- if (!errno && s && !*s) up = getpwuid(uid);
- }
- if (!up) perror_exit("user '%s'", user);
+ uid = estrtol(name, &s, 10);
+ if (!errno && s && !*s && uid>=0 && uid<=UINT_MAX) return uid;
- return up;
+ error_exit("bad user '%s'", name);
}
-struct group *xgetgrnamid(char *group)
+unsigned xgetgid(char *name)
{
- struct group *gr = getgrnam(group);
- gid_t gid;
+ struct group *gr = getgrnam(name);
+ char *s = 0;
+ long gid;
- if (!gr) {
- char *s = 0;
+ if (gr) return gr->gr_gid;
- gid = estrtol(group, &s, 10);
- if (!errno && s && !*s) gr = getgrgid(gid);
- }
- if (!gr) perror_exit("group '%s'", group);
+ gid = estrtol(name, &s, 10);
+ if (!errno && s && !*s && gid>=0 && gid<=UINT_MAX) return gid;
- return gr;
+ error_exit("bad group '%s'", name);
}
struct passwd *xgetpwnam(char *name)
@@ -642,6 +684,8 @@ char *xreadfile(char *name, char *buf, off_t len)
return buf;
}
+// The data argument to ioctl() is actually long, but it's usually used as
+// a pointer. If you need to feed in a number, do (void *)(long) typecast.
int xioctl(int fd, int request, void *data)
{
int rc;
diff --git a/main.c b/main.c
index eeae2f39..c0c1b824 100644
--- a/main.c
+++ b/main.c
@@ -6,14 +6,14 @@
#include "toys.h"
#ifndef TOYBOX_VERSION
-#define TOYBOX_VERSION "0.7.0"
+#define TOYBOX_VERSION "0.7.1"
#endif
// Populate toy_list[].
#undef NEWTOY
#undef OLDTOY
-#define NEWTOY(name, opts, flags) {#name, name##_main, opts, flags},
+#define NEWTOY(name, opts, flags) {#name, name##_main, OPTSTR_##name, flags},
#define OLDTOY(name, oldname, flags) \
{#name, oldname##_main, OPTSTR_##oldname, flags},
@@ -75,7 +75,9 @@ static void toy_singleinit(struct toy_list *which, char *argv[])
if (CFG_TOYBOX_I18N) setlocale(LC_ALL, "C"+!!(which->flags & TOYFLAG_LOCALE));
- if (CFG_TOYBOX_HELP_DASHDASH && argv[1] && !strcmp(argv[1], "--help")) {
+ if (CFG_TOYBOX_HELP_DASHDASH && !(which->flags & TOYFLAG_NOHELP)
+ && argv[1] && !strcmp(argv[1], "--help"))
+ {
if (CFG_TOYBOX && toys.which == toy_list && toys.argv[2])
if (!(toys.which = toy_find(toys.argv[2]))) return;
show_help(stdout);
diff --git a/scripts/genconfig.sh b/scripts/genconfig.sh
index e4c2aad7..c55e7d12 100755
--- a/scripts/genconfig.sh
+++ b/scripts/genconfig.sh
@@ -102,7 +102,7 @@ EOF
genconfig()
{
# Reverse sort puts posix first, examples last.
- for j in $(ls toys/*/README | sort -r)
+ for j in $(ls toys/*/README | sort -s -r)
do
DIR="$(dirname "$j")"
diff --git a/scripts/make.sh b/scripts/make.sh
index d3dc8eb9..50415e55 100755
--- a/scripts/make.sh
+++ b/scripts/make.sh
@@ -27,7 +27,9 @@ do_loudly()
# Is anything under directory $2 newer than file $1
isnewer()
{
- [ ! -z "$(find "$2" -newer "$1" 2>/dev/null || echo yes)" ]
+ CHECK="$1"
+ shift
+ [ ! -z "$(find "$@" -newer "$CHECK" 2>/dev/null || echo yes)" ]
}
echo "Generate headers from toys/*/*.c..."
@@ -66,7 +68,8 @@ TOYFILES="$(sed -n 's/^CONFIG_\([^=]*\)=.*/\1/p' "$KCONFIG_CONFIG" | xargs | tr
TOYFILES="$(egrep -l "TOY[(]($TOYFILES)[ ,]" toys/*/*.c)"
CFLAGS="$CFLAGS $(cat generated/cflags)"
BUILD="$(echo ${CROSS_COMPILE}${CC} $CFLAGS -I . $OPTIMIZE $GITHASH)"
-FILES="$(echo lib/*.c main.c $TOYFILES)"
+LIBFILES="$(ls lib/*.c | grep -v lib/help.c)"
+TOYFILES="lib/help.c main.c $TOYFILES"
if [ "${TOYFILES/pending//}" != "$TOYFILES" ]
then
@@ -79,11 +82,11 @@ genbuildsh()
echo "#!/bin/sh"
echo
- echo "BUILD=\"$BUILD\""
+ echo "BUILD='$BUILD'"
echo
- echo "FILES=\"$FILES\""
+ echo "FILES='$LIBFILES $TOYFILES'"
echo
- echo "LINK=\"$LINK\""
+ echo "LINK='$LINK'"
echo
echo
echo '$BUILD $FILES $LINK'
@@ -100,7 +103,7 @@ then
# for it.
> generated/optlibs.dat
- for i in util crypt m resolv selinux smack attr rt
+ for i in util crypt m resolv selinux smack attr rt crypto
do
echo "int main(int argc, char *argv[]) {return 0;}" | \
${CROSS_COMPILE}${CC} $CFLAGS -xc - -o generated/libprobe -Wl,--as-needed -l$i > /dev/null 2>/dev/null &&
@@ -116,77 +119,88 @@ fi
LINK="$(echo $LDOPTIMIZE $LDFLAGS -o "$UNSTRIPPED" -Wl,--as-needed $(cat generated/optlibs.dat))"
genbuildsh > generated/build.sh && chmod +x generated/build.sh || exit 1
-echo "Make generated/config.h from $KCONFIG_CONFIG."
-
-# This long and roundabout sed invocation is to make old versions of sed happy.
-# New ones have '\n' so can replace one line with two without all the branches
-# and tedious mucking about with hold space.
-
-sed -n \
- -e 's/^# CONFIG_\(.*\) is not set.*/\1/' \
- -e 't notset' \
- -e 's/^CONFIG_\(.*\)=y.*/\1/' \
- -e 't isset' \
- -e 's/^CONFIG_\([^=]*\)=\(.*\)/#define CFG_\1 \2/p' \
- -e 'd' \
- -e ':notset' \
- -e 'h' \
- -e 's/.*/#define CFG_& 0/p' \
- -e 'g' \
- -e 's/.*/#define USE_&(...)/p' \
- -e 'd' \
- -e ':isset' \
- -e 'h' \
- -e 's/.*/#define CFG_& 1/p' \
- -e 'g' \
- -e 's/.*/#define USE_&(...) __VA_ARGS__/p' \
- $KCONFIG_CONFIG > generated/config.h || exit 1
+if isnewer generated/config.h "$KCONFIG_CONFIG"
+then
+ echo "Make generated/config.h from $KCONFIG_CONFIG."
+
+ # This long and roundabout sed invocation is to make old versions of sed
+ # happy. New ones have '\n' so can replace one line with two without all
+ # the branches and tedious mucking about with hold space.
+
+ sed -n \
+ -e 's/^# CONFIG_\(.*\) is not set.*/\1/' \
+ -e 't notset' \
+ -e 's/^CONFIG_\(.*\)=y.*/\1/' \
+ -e 't isset' \
+ -e 's/^CONFIG_\([^=]*\)=\(.*\)/#define CFG_\1 \2/p' \
+ -e 'd' \
+ -e ':notset' \
+ -e 'h' \
+ -e 's/.*/#define CFG_& 0/p' \
+ -e 'g' \
+ -e 's/.*/#define USE_&(...)/p' \
+ -e 'd' \
+ -e ':isset' \
+ -e 'h' \
+ -e 's/.*/#define CFG_& 1/p' \
+ -e 'g' \
+ -e 's/.*/#define USE_&(...) __VA_ARGS__/p' \
+ $KCONFIG_CONFIG > generated/config.h || exit 1
+fi
if [ generated/mkflags -ot scripts/mkflags.c ]
then
do_loudly $HOSTCC scripts/mkflags.c -o generated/mkflags || exit 1
fi
-echo -n "generated/flags.h "
-
# Process config.h and newtoys.h to generate FLAG_x macros. Note we must
# always #define the relevant macro, even when it's disabled, because we
# allow multiple NEWTOY() in the same C file. (When disabled the FLAG is 0,
# so flags&0 becomes a constant 0 allowing dead code elimination.)
-# Parse files through C preprocessor twice, once to get flags for current
-# .config and once to get flags for allyesconfig
-for I in A B
-do
- (
- # define macros and select header files with option string data
-
- echo "#define NEWTOY(aa,bb,cc) aa $I bb"
- echo '#define OLDTOY(...)'
- if [ "$I" == A ]
- then
- cat generated/config.h
- else
- sed '/USE_.*([^)]*)$/s/$/ __VA_ARGS__/' generated/config.h
- fi
- cat generated/newtoys.h
-
- # Run result through preprocessor, glue together " " gaps leftover from USE
- # macros, delete comment lines, print any line with a quoted optstring,
- # turn any non-quoted opstring (NULL or 0) into " " (because fscanf can't
- # handle "" with nothing in it, and mkflags uses that).
-
- ) | ${CROSS_COMPILE}${CC} -E - | \
+make_flagsh()
+{
+ # Parse files through C preprocessor twice, once to get flags for current
+ # .config and once to get flags for allyesconfig
+ for I in A B
+ do
+ (
+ # define macros and select header files with option string data
+
+ echo "#define NEWTOY(aa,bb,cc) aa $I bb"
+ echo '#define OLDTOY(...)'
+ if [ "$I" == A ]
+ then
+ cat generated/config.h
+ else
+ sed '/USE_.*([^)]*)$/s/$/ __VA_ARGS__/' generated/config.h
+ fi
+ cat generated/newtoys.h
+
+ # Run result through preprocessor, glue together " " gaps leftover from USE
+ # macros, delete comment lines, print any line with a quoted optstring,
+ # turn any non-quoted opstring (NULL or 0) into " " (because fscanf can't
+ # handle "" with nothing in it, and mkflags uses that).
+
+ ) | ${CROSS_COMPILE}${CC} -E - | \
sed -n -e 's/" *"//g;/^#/d;t clear;:clear;s/"/"/p;t;s/\( [AB] \).*/\1 " "/p'
-# Sort resulting line pairs and glue them together into triplets of
-# command "flags" "allflags"
-# to feed into mkflags C program that outputs actual flag macros
-# If no pair (because command's disabled in config), use " " for flags
-# so allflags can define the appropriate zero macros.
+ # Sort resulting line pairs and glue them together into triplets of
+ # command "flags" "allflags"
+ # to feed into mkflags C program that outputs actual flag macros
+ # If no pair (because command's disabled in config), use " " for flags
+ # so allflags can define the appropriate zero macros.
-done | sort -s | sed -n 's/ A / /;t pair;h;s/\([^ ]*\).*/\1 " "/;x;b single;:pair;h;n;:single;s/[^ ]* B //;H;g;s/\n/ /;p' | tee generated/flags.raw | \
-generated/mkflags > generated/flags.h || exit 1
+ done | sort -s | sed -n -e 's/ A / /;t pair;h;s/\([^ ]*\).*/\1 " "/;x' \
+ -e 'b single;:pair;h;n;:single;s/[^ ]* B //;H;g;s/\n/ /;p' | \
+ tee generated/flags.raw | generated/mkflags > generated/flags.h || exit 1
+}
+
+if isnewer generated/flags.h toys "$KCONFIG_CONFIG"
+then
+ echo -n "generated/flags.h "
+ make_flagsh
+fi
# Extract global structure definitions and flag definitions from toys/*/*.c
@@ -230,13 +244,16 @@ then
toys/*/*.c lib/*.c | generated/mktags > generated/tags.h
fi
-echo "generated/help.h"
if [ generated/config2help -ot scripts/config2help.c ]
then
do_loudly $HOSTCC scripts/config2help.c -I . lib/xwrap.c lib/llist.c \
lib/lib.c lib/portability.c -o generated/config2help || exit 1
fi
-generated/config2help Config.in $KCONFIG_CONFIG > generated/help.h || exit 1
+if isnewer generated/help.h generated/Config.in
+then
+ echo "generated/help.h"
+ generated/config2help Config.in $KCONFIG_CONFIG > generated/help.h || exit 1
+fi
[ ! -z "$NOBUILD" ] && exit 0
@@ -246,26 +263,38 @@ DOTPROG=.
# This is a parallel version of: do_loudly $BUILD $FILES $LINK || exit 1
+# Any headers newer than the oldest generated/obj file?
X="$(ls -1t generated/obj/* 2>/dev/null | tail -n 1)"
+# TODO: redo this
if [ ! -e "$X" ] || [ ! -z "$(find toys -name "*.h" -newer "$X")" ]
then
rm -rf generated/obj && mkdir -p generated/obj || exit 1
else
rm -f generated/obj/{main,lib_help}.o || exit 1
fi
+
+# build each generated/obj/*.o file in parallel
+
PENDING=
-LFILES=
+LNKFILES=
DONE=0
COUNT=0
-for i in $FILES
+CLICK=
+
+for i in $LIBFILES click $TOYFILES
do
- # build each generated/obj/*.o file in parallel
+ [ "$i" == click ] && CLICK=1 && continue
X=${i/lib\//lib_}
X=${X##*/}
OUT="generated/obj/${X%%.c}.o"
- LFILES="$LFILES $OUT"
- [ "$OUT" -nt "$i" ] && continue
+ LNKFILES="$LNKFILES $OUT"
+
+ # $LIBFILES doesn't need to be rebuilt if newer than .config, $TOYFILES does
+
+ [ "$OUT" -nt "$i" ] && [ -z "$CLICK" -o "$OUT" -nt "$KCONFIG_CONFIG" ] &&
+ continue
+
do_loudly $BUILD -c $i -o $OUT &
PENDING="$PENDING $!"
COUNT=$(($COUNT+1))
@@ -294,7 +323,7 @@ done
[ $DONE -ne 0 ] && exit 1
-do_loudly $BUILD $LFILES $LINK || exit 1
+do_loudly $BUILD $LNKFILES $LINK || exit 1
if [ ! -z "$NOSTRIP" ] ||
! do_loudly ${CROSS_COMPILE}strip "$UNSTRIPPED" -o "$OUTNAME"
then
diff --git a/scripts/mkflags.c b/scripts/mkflags.c
index da3b2f9b..39b935bb 100644
--- a/scripts/mkflags.c
+++ b/scripts/mkflags.c
@@ -122,7 +122,7 @@ int main(int argc, char *argv[])
for (;;) {
struct flag *flist, *aflist, *offlist;
- char *gaps, *mgaps, c;
+ char *mgaps = 0;
unsigned bit;
*command = *flags = *allflags = 0;
@@ -141,16 +141,13 @@ int main(int argc, char *argv[])
bit = 0;
printf("// %s %s %s\n", command, flags, allflags);
- mgaps = mark_gaps(flags, allflags);
- for (gaps = mgaps; *gaps == 1; gaps++);
- if (*gaps) c = '"';
- else {
- c = ' ';
- gaps = "0";
- }
- printf("#undef OPTSTR_%s\n#define OPTSTR_%s %c%s%c\n",
- command, command, c, gaps, c);
- free(mgaps);
+ if (*flags != ' ') mgaps = mark_gaps(flags, allflags);
+ else if (*allflags != ' ') mgaps = allflags;
+ // If command disabled, use allflags for OLDTOY()
+ printf("#undef OPTSTR_%s\n#define OPTSTR_%s ", command, command);
+ if (mgaps) printf("\"%s\"\n", mgaps);
+ else printf("0\n");
+ if (mgaps != allflags) free(mgaps);
flist = digest(flags);
offlist = aflist = digest(allflags);
@@ -194,7 +191,7 @@ int main(int argc, char *argv[])
}
// Output normal flag macro
} else if (aflist->command) {
- if (flist && (!flist->command || *aflist->command == *flist->command)) {
+ if (flist && flist->command && *aflist->command == *flist->command) {
if (aflist->command)
sprintf(out, "#define FLAG_%c (1%s<<%d)\n", *aflist->command,
llstr, bit);
diff --git a/scripts/runtest.sh b/scripts/runtest.sh
index 875ce572..6e94d945 100644
--- a/scripts/runtest.sh
+++ b/scripts/runtest.sh
@@ -90,8 +90,8 @@ testing()
[ $RETVAL -gt 128 ] && [ $RETVAL -lt 255 ] &&
echo "exited with signal (or returned $RETVAL)" >> actual
- cmp expected actual > /dev/null 2>&1
- if [ $? -ne 0 ]
+ DIFF="$(diff -au${NOSPACE:+b} expected actual)"
+ if [ ! -z "$DIFF" ]
then
FAILCOUNT=$[$FAILCOUNT+1]
echo "$SHOWFAIL: $NAME"
@@ -99,7 +99,7 @@ testing()
then
[ ! -z "$4" ] && echo "echo -ne \"$4\" > input"
echo "echo -ne '$5' |$EVAL $2"
- diff -au expected actual
+ echo "$DIFF"
[ "$VERBOSE" == fail ] && exit 1
fi
else
@@ -109,7 +109,7 @@ testing()
[ -n "$DEBUG" ] && set +x
- return $RETVAL
+ return 0
}
# Recursively grab an executable and all the libraries needed to run it.
diff --git a/tests/chattr.test b/tests/chattr.test
index bbf8b099..067014df 100755
--- a/tests/chattr.test
+++ b/tests/chattr.test
@@ -4,6 +4,13 @@
#testing "name" "command" "result" "infile" "stdin"
+if [ "$(id -u)" -ne 0 ]
+then
+ echo "$SHOWSKIP: chattr (not root)"
+ continue 2>/dev/null
+ exit
+fi
+
# chattr - Testcases
mkdir testattr
diff --git a/tests/cmp.test b/tests/cmp.test
index c3e8f5be..3b2dd1b2 100755
--- a/tests/cmp.test
+++ b/tests/cmp.test
@@ -22,12 +22,14 @@ testing "EOF, return code" "cmp input input2 2>/dev/null || echo yes" "yes\n" "a
testing "diff, stdout" "cmp input input2" "input input2 differ: char 4, line 2\n" "ab\nx\nx" ""
testing "diff, return code" "cmp input input2 > /dev/null || echo yes" "yes\n" "ab\nx\nx" ""
-testing "-s EOF, return code" "cmp -s input input2 || echo yes" "yes\n" "ab\nc\nx" ""
-testing "-s diff, return code" "cmp -s input input2 || echo yes" "yes\n" "ab\nx\nx" ""
+testing "-s EOF, return code" "cmp -s input input2 2>&1 || echo yes" "yes\n" "ab\nc\nx" ""
+testing "-s diff, return code" "cmp -s input input2 2>&1 || echo yes" "yes\n" "ab\nx\nx" ""
testing "-l EOF, stderr" "cmp -l input input2 2>&1" "cmp: EOF on input2\n" "ab\nc\nx" ""
testing "-l diff and EOF, stdout and stderr" "cmp -l input input2 2>&1 | sort" "4 170 143\ncmp: EOF on input2\n" "ab\nx\nx" ""
+testing "-s not exist" "cmp -s input doesnotexist 2>&1 || echo yes" "yes\n" "" ""
+
rm input2
testing "stdin and file" "cmp input -" "input - differ: char 4, line 2\n" "ab\nc\n" "ab\nx\n"
diff --git a/tests/date.test b/tests/date.test
index 1d77faa5..213174ee 100644
--- a/tests/date.test
+++ b/tests/date.test
@@ -19,8 +19,8 @@ testing "-d 1110143115.30" "TZ=UTC date -d 1110143115.30 2>&1" "Sun Nov 10 14:31
testing "-d 111014312015.30" "TZ=UTC date -d 111014312015.30 2>&1" "Sun Nov 10 14:31:30 UTC 2015\n" "" ""
# Accidentally given a Unix time, we should trivially reject that.
-testing "Unix time missing @" "TZ=UTC date 1438053157 2>&1" \
- "date: bad date '1438053157'; Wed February 38 05:31:00 UTC 2057 != Sun Mar 10 05:31:00 UTC 2058\n" "" ""
+testing "Unix time missing @" "TZ=UTC date 1438053157 2>/dev/null || echo no" \
+ "no\n" "" ""
# But some invalid dates are more subtle, like Febuary 29th in a non-leap year.
-testing "Feb 29th" "TZ=UTC date 022900001975 2>&1" \
- "date: bad date '022900001975'; Wed Feb 29 00:00:00 UTC 1975 != Sat Mar 1 00:00:00 UTC 1975\n" "" ""
+testing "Feb 29th" "TZ=UTC date 022900001975 2>/dev/null || echo no" \
+ "no\n" "" ""
diff --git a/tests/dd.test b/tests/dd.test
index 42cd170a..9da2108c 100755
--- a/tests/dd.test
+++ b/tests/dd.test
@@ -10,6 +10,12 @@ opt="2>/dev/null"
#testing "name" "command" "result" "infile" "stdin"
+# Test suffixed number parsing; `count` is representative.
+testing "count=2" "dd if=input count=2 ibs=1 $opt" "hi" "high\n" ""
+testing "count= 2" "dd if=input 'count= 2' ibs=1 $opt" "hi" "high\n" ""
+testing "count=0x2" "dd if=input 'count=0x2' ibs=1 $opt" "hi" "high\n" ""
+testing "count=-2" "dd if=input 'count=-2' ibs=1 2>&1" "dd: invalid number '-2'\n" "" ""
+
testing "if=(file)" "dd if=input $opt" "I WANT\n" "I WANT\n" ""
testing "of=(file)" "dd of=file $opt && cat file" "I WANT\n" "" "I WANT\n"
testing "if=file of=file" "dd if=input of=foo $opt && cat foo && rm -f foo" \
@@ -43,6 +49,9 @@ unlink softlink && rm -f file
testing "if=file of=file (same file)" "dd if=input of=input $opt &&
[ -f input ] && cat input && echo 'yes'" "yes\n" "I WANT\n" ""
+testing "same file notrunc" \
+ "dd if=input of=input conv=notrunc $opt && cat input" \
+ "I WANT\n" "I WANT\n" ""
testing "with ibs obs bs" "dd ibs=2 obs=5 bs=9 $opt" "I WANT\n" "" "I WANT\n"
testing "with ibs obs bs if" "dd ibs=2 obs=5 bs=9 if=input $opt" \
@@ -61,9 +70,6 @@ testing "with skip if" "dd skip=0 if=input $opt" "I WANT\n" "I WANT\n" ""
testing "with seek" "dd seek=0 $opt" "I WANT\n" "" "I WANT\n"
testing "with seek if" "dd seek=0 if=input $opt" "I WANT\n" "I WANT\n" ""
-# These type of conv is not supported in toybox: 'ascii', 'ebcdic', 'ibm',
-# 'block', 'unblock', 'nocreat', 'notronc', 'lcase', 'ucase', 'excl', 'swab'
-
# Testing only 'notrunc', 'noerror', 'fsync', 'sync'
testing "conv=notrunc" "dd conv=notrunc $opt" "I WANT\n" "" "I WANT\n"
@@ -81,3 +87,7 @@ testing "conv=fsync with IF" "dd conv=fsync if=input $opt" "I WANT\n" \
testing "conv=sync" "dd conv=sync $opt | head -n 1" "I WANT\n" "" "I WANT\n"
testing "conv=sync with IF" "dd conv=sync if=input $opt | head -n 1" "I WANT\n" \
"I WANT\n" ""
+
+# status=noxfer|none
+testing "status=noxfer" "dd if=input status=noxfer ibs=1 2>&1" "input\n6+0 records in\n0+1 records out\n" "input\n" ""
+testing "status=none" "dd if=input status=none ibs=1 2>&1" "input\n" "input\n" ""
diff --git a/tests/file.test b/tests/file.test
index 234282f9..4c7f001c 100644
--- a/tests/file.test
+++ b/tests/file.test
@@ -10,6 +10,7 @@ echo "#! /bin/bash" > bash.script2
echo "#! /usr/bin/env python" > env.python.script
echo "Hello, world!" > ascii
echo "cafebabe000000310000" | xxd -r -p > java.class
+ln -s java.class symlink
testing "empty" "file empty" "empty: empty\n" "" ""
testing "bash.script" "file bash.script" "bash.script: /bin/bash script\n" "" ""
@@ -17,5 +18,8 @@ testing "bash.script with spaces" "file bash.script2" "bash.script2: /bin/bash s
testing "env python script" "file env.python.script" "env.python.script: python script\n" "" ""
testing "ascii" "file ascii" "ascii: ASCII text\n" "" ""
testing "java class" "file java.class" "java.class: Java class file, version 49.0\n" "" ""
+testing "symlink" "file symlink" "symlink: symbolic link\n" "" ""
+testing "symlink -h" "file -h symlink" "symlink: symbolic link\n" "" ""
+testing "symlink -L" "file -L symlink" "symlink: Java class file, version 49.0\n" "" ""
rm empty bash.script bash.script2 env.python.script ascii java.class
diff --git a/tests/getfattr.test b/tests/getfattr.test
new file mode 100755
index 00000000..cb0f9475
--- /dev/null
+++ b/tests/getfattr.test
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+mkdir attrs
+touch attrs/file
+setfattr -n user.empty attrs/file
+setfattr -n user.data -v hello attrs/file
+
+testing "" "getfattr attrs/file" \
+ "# file: attrs/file\nuser.data\nuser.empty\n\n" "" ""
+testing "-d" "getfattr -d attrs/file" \
+ "# file: attrs/file\nuser.data=\"hello\"\nuser.empty\n\n" "" ""
+testing "-n" "getfattr -n user.empty attrs/file" \
+ "# file: attrs/file\nuser.empty\n\n" "" ""
+testing "-d -n" "getfattr -d -n user.data attrs/file" \
+ "# file: attrs/file\nuser.data=\"hello\"\n\n" "" ""
+
+rm -rf attrs
diff --git a/tests/grep.test b/tests/grep.test
index 227fee00..2a4f178b 100755
--- a/tests/grep.test
+++ b/tests/grep.test
@@ -109,3 +109,37 @@ testing "-C" "grep -C 1 yes" \
testing "-HnC" "grep -HnC1 two" \
"(standard input)-1-one\n(standard input):2:two\n(standard input)-3-three\n" \
"" "one\ntwo\nthree"
+
+# Context lines weren't showing -b
+testing "-HnbB1" "grep -HnbB1 f input" \
+ "input-3-8-three\ninput:4:14:four\ninput:5:19:five\n" \
+ "one\ntwo\nthree\nfour\nfive\n" ""
+
+testing "-q match overrides error" \
+ "grep -q hello missing input 2>/dev/null && echo yes" "yes\n" "hello\n" ""
+testing "-q not found is 1" \
+ 'grep -q hello input || echo $?' "1\n" "" ""
+testing "-q missing is 2" \
+ 'grep -q hello missing missing 2>/dev/null || echo $?' "2\n" "" ""
+testing "-q missing survives exists but not found" \
+ 'grep -q hello missing missing input 2>/dev/null || echo $?' "2\n" "" ""
+testing "not found retained past match" \
+ 'grep hello missing input 2>/dev/null || echo $?' \
+ "input:hello\n2\n" "hello\n" ""
+touch empty
+testing "one match good enough for 0" \
+ 'grep hello input empty && echo $?' 'input:hello\n0\n' 'hello\n' ''
+rm empty
+
+testing "-o ''" "grep -o ''" "" "" "one two three\none two\none\n"
+testing '' "grep -o -e '' -e two" "two\ntwo\n" "" \
+ "one two three\none two\none\n"
+
+echo "one\ntwo\nthree" > test
+testing "-l trumps -C" "grep -l -C1 two test input" "test\ninput\n" \
+ "three\ntwo\none\n" ""
+rm test
+
+# match after NUL byte
+testing "match after NUL byte" "grep -a two" "one\0and two three\n" \
+ "" 'one\0and two three'
diff --git a/tests/md5sum.test b/tests/md5sum.test
index c4dfec94..f159d1ed 100755
--- a/tests/md5sum.test
+++ b/tests/md5sum.test
@@ -20,3 +20,11 @@ testing "5" "md5sum" "d174ab98d277d9f5a5611c2c9f419d9f -\n" \
testing "6" "md5sum" "57edf4a22be3c955ac49da2e2107b67a -\n" \
"" "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+echo -n "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" > "te st"
+touch empty
+testing "-c spaces" "md5sum -c input || echo ok" \
+ "te st: OK\nempty: FAILED\n-: OK\nok\n" \
+"$(printf "d174ab98d277d9f5a5611c2c9f419d9f te st\n12345678901234567890123456789012 empty\nd41d8cd98f00b204e9800998ecf8427e -\n")" ""
+rm "te st" empty
+
+testing "-c nolines" "md5sum -c input 2>/dev/null || echo ok" "ok\n" "" ""
diff --git a/tests/pgrep.test b/tests/pgrep.test
index 753a55ab..3319c79a 100755
--- a/tests/pgrep.test
+++ b/tests/pgrep.test
@@ -29,5 +29,9 @@ testing "-o pattern" "pgrep -o yes" "$proc\n" "" ""
testing "-s" "pgrep -s $session_id yes" "$proc\n" "" ""
testing "-P" "pgrep -P $proc_parent yes" "$proc\n" "" ""
+testing "return success" "pgrep yes && echo success" "$proc\nsuccess\n" "" ""
+testing "return failure" "pgrep almost-certainly-not || echo failure" \
+ "failure\n" "" ""
+
#Clean-up
killall yes >/dev/null 2>&1
diff --git a/tests/pkill.test b/tests/pkill.test
index 7a20ae5c..3f20d260 100755
--- a/tests/pkill.test
+++ b/tests/pkill.test
@@ -63,6 +63,7 @@ killall yes >/dev/null 2>&1
yes >/dev/null &
proc1=$!
+sleep 1
yes >/dev/null &
proc2=$!
sleep 1
@@ -91,10 +92,16 @@ testing "-P parent_prodId pattern" "pkill -P $proc_p yes && sleep 1 &&
killall yes >/dev/null 2>&1
yes >/dev/null &
-proc=$!
-proc_parent=`cat /proc/${proc}/stat | awk '{ print $4 }'`
sleep 1
testing "-9 pattern" "pkill -9 yes && sleep 1 &&
(pgrep yes || echo 'yes')" "yes\n" "" ""
killall yes >/dev/null 2>&1
+yes >/dev/null &
+sleep 1
+testing "return success" "pkill yes && echo success" "success\n" "" ""
+killall yes >/dev/null 2>&1
+
+testing "return failure" "pkill almost-certainly-not || echo failure" \
+ "failure\n" "" ""
+
diff --git a/tests/printf.test b/tests/printf.test
index 7b077f0c..a3331748 100755
--- a/tests/printf.test
+++ b/tests/printf.test
@@ -59,3 +59,9 @@ testing "'%g %G' 78 79" "$PRINTF '%g %G' 78 79" "78 79" "" ""
testing "'%s %s' 78 79" "$PRINTF '%s %s' 78 79" "78 79" "" ""
testing "%.s acts like %.0s" "$PRINTF %.s_ 1 2 3 4 5" "_____" "" ""
+testing "corner case" "$PRINTF '\\8'" '\8' '' ''
+
+# The posix spec explicitly specifies inconsistent behavior,
+# so treating the \0066 in %b like the \0066 not in %b is wrong because posix.
+testing "printf posix inconsistency" "$PRINTF '\\0066-%b' '\\0066'" "\x066-6" \
+ "" ""
diff --git a/tests/sed.test b/tests/sed.test
index 822cfa37..f48b73e6 100755
--- a/tests/sed.test
+++ b/tests/sed.test
@@ -2,26 +2,26 @@
#testing "name" "command" "result" "infile" "stdin"
-testing 'sed as cat' 'sed ""' "one\ntwo\nthree" "" "one\ntwo\nthree"
+testing 'as cat' 'sed ""' "one\ntwo\nthree" "" "one\ntwo\nthree"
# This segfaults ubuntu 12.04's sed. No really.
SKIP_HOST=1 testing 'sed - - twice' 'sed "" - -' "hello\n" "" "hello\n"
-testing 'sed -n' 'sed -n ""' "" "" "one\ntwo\nthree"
-testing 'sed -n p' 'sed -n p' "one\ntwo\nthree" "" "one\ntwo\nthree"
-testing 'sed explicit pattern' 'sed -e p -n' "one\ntwo\nthree" "" \
+testing '-n' 'sed -n ""' "" "" "one\ntwo\nthree"
+testing '-n p' 'sed -n p' "one\ntwo\nthree" "" "one\ntwo\nthree"
+testing 'explicit pattern' 'sed -e p -n' "one\ntwo\nthree" "" \
"one\ntwo\nthree"
# Exploring the wonders of sed addressing modes
testing '' 'sed -n 1p' "one\n" "" "one\ntwo\nthree"
testing '' 'sed 2p' "one\ntwo\ntwo\nthree" "" "one\ntwo\nthree"
testing '' 'sed -n 2p' "two\n" "" "one\ntwo\nthree"
-testing 'sed -n $p' 'sed -n \$p' "three" "" "one\ntwo\nthree"
-testing 'sed as cat #2' "sed -n '1,\$p'" "one\ntwo\nthree" "" "one\ntwo\nthree"
-testing 'sed no input means no last line' "sed '\$a boing'" "" "" ""
-testing 'sed -n $,$p' 'sed -n \$,\$p' 'three' '' 'one\ntwo\nthree'
+testing '-n $p' 'sed -n \$p' "three" "" "one\ntwo\nthree"
+testing 'as cat #2' "sed -n '1,\$p'" "one\ntwo\nthree" "" "one\ntwo\nthree"
+testing 'no input means no last line' "sed '\$a boing'" "" "" ""
+testing '-n $,$p' 'sed -n \$,\$p' 'three' '' 'one\ntwo\nthree'
testing '' 'sed -n 1,2p' "one\ntwo\n" "" "one\ntwo\nthree"
testing '' 'sed -n 2,3p' "two\nthree" "" "one\ntwo\nthree"
testing '' 'sed -n 2,1p' "two\n" "" "one\ntwo\nthree"
-testing 'sed $ with 2 inputs' 'sed -n \$p - input' "four\n" "four\n" \
+testing '$ with 2 inputs' 'sed -n \$p - input' "four\n" "four\n" \
"one\ntwo\nthree"
testing '' 'sed -n /two/p' "two\n" "" "one\ntwo\nthree"
testing '' 'sed -n 1,/two/p' 'one\ntwo\n' '' 'one\ntwo\nthree'
@@ -33,36 +33,38 @@ testing 'sed -n /two/,$p' 'sed -n /two/,\$p' 'two\nthree' '' 'one\ntwo\nthree'
# Fun with newlines!
testing '' 'sed -n 3p' "three" "" "one\ntwo\nthree"
-testing 'sed prodigal newline' "sed -n '1,\$p' - input" \
+testing 'prodigal newline' "sed -n '1,\$p' - input" \
"one\ntwo\nthree\nfour\n" "four\n" "one\ntwo\nthree"
-testing 'sed Newline only added if further output' "sed -n 3p - input" "three" \
+testing 'Newline only added if further output' "sed -n 3p - input" "three" \
"four\n" "one\ntwo\nthree"
# Fun with match delimiters and escapes
-testing 'sed match \t tab' "sed -n '/\t/p'" "\tx\n" "" "\tx\n"
-testing 'sed match t delim disables \t tab' "sed -n '\t\txtp'" "" "" "\tx\n"
-testing 'sed match t delim makes \t literal t' \
+testing 'match \t tab' "sed -n '/\t/p'" "\tx\n" "" "\tx\n"
+testing 'match t delim disables \t tab' "sed -n '\t\txtp'" "" "" "\tx\n"
+testing 'match t delim makes \t literal t' \
"sed -n '\t\txtp'" "tx\n" "" "tx\n"
-testing 'sed match n delim' "sed -n '\n\txnp'" "\tx\n" "" "\tx\n"
-testing 'sed match n delim disables \n newline' "sed -n '\n\nxnp'" "" "" "\nx\n"
-SKIP_HOST=1 testing 'sed match \n literal n' "sed -n '\n\nxnp'" "nx\n" "" "nx\n"
-testing 'sed end match does not check starting match line' \
+testing 'match n delim' "sed -n '\n\txnp'" "\tx\n" "" "\tx\n"
+testing 'match n delim disables \n newline' "sed -n '\n\nxnp'" "" "" "\nx\n"
+SKIP_HOST=1 testing 'match \n literal n' "sed -n '\n\nxnp'" "nx\n" "" "nx\n"
+testing 'end match does not check starting match line' \
"sed -n '/two/,/two/p'" "two\nthree" "" "one\ntwo\nthree"
-testing 'sed end match/start match mixing number/letter' \
+testing 'end match/start match mixing number/letter' \
"sed -n '2,/two/p'" "two\nthree" "" "one\ntwo\nthree"
-testing 'sed num then regex' 'sed -n 2,/d/p' 'b\nc\nd\n' '' 'a\nb\nc\nd\ne\nf\n'
-testing 'sed regex then num' 'sed -n /b/,4p' 'b\nc\nd\n' '' 'a\nb\nc\nd\ne\nf\n'
-testing 'sed multiple regex address match' 'sed -n /on/,/off/p' \
+testing 'num then regex' 'sed -n 2,/d/p' 'b\nc\nd\n' '' 'a\nb\nc\nd\ne\nf\n'
+testing 'regex then num' 'sed -n /b/,4p' 'b\nc\nd\n' '' 'a\nb\nc\nd\ne\nf\n'
+testing 'multiple regex address match' 'sed -n /on/,/off/p' \
'bone\nturtle\scoff\ntron\nlurid\noffer\n' "" \
'zap\nbone\nturtle\scoff\nfred\ntron\nlurid\noffer\nbecause\n'
-testing 'sed regex address overlap' 'sed -n /on/,/off/p' "on\nzap\noffon\n" "" \
+testing 'regex address overlap' 'sed -n /on/,/off/p' "on\nzap\noffon\n" "" \
'on\nzap\noffon\nping\noff\n'
+testing 'getdelim with nested [:blah:]' 'sed -n "sa\a[a[:space:]bc]*aXXagp"' \
+ "ABXXCDXXEFXXGHXXIXX" "" "ABaaCDa EFaa aGHa a Ia "
# gGhHlnNpPqrstwxy:=
# s///#comment
# abcdDi
-testing 'sed prodigaler newline' 'sed -e a\\ -e woo' 'one\nwoo\n' '' 'one'
+testing 'prodigaler newline' 'sed -e a\\ -e woo' 'one\nwoo\n' '' 'one'
testing "aci" \
"sed -e '3a boom' -e '/hre/i bang' -e '3a whack' -e '3c bong'" \
"one\ntwo\nbang\nbong\nboom\nwhack\nfour\n" "" \
@@ -81,7 +83,7 @@ SKIP_HOST=1 testing "c empty continuation" "sed -e 'c\\'" "\n" "" "hello"
testing "D further processing depends on whether line is blank" \
"sed -e '/one/,/three/{' -e 'i meep' -e'N;2D;}'" \
"meep\nmeep\ntwo\nthree\n" "" "one\ntwo\nthree\n"
-testing 'sed newline staying away' 'sed s/o/x/' 'xne\ntwx' '' 'one\ntwo'
+testing 'newline staying away' 'sed s/o/x/' 'xne\ntwx' '' 'one\ntwo'
# Why on _earth_ is this not an error? There's a \ with no continuation!
#testing 'sed what, _really_?' 'sed -e a\\ && echo yes really' \
@@ -91,27 +93,27 @@ testing 'sed newline staying away' 'sed s/o/x/' 'xne\ntwx' '' 'one\ntwo'
testing "match empty line" "sed -e 's/^\$/@/'" "@\n" "" "\n"
-testing 'sed \1' "sed 's/t\\(w\\)o/za\\1py/'" "one\nzawpy\nthree" "" \
+testing '\1' "sed 's/t\\(w\\)o/za\\1py/'" "one\nzawpy\nthree" "" \
"one\ntwo\nthree"
-testing 'sed \1 p' "sed 's/t\\(w\\)o/za\\1py/p'" "one\nzawpy\nzawpy\nthree" \
+testing '\1 p' "sed 's/t\\(w\\)o/za\\1py/p'" "one\nzawpy\nzawpy\nthree" \
"" "one\ntwo\nthree"
-testing 'sed \1 no newline' "sed 's/t\\(w\\)o/za\\1py/'" "one\nzawpy" "" \
+testing '\1 no newline' "sed 's/t\\(w\\)o/za\\1py/'" "one\nzawpy" "" \
"one\ntwo"
-testing 'sed \1 p no newline' "sed 's/t\\(w\\)o/za\\1py/p'" \
+testing '\1 p no newline' "sed 's/t\\(w\\)o/za\\1py/p'" \
"one\nzawpy\nzawpy" "" "one\ntwo"
-testing 'sed -n s//\1/p' "sed -n 's/t\\(w\\)o/za\\1py/p'" "zawpy" "" "one\ntwo"
-testing 'sed -n s//\1/p no newline' "sed -n 's/t\\(w\\)o/za\\1py/p'" "zawpy" \
+testing '-n s//\1/p' "sed -n 's/t\\(w\\)o/za\\1py/p'" "zawpy" "" "one\ntwo"
+testing '-n s//\1/p no newline' "sed -n 's/t\\(w\\)o/za\\1py/p'" "zawpy" \
"" "one\ntwo"
-testing 'sed backref error' \
+testing 'backref error' \
"sed 's/w/ale \2 ha/' >/dev/null 2>/dev/null || echo no" \
"no\n" "" "one\ntwo\nthree"
-testing 'sed empty match after nonempty match' "sed -e 's/a*/c/g'" 'cbcncgc' \
+testing 'empty match after nonempty match' "sed -e 's/a*/c/g'" 'cbcncgc' \
'' 'baaang'
-testing 'sed empty match' "sed -e 's/[^ac]*/A/g'" 'AaAcA' '' 'abcde'
-testing 'sed s///#comment' "sed -e 's/TWO/four/i#comment'" "one\nfour\nthree" \
+testing 'empty match' "sed -e 's/[^ac]*/A/g'" 'AaAcA' '' 'abcde'
+testing 's///#comment' "sed -e 's/TWO/four/i#comment'" "one\nfour\nthree" \
"" "one\ntwo\nthree"
-testing 'sed N flushes pending a and advances match counter' \
+testing 'N flushes pending a and advances match counter' \
"sed -e 'a woo' -e 'N;\$p'" 'woo\none\ntwo\none\ntwo' "" 'one\ntwo'
testing "delimiter in regex [char range] doesn't count" "sed -e 's/[/]//'" \
"onetwo\n" "" 'one/two\n'
diff --git a/tests/setfattr.test b/tests/setfattr.test
new file mode 100755
index 00000000..6a044ea2
--- /dev/null
+++ b/tests/setfattr.test
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+mkdir attrs
+touch attrs/file
+setfattr -n user.empty attrs/file
+setfattr -n user.data -v hello attrs/file
+setfattr -n user.delete-me -v hello attrs/file
+
+testing "-x" \
+ "setfattr -x user.delete-me attrs/file && getfattr attrs/file" \
+ "# file: attrs/file\nuser.data\nuser.empty\n\n" "" ""
+testing "-n" "setfattr -n user.new attrs/file && getfattr -d attrs/file" \
+ "# file: attrs/file\nuser.data=\"hello\"\nuser.empty\nuser.new\n\n" "" ""
+testing "-n -v" "setfattr -n user.new -v data attrs/file && getfattr -d attrs/file" \
+ "# file: attrs/file\nuser.data=\"hello\"\nuser.empty\nuser.new=\"data\"\n\n" "" ""
+
+rm -rf attrs
diff --git a/tests/wc.test b/tests/wc.test
index abb237e8..d227b9c0 100755
--- a/tests/wc.test
+++ b/tests/wc.test
@@ -12,16 +12,14 @@ lines
EOF
testing "wc" "wc >/dev/null && echo yes" "yes\n" "" ""
-testing "empty file" "wc" "0 0 0\n" "" ""
-testing "standard input" "wc" "1 3 5\n" "" "a b\nc"
+testing "empty file" "wc" " 0 0 0\n" "" ""
+testing "standard input" "wc" " 1 3 5\n" "" "a b\nc"
testing "-c" "wc -c file1" "26 file1\n" "" ""
testing "-l" "wc -l file1" "4 file1\n" "" ""
testing "-w" "wc -w file1" "5 file1\n" "" ""
-testing "format" "wc file1" "4 5 26 file1\n" "" ""
+NOSPACE=1 testing "format" "wc file1" " 4 5 26 file1\n" "" ""
testing "multiple files" "wc input - file1" \
- "1 2 3 input\n0 2 3 -\n4 5 26 file1\n5 9 32 total\n" "a\nb" "a b"
-
-optional TOYBOX_I18N
+ " 1 2 3 input\n 0 2 3 -\n 4 5 26 file1\n 5 9 32 total\n" "a\nb" "a b"
#Tests for wc -m
if printf "%s" "$LANG" | grep -q UTF-8
@@ -33,13 +31,14 @@ do
printf "ü" >> file1
done
testing "-m" "wc -m file1" "8193 file1\n" "" ""
+testing "-m 2" 'cat "$FILES/utf8/test2.txt" | wc -m' "169\n" "" ""
printf " " > file1
for i in $(seq 1 8192)
do
printf "ü" >> file1
done
testing "-m (invalid chars)" "wc -m file1" "8193 file1\n" "" ""
-testing "-mlw" "wc -mlw input" "1 2 11 input\n" "hello, 世界!\n" ""
+NOSPACE=1 testing "-mlw" "wc -mlw input" " 1 2 11 input\n" "hello, 世界!\n" ""
else
printf "skipping tests for wc -m"
diff --git a/tests/xxd.test b/tests/xxd.test
index 187bda51..5f43b8b5 100644
--- a/tests/xxd.test
+++ b/tests/xxd.test
@@ -27,6 +27,8 @@ testing "-c 8 -g 3 file1" "xxd -c 8 -g 3 file1" \
testing "-p" "xxd -p file1" "7468697320697320736f6d6520746578740a\n" "" ""
+testing "-s" "xxd -s 13 file1" "0000000d: 7465 7874 0a text.\n" "" ""
+
testing "-r" "xxd file1 | xxd -r" "this is some text\n" "" ""
testing "-r -p" "xxd -p file1 | xxd -r -p" "this is some text\n" "" ""
diff --git a/toys/android/load_policy.c b/toys/android/load_policy.c
index 84967360..d9ff1486 100644
--- a/toys/android/load_policy.c
+++ b/toys/android/load_policy.c
@@ -19,14 +19,13 @@ config LOAD_POLICY
void load_policy_main(void)
{
- char *path = *toys.optargs;
- int fd = xopen(path, O_RDONLY);
+ int fd = xopenro(*toys.optargs);
off_t policy_len = fdlength(fd);
char *policy_data = mmap(0, policy_len, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
if (!policy_data || security_load_policy(policy_data, policy_len) < 0)
- perror_exit("Couldn't %s %s", policy_data ? "load" : "read", path);
+ perror_exit("Couldn't %s %s", policy_data ? "load" : "read", *toys.optargs);
munmap(policy_data, policy_len);
}
diff --git a/toys/android/log.c b/toys/android/log.c
new file mode 100644
index 00000000..7da37b6f
--- /dev/null
+++ b/toys/android/log.c
@@ -0,0 +1,58 @@
+/* log.c - Log to logcat.
+ *
+ * Copyright 2016 The Android Open Source Project
+
+USE_LOG(NEWTOY(log, "<1p:t:", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config LOG
+ bool "log"
+ depends on TOYBOX_ON_ANDROID
+ default y
+ help
+ usage: log [-p PRI] [-t TAG] MESSAGE...
+
+ Logs message to logcat.
+
+ -p use the given priority instead of INFO:
+ d: DEBUG e: ERROR f: FATAL i: INFO v: VERBOSE w: WARN s: SILENT
+ -t use the given tag instead of "log"
+*/
+
+#define FOR_log
+#include "toys.h"
+#include <android/log.h>
+
+GLOBALS(
+ char *tag;
+ char *pri;
+)
+
+void log_main(void)
+{
+ android_LogPriority pri = ANDROID_LOG_INFO;
+ char *s = toybuf;
+ int i;
+
+ if (TT.pri) {
+ i = stridx("defisvw", tolower(*TT.pri));
+ if (i==-1 || strlen(TT.pri)!=1) error_exit("bad -p '%s'", TT.pri);
+ pri = (android_LogPriority []){ANDROID_LOG_DEBUG, ANDROID_LOG_ERROR,
+ ANDROID_LOG_FATAL, ANDROID_LOG_INFO, ANDROID_LOG_SILENT,
+ ANDROID_LOG_VERBOSE, ANDROID_LOG_WARN}[i];
+ }
+ if (!TT.tag) TT.tag = "log";
+
+ for (i = 0; toys.optargs[i]; i++) {
+ if (i) *s++ = ' ';
+ if ((s-toybuf)+strlen(toys.optargs[i])>=1024) {
+ memcpy(s, toys.optargs[i], 1024-(s-toybuf));
+ toybuf[1024] = 0;
+ perror_msg("log cut at 1024 bytes");
+
+ break;
+ }
+ s = stpcpy(s, toys.optargs[i]);
+ }
+
+ __android_log_write(pri, TT.tag, toybuf);
+}
diff --git a/toys/android/sendevent.c b/toys/android/sendevent.c
new file mode 100644
index 00000000..8e982e0b
--- /dev/null
+++ b/toys/android/sendevent.c
@@ -0,0 +1,37 @@
+/* sendevent.c - Send Linux input events.
+ *
+ * Copyright 2016 The Android Open Source Project
+
+USE_SENDEVENT(NEWTOY(sendevent, "<4>4", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config SENDEVENT
+ bool "sendevent"
+ default y
+ depends on TOYBOX_ON_ANDROID
+ help
+ usage: sendevent DEVICE TYPE CODE VALUE
+
+ Sends a Linux input event.
+*/
+
+#define FOR_sendevent
+#include "toys.h"
+
+#include <linux/input.h>
+
+void sendevent_main(void)
+{
+ int fd = xopen(*toys.optargs, O_RDWR);
+ int version;
+ struct input_event ev;
+
+ if (ioctl(fd, EVIOCGVERSION, &version))
+ perror_exit("EVIOCGVERSION failed for %s", *toys.optargs);
+
+ memset(&ev, 0, sizeof(ev));
+ // TODO: error checking and support for named constants.
+ ev.type = atoi(toys.optargs[1]);
+ ev.code = atoi(toys.optargs[2]);
+ ev.value = atoi(toys.optargs[3]);
+ xwrite(fd, &ev, sizeof(ev));
+}
diff --git a/toys/android/start.c b/toys/android/start.c
new file mode 100644
index 00000000..20fa2b9e
--- /dev/null
+++ b/toys/android/start.c
@@ -0,0 +1,61 @@
+/* start.c - Start/stop system services.
+ *
+ * Copyright 2016 The Android Open Source Project
+
+USE_START(NEWTOY(start, "", TOYFLAG_USR|TOYFLAG_SBIN))
+USE_STOP(NEWTOY(stop, "", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config START
+ bool "start"
+ depends on TOYBOX_ON_ANDROID
+ default y
+ help
+ usage: start [SERVICE...]
+
+ Starts the given system service, or netd/surfaceflinger/zygotes.
+
+config STOP
+ bool "stop"
+ depends on TOYBOX_ON_ANDROID
+ default y
+ help
+ usage: stop [SERVICE...]
+
+ Stop the given system service, or netd/surfaceflinger/zygotes.
+*/
+
+#define FOR_start
+#include "toys.h"
+
+#include <cutils/properties.h>
+
+static void start_stop(int start)
+{
+ char *property = start ? "ctl.start" : "ctl.stop";
+ // null terminated in both directions
+ char *services[] = {0,"netd","surfaceflinger","zygote","zygote_secondary",0},
+ **ss = toys.optargs;
+ int direction = 1;
+
+ if (getuid()) error_exit("must be root");
+
+ if (!*ss) {
+ // If we don't have optargs, iterate through services forward/backward.
+ ss = services+1;
+ if (!start) ss = services+ARRAY_LEN(services)-2, direction = -1;
+ }
+
+ for (; *ss; ss += direction)
+ if (property_set(property, *ss))
+ error_exit("failed to set property '%s' to '%s'", property, *ss);
+}
+
+void start_main(void)
+{
+ start_stop(1);
+}
+
+void stop_main(void)
+{
+ start_stop(0);
+}
diff --git a/toys/example/test_human_readable.c b/toys/example/test_human_readable.c
index ae8e7888..9fff2626 100644
--- a/toys/example/test_human_readable.c
+++ b/toys/example/test_human_readable.c
@@ -2,7 +2,7 @@
*
* Copyright 2015 Rob Landley <rob@landley.net>
-USE_TEST_HUMAN_READABLE(NEWTOY(test_human_readable, "<1>1ibs", 0))
+USE_TEST_HUMAN_READABLE(NEWTOY(test_human_readable, "<1>1ibs", TOYFLAG_BIN))
config TEST_HUMAN_READABLE
bool "test_human_readable"
diff --git a/toys/example/test_many_options.c b/toys/example/test_many_options.c
index d2f5c846..e071d26c 100644
--- a/toys/example/test_many_options.c
+++ b/toys/example/test_many_options.c
@@ -2,7 +2,7 @@
*
* Copyright 2015 Rob Landley <rob@landley.net>
-USE_TEST_MANY_OPTIONS(NEWTOY(test_many_options, "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TEST_MANY_OPTIONS(NEWTOY(test_many_options, "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba", TOYFLAG_BIN))
config TEST_MANY_OPTIONS
bool "test_many_options"
diff --git a/toys/example/test_scankey.c b/toys/example/test_scankey.c
index 17eb0cfd..db900270 100644
--- a/toys/example/test_scankey.c
+++ b/toys/example/test_scankey.c
@@ -4,7 +4,7 @@
*
* TODO sigwinch
-USE_TEST_SCANKEY(NEWTOY(test_scankey, 0, 0))
+USE_TEST_SCANKEY(NEWTOY(test_scankey, 0, TOYFLAG_BIN))
config TEST_SCANKEY
bool "test_scankey"
diff --git a/toys/lsb/md5sum.c b/toys/lsb/md5sum.c
index 12f04503..9efdc872 100644
--- a/toys/lsb/md5sum.c
+++ b/toys/lsb/md5sum.c
@@ -6,40 +6,91 @@
* and http://www.ietf.org/rfc/rfc1321.txt
*
* They're combined this way to share infrastructure, and because md5sum is
- * and LSB standard command, sha1sum is just a good idea.
+ * and LSB standard command (but sha1sum and newer hashes are a good idea,
+ * see http://valerieaurora.org/hash.html).
+ *
+ * We optionally use openssl (or equivalent) to access assembly optimized
+ * versions of these functions, but provide a built-in version to reduce
+ * required dependencies.
-USE_MD5SUM(NEWTOY(md5sum, "b", TOYFLAG_USR|TOYFLAG_BIN))
-USE_SHA1SUM(NEWTOY(sha1sum, "b", TOYFLAG_USR|TOYFLAG_BIN))
+USE_MD5SUM(NEWTOY(md5sum, "bc*[!bc]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_SHA1SUM(NEWTOY(sha1sum, "bc*[!bc]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_SHA224SUM(OLDTOY(sha224sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))
+USE_SHA256SUM(OLDTOY(sha256sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))
+USE_SHA384SUM(OLDTOY(sha384sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))
+USE_SHA512SUM(OLDTOY(sha512sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN))
config MD5SUM
bool "md5sum"
default y
help
- usage: md5sum [FILE]...
+ usage: md5sum [-b] [-c FILE] [FILE]...
Calculate md5 hash for each input file, reading from stdin if none.
- Output one hash (16 hex digits) for each input file, followed by
- filename.
+ Output one hash (32 hex digits) for each input file, followed by filename.
-b brief (hash only, no filename)
+ -c Check each line of FILE is the same hash+filename we'd output.
config SHA1SUM
bool "sha1sum"
default y
help
- usage: sha1sum [FILE]...
+ usage: sha?sum [-b] [-c FILE] [FILE]...
- calculate sha1 hash for each input file, reading from stdin if none.
- Output one hash (20 hex digits) for each input file, followed by
- filename.
+ calculate sha hash for each input file, reading from stdin if none. Output
+ one hash (40 hex digits for sha1, 56 for sha224, 64 for sha256, 96 for sha384,
+ and 128 for sha512) for each input file, followed by filename.
-b brief (hash only, no filename)
+ -c Check each line of FILE is the same hash+filename we'd output.
+
+config SHA224SUM
+ bool "sha224sum"
+ default y
+ depends on TOYBOX_LIBCRYPTO
+ help
+ See sha1sum
+
+config SHA256SUM
+ bool "sha256sum"
+ default y
+ depends on TOYBOX_LIBCRYPTO
+ help
+ See sha1sum
+
+config SHA384SUM
+ bool "sha384sum"
+ default y
+ depends on TOYBOX_LIBCRYPTO
+ help
+ See sha1sum
+
+config SHA512SUM
+ bool "sha512sum"
+ default y
+ depends on TOYBOX_LIBCRYPTO
+ help
+ See sha1sum
*/
+#define FORCE_FLAGS
#define FOR_md5sum
#include "toys.h"
+#if CFG_TOYBOX_LIBCRYPTO
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#else
+typedef int SHA512_CTX;
+#endif
+
GLOBALS(
+ struct arg_list *c;
+
+ int sawline;
+
+ // Crypto variables blanked after summing
unsigned state[5];
unsigned oldstate[5];
uint64_t count;
@@ -185,12 +236,58 @@ static void hash_update(char *data, unsigned int len, void (*transform)(void))
}
}
+// Initialize array tersely
+#define HASH_INIT(name, prefix) { name, (void *)prefix##_Init, \
+ (void *)prefix##_Update, (void *)prefix##_Final, \
+ prefix##_DIGEST_LENGTH, }
+#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
+
+// Call the assembly optimized library code when CFG_TOYBOX_LIBCRYPTO
+static void do_lib_hash(int fd, char *name)
+{
+ // Largest context
+ SHA512_CTX ctx;
+ struct hash {
+ char *name;
+ int (*init)(void *);
+ int (*update)(void *, void *, size_t);
+ int (*final)(void *, void *);
+ int digest_length;
+ } algorithms[] = {
+ USE_TOYBOX_LIBCRYPTO(
+ USE_MD5SUM(HASH_INIT("md5sum", MD5),)
+ USE_SHA1SUM(HASH_INIT("sha1sum", SHA1),)
+ USE_SHA224SUM(HASH_INIT("sha224sum", SHA224),)
+ USE_SHA256SUM(HASH_INIT("sha256sum", SHA256),)
+ USE_SHA384SUM(HASH_INIT("sha384sum", SHA384),)
+ USE_SHA512SUM(HASH_INIT("sha512sum", SHA512),)
+ )
+ }, * hash;
+ int i;
+
+ // This should never NOT match, so no need to check
+ for (i = 0; i<ARRAY_LEN(algorithms); i++)
+ if (!strcmp(toys.which->name, algorithms[i].name)) break;
+ hash = algorithms+i;
+
+ hash->init(&ctx);
+ for (;;) {
+ i = read(fd, toybuf, sizeof(toybuf));
+ if (i<1) break;
+ hash->update(&ctx, toybuf, i);
+ }
+ hash->final(toybuf+128, &ctx);
+
+ for (i = 0; i<hash->digest_length; i++)
+ sprintf(toybuf+2*i, "%02x", toybuf[i+128]);
+}
+
// Callback for loopfiles()
-static void do_hash(int fd, char *name)
+static void do_builtin_hash(int fd, char *name)
{
uint64_t count;
- int i, sha1=toys.which->name[0]=='s';;
+ int i, sha1=toys.which->name[0]=='s';
char buf;
void (*transform)(void);
@@ -228,18 +325,97 @@ static void do_hash(int fd, char *name)
if (sha1)
for (i = 0; i < 20; i++)
- printf("%02x", 255&(TT.state[i>>2] >> ((3-(i & 3)) * 8)));
- else for (i=0; i<4; i++) printf("%08x", bswap_32(TT.state[i]));
+ sprintf(toybuf+2*i, "%02x", 255&(TT.state[i>>2] >> ((3-(i & 3)) * 8)));
+ else for (i=0; i<4; i++) sprintf(toybuf+8*i, "%08x", bswap_32(TT.state[i]));
// Wipe variables. Cryptographer paranoia.
- memset(&TT, 0, sizeof(TT));
+ memset(TT.state, 0, sizeof(TT)-((long)TT.state-(long)&TT));
+ i = strlen(toybuf)+1;
+ memset(toybuf+i, 0, sizeof(toybuf)-i);
+}
- printf((toys.optflags & FLAG_b) ? "\n" : " %s\n", name);
+// Call builtin or lib hash function, then display output if necessary
+static void do_hash(int fd, char *name)
+{
+ if (CFG_TOYBOX_LIBCRYPTO) do_lib_hash(fd, name);
+ else do_builtin_hash(fd,name);
+
+ if (name)
+ printf((toys.optflags & FLAG_b) ? "%s\n" : "%s %s\n", toybuf, name);
+}
+
+static int do_c(char *line, size_t len)
+{
+ int space = 0, fail = 0;
+ char *name;
+
+ for (name = line; *name; name++) {
+ if (isspace(*name)) {
+ space++;
+ *name = 0;
+ } else if (space) break;
+ }
+
+ if (!space || !*line || !*name) error_msg("bad line %s", line);
+ else {
+ int fd = !strcmp(name, "-") ? 0 : open(name, O_RDONLY);
+
+ TT.sawline = 1;
+ if (fd==-1) {
+ perror_msg_raw(name);
+ *toybuf = 0;
+ } else do_hash(fd, 0);
+ if (strcasecmp(line, toybuf)) toys.exitval = fail = 1;
+ printf("%s: %s\n", name, fail ? "FAILED" : "OK");
+ if (fd>0) close(fd);
+ }
+
+ return 0;
+}
+
+// Open file, read each line, and call do_line(). Returns 0 if file existed
+// and we read it to the end, 1 if interrupted by callback, 2 of didn't exist
+// do_line returns 0 to free line, 1 to keep line, 2 to end loop
+int looplines(char *name, int trim, int (*do_line)(char *line, size_t len))
+{
+ FILE *fp = !strcmp(name, "-") ? stdin : fopen(name, "r");
+ int rc = 0;
+
+ if (!fp) {
+ perror_msg_raw(name);
+
+ return 2;
+ }
+
+ for (;;) {
+ char *line = 0;
+ ssize_t len;
+
+ if ((len = getline(&line, (void *)&len, fp))<1) break;
+ if (line[len-1]=='\n') len--;
+ if (trim) line[len] = 0;
+ len = do_line(line, len);
+ if (!len) free(line);
+ if (len==2) {
+ rc = 2;
+ break;
+ }
+ }
+ if (fp!=stdin) fclose(fp);
+
+ return rc;
}
void md5sum_main(void)
{
- loopfiles(toys.optargs, do_hash);
+ struct arg_list *al;
+
+ if (!TT.c) loopfiles(toys.optargs, do_hash);
+ else for (al = TT.c; al; al = al->next) {
+ TT.sawline = 0;
+ looplines(al->arg, 1, do_c);
+ if (!TT.sawline) error_msg("%s: no lines", al->arg);
+ }
}
void sha1sum_main(void)
diff --git a/toys/net/README b/toys/net/README
new file mode 100644
index 00000000..8708e4b5
--- /dev/null
+++ b/toys/net/README
@@ -0,0 +1 @@
+Networking
diff --git a/toys/other/ifconfig.c b/toys/net/ifconfig.c
index 1d2a41dc..1d2a41dc 100644
--- a/toys/other/ifconfig.c
+++ b/toys/net/ifconfig.c
diff --git a/toys/other/netcat.c b/toys/net/netcat.c
index 1c75eb26..1c75eb26 100644
--- a/toys/other/netcat.c
+++ b/toys/net/netcat.c
diff --git a/toys/net/netstat.c b/toys/net/netstat.c
new file mode 100644
index 00000000..4e5c884e
--- /dev/null
+++ b/toys/net/netstat.c
@@ -0,0 +1,383 @@
+/* netstat.c - Display Linux networking subsystem.
+ *
+ * Copyright 2012 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * Not in SUSv4.
+ *
+USE_NETSTAT(NEWTOY(netstat, "pWrxwutneal", TOYFLAG_BIN))
+config NETSTAT
+ bool "netstat"
+ default y
+ help
+ usage: netstat [-pWrxwutneal]
+
+ Display networking information. Default is netsat -tuwx
+
+ -r routing table
+ -a all sockets (not just connected)
+ -l listening server sockets
+ -t TCP sockets
+ -u UDP sockets
+ -w raw sockets
+ -x unix sockets
+ -e extended info
+ -n don't resolve names
+ -W wide display
+ -p PID/Program name of sockets
+*/
+
+#define FOR_netstat
+#include "toys.h"
+#include <net/route.h>
+
+GLOBALS(
+ struct num_cache *inodes;
+ int wpad;
+);
+
+// convert address into text format.
+static void addr2str(int af, void *addr, unsigned port, char *buf, int len,
+ char *proto)
+{
+ int pos, count;
+ struct servent *ser = 0;
+
+ // Convert to numeric address
+ if (!inet_ntop(af, addr, buf, 256)) {
+ *buf = 0;
+
+ return;
+ }
+ buf[len] = 0;
+ pos = strlen(buf);
+
+ // If there's no port number, it's a local :* binding, nothing to look up.
+ if (!port) {
+ if (len-pos<2) pos = len-2;
+ strcpy(buf+pos, ":*");
+
+ return;
+ }
+
+ if (!(toys.optflags & FLAG_n)) {
+ struct addrinfo hints, *result, *rp;
+ char cut[4];
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = af;
+
+ if (!getaddrinfo(buf, NULL, &hints, &result)) {
+ socklen_t sock_len = (af == AF_INET) ? sizeof(struct sockaddr_in)
+ : sizeof(struct sockaddr_in6);
+
+ // We assume that a failing getnameinfo dosn't stomp "buf" here.
+ for (rp = result; rp; rp = rp->ai_next)
+ if (!getnameinfo(rp->ai_addr, sock_len, buf, 256, 0, 0, 0)) break;
+ freeaddrinfo(result);
+ buf[len] = 0;
+ pos = strlen(buf);
+ }
+
+ // Doesn't understand proto "tcp6", so truncate
+ memcpy(cut, proto, 3);
+ cut[3] = 0;
+ ser = getservbyport(htons(port), cut);
+ }
+
+ // Append :service
+ count = snprintf(0, 0, ":%u", port);
+ if (ser) {
+ count = snprintf(0, 0, ":%s", ser->s_name);
+ // sheer paranoia
+ if (count>=len) {
+ count = len-1;
+ ser->s_name[count] = 0;
+ }
+ }
+ if (len-pos<count) pos = len-count;
+ if (ser) sprintf(buf+pos, ":%s", ser->s_name);
+ else sprintf(buf+pos, ":%u", port);
+}
+
+// Display info for tcp/udp/raw
+static void show_ip(char *fname)
+{
+ char *ss_state = "UNKNOWN", buf[12], *s, *label = strrchr(fname, '/')+1;
+ char *state_label[] = {"", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1",
+ "FIN_WAIT2", "TIME_WAIT", "CLOSE", "CLOSE_WAIT",
+ "LAST_ACK", "LISTEN", "CLOSING", "UNKNOWN"};
+ struct passwd *pw;
+ FILE *fp = fopen(fname, "r");
+
+ if (!fp) {
+ perror_msg("'%s'", fname);
+ return;
+ }
+
+ if(!fgets(toybuf, sizeof(toybuf), fp)) return; //skip header.
+
+ while (fgets(toybuf, sizeof(toybuf), fp)) {
+ char lip[256], rip[256];
+ union {
+ struct {unsigned u; unsigned char b[4];} i4;
+ struct {struct {unsigned a, b, c, d;} u; unsigned char b[16];} i6;
+ } laddr, raddr;
+ unsigned lport, rport, state, txq, rxq, num, uid, nitems;
+ unsigned long inode;
+
+ // Try ipv6, then try ipv4
+ nitems = sscanf(toybuf,
+ " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x %*X:%*X %*X %d %*d %ld",
+ &num, &laddr.i6.u.a, &laddr.i6.u.b, &laddr.i6.u.c,
+ &laddr.i6.u.d, &lport, &raddr.i6.u.a, &raddr.i6.u.b,
+ &raddr.i6.u.c, &raddr.i6.u.d, &rport, &state, &txq, &rxq,
+ &uid, &inode);
+
+ if (nitems!=16) {
+ nitems = sscanf(toybuf,
+ " %d: %x:%x %x:%x %x %x:%x %*X:%*X %*X %d %*d %ld",
+ &num, &laddr.i4.u, &lport, &raddr.i4.u, &rport, &state, &txq,
+ &rxq, &uid, &inode);
+
+ if (nitems!=10) continue;
+ nitems = AF_INET;
+ } else nitems = AF_INET6;
+
+ // Should we display this? (listening or all or TCP/UDP/RAW)
+ if (!((toys.optflags & FLAG_l) && (!rport && (state & 0xA)))
+ && !(toys.optflags & FLAG_a) && !(rport & (0x10 | 0x20 | 0x40)))
+ continue;
+
+ addr2str(nitems, &laddr, lport, lip, TT.wpad, label);
+ addr2str(nitems, &raddr, rport, rip, TT.wpad, label);
+
+ // Display data
+ s = label;
+ if (strstart(&s, "tcp")) {
+ int sz = ARRAY_LEN(state_label);
+ if (!state || state >= sz) state = sz-1;
+ ss_state = state_label[state];
+ } else if (strstart(&s, "udp")) {
+ if (state == 1) ss_state = state_label[state];
+ else if (state == 7) ss_state = "";
+ } else if (strstart(&s, "raw")) sprintf(ss_state = buf, "%u", state);
+
+ if (!(toys.optflags & FLAG_n) && (pw = bufgetpwuid(uid)))
+ snprintf(toybuf, sizeof(toybuf), "%s", pw->pw_name);
+ else snprintf(toybuf, sizeof(toybuf), "%d", uid);
+
+ printf("%-6s%6d%7d ", label, rxq, txq);
+ printf("%*.*s %*.*s ", -TT.wpad, TT.wpad, lip, -TT.wpad, TT.wpad, rip);
+ printf("%-11s", ss_state);
+ if ((toys.optflags & FLAG_e)) printf(" %-10s %-11ld", toybuf, inode);
+ if ((toys.optflags & FLAG_p)) {
+ struct num_cache *nc = get_num_cache(TT.inodes, inode);
+
+ printf(" %s", nc ? nc->data : "-");
+ }
+ xputc('\n');
+ }
+ fclose(fp);
+}
+
+static void show_unix_sockets(void)
+{
+ char *types[] = {"","STREAM","DGRAM","RAW","RDM","SEQPACKET","DCCP","PACKET"},
+ *states[] = {"","LISTENING","CONNECTING","CONNECTED","DISCONNECTING"},
+ *s, *ss;
+ unsigned long refcount, flags, type, state, inode;
+ FILE *fp = xfopen("/proc/net/unix", "r");
+
+ if(!fgets(toybuf, sizeof(toybuf), fp)) return; //skip header.
+
+ while (fgets(toybuf, sizeof(toybuf), fp)) {
+ unsigned offset = 0;
+
+ // count = 6 or 7 (first field ignored, sockets don't always have filenames)
+ if (6<sscanf(toybuf, "%*p: %lX %*X %lX %lX %lX %lu %n",
+ &refcount, &flags, &type, &state, &inode, &offset))
+ continue;
+
+ // Linux exports only SO_ACCEPTCON since 2.3.15pre3 in 1999, but let's
+ // filter in case they add more someday.
+ flags &= 1<<16;
+
+ // Only show unconnected listening sockets with -a
+ if (state==1 && flags && !(toys.optflags&FLAG_a)) continue;
+
+ if (type==10) type = 7; // move SOCK_PACKET into line
+ if (type>ARRAY_LEN(types)) type = 0;
+ if (state>ARRAY_LEN(states) || (state==1 && !flags)) state = 0;
+ sprintf(toybuf, "[ %s]", flags ? "ACC " : "");
+
+ printf("unix %-6ld %-11s %-10s %-13s %8lu ",
+ refcount, toybuf, types[type], states[state], inode);
+ if (toys.optflags & FLAG_p) {
+ struct num_cache *nc = get_num_cache(TT.inodes, inode);
+
+ printf("%-19.19s", nc ? nc->data : "-");
+ }
+
+ if (offset) {
+ if ((ss = strrchr(s = toybuf+offset, '\n'))) *ss = 0;
+ printf("%s", s);
+ }
+ xputc('\n');
+ }
+
+ fclose(fp);
+}
+
+static int scan_pids(struct dirtree *node)
+{
+ char *s = toybuf+256;
+ struct dirent *entry;
+ DIR *dp;
+ int pid, dirfd;
+
+ if (!node->parent) return DIRTREE_RECURSE;
+ if (!(pid = atol(node->name))) return 0;
+
+ sprintf(toybuf, "/proc/%d/cmdline", pid);
+ if (!(readfile(toybuf, toybuf, 256))) return 0;
+
+ sprintf(s, "%d/fd", pid);
+ if (-1==(dirfd = openat(dirtree_parentfd(node), s, O_RDONLY))) return 0;
+ if (!(dp = fdopendir(dirfd))) {
+ close(dirfd);
+
+ return 0;
+ }
+
+ while ((entry = readdir(dp))) {
+ s = toybuf+256;
+ if (!readlinkat0(dirfd, entry->d_name, s, sizeof(toybuf)-256)) continue;
+ // Can the "[0000]:" happen in a modern kernel?
+ if (strstart(&s, "socket:[") || strstart(&s, "[0000]:")) {
+ long long ll = atoll(s);
+
+ sprintf(s, "%d/%s", pid, getbasename(toybuf));
+ add_num_cache(&TT.inodes, ll, s, strlen(s)+1);
+ }
+ }
+ closedir(dp);
+
+ return 0;
+}
+
+/*
+ * extract inet4 route info from /proc/net/route file and display it.
+ */
+static void display_routes(void)
+{
+ static const char flagchars[] = "GHRDMDAC";
+ static const unsigned flagarray[] = {
+ RTF_GATEWAY, RTF_HOST, RTF_REINSTATE, RTF_DYNAMIC, RTF_MODIFIED
+ };
+ unsigned long dest, gate, mask;
+ int flags, ref, use, metric, mss, win, irtt;
+ char *out = toybuf, *flag_val;
+ char iface[64]={0};
+ FILE *fp = xfopen("/proc/net/route", "r");
+
+ if(!fgets(toybuf, sizeof(toybuf), fp)) return; //skip header.
+
+ printf("Kernel IP routing table\n"
+ "Destination\tGateway \tGenmask \tFlags %s Iface\n",
+ !(toys.optflags&FLAG_e) ? " MSS Window irtt" : "Metric Ref Use");
+
+ while (fgets(toybuf, sizeof(toybuf), fp)) {
+ char *destip = 0, *gateip = 0, *maskip = 0;
+
+ if (11 != sscanf(toybuf, "%63s%lx%lx%X%d%d%d%lx%d%d%d", iface, &dest,
+ &gate, &flags, &ref, &use, &metric, &mask, &mss, &win, &irtt))
+ break;
+
+ // skip down interfaces.
+ if (!(flags & RTF_UP)) continue;
+
+// TODO /proc/net/ipv6_route
+
+ if (dest) {
+ if (inet_ntop(AF_INET, &dest, out, 16)) destip = out;
+ } else destip = (toys.optflags&FLAG_n) ? "0.0.0.0" : "default";
+ out += 16;
+
+ if (gate) {
+ if (inet_ntop(AF_INET, &gate, out, 16)) gateip = out;
+ } else gateip = (toys.optflags&FLAG_n) ? "0.0.0.0" : "*";
+ out += 16;
+
+// TODO /24
+ //For Mask
+ if (inet_ntop(AF_INET, &mask, out, 16)) maskip = out;
+ else maskip = "?";
+ out += 16;
+
+ //Get flag Values
+ flag_val = out;
+ *out++ = 'U';
+ for (dest = 0; dest < ARRAY_LEN(flagarray); dest++)
+ if (flags&flagarray[dest]) *out++ = flagchars[dest];
+ *out = 0;
+ if (flags & RTF_REJECT) *flag_val = '!';
+
+ printf("%-15.15s %-15.15s %-16s%-6s", destip, gateip, maskip, flag_val);
+ if (!(toys.optflags & FLAG_e))
+ printf("%5d %-5d %6d %s\n", mss, win, irtt, iface);
+ else printf("%-6d %-2d %7d %s\n", metric, ref, use, iface);
+ }
+
+ fclose(fp);
+}
+
+void netstat_main(void)
+{
+ int tuwx = FLAG_t|FLAG_u|FLAG_w|FLAG_x;
+ char *type = "w/o";
+
+ TT.wpad = (toys.optflags&FLAG_W) ? 51 : 23;
+ if (!(toys.optflags&(FLAG_r|tuwx))) toys.optflags |= tuwx;
+ if (toys.optflags & FLAG_r) display_routes();
+ if (!(toys.optflags&tuwx)) return;
+
+ if (toys.optflags & FLAG_a) type = "established and";
+ else if (toys.optflags & FLAG_l) type = "only";
+
+ if (toys.optflags & FLAG_p) dirtree_read("/proc", scan_pids);
+
+ if (toys.optflags&(FLAG_t|FLAG_u|FLAG_w)) {
+ printf("Active %s (%s servers)\n", "Internet connections", type);
+ printf("Proto Recv-Q Send-Q %*s %*s State ", -TT.wpad, "Local Address",
+ -TT.wpad, "Foreign Address");
+ if (toys.optflags & FLAG_e) printf(" User Inode ");
+ if (toys.optflags & FLAG_p) printf(" PID/Program Name");
+ xputc('\n');
+
+ if (toys.optflags & FLAG_t) {
+ show_ip("/proc/net/tcp");
+ show_ip("/proc/net/tcp6");
+ }
+ if (toys.optflags & FLAG_u) {
+ show_ip("/proc/net/udp");
+ show_ip("/proc/net/udp6");
+ }
+ if (toys.optflags & FLAG_w) {
+ show_ip("/proc/net/raw");
+ show_ip("/proc/net/raw6");
+ }
+ }
+
+ if (toys.optflags & FLAG_x) {
+ printf("Active %s (%s servers)\n", "UNIX domain sockets", type);
+
+ printf("Proto RefCnt Flags\t Type\t State\t %s Path\n",
+ (toys.optflags&FLAG_p) ? "PID/Program Name" : "I-Node");
+ show_unix_sockets();
+ }
+
+ if ((toys.optflags & FLAG_p) && CFG_TOYBOX_FREE)
+ llist_traverse(TT.inodes, free);
+ toys.exitval = 0;
+}
diff --git a/toys/other/rfkill.c b/toys/net/rfkill.c
index 36fe320d..56e57687 100644
--- a/toys/other/rfkill.c
+++ b/toys/net/rfkill.c
@@ -80,7 +80,7 @@ void rfkill_main(void)
continue;
sprintf(toybuf, "/sys/class/rfkill/rfkill%u/uevent", rfevent.idx);
- tvar = xopen(toybuf, O_RDONLY);
+ tvar = xopenro(toybuf);
while ((line = get_line(tvar))) {
char *s = line;
diff --git a/toys/net/tunctl.c b/toys/net/tunctl.c
new file mode 100644
index 00000000..1aafebfd
--- /dev/null
+++ b/toys/net/tunctl.c
@@ -0,0 +1,53 @@
+/* tunctl.c - Control tap/tun network devices.
+ *
+ * Copyright 2016 Rob Landley <rob@landley.net>
+ *
+ * See http://kernel.org/doc/Documentation/networking/tuntap.txt
+ *
+ * This is useful for things like "kvm -netdev tap" and containers.
+ * See https://landley.net/lxc/02-networking.html for example usage.
+ *
+ * todo: bridge mode
+ * -b bridge daemon (forwards packets between NAME and NAME2 interfaces)
+
+
+USE_TUNCTL(NEWTOY(tunctl, "<1>1t|d|u:T[!td]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config TUNCTL
+ bool "tunctl"
+ default y
+ help
+ usage: tunctl [-dtT] [-u USER] NAME
+
+ Create and delete tun/tap virtual ethernet devices.
+
+ -T Use tap (ethernet frames) instead of tun (ip packets)
+ -d Delete tun/tap device
+ -t Create tun/tap device
+ -u Set owner (user who can read/write device without root access)
+*/
+
+#define FOR_tunctl
+#include "toys.h"
+#include <linux/if_tun.h>
+
+GLOBALS(
+ char *user;
+)
+
+void tunctl_main(void)
+{
+ struct ifreq *ifr = (void *)toybuf;
+ uid_t u = TT.user ? xgetuid(TT.user) : 0;
+ int fd = xopen("/dev/net/tun", O_RDWR);
+
+ // Associate filehandle with device
+ ifr->ifr_flags = ((toys.optflags&FLAG_T) ? IFF_TUN : IFF_TAP)|IFF_NO_PI;
+ strncpy(ifr->ifr_name, *toys.optargs, sizeof(ifr->ifr_name));
+ xioctl(fd, TUNSETIFF, toybuf);
+
+ if (toys.optflags&FLAG_t) {
+ xioctl(fd, TUNSETPERSIST, (void *)1);
+ xioctl(fd, TUNSETOWNER, (void *)(long)u);
+ } else xioctl(fd, TUNSETPERSIST, (void *)0);
+}
diff --git a/toys/other/blockdev.c b/toys/other/blockdev.c
index e5a504e6..38e09935 100644
--- a/toys/other/blockdev.c
+++ b/toys/other/blockdev.c
@@ -46,7 +46,7 @@ void blockdev_main(void)
if (!toys.optflags) help_exit("need --option");
for (ss = toys.optargs; *ss; ss++) {
- int fd = xopen(*ss, O_RDONLY), i;
+ int fd = xopenro(*ss), i;
// Command line order discarded so perform multiple operations in flag order
for (i = 0; i < 32; i++) {
diff --git a/toys/other/fsfreeze.c b/toys/other/fsfreeze.c
index e169554e..dfe17fb9 100644
--- a/toys/other/fsfreeze.c
+++ b/toys/other/fsfreeze.c
@@ -23,7 +23,7 @@ config FSFREEZE
void fsfreeze_main(void)
{
- int fd = xopen(*toys.optargs, O_RDONLY);
+ int fd = xopenro(*toys.optargs);
long p = 1;
xioctl(fd, (toys.optflags & FLAG_f) ? FIFREEZE : FITHAW, &p);
diff --git a/toys/other/fsync.c b/toys/other/fsync.c
index e6f6c8d9..bd73f398 100644
--- a/toys/other/fsync.c
+++ b/toys/other/fsync.c
@@ -28,6 +28,6 @@ static void do_fsync(int fd, char *name)
void fsync_main(void)
{
- loopfiles_rw(toys.optargs, O_RDONLY|O_NOATIME|O_NOCTTY|O_CLOEXEC,
- 0, 0, do_fsync);
+ loopfiles_rw(toys.optargs, O_RDONLY|O_NOATIME|O_NOCTTY|O_CLOEXEC|WARN_ONLY,
+ 0, do_fsync);
}
diff --git a/toys/other/insmod.c b/toys/other/insmod.c
index 18ac9176..9a3f5958 100644
--- a/toys/other/insmod.c
+++ b/toys/other/insmod.c
@@ -25,7 +25,7 @@ config INSMOD
void insmod_main(void)
{
- int fd = !strcmp(*toys.optargs, "-") ? 0 : xopen(*toys.optargs, O_RDONLY);
+ int fd = xopenro(*toys.optargs);
int i, rc;
i = 1;
diff --git a/toys/other/lspci.c b/toys/other/lspci.c
index 077ce757..a0671791 100644
--- a/toys/other/lspci.c
+++ b/toys/other/lspci.c
@@ -50,10 +50,9 @@ static int do_lspci(struct dirtree *new)
if (-1 == (dirfd = openat(dirtree_parentfd(new), new->name, O_RDONLY)))
return 0;
- // it's ok for the driver link not to be there, whatever fortify says
*driver = 0;
if (toys.optflags & FLAG_k)
- if (readlinkat(dirfd, "driver", driver, sizeof(driver))) {};
+ readlinkat0(dirfd, "driver", driver, sizeof(driver));
for (fields = (char*[]){"class", "vendor", "device", 0}; *fields; fields++) {
int fd, size = 6 + 2*((toys.optflags & FLAG_e) && p == toybuf);
@@ -122,8 +121,7 @@ void lspci_main(void)
{
if (CFG_LSPCI_TEXT && TT.numeric != 1) {
if (!TT.ids) TT.ids = "/usr/share/misc/pci.ids";
- if (!(TT.db = fopen(TT.ids, "r")))
- perror_msg("could not open PCI ID db");
+ if (!(TT.db = fopen(TT.ids, "r"))) perror_msg("%s", TT.ids);
}
dirtree_read("/sys/bus/pci/devices", do_lspci);
diff --git a/toys/other/makedevs.c b/toys/other/makedevs.c
index 0f79b25f..5e6a9822 100644
--- a/toys/other/makedevs.c
+++ b/toys/other/makedevs.c
@@ -47,7 +47,7 @@ void makedevs_main()
// Open file and chdir, verbosely
xprintf("rootdir = %s\n", *toys.optargs);
if (toys.optflags & FLAG_d && strcmp(TT.fname, "-")) {
- fd = xopen(TT.fname, O_RDONLY);
+ fd = xopenro(TT.fname);
xprintf("table = %s\n", TT.fname);
} else xprintf("table = <stdin>\n");
xchdir(*toys.optargs);
@@ -78,8 +78,8 @@ void makedevs_main()
continue;
} else mode |= (mode_t[]){S_IFIFO, S_IFCHR, S_IFBLK, 0, 0}[i];
- uid = *user ? xgetpwnamid(user)->pw_uid : getuid();
- gid = *group ? xgetgrnamid(group)->gr_gid : getgid();
+ uid = *user ? xgetuid(user) : getuid();
+ gid = *group ? xgetgid(group) : getgid();
while (*node == '/') node++; // using relative path
diff --git a/toys/other/nsenter.c b/toys/other/nsenter.c
index 13757280..78a9d91a 100644
--- a/toys/other/nsenter.c
+++ b/toys/other/nsenter.c
@@ -152,8 +152,7 @@ void unshare_main(void)
filename = toybuf;
}
- if (setns(fd = xopen(filename, O_RDONLY), flags[i]))
- perror_exit("setns");
+ if (setns(fd = xopenro(filename), flags[i])) perror_exit("setns");
close(fd);
}
nsnames += strlen(nsnames)+1;
diff --git a/toys/other/oneit.c b/toys/other/oneit.c
index 0e95a104..9be67c05 100644
--- a/toys/other/oneit.c
+++ b/toys/other/oneit.c
@@ -68,11 +68,11 @@ void oneit_main(void)
for (i = 0; i<ARRAY_LEN(pipes); i++) xsignal(pipes[i], oneit_signaled);
if (toys.optflags & FLAG_3) {
- // Ensure next available filehandle is #3
- while (open("/", 0) < 3);
+ // Ensure next available filehandles are #3 and #4
+ while (xopen_stdio("/", 0) < 3);
close(3);
close(4);
- if (pipe(pipes)) perror_exit("pipe");
+ xpipe(pipes);
fcntl(4, F_SETFD, FD_CLOEXEC);
}
diff --git a/toys/other/pwdx.c b/toys/other/pwdx.c
index bde16e79..2a72dba3 100644
--- a/toys/other/pwdx.c
+++ b/toys/other/pwdx.c
@@ -20,20 +20,14 @@ void pwdx_main(void)
char **optargs;
for (optargs = toys.optargs; *optargs; optargs++) {
- char *path;
- int num_bytes;
+ char *path = toybuf;
- path = xmprintf("/proc/%s/cwd", *optargs);
- num_bytes = readlink(path, toybuf, sizeof(toybuf)-1);
- free(path);
-
- if (num_bytes==-1) {
+ sprintf(toybuf, "/proc/%d/cwd", atoi(*optargs));
+ if (!readlink0(path, toybuf, sizeof(toybuf))) {
path = strerror(errno);
toys.exitval = 1;
- } else {
- path = toybuf;
- toybuf[num_bytes] = 0;
}
+
xprintf("%s: %s\n", *optargs, path);
}
}
diff --git a/toys/other/setfattr.c b/toys/other/setfattr.c
new file mode 100644
index 00000000..080991f2
--- /dev/null
+++ b/toys/other/setfattr.c
@@ -0,0 +1,47 @@
+/* setfattr.c - Write POSIX extended attributes.
+ *
+ * Copyright 2016 Android Open Source Project.
+ *
+ * No standard
+
+USE_SETFATTR(NEWTOY(setfattr, "hn:|v:x:|[!xv]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config SETFATTR
+ bool "setfattr"
+ default y
+ help
+ usage: setfattr [-h] [-x|-n NAME] [-v VALUE] FILE...
+
+ Write POSIX extended attributes.
+
+ -h Do not dereference symlink.
+ -n Set given attribute.
+ -x Remove given attribute.
+ -v Set value for attribute -n (default is empty).
+*/
+
+#define FOR_setfattr
+#include "toys.h"
+
+GLOBALS(
+ char *x, *v, *n;
+)
+
+static void do_setfattr(char *file)
+{
+ int h = toys.optflags & FLAG_h;
+
+ if (toys.optflags&FLAG_x) {
+ if ((h ? lremovexattr : removexattr)(file, TT.x))
+ perror_msg("removexattr failed");
+ } else
+ if ((h ? lsetxattr : setxattr)(file, TT.n, TT.v, TT.v?strlen(TT.v):0, 0))
+ perror_msg("setxattr failed");
+}
+
+void setfattr_main(void)
+{
+ char **s;
+
+ for (s=toys.optargs; *s; s++) do_setfattr(*s);
+}
diff --git a/toys/other/shred.c b/toys/other/shred.c
index 5b018ea0..30b5e7d9 100644
--- a/toys/other/shred.c
+++ b/toys/other/shred.c
@@ -42,7 +42,7 @@ void shred_main(void)
char **try;
if (!(toys.optflags & FLAG_n)) TT.iterations++;
- TT.ufd = xopen("/dev/urandom", O_RDONLY);
+ TT.ufd = xopenro("/dev/urandom");
// We don't use loopfiles() here because "-" isn't stdin, and want to
// respond to files we can't open via chmod.
diff --git a/toys/other/stat.c b/toys/other/stat.c
index f66eb4b7..b5dfcc87 100644
--- a/toys/other/stat.c
+++ b/toys/other/stat.c
@@ -2,27 +2,30 @@
* Copyright 2012 <warior.linux@gmail.com>
* Copyright 2013 <anand.sinha85@gmail.com>
-USE_STAT(NEWTOY(stat, "<1c:tf", TOYFLAG_BIN))
+USE_STAT(NEWTOY(stat, "<1c:fLt", TOYFLAG_BIN))
config STAT
bool stat
default y
help
- usage: stat [-f] [-t] [-c FORMAT] FILE...
+ usage: stat [-tfL] [-c FORMAT] FILE...
Display status of files or filesystems.
- -f display filesystem status instead of file status
- -c Output specified FORMAT string instead of default
- -t Display info in terse form
+ -c Output specified FORMAT string instead of default
+ -f display filesystem status instead of file status
+ -L Follow symlinks
+ -t terse (-c "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o")
+ (with -f = -c "%n %i %l %t %s %S %b %f %a %c %d")
The valid format escape sequences for files:
- %a Access bits (octal) |%A Access bits (flags)|%b Blocks allocated
- %B Bytes per block |%d Device ID (dec) |%D Device ID (hex)
+ %a Access bits (octal) |%A Access bits (flags)|%b Size/512
+ %B Bytes per %b (512) |%d Device ID (dec) |%D Device ID (hex)
%f All mode bits (hex) |%F File type |%g Group ID
%G Group name |%h Hard links |%i Inode
- %n Filename |%N Long filename |%o I/O block size
- %s Size (bytes) |%u User ID |%U User name
+ %m Mount point |%n Filename |%N Long filename
+ %o I/O block size |%s Size (bytes) |%t Devtype major (hex)
+ %T Devtype minor (hex) |%u User ID |%U User name
%x Access time |%X Access unix time |%y File write time
%Y File write unix time|%z Dir change time |%Z Dir change unix time
@@ -30,7 +33,7 @@ config STAT
%a Available blocks |%b Total blocks |%c Total inodes
%d Free inodes |%f Free blocks |%i File system ID
%l Max filename length |%n File name |%s Fragment size
- %S Best transfer size |%t Filesystem type |%T Filesystem type name
+ %S Best transfer size |%t FS type (hex) |%T FS type (driver name)
*/
#define FOR_stat
@@ -43,10 +46,24 @@ GLOBALS(
struct stat st;
struct statfs sf;
} stat;
- struct passwd *user_name;
- struct group *group_name;
+ char *file, *pattern;
+ int patlen;
)
+// Force numeric output to long long instead of manually typecasting everything
+// and safely parse length prefix
+static void out(char c, long long val)
+{
+ sprintf(toybuf, "%.*sll%c", TT.patlen, TT.pattern, c);
+ printf(toybuf, val);
+}
+
+// Output string with parsed length prefix
+static void strout(char *val)
+{
+ sprintf(toybuf, "%.*ss", TT.patlen, TT.pattern);
+ printf(toybuf, val);
+}
// Note: the atime, mtime, and ctime fields in struct stat are the start
// of embedded struct timespec, but posix won't let them use that
@@ -54,16 +71,11 @@ GLOBALS(
static void date_stat_format(struct timespec *ts)
{
- strftime(toybuf, sizeof(toybuf), "%Y-%m-%d %H:%M:%S",
+ char *s = toybuf+128;
+ strftime(s, sizeof(toybuf), "%Y-%m-%d %H:%M:%S",
localtime(&(ts->tv_sec)));
- xprintf("%s.%09ld", toybuf, ts->tv_nsec);
-}
-
-// Force numeric output to long long instead of manually typecasting everything
-static void out(char c, long long val)
-{
- sprintf(toybuf, "%%ll%c", c);
- printf(toybuf, val);
+ sprintf(s+strlen(s), ".%09ld", ts->tv_nsec);
+ strout(s);
}
static void print_stat(char type)
@@ -75,9 +87,9 @@ static void print_stat(char type)
char str[11];
mode_to_string(stat->st_mode, str);
- xprintf("%s", str);
+ strout(str);
} else if (type == 'b') out('u', stat->st_blocks);
- else if (type == 'B') out('u', stat->st_blksize);
+ else if (type == 'B') out('d', 512);
else if (type == 'd') out('d', stat->st_dev);
else if (type == 'D') out('x', stat->st_dev);
else if (type == 'f') out('x', stat->st_mode);
@@ -88,20 +100,32 @@ static void print_stat(char type)
for (i = 1; filetype != (i*8192) && i < 7; i++) t += strlen(t)+1;
if (!stat->st_size && filetype == S_IFREG) t = "regular empty file";
- xprintf("%s", t);
+ strout(t);
} else if (type == 'g') out('u', stat->st_gid);
- else if (type == 'G') xprintf("%8s", TT.group_name->gr_name);
+ else if (type == 'G') strout(getgroupname(stat->st_gid));
else if (type == 'h') out('u', stat->st_nlink);
else if (type == 'i') out('u', stat->st_ino);
- else if (type == 'N') {
- xprintf("`%s'", *toys.optargs);
+ else if (type == 'm') {
+ struct mtab_list *mt = xgetmountlist(0);
+ dev_t dev = stat->st_rdev ? stat->st_rdev : stat->st_dev;
+
+ // This mount point could exist multiple times, so show oldest.
+ for (dlist_terminate(mt); mt; mt = mt->next) if (mt->stat.st_dev == dev) {
+ strout(mt->dir);
+ break;
+ }
+ llist_traverse(mt, free);
+ } else if (type == 'N') {
+ xprintf("`%s'", TT.file);
if (S_ISLNK(stat->st_mode))
- if (0<readlink(*toys.optargs, toybuf, sizeof(toybuf)))
+ if (readlink0(TT.file, toybuf, sizeof(toybuf)))
xprintf(" -> `%s'", toybuf);
} else if (type == 'o') out('u', stat->st_blksize);
else if (type == 's') out('u', stat->st_size);
+ else if (type == 't') out('x', dev_major(stat->st_rdev));
+ else if (type == 'T') out('x', dev_minor(stat->st_rdev));
else if (type == 'u') out('u', stat->st_uid);
- else if (type == 'U') xprintf("%8s", TT.user_name->pw_name);
+ else if (type == 'U') strout(getusername(stat->st_uid));
else if (type == 'x') date_stat_format((void *)&stat->st_atime);
else if (type == 'X') out('u', stat->st_atime);
else if (type == 'y') date_stat_format((void *)&stat->st_mtime);
@@ -137,50 +161,56 @@ static void print_statfs(char type) {
for (i=0; i<ARRAY_LEN(nn); i++)
if (nn[i].num == statfs->f_type) s = nn[i].name;
- fputs(s, stdout);
- } else if (type == 'i')
- xprintf("%08x%08x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]);
- else if (type == 's') out('d', statfs->f_frsize);
+ strout(s);
+ } else if (type == 'i') {
+ char buf[32];
+
+ sprintf(buf, "%08x%08x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]);
+ strout(buf);
+ } else if (type == 's') out('d', statfs->f_frsize);
else if (type == 'S') out('d', statfs->f_bsize);
- else xprintf("?");
+ else strout("?");
}
void stat_main(void)
{
- int flagf = toys.optflags & FLAG_f;
- char *format = flagf
+ int flagf = toys.optflags & FLAG_f, i;
+ char *format, *f;
+
+ if (toys.optflags&FLAG_t) {
+ format = flagf ? "%n %i %l %t %s %S %b %f %a %c %d" :
+ "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
+ } else format = flagf
? " File: \"%n\"\n ID: %i Namelen: %l Type: %t\n"
"Block Size: %s Fundamental block size: %S\n"
"Blocks: Total: %b\tFree: %f\tAvailable: %a\n"
"Inodes: Total: %c\tFree: %d"
: " File: %N\n Size: %s\t Blocks: %b\t IO Blocks: %B\t%F\n"
"Device: %Dh/%dd\t Inode: %i\t Links: %h\n"
- "Access: (%a/%A)\tUid: (%u/%U)\tGid: (%g/%G)\n"
+ "Access: (%a/%A)\tUid: (%5u/%8U)\tGid: (%5g/%8G)\n"
"Access: %x\nModify: %y\nChange: %z";
char *terse_format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
if (toys.optflags & FLAG_c) format = TT.fmt;
if (toys.optflags & FLAG_t) format = terse_format;
- for (; *toys.optargs; toys.optargs++) {
- char *f;
-
- if (flagf && !statfs(*toys.optargs, (void *)&TT.stat));
- else if (!flagf && !lstat(*toys.optargs, (void *)&TT.stat)) {
- struct stat *stat = (struct stat*)&TT.stat;
+ for (i = 0; toys.optargs[i]; i++) {
+ int L = toys.optflags & FLAG_L;
- // check user and group name
- TT.user_name = getpwuid(stat->st_uid);
- TT.group_name = getgrgid(stat->st_gid);
- } else {
- perror_msg("'%s'", *toys.optargs);
+ TT.file = toys.optargs[i];
+ if (flagf && !statfs(TT.file, (void *)&TT.stat));
+ else if (flagf || (L ? stat : lstat)(TT.file, (void *)&TT.stat)) {
+ perror_msg("'%s'", TT.file);
continue;
}
for (f = format; *f; f++) {
if (*f != '%') putchar(*f);
else {
- if (*++f == 'n') xprintf("%s", *toys.optargs);
+ f = next_printf(f, &TT.pattern);
+ TT.patlen = f-TT.pattern;
+ if (TT.patlen>99) error_exit("bad %s", TT.pattern);
+ if (*f == 'n') strout(TT.file);
else if (flagf) print_statfs(*f);
else print_stat(*f);
}
diff --git a/toys/other/sysctl.c b/toys/other/sysctl.c
index a123110e..ad643c92 100644
--- a/toys/other/sysctl.c
+++ b/toys/other/sysctl.c
@@ -50,7 +50,7 @@ static void key_error(char *key)
static int write_key(char *path, char *key, char *value)
{
- int fd = open(path, O_WRONLY);;
+ int fd = open(path, O_WRONLY);
if (fd < 0) {
key_error(key);
diff --git a/toys/other/timeout.c b/toys/other/timeout.c
index 0e912f7c..e39dc7a3 100644
--- a/toys/other/timeout.c
+++ b/toys/other/timeout.c
@@ -39,7 +39,8 @@ GLOBALS(
static void handler(int i)
{
- fprintf(stderr, "timeout pid %d signal %d\n", TT.pid, TT.nextsig);
+ if (toys.optflags & FLAG_v)
+ fprintf(stderr, "timeout pid %d signal %d\n", TT.pid, TT.nextsig);
kill(TT.pid, TT.nextsig);
if (TT.k_timeout) {
diff --git a/toys/other/truncate.c b/toys/other/truncate.c
index bfe1f10c..6092d5a9 100644
--- a/toys/other/truncate.c
+++ b/toys/other/truncate.c
@@ -53,13 +53,13 @@ static void do_truncate(int fd, char *name)
void truncate_main(void)
{
- int cr = !(toys.optflags&1);
+ int cr = !(toys.optflags&FLAG_c);
if (-1 != (TT.type = stridx("+-<>/%", *TT.s))) TT.s++;
TT.size = atolx(TT.s);
// Create files with mask rwrwrw.
// Nonexistent files are only an error if we're supposed to create them.
- loopfiles_rw(toys.optargs, O_WRONLY|O_CLOEXEC|(cr ? O_CREAT : 0), 0666, cr,
- do_truncate);
+ loopfiles_rw(toys.optargs, O_WRONLY|O_CLOEXEC|(cr ? O_CREAT|WARN_ONLY : 0),
+ 0666, do_truncate);
}
diff --git a/toys/other/xxd.c b/toys/other/xxd.c
index 0250f8f8..99de2ee2 100644
--- a/toys/other/xxd.c
+++ b/toys/other/xxd.c
@@ -4,17 +4,14 @@
*
* No obvious standard, output looks like:
* 0000000: 4c69 6e75 7820 7665 7273 696f 6e20 332e Linux version 3.
- *
- * TODO: support for reversing a hexdump back into the original data.
- * TODO: -s seek
-USE_XXD(NEWTOY(xxd, ">1c#<1>4096=16l#g#<1=2pr", TOYFLAG_USR|TOYFLAG_BIN))
+USE_XXD(NEWTOY(xxd, ">1c#<1>4096=16l#g#<1=2prs#[!rs]", TOYFLAG_USR|TOYFLAG_BIN))
config XXD
bool "xxd"
default y
help
- usage: xxd [-c n] [-g n] [-l n] [-p] [-r] [file]
+ usage: xxd [-c n] [-g n] [-l n] [-p] [-r] [-s n] [file]
Hexdump a file to stdout. If no file is listed, copy from stdin.
Filename "-" is a synonym for stdin.
@@ -24,12 +21,14 @@ config XXD
-l n Limit of n bytes before stopping (default is no limit).
-p Plain hexdump (30 bytes/line, no grouping).
-r Reverse operation: turn a hexdump into a binary file.
+ -s n Skip to offset n.
*/
#define FOR_xxd
#include "toys.h"
GLOBALS(
+ long s;
long g;
long l;
long c;
@@ -38,9 +37,17 @@ GLOBALS(
static void do_xxd(int fd, char *name)
{
long long pos = 0;
+ long long limit = TT.l;
int i, len, space;
- while (0<(len = readall(fd, toybuf, (TT.l && TT.l-pos<TT.c)?TT.l-pos:TT.c))) {
+ if (toys.optflags&FLAG_s) {
+ xlseek(fd, TT.s, SEEK_SET);
+ pos = TT.s;
+ if (limit) limit += TT.s;
+ }
+
+ while (0<(len = readall(fd, toybuf,
+ (limit && limit-pos<TT.c)?limit-pos:TT.c))) {
if (!(toys.optflags&FLAG_p)) printf("%08llx: ", pos);
pos += len;
space = 2*TT.c+TT.c/TT.g+1;
diff --git a/toys/pending/arp.c b/toys/pending/arp.c
index e725112b..6b57c3ca 100644
--- a/toys/pending/arp.c
+++ b/toys/pending/arp.c
@@ -245,7 +245,7 @@ void arp_main(void)
if ((toys.optflags & FLAG_d) && !delete_entry()) return;
//show arp chache
- fd = xopen("/proc/net/arp", O_RDONLY);
+ fd = xopenro("/proc/net/arp");
buf = get_line(fd);
free(buf); //skip first line
diff --git a/toys/pending/chrt.c b/toys/pending/chrt.c
new file mode 100644
index 00000000..0c25f484
--- /dev/null
+++ b/toys/pending/chrt.c
@@ -0,0 +1,92 @@
+/* chrt.c - Get/set real-time (scheduling) attributes
+ *
+ * Copyright 2016 The Android Open Source Project
+
+USE_CHRT(NEWTOY(chrt, "mp#bfiorR[!bfior]", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config CHRT
+ bool "chrt"
+ default y
+ help
+ usage: chrt [-m] [-p PID] [POLICY PRIO] [COMMAND [ARGS...]]
+
+ Get/set a process' real-time (scheduling) attributes.
+
+ -p Apply to given pid
+ -R Set SCHED_RESET_ON_FORK
+ -m Show min/max priorities available
+
+ Policies:
+ -b SCHED_BATCH -f SCHED_FIFO -i SCHED_IDLE
+ -o SCHED_OTHER -r SCHED_RR
+*/
+
+#define FOR_chrt
+#include "toys.h"
+
+#include <linux/sched.h>
+
+GLOBALS(
+ long pid;
+)
+
+static char *policy_name(int policy) {
+ char *policy_names[] = { "SCHED_OTHER", "SCHED_FIFO", "SCHED_RR",
+ "SCHED_BATCH", "4", "SCHED_IDLE", "SCHED_DEADLINE" };
+
+ return policy < ARRAY_LEN(policy_names) ? policy_names[policy] : "???";
+}
+
+void chrt_main(void)
+{
+ int policy = SCHED_RR;
+ struct sched_param p;
+
+ // Show min/maxes?
+ if (toys.optflags&FLAG_m) {
+ for (policy = SCHED_OTHER; policy <= SCHED_IDLE; ++policy)
+ if (policy != 4) // There's an unused hole in the priorities.
+ printf("%s min/max priority\t: %d/%d\n", policy_name(policy),
+ sched_get_priority_min(policy), sched_get_priority_max(policy));
+ return;
+ }
+
+ // If we have a pid but no command or policy, we're just querying.
+ if (TT.pid && !*(toys.optargs+1) &&
+ !(toys.optflags&(FLAG_b|FLAG_f|FLAG_i|FLAG_o|FLAG_r))) {
+ policy = sched_getscheduler(TT.pid);
+ if (policy == -1) perror_exit("sched_getscheduler");
+ policy &= ~SCHED_RESET_ON_FORK;
+ printf("pid %ld's current scheduling policy: %s\n",
+ TT.pid, policy_name(policy));
+
+ if (sched_getparam(TT.pid, &p)) perror_exit("sched_getparam");
+ printf("pid %ld's current scheduling priority: %d\n",
+ TT.pid, p.sched_priority);
+
+ return;
+ }
+
+ // Did we get a meaningful combination of arguments?
+ if (!*toys.optargs) help_exit("missing priority");
+ if (TT.pid && *(toys.optargs+1)) help_exit("-p and command");
+ if (!TT.pid && !*(toys.optargs+1)) help_exit("missing command");
+
+ // Translate into policy and priority.
+ if (toys.optflags&FLAG_b) policy = SCHED_BATCH;
+ else if (toys.optflags&FLAG_f) policy = SCHED_FIFO;
+ else if (toys.optflags&FLAG_i) policy = SCHED_IDLE;
+ else if (toys.optflags&FLAG_o) policy = SCHED_OTHER;
+
+ if (toys.optflags&FLAG_R) policy |= SCHED_RESET_ON_FORK;
+
+ p.sched_priority = atolx_range(*toys.optargs, sched_get_priority_min(policy),
+ sched_get_priority_max(policy));
+
+ if (sched_setscheduler(TT.pid, policy, &p)) perror_exit("sched_setscheduler");
+
+ if (*(toys.optargs+1)) {
+ toys.stacktop = 0;
+ xexec(++toys.optargs);
+ }
+}
diff --git a/toys/pending/crond.c b/toys/pending/crond.c
index 1b5e4194..df8b5f11 100644
--- a/toys/pending/crond.c
+++ b/toys/pending/crond.c
@@ -79,10 +79,11 @@ static void loginfo(uint8_t loglevel, char *msg, ...)
if (!TT.flagd && TT.logfile) {
int fd = open(TT.logfile, O_WRONLY | O_CREAT | O_APPEND, 0666);
- if (fd >=0 && fd != 2) {
+ if (fd==-1) perror_msg("'%s", TT.logfile);
+ else {
dup2(fd, 2);
close(fd);
- } else if (fd < 0) perror_msg("'%s", TT.logfile);
+ }
}
used = vsnprintf(NULL, 0, msg, d);
smsg = xzalloc(++used);
diff --git a/toys/pending/crontab.c b/toys/pending/crontab.c
index 80a881d7..0b1c47db 100644
--- a/toys/pending/crontab.c
+++ b/toys/pending/crontab.c
@@ -114,7 +114,7 @@ static int validate_component(int min, int max, char *src)
static int parse_crontab(char *fname)
{
char *line;
- int lno, fd = xopen(fname, O_RDONLY);
+ int lno, fd = xopenro(fname);
long plen = 0;
for (lno = 1; (line = get_rawline(fd, &plen, '\n')); lno++,free(line)) {
@@ -214,8 +214,7 @@ static void do_list(char *name)
int fdin;
snprintf(toybuf, sizeof(toybuf), "%s%s", TT.cdir, name);
- if ((fdin = open(toybuf, O_RDONLY)) == -1)
- error_exit("No crontab for '%s'", name);
+ fdin = xopenro(toybuf);
xsendfile(fdin, 1);
xclose(fdin);
}
@@ -233,7 +232,7 @@ static void update_crontab(char *src, char *dest)
snprintf(toybuf, sizeof(toybuf), "%s%s", TT.cdir, dest);
fdout = xcreate(toybuf, O_WRONLY|O_CREAT|O_TRUNC, 0600);
- fdin = xopen(src, O_RDONLY);
+ fdin = xopenro(src);
xsendfile(fdin, fdout);
xclose(fdin);
@@ -277,7 +276,7 @@ static void do_edit(struct passwd *pwd)
if (!stat(toybuf, &sb)) { // file exists and have some content.
if (sb.st_size) {
- srcfd = xopen(toybuf, O_RDONLY);
+ srcfd = xopenro(toybuf);
xsendfile(srcfd, destfd);
xclose(srcfd);
}
diff --git a/toys/pending/dd.c b/toys/pending/dd.c
index 24d95657..0bb48494 100644
--- a/toys/pending/dd.c
+++ b/toys/pending/dd.c
@@ -4,14 +4,17 @@
* Copyright 2013 Kyungwan Han <asura321@gmail.com>
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/dd.html
+ *
+ * todo: ctrl-c doesn't work, the read() is restarting.
+
USE_DD(NEWTOY(dd, NULL, TOYFLAG_USR|TOYFLAG_BIN))
config DD
bool "dd"
default n
- help
+ help
usage: dd [if=FILE] [of=FILE] [ibs=N] [obs=N] [bs=N] [count=N] [skip=N]
- [seek=N] [conv=notrunc|noerror|sync|fsync]
+ [seek=N] [conv=notrunc|noerror|sync|fsync] [status=noxfer|none]
Options:
if=FILE Read from FILE instead of stdin
@@ -26,44 +29,35 @@ config DD
conv=noerror Continue after read errors
conv=sync Pad blocks with zeros
conv=fsync Physically write data out before finishing
+ status=noxfer Don't show transfer rate
+ status=none Don't show transfer rate or records in/out
- Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),
- MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)
- Copy a file, converting and formatting according to the operands.
+ Numbers may be suffixed by c (*1), w (*2), b (*512), kD (*1000), k (*1024),
+ MD (*1000*1000), M (*1024*1024), GD (*1000*1000*1000) or G (*1024*1024*1024).
*/
+
#define FOR_dd
#include "toys.h"
GLOBALS(
- int sig;
-)
-#define C_CONV 0x0000
-#define C_BS 0x0001
-#define C_COUNT 0x0002
-#define C_IBS 0x0004
-#define C_OBS 0x0008
-#define C_IF 0x0010
-#define C_OF 0x0020
-#define C_SEEK 0x0040
-#define C_SKIP 0x0080
+ int show_xfer;
+ int show_records;
+ unsigned long long bytes, c_count, in_full, in_part, out_full, out_part;
+ struct timeval start;
+ struct {
+ char *name;
+ int fd;
+ unsigned char *buff, *bp;
+ long sz, count;
+ unsigned long long offset;
+ } in, out;
+);
+
#define C_SYNC 0x0100
#define C_FSYNC 0x0200
#define C_NOERROR 0x0400
#define C_NOTRUNC 0x0800
-struct io {
- char *name;
- int fd;
- unsigned char *buff, *bp;
- long sz, count;
- unsigned long long offset;
-};
-
-struct iostat {
- unsigned long long in_full, in_part, out_full, out_part, bytes;
- struct timeval start;
-};
-
struct pair {
char *name;
unsigned val;
@@ -83,266 +77,224 @@ static struct pair clist[] = {
{ "sync", C_SYNC },
};
-static struct pair operands[] = {
- // keep the array sorted by name, bsearch() can be used.
- { "bs", C_BS },
- { "conv", C_CONV },
- { "count", C_COUNT},
- { "ibs", C_IBS },
- { "if", C_IF },
- { "obs", C_OBS },
- { "of", C_OF },
- { "seek", C_SEEK },
- { "skip", C_SKIP },
-};
-
-static struct io in, out;
-static struct iostat st;
-static unsigned long long c_count;
-
-static unsigned long long strsuftoll(char* arg, int def, unsigned long long max)
+static unsigned long long strsuftoll(char *arg, int def, unsigned long long max)
{
unsigned long long result;
- char *endp, *ch = arg;
+ char *p = arg;
int i, idx = -1;
- errno = 0;
- while (isspace(*ch)) ch++;
- if (*ch == '-') error_exit("invalid number '%s'",arg);
- result = strtoull(arg, &endp, 10);
+ while (isspace(*p)) p++;
+ if (*p == '-') error_exit("invalid number '%s'", arg);
+
+ errno = 0;
+ result = strtoull(p, &p, 0);
if (errno == ERANGE || result > max || result < def)
- perror_exit("invalid number '%s'",arg);
- if (*endp != '\0') {
+ perror_exit("invalid number '%s'", arg);
+ if (*p != '\0') {
for (i = 0; i < ARRAY_LEN(suffixes); i++)
- if (!strcmp(endp, suffixes[i].name)) idx = i;
+ if (!strcmp(p, suffixes[i].name)) idx = i;
if (idx == -1 || (max/suffixes[idx].val < result))
- error_exit("invalid number '%s'",arg);
- result = result* suffixes[idx].val;
+ error_exit("invalid number '%s'", arg);
+ result *= suffixes[idx].val;
}
return result;
}
-static void summary()
+static void status()
{
- double seconds = 5.0;
+ double seconds;
struct timeval now;
gettimeofday(&now, NULL);
- seconds = ((now.tv_sec * 1000000 + now.tv_usec) - (st.start.tv_sec * 1000000
- + st.start.tv_usec))/1000000.0;
- //out to STDERR
- fprintf(stderr,"%llu+%llu records in\n%llu+%llu records out\n", st.in_full, st.in_part,
- st.out_full, st.out_part);
- human_readable(toybuf, st.bytes, HR_SPACE|HR_B);
- fprintf(stderr, "%llu bytes (%s) copied, ",st.bytes, toybuf);
- human_readable(toybuf, st.bytes/seconds, HR_SPACE|HR_B);
- fprintf(stderr, "%f s, %s/s\n", seconds, toybuf);
+ seconds = ((now.tv_sec * 1000000 + now.tv_usec) -
+ (TT.start.tv_sec * 1000000 + TT.start.tv_usec))/1000000.0;
+
+ if (TT.show_records)
+ fprintf(stderr, "%llu+%llu records in\n%llu+%llu records out\n",
+ TT.in_full, TT.in_part, TT.out_full, TT.out_part);
+
+ if (TT.show_xfer) {
+ human_readable(toybuf, TT.bytes, HR_SPACE|HR_B);
+ fprintf(stderr, "%llu bytes (%s) copied, ", TT.bytes, toybuf);
+ human_readable(toybuf, TT.bytes/seconds, HR_SPACE|HR_B);
+ fprintf(stderr, "%f s, %s/s\n", seconds, toybuf);
+ }
}
-static void sig_handler(int sig)
+static void write_out(int all)
{
- TT.sig = sig;
+ TT.out.bp = TT.out.buff;
+ while (TT.out.count) {
+ ssize_t nw = writeall(TT.out.fd, TT.out.bp, ((all)? TT.out.count : TT.out.sz));
+
+ all = 0; //further writes will be on obs
+ if (nw <= 0) perror_exit("%s: write error", TT.out.name);
+ if (nw == TT.out.sz) TT.out_full++;
+ else TT.out_part++;
+ TT.out.count -= nw;
+ TT.out.bp += nw;
+ TT.bytes += nw;
+ if (TT.out.count < TT.out.sz) break;
+ }
+ if (TT.out.count) memmove(TT.out.buff, TT.out.bp, TT.out.count); //move remainder to front
}
-static int xmove_fd(int fd)
+int strstarteq(char **a, char *b)
{
- int newfd;
+ char *aa = *a;
- if (fd > STDERR_FILENO) return fd;
- if ((newfd = fcntl(fd, F_DUPFD, 3) < 0)) perror_exit("dupfd IO");
- close(fd);
- return newfd;
+ if (!strstart(&aa, b)) return 0;
+ if (*aa != '=') return 0;
+ *a = ++aa;
+
+ return 1;
}
-static void setup_inout()
+static int comp(const void *a, const void *b) //const to shut compiler up
+{
+ return strcmp(((struct pair*)a)->name, ((struct pair*)b)->name);
+}
+
+void dd_main()
{
- ssize_t n;
+ struct pair *res, key;
+ char **args;
+ unsigned long long bs = 0;
+ int trunc = O_TRUNC;
+
+ TT.show_xfer = TT.show_records = 1;
+ TT.c_count = ULLONG_MAX;
+
+ TT.in.sz = TT.out.sz = 512; //default io block size
+ for (args = toys.optargs; *args; args++) {
+ char *arg = *args;
+
+ if (strstarteq(&arg, "bs")) bs = strsuftoll(arg, 1, LONG_MAX);
+ else if (strstarteq(&arg, "ibs")) TT.in.sz = strsuftoll(arg, 1, LONG_MAX);
+ else if (strstarteq(&arg, "obs")) TT.out.sz = strsuftoll(arg, 1, LONG_MAX);
+ else if (strstarteq(&arg, "count")) TT.c_count = strsuftoll(arg, 0, ULLONG_MAX-1);
+ else if (strstarteq(&arg, "if")) TT.in.name = arg;
+ else if (strstarteq(&arg, "of")) TT.out.name = arg;
+ else if (strstarteq(&arg, "seek"))
+ TT.out.offset = strsuftoll(arg, 0, ULLONG_MAX);
+ else if (strstarteq(&arg, "skip"))
+ TT.in.offset = strsuftoll(arg, 0, ULLONG_MAX);
+ else if (strstarteq(&arg, "status")) {
+ if (!strcmp(arg, "noxfer")) TT.show_xfer = 0;
+ else if (!strcmp(arg, "none")) TT.show_xfer = TT.show_records = 0;
+ else error_exit("unknown status '%s'", arg);
+ } else if (strstarteq(&arg, "conv")) {
+ while (arg) {
+ key.name = strsep(&arg, ",");
+ if (!(res = bsearch(&key, clist, ARRAY_LEN(clist),
+ sizeof(struct pair), comp)))
+ error_exit("unknown conversion %s", key.name);
+
+ toys.optflags |= res->val;
+ }
+ } else error_exit("bad arg %s", arg);
+ }
+ if (bs) TT.in.sz = TT.out.sz = bs;
+
+ signal(SIGINT, generic_signal);
+ signal(SIGUSR1, generic_signal);
+ gettimeofday(&TT.start, NULL);
- /* for C_BS, in/out is done as it is. so only in.sz is enough.
+ /* for bs=, in/out is done as it is. so only in.sz is enough.
* With Single buffer there will be overflow in a read following partial read
*/
- in.buff = out.buff = xmalloc(in.sz + ((toys.optflags & C_BS)? 0: out.sz));
- in.bp = out.bp = in.buff;
- atexit(summary);
+ TT.in.buff = TT.out.buff = xmalloc(TT.in.sz + (bs ? 0 : TT.out.sz));
+ TT.in.bp = TT.out.bp = TT.in.buff;
//setup input
- if (!in.name) {
- in.name = "stdin";
- in.fd = STDIN_FILENO;
- } else {
- in.fd = xopen(in.name, O_RDONLY);
- in.fd = xmove_fd(in.fd);
- }
- //setup outout
- if (!out.name) {
- out.name = "stdout";
- out.fd = STDOUT_FILENO;
- } else {
- out.fd = xcreate(out.name, O_WRONLY | O_CREAT, 0666);
- out.fd = xmove_fd(out.fd);
- }
-
- if (in.offset) {
- if (lseek(in.fd, (off_t)(in.offset * in.sz), SEEK_CUR) < 0) {
- while (in.offset--) {
- if ((n = read(in.fd, in.bp, in.sz)) < 0) {
- if (toys.optflags & C_NOERROR) { //warn message and summary
- error_msg("%s: read error", in.name);
- summary();
- } else perror_exit("%s: read error", in.name);
+ if (!TT.in.name) TT.in.name = "stdin";
+ else TT.in.fd = xopenro(TT.in.name);
+
+ if (toys.optflags&C_NOTRUNC) trunc = 0;
+
+ //setup output
+ if (!TT.out.name) {
+ TT.out.name = "stdout";
+ TT.out.fd = 1;
+ } else TT.out.fd = xcreate(TT.out.name,
+ O_WRONLY|O_CREAT|(trunc*!TT.out.offset), 0666);
+
+ // Implement skip=
+ if (TT.in.offset) {
+ if (lseek(TT.in.fd, (off_t)(TT.in.offset * TT.in.sz), SEEK_CUR) < 0) {
+ while (TT.in.offset--) {
+ ssize_t n = read(TT.in.fd, TT.in.bp, TT.in.sz);
+
+ if (n < 0) {
+ perror_msg("%s", TT.in.name);
+ if (toys.optflags & C_NOERROR) status();
+ else return;
} else if (!n) {
- xprintf("%s: Can't skip\n", in.name);
- exit(0);
+ xprintf("%s: Can't skip\n", TT.in.name);
+ return;
}
}
}
}
- if (out.offset) xlseek(out.fd, (off_t)(out.offset * out.sz), SEEK_CUR);
-}
-
-static void write_out(int all)
-{
- ssize_t nw;
- out.bp = out.buff;
- while (out.count) {
- nw = writeall(out.fd, out.bp, ((all)? out.count : out.sz));
- all = 0; //further writes will be on obs
- if (nw <= 0) perror_exit("%s: write error",out.name);
- if (nw == out.sz) st.out_full++;
- else st.out_part++;
- out.count -= nw;
- out.bp += nw;
- st.bytes += nw;
- if (out.count < out.sz) break;
+ // seek/truncate as necessary. We handled position zero truncate with
+ // O_TRUNC on open, so output to /dev/null and such doesn't error.
+ if (TT.out.fd!=1 && (bs = TT.out.offset*TT.out.sz)) {
+ xlseek(TT.out.fd, bs, SEEK_CUR);
+ if (trunc && ftruncate(TT.out.fd, bs)) perror_exit("ftruncate");
}
- if (out.count) memmove(out.buff, out.bp, out.count); //move remainder to front
-}
-static void do_dd(void)
-{
- ssize_t n;
- struct sigaction sa;
-
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = sig_handler;
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGUSR1, &sa, NULL);
- setup_inout();
- gettimeofday(&st.start, NULL);
-
- if (toys.optflags & (C_OF | C_SEEK) && !(toys.optflags & C_NOTRUNC))
- ftruncate(out.fd, (off_t)out.offset * out.sz);
-
- while (!(toys.optflags & C_COUNT) || (st.in_full + st.in_part) < c_count) {
- if (TT.sig == SIGUSR1) {
- summary();
- TT.sig = 0;
- } else if (TT.sig == SIGINT) exit(TT.sig | 128);
- in.bp = in.buff + in.count;
- if (toys.optflags & C_SYNC) memset(in.bp, 0, in.sz);
- if (!(n = read(in.fd, in.bp, in.sz))) break;
+ while (TT.c_count==ULLONG_MAX || (TT.in_full + TT.in_part) < TT.c_count) {
+ ssize_t n;
+
+ // Show progress and exit on SIGINT or just continue on SIGUSR1.
+ if (toys.signal) {
+ status();
+ if (toys.signal==SIGINT) exit_signal(toys.signal);
+ toys.signal = 0;
+ }
+
+ TT.in.bp = TT.in.buff + TT.in.count;
+ if (toys.optflags & C_SYNC) memset(TT.in.bp, 0, TT.in.sz);
+ if (!(n = read(TT.in.fd, TT.in.bp, TT.in.sz))) break;
if (n < 0) {
if (errno == EINTR) continue;
//read error case.
- perror_msg("%s: read error", in.name);
+ perror_msg("%s: read error", TT.in.name);
if (!(toys.optflags & C_NOERROR)) exit(1);
- summary();
- xlseek(in.fd, in.sz, SEEK_CUR);
+ status();
+ xlseek(TT.in.fd, TT.in.sz, SEEK_CUR);
if (!(toys.optflags & C_SYNC)) continue;
// if SYNC, then treat as full block of nuls
- n = in.sz;
+ n = TT.in.sz;
}
- if (n == in.sz) {
- st.in_full++;
- in.count += n;
+ if (n == TT.in.sz) {
+ TT.in_full++;
+ TT.in.count += n;
} else {
- st.in_part++;
- if (toys.optflags & C_SYNC) in.count += in.sz;
- else in.count += n;
+ TT.in_part++;
+ if (toys.optflags & C_SYNC) TT.in.count += TT.in.sz;
+ else TT.in.count += n;
}
- out.count = in.count;
- if (toys.optflags & C_BS) {
+ TT.out.count = TT.in.count;
+ if (bs) {
write_out(1);
- in.count = 0;
+ TT.in.count = 0;
continue;
}
- if (in.count >= out.sz) {
+ if (TT.in.count >= TT.out.sz) {
write_out(0);
- in.count = out.count;
+ TT.in.count = TT.out.count;
}
}
- if (out.count) write_out(1); //write any remaining input blocks
- if (toys.optflags & C_FSYNC && fsync(out.fd) < 0)
- perror_exit("%s: fsync fail", out.name);
-
- close(in.fd);
- close(out.fd);
- if (in.buff) free(in.buff);
-}
-
-static int comp(const void *a, const void *b) //const to shut compiler up
-{
- return strcmp(((struct pair*)a)->name, ((struct pair*)b)->name);
-}
+ if (TT.out.count) write_out(1); //write any remaining input blocks
+ if (toys.optflags & C_FSYNC && fsync(TT.out.fd) < 0)
+ perror_exit("%s: fsync fail", TT.out.name);
-void dd_main()
-{
- struct pair *res, key;
- char *arg;
- long sz;
-
- in.sz = out.sz = 512; //default io block size
- while (*toys.optargs) {
- if (!(arg = strchr(*toys.optargs, '='))) error_exit("unknown arg %s", *toys.optargs);
- *arg++ = '\0';
- if (!*arg) help_exit(0);
- key.name = *toys.optargs;
- if (!(res = bsearch(&key, operands, ARRAY_LEN(operands), sizeof(struct pair),
- comp))) error_exit("unknown arg %s", key.name);
-
- toys.optflags |= res->val;
- switch(res->val) {
- case C_BS:
- in.sz = out.sz = strsuftoll(arg, 1, LONG_MAX);
- break;
- case C_IBS:
- sz = strsuftoll(arg, 1, LONG_MAX);
- if (!(toys.optflags & C_BS)) in.sz = sz;
- break;
- case C_OBS:
- sz = strsuftoll(arg, 1, LONG_MAX);
- if (!(toys.optflags & C_BS)) out.sz = sz;
- break;
- case C_COUNT:
- c_count = strsuftoll(arg, 0, ULLONG_MAX);
- break;
- case C_IF:
- in.name = arg;
- break;
- case C_OF:
- out.name = arg;
- break;
- case C_SEEK:
- out.offset = strsuftoll(arg, 0, ULLONG_MAX);
- break;
- case C_SKIP:
- in.offset = strsuftoll(arg, 0, ULLONG_MAX);
- break;
- case C_CONV:
- while (arg) {
- key.name = strsep(&arg, ",");
- if (!(res = bsearch(&key, clist, ARRAY_LEN(clist),
- sizeof(struct pair), comp)))
- error_exit("unknown conversion %s", key.name);
-
- toys.optflags |= res->val;
- }
- break;
- }
- toys.optargs++;
- }
+ close(TT.in.fd);
+ close(TT.out.fd);
+ if (TT.in.buff) free(TT.in.buff);
- do_dd();
+ status();
}
diff --git a/toys/pending/dhcp.c b/toys/pending/dhcp.c
index cb9d15a1..b99bb4c0 100644
--- a/toys/pending/dhcp.c
+++ b/toys/pending/dhcp.c
@@ -566,7 +566,9 @@ static void run_script(dhcpc_result_t *res, char *name)
static uint32_t getxid(void)
{
uint32_t randnum;
- int fd = xopen("/dev/urandom", O_RDONLY);
+ int fd = xopenro("/dev/urandom");
+
+// TODO xreadfile
xreadall(fd, &randnum, sizeof(randnum));
xclose(fd);
return randnum;
diff --git a/toys/pending/dumpleases.c b/toys/pending/dumpleases.c
index 86cb4e76..ef17aab4 100644
--- a/toys/pending/dumpleases.c
+++ b/toys/pending/dumpleases.c
@@ -42,7 +42,7 @@ void dumpleases_main(void)
int i, fd;
if(!(toys.optflags & FLAG_f)) TT.file = "/var/lib/misc/dhcpd.leases"; //DEF_LEASE_FILE
- fd = xopen(TT.file, O_RDONLY);
+ fd = xopenro(TT.file);
xprintf("Mac Address IP Address Host Name Expires %s\n", (toys.optflags & FLAG_a) ? "at" : "in");
xread(fd, &written_time, sizeof(written_time));
current_time = time(NULL);
diff --git a/toys/pending/getfattr.c b/toys/pending/getfattr.c
new file mode 100644
index 00000000..efec53a8
--- /dev/null
+++ b/toys/pending/getfattr.c
@@ -0,0 +1,95 @@
+/* getfattr.c - Read POSIX extended attributes.
+ *
+ * Copyright 2016 Android Open Source Project.
+ *
+ * No standard
+
+USE_GETFATTR(NEWTOY(getfattr, "dhn:", TOYFLAG_USR|TOYFLAG_BIN))
+
+config GETFATTR
+ bool "getfattr"
+ default y
+ help
+ usage: getfattr [-d] [-h] [-n NAME] FILE...
+
+ Read POSIX extended attributes.
+
+ -d Show values as well as names.
+ -h Do not dereference symbolic links.
+ -n Show only attributes with the given name.
+*/
+
+#define FOR_getfattr
+#include "toys.h"
+
+GLOBALS(
+ char *n;
+)
+
+// TODO: factor out the lister and getter loops and use them in cp too.
+static void do_getfattr(char *file)
+{
+ ssize_t (*getter)(const char *, const char *, void *, size_t) = getxattr;
+ ssize_t (*lister)(const char *, char *, size_t) = listxattr;
+ char **sorted_keys;
+ ssize_t keys_len;
+ char *keys, *key;
+ int i, key_count;
+
+ if (toys.optflags&FLAG_h) {
+ getter = lgetxattr;
+ lister = llistxattr;
+ }
+
+ // Collect the keys.
+ while ((keys_len = lister(file, NULL, 0))) {
+ if (keys_len == -1) perror_msg("listxattr failed");
+ keys = xmalloc(keys_len);
+ if (lister(file, keys, keys_len) == keys_len) break;
+ free(keys);
+ }
+
+ if (keys_len == 0) return;
+
+ // Sort the keys.
+ for (key = keys, key_count = 0; key-keys < keys_len; key += strlen(key)+1)
+ key_count++;
+ sorted_keys = xmalloc(key_count * sizeof(char *));
+ for (key = keys, i = 0; key-keys < keys_len; key += strlen(key)+1)
+ sorted_keys[i++] = key;
+ qsort(sorted_keys, key_count, sizeof(char *), qstrcmp);
+
+ printf("# file: %s\n", file);
+
+ for (i = 0; i < key_count; i++) {
+ key = sorted_keys[i];
+
+ if (TT.n && strcmp(TT.n, key)) continue;
+
+ if (toys.optflags&FLAG_d) {
+ ssize_t value_len;
+ char *value = NULL;
+
+ while ((value_len = getter(file, key, NULL, 0))) {
+ if (value_len == -1) perror_msg("getxattr failed");
+ value = xzalloc(value_len+1);
+ if (getter(file, key, value, value_len) == value_len) break;
+ free(value);
+ }
+
+ if (!value) puts(key);
+ else printf("%s=\"%s\"\n", key, value);
+ free(value);
+ } else puts(key); // Just list names.
+ }
+
+ xputc('\n');
+ free(sorted_keys);
+}
+
+void getfattr_main(void)
+{
+ char **s;
+
+ for (s=toys.optargs; *s; s++) do_getfattr(*s);
+}
diff --git a/toys/pending/getty.c b/toys/pending/getty.c
index c7376288..25d04eaa 100644
--- a/toys/pending/getty.c
+++ b/toys/pending/getty.c
@@ -128,7 +128,7 @@ static void open_tty(void)
if ((setsid() < 0) && (getpid() != getsid(0)))
perror_exit("setsid");
xclose(0);
- xopen(TT.tty_name, O_RDWR|O_NDELAY|O_CLOEXEC);
+ xopen_stdio(TT.tty_name, O_RDWR|O_NDELAY|O_CLOEXEC);
fcntl(0, F_SETFL, fcntl(0, F_GETFL) & ~O_NONBLOCK); // Block read
dup2(0, 1);
dup2(0, 2);
diff --git a/toys/pending/klogd.c b/toys/pending/klogd.c
index 2c842889..d950981d 100644
--- a/toys/pending/klogd.c
+++ b/toys/pending/klogd.c
@@ -74,7 +74,7 @@ void klogd_main(void)
syslog(LOG_NOTICE, "KLOGD: started with Kernel ring buffer as log source\n");
klogctl(1, NULL, 0);
} else {
- TT.fd = xopen("/proc/kmsg", O_RDONLY); //_PATH_KLOG in paths.h
+ TT.fd = xopenro("/proc/kmsg"); //_PATH_KLOG in paths.h
syslog(LOG_NOTICE, "KLOGD: started with /proc/kmsg as log source\n");
}
openlog("Kernel", 0, LOG_KERN); //open connection to system logger..
diff --git a/toys/pending/last.c b/toys/pending/last.c
index b207afef..4b7b472e 100644
--- a/toys/pending/last.c
+++ b/toys/pending/last.c
@@ -96,7 +96,7 @@ void last_main(void)
pwidth = (toys.optflags & FLAG_W) ? 46 : 16;
*tm = time(tm+1);
- fd = xopen(file, O_RDONLY);
+ fd = xopenro(file);
loc = xlseek(fd, 0, SEEK_END);
// Loop through file structures in reverse order.
diff --git a/toys/pending/lsof.c b/toys/pending/lsof.c
index e99b011a..436fdd2a 100644
--- a/toys/pending/lsof.c
+++ b/toys/pending/lsof.c
@@ -277,8 +277,8 @@ static void fill_stat(struct file_info *fi, const char *path)
// Fill DEVICE.
dev = (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) ? sb.st_rdev : sb.st_dev;
if (!S_ISSOCK(sb.st_mode))
- snprintf(fi->device, sizeof(fi->device), "%ld,%ld",
- (long)major(dev), (long)minor(dev));
+ snprintf(fi->device, sizeof(fi->device), "%d,%d",
+ dev_major(dev), dev_minor(dev));
// Fill SIZE/OFF.
if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
diff --git a/toys/pending/mdev.c b/toys/pending/mdev.c
index 975d31da..2688cf35 100644
--- a/toys/pending/mdev.c
+++ b/toys/pending/mdev.c
@@ -40,8 +40,8 @@ static void make_device(char *path)
gid_t gid = 0;
if (path) {
- // Try to read major/minor string
+ // Try to read major/minor string, returning if we can't
temp = strrchr(path, '/');
fd = open(path, O_RDONLY);
*temp = 0;
diff --git a/toys/pending/modprobe.c b/toys/pending/modprobe.c
index 7a35c186..ebf17a0e 100644
--- a/toys/pending/modprobe.c
+++ b/toys/pending/modprobe.c
@@ -367,7 +367,9 @@ static int ins_mod(char *modules, char *flags)
{
char *buf = NULL;
int len, res;
- int fd = xopen(modules, O_RDONLY);
+ int fd = xopenro(modules);
+
+ // TODO xreadfile()
len = fdlength(fd);
buf = xmalloc(len);
diff --git a/toys/pending/netstat.c b/toys/pending/netstat.c
deleted file mode 100644
index 9803ca06..00000000
--- a/toys/pending/netstat.c
+++ /dev/null
@@ -1,664 +0,0 @@
-/* netstat.c - Display Linux networking subsystem.
- *
- * Copyright 2012 Ranjan Kumar <ranjankumar.bth@gmail.com>
- * Copyright 2013 Kyungwan Han <asura321@gmail.com>
- *
- * Not in SUSv4.
- *
-USE_NETSTAT(NEWTOY(netstat, "pWrxwutneal", TOYFLAG_BIN))
-config NETSTAT
- bool "netstat"
- default n
- help
- usage: netstat [-pWrxwutneal]
-
- Display networking information.
-
- -r Display routing table.
- -a Display all sockets (Default: Connected).
- -l Display listening server sockets.
- -t Display TCP sockets.
- -u Display UDP sockets.
- -w Display Raw sockets.
- -x Display Unix sockets.
- -e Display other/more information.
- -n Don't resolve names.
- -W Wide Display.
- -p Display PID/Program name for sockets.
-*/
-
-#define FOR_netstat
-#include "toys.h"
-
-#include <net/route.h>
-
-GLOBALS(
- char current_name[21];
- int some_process_unidentified;
-);
-
-typedef union _iaddr {
- unsigned u;
- unsigned char b[4];
-} iaddr;
-
-typedef union _iaddr6 {
- struct {
- unsigned a;
- unsigned b;
- unsigned c;
- unsigned d;
- } u;
- unsigned char b[16];
-} iaddr6;
-
-#define ADDR_LEN (INET6_ADDRSTRLEN + 1 + 5 + 1)//IPv6 addr len + : + port + '\0'
-
-//For unix states
-enum {
- SOCK_ACCEPTCON = (1 << 16), //performed a listen.
- SOCK_WAIT_DATA = (1 << 17), //wait data to read.
- SOCK_NO_SPACE = (1 << 18), //no space to write.
-};
-
-#define SOCK_NOT_CONNECTED 1
-
-typedef struct _pidlist {
- struct _pidlist *next;
- long inode;
- char name[21];
-} PID_LIST;
-
-PID_LIST *pid_list = NULL;
-
-/*
- * used to convert string into int and
- * validate the input str for invalid int value or out-of-range.
- */
-static unsigned long get_strtou(char *str, char **endp, int base)
-{
- unsigned long uli;
- char *endptr;
-
- if (!isalnum(str[0])) {
- errno = ERANGE;
- return UINT_MAX;
- }
- errno = 0;
- uli = strtoul(str, &endptr, base);
- if (uli > UINT_MAX) {
- errno = ERANGE;
- return UINT_MAX;
- }
-
- if (endp) *endp = endptr;
- if (endptr[0]) {
- if (isalnum(endptr[0]) || errno) { //"123abc" or out-of-range
- errno = ERANGE;
- return UINT_MAX;
- }
- errno = EINVAL;
- }
- return uli;
-}
-
-/*
- * used to retrive pid name from pid list.
- */
-static const char *get_pid_name(unsigned long inode)
-{
- PID_LIST *tmp;
-
- for (tmp = pid_list; tmp; tmp = tmp->next)
- if (tmp->inode == inode) return tmp->name;
-
- return "-";
-}
-
-/*
- * For TCP/UDP/RAW display data.
- */
-static void display_data(unsigned rport, char *label,
- unsigned rxq, unsigned txq, char *lip, char *rip,
- unsigned state, unsigned uid, unsigned long inode)
-{
- char *ss_state = "UNKNOWN", buf[12];
- char *state_label[] = {"", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1",
- "FIN_WAIT2", "TIME_WAIT", "CLOSE", "CLOSE_WAIT",
- "LAST_ACK", "LISTEN", "CLOSING", "UNKNOWN"};
- char user[11];
- struct passwd *pw;
-
- if (!strcmp(label, "tcp")) {
- int sz = ARRAY_LEN(state_label);
- if (!state || state >= sz) state = sz-1;
- ss_state = state_label[state];
- }
- else if (!strcmp(label, "udp")) {
- if (state == 1) ss_state = state_label[state];
- else if (state == 7) ss_state = "";
- }
- else if (!strcmp(label, "raw")) sprintf(ss_state = buf, "%u", state);
-
- if (!(toys.optflags & FLAG_n) && (pw = getpwuid(uid))) {
- snprintf(user, sizeof(user), "%s", pw->pw_name);
- } else snprintf(user, sizeof(user), "%d", uid);
-
- xprintf("%3s %6d %6d ", label, rxq, txq);
- xprintf((toys.optflags & FLAG_W) ? "%-51.51s %-51.51s " : "%-23.23s %-23.23s "
- , lip, rip);
- xprintf("%-11s ", ss_state);
- if ((toys.optflags & FLAG_e)) xprintf("%-10s %-11ld ", user, inode);
- if ((toys.optflags & FLAG_p)) xprintf("%s", get_pid_name(inode));
- xputc('\n');
-}
-
-/*
- * For TCP/UDP/RAW show data.
- */
-static void show_data(unsigned rport, char *label, unsigned rxq, unsigned txq,
- char *lip, char *rip, unsigned state, unsigned uid,
- unsigned long inode)
-{
- if (toys.optflags & FLAG_l) {
- if (!rport && (state & 0xA))
- display_data(rport, label, rxq, txq, lip, rip, state, uid, inode);
- } else if (toys.optflags & FLAG_a)
- display_data(rport, label, rxq, txq, lip, rip, state, uid, inode);
- //rport && (TCP | UDP | RAW)
- else if (rport & (0x10 | 0x20 | 0x40))
- display_data(rport, label, rxq, txq, lip, rip, state, uid, inode);
-}
-
-/*
- * used to get service name.
- */
-static char *get_servname(int port, char *label)
-{
- int lport = htons(port);
- if (!lport) return xmprintf("%s", "*");
- struct servent *ser = getservbyport(lport, label);
- if (ser) return xmprintf("%s", ser->s_name);
- return xmprintf("%u", (unsigned)ntohs(lport));
-}
-
-/*
- * used to convert address into text format.
- */
-static void addr2str(int af, void *addr, unsigned port, char *buf, char *label)
-{
- char ip[ADDR_LEN] = {0,};
- if (!inet_ntop(af, addr, ip, ADDR_LEN)) {
- *buf = '\0';
- return;
- }
- size_t iplen = strlen(ip);
- if (!port) {
- strncat(ip+iplen, ":*", ADDR_LEN-iplen-1);
- memcpy(buf, ip, ADDR_LEN);
- return;
- }
-
- if (!(toys.optflags & FLAG_n)) {
- struct addrinfo hints, *result, *rp;
-
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_family = af;
-
- if (!getaddrinfo(ip, NULL, &hints, &result)) {
- char hbuf[NI_MAXHOST] = {0,}, sbuf[NI_MAXSERV] = {0,};
- socklen_t sock_len;
- char *sname = NULL;
- int plen = 0;
-
- if (af == AF_INET) sock_len = sizeof(struct sockaddr_in);
- else sock_len = sizeof(struct sockaddr_in6);
-
- for (rp = result; rp; rp = rp->ai_next)
- if (!getnameinfo(rp->ai_addr, sock_len, hbuf, sizeof(hbuf), sbuf,
- sizeof(sbuf), NI_NUMERICSERV))
- break;
-
- freeaddrinfo(result);
- sname = get_servname(port, label);
- plen = strlen(sname);
- if (*hbuf) {
- memset(ip, 0, ADDR_LEN);
- memcpy(ip, hbuf, (ADDR_LEN - plen - 2));
- iplen = strlen(ip);
- }
- snprintf(ip + iplen, ADDR_LEN-iplen, ":%s", sname);
- free(sname);
- }
- }
- else snprintf(ip+iplen, ADDR_LEN-iplen, ":%d", port);
- memcpy(buf, ip, ADDR_LEN);
-}
-
-/*
- * display ipv4 info for TCP/UDP/RAW.
- */
-static void show_ipv4(char *fname, char *label)
-{
- FILE *fp = fopen(fname, "r");
- if (!fp) {
- perror_msg("'%s'", fname);
- return;
- }
-
- if(!fgets(toybuf, sizeof(toybuf), fp)) return; //skip header.
-
- while (fgets(toybuf, sizeof(toybuf), fp)) {
- char lip[ADDR_LEN] = {0,}, rip[ADDR_LEN] = {0,};
- iaddr laddr, raddr;
- unsigned lport, rport, state, txq, rxq, num, uid;
- unsigned long inode;
-
- int nitems = sscanf(toybuf, " %d: %x:%x %x:%x %x %x:%x %*X:%*X %*X %d %*d %ld",
- &num, &laddr.u, &lport, &raddr.u, &rport, &state, &txq,
- &rxq, &uid, &inode);
- if (nitems == 10) {
- addr2str(AF_INET, &laddr, lport, lip, label);
- addr2str(AF_INET, &raddr, rport, rip, label);
- show_data(rport, label, rxq, txq, lip, rip, state, uid, inode);
- }
- }//End of While
- fclose(fp);
-}
-
-/*
- * display ipv6 info for TCP/UDP/RAW.
- */
-static void show_ipv6(char *fname, char *label)
-{
- FILE *fp = fopen(fname, "r");
- if (!fp) {
- perror_msg("'%s'", fname);
- return;
- }
-
- if(!fgets(toybuf, sizeof(toybuf), fp)) return; //skip header.
-
- while (fgets(toybuf, sizeof(toybuf), fp)) {
- char lip[ADDR_LEN] = {0,}, rip[ADDR_LEN] = {0,};
- iaddr6 laddr6, raddr6;
- unsigned lport, rport, state, txq, rxq, num, uid;
- unsigned long inode;
- int nitems = sscanf(toybuf, " %d: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %x:%x "
- "%*X:%*X %*X %d %*d %ld",
- &num, &laddr6.u.a, &laddr6.u.b, &laddr6.u.c,
- &laddr6.u.d, &lport, &raddr6.u.a, &raddr6.u.b,
- &raddr6.u.c, &raddr6.u.d, &rport, &state, &txq, &rxq,
- &uid, &inode);
- if (nitems == 16) {
- addr2str(AF_INET6, &laddr6, lport, lip, label);
- addr2str(AF_INET6, &raddr6, rport, rip, label);
- show_data(rport, label, rxq, txq, lip, rip, state, uid, inode);
- }
- }//End of While
- fclose(fp);
-}
-
-/*
- * display unix socket info.
- */
-static void show_unix_sockets(char *fname, char *label)
-{
- FILE *fp = fopen((char *)fname, "r");
- if (!fp) {
- perror_msg("'%s'", fname);
- return;
- }
-
- if(!fgets(toybuf, sizeof(toybuf), fp)) return; //skip header.
-
- while (fgets(toybuf, sizeof(toybuf), fp)) {
- unsigned long refcount, label, flags, inode;
- int nitems = 0, path_offset = 0, type, state;
- char sock_flags[32] = {0,}, *sock_type, *sock_state, *bptr = toybuf, *term;
-
- if (!toybuf[0]) continue;
-
- nitems = sscanf(toybuf, "%*p: %lX %lX %lX %X %X %lu %n",
- &refcount, &label, &flags, &type, &state, &inode, &path_offset);
-
- //for state one less
- if (nitems < 6) break;
-
- if (toys.optflags & FLAG_l) {
- if ( !((state == SOCK_NOT_CONNECTED) && (flags & SOCK_ACCEPTCON)) )
- continue;
- } else if (!(toys.optflags & FLAG_a)) {
- if ((state == SOCK_NOT_CONNECTED) && (flags & SOCK_ACCEPTCON)) continue;
- }
-
- //prepare socket type, state and flags.
- {
- char *ss_type[] = { "", "STREAM", "DGRAM", "RAW", "RDM", "SEQPACKET",
- "UNKNOWN"};
- char *ss_state[] = { "FREE", "LISTENING", "CONNECTING", "CONNECTED",
- "DISCONNECTING", "UNKNOWN"};
-
- int sz = ARRAY_LEN(ss_type);//sizeof(ss_type)/sizeof(ss_type[0]);
- if ( (type < SOCK_STREAM) || (type > SOCK_SEQPACKET) )
- sock_type = ss_type[sz-1];
- else sock_type = ss_type[type];
-
- sz = ARRAY_LEN(ss_state);//sizeof(ss_state)/sizeof(ss_state[0]);
- if ((state < 0) || (state > sz-2)) sock_state = ss_state[sz-1];
- else if (state == SOCK_NOT_CONNECTED) {
- if (flags & SOCK_ACCEPTCON) sock_state = ss_state[state];
- else sock_state = " ";
- } else sock_state = ss_state[state];
-
- strcpy(sock_flags, "[ ");
- if (flags & SOCK_ACCEPTCON) strcat(sock_flags, "ACC ");
- if (flags & SOCK_WAIT_DATA) strcat(sock_flags, "W ");
- if (flags & SOCK_NO_SPACE) strcat(sock_flags, "N ");
- strcat(sock_flags, "]");
- }
- xprintf("%-5s %-6ld %-11s %-10s %-13s %8lu ", (!label ? "unix" : "??"),
- refcount, sock_flags, sock_type, sock_state, inode);
- if (toys.optflags & FLAG_p) xprintf("%-20s", get_pid_name(inode));
-
- bptr += path_offset;
- if ((term = strchr(bptr, '\n'))) *term = '\0';
- xprintf("%s\n", bptr);
- }//End of while
- fclose(fp);
-}
-
-/*
- * extract inode value from the link.
- */
-static long ss_inode(char *link)
-{
- long inode = -1;
- //"link = socket:[12345]", get "12345" as inode.
- if (link == NULL)
- return -1;
-
- if (!strncmp(link, "socket:[", sizeof("socket:[")-1)) {
- inode = get_strtou(link + sizeof("socket:[")-1, (char**)&link, 0);
- if (*link != ']') inode = -1;
- }
- //"link = [0000]:12345", get "12345" as inode.
- else if (!strncmp(link, "[0000]:", sizeof("[0000]:")-1)) {
- inode = get_strtou(link + sizeof("[0000]:")-1, NULL, 0);
- //if not NULL terminated.
- if (errno) inode = -1;
- }
- return inode;
-}
-
-/*
- * add inode and progname in the pid list.
- */
-static void add2list(long inode)
-{
- PID_LIST *node = pid_list;
-
- for(; node; node = node->next) {
- if(node->inode == inode)
- return;
- }
-
- PID_LIST *new = (PID_LIST *)xzalloc(sizeof(PID_LIST));
- new->inode = inode;
- xstrncpy(new->name, TT.current_name, sizeof(new->name));
- new->next = pid_list;
- pid_list = new;
-}
-
-static void scan_pid_inodes(char *path)
-{
- DIR *dp;
- struct dirent *entry;
-
- if (!(dp = opendir(path))) {
- if (errno == EACCES) {
- TT.some_process_unidentified = 1;
- return;
- } else perror_exit("%s", path);
- }
- while ((entry = readdir(dp))) {
- char link_name[64], *link;
- long inode;
-
- if (!isdigit(entry->d_name[0])) continue;
- snprintf(link_name, sizeof(link_name), "%s/%s", path, entry->d_name);
- link = xreadlink(link_name);
- if ((inode = ss_inode(link)) != -1) add2list(inode);
- free(link);
- }
- closedir(dp);
-}
-
-static void scan_pid(int pid)
-{
- char *line, *p, *fd_dir;
-
- snprintf(toybuf, sizeof(toybuf), "/proc/%d/cmdline", pid);
- line = xreadfile(toybuf, 0, 0);
-
- if ((p = strchr(line, ' '))) *p = 0; // "/bin/netstat -ntp" -> "/bin/netstat"
- snprintf(TT.current_name, sizeof(TT.current_name), "%d/%s",
- pid, getbasename(line)); // "584/netstat"
- free(line);
-
- fd_dir = xmprintf("/proc/%d/fd", pid);
- scan_pid_inodes(fd_dir);
- free(fd_dir);
-}
-
-static int scan_pids(struct dirtree *node)
-{
- int pid;
-
- if (!node->parent) return DIRTREE_RECURSE;
- if ((pid = atol(node->name))) scan_pid(pid);
-
- return 0;
-}
-
-/*
- * Dealloc pid list.
- */
-static void clean_pid_list(void)
-{
- PID_LIST *tmp;
- while (pid_list) {
- tmp = pid_list->next;
- free(pid_list);
- pid_list = tmp;
- }
-}
-
-/*
- * For TCP/UDP/RAW show the header.
- */
-static void show_header(void)
-{
- xprintf("Proto Recv-Q Send-Q ");
- xprintf((toys.optflags & FLAG_W) ? "%-51s %-51s" : "%-23s %-23s",
- "Local Address", "Foreign Address");
- xprintf(" State ");
- if (toys.optflags & FLAG_e) xprintf(" User Inode ");
- if (toys.optflags & FLAG_p) xprintf(" PID/Program Name");
- xputc('\n');
-}
-
-/*
- * used to get the flag values for route command.
- */
-static void get_flag_value(char *flagstr, int flags)
-{
- int i = 0;
- char *str = flagstr;
- static const char flagchars[] = "GHRDMDAC";
- static const unsigned flagarray[] = {
- RTF_GATEWAY,
- RTF_HOST,
- RTF_REINSTATE,
- RTF_DYNAMIC,
- RTF_MODIFIED,
- RTF_DEFAULT,
- RTF_ADDRCONF,
- RTF_CACHE
- };
- *str++ = 'U';
-
- while ( (*str = flagchars[i]) ) {
- if (flags & flagarray[i++]) ++str;
- }
-}
-
-/*
- * extract inet4 route info from /proc/net/route file and display it.
- */
-static void display_routes(int is_more_info, int notresolve)
-{
-#define IPV4_MASK (RTF_GATEWAY|RTF_HOST|RTF_REINSTATE|RTF_DYNAMIC|RTF_MODIFIED)
- unsigned long dest, gate, mask;
- int flags, ref, use, metric, mss, win, irtt;
- char iface[64]={0,};
- char flag_val[10]={0,}; //there are 9 flags "UGHRDMDAC" for route.
-
- FILE *fp = xfopen("/proc/net/route", "r");
-
- if(!fgets(toybuf, sizeof(toybuf), fp)) return; //skip header.
-
- xprintf("Kernel IP routing table\n"
- "Destination Gateway Genmask Flags %s Iface\n",
- is_more_info ? " MSS Window irtt" : "Metric Ref Use");
-
- while (fgets(toybuf, sizeof(toybuf), fp)) {
- int nitems = 0;
- char *destip = NULL, *gateip = NULL, *maskip = NULL;
-
- nitems = sscanf(toybuf, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n", iface, &dest,
- &gate, &flags, &ref, &use, &metric, &mask, &mss, &win, &irtt);
- if (nitems != 11) {//EOF with no (nonspace) chars read.
- if ((nitems < 0) && feof(fp)) break;
- perror_exit("sscanf");
- }
-
- //skip down interfaces.
- if (!(flags & RTF_UP)) continue;
-
- if (dest) {//For Destination
- if (inet_ntop(AF_INET, &dest, toybuf, sizeof(toybuf)) )
- destip = xstrdup(toybuf);
- } else {
- if (!notresolve) destip = xstrdup("default");
- else destip = xstrdup("0.0.0.0");
- }
-
- if (gate) {//For Gateway
- if (inet_ntop(AF_INET, &gate, toybuf, sizeof(toybuf)) )
- gateip = xstrdup(toybuf);
- } else {
- if (!notresolve) gateip = xstrdup("*");
- else gateip = xstrdup("0.0.0.0");
- }
-
- //For Mask
- if (inet_ntop(AF_INET, &mask, toybuf, sizeof(toybuf)) )
- maskip = xstrdup(toybuf);
-
- //Get flag Values
- get_flag_value(flag_val, flags & IPV4_MASK);
- if (flags & RTF_REJECT) flag_val[0] = '!';
-
- xprintf("%-15.15s %-15.15s %-16s%-6s", destip, gateip, maskip, flag_val);
- if (is_more_info) xprintf("%5d %-5d %6d %s\n", mss, win, irtt, iface);
- else xprintf("%-6d %-2d %7d %s\n", metric, ref, use, iface);
-
- if (destip) free(destip);
- if (gateip) free(gateip);
- if (maskip) free(maskip);
- }//end of while.
- fclose(fp);
-#undef IPV4_MASK
-}
-
-/*
- * netstat utility main function.
- */
-void netstat_main(void)
-{
-#define IS_NETSTAT_PROTO_FLAGS_UP (toys.optflags & (FLAG_t | FLAG_u | FLAG_w \
- | FLAG_x))
-
- // For no parameter, add 't', 'u', 'w', 'x' options as default
- if (!toys.optflags) toys.optflags = FLAG_t | FLAG_u | FLAG_w | FLAG_x;
-
- // For both 'a' and 'l' are set, remove 'l' option
- if (toys.optflags & FLAG_a && toys.optflags & FLAG_l)
- toys.optflags &= ~FLAG_l;
-
- // For each 'a', 'l', 'e', 'n', 'W', 'p' options
- // without any 't', 'u', 'w', 'x' option, add 't', 'u', 'w', 'x' options
- if (((toys.optflags & FLAG_a) || (toys.optflags & FLAG_l) ||
- (toys.optflags & FLAG_e) || (toys.optflags & FLAG_n) ||
- (toys.optflags & FLAG_W) || (toys.optflags & FLAG_p)) &&
- (!IS_NETSTAT_PROTO_FLAGS_UP) )
- toys.optflags |= FLAG_t | FLAG_u | FLAG_w | FLAG_x;
-
- //Display routing table.
- if (toys.optflags & FLAG_r) {
- display_routes(!(toys.optflags & FLAG_e), (toys.optflags & FLAG_n));
- return;
- }
-
- if (toys.optflags & FLAG_p) {
- dirtree_read("/proc", scan_pids);
- // TODO: we probably shouldn't warn if all the processes we're going to
- // list were identified.
- if (TT.some_process_unidentified)
- fprintf(stderr,
- "(Not all processes could be identified, non-owned process info\n"
- " will not be shown, you would have to be root to see it all.)\n");
- }
-
- //For TCP/UDP/RAW.
- if ( (toys.optflags & FLAG_t) || (toys.optflags & FLAG_u) ||
- (toys.optflags & FLAG_w) ) {
- xprintf("Active Internet connections ");
-
- if (toys.optflags & FLAG_a) xprintf("(servers and established)\n");
- else if (toys.optflags & FLAG_l) xprintf("(only servers)\n");
- else xprintf("(w/o servers)\n");
-
- show_header();
- if (toys.optflags & FLAG_t) {//For TCP
- show_ipv4("/proc/net/tcp", "tcp");
- show_ipv6("/proc/net/tcp6", "tcp");
- }
- if (toys.optflags & FLAG_u) {//For UDP
- show_ipv4("/proc/net/udp", "udp");
- show_ipv6("/proc/net/udp6", "udp");
- }
- if (toys.optflags & FLAG_w) {//For raw
- show_ipv4("/proc/net/raw", "raw");
- show_ipv6("/proc/net/raw6", "raw");
- }
- }
- if (toys.optflags & FLAG_x) {//For UNIX
- xprintf("Active UNIX domain sockets ");
- if (toys.optflags & FLAG_a) xprintf("(servers and established)\n");
- else if (toys.optflags & FLAG_l) xprintf("(only servers)\n");
- else xprintf("(w/o servers)\n");
-
- if (toys.optflags & FLAG_p)
- xprintf("Proto RefCnt Flags Type State "
- "I-Node PID/Program Name Path\n");
- else
- xprintf("Proto RefCnt Flags Type State "
- "I-Node Path\n");
- show_unix_sockets("/proc/net/unix", "unix");
- }
- if (toys.optflags & FLAG_p) clean_pid_list();
- if (toys.exitval) toys.exitval = 0;
-#undef IS_NETSTAT_PROTO_FLAGS_UP
-}
diff --git a/toys/pending/openvt.c b/toys/pending/openvt.c
index 042b897c..29f8a174 100644
--- a/toys/pending/openvt.c
+++ b/toys/pending/openvt.c
@@ -100,7 +100,7 @@ void openvt_main(void)
xioctl(fd, VT_GETSTATE, &vstate);
close(0); //new vt becomes stdin
- vt_fd = xopen(toybuf, O_RDWR);
+ vt_fd = xopen_stdio(toybuf, O_RDWR);
if (toys.optflags & FLAG_s) {
ioctl(vt_fd, VT_ACTIVATE, TT.vt_num);
ioctl(vt_fd, VT_WAITACTIVE, TT.vt_num);
diff --git a/toys/pending/sulogin.c b/toys/pending/sulogin.c
index e6cb8314..bc3638e3 100644
--- a/toys/pending/sulogin.c
+++ b/toys/pending/sulogin.c
@@ -88,7 +88,7 @@ void sulogin_main(void)
if (toys.optargs[0]) {
int fd;
- dup2((fd = xopen(toys.optargs[0], O_RDWR)), 0);
+ dup2((fd = xopen_stdin(toys.optargs[0], O_RDWR)), 0);
if (!isatty(0)) error_exit("%s: it is not a tty", toys.optargs[0]);
dup2( fd, 1);
dup2( fd, 2);
diff --git a/toys/pending/tftp.c b/toys/pending/tftp.c
index 60d5f172..1c6fe9e6 100644
--- a/toys/pending/tftp.c
+++ b/toys/pending/tftp.c
@@ -381,7 +381,7 @@ int file_put(void)
sd = init_tftp(&server);
packet = (uint8_t*)xzalloc(TFTP_IOBUFSIZE);
- fd = xopen(TT.local_file, O_RDONLY);
+ fd = xopenro(TT.local_file);
for (;;) { //first loop for request send and confirmation from server.
packetlen = mkpkt_request(packet, TFTP_OP_WRQ, TT.remote_file, 1);
diff --git a/toys/posix/chgrp.c b/toys/posix/chgrp.c
index e0690c93..62e9eb1d 100644
--- a/toys/posix/chgrp.c
+++ b/toys/posix/chgrp.c
@@ -87,11 +87,11 @@ void chgrp_main(void)
*(grp++) = 0;
TT.group_name = grp;
}
- if (*own) TT.owner = xgetpwnamid(TT.owner_name = own)->pw_uid;
+ if (*own) TT.owner = xgetuid(TT.owner_name = own);
} else TT.group_name = *toys.optargs;
if (TT.group_name && *TT.group_name)
- TT.group = xgetgrnamid(TT.group_name)->gr_gid;
+ TT.group = xgetgid(TT.group_name);
for (s=toys.optargs+1; *s; s++)
dirtree_flagread(*s, DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)),
diff --git a/toys/posix/cmp.c b/toys/posix/cmp.c
index 829da75c..f4c34091 100644
--- a/toys/posix/cmp.c
+++ b/toys/posix/cmp.c
@@ -4,7 +4,7 @@
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/cmp.html
-USE_CMP(NEWTOY(cmp, "<2>2ls", TOYFLAG_USR|TOYFLAG_BIN))
+USE_CMP(NEWTOY(cmp, "<2>2ls[!ls]", TOYFLAG_USR|TOYFLAG_BIN))
config CMP
bool "cmp"
@@ -43,6 +43,8 @@ static void do_cmp(int fd, char *name)
return;
}
+ toys.exitval = 0;
+
for (;;) {
len1 = readall(TT.fd, toybuf, size);
len2 = readall(fd, buf2, size);
@@ -54,11 +56,9 @@ static void do_cmp(int fd, char *name)
if (toys.optflags & FLAG_l)
printf("%ld %o %o\n", byte_no, toybuf[i], buf2[i]);
else {
- if (!(toys.optflags & FLAG_s)) {
+ if (!(toys.optflags & FLAG_s))
printf("%s %s differ: char %ld, line %ld\n",
TT.name, name, byte_no, line_no);
- toys.exitval++;
- }
goto out;
}
}
@@ -79,6 +79,8 @@ out:
void cmp_main(void)
{
- loopfiles_rw(toys.optargs, O_CLOEXEC, 0, toys.optflags&FLAG_s, do_cmp);
+ toys.exitval = 2;
+ loopfiles_rw(toys.optargs, O_CLOEXEC|(WARN_ONLY*!(toys.optflags&FLAG_s)), 0,
+ do_cmp);
}
diff --git a/toys/posix/comm.c b/toys/posix/comm.c
index 6c726cf6..ded262f5 100644
--- a/toys/posix/comm.c
+++ b/toys/posix/comm.c
@@ -48,8 +48,7 @@ void comm_main(void)
if (toys.optflags == 7) return;
for (i = 0; i < 2; i++) {
- file[i] = strcmp("-", toys.optargs[i])
- ? xopen(toys.optargs[i], O_RDONLY) : 0;
+ file[i] = xopenro(toys.optargs[i]);
line[i] = get_line(file[i]);
}
diff --git a/toys/posix/cp.c b/toys/posix/cp.c
index d8ae783f..6e035f77 100644
--- a/toys/posix/cp.c
+++ b/toys/posix/cp.c
@@ -251,8 +251,8 @@ int cp_node(struct dirtree *try)
// make symlink, or make block/char/fifo/socket
if (S_ISLNK(try->st.st_mode)
- ? (0 < (i = readlinkat(tfd, try->name, toybuf, sizeof(toybuf))) &&
- sizeof(toybuf) > i && !symlinkat(toybuf, cfd, catch))
+ ? ((i = readlinkat0(tfd, try->name, toybuf, sizeof(toybuf))) &&
+ !symlinkat(toybuf, cfd, catch))
: !mknodat(cfd, catch, try->st.st_mode, try->st.st_rdev))
{
err = 0;
@@ -317,7 +317,13 @@ int cp_node(struct dirtree *try)
if (fdout == AT_FDCWD)
fchownat(cfd, catch, try->st.st_uid, try->st.st_gid,
AT_SYMLINK_NOFOLLOW);
- else fchown(fdout, try->st.st_uid, try->st.st_gid);
+ else rc = fchown(fdout, try->st.st_uid, try->st.st_gid);
+ if (rc && !geteuid()) {
+ char *pp;
+
+ perror_msg("chown '%s'", pp = dirtree_path(try, 0));
+ free(pp);
+ }
}
// timestamp
@@ -339,7 +345,19 @@ int cp_node(struct dirtree *try)
err = "%s";
}
- if (err) perror_msg(err, catch);
+ if (err) {
+ char *f = 0;
+
+ if (catch == try->name) {
+ f = dirtree_path(try, 0);
+ while (try->parent) try = try->parent;
+ catch = xmprintf("%s%s", TT.destname, f+strlen(try->name));
+ free(f);
+ f = catch;
+ }
+ perror_msg(err, catch);
+ free(f);
+ }
return 0;
}
@@ -481,8 +499,8 @@ void install_main(void)
if (flags & FLAG_v) toys.optflags |= cp_flag_v();
if (flags & (FLAG_p|FLAG_o|FLAG_g)) toys.optflags |= cp_flag_p();
- if (TT.i.user) TT.uid = xgetpwnamid(TT.i.user)->pw_uid;
- if (TT.i.group) TT.gid = xgetgrnamid(TT.i.group)->gr_gid;
+ if (TT.i.user) TT.uid = xgetuid(TT.i.user);
+ if (TT.i.group) TT.gid = xgetgid(TT.i.group);
TT.callback = install_node;
cp_main();
diff --git a/toys/posix/cut.c b/toys/posix/cut.c
index 1acefe2b..13be5e74 100644
--- a/toys/posix/cut.c
+++ b/toys/posix/cut.c
@@ -77,13 +77,13 @@ static void parse_list(char *list)
if (!ctoken) break;
if (!*ctoken) continue;
- //Get start position.
+ // Get start position.
if (*(dtoken = strsep(&ctoken, "-"))) {
start = atolx_range(dtoken, 0, INT_MAX);
start = (start?(start-1):start);
}
- //Get end position.
+ // Get end position.
if (!ctoken) end = -1; //case e.g. 1,2,3
else if (*ctoken) {//case e.g. N-M
end = atolx_range(ctoken, 0, INT_MAX);
@@ -94,7 +94,7 @@ static void parse_list(char *list)
add_to_list(start, end);
TT.nelem++;
}
- //if list is missing in command line.
+ // if list is missing in command line.
if (!TT.nelem) error_exit("missing positions list");
}
@@ -112,7 +112,7 @@ static void get_data(void)
if(strcmp(*argv, "-") == 0) TT.do_cut(0); //for stdin
else {
int fd = open(*argv, O_RDONLY, 0);
- if(fd < 0) {//if file not present then continue with other files.
+ if (fd < 0) {//if file not present then continue with other files.
perror_msg_raw(*argv);
continue;
}
diff --git a/toys/posix/echo.c b/toys/posix/echo.c
index 45890dc4..33de6781 100644
--- a/toys/posix/echo.c
+++ b/toys/posix/echo.c
@@ -3,6 +3,11 @@
* Copyright 2007 Rob Landley <rob@landley.net>
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/echo.html
+ *
+ * Deviations from posix: we parse command line options, as Linux has
+ * consistently done since 1992. Posix defaults -e to on, we require -e.
+ * We also honor -- to _stop_ option parsing (bash doesn't, we go with
+ * consistency over compatibility here).
USE_ECHO(NEWTOY(echo, "^?en", TOYFLAG_BIN))
diff --git a/toys/posix/false.c b/toys/posix/false.c
index 73458bea..0853b010 100644
--- a/toys/posix/false.c
+++ b/toys/posix/false.c
@@ -4,7 +4,7 @@
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/false.html
-USE_FALSE(NEWTOY(false, NULL, TOYFLAG_BIN))
+USE_FALSE(NEWTOY(false, NULL, TOYFLAG_BIN|TOYFLAG_NOHELP))
config FALSE
bool "false"
diff --git a/toys/pending/file.c b/toys/posix/file.c
index 18941227..4827f8f5 100644
--- a/toys/pending/file.c
+++ b/toys/posix/file.c
@@ -3,18 +3,19 @@
* Copyright 2016 The Android Open Source Project
*
* See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/file.html
- *
- * TODO: ar
-USE_FILE(NEWTOY(file, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_FILE(NEWTOY(file, "<1hL[!hL]", TOYFLAG_USR|TOYFLAG_BIN))
config FILE
bool "file"
- default n
+ default y
help
- usage: file [file...]
+ usage: file [-hL] [file...]
Examine the given files and describe their content types.
+
+ -h don't follow symlinks (default)
+ -L follow symlinks
*/
#define FOR_file
@@ -26,7 +27,7 @@ GLOBALS(
// We don't trust elf.h to be there, and two codepaths for 32/64 is awkward
// anyway, so calculate struct offsets manually. (It's a fixed ABI.)
-static void do_elf_file(int fd)
+static void do_elf_file(int fd, struct stat *sb)
{
int endian = toybuf[5], bits = toybuf[4], i, j;
int64_t (*elf_int)(void *ptr, unsigned size) = peek_le;
@@ -45,6 +46,11 @@ static void do_elf_file(int fd)
{191, "tilegx"}, {3, "386"}, {6, "486"}, {62, "x86-64"}, {94, "xtensa"},
{0xabc7, "xtensa-old"}
};
+ int dynamic = 0;
+ int stripped = 1;
+ char *map;
+ off_t phoff, shoff;
+ int phsize, phnum, shsize, shnum;
printf("ELF ");
@@ -82,53 +88,87 @@ static void do_elf_file(int fd)
else printf("(unknown arch %d)", j);
bits--;
- // If we know our bits and endianness and phentsize agrees show dynamic linker
- if ((bits&1)==bits && endian &&
- (i = elf_int(toybuf+42+12*bits, 2)) == 32+24*bits)
- {
- char *map, *phdr;
- int phsize = i, phnum = elf_int(toybuf+44+12*bits, 2),
- psz = sysconf(_SC_PAGE_SIZE), lib = 0;
- off_t phoff = elf_int(toybuf+28+4*bits, 4+4*bits),
- mapoff = phoff^(phoff&(psz-1));
-
- // map e_phentsize*e_phnum bytes at e_phoff
- map = mmap(0, phsize*phnum, PROT_READ, MAP_SHARED, fd, mapoff);
- if (map) {
- // Find PT_INTERP entry. (Note: fields got reordered for 64 bit)
- for (i = 0; i<phnum; i++) {
- long long dlpos, dllen;
-
- // skip non-PT_INTERP entries
- j = elf_int(phdr = map+(phoff-mapoff)+i*phsize, 4);
- if (j==2) lib++;
- if (j!=3) continue;
-
- // Read p_offset and p_filesz
- j = bits+1;
- dlpos = elf_int(phdr+4*j, 4*j);
- dllen = elf_int(phdr+16*j, 4*j);
- if (dllen<0 || dllen>sizeof(toybuf)-128
- || dlpos!=lseek(fd, dlpos, SEEK_SET)
- || dllen!=readall(fd, toybuf+128, dllen)) break;
- printf(", dynamic (%.*s", (int)dllen, toybuf+128);
+ // If what we've seen so far doesn't seem consistent, bail.
+ if (!((bits&1)==bits && endian &&
+ (i = elf_int(toybuf+42+12*bits, 2)) == 32+24*bits)) {
+ printf(", corrupt?\n");
+ return;
+ }
+
+ // Stash what we need from the header; it's okay to reuse toybuf after this.
+ phsize = i;
+ phnum = elf_int(toybuf+44+12*bits, 2);
+ phoff = elf_int(toybuf+28+4*bits, 4+4*bits);
+ shsize = elf_int(toybuf+46+12*bits, 2);
+ shnum = elf_int(toybuf+48+12*bits, 2);
+ shoff = elf_int(toybuf+32+8*bits, 4+4*bits);
+
+ map = mmap(0, sb->st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!map) perror_exit("mmap");
+
+ // We need to read the phdrs for dynamic vs static and any notes.
+ // (Note: fields got reordered for 64 bit)
+ for (i = 0; i<phnum; i++) {
+ char *phdr = map+phoff+i*phsize;
+ int p_type = elf_int(phdr, 4);
+ long long p_offset, p_filesz;
+
+ if (p_type==2 /*PT_DYNAMIC*/) dynamic = 1;
+ if (p_type!=3 /*PT_INTERP*/ && p_type!=4 /*PT_NOTE*/) continue;
+
+ j = bits+1;
+ p_offset = elf_int(phdr+4*j, 4*j);
+ p_filesz = elf_int(phdr+16*j, 4*j);
+
+ if (p_type==3 /*PT_INTERP*/)
+ printf(", dynamic (%.*s)", (int)p_filesz, map+p_offset);
+ else {
+ char *note = map+p_offset;
+
+ // A PT_NOTE phdr is a sequence of entries, each consisting of an
+ // ndhr followed by n_namesz+n_descsz bytes of data (each of those
+ // rounded up to the next 4 bytes, without this being reflected in
+ // the header byte counts themselves).
+ while (p_filesz >= 3*4) { // Don't try to read a truncated entry.
+ int n_namesz = elf_int(note, 4);
+ int n_descsz = elf_int(note+4, 4);
+ int n_type = elf_int(note+8, 4);
+ int notesz = 3*4 + ((n_namesz+3)&~3) + ((n_descsz+3)&~3);
+
+ if (n_namesz==4 && !memcmp(note+12, "GNU", 4)) {
+ if (n_type == 3 /*NT_GNU_BUILD_ID*/) {
+ printf(", BuildID=");
+ for (j = 0; j < n_descsz; ++j) printf("%02x", note[16 + j]);
+ }
+ } else if (n_namesz==8 && !memcmp(note+12, "Android", 8)) {
+ if (n_type==1) printf(", for Android %d", (int)elf_int(note+20, 4));
+ }
+
+ note += notesz;
+ p_filesz -= notesz;
}
- if (!lib) printf(", static");
- else printf(" loads %d lib%s)", lib, lib>1 ? "s" : "");
- munmap(map, phsize*phnum);
}
}
+ if (!dynamic) printf(", static");
+
+ // We need to read the shdrs for stripped/unstripped.
+ // (Note: fields got reordered for 64 bit)
+ for (i = 0; i<shnum; i++) {
+ char *shdr = map+shoff+i*shsize;
+ int sh_type = elf_int(shdr+4, 4);
- // TODO: we'd need to actually parse the ELF file to report the rest...
- // ", dynamically linked"
- // " (uses shared libs)"
- // ", for Linux 2.6.24"
- // ", BuildID[sha1]=SHA"
- // ", stripped"
+ if (sh_type == 2 /*SHT_SYMTAB*/) {
+ stripped = 0;
+ break;
+ }
+ }
+ printf(", %sstripped", stripped ? "" : "not ");
xputc('\n');
+
+ munmap(map, sb->st_size);
}
-static void do_regular_file(int fd, char *name)
+static void do_regular_file(int fd, char *name, struct stat *sb)
{
char *s;
int len = read(fd, s = toybuf, sizeof(toybuf)-256);
@@ -136,7 +176,8 @@ static void do_regular_file(int fd, char *name)
if (len<0) perror_msg("%s", name);
- if (len>40 && strstart(&s, "\177ELF")) do_elf_file(fd);
+ if (len>40 && strstart(&s, "\177ELF")) do_elf_file(fd, sb);
+ else if (len>=8 && strstart(&s, "!<arch>\n")) xprintf("ar archive\n");
else if (len>28 && strstart(&s, "\x89PNG\x0d\x0a\x1a\x0a")) {
// PNG is big-endian: https://www.w3.org/TR/PNG/#7Integers-and-byte-order
int chunk_length = peek_be(s, 4);
@@ -182,24 +223,20 @@ static void do_regular_file(int fd, char *name)
else if (toybuf[5] == '1') cpioformat = "SVR4 with no CRC";
else if (toybuf[5] == '2') cpioformat = "SVR4 with CRC";
xprintf("ASCII cpio archive (%s)\n", cpioformat);
- }
- else if (len>33 && (magic=peek(&s,2), magic==0143561 || magic==070707)) {
+ } else if (len>33 && (magic=peek(&s,2), magic==0143561 || magic==070707)) {
if (magic == 0143561) printf("byte-swapped ");
xprintf("cpio archive\n");
- }
// tar archive (ustar/pax or gnu)
- else if (len>500 && !strncmp(s+257, "ustar", 5)) {
+ } else if (len>500 && !strncmp(s+257, "ustar", 5)) {
xprintf("POSIX tar archive%s\n", strncmp(s+262," ",2)?"":" (GNU)");
- }
// zip/jar/apk archive, ODF/OOXML document, or such
- else if (len>5 && strstart(&s, "PK\03\04")) {
+ } else if (len>5 && strstart(&s, "PK\03\04")) {
int ver = (int)(char)(toybuf[4]);
xprintf("Zip archive data");
if (ver)
xprintf(", requires at least v%d.%d to extract", ver/10, ver%10);
xputc('\n');
- }
- else {
+ } else {
char *what = 0;
int i, bytes;
@@ -240,23 +277,22 @@ void file_main(void)
// Can't use loopfiles here because it doesn't call function when can't open
for (arg = toys.optargs; *arg; arg++) {
- struct stat sb;
char *name = *arg, *what = "cannot open";
+ struct stat sb;
+ int fd = !strcmp(name, "-");
xprintf("%s: %*s", name, (int)(TT.max_name_len - strlen(name)), "");
- if (!lstat(name, &sb)) {
- if (S_ISFIFO(sb.st_mode)) what = "fifo";
- else if (S_ISREG(sb.st_mode)) {
- int fd = !strcmp(name, "-") ? 0 : open(name, O_RDONLY);
-
- if (fd!=-1) {
- if (!sb.st_size) what = "empty";
- else do_regular_file(fd, name);
+ if (fd || !((toys.optflags & FLAG_L) ? stat : lstat)(name, &sb)) {
+ if (fd || S_ISREG(sb.st_mode)) {
+ if (!sb.st_size) what = "empty";
+ else if ((fd = openro(name, O_RDONLY)) != -1) {
+ do_regular_file(fd, name, &sb);
if (fd) close(fd);
- if (sb.st_size) continue;
+ continue;
}
- } else if (S_ISBLK(sb.st_mode)) what = "block special";
+ } else if (S_ISFIFO(sb.st_mode)) what = "fifo";
+ else if (S_ISBLK(sb.st_mode)) what = "block special";
else if (S_ISCHR(sb.st_mode)) what = "character special";
else if (S_ISDIR(sb.st_mode)) what = "directory";
else if (S_ISSOCK(sb.st_mode)) what = "socket";
diff --git a/toys/posix/find.c b/toys/posix/find.c
index 3b27225d..86fc141f 100644
--- a/toys/posix/find.c
+++ b/toys/posix/find.c
@@ -295,7 +295,7 @@ static int do_find(struct dirtree *new)
if (check) not = !not;
continue;
// Mostly ignore NOP argument
- } else if (!strcmp(s, "a") || !strcmp(s, "and")) {
+ } else if (!strcmp(s, "a") || !strcmp(s, "and") || !strcmp(s, "noleaf")) {
if (not) goto error;
} else if (!strcmp(s, "print") || !strcmp("print0", s)) {
@@ -303,9 +303,9 @@ static int do_find(struct dirtree *new)
if (check) do_print(new, s[5] ? 0 : '\n');
} else if (!strcmp(s, "nouser")) {
- if (check) if (getpwuid(new->st.st_uid)) test = 0;
+ if (check) if (bufgetpwuid(new->st.st_uid)) test = 0;
} else if (!strcmp(s, "nogroup")) {
- if (check) if (getgrgid(new->st.st_gid)) test = 0;
+ if (check) if (bufgetgrgid(new->st.st_gid)) test = 0;
} else if (!strcmp(s, "prune")) {
if (check && S_ISDIR(new->st.st_mode) && !TT.depth) recurse = 0;
@@ -398,8 +398,8 @@ static int do_find(struct dirtree *new)
udl = xmalloc(sizeof(*udl));
dlist_add_nomalloc(&TT.argdata, (void *)udl);
- if (*s == 'u') udl->u.uid = xgetpwnamid(ss[1])->pw_uid;
- else if (*s == 'g') udl->u.gid = xgetgrnamid(ss[1])->gr_gid;
+ if (*s == 'u') udl->u.uid = xgetuid(ss[1]);
+ else if (*s == 'g') udl->u.gid = xgetgid(ss[1]);
else {
struct stat st;
@@ -454,7 +454,7 @@ static int do_find(struct dirtree *new)
ss += len;
aa->arglen = len;
aa->dir = !!strchr(s, 'd');
- if (TT.topdir == -1) TT.topdir = xopen(".", 0);
+ if (TT.topdir == -1) TT.topdir = xopenro(".");
// collect names and execute commands
} else {
diff --git a/toys/posix/grep.c b/toys/posix/grep.c
index 2ca02d2c..2fe6ac27 100644
--- a/toys/posix/grep.c
+++ b/toys/posix/grep.c
@@ -74,24 +74,19 @@ static void outline(char *line, char dash, char *name, long lcount, long bcount,
if (!line || (lcount && (toys.optflags&FLAG_n)))
printf("%ld%c", lcount, line ? dash : TT.outdelim);
if (bcount && (toys.optflags&FLAG_b)) printf("%ld%c", bcount-1, dash);
- if (line) xprintf("%.*s%c", trim ? trim : INT_MAX/2, line, TT.outdelim);
+ if (line) xprintf("%.*s%c", trim, line, TT.outdelim);
}
// Show matches in one file
static void do_grep(int fd, char *name)
{
struct double_list *dlb = 0;
- FILE *file = fdopen(fd, "r");
+ FILE *file = xfdopen(fd, "r");
long lcount = 0, mcount = 0, offset = 0, after = 0, before = 0;
char *bars = 0;
if (!fd) name = "(standard input)";
- if (!file) {
- perror_msg_raw(name);
- return;
- }
-
// Loop through lines of input
for (;;) {
char *line = 0, *start;
@@ -201,13 +196,13 @@ static void do_grep(int fd, char *name)
while (dlb) {
struct double_list *dl = dlist_pop(&dlb);
- outline(dl->data, '-', name, lcount-before, 0, 0);
+ outline(dl->data, '-', name, lcount-before, 0, -1);
free(dl->data);
free(dl);
before--;
}
- outline(line, ':', name, lcount, bcount, 0);
+ outline(line, ':', name, lcount, bcount, -1);
if (TT.a) after = TT.a+1;
} else outline(start+matches.rm_so, ':', name, lcount, bcount,
matches.rm_eo-matches.rm_so);
@@ -223,7 +218,7 @@ static void do_grep(int fd, char *name)
int discard = (after || TT.b);
if (after && --after) {
- outline(line, '-', name, lcount, 0, 0);
+ outline(line, '-', name, lcount, 0, -1);
discard = 0;
}
if (discard && TT.b) {
@@ -247,7 +242,7 @@ static void do_grep(int fd, char *name)
if ((toys.optflags & FLAG_m) && mcount >= TT.m) break;
}
- if (toys.optflags & FLAG_c) outline(0, ':', name, mcount, 0, 0);
+ if (toys.optflags & FLAG_c) outline(0, ':', name, mcount, 0, -1);
// loopfiles will also close the fd, but this frees an (opaque) struct.
fclose(file);
@@ -359,7 +354,7 @@ void grep_main(void)
toys.exitval = 1;
if (toys.optflags & FLAG_s) {
close(2);
- xopen("/dev/null", O_RDWR);
+ xopen_stdio("/dev/null", O_RDWR);
}
if (toys.optflags & FLAG_r) {
@@ -368,5 +363,5 @@ void grep_main(void)
if (!strcmp(*ss, "-")) do_grep(0, *ss);
else dirtree_read(*ss, do_grep_r);
}
- } else loopfiles_rw(ss, O_RDONLY, 0, 1, do_grep);
+ } else loopfiles_rw(ss, O_RDONLY|WARN_ONLY, 0, do_grep);
}
diff --git a/toys/posix/id.c b/toys/posix/id.c
index 01610bcd..4b732b1b 100644
--- a/toys/posix/id.c
+++ b/toys/posix/id.c
@@ -73,7 +73,7 @@ static void s_or_u(char *s, unsigned u, int done)
else printf("%u", u);
if (done) {
xputc('\n');
- exit(0);
+ xexit();
}
}
@@ -143,7 +143,7 @@ static void do_id(char *username)
}
if (toys.optflags&FLAG_G) {
xputc('\n');
- exit(0);
+ xexit();
}
}
diff --git a/toys/posix/ls.c b/toys/posix/ls.c
index 94359d7a..b052eace 100644
--- a/toys/posix/ls.c
+++ b/toys/posix/ls.c
@@ -18,12 +18,12 @@ config LS
what to show:
-a all files including .hidden -b escape nongraphic chars
-c use ctime for timestamps -d directory, not contents
- -i inode number -k block sizes in kilobytes
- -p put a '/' after dir names -q unprintable chars as '?'
- -s size (in blocks) -u use access time for timestamps
- -A list all files but . and .. -H follow command line symlinks
- -L follow symlinks -R recursively list files in subdirs
- -F append /dir *exe @sym |FIFO -Z security context
+ -i inode number -p put a '/' after dir names
+ -q unprintable chars as '?' -s storage used (1024 byte units)
+ -u use access time for timestamps -A list all files but . and ..
+ -H follow command line symlinks -L follow symlinks
+ -R recursively list in subdirs -F append /dir *exe @sym |FIFO
+ -Z security context
output formats:
-1 list one file per line -C columns (sorted vertically)
@@ -61,7 +61,7 @@ GLOBALS(
unsigned screen_width;
int nl_title;
- char uid_buf[12], gid_buf[12], *escmore;
+ char *escmore;
)
// Callback from crunch_str to represent unprintable chars
@@ -121,25 +121,15 @@ static char endtype(struct stat *st)
return 0;
}
-static char *getusername(uid_t uid)
+static int numlen(long long ll)
{
- struct passwd *pw = getpwuid(uid);
-
- sprintf(TT.uid_buf, "%u", (unsigned)uid);
- return pw ? pw->pw_name : TT.uid_buf;
+ return snprintf(0, 0, "%llu", ll);
}
-static char *getgroupname(gid_t gid)
+static int print_with_h(char *s, long long value, int units)
{
- struct group *gr = getgrgid(gid);
-
- sprintf(TT.gid_buf, "%u", (unsigned)gid);
- return gr ? gr->gr_name : TT.gid_buf;
-}
-
-static int numlen(long long ll)
-{
- return snprintf(0, 0, "%llu", ll);
+ if (toys.optflags&FLAG_h) return human_readable(s, value*units, 0);
+ else return sprintf(s, "%lld", value);
}
// Figure out size of printable entry fields for display indent/wrap
@@ -164,13 +154,10 @@ static void entrylen(struct dirtree *dt, unsigned *len)
// cheating slightly here: assuming minor is always 3 digits to avoid
// tracking another column
len[5] = numlen(dev_major(st->st_rdev))+5;
- } else if (flags & FLAG_h) {
- human_readable(tmp, st->st_size, 0);
- len[5] = strwidth(tmp);
- } else len[5] = numlen(st->st_size);
+ } else len[5] = print_with_h(tmp, st->st_size, 1);
}
- len[6] = (flags & FLAG_s) ? numlen(st->st_blocks) : 0;
+ len[6] = (flags & FLAG_s) ? print_with_h(tmp, st->st_blocks, 512) : 0;
len[7] = (flags & FLAG_Z) ? strwidth((char *)dt->extra) : 0;
}
@@ -235,7 +222,7 @@ static int filter(struct dirtree *new)
if (flags & FLAG_u) new->st.st_mtime = new->st.st_atime;
if (flags & FLAG_c) new->st.st_mtime = new->st.st_ctime;
- if (flags & FLAG_k) new->st.st_blocks = (new->st.st_blocks + 1) / 2;
+ new->st.st_blocks >>= 1;
if (flags & (FLAG_a|FLAG_f)) return DIRTREE_SAVE;
if (!(flags & FLAG_A) && new->name[0]=='.') return 0;
@@ -334,12 +321,10 @@ static void listfiles(int dirfd, struct dirtree *indir)
// Do preprocessing (Dirtree didn't populate, so callback wasn't called.)
for (;dt; dt = dt->next) filter(dt);
if (flags == (FLAG_1|FLAG_f)) return;
- } else {
- // Read directory contents. We dup() the fd because this will close it.
- // This reads/saves contents to display later, except for in "ls -1f" mode.
- dirtree_recurse(indir, filter, dup(dirfd),
+ // Read directory contents. We dup() the fd because this will close it.
+ // This reads/saves contents to display later, except for in "ls -1f" mode.
+ } else dirtree_recurse(indir, filter, dup(dirfd),
DIRTREE_SYMFOLLOW*!!(flags&FLAG_L));
- }
// Copy linked list to array and sort it. Directories go in array because
// we visit them in sorted order too. (The nested loops let us measure and
@@ -373,10 +358,8 @@ static void listfiles(int dirfd, struct dirtree *indir)
}
totpad = totals[1]+!!totals[1]+totals[6]+!!totals[6]+totals[7]+!!totals[7];
if ((flags&(FLAG_h|FLAG_l|FLAG_o|FLAG_n|FLAG_g|FLAG_s)) && indir->parent) {
- if (flags&FLAG_h) {
- human_readable(tmp, blocks*512, 0);
- xprintf("total %s\n", tmp);
- } else xprintf("total %llu\n", blocks);
+ print_with_h(tmp, blocks, 512);
+ xprintf("total %s\n", tmp);
}
}
@@ -395,7 +378,7 @@ static void listfiles(int dirfd, struct dirtree *indir)
memset(colsizes, 0, columns*sizeof(unsigned));
for (ul=0; ul<dtlen; ul++) {
entrylen(sort[next_column(ul, dtlen, columns, &c)], len);
- *len += totpad;
+ *len += totpad+1;
if (c == columns) break;
// Expand this column if necessary, break if that puts us over budget
if (*len > colsizes[c]) {
@@ -430,20 +413,22 @@ static void listfiles(int dirfd, struct dirtree *indir)
if (flags & FLAG_m) xputc(',');
if (flags & (FLAG_C|FLAG_x)) {
if (!curcol) xputc('\n');
- } else if ((flags & FLAG_1) || width+1+*len > TT.screen_width) {
+ } else if ((flags & FLAG_1) || width+2+*len > TT.screen_width) {
xputc('\n');
width = 0;
} else {
- xputc(' ');
- width++;
+ printf(" ");
+ width += 2;
}
}
width += *len;
- if (flags & FLAG_i)
- xprintf("%*lu ", totals[1], (unsigned long)st->st_ino);
- if (flags & FLAG_s)
- xprintf("%*lu ", totals[6], (unsigned long)st->st_blocks);
+ if (flags & FLAG_i) printf("%*lu ", totals[1], (unsigned long)st->st_ino);
+
+ if (flags & FLAG_s) {
+ print_with_h(tmp, st->st_blocks, 512);
+ printf("%*s ", totals[6], tmp);
+ }
if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) {
struct tm *tm;
@@ -477,15 +462,15 @@ static void listfiles(int dirfd, struct dirtree *indir)
if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
printf("% *d,% 4d", totals[5]-4, dev_major(st->st_rdev),
dev_minor(st->st_rdev));
- else if (flags&FLAG_h) {
- human_readable(tmp, st->st_size, 0);
- xprintf("%*s", totals[5]+1, tmp);
- } else printf("% *lld", totals[5]+1, (long long)st->st_size);
+ else {
+ print_with_h(tmp, st->st_size, 1);
+ printf("%*s", totals[5]+1, tmp);
+ }
// print time, always in --time-style=long-iso
tm = localtime(&(st->st_mtime));
strftime(tmp, sizeof(tmp), "%F %H:%M", tm);
- xprintf(" %s ", tmp);
+ printf(" %s ", tmp);
} else if (flags & FLAG_Z)
printf("%-*s ", (int)totals[7], (char *)sort[next]->extra);
@@ -496,7 +481,7 @@ static void listfiles(int dirfd, struct dirtree *indir)
ss = sort[next]->name;
crunch_str(&ss, INT_MAX, stdout, TT.escmore, crunch_qb);
- if (color) xprintf("\033[0m");
+ if (color) printf("\033[0m");
if ((flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) && S_ISLNK(mode)) {
printf(" -> ");
@@ -518,7 +503,7 @@ static void listfiles(int dirfd, struct dirtree *indir)
// Pad columns
if (flags & (FLAG_C|FLAG_x)) {
curcol = colsizes[curcol]-(*len)-totpad;
- if (curcol < 255) xprintf("%s", toybuf+255-curcol);
+ if (curcol < 255) printf("%s", toybuf+255-curcol);
}
}
diff --git a/toys/posix/nohup.c b/toys/posix/nohup.c
index 4d6d59f6..b302cbe4 100644
--- a/toys/posix/nohup.c
+++ b/toys/posix/nohup.c
@@ -36,7 +36,7 @@ void nohup_main(void)
}
if (isatty(0)) {
close(0);
- open("/dev/null", O_RDONLY);
+ xopen_stdio("/dev/null", O_RDONLY);
}
xexec(toys.optargs);
}
diff --git a/toys/posix/patch.c b/toys/posix/patch.c
index 23fe83a0..fbad1fb9 100644
--- a/toys/posix/patch.c
+++ b/toys/posix/patch.c
@@ -18,21 +18,23 @@
* -F fuzz (number, default 2)
* [file] which file to patch
-USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"ulp#i:R", TOYFLAG_USR|TOYFLAG_BIN))
+USE_PATCH(NEWTOY(patch, "(dry-run)"USE_TOYBOX_DEBUG("x")"d:ulp#i:R", TOYFLAG_USR|TOYFLAG_BIN))
config PATCH
bool "patch"
default y
help
- usage: patch [-i file] [-p depth] [-Ru]
+ usage: patch [-d DIR] [-i file] [-p depth] [-Rlu] [--dry-run]
Apply a unified diff to one or more files.
+ -d modify files in DIR
-i Input file (defaults=stdin)
-l Loose match (ignore whitespace)
-p Number of '/' to strip from start of file paths (default=all)
-R Reverse patch.
-u Ignored (only handles "unified" diffs)
+ --dry-run Don't change files, just confirm patch applies
This version of patch only handles unified diffs, and only modifies
a file when all all hunks to that file apply. Patch prints failed
@@ -48,6 +50,7 @@ config PATCH
GLOBALS(
char *infile;
long prefix;
+ char *dir;
struct double_list *current_hunk;
long oldline, oldlen, newline, newlen;
@@ -102,7 +105,8 @@ static void fail_hunk(void)
TT.state = 2;
llist_traverse(TT.current_hunk, do_line);
TT.current_hunk = NULL;
- delete_tempfile(TT.filein, TT.fileout, &TT.tempname);
+ if (!(toys.optflags & FLAG_dry_run))
+ delete_tempfile(TT.filein, TT.fileout, &TT.tempname);
TT.state = 0;
}
@@ -261,9 +265,11 @@ void patch_main(void)
strip = 0;
char *oldname = NULL, *newname = NULL;
- if (TT.infile) TT.filepatch = xopen(TT.infile, O_RDONLY);
+ if (TT.infile) TT.filepatch = xopenro(TT.infile);
TT.filein = TT.fileout = -1;
+ if (TT.dir) xchdir(TT.dir);
+
// Loop through the lines in the patch
for (;;) {
char *patchline;
@@ -396,9 +402,11 @@ void patch_main(void)
TT.filein = xcreate(name, O_CREAT|O_EXCL|O_RDWR, 0666);
} else {
printf("patching %s\n", name);
- TT.filein = xopen(name, O_RDONLY);
+ TT.filein = xopenro(name);
}
- TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname);
+ if (toys.optflags & FLAG_dry_run)
+ TT.fileout = xopen("/dev/null", O_RDWR);
+ else TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname);
TT.linenum = 0;
TT.hunknum = 0;
}
diff --git a/toys/posix/printf.c b/toys/posix/printf.c
index 365b8f36..2dd1e2f1 100644
--- a/toys/posix/printf.c
+++ b/toys/posix/printf.c
@@ -33,7 +33,7 @@ static int eat(char **s, char c)
}
// Parse escape sequences.
-static int handle_slash(char **esc_val)
+static int handle_slash(char **esc_val, int posix)
{
char *ptr = *esc_val;
int len, base = 0;
@@ -43,7 +43,10 @@ static int handle_slash(char **esc_val)
// 0x12 hex escapes have 1-2 digits, \123 octal escapes have 1-3 digits.
if (eat(&ptr, 'x')) base = 16;
- else if (*ptr >= '0' && *ptr <= '8') base = 8;
+ else {
+ if (posix && *ptr=='0') ptr++;
+ if (*ptr >= '0' && *ptr <= '7') base = 8;
+ }
len = (char []){0,3,2}[base/8];
// Not a hex or octal escape? (This catches trailing \)
@@ -85,7 +88,7 @@ void printf_main(void)
// Loop through characters in format
while (*f) {
- if (eat(&f, '\\')) putchar(handle_slash(&f));
+ if (eat(&f, '\\')) putchar(handle_slash(&f, 0));
else if (!eat(&f, '%') || *f == '%') putchar(*f++);
// Handle %escape
@@ -110,7 +113,7 @@ void printf_main(void)
// Output %esc using parsed format string
if (c == 'b') {
- while (*aa) putchar(eat(&aa, '\\') ? handle_slash(&aa) : *aa++);
+ while (*aa) putchar(eat(&aa, '\\') ? handle_slash(&aa, 1) : *aa++);
continue;
} else if (c == 'c') printf(toybuf, wp[0], wp[1], *aa);
diff --git a/toys/posix/ps.c b/toys/posix/ps.c
index bfd6807a..6a128bde 100644
--- a/toys/posix/ps.c
+++ b/toys/posix/ps.c
@@ -43,12 +43,12 @@
* TODO: top: thread support and SMP
* TODO: pgrep -f only searches the amount of cmdline that fits in toybuf.
-USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
// stayroot because iotop needs root to read other process' proc/$$/io
-USE_TOP(NEWTOY(top, ">0m" "Hk*o*p*u*s#<1=9d#=3<1n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_TOP(NEWTOY(top, ">0m" "O*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
USE_IOTOP(NEWTOY(iotop, ">0AaKO" "k*o*p*u*s#<1=7d#=3<1n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_PKILL(NEWTOY(pkill, "Vu*U*t*s*P*g*G*fnovxl:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_PKILL(NEWTOY(pkill, "?Vu*U*t*s*P*g*G*fnovxl:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
config PS
bool "ps"
@@ -83,23 +83,26 @@ config PS
Which FIELDs to show. (Default = -o PID,TTY,TIME,CMD)
- -f Full listing (-o USER:8=UID,PID,PPID,C,STIME,TTY,TIME,CMD)
+ -f Full listing (-o USER:8=UID,PID,PPID,C,STIME,TTY,TIME,ARGS=CMD)
-l Long listing (-o F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD)
-o Output FIELDs instead of defaults, each with optional :size and =title
-O Add FIELDS to defaults
-Z Include LABEL
- Available -o FIELDs:
+ Command line -o fields:
- ADDR Instruction pointer ARGS Command line (argv[] -path)
- BIT Is this process 32 or 64 bits
- CMD COMM, or ARGS with -f CMDLINE Command line (argv[])
- COMM Original command name COMMAND Original command path
+ ARGS CMDLINE minus initial path CMD Command (thread) name (stat[2])
+ CMDLINE Command line (argv[]) COMM Command filename (/proc/$PID/exe)
+ COMMAND Command file (/proc/$PID/exe) NAME Process name (argv[0] of $PID)
+
+ Process attribute -o FIELDs:
+
+ ADDR Instruction pointer BIT Is this process 32 or 64 bits
CPU Which processor running on ETIME Elapsed time since PID start
F Flags (1=FORKNOEXEC 4=SUPERPRIV) GID Group id
GROUP Group name LABEL Security label
MAJFL Major page faults MINFL Minor page faults
- NAME Command name (argv[0]) NI Niceness (lower is faster)
+ NI Niceness (lower is faster)
PCPU Percentage of CPU time used PCY Android scheduling policy
PGID Process Group ID
PID Process ID PPID Parent Process ID
@@ -120,10 +123,11 @@ config PS
TIME CPU time consumed TTY Controlling terminal
UID User id USER User name
VSZ Virtual memory size (1k units) %VSZ VSZ as % of physical memory
- WCHAN Waiting in kernel for
+ WCHAN What are we waiting in kernel for
config TOP
bool "top"
+ depends on TOP_COMMON
default y
help
usage: top [-H] [-k FIELD,] [-o FIELD,] [-s SORT]
@@ -133,11 +137,13 @@ config TOP
-H Show threads
-k Fallback sort FIELDS (default -S,-%CPU,-ETIME,-PID)
-o Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)
+ -O Add FIELDS (replacing PR,NI,VIRT,RES,SHR,S from default)
-s Sort by field number (1-X, default 9)
# Requires CONFIG_IRQ_TIME_ACCOUNTING in the kernel for /proc/$$/io
config IOTOP
bool "iotop"
+ depends on TOP_COMMON
default y
help
usage: iotop [-AaKO]
@@ -156,7 +162,7 @@ config TOP_COMMON
bool
default y
help
- usage: COMMON [-bq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]
+ usage: * [-bq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]
-b Batch mode (no tty)
-d Delay SECONDS between each cycle (default 3)
@@ -183,11 +189,21 @@ config PGREP
-L Send SIGNAL instead of printing name
-l Show command name
+config PKILL
+ bool "pkill"
+ default y
+ depends on PGKILL_COMMON
+ help
+ usage: pkill [-SIGNAL|-l SIGNAL] [PATTERN]
+
+ -l Send SIGNAL (default SIGTERM)
+ -V verbose
+
config PGKILL_COMMON
bool
default y
help
- usage: pgrep [-fnovx] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]
+ usage: * [-fnovx] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]
-f Check full command line for PATTERN
-G Match real Group ID(s)
@@ -201,15 +217,6 @@ config PGKILL_COMMON
-u Match effective User ID(s)
-v Negate the match
-x Match whole command (not substring)
-
-config PKILL
- bool "pkill"
- default y
- help
- usage: pkill [-l SIGNAL] [PATTERN]
-
- -l SIGNAL to send
- -V verbose
*/
#define FOR_ps
@@ -238,8 +245,9 @@ GLOBALS(
struct arg_list *p;
struct arg_list *o;
struct arg_list *k;
+ struct arg_list *O;
} top;
- struct{
+ struct {
char *L;
struct arg_list *G;
struct arg_list *g;
@@ -258,6 +266,7 @@ GLOBALS(
struct sysinfo si;
struct ptr_len gg, GG, pp, PP, ss, tt, uu, UU;
+ struct dirtree *threadparent;
unsigned width, height;
dev_t tty;
void *fields, *kfields;
@@ -315,7 +324,7 @@ enum {
// Data layout in toybuf
struct carveup {
long long slot[SLOT_count]; // data (see enum above)
- unsigned short offset[5]; // offset of fields in str[] (skip name, always 0)
+ unsigned short offset[6]; // offset of fields in str[] (skip name, always 0)
char state;
char str[]; // name, tty, command, wchan, attr, cmdline
};
@@ -329,16 +338,16 @@ struct typography {
// Numbers
{"PID", 5, SLOT_pid}, {"PPID", 5, SLOT_ppid}, {"PRI", 3, SLOT_priority},
{"NI", 3, SLOT_nice}, {"ADDR", 4+sizeof(long), SLOT_eip},
- {"SZ", 5, SLOT_vsize}, {"RSS", 5, SLOT_rss}, {"PGID", 5, SLOT_pgrp},
- {"VSZ", 6, SLOT_vsize}, {"MAJFL", 6, SLOT_majflt}, {"MINFL", 6, SLOT_minflt},
+ {"SZ", 5, SLOT_vsize}, {"RSS", 6, SLOT_rss}, {"PGID", 5, SLOT_pgrp},
+ {"VSZ", 7, SLOT_vsize}, {"MAJFL", 6, SLOT_majflt}, {"MINFL", 6, SLOT_minflt},
{"PR", 2, SLOT_priority}, {"PSR", 3, SLOT_taskcpu},
{"RTPRIO", 6, SLOT_rtprio}, {"SCH", 3, SLOT_policy}, {"CPU", 3, SLOT_taskcpu},
{"TID", 5, SLOT_tid}, {"TCNT", 4, SLOT_tcount}, {"BIT", 3, SLOT_bits},
// String fields
- {"COMM", -15, -1}, {"TTY", -8, -2}, {"WCHAN", -6, -3}, {"LABEL", -30, -4},
- {"COMMAND", -27, -5}, {"CMDLINE", -27, -6}, {"ARGS", -27, -6},
- {"NAME", -15, -6}, {"CMD", -27, -1},
+ {"TTY", -8, -2}, {"WCHAN", -6, -3}, {"LABEL", -30, -4}, {"COMM", -27, -5},
+ {"NAME", -27, -7}, {"COMMAND", -27, -5}, {"CMDLINE", -27, -6},
+ {"ARGS", -27, -6}, {"CMD", -15, -1},
// user/group
{"UID", 5, SLOT_uid}, {"USER", -8, 64|SLOT_uid}, {"RUID", 4, SLOT_ruid},
@@ -378,6 +387,7 @@ static int shared_match_process(long long *slot)
// Do we have -g -G -p -P -s -t -u -U options selecting processes?
for (i = 0; i < ARRAY_LEN(match); i++) {
struct ptr_len *mm = match[i].ptr;
+
if (mm->len) {
ll = mm->ptr;
for (j = 0; j<mm->len; j++) if (ll[j] == slot[match[i].len]) return 1;
@@ -428,26 +438,30 @@ static char *string_field(struct carveup *tb, struct strawberry *field)
// String fields
} else if (sl < 0) {
- if (slot[SLOT_argv0len])
- tb->str[tb->offset[4]+slot[SLOT_argv0len]] = (which==PS_NAME) ? 0 : ' ';
out = tb->str;
sl *= -1;
+ // First string slot has offset 0, others are offset[-slot-2]
if (--sl) out += tb->offset[--sl];
- if (which==PS_ARGS)
- for (s = out; *s && *s != ' '; s++) if (*s == '/') out = s+1;
- if (which>=PS_COMMAND && (!*out || *slot != slot[SLOT_tid]))
- sprintf(out = buf, "[%s]", tb->str);
+ if (which==PS_ARGS || which==PS_COMM) {
+ int i;
+
+ s = out;
+ for (i = 0; (which==PS_ARGS) ? i < slot[SLOT_argv0len] : out[i]; i++)
+ if (out[i] == '/') s = out+i+1;
+ out = s;
+ }
+ if (which>=PS_COMM && !*out) sprintf(out = buf, "[%s]", tb->str);
// user/group
} else if (which <= PS_RGROUP) {
sprintf(out, "%lld", ll);
if (sl&64) {
if (which > PS_RUSER) {
- struct group *gr = getgrgid(ll);
+ struct group *gr = bufgetgrgid(ll);
if (gr) out = gr->gr_name;
} else {
- struct passwd *pw = getpwuid(ll);
+ struct passwd *pw = bufgetpwuid(ll);
if (pw) out = pw->pw_name;
}
@@ -533,21 +547,44 @@ static char *string_field(struct carveup *tb, struct strawberry *field)
static void show_ps(struct carveup *tb)
{
struct strawberry *field;
- int pad, len, width = TT.width;
+ int pad, len, width = TT.width, abslen, sign, olen, extra = 0;
// Loop through fields to display
for (field = TT.fields; field; field = field->next) {
char *out = string_field(tb, field);
// Output the field, appropriately padded
+
+ // Minimum one space between each field
if (field != TT.fields) {
putchar(' ');
width--;
}
- len = width;
- pad = 0;
- if (field->next || field->len>0)
- len = abs(pad = width<abs(field->len) ? width : field->len);
+
+ // Don't truncate number fields, but try to reclaim extra offset from later
+ // fields that can naturally be shorter
+ abslen = abs(field->len);
+ sign = field->len<0 ? -1 : 1;
+ olen = strlen(out);
+ if (field->which<=PS_BIT && olen>abslen) {
+ // overflow but remember by how much
+ extra += olen-abslen;
+ abslen = olen;
+ } else if (extra && olen<abslen) {
+ // If later fields have slack space, take back overflow
+ olen = abslen-olen;
+ if (olen>extra) olen = extra;
+ abslen -= olen;
+ extra -= olen;
+ }
+ if (abslen>width) abslen = width;
+ len = pad = abslen;
+ pad *= sign;
+ // If last field is left justified, no trailing spaces.
+ if (!field->next && sign<0) {
+ pad = 0;
+ len = width;
+ }
if (TT.tty) width -= draw_trim(out, pad, len);
else width -= printf("%*.*s", pad, len, out);
@@ -562,12 +599,13 @@ static void show_ps(struct carveup *tb)
static int get_ps(struct dirtree *new)
{
struct {
- char *name;
- long long bits;
+ char *name; // Path under /proc/$PID directory
+ long long bits; // Only fetch extra data if an -o field is displaying it
} fetch[] = {
// sources for carveup->offset[] data
{"fd/", _PS_TTY}, {"wchan", _PS_WCHAN}, {"attr/current", _PS_LABEL},
- {"exe", _PS_COMMAND}, {"cmdline", _PS_CMDLINE|_PS_ARGS|_PS_NAME}
+ {"exe", _PS_COMMAND|_PS_COMM}, {"cmdline", _PS_CMDLINE|_PS_ARGS|_PS_NAME},
+ {"", _PS_NAME}
};
struct carveup *tb = (void *)toybuf;
long long *slot = tb->slot;
@@ -577,10 +615,13 @@ static int get_ps(struct dirtree *new)
// Recurse one level into /proc children, skip non-numeric entries
if (!new->parent)
- return DIRTREE_RECURSE|DIRTREE_SHUTUP|(DIRTREE_SAVE*!TT.show_process);
+ return DIRTREE_RECURSE|DIRTREE_SHUTUP
+ |(DIRTREE_SAVE*(TT.threadparent||!TT.show_process));
memset(slot, 0, sizeof(tb->slot));
if (!(tb->slot[SLOT_tid] = *slot = atol(new->name))) return 0;
+ if (TT.threadparent && TT.threadparent->extra)
+ if (*slot == *(((struct carveup *)TT.threadparent->extra)->slot)) return 0;
fd = dirtree_parentfd(new);
len = 2048;
@@ -596,7 +637,8 @@ static int get_ps(struct dirtree *new)
// Parse numeric fields (starting at 4th field in slot[SLOT_ppid])
if (1>sscanf(s = end, ") %c%n", &tb->state, &i)) return 0;
- for (j = 1; j<50; j++) if (1>sscanf(s += i, " %lld%n", slot+j, &i)) break;
+ for (j = 1; j<SLOT_count; j++)
+ if (1>sscanf(s += i, " %lld%n", slot+j, &i)) break;
// Now we've read the data, move status and name right after slot[] array,
// and convert low chars to ? for non-tty display while we're at it.
@@ -688,7 +730,7 @@ static int get_ps(struct dirtree *new)
// it'd almost never get used, querying length of a proc file is awkward,
// fixed buffer is nommu friendly... Wait for somebody to complain. :)
slot[SLOT_argv0len] = 0;
- for (j = 0; j<ARRAY_LEN(fetch); j++) {
+ for (j = 0; j<ARRAY_LEN(fetch); j++) {
tb->offset[j] = buf-(tb->str);
if (!(TT.bits&fetch[j].bits)) {
*buf++ = 0;
@@ -701,9 +743,30 @@ static int get_ps(struct dirtree *new)
sprintf(buf, "%lld/%s", *slot, fetch[j].name);
// For exe we readlink instead of read contents
- if (j==3) {
- if ((len = readlinkat(fd, buf, buf, len))>0) buf[len] = 0;
- else *buf = 0;
+ if (j==3 || j==5) {
+ struct carveup *ptb = 0;
+ int k;
+
+ // Thread doesn't have exe or argv[0], so use parent's
+ if (TT.threadparent && TT.threadparent->extra)
+ ptb = (void *)TT.threadparent->extra;
+
+ if (j==3 && !ptb) len = readlinkat0(fd, buf, buf, len);
+ else {
+ if (j==3) i = strlen(s = ptb->str+ptb->offset[3]);
+ else {
+ if (!ptb || tb->slot[SLOT_argv0len]) ptb = tb;
+ i = ptb->slot[SLOT_argv0len];
+ s = ptb->str+ptb->offset[4];
+ while (-1!=(k = stridx(s, '/')) && k<i) {
+ s += k+1;
+ i -= k+1;
+ }
+ }
+ if (i<len) len = i;
+ memcpy(buf, s, len);
+ buf[len] = 0;
+ }
// If it's not the TTY field, data we want is in a file.
// Last length saved in slot[] is command line (which has embedded NULs)
@@ -718,11 +781,8 @@ static int get_ps(struct dirtree *new)
for (i = 0; i<3; i++) {
sprintf(buf, "%lld/fd/%i", *slot, i);
if (!fstatat(fd, buf, &st, 0) && S_ISCHR(st.st_mode)
- && st.st_rdev == rdev && 0<(len = readlinkat(fd, buf, buf, len)))
- {
- buf[len] = 0;
- break;
- }
+ && st.st_rdev == rdev && (len = readlinkat0(fd, buf, buf, len)))
+ break;
}
// Couldn't find it, try all the tty drivers.
@@ -734,7 +794,8 @@ static int get_ps(struct dirtree *new)
while (fscanf(fp, "%*s %256s %d %*s %*s", buf, &tty_major) == 2) {
// TODO: we could parse the minor range too.
if (tty_major == maj) {
- sprintf(buf+strlen(buf), "%d", min);
+ len = strlen(buf);
+ len += sprintf(buf+len, "%d", min);
if (!stat(buf, &st) && S_ISCHR(st.st_mode) && st.st_rdev==rdev)
break;
}
@@ -744,11 +805,11 @@ static int get_ps(struct dirtree *new)
}
// Really couldn't find it, so just show major:minor.
- if (!tty_major) sprintf(buf, "%d:%d", maj, min);
+ if (!tty_major) len = sprintf(buf, "%d:%d", maj, min);
}
s = buf;
- if (strstart(&s, "/dev/")) memmove(buf, s, strlen(s)+1);
+ if (strstart(&s, "/dev/")) memmove(buf, s, len -= 5);
}
// Data we want is in a file.
@@ -759,7 +820,10 @@ static int get_ps(struct dirtree *new)
if (readfileat(fd, buf, buf, &len) && len>0) {
int temp = 0;
- if (buf[len-1]=='\n') buf[--len] = 0;
+ // Trim trailing whitespace and NUL bytes
+ while (len)
+ if (!buf[len-1] || isspace(buf[len-1])) buf[--len] = 0;
+ else break;
// Turn NUL to space, other low ascii to ? (in non-tty mode)
// cmdline has a trailing NUL that we don't want to turn to space.
@@ -772,17 +836,18 @@ static int get_ps(struct dirtree *new)
} else if (!TT.tty && c<' ') c = '?';
buf[i] = c;
}
- len = temp; // position of _first_ NUL
+ // Store end of argv[0] so ARGS and CMDLINE can differ.
+ // We do it for each file string slot but last is cmdline, which sticks.
+ slot[SLOT_argv0len] = temp ? temp : len; // Position of _first_ NUL
} else *buf = len = 0;
- // Store end of argv[0] so NAME and CMDLINE can differ.
- slot[SLOT_argv0len] = len;
}
- buf += strlen(buf)+1;
+ // Above calculated/retained len, so we don't need to re-strlen.
+ buf += len+1;
}
TT.kcount++;
- if (TT.show_process) {
+ if (TT.show_process && !TT.threadparent) {
TT.show_process(tb);
return 0;
@@ -798,41 +863,50 @@ static int get_ps(struct dirtree *new)
static int get_threads(struct dirtree *new)
{
- struct dirtree *threads, *dt;
+ struct dirtree *dt;
+ struct carveup *tb;
unsigned pid, kcount;
- void (*show_process)(void *tb) = TT.show_process;
if (!new->parent) return get_ps(new);
if (!(pid = atol(new->name))) return 0;
+ TT.threadparent = new;
+ if (!get_ps(new)) {
+ TT.threadparent = 0;
+
+ return 0;
+ }
+
// Recurse down into tasks, retaining thread groups.
- TT.show_process = 0;
- sprintf(toybuf, "/proc/%u/task", pid);
+ // Disable show_process at least until we can calculate tcount
kcount = TT.kcount;
- threads = dirtree_read(toybuf, get_ps);
- if (!threads) return 0;
+ sprintf(toybuf, "/proc/%u/task", pid);
+ new->child = dirtree_flagread(toybuf, DIRTREE_SHUTUP, get_ps);
+ TT.threadparent = 0;
+ kcount = TT.kcount-kcount+1;
+ tb = (void *)new->extra;
+ tb->slot[SLOT_tcount] = kcount;
// Fill out tid and thread count for each entry in group
- for (dt = threads->child; dt; dt = dt->next) {
- struct carveup *tb = (void *)dt->extra;
-
- tb->slot[SLOT_tid] = tb->slot[SLOT_pid];
+ if (new->child) for (dt = new->child->child; dt; dt = dt->next) {
+ tb = (void *)dt->extra;
tb->slot[SLOT_pid] = pid;
- tb->slot[SLOT_tcount] = TT.kcount - kcount;
+ tb->slot[SLOT_tcount] = kcount;
}
// Save or display
- if (!(TT.show_process = show_process)) {
- new->child = threads;
-
- return DIRTREE_SAVE;
- } while (threads->child) {
- dt = threads->child->next;
- show_process((void *)threads->child->extra);
- free(threads->child);
- threads->child = dt;
+ if (!TT.show_process) return DIRTREE_SAVE;
+ TT.show_process((void *)new->extra);
+ dt = new->child;
+ new->child = 0;
+ while (dt->child) {
+ new = dt->child->next;
+ TT.show_process((void *)dt->child->extra);
+ free(dt->child);
+ dt->child = new;
}
+ free(dt);
return 0;
}
@@ -930,6 +1004,8 @@ static char *parse_rest(void *data, char *str, int len)
if (isdigit(*str)) {
ll[pl->len] = xstrtol(str, &end, 10);
if (end==(len+str)) num++;
+ // For pkill, -s 0 represents pkill's session id.
+ if (pl==&TT.ss && ll[pl->len]==0) ll[pl->len] = getsid(0);
}
if (pl==&TT.pp || pl==&TT.ss) {
@@ -1023,8 +1099,8 @@ static struct carveup **collate_leaves(struct carveup **tb, struct dirtree *dt)
while (dt) {
struct dirtree *next = dt->next;
+ if (dt->extra) *(tb++) = (void *)dt->extra;
if (dt->child) tb = collate_leaves(tb, dt->child);
- else *(tb++) = (void *)dt->extra;
free(dt);
dt = next;
}
@@ -1097,7 +1173,7 @@ void ps_main(void)
// Figure out which fields to display
not_o = "%sTTY,TIME,CMD";
if (toys.optflags&FLAG_f)
- sprintf(not_o = toybuf+128, "USER:8=UID,%%sPPID,%s,STIME,TTY,TIME,CMD",
+ sprintf(not_o = toybuf+128, "USER:8=UID,%%sPPID,%s,STIME,TTY,TIME,ARGS=CMD",
(toys.optflags&FLAG_T) ? "TCNT" : "C");
else if (toys.optflags&FLAG_l)
not_o = "F,S,UID,%sPPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD";
@@ -1121,7 +1197,6 @@ void ps_main(void)
struct strawberry *ever;
for (ever = TT.fields; ever; ever = ever->next) {
- if ((toys.optflags&FLAG_f) && ever->which==PS_CMD) ever->which = PS_ARGS;
if ((toys.optflags&FLAG_n) && ever->which>=PS_UID
&& ever->which<=PS_RGROUP && (typos[ever->which].slot&64))
ever->which--;
@@ -1293,7 +1368,7 @@ static void top_common(
while (old.count || new.count) {
struct carveup *otb = *old.tb, *ntb = *new.tb;
- // If we just have old, discard it.
+ // If we just have old for this process, it exited. Discard it.
if (old.count && (!new.count || *otb->slot < *ntb->slot)) {
old.tb++;
old.count--;
@@ -1316,7 +1391,7 @@ static void top_common(
new.count--;
}
- // We will re-fetch no data before its time. - Mork calling Orson Welles
+ // Don't re-fetch data if it's not time yet, just re-display existing data.
for (;;) {
char was, is;
@@ -1332,17 +1407,18 @@ static void top_common(
lines = TT.height;
}
if (recalc && !(toys.optflags&FLAG_q)) {
+ // Display "top" header.
if (*toys.which->name == 't') {
struct strawberry alluc;
long long ll, up = 0;
long run[6];
int j;
+ // Count running, sleeping, stopped, zombie processes.
alluc.which = PS_S;
memset(run, 0, sizeof(run));
for (i = 0; i<mix.count; i++)
run[1+stridx("RSTZ", *string_field(mix.tb[i], &alluc))]++;
-
sprintf(toybuf,
"Tasks: %d total,%4ld running,%4ld sleeping,%4ld stopped,"
"%4ld zombie", mix.count, run[1], run[2], run[3], run[4]);
@@ -1408,10 +1484,11 @@ static void top_common(
}
get_headers(TT.fields, pos = toybuf, sizeof(toybuf));
- for (i = 0, is = *pos; *pos; pos++) {
+ for (i = 0, is = ' '; *pos; pos++) {
was = is;
is = *pos;
- if (isspace(was) && !isspace(is) && i++==TT.sortpos) pos[-1] = '[';
+ if (isspace(was) && !isspace(is) && i++==TT.sortpos && pos!=toybuf)
+ pos[-1] = '[';
if (!isspace(was) && isspace(is) && i==TT.sortpos+1) *pos = ']';
}
*pos = 0;
@@ -1486,8 +1563,6 @@ static void top_common(
static void top_setup(char *defo, char *defk)
{
- int len;
-
TT.top.d *= 1000;
if (toys.optflags&FLAG_b) TT.width = TT.height = 99999;
else {
@@ -1505,8 +1580,6 @@ static void top_setup(char *defo, char *defk)
default_ko(defo, &TT.fields, "bad -o", TT.top.o);
dlist_terminate(TT.fields);
- len = strlen(toybuf);
- if (toybuf[len-1]!=' ' && len<sizeof(toybuf)-1) strcpy(toybuf+len, " ");
// First (dummy) sort field is overwritten by setsort()
default_ko("-S", &TT.kfields, 0, 0);
@@ -1519,9 +1592,17 @@ void top_main(void)
{
// usage: [-h HEADER] -o OUTPUT -k SORT
- top_setup(
- "PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,ARGS",
- "-%CPU,-ETIME,-PID");
+ sprintf(toybuf, "PID,USER,%s%%CPU,%%MEM,TIME+,ARGS",
+ TT.top.O ? "" : "PR,NI,VIRT,RES,SHR,S,");
+ if (!TT.top.s) TT.top.s = TT.top.O ? 3 : 9;
+ top_setup(toybuf, "-%CPU,-ETIME,-PID");
+ if (TT.top.O) {
+ struct strawberry *fields = TT.fields;
+
+ fields = fields->next->next;
+ comma_args(TT.top.O, &fields, "bad -O", parse_ko);
+ }
+
top_common(merge_deltas);
}
@@ -1601,7 +1682,10 @@ static void match_pgrep(struct carveup *tb)
if ((toys.optflags&FLAG_v) ? !!reg : !reg) return;
}
- // Repurpose a field for -c count
+ // pgrep should return success if there's a match.
+ toys.exitval = 0;
+
+ // Repurpose a field for -c count.
TT.sortpos++;
if (toys.optflags&(FLAG_n|FLAG_o)) {
long long ll = tb->slot[SLOT_starttime];
@@ -1654,6 +1738,9 @@ void pgrep_main(void)
TT.match_process = pgrep_match_process;
TT.show_process = (void *)match_pgrep;
+ // pgrep should return failure if there are no matches.
+ toys.exitval = 1;
+
dirtree_read("/proc", get_ps);
if (toys.optflags&FLAG_c) printf("%d\n", TT.sortpos);
if (TT.pgrep.snapshot) {
@@ -1669,6 +1756,9 @@ void pgrep_main(void)
void pkill_main(void)
{
+ char **args = toys.optargs;
+
+ if (!(toys.optflags&FLAG_l) && *args && **args=='-') TT.pgrep.L = *(args++)+1;
if (!TT.pgrep.L) TT.pgrep.signal = SIGTERM;
if (toys.optflags & FLAG_V) TT.tty = 1;
pgrep_main();
diff --git a/toys/posix/sed.c b/toys/posix/sed.c
index 7da519d0..31268ece 100644
--- a/toys/posix/sed.c
+++ b/toys/posix/sed.c
@@ -219,41 +219,6 @@ static int emit(char *line, long len, int eol)
return 0;
}
-// Do regex matching handling embedded NUL bytes in string. Note that
-// neither the pattern nor the match can currently include NUL bytes
-// (even with wildcards) and string must be null terminated at string[len].
-// But this can find a match after the first NUL.
-static int regex_null(regex_t *preg, char *string, long len, int nmatch,
- regmatch_t pmatch[], int eflags)
-{
- char *s = string;
-
- for (;;) {
- long ll = 0;
- int rc;
-
- while (len && !*s) {
- s++;
- len--;
- }
- while (s[ll] && ll<len) ll++;
-
- rc = regexec(preg, s, nmatch, pmatch, eflags);
- if (!rc) {
- for (rc = 0; rc<nmatch && pmatch[rc].rm_so!=-1; rc++) {
- pmatch[rc].rm_so += s-string;
- pmatch[rc].rm_eo += s-string;
- }
-
- return 0;
- }
- if (ll==len) return rc;
-
- s += ll;
- len -= ll;
- }
-}
-
// Extend allocation to include new string, with newline between if newlen<0
static char *extend_string(char **old, char *new, int oldlen, int newlen)
@@ -330,7 +295,7 @@ static void process_line(char **pline, long plen)
void *rm = get_regex(command, command->rmatch[1]);
// regex match end includes matching line, so defer deactivation
- if (line && !regex_null(rm, line, len, 0, 0, 0)) miss = 1;
+ if (line && !regexec0(rm, line, len, 0, 0, 0)) miss = 1;
}
} else if (lm > 0 && lm < TT.count) command->hit = 0;
@@ -339,7 +304,7 @@ static void process_line(char **pline, long plen)
if (!(lm = *command->lmatch)) {
void *rm = get_regex(command, *command->rmatch);
- if (line && !regex_null(rm, line, len, 0, 0, 0)) command->hit++;
+ if (line && !regexec0(rm, line, len, 0, 0, 0)) command->hit++;
} else if (lm == TT.count || (lm == -1 && !pline)) command->hit++;
if (!command->lmatch[1] && !command->rmatch[1]) miss = 1;
@@ -501,7 +466,7 @@ static void process_line(char **pline, long plen)
int mflags = 0, count = 0, zmatch = 1, rlen = len, mlen, off, newlen;
// Find match in remaining line (up to remaining len)
- while (!regex_null(reg, rline, rlen, 10, match, mflags)) {
+ while (!regexec0(reg, rline, rlen, 10, match, mflags)) {
mflags = REG_NOTBOL;
// Zero length matches don't count immediately after a previous match
@@ -635,8 +600,6 @@ writenow:
if (line && !(toys.optflags & FLAG_n)) emit(line, len, eol);
done:
- free(line);
-
if (dlist_terminate(append)) while (append) {
struct append *a = append->next;
@@ -655,30 +618,7 @@ done:
free(append);
append = a;
}
-}
-
-// Genericish function, can probably get moved to lib.c
-
-// Iterate over lines in file, calling function. Function can write 0 to
-// the line pointer if they want to keep it, or 1 to terminate processing,
-// otherwise line is freed. Passed file descriptor is closed at the end.
-static void do_lines(int fd, char *name, void (*call)(char **pline, long len))
-{
- FILE *fp = fd ? xfdopen(fd, "r") : stdin;
-
- for (;;) {
- char *line = 0;
- ssize_t len;
-
- len = getline(&line, (void *)&len, fp);
- if (len > 0) {
- call(&line, len);
- if (line == (void *)1) break;
- free(line);
- } else break;
- }
-
- if (fd) fclose(fp);
+ free(line);
}
// Callback called on each input file
@@ -699,7 +639,7 @@ static void do_sed(int fd, char *name)
for (command = (void *)TT.pattern; command; command = command->next)
command->hit = 0;
}
- do_lines(fd, name, process_line);
+ do_lines(fd, process_line);
if (i) {
process_line(0, 0);
replace_tempfile(-1, TT.fdout, &tmp);
@@ -717,6 +657,7 @@ static char *unescape_delimited_string(char **pstr, char *delim)
{
char *to, *from, mode = 0, d;
+ // Grab leading delimiter (if necessary), allocate space for new string
from = *pstr;
if (!delim || !*delim) {
if (!(d = *(from++))) return 0;
@@ -730,13 +671,23 @@ static char *unescape_delimited_string(char **pstr, char *delim)
if (!*from) return 0;
// delimiter in regex character range doesn't count
- if (!mode && *from == '[') {
- mode = '[';
- if (from[1]=='-' || from[1]==']') *(to++) = *(from++);
- } else if (mode && *from == ']') mode = 0;
+ if (*from == '[') {
+ if (!mode) {
+ mode = ']';
+ if (from[1]=='-' || from[1]==']') *(to++) = *(from++);
+ } else if (mode == ']' && strchr(".=:", from[1])) {
+ *(to++) = *(from++);
+ mode = *from;
+ }
+ } else if (*from == mode) {
+ if (mode == ']') mode = 0;
+ else {
+ *(to++) = *(from++);
+ mode = ']';
+ }
// Length 1 range (X-X with same X) is "undefined" and makes regcomp err,
// but the perl build does it, so we need to filter it out.
- else if (mode && *from == '-' && from[-1] == from[1]) {
+ } else if (mode && *from == '-' && from[-1] == from[1]) {
from+=2;
continue;
} else if (*from == '\\') {
@@ -1062,9 +1013,7 @@ void sed_main(void)
// so handle all -e, then all -f. (At least the behavior's consistent.)
for (al = TT.e; al; al = al->next) parse_pattern(&al->arg, strlen(al->arg));
- for (al = TT.f; al; al = al->next)
- do_lines(strcmp(al->arg, "-") ? xopen(al->arg, O_RDONLY) : 0,
- al->arg, parse_pattern);
+ for (al = TT.f; al; al = al->next) do_lines(xopenro(al->arg), parse_pattern);
parse_pattern(0, 0);
dlist_terminate(TT.pattern);
if (TT.nextlen) error_exit("no }");
@@ -1072,8 +1021,8 @@ void sed_main(void)
TT.fdout = 1;
TT.remember = xstrdup("");
- // Inflict pattern upon input files
- loopfiles_rw(args, O_RDONLY, 0, 0, do_sed);
+ // Inflict pattern upon input files. Long version because !O_CLOEXEC
+ loopfiles_rw(args, O_RDONLY|WARN_ONLY, 0, do_sed);
if (!(toys.optflags & FLAG_i)) process_line(0, 0);
diff --git a/toys/posix/tail.c b/toys/posix/tail.c
index 787e116e..22b5ac6d 100644
--- a/toys/posix/tail.c
+++ b/toys/posix/tail.c
@@ -242,8 +242,8 @@ void tail_main(void)
if ((TT.ffd = inotify_init()) < 0) perror_exit("inotify_init");
TT.files = xmalloc(toys.optc*8);
}
- loopfiles_rw(args, O_RDONLY|(O_CLOEXEC*!(toys.optflags&FLAG_f)),
- 0, 0, do_tail);
+ loopfiles_rw(args, O_RDONLY|WARN_ONLY|(O_CLOEXEC*!(toys.optflags&FLAG_f)),
+ 0, do_tail);
if ((toys.optflags & FLAG_f) && TT.file_no) {
int len, last_fd = TT.files[(TT.file_no-1)*2], i, fd;
diff --git a/toys/posix/tee.c b/toys/posix/tee.c
index d5591b67..6167c8ad 100644
--- a/toys/posix/tee.c
+++ b/toys/posix/tee.c
@@ -49,8 +49,8 @@ void tee_main(void)
// Open output files
loopfiles_rw(toys.optargs,
- O_RDWR|O_CREAT|((toys.optflags & FLAG_a)?O_APPEND:O_TRUNC),
- 0666, 0, do_tee_open);
+ O_RDWR|O_CREAT|WARN_ONLY|((toys.optflags & FLAG_a)?O_APPEND:O_TRUNC),
+ 0666, do_tee_open);
for (;;) {
struct fd_list *fdl;
diff --git a/toys/posix/touch.c b/toys/posix/touch.c
index 22a1e2e8..cd7dd53d 100644
--- a/toys/posix/touch.c
+++ b/toys/posix/touch.c
@@ -97,7 +97,7 @@ void touch_main(void)
errno = 0;
ts->tv_sec = mktime(&tm);
- if (!s || *s || errno == EOVERFLOW) perror_exit("bad '%s'", date);
+ if (!s || *s || ts->tv_sec == -1) perror_exit("bad '%s'", date);
}
ts[1]=ts[0];
diff --git a/toys/posix/true.c b/toys/posix/true.c
index 0fbb1786..2543b821 100644
--- a/toys/posix/true.c
+++ b/toys/posix/true.c
@@ -4,8 +4,8 @@
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/true.html
-USE_TRUE(NEWTOY(true, NULL, TOYFLAG_BIN))
-USE_TRUE(OLDTOY(:, true, TOYFLAG_NOFORK))
+USE_TRUE(NEWTOY(true, NULL, TOYFLAG_BIN|TOYFLAG_NOHELP))
+USE_TRUE(OLDTOY(:, true, TOYFLAG_NOFORK|TOYFLAG_NOHELP))
config TRUE
bool "true"
diff --git a/toys/posix/uudecode.c b/toys/posix/uudecode.c
index fd557eca..238e27e9 100644
--- a/toys/posix/uudecode.c
+++ b/toys/posix/uudecode.c
@@ -30,7 +30,7 @@ void uudecode_main(void)
char *line = 0, mode[16],
*class[] = {"begin%*[ ]%15s%*[ ]%n", "begin-base64%*[ ]%15s%*[ ]%n"};
- if (toys.optc) ifd = xopen(*toys.optargs, O_RDONLY);
+ if (toys.optc) ifd = xopenro(*toys.optargs);
while (!idx) {
free(line);
diff --git a/toys/posix/uuencode.c b/toys/posix/uuencode.c
index 34ca7013..06709d5e 100644
--- a/toys/posix/uuencode.c
+++ b/toys/posix/uuencode.c
@@ -26,7 +26,7 @@ void uuencode_main(void)
int i, m = toys.optflags & FLAG_m, fd = 0;
- if (toys.optc > 1) fd = xopen(toys.optargs[0], O_RDONLY);
+ if (toys.optc > 1) fd = xopenro(toys.optargs[0]);
base64_init(toybuf);
diff --git a/toys/posix/wc.c b/toys/posix/wc.c
index e7afc813..a8c3e452 100644
--- a/toys/posix/wc.c
+++ b/toys/posix/wc.c
@@ -4,7 +4,7 @@
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/wc.html
-USE_WC(NEWTOY(wc, USE_TOYBOX_I18N("m")"cwl[!cm]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_WC(NEWTOY(wc, "mcwl", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
config WC
bool "wc"
@@ -28,68 +28,75 @@ config WC
#include "toys.h"
GLOBALS(
- unsigned long totals[3];
+ unsigned long totals[4];
)
static void show_lengths(unsigned long *lengths, char *name)
{
- int i, nospace = 1;
- for (i=0; i<3; i++) {
- if (!toys.optflags || (toys.optflags&(1<<i))) {
- xprintf(" %ld"+nospace, lengths[i]);
- nospace = 0;
+ int i, space = 7, first = 1;
+
+ for (i = 0; i<4; i++) if (toys.optflags == (1<<i)) space = 0;
+ for (i = 0; i<4; i++) {
+ if (toys.optflags&(1<<i)) {
+ printf(" %*ld"+first, space, lengths[i]);
+ first = 0;
}
TT.totals[i] += lengths[i];
}
- if (*toys.optargs) xprintf(" %s", name);
+ if (*toys.optargs) printf(" %s", name);
xputc('\n');
}
static void do_wc(int fd, char *name)
{
- int i, len, clen=1, space;
- unsigned long word=0, lengths[]={0,0,0};
+ int len = 0, clen = 1, space = 0;
+ unsigned long word = 0, lengths[] = {0,0,0,0};
+ // Speed up common case: wc -c normalfile is file length.
if (toys.optflags == FLAG_c) {
struct stat st;
// On Linux, files in /proc often report their size as 0.
- if (!fstat(fd, &st) && S_ISREG(st.st_mode) && st.st_size > 0) {
+ if (!fstat(fd, &st) && S_ISREG(st.st_mode) && st.st_size) {
lengths[2] = st.st_size;
goto show;
}
}
for (;;) {
- len = read(fd, toybuf, sizeof(toybuf));
- if (len<0) perror_msg_raw(name);
- if (len<1) break;
- if (toys.optflags == FLAG_c) {
- lengths[2] += len;
- continue;
- }
- for (i=0; i<len; i+=clen) {
- wchar_t wchar;
-
- if (CFG_TOYBOX_I18N && (toys.optflags&FLAG_m)) {
- clen = mbrtowc(&wchar, toybuf+i, len-i, 0);
- if (clen == -1) {
- clen = 1;
- continue;
+ int pos, done = 0, len2 = read(fd, toybuf+len, sizeof(toybuf)-len);
+
+ if (len2<0) perror_msg_raw(name);
+ else len += len2;
+ if (len2<1) done++;
+
+ for (pos = 0; pos<len; pos++) {
+ if (toybuf[pos]=='\n') lengths[0]++;
+ lengths[2]++;
+ if (toys.optflags&FLAG_m) {
+ // If we've consumed next wide char
+ if (--clen<1) {
+ wchar_t wchar;
+
+ // next wide size, don't count invalid, fetch more data if necessary
+ clen = mbrtowc(&wchar, toybuf+pos, len-pos, 0);
+ if (clen == -1) continue;
+ if (clen == -2 && !done) break;
+
+ lengths[3]++;
+ space = iswspace(wchar);
}
- if (clen == -2) break;
- if (clen == 0) clen=1;
- space = iswspace(wchar);
- } else space = isspace(toybuf[i]);
+ } else space = isspace(toybuf[pos]);
- if (toybuf[i]==10) lengths[0]++;
if (space) word=0;
else {
if (!word) lengths[1]++;
word=1;
}
- lengths[2]++;
}
+ if (done) break;
+ if (pos != len) memmove(toybuf, toybuf+pos, len-pos);
+ len -= pos;
}
show:
@@ -98,7 +105,7 @@ show:
void wc_main(void)
{
- toys.optflags |= (toys.optflags&8)>>1;
+ if (!toys.optflags) toys.optflags = FLAG_l|FLAG_w|FLAG_c;
loopfiles(toys.optargs, do_wc);
if (toys.optc>1) show_lengths(TT.totals, "total");
}
diff --git a/www/code.html b/www/code.html
index c0566b4c..77b0b211 100644
--- a/www/code.html
+++ b/www/code.html
@@ -743,12 +743,8 @@ away in libc.</p></blockquote>
<li><p><b>struct passwd *xgetpwuid(uid_t uid)<br />
struct group *xgetgrgid(gid_t gid)<br />
struct passwd *xgetpwnam(char *name)</b></p>
-
-<p></p>
</li>
-
-
<li><b>void xsetuser(struct passwd *pwd)</b></li>
<li><b>char *xreadlink(char *name)</b></li>
<li><b>char *xreadfile(char *name, char *buf, off_t len)</b></li>
@@ -760,53 +756,7 @@ struct passwd *xgetpwnam(char *name)</b></p>
</ul>
<a name="lib_lib"><h3>lib/lib.c</h3>
-<p>Eight gazillion common functions:</p>
-
-<ul>
-<li><b>void verror_msg(char *msg, int err, va_list va)</b></li>
-<li><b>void error_msg(char *msg, ...)</b></li>
-<li><b>void perror_msg(char *msg, ...)</b></li>
-<li><b>void error_exit(char *msg, ...)</b></li>
-<li><b>void perror_exit(char *msg, ...)</b></li>
-<li><b>ssize_t readall(int fd, void *buf, size_t len)</b></li>
-<li><b>ssize_t writeall(int fd, void *buf, size_t len)</b></li>
-<li><b>off_t lskip(int fd, off_t offset)</b></li>
-<li><b>int mkpathat(int atfd, char *dir, mode_t lastmode, int flags)</b></li>
-<li><b>struct string_list **splitpath(char *path, struct string_list **list)</b></li>
-<li><b>struct string_list *find_in_path(char *path, char *filename)</b></li>
-<li><b>long atolx(char *numstr)</b></li>
-<li><b>long atolx_range(char *numstr, long low, long high)</b></li>
-<li><b>int numlen(long l)</b></li>
-<li><b>int stridx(char *haystack, char needle)</b></li>
-<li><b>int strstart(char **a, char *b)</b></li>
-<li><b>off_t fdlength(int fd)</b></li>
-<li><b>char *readfile(char *name, char *ibuf, off_t len)</b></li>
-<li><b>void msleep(long miliseconds)</b></li>
-<li><b>int64_t peek_le(void *ptr, unsigned size)</b></li>
-<li><b>int64_t peek_be(void *ptr, unsigned size)</b></li>
-<li><b>int64_t peek(void *ptr, unsigned size)</b></li>
-<li><b>void poke(void *ptr, uint64_t val, int size)</b></li>
-<li><b>void loopfiles_rw(char **argv, int flags, int permissions, int failok,</b></li>
-<li><b>void loopfiles(char **argv, void (*function)(int fd, char *name))</b></li>
-<li><b>char *get_rawline(int fd, long *plen, char end)</b></li>
-<li><b>char *get_line(int fd)</b></li>
-<li><b>int wfchmodat(int fd, char *name, mode_t mode)</b></li>
-<li><b>static void tempfile_handler(int i)</b></li>
-<li><b>int copy_tempfile(int fdin, char *name, char **tempname)</b></li>
-<li><b>void delete_tempfile(int fdin, int fdout, char **tempname)</b></li>
-<li><b>void replace_tempfile(int fdin, int fdout, char **tempname)</b></li>
-<li><b>void crc_init(unsigned int *crc_table, int little_endian)</b></li>
-<li><b>int terminal_size(unsigned *xx, unsigned *yy)</b></li>
-<li><b>int yesno(char *prompt, int def)</b></li>
-<li><b>void generic_signal(int sig)</b></li>
-<li><b>void sigatexit(void *handler)</b></li>
-<li><b>int sig_to_num(char *pidstr)</b></li>
-<li><b>char *num_to_sig(int sig)</b></li>
-<li><b>mode_t string_to_mode(char *modestr, mode_t mode)</b></li>
-<li><b>void mode_to_string(mode_t mode, char *buf)</b></li>
-<li><b>void names_to_pid(char **names, int (*callback)(pid_t pid, char *name))</b></li>
-<li><b>int human_readable(char *buf, unsigned long long num)</b></li>
-</ul>
+<p>Eight gazillion common functions, see lib/lib.h for the moment:</p>
<h3>lib/portability.h</h3>
@@ -1087,6 +1037,15 @@ in the same order they're declared, and that padding won't be inserted between
consecutive variables of register size. Thus the first few entries can
be longs or pointers corresponding to the saved arguments.</p>
+<p>The main downside is that numeric arguments ("#" and "-" format)
+are limited to +- 2 billion on 32 bit platforms (the "truncate -s 8G"
+problem), because long is only 64 bits on 64 bit hosts, so the capabilities
+of some tools differ when built in 32 bit vs 64 bit mode. Fixing this
+kind of ugly and even embedded designs are slowly moving to 64 bits,
+so our current plan is to document the problem and wait it out. (If
+"x32 mode" and similar becomes popular enough, we may revisit this
+decision.)</p>
+
<p>See toys/example/*.c for longer examples of parsing options into the
GLOBALS block.</p>
diff --git a/www/design.html b/www/design.html
index 050c953f..993a7f78 100755..100644
--- a/www/design.html
+++ b/www/design.html
@@ -216,6 +216,22 @@ usage), and avoiding unnecessary work makes code run faster. Smaller code
also tends to run faster on modern hardware due to CPU cacheing: fitting your
code into L1 cache is great, and staying in L2 cache is still pretty good.</p>
+<p>But a simple implementation is not always the smallest or fastest, and
+balancing simplicity vs the other goals can be difficult. For example, the
+atolx_range() function in lib/lib.c uses the always 64 bit "long long" type,
+which produces larger and slower code on 32 bit platforms and
+often assigned into smaller interger types. Although libc has parallel
+implementations for different data sizes (atoi, atol, atoll) we only
+used the largest, which can cover all cases.</p>
+
+<p>On the other hand, the "tail" command has two codepaths, one for seekable
+files and one for nonseekable files. Although the nonseekable case can handle
+all inputs (and is required when input comes from a pipe or similar, so cannot
+be removed), reading through multiple gigabytes of data to reach the end of
+seekable files was both a common case and hugely penalized by a nonseekable
+approach (half-minute wait vs instant results). This is one example
+where performance did outweigh simplicity of implementation.</p>
+
<p><a href=http://www.joelonsoftware.com/articles/fog0000000069.html>Joel
Spolsky argues against throwing code out and starting over</a>, and he has
good points: an existing debugged codebase contains a huge amount of baked
@@ -243,6 +259,13 @@ the GNU tools were yet another rewrite intended for use in the stillborn
were written in Plan 9, uclinux, klibc, sash, sbase, s6, and of course
android toolbox...) but maybe toybox can do a better job. :)</p>
+<p>As Antoine de St. Exupery (author of "The Little Prince" and an early
+aircraft designer) said, "Perfection is achieved, not when there
+is nothing left to add, but when there is nothing left to take away."
+And Ken Thompson (creator of Unix) said "One of my most productive
+days was throwing away 1000 lines of code." It's always possible to
+come up with a better way to do it.</p>
+
<p>P.S. How could I resist linking to an article about
<a href=http://blog.outer-court.com/archive/2005-08-24-n14.html>why
programmers should strive to be lazy and dumb</a>?</p>
@@ -266,12 +289,13 @@ older kernels or other implementations (ala BSD), but we don't police their
corner cases.</p>
<b><h3>32/64 bit</h3></b>
-<p>Toybox should work on both 32 bit and 64 bit systems. By the end of 2008
-64 bit hardware will be the new desktop standard, but 32 bit hardware will
-continue to be important in embedded devices for years to come.</p>
+<p>Toybox should work on both 32 bit and 64 bit systems. 64 bit desktop
+hardware went mainstream in 2005 and was essentially ubiquitous
+by the end of the decade, but 32 bit hardware will continue to be important
+in embedded devices for several more years.</p>
<p>Toybox relies on the fact that on any Unix-like platform, pointer and long
-are always the same size (on both 32 and 64 bit). Pointer and int are _not_
+are always the same size (on both 32 and 64 bit). Pointer and int are _not_
the same size on 64 bit systems, but pointer and long are.</p>
<p>This is guaranteed by the LP64 memory model, a Unix standard (which Linux
@@ -329,6 +353,28 @@ of it.)</p>
<p>Locale support isn't currently a goal; that's a presentation layer issue
(I.E. a GUI problem).</p>
+<p><h3>Shared Libraries</h3></p>
+
+<p>Toybox's policy on shared libraries is that they should never be
+required, but can optionally be used to improve performance.</p>
+
+<p>Toybox should provide the command line utilities for
+<a href=roadmap.html#dev_env>self-hosting development evirionments</a>,
+and an easy way to set up "hermetic builds" (I.E. builds which provide
+their own dependencies, isolating the build logic from host command version
+skew with a simple known build environment). In both cases, external
+dependencies defeat the purpose.</p>
+
+<p>This means toybox should provide full functionality without relying
+on any external dependencies (other than libc). But toybox may optionally use
+libraries such as zlib and openssl to improve performance for things like
+deflate and sha1sum, which lets the corresponding built-in implementations
+be simple (and thus slow). But the built-in implementations need to exist and
+work.</p>
+
+<p>(This is why we use an external https wrapper program, because depending on
+openssl or similar to be linked in would change the behavior of toybox.)</p>
+
<a name="codestyle" />
<h2>Coding style</h2>
diff --git a/www/faq.html b/www/faq.html
new file mode 100755
index 00000000..52ea6f5b
--- /dev/null
+++ b/www/faq.html
@@ -0,0 +1,42 @@
+<html><head><title>toybox news</title>
+<!--#include file="header.html" -->
+
+<h2>Q: "Why is there toybox? What was wrong with busybox?"</h2>
+
+<p>A: To answer the first part: Toybox dates back to when its maintainer
+<a href=https://lwn.net/Articles/202106/>handed off BusyBox maintainership</a>
+and <a href=http://landley.net/notes-2006.html#28-09-2006>started over from
+scratch</a> on a new codebase after a
+<a href=http://lists.busybox.net/pipermail/busybox/2006-September/058617.html>protracted licensing argument</a> took all the fun out of
+working on BusyBox. Toybox was just a personal project until it got
+<a href=https://lwn.net/Articles/478308/>relicensed years
+later</a> after its author did a lot of thinking
+<a href=http://landley.net/talks/ohio-2013.txt>about licenses</a>
+and about <a href=http://landley.net/notes-2011.html#21-03-2011>the
+transition to smartphones</a>. This led to the
+<a href=http://landley.net/talks/celf-2013.txt>2013</a>
+<a href=https://www.youtube.com/watch?v=SGmtP5Lg_t0>talk</a> laying
+out a strategy to make Android self-hosting, which helped
+<a href=https://code.google.com/p/android/issues/detail?id=76861>bring
+it to Android's attention</a>, and they
+<a href=https://lwn.net/Articles/629362/>merged it</a> into Android M.</p>
+
+<p>To answer the second part: BusyBox predates Android
+by almost a decade, but Android still doesn't ship with it because GPLv3 came
+out around the same time Android did and caused many people to throw
+out the GPLv2 baby with the GPLv3 bathwater.
+Android <a href=https://source.android.com/source/licenses.html>explicitly
+discourages</a> use of GPL and LGPL licenses in its products, and has gradually
+reimplemented historical GPL components such as its bluetooth stack under the
+Apache license. Similarly, Apple froze xcode at the last GPLv2 releases
+(GCC 4.2.1 with binutils 2.17) for over 5 years while it sponsored the
+development of new projects (clang/llvm/lld) to replace them,
+implemented its SMB server from scratch to replace samba,
+<a href=http://meta.ath0.com/2012/02/05/apples-great-gpl-purge/>and so
+on</a>. Toybox itself exists because somebody with in a legacy position
+just wouldn't shut up about GPLv3, otherwise its maintainer would probably
+still happily be maintaining BusyBox. (For more on how said maintainer wound
+up working on busybox in the first place,
+<a href=http://landley.net/aboriginal/history.html>see here</a>.)</p>
+
+<!--#include file="footer.html" -->
diff --git a/www/roadmap.html b/www/roadmap.html
index 56067317..4cdafb0d 100755
--- a/www/roadmap.html
+++ b/www/roadmap.html
@@ -96,7 +96,7 @@ source.)</p>
alias bg cd command fc fg getopts hash jobs kill read type ulimit umask
unalias wait exit if while for case export set unset trap exec function source
</span>
-<b></blockquote>
+</b></blockquote>
<p>A few other commands are judgement calls, providing command-line
internationalization support (iconv locale localedef), System V inter-process
@@ -193,9 +193,9 @@ su sync tar umount useradd userdel usermod zcat
<a name="dev_env">
<h2><a href="#dev_env">Use case: provide a self-hosting development environment</a></h2>
-<p>The following commands are enough to build the Aboriginal Linux development
-environment, boot it to a shell prompt, and build Linux From Scratch 6.8 under
-it. (Aboriginal Linux currently uses BusyBox for this, thus provides a
+<p>The following commands are enough to build the <a href=http://landley.net/aboriginal/about.html>Aboriginal Linux</a> development
+environment, boot it to a shell prompt, and build <a href=http://www.linuxfromscratch.org/lfs/view/6.8/>Linux From Scratch 6.8</a> under
+it. (Aboriginal Linux <a href=http://landley.net/aboriginal/history.html>currently uses</a> BusyBox for this, thus providing a
drop-in test environment for toybox. We install both implementations side
by side, redirecting the symlinks a command at a time until the older
package is no longer used, and can be removed.)</p>
@@ -269,11 +269,12 @@ system/core/toolbox/Android.mk</a> the toolbox directory builds the
following commands:</p>
<blockquote><b>
-dd getevent ioctl log
-nandread newfs_msdos
-sendevent start stop top
+dd getevent newfs_msdos
</b></blockquote>
+<p>The toolbox makefile also builds the BSD grep right now, because toybox
+grep is missing <code>--color</code>.</p>
+
<h3>Other Android core commands</h3>
<p>Other than the toolbox directory, the currently interesting
@@ -297,10 +298,9 @@ implementing the full commands (fdisk, init, and sudo) come first.</p>
<p>For reference, combining everything listed above, we get:</p>
<blockquote><b>
-dd getevent init ioctl
-log logcat logwrapper nandread
+dd getevent init
+logcat logwrapper
newfs_msdos reboot run-as
-sendevent start stop top
</b></blockquote>
<p>We may eventually implement all of that, but for toybox 1.0 we need to
@@ -312,8 +312,7 @@ for later).</p>
<p>This means toybox should implement (or finish implementing):</p>
<blockquote><b>
<span id=toolbox>
-dd getevent ioctl log logcat logwrapper
-nandread newfs_msdos sendevent start stop
+dd getevent logcat logwrapper newfs_msdos
</span>
</b></blockquote>
@@ -321,7 +320,7 @@ nandread newfs_msdos sendevent start stop
of "pending". These should be a priority for cleanup:</p>
<blockquote><b>
-dd expr lsof more netstat route tar tr traceroute
+dd expr lsof more tar tr traceroute
</b></blockquote>
<p>Android wishlist:</p>