#
-# Manually-generated.
+# Automatically generated make config: don't edit
# ToyBox version: KCONFIG_VERSION
+# Wed Mar 9 02:03:44 2016
#
CONFIG_TOYBOX_CONTAINER=y
-CONFIG_TOYBOX_FALLOCATE=y
CONFIG_TOYBOX_FIFREEZE=y
-CONFIG_TOYBOX_FORK=y
-CONFIG_TOYBOX_ICONV=y
-CONFIG_TOYBOX_ON_ANDROID=y
-# CONFIG_TOYBOX_SHADOW is not set
+# CONFIG_TOYBOX_ICONV is not set
+CONFIG_TOYBOX_FALLOCATE=y
# CONFIG_TOYBOX_UTMPX is not set
+# CONFIG_TOYBOX_SHADOW is not set
+CONFIG_TOYBOX_ON_ANDROID=y
+CONFIG_TOYBOX_FORK=y
+CONFIG_TOYBOX_PRLIMIT=y
#
# Posix commands
CONFIG_ENV=y
CONFIG_EXPAND=y
CONFIG_FALSE=y
-# CONFIG_FILE is not set
+CONFIG_FILE=y
CONFIG_FIND=y
CONFIG_GREP=y
CONFIG_EGREP=y
CONFIG_HEAD=y
CONFIG_ID=y
CONFIG_ID_Z=y
-CONFIG_IONICE=y
-CONFIG_IORENICE=y
CONFIG_GROUPS=y
CONFIG_LOGNAME=y
CONFIG_WHOAMI=y
CONFIG_LN=y
CONFIG_LS=y
CONFIG_LS_COLOR=y
-CONFIG_LS_Z=y
CONFIG_MKDIR=y
CONFIG_MKDIR_Z=y
CONFIG_MKFIFO=y
CONFIG_MKFIFO_Z=y
-CONFIG_MKNOD=y
-CONFIG_MKNOD_Z=y
CONFIG_NICE=y
CONFIG_NL=y
CONFIG_NOHUP=y
-# CONFIG_NPROC is not set
CONFIG_OD=y
CONFIG_PASTE=y
CONFIG_PATCH=y
CONFIG_PRINTF=y
CONFIG_PS=y
-# CONFIG_TTOP is not set
+CONFIG_TOP=y
+CONFIG_IOTOP=y
+CONFIG_TOP_COMMON=y
+CONFIG_PGREP=y
+CONFIG_PGKILL_COMMON=y
+CONFIG_PKILL=y
CONFIG_PWD=y
CONFIG_RENICE=y
CONFIG_RM=y
CONFIG_STRINGS=y
CONFIG_TAIL=y
CONFIG_TAIL_SEEK=y
-CONFIG_TASKSET=y
CONFIG_TEE=y
CONFIG_TIME=y
CONFIG_TOUCH=y
# CONFIG_UNLINK is not set
# CONFIG_UUDECODE is not set
# CONFIG_UUENCODE is not set
-# CONFIG_VI is not set
CONFIG_WC=y
# CONFIG_WHO is not set
CONFIG_XARGS=y
#
# pending (see toys/pending/README)
#
-# CONFIG_ARP is not set
+CONFIG_ARP=y
# CONFIG_ARPING is not set
# 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
# CONFIG_DHCP is not set
# CONFIG_DHCPD is not set
# CONFIG_DEBUG_DHCP is not set
-# CONFIG_DIFF is not set
+CONFIG_DIFF=y
# CONFIG_DUMPLEASES is not set
CONFIG_EXPR=y
-# CONFIG_FDISK is not set
+CONFIG_FDISK=y
+CONFIG_FILE=y
# CONFIG_FOLD is not set
# CONFIG_FSCK is not set
-# CONFIG_FTPGET is not set
+CONFIG_FTPGET=y
+CONFIG_GETFATTR=y
# CONFIG_GETTY is not set
# CONFIG_GROUPADD is not set
# CONFIG_GROUPDEL is not set
-# CONFIG_HEXEDIT is not set
-# CONFIG_HOST is not set
-CONFIG_HWCLOCK=y
+CONFIG_HOST=y
# CONFIG_ICONV is not set
# CONFIG_INIT is not set
-# CONFIG_IOTOP is not set
# CONFIG_IP is not set
# CONFIG_IPCRM is not set
# CONFIG_IPCS is not set
CONFIG_NETSTAT=y
# CONFIG_OPENVT is not set
# CONFIG_DEALLOCVT is not set
-CONFIG_PGREP=y
-CONFIG_PKILL=y
# CONFIG_PING is not set
-# CONFIG_RESET is not set
+CONFIG_RESIZE=y
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
# CONFIG_TCPSVD is not set
-# CONFIG_TELNET is not set
+CONFIG_TELNET=y
# CONFIG_TELNETD is not set
-# CONFIG_TEST is not set
+CONFIG_TEST=y
# CONFIG_TFTP is not set
# CONFIG_TFTPD is not set
-CONFIG_TOP=y
CONFIG_TRACEROUTE=y
CONFIG_TR=y
# CONFIG_USERADD is not set
# CONFIG_USERDEL is not set
-# CONFIG_WATCH is not set
-# CONFIG_XZCAT is not set
+# CONFIG_VI is not set
+CONFIG_WATCH=y
+# CONFIG_WGET is not set
+CONFIG_XZCAT=y
#
# Other commands
CONFIG_ACPI=y
CONFIG_BASE64=y
CONFIG_BLKID=y
-# CONFIG_FSTYPE is not set
+CONFIG_FSTYPE=y
CONFIG_BLOCKDEV=y
-CONFIG_BUNZIP2=y
+# CONFIG_BUNZIP2 is not set
CONFIG_BZCAT=y
CONFIG_CHCON=y
CONFIG_CHROOT=y
# CONFIG_FSYNC is not set
CONFIG_HELP=y
CONFIG_HELP_EXTRAS=y
+# CONFIG_HEXEDIT is not set
# CONFIG_HOSTID is not set
+CONFIG_HWCLOCK=y
CONFIG_IFCONFIG=y
CONFIG_INOTIFYD=y
CONFIG_INSMOD=y
+CONFIG_IONICE=y
+CONFIG_IORENICE=y
# CONFIG_LOGIN is not set
CONFIG_LOSETUP=y
CONFIG_LSATTR=y
CONFIG_CHATTR=y
CONFIG_LSMOD=y
-# CONFIG_LSPCI is not set
+CONFIG_LSPCI=y
CONFIG_LSPCI_TEXT=y
CONFIG_LSUSB=y
CONFIG_MAKEDEVS=y
CONFIG_NBD_CLIENT=y
CONFIG_NETCAT=y
CONFIG_NETCAT_LISTEN=y
+CONFIG_NETCAT_LISTEN_TTY=y
# CONFIG_UNSHARE is not set
# CONFIG_NSENTER is not set
# CONFIG_ONEIT is not set
CONFIG_PMAP=y
CONFIG_PRINTENV=y
CONFIG_PWDX=y
-# CONFIG_READAHEAD is not set
+CONFIG_READAHEAD=y
CONFIG_READLINK=y
CONFIG_REALPATH=y
# CONFIG_REBOOT is not set
+CONFIG_RESET=y
CONFIG_REV=y
CONFIG_RFKILL=y
CONFIG_RMMOD=y
CONFIG_STAT=y
CONFIG_SWAPOFF=y
CONFIG_SWAPON=y
-CONFIG_SWITCH_ROOT=y
+# CONFIG_SWITCH_ROOT is not set
CONFIG_SYSCTL=y
CONFIG_TAC=y
+CONFIG_NPROC=y
CONFIG_TASKSET=y
CONFIG_TIMEOUT=y
CONFIG_TRUNCATE=y
+CONFIG_TUNCTL=y
CONFIG_UPTIME=y
CONFIG_USLEEP=y
CONFIG_VCONFIG=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
CONFIG_MOUNT=y
# CONFIG_PASSWD is not set
+# CONFIG_PASSWD_SAD is not set
CONFIG_PIDOF=y
CONFIG_SEQ=y
# CONFIG_SU is not set
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
#
#
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 is not set
+CONFIG_TOYBOX_NORECURSE=y
# CONFIG_TOYBOX_DEBUG is not set
CONFIG_TOYBOX_UID_SYS=100
CONFIG_TOYBOX_UID_USR=500
LOCAL_PATH := $(call my-dir)
+common_cflags := \
+ -std=c99 \
+ -Os \
+ -Wno-char-subscripts \
+ -Wno-sign-compare \
+ -Wno-string-plus-int \
+ -Wno-uninitialized \
+ -Wno-unused-parameter \
+ -funsigned-char \
+ -ffunction-sections -fdata-sections \
+ -fno-asynchronous-unwind-tables \
+
+toybox_upstream_version := $(shell grep -o 'TOYBOX_VERSION.*\".*\"' $(LOCAL_PATH)/main.c | cut -d'"' -f2)
+toybox_sha := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)
+
+toybox_version := $(toybox_upstream_version)-$(toybox_sha)-android
+common_cflags += -DTOYBOX_VERSION='"$(toybox_version)"'
+
#
# To update:
#
# 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.
lib/linestack.c \
lib/llist.c \
lib/net.c \
+ lib/password.c \
lib/portability.c \
lib/xwrap.c \
main.c \
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 \
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 \
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 \
toys/other/losetup.c \
toys/other/lsattr.c \
toys/other/lsmod.c \
+ toys/other/lspci.c \
toys/other/lsusb.c \
toys/other/makedevs.c \
toys/other/mkswap.c \
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 \
toys/other/printenv.c \
toys/other/pwdx.c \
+ toys/other/readahead.c \
toys/other/readlink.c \
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 \
toys/other/swapon.c \
- toys/other/switch_root.c \
toys/other/sysctl.c \
toys/other/tac.c \
toys/other/taskset.c \
toys/other/which.c \
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/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 \
+ toys/pending/telnet.c \
+ toys/pending/test.c \
toys/pending/tr.c \
toys/pending/traceroute.c \
+ toys/pending/watch.c \
+ toys/pending/xzcat.c \
toys/posix/basename.c \
toys/posix/cal.c \
toys/posix/cat.c \
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 \
toys/posix/uname.c \
toys/posix/uniq.c \
toys/posix/wc.c \
- toys/posix/xargs.c \
-
-LOCAL_CFLAGS += \
- -std=c99 \
- -Os \
- -Wno-char-subscripts \
- -Wno-sign-compare \
- -Wno-string-plus-int \
- -Wno-uninitialized \
- -Wno-unused-parameter \
- -funsigned-char \
- -ffunction-sections -fdata-sections \
- -fno-asynchronous-unwind-tables \
-
-toybox_upstream_version := $(shell awk 'match($$0, /TOYBOX_VERSION.*"(.*)"/, ary) {print ary[1]}' $(LOCAL_PATH)/main.c)
-toybox_sha := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)
-
-toybox_version := $(toybox_upstream_version)-$(toybox_sha)-android
-LOCAL_CFLAGS += -DTOYBOX_VERSION='"$(toybox_version)"'
+ toys/posix/xargs.c
+LOCAL_CFLAGS := $(common_cflags)
LOCAL_CLANG := true
-LOCAL_SHARED_LIBRARIES := libcutils 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++.
LOCAL_CXX_STL := none
+LOCAL_C_INCLUDES += bionic/libc/dns/include
+
+LOCAL_MODULE := libtoybox
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+# Host binary to enumerate the toys
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := scripts/install.c
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_CLANG := true
+LOCAL_MODULE := toybox-instlist
+include $(BUILD_HOST_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := main.c
+LOCAL_STATIC_LIBRARIES := libtoybox
+LOCAL_SHARED_LIBRARIES := libcutils libselinux libcrypto
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_CXX_STL := none
+LOCAL_CLANG := true
LOCAL_MODULE := toybox
-# dupes: dd
-# useless?: freeramdisk fsfreeze install makedevs mkfifo nbd-client
-# partprobe pivot_root pwdx rev rfkill switch_root vconfig
-# prefer BSD netcat instead?: nc netcat
-# prefer efs2progs instead?: blkid chattr lsattr
+# for dumping the list of toys
+TOYBOX_INSTLIST := $(HOST_OUT_EXECUTABLES)/toybox-instlist
+LOCAL_ADDITIONAL_DEPENDENCIES := toybox_links
-ALL_TOOLS := \
- acpi \
- base64 \
- basename \
- blockdev \
- bzcat \
- cal \
- cat \
- chcon \
- chgrp \
- chmod \
- chown \
- chroot \
- cksum \
- clear \
- comm \
- cmp \
- cp \
- cpio \
- cut \
- date \
- df \
- dirname \
- dmesg \
- dos2unix \
- du \
- echo \
- env \
- expand \
- expr \
- fallocate \
- false \
- find \
- flock \
- free \
- getenforce \
- getprop \
- groups \
- head \
- hostname \
- hwclock \
- id \
- ifconfig \
- inotifyd \
- insmod \
- ionice \
- iorenice \
- kill \
- killall \
- load_policy \
- ln \
- logname \
- losetup \
- ls \
- lsmod \
- lsof \
- lsusb \
- md5sum \
- mkdir \
- mknod \
- mkswap \
- mktemp \
- modinfo \
- more \
- mount \
- mountpoint \
- mv \
- netstat \
- nice \
- nl \
- nohup \
- od \
- paste \
- patch \
- pgrep \
- pidof \
- pkill \
- pmap \
- printenv \
- printf \
- pwd \
- readlink \
- realpath \
- renice \
- restorecon \
- rm \
- rmdir \
- rmmod \
- route \
- runcon \
- sed \
- seq \
- setenforce \
- setprop \
- setsid \
- sha1sum \
- sleep \
- sort \
- split \
- stat \
- strings \
- swapoff \
- swapon \
- sync \
- sysctl \
- tac \
- tail \
- tar \
- taskset \
- tee \
- time \
- timeout \
- touch \
- tr \
- true \
- truncate \
- tty \
- ulimit \
- umount \
- uname \
- uniq \
- unix2dos \
- uptime \
- usleep \
- vmstat \
- wc \
- which \
- whoami \
- xargs \
- xxd \
- yes \
+# we still want a link for ps, but the toolbox version needs to
+# stick around for compatibility reasons, for now.
+TOYS_FOR_XBIN := ps
-# Install the symlinks.
-LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(ALL_TOOLS),ln -sf toybox $(TARGET_OUT)/bin/$(t);)
+# skip links for these toys in the system image, they already have
+# a full-blown counterpart. we still want them for the recovery
+# image though.
+TOYS_WITHOUT_LINKS := blkid traceroute6
+
+include $(BUILD_EXECUTABLE)
+toybox_links: $(TOYBOX_INSTLIST)
+toybox_links: TOYBOX_BINARY := $(TARGET_OUT)/bin/toybox
+toybox_links:
+ @echo "Generate Toybox links:" $$($(TOYBOX_INSTLIST))
+ @mkdir -p $(TARGET_OUT_EXECUTABLES) $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+ $(hide) $(TOYBOX_INSTLIST) | grep -vFx -f <(tr ' ' '\n' <<< '$(TOYS_FOR_XBIN) $(TOYS_WITHOUT_LINKS)') | xargs -I'{}' ln -sf toybox '$(TARGET_OUT_EXECUTABLES)/{}'
+ $(hide) tr ' ' '\n' <<< '$(TOYS_FOR_XBIN)' | xargs -I'{}' ln -sf ../bin/toybox '$(TARGET_OUT_OPTIONAL_EXECUTABLES)/{}'
+
+
+# This is used by the recovery system
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := main.c
+LOCAL_WHOLE_STATIC_LIBRARIES := libselinux libtoybox
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_CFLAGS += -Dmain=toybox_driver
+LOCAL_CXX_STL := none
+LOCAL_CLANG := true
+LOCAL_MODULE := libtoybox_driver
+include $(BUILD_STATIC_LIBRARY)
+
+# static executable for use in limited environments
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := main.c
+LOCAL_CFLAGS := $(common_cflags)
+LOCAL_CXX_STL := none
+LOCAL_CLANG := true
+LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
+LOCAL_MODULE := toybox_static
+LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
+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 libcrypto_static liblog
+LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
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
toybox_stuff: $(KCONFIG_CONFIG) *.[ch] lib/*.[ch] toys/*.h toys/*/*.c scripts/*.sh
-toybox toybox_unstripped: toybox_stuff
+toybox generated/unstripped/toybox: toybox_stuff
scripts/make.sh
.PHONY: clean distclean baseline bloatcheck install install_flat \
- uinstall uninstall_flat test tests help toybox_stuff change \
+ uinstall uninstall_flat tests help toybox_stuff change \
list list_working list_pending
include kconfig/Makefile
scripts/genconfig.sh
# Development targets
-baseline: toybox_unstripped
- @cp toybox_unstripped toybox_old
+baseline: generated/unstripped/toybox
+ @cp generated/unstripped/toybox generated/unstripped/toybox_old
-bloatcheck: toybox_old toybox_unstripped
- @scripts/bloatcheck toybox_old toybox_unstripped
+bloatcheck: toybox_old generated/unstripped/toybox
+ @scripts/bloatcheck generated/unstripped/toybox_old generated/unstripped/toybox
install_flat:
scripts/install.sh --symlink --force
scripts/change.sh
clean::
- rm -rf toybox toybox_unstripped generated change .singleconfig*
+ 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
-test: tests
-
tests:
scripts/test.sh
help::
@echo ' toybox - Build toybox.'
@echo ' COMMANDNAME - Build individual toybox command as a standalone binary.'
- @echo ' list - List COMMANDNAMEs (also list_working and list_pending).'
+ @echo ' list - List COMMANDNAMEs you can build standalone.'
+ @echo ' list_pending - List unfinished COMMANDNAMEs out of toys/pending.'
@echo ' change - Build each command standalone under change/.'
@echo ' baseline - Create toybox_old for use by bloatcheck.'
@echo ' bloatcheck - Report size differences between old and current versions'
- @echo ' test_COMMAND - Run tests for COMMAND (test_ps, test_cat, etc.)
- @echo ' test - Run test suite against all compiled commands.'
+ @echo ' test_COMMAND - Run tests for COMMAND (test_ps, test_cat, etc.)'
+ @echo ' tests - Run test suite against all compiled commands.'
@echo ' export TEST_HOST=1 to test host command, VERBOSE=1'
@echo ' to show diff, VERBOSE=fail to stop after first failure.'
@echo ' clean - Delete temporary files.'
the parent directory), and you can run a program that isn't in the $PATH by
specifying a path to it, so this should work:
- wget http://landley.net/bin/toybox-x86_64
+ wget http://landley.net/toybox/bin/toybox-x86_64
chmod +x toybox-x86_64
./toybox-x86_64 echo hello world
It works like the Linux kernel: allnoconfig, defconfig, and menuconfig edit
a ".config" file that selects which features to include in the resulting
-binary.
+binary. You can save and re-use your .config file, although may want to
+run "make oldconfig" to re-run the dependency resolver when migrating to
+new versions.
The maximum sane configuration is "make defconfig": allyesconfig isn't
recommended for toybox because it enables unfinished commands and debug code.
Toybox is not a complete operating system, it's a program that runs under
an operating system. Booting a simple system to a shell prompt requires
-three packages: an operating system kernel (Linux) to drive the hardware,
-a program for the system to run (toybox), and a C library to tie them
-together (toybox has been tested with musl, uClibc, glibc, and bionic).
+three packages: an operating system kernel (Linux*) to drive the hardware,
+one or more programs for the system to run (toybox), and a C library ("libc")
+to tie them together (toybox has been tested with musl, uClibc, glibc,
+and bionic).
The C library is part of a "toolchain", which is an integrated suite
of compiler, assembler, and linker, plus the standard headers and libraries
-necessary to build C programs.
+necessary to build C programs. (And miscellaneous binaries like nm and objdump.)
Static linking (with the --static option) copies the shared library contents
into the program, resulting in larger but more portable programs, which
release is regression tested by building Linux From Scratch under this
toybox-based system on each supported architecture, using QEMU to emulate
big and little endian systems with different word size and alignment
-requirements.
+requirements. (The eventual goal is to replace Linux From Scratch with
+the Android Open Source Project.)
+
+* Or something providing the same API such as FreeBSD's Linux emulation layer.
--- Presentations
-1) "Why Toybox?" 2013 talk here at CELF
+1) "Why Toybox?" talk at the Embedded Linux Conference in 2013
video: http://youtu.be/SGmtP5Lg_t0
outline: http://landley.net/talks/celf-2013.txt
video: http://elinux.org/ELC_2015_Presentations
outline: http://landley.net/talks/celf-2015.txt
+--- Contributing
+
+The three important URLs for communicating with the toybox project are:
+
+ web page: http://landley.net/toybox
+
+ mailing list: http://lists.landley.net/listinfo.cgi/toybox-landley.net
+
+ git repo: http://github.com/landley/toybox
+
+The maintainer prefers patches be sent to the mailing list. If you use git,
+the easy thing to do is:
+
+ git format-patch -1 $HASH
+
+Then send a file attachment. The list holds messages from non-subscribers
+for moderation, but I usually get to them in a day or two.
+
+Although I do accept pull requests on github, I download the patches and
+apply them with "git am" (which avoids gratuitous merge commits). Closing
+the pull request is then the submitter's responsibility.
+
+If I haven't responded to your patch after one week, feel free to remind
+me of it.
+
+Android's policy for toybox patches is that non-build patches should go
+upstream first (into vanilla toybox, with discussion on the toybox mailing
+list) and then be pulled into android's toybox repo from there. (They
+generally resync on fridays). The exception is patches to their build scripts
+(Android.mk and the checked-in generated/* files) which go directly to AOSP.
+
--- Code of conduct
We're using twitter's https://engineering.twitter.com/opensource/code-of-conduct
except email rob@landley.net with complaints.
+
+(Yes, I try to pay more attention to marginalized programmers, which somehow
+manages to include 51% of the population. If somebody has to be three times as
+good to get half the recognition, why WOULDN'T you adjust for that?)
#define CFG_TOYBOX_CONTAINER 1
#define USE_TOYBOX_CONTAINER(...) __VA_ARGS__
-#define CFG_TOYBOX_FALLOCATE 1
-#define USE_TOYBOX_FALLOCATE(...) __VA_ARGS__
#define CFG_TOYBOX_FIFREEZE 1
#define USE_TOYBOX_FIFREEZE(...) __VA_ARGS__
-#define CFG_TOYBOX_FORK 1
-#define USE_TOYBOX_FORK(...) __VA_ARGS__
-#define CFG_TOYBOX_ICONV 1
-#define USE_TOYBOX_ICONV(...) __VA_ARGS__
-#define CFG_TOYBOX_ON_ANDROID 1
-#define USE_TOYBOX_ON_ANDROID(...) __VA_ARGS__
-#define CFG_TOYBOX_SHADOW 0
-#define USE_TOYBOX_SHADOW(...)
+#define CFG_TOYBOX_ICONV 0
+#define USE_TOYBOX_ICONV(...)
+#define CFG_TOYBOX_FALLOCATE 1
+#define USE_TOYBOX_FALLOCATE(...) __VA_ARGS__
#define CFG_TOYBOX_UTMPX 0
#define USE_TOYBOX_UTMPX(...)
+#define CFG_TOYBOX_SHADOW 0
+#define USE_TOYBOX_SHADOW(...)
+#define CFG_TOYBOX_ON_ANDROID 1
+#define USE_TOYBOX_ON_ANDROID(...) __VA_ARGS__
+#define CFG_TOYBOX_FORK 1
+#define USE_TOYBOX_FORK(...) __VA_ARGS__
+#define CFG_TOYBOX_PRLIMIT 1
+#define USE_TOYBOX_PRLIMIT(...) __VA_ARGS__
#define CFG_BASENAME 1
#define USE_BASENAME(...) __VA_ARGS__
#define CFG_CAL 1
#define USE_EXPAND(...) __VA_ARGS__
#define CFG_FALSE 1
#define USE_FALSE(...) __VA_ARGS__
-#define CFG_FILE 0
-#define USE_FILE(...)
+#define CFG_FILE 1
+#define USE_FILE(...) __VA_ARGS__
#define CFG_FIND 1
#define USE_FIND(...) __VA_ARGS__
#define CFG_GREP 1
#define USE_ID(...) __VA_ARGS__
#define CFG_ID_Z 1
#define USE_ID_Z(...) __VA_ARGS__
-#define CFG_IONICE 1
-#define USE_IONICE(...) __VA_ARGS__
-#define CFG_IORENICE 1
-#define USE_IORENICE(...) __VA_ARGS__
#define CFG_GROUPS 1
#define USE_GROUPS(...) __VA_ARGS__
#define CFG_LOGNAME 1
#define USE_LS(...) __VA_ARGS__
#define CFG_LS_COLOR 1
#define USE_LS_COLOR(...) __VA_ARGS__
-#define CFG_LS_Z 1
-#define USE_LS_Z(...) __VA_ARGS__
#define CFG_MKDIR 1
#define USE_MKDIR(...) __VA_ARGS__
#define CFG_MKDIR_Z 1
#define USE_MKFIFO(...) __VA_ARGS__
#define CFG_MKFIFO_Z 1
#define USE_MKFIFO_Z(...) __VA_ARGS__
-#define CFG_MKNOD 1
-#define USE_MKNOD(...) __VA_ARGS__
-#define CFG_MKNOD_Z 1
-#define USE_MKNOD_Z(...) __VA_ARGS__
#define CFG_NICE 1
#define USE_NICE(...) __VA_ARGS__
#define CFG_NL 1
#define USE_NL(...) __VA_ARGS__
#define CFG_NOHUP 1
#define USE_NOHUP(...) __VA_ARGS__
-#define CFG_NPROC 0
-#define USE_NPROC(...)
#define CFG_OD 1
#define USE_OD(...) __VA_ARGS__
#define CFG_PASTE 1
#define USE_PRINTF(...) __VA_ARGS__
#define CFG_PS 1
#define USE_PS(...) __VA_ARGS__
-#define CFG_TTOP 0
-#define USE_TTOP(...)
+#define CFG_TOP 1
+#define USE_TOP(...) __VA_ARGS__
+#define CFG_IOTOP 1
+#define USE_IOTOP(...) __VA_ARGS__
+#define CFG_TOP_COMMON 1
+#define USE_TOP_COMMON(...) __VA_ARGS__
+#define CFG_PGREP 1
+#define USE_PGREP(...) __VA_ARGS__
+#define CFG_PGKILL_COMMON 1
+#define USE_PGKILL_COMMON(...) __VA_ARGS__
+#define CFG_PKILL 1
+#define USE_PKILL(...) __VA_ARGS__
#define CFG_PWD 1
#define USE_PWD(...) __VA_ARGS__
#define CFG_RENICE 1
#define USE_TAIL(...) __VA_ARGS__
#define CFG_TAIL_SEEK 1
#define USE_TAIL_SEEK(...) __VA_ARGS__
-#define CFG_TASKSET 1
-#define USE_TASKSET(...) __VA_ARGS__
#define CFG_TEE 1
#define USE_TEE(...) __VA_ARGS__
#define CFG_TIME 1
#define USE_UUDECODE(...)
#define CFG_UUENCODE 0
#define USE_UUENCODE(...)
-#define CFG_VI 0
-#define USE_VI(...)
#define CFG_WC 1
#define USE_WC(...) __VA_ARGS__
#define CFG_WHO 0
#define USE_XARGS(...) __VA_ARGS__
#define CFG_XARGS_PEDANTIC 0
#define USE_XARGS_PEDANTIC(...)
-#define CFG_ARP 0
-#define USE_ARP(...)
+#define CFG_ARP 1
+#define USE_ARP(...) __VA_ARGS__
#define CFG_ARPING 0
#define USE_ARPING(...)
#define CFG_BOOTCHARTD 0
#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
#define USE_DHCPD(...)
#define CFG_DEBUG_DHCP 0
#define USE_DEBUG_DHCP(...)
-#define CFG_DIFF 0
-#define USE_DIFF(...)
+#define CFG_DIFF 1
+#define USE_DIFF(...) __VA_ARGS__
#define CFG_DUMPLEASES 0
#define USE_DUMPLEASES(...)
#define CFG_EXPR 1
#define USE_EXPR(...) __VA_ARGS__
-#define CFG_FDISK 0
-#define USE_FDISK(...)
+#define CFG_FDISK 1
+#define USE_FDISK(...) __VA_ARGS__
+#define CFG_FILE 1
+#define USE_FILE(...) __VA_ARGS__
#define CFG_FOLD 0
#define USE_FOLD(...)
#define CFG_FSCK 0
#define USE_FSCK(...)
-#define CFG_FTPGET 0
-#define USE_FTPGET(...)
+#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
#define USE_GROUPADD(...)
#define CFG_GROUPDEL 0
#define USE_GROUPDEL(...)
-#define CFG_HEXEDIT 0
-#define USE_HEXEDIT(...)
-#define CFG_HOST 0
-#define USE_HOST(...)
-#define CFG_HWCLOCK 1
-#define USE_HWCLOCK(...) __VA_ARGS__
+#define CFG_HOST 1
+#define USE_HOST(...) __VA_ARGS__
#define CFG_ICONV 0
#define USE_ICONV(...)
#define CFG_INIT 0
#define USE_INIT(...)
-#define CFG_IOTOP 0
-#define USE_IOTOP(...)
#define CFG_IP 0
#define USE_IP(...)
#define CFG_IPCRM 0
#define USE_OPENVT(...)
#define CFG_DEALLOCVT 0
#define USE_DEALLOCVT(...)
-#define CFG_PGREP 1
-#define USE_PGREP(...) __VA_ARGS__
-#define CFG_PKILL 1
-#define USE_PKILL(...) __VA_ARGS__
#define CFG_PING 0
#define USE_PING(...)
-#define CFG_RESET 0
-#define USE_RESET(...)
+#define CFG_RESIZE 1
+#define USE_RESIZE(...) __VA_ARGS__
#define CFG_ROUTE 1
#define USE_ROUTE(...) __VA_ARGS__
#define CFG_SH 0
#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
#define USE_TAR(...) __VA_ARGS__
#define CFG_TCPSVD 0
#define USE_TCPSVD(...)
-#define CFG_TELNET 0
-#define USE_TELNET(...)
+#define CFG_TELNET 1
+#define USE_TELNET(...) __VA_ARGS__
#define CFG_TELNETD 0
#define USE_TELNETD(...)
-#define CFG_TEST 0
-#define USE_TEST(...)
+#define CFG_TEST 1
+#define USE_TEST(...) __VA_ARGS__
#define CFG_TFTP 0
#define USE_TFTP(...)
#define CFG_TFTPD 0
#define USE_TFTPD(...)
-#define CFG_TOP 1
-#define USE_TOP(...) __VA_ARGS__
#define CFG_TRACEROUTE 1
#define USE_TRACEROUTE(...) __VA_ARGS__
#define CFG_TR 1
#define USE_USERADD(...)
#define CFG_USERDEL 0
#define USE_USERDEL(...)
-#define CFG_WATCH 0
-#define USE_WATCH(...)
-#define CFG_XZCAT 0
-#define USE_XZCAT(...)
+#define CFG_VI 0
+#define USE_VI(...)
+#define CFG_WATCH 1
+#define USE_WATCH(...) __VA_ARGS__
+#define CFG_WGET 0
+#define USE_WGET(...)
+#define CFG_XZCAT 1
+#define USE_XZCAT(...) __VA_ARGS__
#define CFG_ACPI 1
#define USE_ACPI(...) __VA_ARGS__
#define CFG_BASE64 1
#define USE_BASE64(...) __VA_ARGS__
#define CFG_BLKID 1
#define USE_BLKID(...) __VA_ARGS__
-#define CFG_FSTYPE 0
-#define USE_FSTYPE(...)
+#define CFG_FSTYPE 1
+#define USE_FSTYPE(...) __VA_ARGS__
#define CFG_BLOCKDEV 1
#define USE_BLOCKDEV(...) __VA_ARGS__
-#define CFG_BUNZIP2 1
-#define USE_BUNZIP2(...) __VA_ARGS__
+#define CFG_BUNZIP2 0
+#define USE_BUNZIP2(...)
#define CFG_BZCAT 1
#define USE_BZCAT(...) __VA_ARGS__
#define CFG_CHCON 1
#define USE_HELP(...) __VA_ARGS__
#define CFG_HELP_EXTRAS 1
#define USE_HELP_EXTRAS(...) __VA_ARGS__
+#define CFG_HEXEDIT 0
+#define USE_HEXEDIT(...)
#define CFG_HOSTID 0
#define USE_HOSTID(...)
+#define CFG_HWCLOCK 1
+#define USE_HWCLOCK(...) __VA_ARGS__
#define CFG_IFCONFIG 1
#define USE_IFCONFIG(...) __VA_ARGS__
#define CFG_INOTIFYD 1
#define USE_INOTIFYD(...) __VA_ARGS__
#define CFG_INSMOD 1
#define USE_INSMOD(...) __VA_ARGS__
+#define CFG_IONICE 1
+#define USE_IONICE(...) __VA_ARGS__
+#define CFG_IORENICE 1
+#define USE_IORENICE(...) __VA_ARGS__
#define CFG_LOGIN 0
#define USE_LOGIN(...)
#define CFG_LOSETUP 1
#define USE_CHATTR(...) __VA_ARGS__
#define CFG_LSMOD 1
#define USE_LSMOD(...) __VA_ARGS__
-#define CFG_LSPCI 0
-#define USE_LSPCI(...)
+#define CFG_LSPCI 1
+#define USE_LSPCI(...) __VA_ARGS__
#define CFG_LSPCI_TEXT 1
#define USE_LSPCI_TEXT(...) __VA_ARGS__
#define CFG_LSUSB 1
#define USE_NETCAT(...) __VA_ARGS__
#define CFG_NETCAT_LISTEN 1
#define USE_NETCAT_LISTEN(...) __VA_ARGS__
+#define CFG_NETCAT_LISTEN_TTY 1
+#define USE_NETCAT_LISTEN_TTY(...) __VA_ARGS__
#define CFG_UNSHARE 0
#define USE_UNSHARE(...)
#define CFG_NSENTER 0
#define USE_PRINTENV(...) __VA_ARGS__
#define CFG_PWDX 1
#define USE_PWDX(...) __VA_ARGS__
-#define CFG_READAHEAD 0
-#define USE_READAHEAD(...)
+#define CFG_READAHEAD 1
+#define USE_READAHEAD(...) __VA_ARGS__
#define CFG_READLINK 1
#define USE_READLINK(...) __VA_ARGS__
#define CFG_REALPATH 1
#define USE_REALPATH(...) __VA_ARGS__
#define CFG_REBOOT 0
#define USE_REBOOT(...)
+#define CFG_RESET 1
+#define USE_RESET(...) __VA_ARGS__
#define CFG_REV 1
#define USE_REV(...) __VA_ARGS__
#define CFG_RFKILL 1
#define USE_SWAPOFF(...) __VA_ARGS__
#define CFG_SWAPON 1
#define USE_SWAPON(...) __VA_ARGS__
-#define CFG_SWITCH_ROOT 1
-#define USE_SWITCH_ROOT(...) __VA_ARGS__
+#define CFG_SWITCH_ROOT 0
+#define USE_SWITCH_ROOT(...)
#define CFG_SYSCTL 1
#define USE_SYSCTL(...) __VA_ARGS__
#define CFG_TAC 1
#define USE_TAC(...) __VA_ARGS__
+#define CFG_NPROC 1
+#define USE_NPROC(...) __VA_ARGS__
#define CFG_TASKSET 1
#define USE_TASKSET(...) __VA_ARGS__
#define CFG_TIMEOUT 1
#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
#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
+#define USE_MKNOD_Z(...) __VA_ARGS__
#define CFG_MKTEMP 1
#define USE_MKTEMP(...) __VA_ARGS__
#define CFG_MOUNT 1
#define USE_MOUNT(...) __VA_ARGS__
#define CFG_PASSWD 0
#define USE_PASSWD(...)
+#define CFG_PASSWD_SAD 0
+#define USE_PASSWD_SAD(...)
#define CFG_PIDOF 1
#define USE_PIDOF(...) __VA_ARGS__
#define CFG_SEQ 1
#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
#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 0
-#define USE_TOYBOX_NORECURSE(...)
+#define CFG_TOYBOX_NORECURSE 1
+#define USE_TOYBOX_NORECURSE(...) __VA_ARGS__
#define CFG_TOYBOX_DEBUG 0
#define USE_TOYBOX_DEBUG(...)
#define CFG_TOYBOX_UID_SYS 100
#undef FLAG_a
#endif
-// arp vi:nDsdap:A:H:[+Ap][!sd]
+// arp vi:nDsdap:A:H:[+Ap][!sd] vi:nDsdap:A:H:[+Ap][!sd]
#undef OPTSTR_arp
-#define OPTSTR_arp 0
+#define OPTSTR_arp "vi:nDsdap:A:H:[+Ap][!sd]"
#ifdef CLEANUP_arp
#undef CLEANUP_arp
#undef FOR_arp
// 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
#undef FLAG_s
#endif
-// base64 diw#<1[!dw] diw#<1[!dw]
+// base64 diw#<0=76[!dw] diw#<0=76[!dw]
#undef OPTSTR_base64
-#define OPTSTR_base64 "diw#<1[!dw]"
+#define OPTSTR_base64 "diw#<0=76[!dw]"
#ifdef CLEANUP_base64
#undef CLEANUP_base64
#undef FOR_base64
// blkid
#undef OPTSTR_blkid
-#define OPTSTR_blkid 0
+#define OPTSTR_blkid 0
#ifdef CLEANUP_blkid
#undef CLEANUP_blkid
#undef FOR_blkid
// bootchartd
#undef OPTSTR_bootchartd
-#define OPTSTR_bootchartd 0
+#define OPTSTR_bootchartd 0
#ifdef CLEANUP_bootchartd
#undef CLEANUP_bootchartd
#undef FOR_bootchartd
// brctl <1
#undef OPTSTR_brctl
-#define OPTSTR_brctl 0
+#define OPTSTR_brctl "<1"
#ifdef CLEANUP_brctl
#undef CLEANUP_brctl
#undef FOR_brctl
#endif
-// bunzip2 cftkv cftkv
+// bunzip2 cftkv
#undef OPTSTR_bunzip2
#define OPTSTR_bunzip2 "cftkv"
#ifdef CLEANUP_bunzip2
// bzcat
#undef OPTSTR_bzcat
-#define OPTSTR_bzcat 0
+#define OPTSTR_bzcat 0
#ifdef CLEANUP_bzcat
#undef CLEANUP_bzcat
#undef FOR_bzcat
// catv vte
#undef OPTSTR_catv
-#define OPTSTR_catv 0
+#define OPTSTR_catv "vte"
#ifdef CLEANUP_catv
#undef CLEANUP_catv
#undef FOR_catv
// cd
#undef OPTSTR_cd
-#define OPTSTR_cd 0
+#define OPTSTR_cd 0
#ifdef CLEANUP_cd
#undef CLEANUP_cd
#undef FOR_cd
// chattr
#undef OPTSTR_chattr
-#define OPTSTR_chattr 0
+#define OPTSTR_chattr 0
#ifdef CLEANUP_chattr
#undef CLEANUP_chattr
#undef FOR_chattr
#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
// 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
// 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
// count
#undef OPTSTR_count
-#define OPTSTR_count 0
+#define OPTSTR_count 0
#ifdef CLEANUP_count
#undef CLEANUP_count
#undef FOR_count
// 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
// 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
// dd
#undef OPTSTR_dd
-#define OPTSTR_dd 0
+#define OPTSTR_dd 0
#ifdef CLEANUP_dd
#undef CLEANUP_dd
#undef FOR_dd
// deallocvt >1
#undef OPTSTR_deallocvt
-#define OPTSTR_deallocvt 0
+#define OPTSTR_deallocvt ">1"
#ifdef CLEANUP_deallocvt
#undef CLEANUP_deallocvt
#undef FOR_deallocvt
// 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
// 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
// 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
#undef FLAG_P
#endif
-// diff <2>2B(ignore-blank-lines)d(minimal)b(ignore-space-change)ut(expand-tabs)w(ignore-all-space)i(ignore-case)T(initial-tab)s(report-identical-files)q(brief)a(text)L(label)*S(starting-file):N(new-file)r(recursive)U(unified)#<0=3
+// diff <2>2B(ignore-blank-lines)d(minimal)b(ignore-space-change)ut(expand-tabs)w(ignore-all-space)i(ignore-case)T(initial-tab)s(report-identical-files)q(brief)a(text)L(label)*S(starting-file):N(new-file)r(recursive)U(unified)#<0=3 <2>2B(ignore-blank-lines)d(minimal)b(ignore-space-change)ut(expand-tabs)w(ignore-all-space)i(ignore-case)T(initial-tab)s(report-identical-files)q(brief)a(text)L(label)*S(starting-file):N(new-file)r(recursive)U(unified)#<0=3
#undef OPTSTR_diff
-#define OPTSTR_diff 0
+#define OPTSTR_diff "<2>2B(ignore-blank-lines)d(minimal)b(ignore-space-change)ut(expand-tabs)w(ignore-all-space)i(ignore-case)T(initial-tab)s(report-identical-files)q(brief)a(text)L(label)*S(starting-file):N(new-file)r(recursive)U(unified)#<0=3"
#ifdef CLEANUP_diff
#undef CLEANUP_diff
#undef FOR_diff
// dos2unix
#undef OPTSTR_dos2unix
-#define OPTSTR_dos2unix 0
+#define OPTSTR_dos2unix 0
#ifdef CLEANUP_dos2unix
#undef CLEANUP_dos2unix
#undef FOR_dos2unix
// dumpleases >0arf:[!ar]
#undef OPTSTR_dumpleases
-#define OPTSTR_dumpleases 0
+#define OPTSTR_dumpleases ">0arf:[!ar]"
#ifdef CLEANUP_dumpleases
#undef CLEANUP_dumpleases
#undef FOR_dumpleases
// eject >1stT[!tT]
#undef OPTSTR_eject
-#define OPTSTR_eject 0
+#define OPTSTR_eject ">1stT[!tT]"
#ifdef CLEANUP_eject
#undef CLEANUP_eject
#undef FOR_eject
// exit
#undef OPTSTR_exit
-#define OPTSTR_exit 0
+#define OPTSTR_exit 0
#ifdef CLEANUP_exit
#undef CLEANUP_exit
#undef FOR_exit
// expr
#undef OPTSTR_expr
-#define OPTSTR_expr 0
+#define OPTSTR_expr 0
#ifdef CLEANUP_expr
#undef CLEANUP_expr
#undef FOR_expr
// factor
#undef OPTSTR_factor
-#define OPTSTR_factor 0
+#define OPTSTR_factor 0
#ifdef CLEANUP_factor
#undef CLEANUP_factor
#undef FOR_factor
// false
#undef OPTSTR_false
-#define OPTSTR_false 0
+#define OPTSTR_false 0
#ifdef CLEANUP_false
#undef CLEANUP_false
#undef FOR_false
#endif
-// fdisk C#<0H#<0S#<0b#<512ul
+// fdisk C#<0H#<0S#<0b#<512ul C#<0H#<0S#<0b#<512ul
#undef OPTSTR_fdisk
-#define OPTSTR_fdisk 0
+#define OPTSTR_fdisk "C#<0H#<0S#<0b#<512ul"
#ifdef CLEANUP_fdisk
#undef CLEANUP_fdisk
#undef FOR_fdisk
#undef FLAG_C
#endif
-// file <1
+// file <1hL[!hL] <1hL[!hL]
#undef OPTSTR_file
-#define OPTSTR_file 0
+#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]
// fold bsuw#<1
#undef OPTSTR_fold
-#define OPTSTR_fold 0
+#define OPTSTR_fold "bsuw#<1"
#ifdef CLEANUP_fold
#undef CLEANUP_fold
#undef FOR_fold
// fsck ?t:ANPRTVsC#
#undef OPTSTR_fsck
-#define OPTSTR_fsck 0
+#define OPTSTR_fsck "?t:ANPRTVsC#"
#ifdef CLEANUP_fsck
#undef CLEANUP_fsck
#undef FOR_fsck
#undef FLAG_f
#endif
-// fstype <1
+// fstype <1 <1
#undef OPTSTR_fstype
-#define OPTSTR_fstype 0
+#define OPTSTR_fstype "<1"
#ifdef CLEANUP_fstype
#undef CLEANUP_fstype
#undef FOR_fstype
// fsync <1d
#undef OPTSTR_fsync
-#define OPTSTR_fsync 0
+#define OPTSTR_fsync "<1d"
#ifdef CLEANUP_fsync
#undef CLEANUP_fsync
#undef FOR_fsync
#undef FLAG_d
#endif
-// ftpget <2cvu:p:P#<0=21>65535
+// ftpget <2cvu:p:P#<0=21>65535 <2cvu:p:P#<0=21>65535
#undef OPTSTR_ftpget
-#define OPTSTR_ftpget 0
+#define OPTSTR_ftpget "<2cvu:p:P#<0=21>65535"
#ifdef CLEANUP_ftpget
#undef CLEANUP_ftpget
#undef FOR_ftpget
#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"
// 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
// 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
// groupdel <1>2
#undef OPTSTR_groupdel
-#define OPTSTR_groupdel 0
+#define OPTSTR_groupdel "<1>2"
#ifdef CLEANUP_groupdel
#undef CLEANUP_groupdel
#undef FOR_groupdel
// groups
#undef OPTSTR_groups
-#define OPTSTR_groups 0
+#define OPTSTR_groups 0
#ifdef CLEANUP_groups
#undef CLEANUP_groups
#undef FOR_groups
// gunzip cflqStv
#undef OPTSTR_gunzip
-#define OPTSTR_gunzip 0
+#define OPTSTR_gunzip "cflqStv"
#ifdef CLEANUP_gunzip
#undef CLEANUP_gunzip
#undef FOR_gunzip
// gzip d19dcflqStvgLRz[!gLRz]
#undef OPTSTR_gzip
-#define OPTSTR_gzip 0
+#define OPTSTR_gzip "d19dcflqStvgLRz[!gLRz]"
#ifdef CLEANUP_gzip
#undef CLEANUP_gzip
#undef FOR_gzip
// hello
#undef OPTSTR_hello
-#define OPTSTR_hello 0
+#define OPTSTR_hello 0
#ifdef CLEANUP_hello
#undef CLEANUP_hello
#undef FOR_hello
// hexedit <1>1r
#undef OPTSTR_hexedit
-#define OPTSTR_hexedit 0
+#define OPTSTR_hexedit "<1>1r"
#ifdef CLEANUP_hexedit
#undef CLEANUP_hexedit
#undef FOR_hexedit
#undef FLAG_r
#endif
-// host <1>2avt:
+// host <1>2avt: <1>2avt:
#undef OPTSTR_host
-#define OPTSTR_host 0
+#define OPTSTR_host "<1>2avt:"
#ifdef CLEANUP_host
#undef CLEANUP_host
#undef FOR_host
// hostid >0
#undef OPTSTR_hostid
-#define OPTSTR_hostid 0
+#define OPTSTR_hostid ">0"
#ifdef CLEANUP_hostid
#undef CLEANUP_hostid
#undef FOR_hostid
#endif
-// hostname
+// hostname bF: bF:
#undef OPTSTR_hostname
-#define OPTSTR_hostname 0
+#define OPTSTR_hostname "bF:"
#ifdef CLEANUP_hostname
#undef CLEANUP_hostname
#undef FOR_hostname
+#undef FLAG_F
+#undef FLAG_b
#endif
// hwclock >0(fast)f(rtc):u(utc)l(localtime)t(systz)s(hctosys)r(show)w(systohc)[-ul][!rtsw] >0(fast)f(rtc):u(utc)l(localtime)t(systz)s(hctosys)r(show)w(systohc)[-ul][!rtsw]
// iconv cst:f:
#undef OPTSTR_iconv
-#define OPTSTR_iconv 0
+#define OPTSTR_iconv "cst:f:"
#ifdef CLEANUP_iconv
#undef CLEANUP_iconv
#undef FOR_iconv
// init
#undef OPTSTR_init
-#define OPTSTR_init 0
+#define OPTSTR_init 0
#ifdef CLEANUP_init
#undef CLEANUP_init
#undef FOR_init
#undef FOR_iorenice
#endif
-// iotop >0AaKOk*o*p*u*s#<1=7d#=3<1n#<1bq
+// iotop >0AaKOk*o*p*u*s#<1=7d#=3<1n#<1bq >0AaKOk*o*p*u*s#<1=7d#=3<1n#<1bq
#undef OPTSTR_iotop
-#define OPTSTR_iotop 0
+#define OPTSTR_iotop ">0AaKOk*o*p*u*s#<1=7d#=3<1n#<1bq"
#ifdef CLEANUP_iotop
#undef CLEANUP_iotop
#undef FOR_iotop
// ip
#undef OPTSTR_ip
-#define OPTSTR_ip 0
+#define OPTSTR_ip 0
#ifdef CLEANUP_ip
#undef CLEANUP_ip
#undef FOR_ip
// 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
// ipcs acptulsqmi#
#undef OPTSTR_ipcs
-#define OPTSTR_ipcs 0
+#define OPTSTR_ipcs "acptulsqmi#"
#ifdef CLEANUP_ipcs
#undef CLEANUP_ipcs
#undef FOR_ipcs
// 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
// 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
// last f:W
#undef OPTSTR_last
-#define OPTSTR_last 0
+#define OPTSTR_last "f:W"
#ifdef CLEANUP_last
#undef CLEANUP_last
#undef FOR_last
// link <2>2
#undef OPTSTR_link
-#define OPTSTR_link 0
+#define OPTSTR_link "<2>2"
#ifdef CLEANUP_link
#undef CLEANUP_link
#undef FOR_link
#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
// login >1f:ph:
#undef OPTSTR_login
-#define OPTSTR_login 0
+#define OPTSTR_login ">1f:ph:"
#ifdef CLEANUP_login
#undef CLEANUP_login
#undef FOR_login
#undef FLAG_S
#endif
-// ls (color):;ZgoACFHLRSacdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL] (color):;ZgoACFHLRSacdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL]
+// ls (color):;ZgoACFHLRSabcdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL][!qb] (color):;ZgoACFHLRSabcdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL][!qb]
#undef OPTSTR_ls
-#define OPTSTR_ls "(color):;ZgoACFHLRSacdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL]"
+#define OPTSTR_ls "(color):;ZgoACFHLRSabcdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL][!qb]"
#ifdef CLEANUP_ls
#undef CLEANUP_ls
#undef FOR_ls
#undef FLAG_f
#undef FLAG_d
#undef FLAG_c
+#undef FLAG_b
#undef FLAG_a
#undef FLAG_S
#undef FLAG_R
// lsmod
#undef OPTSTR_lsmod
-#define OPTSTR_lsmod 0
+#define OPTSTR_lsmod 0
#ifdef CLEANUP_lsmod
#undef CLEANUP_lsmod
#undef FOR_lsmod
#endif
-// lsof lp:t lp:t
+// lsof lp*t lp*t
#undef OPTSTR_lsof
-#define OPTSTR_lsof "lp:t"
+#define OPTSTR_lsof "lp*t"
#ifdef CLEANUP_lsof
#undef CLEANUP_lsof
#undef FOR_lsof
#undef FLAG_l
#endif
-// lspci emkn@i:
+// lspci emkn@i: emkn@i:
#undef OPTSTR_lspci
-#define OPTSTR_lspci 0
+#define OPTSTR_lspci "emkn@i:"
#ifdef CLEANUP_lspci
#undef CLEANUP_lspci
#undef FOR_lspci
// lsusb
#undef OPTSTR_lsusb
-#define OPTSTR_lsusb 0
+#define OPTSTR_lsusb 0
#ifdef CLEANUP_lsusb
#undef CLEANUP_lsusb
#undef FOR_lsusb
#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
// 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
// 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
// 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
// modprobe alrqvsDb
#undef OPTSTR_modprobe
-#define OPTSTR_modprobe 0
+#define OPTSTR_modprobe "alrqvsDb"
#ifdef CLEANUP_modprobe
#undef CLEANUP_modprobe
#undef FOR_modprobe
// more
#undef OPTSTR_more
-#define OPTSTR_more 0
+#define OPTSTR_more 0
#ifdef CLEANUP_more
#undef CLEANUP_more
#undef FOR_more
#undef FLAG_q
#endif
-// mv <2vnFfi[-ni] <2vnFfi[-ni]
+// mv <2vnF(remove-destination)fi[-ni] <2vnF(remove-destination)fi[-ni]
#undef OPTSTR_mv
-#define OPTSTR_mv "<2vnFfi[-ni]"
+#define OPTSTR_mv "<2vnF(remove-destination)fi[-ni]"
#ifdef CLEANUP_mv
#undef CLEANUP_mv
#undef FOR_mv
#undef FLAG_i
#undef FLAG_f
+#undef FLAG_remove_destination
#undef FLAG_F
#undef FLAG_n
#undef FLAG_v
#undef FOR_nohup
#endif
-// nproc (all)
+// nproc (all) (all)
#undef OPTSTR_nproc
-#define OPTSTR_nproc 0
+#define OPTSTR_nproc "(all)"
#ifdef CLEANUP_nproc
#undef CLEANUP_nproc
#undef FOR_nproc
// 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
#undef FLAG_F
#endif
-// od j#vN#xsodcbA:t* j#vN#xsodcbA:t*
+// od j#vw#<1=16N#xsodcbA:t* j#vw#<1=16N#xsodcbA:t*
#undef OPTSTR_od
-#define OPTSTR_od "j#vN#xsodcbA:t*"
+#define OPTSTR_od "j#vw#<1=16N#xsodcbA:t*"
#ifdef CLEANUP_od
#undef CLEANUP_od
#undef FOR_od
#undef FLAG_s
#undef FLAG_x
#undef FLAG_N
+#undef FLAG_w
#undef FLAG_v
#undef FLAG_j
#endif
// 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
// 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
// passwd >1a:dlu
#undef OPTSTR_passwd
-#define OPTSTR_passwd 0
+#define OPTSTR_passwd ">1a:dlu"
#ifdef CLEANUP_passwd
#undef CLEANUP_passwd
#undef FOR_passwd
#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)\ 1d:ulp#i:R"
#ifdef CLEANUP_patch
#undef CLEANUP_patch
#undef FOR_patch
#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]
// 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
#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
#undef FOR_printf
#endif
-// ps k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*u*U*g*G*wZ[!ol][+Ae] k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*u*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*u*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
#undef FLAG_g
#undef FLAG_U
#undef FLAG_u
+#undef FLAG_T
#undef FLAG_t
#undef FLAG_s
#undef FLAG_pid
// readahead
#undef OPTSTR_readahead
-#define OPTSTR_readahead 0
+#define OPTSTR_readahead 0
#ifdef CLEANUP_readahead
#undef CLEANUP_readahead
#undef FOR_readahead
// reboot fn
#undef OPTSTR_reboot
-#define OPTSTR_reboot 0
+#define OPTSTR_reboot "fn"
#ifdef CLEANUP_reboot
#undef CLEANUP_reboot
#undef FOR_reboot
// reset
#undef OPTSTR_reset
-#define OPTSTR_reset 0
+#define OPTSTR_reset 0
#ifdef CLEANUP_reset
#undef CLEANUP_reset
#undef FOR_reset
#endif
+// resize c#<1>63sw c#<1>63sw
+#undef OPTSTR_resize
+#define OPTSTR_resize "c#<1>63sw"
+#ifdef CLEANUP_resize
+#undef CLEANUP_resize
+#undef FOR_resize
+#undef FLAG_w
+#undef FLAG_s
+#undef FLAG_c
+#endif
+
// restorecon <1DFnRrv <1DFnRrv
#undef OPTSTR_restorecon
#define OPTSTR_restorecon "<1DFnRrv"
// rev
#undef OPTSTR_rev
-#define OPTSTR_rev 0
+#define OPTSTR_rev 0
#ifdef CLEANUP_rev
#undef CLEANUP_rev
#undef FOR_rev
#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]"
#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"
// sh c:i
#undef OPTSTR_sh
-#define OPTSTR_sh 0
+#define OPTSTR_sh "c:i"
#ifdef CLEANUP_sh
#undef CLEANUP_sh
#undef FOR_sh
#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
// 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
// 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
#undef FLAG_a
#endif
-// stat <1c:f <1c:f
+// 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:f"
+#define OPTSTR_stat "<1c:fLt"
#ifdef CLEANUP_stat
#undef CLEANUP_stat
#undef FOR_stat
+#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"
// su lmpc:s:
#undef OPTSTR_su
-#define OPTSTR_su 0
+#define OPTSTR_su "lmpc:s:"
#ifdef CLEANUP_su
#undef CLEANUP_su
#undef FOR_su
// 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
#undef FLAG_p
#endif
-// switch_root <2c:h <2c:h
+// switch_root <2c:h
#undef OPTSTR_switch_root
#define OPTSTR_switch_root "<2c:h"
#ifdef CLEANUP_switch_root
// sync
#undef OPTSTR_sync
-#define OPTSTR_sync 0
+#define OPTSTR_sync 0
#ifdef CLEANUP_sync
#undef CLEANUP_sync
#undef FOR_sync
// 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
// tac
#undef OPTSTR_tac
-#define OPTSTR_tac 0
+#define OPTSTR_tac 0
#ifdef CLEANUP_tac
#undef CLEANUP_tac
#undef FOR_tac
// 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
#undef FLAG_i
#endif
-// telnet <1>2
+// telnet <1>2 <1>2
#undef OPTSTR_telnet
-#define OPTSTR_telnet 0
+#define OPTSTR_telnet "<1>2"
#ifdef CLEANUP_telnet
#undef CLEANUP_telnet
#undef FOR_telnet
// 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
// test
#undef OPTSTR_test
-#define OPTSTR_test 0
+#define OPTSTR_test 0
#ifdef CLEANUP_test
#undef CLEANUP_test
#undef FOR_test
// 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
// 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
// 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
// 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
// tftpd rcu:l
#undef OPTSTR_tftpd
-#define OPTSTR_tftpd 0
+#define OPTSTR_tftpd "rcu:l"
#ifdef CLEANUP_tftpd
#undef CLEANUP_tftpd
#undef FOR_tftpd
#undef FLAG_v
#endif
-// top >0mk*o*p*u*s#<1=9d#=3<1n#<1bq >0mk*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 ">0mk*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
#undef FLAG_p
#undef FLAG_o
#undef FLAG_k
+#undef FLAG_H
+#undef FLAG_O
#undef FLAG_m
#endif
// toybox
#undef OPTSTR_toybox
-#define OPTSTR_toybox 0
+#define OPTSTR_toybox 0
#ifdef CLEANUP_toybox
#undef CLEANUP_toybox
#undef FOR_toybox
// true
#undef OPTSTR_true
-#define OPTSTR_true 0
+#define OPTSTR_true 0
#ifdef CLEANUP_true
#undef CLEANUP_true
#undef FOR_true
#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]"
// unix2dos
#undef OPTSTR_unix2dos
-#define OPTSTR_unix2dos 0
+#define OPTSTR_unix2dos 0
#ifdef CLEANUP_unix2dos
#undef CLEANUP_unix2dos
#undef FOR_unix2dos
// unlink <1>1
#undef OPTSTR_unlink
-#define OPTSTR_unlink 0
+#define OPTSTR_unlink "<1>1"
#ifdef CLEANUP_unlink
#undef CLEANUP_unlink
#undef FOR_unlink
// 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
// uptime
#undef OPTSTR_uptime
-#define OPTSTR_uptime 0
+#define OPTSTR_uptime 0
#ifdef CLEANUP_uptime
#undef CLEANUP_uptime
#undef FOR_uptime
// 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
// userdel <1>1r
#undef OPTSTR_userdel
-#define OPTSTR_userdel 0
+#define OPTSTR_userdel "<1>1r"
#ifdef CLEANUP_userdel
#undef CLEANUP_userdel
#undef FOR_userdel
// uudecode >1o:
#undef OPTSTR_uudecode
-#define OPTSTR_uudecode 0
+#define OPTSTR_uudecode ">1o:"
#ifdef CLEANUP_uudecode
#undef CLEANUP_uudecode
#undef FOR_uudecode
// uuencode <1>2m
#undef OPTSTR_uuencode
-#define OPTSTR_uuencode 0
+#define OPTSTR_uuencode "<1>2m"
#ifdef CLEANUP_uuencode
#undef CLEANUP_uuencode
#undef FOR_uuencode
// vi <1>1
#undef OPTSTR_vi
-#define OPTSTR_vi 0
+#define OPTSTR_vi "<1>1"
#ifdef CLEANUP_vi
#undef CLEANUP_vi
#undef FOR_vi
// w
#undef OPTSTR_w
-#define OPTSTR_w 0
+#define OPTSTR_w 0
#ifdef CLEANUP_w
#undef CLEANUP_w
#undef FOR_w
#endif
-// watch ^<1n#<0=2te
+// watch ^<1n#<0=2te ^<1n#<0=2te
#undef OPTSTR_watch
-#define OPTSTR_watch 0
+#define OPTSTR_watch "^<1n#<0=2te"
#ifdef CLEANUP_watch
#undef CLEANUP_watch
#undef FOR_watch
#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
#undef FLAG_m
#endif
+// wget f:
+#undef OPTSTR_wget
+#define OPTSTR_wget "f:"
+#ifdef CLEANUP_wget
+#undef CLEANUP_wget
+#undef FOR_wget
+#undef FLAG_f
+#endif
+
// which <1a <1a
#undef OPTSTR_which
#define OPTSTR_which "<1a"
// who a
#undef OPTSTR_who
-#define OPTSTR_who 0
+#define OPTSTR_who "a"
#ifdef CLEANUP_who
#undef CLEANUP_who
#undef FOR_who
#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
// xzcat
#undef OPTSTR_xzcat
-#define OPTSTR_xzcat 0
+#define OPTSTR_xzcat 0
#ifdef CLEANUP_xzcat
#undef CLEANUP_xzcat
#undef FOR_xzcat
// yes
#undef OPTSTR_yes
-#define OPTSTR_yes 0
+#define OPTSTR_yes 0
#ifdef CLEANUP_yes
#undef CLEANUP_yes
#undef FOR_yes
// zcat
#undef OPTSTR_zcat
-#define OPTSTR_zcat 0
+#define OPTSTR_zcat 0
#ifdef CLEANUP_zcat
#undef CLEANUP_zcat
#undef FOR_zcat
#ifndef TT
#define TT this.arp
#endif
-#define FLAG_H (FORCED_FLAG<<0)
-#define FLAG_A (FORCED_FLAG<<1)
-#define FLAG_p (FORCED_FLAG<<2)
-#define FLAG_a (FORCED_FLAG<<3)
-#define FLAG_d (FORCED_FLAG<<4)
-#define FLAG_s (FORCED_FLAG<<5)
-#define FLAG_D (FORCED_FLAG<<6)
-#define FLAG_n (FORCED_FLAG<<7)
-#define FLAG_i (FORCED_FLAG<<8)
-#define FLAG_v (FORCED_FLAG<<9)
+#define FLAG_H (1<<0)
+#define FLAG_A (1<<1)
+#define FLAG_p (1<<2)
+#define FLAG_a (1<<3)
+#define FLAG_d (1<<4)
+#define FLAG_s (1<<5)
+#define FLAG_D (1<<6)
+#define FLAG_n (1<<7)
+#define FLAG_i (1<<8)
+#define FLAG_v (1<<9)
#endif
#ifdef FOR_arping
#ifndef TT
#define TT this.bunzip2
#endif
-#define FLAG_v (1<<0)
-#define FLAG_k (1<<1)
-#define FLAG_t (1<<2)
-#define FLAG_f (1<<3)
-#define FLAG_c (1<<4)
+#define FLAG_v (FORCED_FLAG<<0)
+#define FLAG_k (FORCED_FLAG<<1)
+#define FLAG_t (FORCED_FLAG<<2)
+#define FLAG_f (FORCED_FLAG<<3)
+#define FLAG_c (FORCED_FLAG<<4)
#endif
#ifdef FOR_bzcat
#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
#ifndef TT
#define TT this.diff
#endif
-#define FLAG_unified (FORCED_FLAG<<0)
-#define FLAG_U (FORCED_FLAG<<0)
-#define FLAG_recursive (FORCED_FLAG<<1)
-#define FLAG_r (FORCED_FLAG<<1)
-#define FLAG_new_file (FORCED_FLAG<<2)
-#define FLAG_N (FORCED_FLAG<<2)
-#define FLAG_starting_file (FORCED_FLAG<<3)
-#define FLAG_S (FORCED_FLAG<<3)
-#define FLAG_label (FORCED_FLAG<<4)
-#define FLAG_L (FORCED_FLAG<<4)
-#define FLAG_text (FORCED_FLAG<<5)
-#define FLAG_a (FORCED_FLAG<<5)
-#define FLAG_brief (FORCED_FLAG<<6)
-#define FLAG_q (FORCED_FLAG<<6)
-#define FLAG_report_identical_files (FORCED_FLAG<<7)
-#define FLAG_s (FORCED_FLAG<<7)
-#define FLAG_initial_tab (FORCED_FLAG<<8)
-#define FLAG_T (FORCED_FLAG<<8)
-#define FLAG_ignore_case (FORCED_FLAG<<9)
-#define FLAG_i (FORCED_FLAG<<9)
-#define FLAG_ignore_all_space (FORCED_FLAG<<10)
-#define FLAG_w (FORCED_FLAG<<10)
-#define FLAG_expand_tabs (FORCED_FLAG<<11)
-#define FLAG_t (FORCED_FLAG<<11)
-#define FLAG_u (FORCED_FLAG<<12)
-#define FLAG_ignore_space_change (FORCED_FLAG<<13)
-#define FLAG_b (FORCED_FLAG<<13)
-#define FLAG_minimal (FORCED_FLAG<<14)
-#define FLAG_d (FORCED_FLAG<<14)
-#define FLAG_ignore_blank_lines (FORCED_FLAG<<15)
-#define FLAG_B (FORCED_FLAG<<15)
+#define FLAG_unified (1<<0)
+#define FLAG_U (1<<0)
+#define FLAG_recursive (1<<1)
+#define FLAG_r (1<<1)
+#define FLAG_new_file (1<<2)
+#define FLAG_N (1<<2)
+#define FLAG_starting_file (1<<3)
+#define FLAG_S (1<<3)
+#define FLAG_label (1<<4)
+#define FLAG_L (1<<4)
+#define FLAG_text (1<<5)
+#define FLAG_a (1<<5)
+#define FLAG_brief (1<<6)
+#define FLAG_q (1<<6)
+#define FLAG_report_identical_files (1<<7)
+#define FLAG_s (1<<7)
+#define FLAG_initial_tab (1<<8)
+#define FLAG_T (1<<8)
+#define FLAG_ignore_case (1<<9)
+#define FLAG_i (1<<9)
+#define FLAG_ignore_all_space (1<<10)
+#define FLAG_w (1<<10)
+#define FLAG_expand_tabs (1<<11)
+#define FLAG_t (1<<11)
+#define FLAG_u (1<<12)
+#define FLAG_ignore_space_change (1<<13)
+#define FLAG_b (1<<13)
+#define FLAG_minimal (1<<14)
+#define FLAG_d (1<<14)
+#define FLAG_ignore_blank_lines (1<<15)
+#define FLAG_B (1<<15)
#endif
#ifdef FOR_dirname
#ifndef TT
#define TT this.fdisk
#endif
-#define FLAG_l (FORCED_FLAG<<0)
-#define FLAG_u (FORCED_FLAG<<1)
-#define FLAG_b (FORCED_FLAG<<2)
-#define FLAG_S (FORCED_FLAG<<3)
-#define FLAG_H (FORCED_FLAG<<4)
-#define FLAG_C (FORCED_FLAG<<5)
+#define FLAG_l (1<<0)
+#define FLAG_u (1<<1)
+#define FLAG_b (1<<2)
+#define FLAG_S (1<<3)
+#define FLAG_H (1<<4)
+#define FLAG_C (1<<5)
#endif
#ifdef FOR_file
#ifndef TT
#define TT this.file
#endif
+#define FLAG_L (1<<0)
+#define FLAG_h (1<<1)
#endif
#ifdef FOR_find
#ifndef TT
#define TT this.ftpget
#endif
-#define FLAG_P (FORCED_FLAG<<0)
-#define FLAG_p (FORCED_FLAG<<1)
-#define FLAG_u (FORCED_FLAG<<2)
-#define FLAG_v (FORCED_FLAG<<3)
-#define FLAG_c (FORCED_FLAG<<4)
+#define FLAG_P (1<<0)
+#define FLAG_p (1<<1)
+#define FLAG_u (1<<2)
+#define FLAG_v (1<<3)
+#define FLAG_c (1<<4)
#endif
#ifdef FOR_getenforce
#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
#ifndef TT
#define TT this.host
#endif
-#define FLAG_t (FORCED_FLAG<<0)
-#define FLAG_v (FORCED_FLAG<<1)
-#define FLAG_a (FORCED_FLAG<<2)
+#define FLAG_t (1<<0)
+#define FLAG_v (1<<1)
+#define FLAG_a (1<<2)
#endif
#ifdef FOR_hostid
#ifndef TT
#define TT this.hostname
#endif
+#define FLAG_F (1<<0)
+#define FLAG_b (1<<1)
#endif
#ifdef FOR_hwclock
#ifndef TT
#define TT this.iotop
#endif
-#define FLAG_q (FORCED_FLAG<<0)
-#define FLAG_b (FORCED_FLAG<<1)
-#define FLAG_n (FORCED_FLAG<<2)
-#define FLAG_d (FORCED_FLAG<<3)
-#define FLAG_s (FORCED_FLAG<<4)
-#define FLAG_u (FORCED_FLAG<<5)
-#define FLAG_p (FORCED_FLAG<<6)
-#define FLAG_o (FORCED_FLAG<<7)
-#define FLAG_k (FORCED_FLAG<<8)
-#define FLAG_O (FORCED_FLAG<<9)
-#define FLAG_K (FORCED_FLAG<<10)
-#define FLAG_a (FORCED_FLAG<<11)
-#define FLAG_A (FORCED_FLAG<<12)
+#define FLAG_q (1<<0)
+#define FLAG_b (1<<1)
+#define FLAG_n (1<<2)
+#define FLAG_d (1<<3)
+#define FLAG_s (1<<4)
+#define FLAG_u (1<<5)
+#define FLAG_p (1<<6)
+#define FLAG_o (1<<7)
+#define FLAG_k (1<<8)
+#define FLAG_O (1<<9)
+#define FLAG_K (1<<10)
+#define FLAG_a (1<<11)
+#define FLAG_A (1<<12)
#endif
#ifdef FOR_ip
#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
#define FLAG_f (1<<14)
#define FLAG_d (1<<15)
#define FLAG_c (1<<16)
-#define FLAG_a (1<<17)
-#define FLAG_S (1<<18)
-#define FLAG_R (1<<19)
-#define FLAG_L (1<<20)
-#define FLAG_H (1<<21)
-#define FLAG_F (1<<22)
-#define FLAG_C (1<<23)
-#define FLAG_A (1<<24)
-#define FLAG_o (1<<25)
-#define FLAG_g (1<<26)
-#define FLAG_Z (1<<27)
-#define FLAG_color (1<<28)
+#define FLAG_b (1<<17)
+#define FLAG_a (1<<18)
+#define FLAG_S (1<<19)
+#define FLAG_R (1<<20)
+#define FLAG_L (1<<21)
+#define FLAG_H (1<<22)
+#define FLAG_F (1<<23)
+#define FLAG_C (1<<24)
+#define FLAG_A (1<<25)
+#define FLAG_o (1<<26)
+#define FLAG_g (1<<27)
+#define FLAG_Z (1<<28)
+#define FLAG_color (1<<29)
#endif
#ifdef FOR_lsattr
#ifndef TT
#define TT this.lspci
#endif
-#define FLAG_i (FORCED_FLAG<<0)
-#define FLAG_n (FORCED_FLAG<<1)
-#define FLAG_k (FORCED_FLAG<<2)
-#define FLAG_m (FORCED_FLAG<<3)
-#define FLAG_e (FORCED_FLAG<<4)
+#define FLAG_i (1<<0)
+#define FLAG_n (1<<1)
+#define FLAG_k (1<<2)
+#define FLAG_m (1<<3)
+#define FLAG_e (1<<4)
#endif
#ifdef FOR_lsusb
#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
#endif
#define FLAG_i (1<<0)
#define FLAG_f (1<<1)
+#define FLAG_remove_destination (1<<2)
#define FLAG_F (1<<2)
#define FLAG_n (1<<3)
#define FLAG_v (1<<4)
#ifndef TT
#define TT this.nproc
#endif
-#define FLAG_all (FORCED_FLAG<<0)
+#define FLAG_all (1<<0)
#endif
#ifdef FOR_nsenter
#define FLAG_s (1<<6)
#define FLAG_x (1<<7)
#define FLAG_N (1<<8)
-#define FLAG_v (1<<9)
-#define FLAG_j (1<<10)
+#define FLAG_w (1<<9)
+#define FLAG_v (1<<10)
+#define FLAG_j (1<<11)
#endif
#ifdef FOR_oneit
#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
#define FLAG_g (1<<3)
#define FLAG_U (1<<4)
#define FLAG_u (1<<5)
-#define FLAG_t (1<<6)
-#define FLAG_s (1<<7)
-#define FLAG_pid (1<<8)
-#define FLAG_p (1<<8)
-#define FLAG_O (1<<9)
-#define FLAG_o (1<<10)
-#define FLAG_n (1<<11)
-#define FLAG_M (1<<12)
-#define FLAG_l (1<<13)
-#define FLAG_f (1<<14)
-#define FLAG_e (1<<15)
-#define FLAG_d (1<<16)
-#define FLAG_A (1<<17)
-#define FLAG_a (1<<18)
-#define FLAG_ppid (1<<19)
-#define FLAG_P (1<<19)
-#define FLAG_sort (1<<20)
-#define FLAG_k (1<<20)
+#define FLAG_T (1<<6)
+#define FLAG_t (1<<7)
+#define FLAG_s (1<<8)
+#define FLAG_pid (1<<9)
+#define FLAG_p (1<<9)
+#define FLAG_O (1<<10)
+#define FLAG_o (1<<11)
+#define FLAG_n (1<<12)
+#define FLAG_M (1<<13)
+#define FLAG_l (1<<14)
+#define FLAG_f (1<<15)
+#define FLAG_e (1<<16)
+#define FLAG_d (1<<17)
+#define FLAG_A (1<<18)
+#define FLAG_a (1<<19)
+#define FLAG_ppid (1<<20)
+#define FLAG_P (1<<20)
+#define FLAG_sort (1<<21)
+#define FLAG_k (1<<21)
#endif
#ifdef FOR_pwd
#endif
#endif
+#ifdef FOR_resize
+#ifndef TT
+#define TT this.resize
+#endif
+#define FLAG_w (1<<0)
+#define FLAG_s (1<<1)
+#define FLAG_c (1<<2)
+#endif
+
#ifdef FOR_restorecon
#ifndef TT
#define TT this.restorecon
#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
#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
#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
#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_c (1<<1)
+#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
#ifndef TT
#define TT this.switch_root
#endif
-#define FLAG_h (1<<0)
-#define FLAG_c (1<<1)
+#define FLAG_h (FORCED_FLAG<<0)
+#define FLAG_c (FORCED_FLAG<<1)
#endif
#ifdef FOR_sync
#define FLAG_p (1<<6)
#define FLAG_o (1<<7)
#define FLAG_k (1<<8)
-#define FLAG_m (1<<9)
+#define FLAG_H (1<<9)
+#define FLAG_O (1<<10)
+#define FLAG_m (1<<11)
#endif
#ifdef FOR_touch
#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
#ifndef TT
#define TT this.watch
#endif
-#define FLAG_e (FORCED_FLAG<<0)
-#define FLAG_t (FORCED_FLAG<<1)
-#define FLAG_n (FORCED_FLAG<<2)
+#define FLAG_e (1<<0)
+#define FLAG_t (1<<1)
+#define FLAG_n (1<<2)
#endif
#ifdef FOR_wc
#define FLAG_m (1<<3)
#endif
+#ifdef FOR_wget
+#ifndef TT
+#define TT this.wget
+#endif
+#define FLAG_f (FORCED_FLAG<<0)
+#endif
+
#ifdef FOR_which
#ifndef TT
#define TT this.which
#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
struct selabel_handle *handle;
};
+// toys/android/log.c
+
+struct log_data {
+ char *tag;
+ char *pri;
+};
+
// toys/example/hello.c
struct hello_data {
long size;
};
+// toys/lsb/hostname.c
+
+struct hostname_data {
+ char *fname;
+};
+
// toys/lsb/killall.c
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;
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 {
struct base64_data {
long columns;
+
+ unsigned total;
};
// toys/other/blockdev.c
int utc;
};
-// toys/other/ifconfig.c
-
-struct ifconfig_data {
- int sockfd;
-};
-
// toys/other/ionice.c
struct ionice_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 {
char *console;
};
+// toys/other/setfattr.c
+
+struct setfattr_data {
+ char *x, *v, *n;
+};
+
// toys/other/shred.c
struct shred_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
// toys/other/xxd.c
struct xxd_data {
+ long s;
long g;
long l;
long c;
int sockfd;
};
+// toys/pending/chrt.c
+
+struct chrt_data {
+ long pid;
+};
+
// toys/pending/compress.c
struct compress_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
// toys/pending/expr.c
struct expr_data {
- int argidx;
+ char **tok; // current token, not on the stack since recursive calls mutate it
+
+ char *refree;
};
// toys/pending/fdisk.c
long cylinders;
};
-// toys/pending/file.c
-
-struct file_data {
- int max_name_len;
-};
-
// toys/pending/fold.c
struct fold_data {
char buf[sizeof(struct sockaddr_storage)];
};
+// toys/pending/getfattr.c
+
+struct getfattr_data {
+ char *n;
+};
+
// toys/pending/getty.c
struct getty_data {
// toys/pending/lsof.c
struct lsof_data {
- char *pids;
+ struct arg_list *p;
struct stat *sought_files;
+ struct double_list *all_sockets;
struct double_list *files;
int last_shown_pid;
int shown_header;
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 {
struct sh_data {
char *command;
+
+ long lineno;
};
// toys/pending/sulogin.c
int interval;
};
+// toys/pending/wget.c
+
+struct wget_data {
+ char *filename;
+};
+
// toys/posix/chgrp.c
struct chgrp_data {
unsigned tabcount, *tab;
};
+// toys/posix/file.c
+
+struct file_data {
+ int max_name_len;
+};
+
// toys/posix/find.c
struct find_data {
unsigned screen_width;
int nl_title;
- char uid_buf[12], gid_buf[12];
+ char *escmore;
};
// toys/posix/mkdir.c
struct arg_list *output_base;
char *address_base;
long max_count;
+ long width;
long jump_bytes;
int address_idx;
unsigned types, leftover, star;
- char *buf;
- uint64_t bufs[4]; // force 64-bit alignment
+ char *buf; // Points to buffers[0] or buffers[1].
+ char *bufs[2]; // Used to detect duplicate lines.
off_t pos;
};
struct patch_data {
char *infile;
long prefix;
+ char *dir;
struct double_list *current_hunk;
long oldline, oldlen, newline, newlen;
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;
} pgrep;
};
+#ifndef __APPLE__
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;
// toys/posix/wc.c
struct wc_data {
- unsigned long totals[3];
+ unsigned long totals[4];
};
// toys/posix/xargs.c
extern union global_union {
struct getprop_data getprop;
+ struct log_data log;
struct hello_data hello;
struct skeleton_data skeleton;
struct dmesg_data dmesg;
+ struct hostname_data hostname;
struct killall_data killall;
struct md5sum_data md5sum;
struct mknod_data mknod;
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;
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;
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;
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;
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;
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;
struct useradd_data useradd;
struct vi_data vi;
struct watch_data watch;
+ struct wget_data wget;
struct chgrp_data chgrp;
struct chmod_data chmod;
struct cksum_data cksum;
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;
#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"
#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"
#define HELP_passwd "usage: passwd [-a ALGO] [-dlu] <account name>\n\nupdate user's authentication tokens. Default : current user\n\n-a ALGO Encryption method (des, md5, sha256, sha512) default: des\n-d Set password to ''\n-l Lock (disable) account\n-u Unlock (enable) account\n\n"
-#define HELP_mount "usage: mount [-afFrsvw] [-t TYPE] [-o OPTIONS...] [[DEVICE] DIR]\n\nMount new filesystem(s) on directories. With no arguments, display existing\nmounts.\n\n-a mount all entries in /etc/fstab (with -t, only entries of that TYPE)\n-O only mount -a entries that have this option\n-f fake it (don't actually mount)\n-r read only (same as -o ro)\n-w read/write (default, same as -o rw)\n-t specify filesystem type\n-v verbose\n\nOPTIONS is a comma separated list of options, which can also be supplied\nas --longopts.\n\nThis mount autodetects loopback mounts (a file on a directory) and\nbind mounts (file on file, directory on directory), so you don't need\nto say --bind or --loop. You can also \"mount -a /path\" to mount everything\nin /etc/fstab under /path, even if it's noauto.\n\n\n"
+#define HELP_mount "usage: mount [-afFrsvw] [-t TYPE] [-o OPTION,] [[DEVICE] DIR]\n\nMount new filesystem(s) on directories. With no arguments, display existing\nmounts.\n\n-a mount all entries in /etc/fstab (with -t, only entries of that TYPE)\n-O only mount -a entries that have this option\n-f fake it (don't actually mount)\n-r read only (same as -o ro)\n-w read/write (default, same as -o rw)\n-t specify filesystem type\n-v verbose\n\nOPTIONS is a comma separated list of options, which can also be supplied\nas --longopts.\n\nThis mount autodetects loopback mounts (a file on a directory) and\nbind mounts (file on file, directory on directory), so you don't need\nto say --bind or --loop. You can also \"mount -a /path\" to mount everything\nin /etc/fstab under /path, even if it's noauto.\n\n\n"
#define HELP_mktemp "usage: mktemp [-dqu] [-p DIR] [TEMPLATE]\n\nSafely create a new file \"DIR/TEMPLATE\" and print its name.\n\n-d Create directory instead of file (--directory)\n-p Put new file in DIR (--tmpdir)\n-q Quiet, no error messages\n-u Don't create anything, just print what would be created\n\nEach X in TEMPLATE is replaced with a random printable character. The\ndefault TEMPLATE is tmp.XXXXXX, and the default DIR is $TMPDIR if set,\nelse \"/tmp\".\n\n"
-#define HELP_mknod_z "usage: mknod [-Z CONTEXT] ...\n\n-Z Set security context to created file\n\n"
+#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_mknod "usage: mknod [-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\n-m Mode (file permissions) of new device, in octal or u+x format\n\n"
+#define HELP_sha512sum "See sha1sum\n\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_sha384sum "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_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"
-#define HELP_hostname "usage: hostname [newname]\n\nGet/Set the current hostname\n\n"
+#define HELP_hostname "usage: hostname [-b] [-F FILENAME] [newname]\n\nGet/Set the current hostname\n\n-b Set hostname to 'localhost' if otherwise unset\n-F Set hostname to contents of FILENAME\n\n"
#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"
#define HELP_swapoff "usage: swapoff swapregion\n\nDisable swapping on a given swapregion.\n\n"
-#define HELP_stat "usage: stat [-f] [-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\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"
#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_listen_tty "usage: netcat [-t]\n\n-t allocate tty (must come before -l or -L)\n\n"
-
-#define HELP_netcat "usage: netcat [-lL COMMAND...] [-u] [-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-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"
#define HELP_lsusb "usage: lsusb\n\nList USB hosts/devices.\n\n"
-#define HELP_lspci_text "usage: lspci [-n] [-i FILE ]\n\n-n Numeric output (repeat for readable and numeric)\n-i PCI ID database (default /usr/share/misc/pci.ids)\n\n\n"
-
-#define HELP_lspci "usage: lspci [-ekm]\n\nList PCI devices.\n\n-e Print all 6 digits in class\n-k Print kernel driver\n-m Machine parseable format\n\n"
+#define HELP_lspci "usage: lspci [-ekmn] [-i FILE ] \n\nList PCI devices.\n-e Print all 6 digits in class\n-i PCI ID database (default /usr/share/misc/pci.ids)\n-k Print kernel driver\n-m Machine parseable format\n-n Numeric output (repeat for readable and numeric)\n"
#define HELP_lsmod "usage: lsmod\n\nDisplay the currently loaded modules, their sizes and their dependencies.\n\n"
#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"
#define HELP_blkid "usage: blkid DEV...\n\nPrints type, label and UUID of filesystem on a block device or image.\n\n"
-#define HELP_base64 "usage: base64 [-di] [-w COLUMNS] [FILE...]\n\nEncode or decode in base64.\n\n-d decode\n-i ignore non-alphabetic characters\n-w wrap output at COLUMNS (default 76)\n\n"
+#define HELP_base64 "usage: base64 [-di] [-w COLUMNS] [FILE...]\n\nEncode or decode in base64.\n\n-d decode\n-i ignore non-alphabetic characters\n-w wrap output at COLUMNS (default 76 or 0 for no wrap)\n\n"
#define HELP_acpi "usage: acpi [-abctV]\n\nShow status of power sources and thermal devices.\n\n-a show power adapters\n-b show batteries\n-c show cooling device state\n-t show temperatures\n-V show everything\n\n"
#define HELP_xzcat "usage: xzcat [filename...]\n\nDecompress listed files to stdout. Use stdin if no files listed.\n\n\n\n"
+#define HELP_wget "usage: wget -f filename URL\n-f filename: specify the filename to be saved\nURL: HTTP uniform resource location and only HTTP, not HTTPS\n\nexamples:\n wget -f index.html http://www.example.com\n wget -f sample.jpg http://www.example.com:8080/sample.jpg\n\n"
+
#define HELP_watch "usage: watch [-n SEC] [-t] PROG ARGS\n\nRun PROG periodically\n\n-n Loop period in seconds (default 2)\n-t Don't print header\n-e Freeze updates on command error, and exit after enter.\n\n"
#define HELP_vi "usage: vi FILE\n\nVisual text editor. Predates the existence of standardized cursor keys,\nso the controls are weird and historical.\n\n"
#define HELP_sulogin "usage: sulogin [-t time] [tty]\n\nSingle User Login.\n-t Default Time for Single User Login\n\n"
-#define HELP_cd "usage: cd [-PL] [path]\n\nChange current directory. With no arguments, go $HOME.\n\n-P Physical path: resolve symlinks in path.\n-L Local path: .. trims directories off $PWD (default).\n\n"
-
#define HELP_exit "usage: exit [status]\n\nExit shell. If no return value supplied on command line, use value\nof most recent command, or 0 if none.\n\n"
+#define HELP_cd "usage: cd [-PL] [path]\n\nChange current directory. With no arguments, go $HOME.\n\n-P Physical path: resolve symlinks in path.\n-L Local path: .. trims directories off $PWD (default).\n\n"
+
#define HELP_sh "usage: sh [-c command] [script]\n\nCommand shell. Runs a shell script, or reads input interactively\nand responds to it.\n\n-c command line to execute\n-i interactive mode (default when STDIN is a tty)\n\n"
#define HELP_route "usage: route [-ne] [-A inet[6]] / [add|del]\n\nDisplay/Edit kernel routing tables.\n\n-n no name lookups\n-e display other/more information\n-A inet{6} Select Address Family\n\nreject mod dyn reinstate metric netmask gw mss window irtt dev\n\n"
+#define HELP_resize "usage: resize\n\nreset terminal to maximum width and height\n\n\n"
+
#define HELP_ping "usage: ping [OPTIONS] HOST\n\nCheck network connectivity by sending packets to a host and reporting\nits response.\n\nSend ICMP ECHO_REQUEST packets to ipv4 or ipv6 addresses and prints each\necho it receives back, with round trip time.\n\nOptions:\n-4, -6 Force IPv4 or IPv6\n-c CNT Send CNT many packets\n-I IFACE/IP Source interface or address\n-q Quiet, only displays output at start and when finished\n-s SIZE Packet SIZE in bytes (default 56)\n-t TTL Set Time (number of hops) To Live\n-W SEC Seconds to wait for response after all packets sent (default 10)\n-w SEC Exit after this many seconds\n\n"
#define HELP_deallocvt "usage: deallocvt [N]\n\nDeallocate unused virtual terminal /dev/ttyN, or all unused consoles.\n\n"
#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 (or stdin) one screenful at a time.\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"
#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"
#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]\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_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"
#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"
#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_pgkill_common "usage: pgrep [-fnovx] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]\n\n-f Check full command line for PATTERN\n-G Match real Group ID(s)\n-g Match Process Group(s) (0 is current user)\n-n Newest match only\n-o Oldest match only\n-P Match Parent Process ID(s)\n-s Match Session ID(s) (0 for current)\n-t Match Terminal(s)\n-U Match real User ID(s)\n-u Match effective User ID(s)\n-v Negate the match\n-x Match whole command (not substring)\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 [-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,] [-s SORT]\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 [-m] [ -d seconds ] [ -n iterations ]\n\nShow process activity in real time.\n\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 [-AadeflnwZ] [-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-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 CMD COMM without -f, 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 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 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"
-#define HELP_od "usage: od [-bcdosxv] [-j #] [-N #] [-A doxn] [-t acdfoux[#]]\n\n-A Address base (decimal, octal, hexdecimal, none)\n-j Skip this many bytes of input\n-N Stop dumping after this many bytes\n-t output type a(scii) c(har) d(ecimal) f(loat) o(ctal) u(nsigned) (he)x\n plus optional size in bytes\n aliases: -b=-t o1, -c=-t c, -d=-t u2, -o=-t o2, -s=-t d2, -x=-t x2\n-v Don't collapse repeated lines together\n\n"
+#define HELP_od "usage: od [-bcdosxv] [-j #] [-N #] [-w #] [-A doxn] [-t acdfoux[#]]\n\n-A Address base (decimal, octal, hexdecimal, none)\n-j Skip this many bytes of input\n-N Stop dumping after this many bytes\n-t Output type a(scii) c(har) d(ecimal) f(loat) o(ctal) u(nsigned) (he)x\n plus optional size in bytes\n aliases: -b=-t o1, -c=-t c, -d=-t u2, -o=-t o2, -s=-t d2, -x=-t x2\n-v Don't collapse repeated lines together\n-w Total line width in bytes (default 16).\n\n"
#define HELP_nohup "usage: nohup COMMAND [ARGS...]\n\nRun a command that survives the end of its terminal.\n\nRedirect tty on stdin to /dev/null, tty on stdout to \"nohup.out\".\n\n"
#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 -c use ctime for timestamps\n-d directory, not contents -i inode number\n-k block sizes in kilobytes -p put a '/' after dir names\n-q unprintable chars as '?' -s size (in blocks)\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 files 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_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 -c use ctime for timestamps\n-d directory, not contents -i inode number\n-k block sizes in kilobytes -p put a '/' after dir names\n-q unprintable chars as '?' -s size (in blocks)\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 files 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_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"
#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"
#define HELP_install "usage: install [-dDpsv] [-o USER] [-g GROUP] [-m MODE] [SOURCE...] DEST\n\nCopy files and set attributes.\n\n-d Act like mkdir -p\n-D Create leading directories for DEST\n-g Make copy belong to GROUP\n-m Set permissions to MODE\n-o Make copy belong to USER\n-p Preserve timestamps\n-s Call \"strip -p\"\n-v Verbose\n\n"
-#define HELP_mv "usage: mv [-finv] SOURCE... DEST\"\n\n-f force copy by deleting destination file\n-i interactive, prompt before overwriting existing DEST\n-n no clobber (don't overwrite DEST)\n-v verbose\n"
+#define HELP_mv "usage: mv [-fivn] SOURCE... DEST\"\n\n-f force copy by deleting destination file\n-i interactive, prompt before overwriting existing DEST\n-v verbose\n-n no clobber (don't overwrite DEST)\n\n"
-#define HELP_cp_preserve "-i interactive, prompt before overwriting existing DEST\n-l hard link instead of copy\n-n no clobber (don't overwrite DEST)\n-p preserve timestamps, ownership, and mode\n-r synonym for -R\n-s symlink instead of copy\n-v verbose\nletter(s) of:\n\n mode - permissions (ignore umask for rwx, copy suid and sticky bit)\n ownership - user and group\n timestamps - file creation, modification, and access times.\n context - security context\n xattr - extended attributes\n all - all of the above\nusage: cp [--preserve=motcxa] [-adlnrsv] [-fipRHLP] SOURCE... DEST\n\nCopy files from SOURCE to DEST. If more than one SOURCE, DEST must\nbe a directory.\n\n--preserve takes either a comma separated list of attributes, or the first\n-F delete any existing destination file first (--remove-destination)\n-H Follow symlinks listed on command line\n-L Follow all symlinks\n-P Do not follow symlinks [default]\n-R recurse into subdirectories (DEST must be a directory)\n-a same as -dpr\n-d don't dereference symlinks\n-f delete destination files we can't write to\n"
+#define HELP_cp_preserve "--preserve takes either a comma separated list of attributes, or the first\nletter(s) of:\n\n mode - permissions (ignore umask for rwx, copy suid and sticky bit)\n ownership - user and group\n timestamps - file creation, modification, and access times.\n context - security context\n xattr - extended attributes\n all - all of the above\n\nusage: cp [--preserve=motcxa] [-adlnrsvfipRHLP] SOURCE... DEST\n\nCopy files from SOURCE to DEST. If more than one SOURCE, DEST must\nbe a directory.\n-v verbose\n-s symlink instead of copy\n-r synonym for -R\n-n no clobber (don't overwrite DEST)\n-l hard link instead of copy\n-d don't dereference symlinks\n-a same as -dpr\n-P Do not follow symlinks [default]\n-L Follow all symlinks\n-H Follow symlinks listed on command line\n-R recurse into subdirectories (DEST must be a directory)\n-p preserve timestamps, ownership, and mode\n-i interactive, prompt before overwriting existing DEST\n-F delete any existing destination file first (--remove-destination)\n-f delete destination files we can't write to\n"
-#define HELP_cp "usage: cp [--preserve=motcxa] [-adlnrsv] [-fipRHLP] SOURCE... DEST\n\nCopy files from SOURCE to DEST. If more than one SOURCE, DEST must\nbe a directory.\n\n--preserve takes either a comma separated list of attributes, or the first\n-F delete any existing destination file first (--remove-destination)\n-H Follow symlinks listed on command line\n-L Follow all symlinks\n-P Do not follow symlinks [default]\n-R recurse into subdirectories (DEST must be a directory)\n-a same as -dpr\n-d don't dereference symlinks\n-f delete destination files we can't write to\n-i interactive, prompt before overwriting existing DEST\n-l hard link instead of copy\n-n no clobber (don't overwrite DEST)\n-p preserve timestamps, ownership, and mode\n-r synonym for -R\n-s symlink instead of copy\n-v verbose\nletter(s) of:\n\n mode - permissions (ignore umask for rwx, copy suid and sticky bit)\n ownership - user and group\n timestamps - file creation, modification, and access times.\n context - security context\n xattr - extended attributes\n all - all of the above\n"
+#define HELP_cp "usage: cp [--preserve=motcxa] [-adlnrsvfipRHLP] SOURCE... DEST\n\nCopy files from SOURCE to DEST. If more than one SOURCE, DEST must\nbe a directory.\n-v verbose\n-s symlink instead of copy\n-r synonym for -R\n-n no clobber (don't overwrite DEST)\n-l hard link instead of copy\n-d don't dereference symlinks\n-a same as -dpr\n-P Do not follow symlinks [default]\n-L Follow all symlinks\n-H Follow symlinks listed on command line\n-R recurse into subdirectories (DEST must be a directory)\n-p preserve timestamps, ownership, and mode\n-i interactive, prompt before overwriting existing DEST\n-F delete any existing destination file first (--remove-destination)\n-f delete destination files we can't write to\n--preserve takes either a comma separated list of attributes, or the first\nletter(s) of:\n\n mode - permissions (ignore umask for rwx, copy suid and sticky bit)\n ownership - user and group\n timestamps - file creation, modification, and access times.\n context - security context\n xattr - extended attributes\n all - all of the above\n\n"
#define HELP_comm "usage: comm [-123] FILE1 FILE2\n\nReads FILE1 and FILE2, which should be ordered, and produces three text\ncolumns as output: lines only in FILE1; lines only in FILE2; and lines\nin both files. Filename \"-\" is a synonym for stdin.\n\n-1 suppress the output column of lines unique to FILE1\n-2 suppress the output column of lines unique to FILE2\n-3 suppress the output column of lines duplicated in FILE1 and FILE2\n\n"
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))
USE_ARP(NEWTOY(arp, "vi:nDsdap:A:H:[+Ap][!sd]", TOYFLAG_USR|TOYFLAG_BIN))
USE_ARPING(NEWTOY(arping, "<1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]", TOYFLAG_USR|TOYFLAG_SBIN))
-USE_BASE64(NEWTOY(base64, "diw#<1[!dw]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_BASE64(NEWTOY(base64, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN))
USE_BASENAME(NEWTOY(basename, "<1>2", TOYFLAG_USR|TOYFLAG_BIN))
USE_BLKID(NEWTOY(blkid, 0, TOYFLAG_BIN))
USE_BLOCKDEV(NEWTOY(blockdev, "<1>1(setro)(setrw)(getro)(getss)(getbsz)(setbsz)#<0(getsz)(getsize)(getsize64)(flushbufs)(rereadpt)",TOYFLAG_USR|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))
-USE_CP(NEWTOY(cp, "<2"USE_CP_PRESERVE("(preserve):;")"RHLPp"USE_CP_MORE("rdaslvnF(remove-destination)")"fi[-HLP"USE_CP_MORE("d")"]"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))
+USE_CP(NEWTOY(cp, "<2"USE_CP_PRESERVE("(preserve):;")"RHLPprdaslvnF(remove-destination)fi[-HLPd][-ni]", TOYFLAG_BIN))
USE_CPIO(NEWTOY(cpio, "(no-preserve-owner)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]", TOYFLAG_BIN))
USE_CROND(NEWTOY(crond, "fbSl#<0=8d#<0L:c:[-bf][-LS][-ld]", TOYFLAG_USR|TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
USE_CRONTAB(NEWTOY(crontab, "c:u:elr[!elr]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
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))
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))
USE_HEXEDIT(NEWTOY(hexedit, "<1>1r", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
USE_HOST(NEWTOY(host, "<1>2avt:", TOYFLAG_USR|TOYFLAG_BIN))
USE_HOSTID(NEWTOY(hostid, ">0", TOYFLAG_USR|TOYFLAG_BIN))
-USE_HOSTNAME(NEWTOY(hostname, NULL, TOYFLAG_BIN))
+USE_HOSTNAME(NEWTOY(hostname, "bF:", TOYFLAG_BIN))
USE_HWCLOCK(NEWTOY(hwclock, ">0(fast)f(rtc):u(utc)l(localtime)t(systz)s(hctosys)r(show)w(systohc)[-ul][!rtsw]", TOYFLAG_USR|TOYFLAG_BIN))
USE_ICONV(NEWTOY(iconv, "cst:f:", TOYFLAG_USR|TOYFLAG_BIN))
USE_ID(NEWTOY(id, ">1"USE_ID_Z("Z")"nGgru[!"USE_ID_Z("Z")"Ggu]", TOYFLAG_USR|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))
USE_LOSETUP(NEWTOY(losetup, ">2S(sizelimit)#s(show)ro#j:fdca[!afj]", TOYFLAG_SBIN))
-USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")"ZgoACFHLRSacdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL]", TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")"ZgoACFHLRSabcdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL][!qb]", TOYFLAG_BIN|TOYFLAG_LOCALE))
USE_LSATTR(NEWTOY(lsattr, "vldaR", TOYFLAG_BIN))
USE_LSMOD(NEWTOY(lsmod, NULL, TOYFLAG_SBIN))
-USE_LSOF(NEWTOY(lsof, "lp:t", TOYFLAG_USR|TOYFLAG_BIN))
+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))
USE_MKTEMP(NEWTOY(mktemp, ">1uqd(directory)p(tmpdir):", TOYFLAG_BIN))
USE_MODINFO(NEWTOY(modinfo, "<1b:k:F:0", TOYFLAG_BIN))
USE_MODPROBE(NEWTOY(modprobe, "alrqvsDb", TOYFLAG_SBIN))
-USE_MORE(NEWTOY(more, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_MORE(NEWTOY(more, 0, TOYFLAG_USR|TOYFLAG_BIN))
USE_MOUNT(NEWTOY(mount, "?O:afnrvwt:o*[-rw]", TOYFLAG_BIN|TOYFLAG_STAYROOT))
USE_MOUNTPOINT(NEWTOY(mountpoint, "<1qdx[-dx]", TOYFLAG_BIN))
-USE_MV(NEWTOY(mv, "<2"USE_CP_MORE("vnF")"fi"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))
+USE_MV(NEWTOY(mv, "<2vnF(remove-destination)fi[-ni]", TOYFLAG_BIN))
USE_NBD_CLIENT(OLDTOY(nbd-client, nbd_client, TOYFLAG_USR|TOYFLAG_BIN))
USE_NBD_CLIENT(NEWTOY(nbd_client, "<3>3ns", 0))
USE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN))
USE_NOHUP(NEWTOY(nohup, "<1^", TOYFLAG_USR|TOYFLAG_BIN))
USE_NPROC(NEWTOY(nproc, "(all)", TOYFLAG_USR|TOYFLAG_BIN))
USE_NSENTER(NEWTOY(nsenter, "<1F(no-fork)t#<1(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN))
-USE_OD(NEWTOY(od, "j#vN#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN))
+USE_OD(NEWTOY(od, "j#vw#<1=16N#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN))
USE_ONEIT(NEWTOY(oneit, "^<1nc:p3[!pn]", TOYFLAG_SBIN))
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*u*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))
USE_REBOOT(NEWTOY(reboot, "fn", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
USE_RENICE(NEWTOY(renice, "<1gpun#|", TOYFLAG_USR|TOYFLAG_BIN))
USE_RESET(NEWTOY(reset, 0, TOYFLAG_USR|TOYFLAG_BIN))
+USE_RESIZE(NEWTOY(resize, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_USR))
USE_RESTORECON(NEWTOY(restorecon, "<1DFnRrv", TOYFLAG_USR|TOYFLAG_SBIN))
USE_REV(NEWTOY(rev, NULL, TOYFLAG_USR|TOYFLAG_BIN))
USE_RFKILL(NEWTOY(rfkill, "<1>2", TOYFLAG_USR|TOYFLAG_SBIN))
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:f", 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))
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" "k*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))
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))
#define _PS_SCH (1<<14)
#define PS_CPU 15
#define _PS_CPU (1<<15)
-#define PS_COMM 16
-#define _PS_COMM (1<<16)
-#define PS_TTY 17
-#define _PS_TTY (1<<17)
-#define PS_WCHAN 18
-#define _PS_WCHAN (1<<18)
-#define PS_LABEL 19
-#define _PS_LABEL (1<<19)
-#define PS_COMMAND 20
-#define _PS_COMMAND (1<<20)
-#define PS_CMDLINE 21
-#define _PS_CMDLINE (1<<21)
-#define PS_ARGS 22
-#define _PS_ARGS (1<<22)
+#define PS_TID 16
+#define _PS_TID (1<<16)
+#define PS_TCNT 17
+#define _PS_TCNT (1<<17)
+#define PS_BIT 18
+#define _PS_BIT (1<<18)
+#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_CMD 24
-#define _PS_CMD (1<<24)
-#define PS_UID 25
-#define _PS_UID (1<<25)
-#define PS_USER 26
-#define _PS_USER (1<<26)
-#define PS_RUID 27
-#define _PS_RUID (1<<27)
-#define PS_RUSER 28
-#define _PS_RUSER (1<<28)
-#define PS_GID 29
-#define _PS_GID (1<<29)
-#define PS_GROUP 30
-#define _PS_GROUP (1<<30)
-#define PS_RGID 31
-#define _PS_RGID (1<<31)
-#define PS_RGROUP 32
-#define _PS_RGROUP (1LL<<32)
-#define PS_TIME 33
-#define _PS_TIME (1LL<<33)
-#define PS_ELAPSED 34
-#define _PS_ELAPSED (1LL<<34)
-#define PS_TIME_ 35
-#define _PS_TIME_ (1LL<<35)
-#define PS_C 36
-#define _PS_C (1LL<<36)
-#define PS__VSZ 37
-#define _PS__VSZ (1LL<<37)
-#define PS__MEM 38
-#define _PS__MEM (1LL<<38)
-#define PS__CPU 39
-#define _PS__CPU (1LL<<39)
-#define PS_VIRT 40
-#define _PS_VIRT (1LL<<40)
-#define PS_RES 41
-#define _PS_RES (1LL<<41)
-#define PS_SHR 42
-#define _PS_SHR (1LL<<42)
-#define PS_READ 43
-#define _PS_READ (1LL<<43)
-#define PS_WRITE 44
-#define _PS_WRITE (1LL<<44)
-#define PS_IO 45
-#define _PS_IO (1LL<<45)
-#define PS_DREAD 46
-#define _PS_DREAD (1LL<<46)
-#define PS_DWRITE 47
-#define _PS_DWRITE (1LL<<47)
-#define PS_SWAP 48
-#define _PS_SWAP (1LL<<48)
-#define PS_DIO 49
-#define _PS_DIO (1LL<<49)
-#define PS_STIME 50
-#define _PS_STIME (1LL<<50)
-#define PS_F 51
-#define _PS_F (1LL<<51)
-#define PS_S 52
-#define _PS_S (1LL<<52)
-#define PS_STAT 53
-#define _PS_STAT (1LL<<53)
+#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
+#define _PS_UID (1<<28)
+#define PS_USER 29
+#define _PS_USER (1<<29)
+#define PS_RUID 30
+#define _PS_RUID (1<<30)
+#define PS_RUSER 31
+#define _PS_RUSER (1<<31)
+#define PS_GID 32
+#define _PS_GID (1LL<<32)
+#define PS_GROUP 33
+#define _PS_GROUP (1LL<<33)
+#define PS_RGID 34
+#define _PS_RGID (1LL<<34)
+#define PS_RGROUP 35
+#define _PS_RGROUP (1LL<<35)
+#define PS_TIME 36
+#define _PS_TIME (1LL<<36)
+#define PS_ELAPSED 37
+#define _PS_ELAPSED (1LL<<37)
+#define PS_TIME_ 38
+#define _PS_TIME_ (1LL<<38)
+#define PS_C 39
+#define _PS_C (1LL<<39)
+#define PS__VSZ 40
+#define _PS__VSZ (1LL<<40)
+#define PS__MEM 41
+#define _PS__MEM (1LL<<41)
+#define PS__CPU 42
+#define _PS__CPU (1LL<<42)
+#define PS_VIRT 43
+#define _PS_VIRT (1LL<<43)
+#define PS_RES 44
+#define _PS_RES (1LL<<44)
+#define PS_SHR 45
+#define _PS_SHR (1LL<<45)
+#define PS_READ 46
+#define _PS_READ (1LL<<46)
+#define PS_WRITE 47
+#define _PS_WRITE (1LL<<47)
+#define PS_IO 48
+#define _PS_IO (1LL<<48)
+#define PS_DREAD 49
+#define _PS_DREAD (1LL<<49)
+#define PS_DWRITE 50
+#define _PS_DWRITE (1LL<<50)
+#define PS_SWAP 51
+#define _PS_SWAP (1LL<<51)
+#define PS_DIO 52
+#define _PS_DIO (1LL<<52)
+#define PS_STIME 53
+#define _PS_STIME (1LL<<53)
+#define PS_F 54
+#define _PS_F (1LL<<54)
+#define PS_S 55
+#define _PS_S (1LL<<55)
+#define PS_STAT 56
+#define _PS_STAT (1LL<<56)
+#define PS_PCY 57
+#define _PS_PCY (1LL<<57)
#define KEY_UP 0
#define _KEY_UP (1<<0)
#define KEY_DOWN 1
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) {
int dirtree_notdotdot(struct dirtree *catch)
{
// Should we skip "." and ".."?
- return notdotdot(catch->name) ? DIRTREE_SAVE|DIRTREE_RECURSE : 0;
+ return notdotdot(catch->name)*(DIRTREE_SAVE|DIRTREE_RECURSE);
}
// Create a dirtree node from a path, with stat and symlink info.
return node->parent ? node->parent->dirfd : AT_FDCWD;
}
-// Handle callback for a node in the tree. Returns saved node(s) or NULL.
-//
-// By default, allocates a tree of struct dirtree, not following symlinks
-// If callback==NULL, or callback always returns 0, allocate tree of struct
-// dirtree and return root of tree. Otherwise call callback(node) on each
-// hit, free structures after use, and return NULL.
-//
+// Handle callback for a node in the tree. Returns saved node(s) if
+// callback returns DIRTREE_SAVE, otherwise frees consumed nodes and
+// returns NULL. If !callback return top node unchanged.
+// If !new return DIRTREE_ABORTVAL
struct dirtree *dirtree_handle_callback(struct dirtree *new,
int (*callback)(struct dirtree *node))
{
int flags;
- if (!new) return 0;
- if (!callback) callback = dirtree_notdotdot;
+ if (!new) return DIRTREE_ABORTVAL;
+ if (!callback) return new;
flags = callback(new);
- if (S_ISDIR(new->st.st_mode)) {
- if (flags & (DIRTREE_RECURSE|DIRTREE_COMEAGAIN)) {
- new->dirfd = openat(dirtree_parentfd(new), new->name, O_CLOEXEC);
- flags = dirtree_recurse(new, callback, flags);
- }
- }
+ if (S_ISDIR(new->st.st_mode) && (flags & (DIRTREE_RECURSE|DIRTREE_COMEAGAIN)))
+ flags = dirtree_recurse(new, callback,
+ openat(dirtree_parentfd(new), new->name, O_CLOEXEC), flags);
// If this had children, it was callback's job to free them already.
if (!(flags & DIRTREE_SAVE)) {
// callback(). Uses and closes supplied ->dirfd.
int dirtree_recurse(struct dirtree *node,
- int (*callback)(struct dirtree *node), int flags)
+ int (*callback)(struct dirtree *node), int dirfd, int flags)
{
struct dirtree *new, **ddt = &(node->child);
struct dirent *entry;
DIR *dir;
+ node->dirfd = dirfd;
if (node->dirfd == -1 || !(dir = fdopendir(node->dirfd))) {
if (!(flags & DIRTREE_SHUTUP)) {
char *path = dirtree_path(node, 0);
return flags;
}
-// Create dirtree root
-struct dirtree *dirtree_start(char *name, int symfollow)
+// Create dirtree from path, using callback to filter nodes. If !callback
+// return just the top node. Use dirtree_notdotdot callback to allocate a
+// tree of struct dirtree nodes and return pointer to root node for later
+// processing.
+// Returns DIRTREE_ABORTVAL if path didn't exist (use DIRTREE_SHUTUP to handle
+// error message yourself).
+
+struct dirtree *dirtree_flagread(char *path, int flags,
+ int (*callback)(struct dirtree *node))
{
- return dirtree_add_node(0, name, DIRTREE_SYMFOLLOW*!!symfollow);
+ return dirtree_handle_callback(dirtree_add_node(0, path, flags), callback);
}
-// Create dirtree from path, using callback to filter nodes.
-// If callback == NULL allocate a tree of struct dirtree nodes and return
-// pointer to root node.
-
+// Common case
struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node))
{
- struct dirtree *root = dirtree_start(path, 0);
-
- return root ? dirtree_handle_callback(root, callback) : DIRTREE_ABORTVAL;
+ return dirtree_flagread(path, 0, callback);
}
#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"
;
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
void tty_reset(void)
{
- set_terminal(1, 0, 0);
+ set_terminal(0, 0, 0);
tty_esc("?25h");
tty_esc("0m");
tty_jump(0, 999);
void tty_sigreset(int i)
{
tty_reset();
- _exit(128+i);
+ _exit(i ? 128+i : 0);
}
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);
// 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;
}
// 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;
}
// 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, "-");
// 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.
}
static char *tempfile2zap;
-static void tempfile_handler(int i)
+static void tempfile_handler(void)
{
if (1 < (long)tempfile2zap) unlink(tempfile2zap);
- _exit(1);
}
// Open a temporary file to copy an existing file into.
toys.signal = sig;
}
-// Install the same handler on every signal that defaults to killing the process
+void exit_signal(int sig)
+{
+ if (sig) toys.exitval = sig|128;
+ xexit();
+}
+
+// Install the same handler on every signal that defaults to killing the
+// process, calling the handler on the way out. Calling multiple times
+// adds the handlers to a list, to be called in order.
void sigatexit(void *handler)
{
+ struct arg_list *al = xmalloc(sizeof(struct arg_list));
int i;
- for (i=0; signames[i].num != SIGCHLD; i++) signal(signames[i].num, handler);
+
+ for (i=0; signames[i].num != SIGCHLD; i++)
+ signal(signames[i].num, exit_signal);
+ al->next = toys.xexit;
+ al->arg = handler;
+ toys.xexit = al;
}
// Convert name to signal number. If name == NULL print names.
*buf = c;
}
-char *basename_r(char *name)
+// basename() can modify its argument or return a pointer to a constant string
+// This just gives after the last '/' or the whole stirng if no /
+char *getbasename(char *name)
{
char *s = strrchr(name, '/');
if (s) return s+1;
+
return name;
}
for (curname = names; *curname; curname++)
if (**curname == '/' ? !strcmp(cmd, *curname)
- : !strcmp(basename_r(cmd), basename_r(*curname)))
+ : !strcmp(getbasename(cmd), getbasename(*curname)))
if (callback(u, *curname)) break;
if (*curname) break;
}
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);
return *s ? s : 0;
}
+
+int dev_minor(int dev)
+{
+ return ((dev&0xfff00000)>>12)|(dev&0xff);
+}
+
+int dev_major(int dev)
+{
+ return (dev&0xfff00)>>8;
+}
+
+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);
+}
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));
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);
#define DIRTREE_SYMFOLLOW 8
// Don't warn about failure to stat
#define DIRTREE_SHUTUP 16
+// Breadth first traversal, conserves filehandles at the expense of memory
+#define DIRTREE_BREADTH 32
// Don't look at any more files in this directory.
#define DIRTREE_ABORT 256
char name[];
};
-struct dirtree *dirtree_start(char *name, int symfollow);
struct dirtree *dirtree_add_node(struct dirtree *p, char *name, int flags);
char *dirtree_path(struct dirtree *node, int *plen);
int dirtree_notdotdot(struct dirtree *catch);
int dirtree_parentfd(struct dirtree *node);
-struct dirtree *dirtree_handle_callback(struct dirtree *new,
- int (*callback)(struct dirtree *node));
int dirtree_recurse(struct dirtree *node, int (*callback)(struct dirtree *node),
- int symfollow);
+ int dirfd, int symfollow);
+struct dirtree *dirtree_flagread(char *path, int flags,
+ int (*callback)(struct dirtree *node));
struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node));
// help.c
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);
+void _xexit(void) noreturn;
void xexit(void) noreturn;
void *xmalloc(size_t size);
void *xzalloc(size_t size);
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);
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);
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);
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);
char *show_uuid(char *uuid);
char *next_printf(char *s, char **start);
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
void linestack_insert(struct linestack **lls, long pos, char *line, long len);
void linestack_append(struct linestack **lls, char *line);
struct linestack *linestack_load(char *name);
-int crunch_str(char **str, int width, FILE *out,
- int (*escout)(FILE *out, int cols, char **buf));
+int crunch_escape(FILE *out, int cols, int wc);
+int crunch_rev_escape(FILE *out, int cols, int wc);
+int crunch_str(char **str, int width, FILE *out, char *escmore,
+ int (*escout)(FILE *out, int cols, int wc));
int draw_str(char *start, int width);
int utf8len(char *str);
int utf8skip(char *str, int width);
+int draw_trim_esc(char *str, int padto, int width, char *escmore,
+ int (*escout)(FILE *out, int cols,int wc));
int draw_trim(char *str, int padto, int width);
// interestingtimes.c
// 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);
mode_t string_to_mode(char *mode_str, mode_t base);
void mode_to_string(mode_t mode, char *buf);
-char *basename_r(char *name);
+
+char *getbasename(char *name);
void names_to_pid(char **names, int (*callback)(pid_t pid, char *name));
pid_t xvforkwrap(pid_t pid);
// if escout, send it unprintable chars, returns columns output or -1 for
// standard escape: ^X if <32, <XX> if invliad UTF8, U+XXXX if UTF8 !iswprint()
// Returns width in columns, moves *str to end of data consumed.
-int crunch_str(char **str, int width, FILE *out,
- int (*escout)(FILE *out, int cols, char **buf))
+int crunch_str(char **str, int width, FILE *out, char *escmore,
+ int (*escout)(FILE *out, int cols, int wc))
{
int columns = 0, col, bytes;
char *start, *end;
- for (end = start = *str; *end;) {
- wchar_t wc = *end;
+ for (end = start = *str; *end; columns += col, end += bytes) {
+ wchar_t wc;
- bytes = 0;
- if (*end >= ' ' && (bytes = mbrtowc(&wc, end, 99,0))>0
- && (col = wcwidth(wc))>=0)
+ if ((bytes = mbrtowc(&wc, end, MB_CUR_MAX, 0))>0 && (col = wcwidth(wc))>=0)
{
- if (width-columns<col) break;
- if (out) fwrite(end, bytes, 1, out);
- } else if (!escout || 0>(col = escout(out, width-columns, &end))) {
- char buf[32];
-
- tty_esc("7m");
- if (*end < ' ') {
- bytes = 1;
- sprintf(buf, "^%c", '@'+*end);
- } else if (bytes<1) {
- bytes = 1;
- sprintf(buf, "<%02X>", *end);
- } else sprintf(buf, "U+%04X", wc);
- col = strlen(buf);
- if (width-columns<col) buf[col = width-columns] = 0;
- if (out) fputs(buf, out);
- tty_esc("27m");
- } else continue;
- columns += col;
- end += bytes;
+ if (!escmore || wc>255 || !strchr(escmore, wc)) {
+ if (width-columns<col) break;
+ if (out) fwrite(end, bytes, 1, out);
+
+ continue;
+ }
+ }
+
+ if (bytes<1) {
+ bytes = 1;
+ wc = *end;
+ }
+ col = width-columns;
+ if (col<1) break;
+ col = escout(out, col, wc);
}
*str = end;
return columns;
}
+int crunch_escape(FILE *out, int cols, int wc)
+{
+ char buf[8];
+ int rc;
+
+ if (wc<' ') rc = sprintf(buf, "^%c", '@'+wc);
+ else if (wc<256) rc = sprintf(buf, "<%02X>", wc);
+ else rc = sprintf(buf, "U+%04X", wc);
+
+ if (rc > cols) buf[rc = cols] = 0;
+ if (out) fputs(buf, out);
+
+ return rc;
+}
+
+int crunch_rev_escape(FILE *out, int cols, int wc)
+{
+ int rc;
+
+ tty_esc("7m");
+ rc = crunch_escape(out, cols, wc);
+ tty_esc("27m");
+
+ return rc;
+}
+
// Write width chars at start of string to strdout with standard escapes
// Returns length in columns so caller can pad it out with spaces.
int draw_str(char *start, int width)
{
- return crunch_str(&start, width, stdout, 0);
+ return crunch_str(&start, width, stdout, 0, crunch_rev_escape);
}
// Return utf8 columns
int utf8len(char *str)
{
- return crunch_str(&str, INT_MAX, 0, 0);
+ return crunch_str(&str, INT_MAX, 0, 0, crunch_rev_escape);
}
// Return bytes used by (up to) this many columns
{
char *s = str;
- crunch_str(&s, width, 0, 0);
+ crunch_str(&s, width, 0, 0, crunch_rev_escape);
return s-str;
}
-// Print utf8 to stdout with standard escapes,trimmed to width and padded
+// Print utf8 to stdout with standard escapes, trimmed to width and padded
// out to padto. If padto<0 left justify. Returns columns printed
-int draw_trim(char *str, int padto, int width)
+int draw_trim_esc(char *str, int padto, int width, char *escmore,
+ int (*escout)(FILE *out, int cols, int wc))
{
int apad = abs(padto), len = utf8len(str);
// Left pad if right justified
if (padto>0 && apad>len) printf("%*s", apad-len, "");
- crunch_str(&str, len, stdout, 0);
+ crunch_str(&str, len, stdout, 0, crunch_rev_escape);
if (padto<0 && apad>len) printf("%*s", apad-len, "");
return (apad > len) ? apad : len;
}
+
+// draw_trim_esc() with default escape
+int draw_trim(char *str, int padto, int width)
+{
+ return draw_trim_esc(str, padto, width, 0, 0);
+}
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;
+}
* Copyright 2015 Rob Landley <rob@landley.net>
*/
+#include <sys/xattr.h>
+
#if CFG_TOYBOX_SELINUX
#include <selinux/selinux.h>
#else
#if CFG_TOYBOX_SMACK
#include <sys/smack.h>
-#include <sys/xattr.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)
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);
// Test for gcc (using compiler builtin #define)
-#ifdef __GNUC__
+#if defined(__GNUC__) && !defined(__APPLE__)
#define noreturn __attribute__((noreturn))
#define printf_format __attribute__((format(printf, 1, 2)))
#else
// This isn't in the spec, but it's how we determine what libc we're using.
+#ifndef __APPLE__
#include <features.h>
+#endif
// Types various replacement prototypes need
#include <sys/types.h>
#ifndef MS_SHARED
#define MS_SHARED (1<<20)
#endif
+#ifndef MS_RELATIME
+#define MS_RELATIME (1<<21)
+#endif
// When building under obsolete glibc (Ubuntu 8.04-ish), hold its hand a bit.
#elif __GLIBC__ == 2 && __GLIBC_MINOR__ < 10
#endif // glibc in general
-#if !defined(__GLIBC__) && !defined(__BIONIC__)
+#if !defined(__GLIBC__)
// POSIX basename.
#include <libgen.h>
#endif
-// glibc was handled above; for 32-bit bionic we need to avoid a collision
-// with toybox's basename_r so we can't include <libgen.h> even though that
-// would give us a POSIX basename(3).
-#if defined(__BIONIC__)
-char *basename(char *path);
-char *dirname(char *path);
-#endif
-
// Work out how to do endianness
#ifndef __APPLE__
#if defined(__APPLE__) \
|| (defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 10)
+#include <stdio.h>
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
#endif
// Linux headers not listed by POSIX or LSB
#include <sys/mount.h>
+#ifndef __APPLE__
#include <sys/swap.h>
+#endif
// Android is missing some headers and functions
// "generated/config.h" is included first
//#define strncpy(...) @@strncpyisbadmmkay@@
//#define strncat(...) @@strncatisbadmmkay@@
+#ifdef __ANDROID__
+#include <cutils/sched_policy.h>
+#else
+static inline int get_sched_policy(int tid, void *policy) {return 0;}
+static inline char *get_sched_policy_name(int policy) {return "unknown";}
+#endif
// 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)
strcpy(dest+len, src);
}
+// We replaced exit(), _exit(), and atexit() with xexit(), _xexit(), and
+// sigatexit(). This gives _xexit() the option to siglongjmp(toys.rebound, 1)
+// instead of exiting, lets xexit() report stdout flush failures to stderr
+// and change the exit code to indicate error, lets our toys.exit function
+// change happen for signal exit paths and lets us remove the functions
+// after we've called them.
+
+void _xexit(void)
+{
+ if (toys.rebound) siglongjmp(*toys.rebound, 1);
+
+ _exit(toys.exitval);
+}
+
void xexit(void)
{
- if (toys.rebound) longjmp(*toys.rebound, 1);
+ // Call toys.xexit functions in reverse order added.
+ while (toys.xexit) {
+ // This is typecasting xexit->arg to a function pointer,then calling it.
+ // Using the invalid signal number 0 lets the signal handlers distinguish
+ // an actual signal from a regular exit.
+ ((void (*)(int))(toys.xexit->arg))(0);
+
+ free(llist_pop(&toys.xexit));
+ }
if (fflush(NULL) || ferror(stdout))
if (!toys.exitval) perror_msg("write");
-
- exit(toys.exitval);
+ _xexit();
}
// Die unless we can allocate memory.
}
// 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)
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);
{
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 != '/') {
} 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) {
}
// 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);
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) {
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)
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;
#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},
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);
if (!(which = toy_find(*argv))) return;
// Return if stack depth getting noticeable (proxy for leaked heap, etc).
- if (toys.stacktop && labs((char *)toys.stacktop-(char *)&which)>6000)
- return;
+
+ // Compiler writers have decided subtracting char * is undefined behavior,
+ // so convert to integers. (LP64 says sizeof(long)==sizeof(pointer).)
+ if (!CFG_TOYBOX_NORECURSE)
+ if (toys.stacktop && labs((long)toys.stacktop-(long)&which)>6000) return;
// Return if we need to re-exec to acquire root via suid bit.
if (toys.which && (which->flags&TOYFLAG_ROOTONLY) && toys.wasroot) return;
toys.stacktop = &stack;
}
- *argv = basename_r(*argv);
+ *argv = getbasename(*argv);
// If nommu can't fork, special reentry path.
// Use !stacktop to signal "vfork happened", both before and after xexec()
//#include "toys.h"
+#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <termios.h>
#include <poll.h>
+#include <sys/socket.h>
struct statvfs {int i;};
#include "lib/portability.h"
#include "lib/lib.h"
int main(int argc, char *argv[]) { return fork(); }
EOF
echo -e '\tdepends on !TOYBOX_MUSL_NOMMU_IS_BROKEN'
+
+ probesymbol TOYBOX_PRLIMIT << EOF
+ #include <sys/time.h>
+ #include <sys/resource.h>
+
+ int main(int argc, char *argv[]) { prlimit(0, 0, 0, 0); }
+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")"
[ "${FILE/pending//}" != "$FILE" ] &&
PENDING="$PENDING $NAME" ||
WORKING="$WORKING $NAME"
-done > .singlemake &&
-echo -e "clean::\n\trm -f $WORKING $PENDING" >> .singlemake &&
-echo -e "list:\n\t@echo $(echo $WORKING $PENDING | tr ' ' '\n' | sort | xargs)"\
- >> .singlemake &&
-echo -e "list_working:\n\t@echo $(echo $WORKING | tr ' ' '\n' | sort | xargs)" \
- >> .singlemake &&
-echo -e "list_pending:\n\t@echo $(echo $PENDING | tr ' ' '\n' | sort | xargs)" \
- >> .singlemake
-)
+done &&
+echo -e "clean::\n\trm -f $WORKING $PENDING" &&
+echo -e "list:\n\t@echo $(echo $WORKING | tr ' ' '\n' | sort | xargs)" &&
+echo -e "list_pending:\n\t@echo $(echo $PENDING | tr ' ' '\n' | sort | xargs)" &&
+echo -e ".PHONY: $WORKING $PENDING" | sed 's/ \([^ ]\)/ test_\1/g'
+) > .singlemake
source ./configure
-# Parse command line arguments.
+[ -z "$PREFIX" ] && PREFIX="/usr/toybox"
-[ -z "$PREFIX" ] && PREFIX="."
+# Parse command line arguments.
LONG_PATH=""
while [ ! -z "$1" ]
do
# Create symlinks instead of hardlinks?
-
[ "$1" == "--symlink" ] && LINK_TYPE="-s"
# Uninstall?
-
- [ "$1" == "--uninstall" ] && UNINSTALL=1
+ [ "$1" == "--uninstall" ] && UNINSTALL=Uninstall
# Delete destination command if it exists?
-
[ "$1" == "--force" ] && DO_FORCE="-f"
# Use {,usr}/{bin,sbin} paths instead of all files in one directory?
-
- if [ "$1" == "--long" ]
- then
- LONG_PATH="bin/"
- fi
+ [ "$1" == "--long" ] && LONG_PATH="bin/"
shift
done
$DEBUG $HOSTCC -I . scripts/install.c -o generated/instlist || exit 1
COMMANDS="$(generated/instlist $LONG_PATH)"
-echo "Install commands..."
+echo "${UNINSTALL:-Install} commands..."
# Copy toybox itself
if [ -z "$UNINSTALL" ]
then
- mkdir -p ${PREFIX}/${LONG_PATH} || exit 1
+ mkdir -p "${PREFIX}/${LONG_PATH}" &&
+ rm -f "${PREFIX}/${LONG_PATH}/toybox" &&
cp toybox ${PREFIX}/${LONG_PATH} || exit 1
else
- rm "${PREFIX}/${LONG_PATH}/toybox" 2>/dev/null
- rmdir "${PREFIX}/${LONG_PATH}" 2>/dev/null
+ rm -f "${PREFIX}/${LONG_PATH}/toybox" 2>/dev/null
fi
-cd "${PREFIX}"
+cd "$PREFIX" || exit 1
# Make links to toybox
+EXIT=0
+
for i in $COMMANDS
do
# Figure out target of link
else
# Create subdirectory for command to go in (if necessary)
- DOTPATH="$(echo $i | sed 's@\(.*/\).*@\1@')"
+ DOTPATH="$(dirname "$i")"/
if [ -z "$UNINSTALL" ]
then
mkdir -p "$DOTPATH" || exit 1
- else
- rmdir "$DOTPATH" 2>/dev/null
fi
if [ -z "$LINK_TYPE" ]
then
- dotpath="bin/"
+ DOTPATH="bin/"
else
if [ "$DOTPATH" != "$LONG_PATH" ]
then
+ # For symlinks we need ../../bin style relative paths
DOTPATH="$(echo $DOTPATH | sed -e 's@[^/]*/@../@g')"$LONG_PATH
else
DOTPATH=""
fi
# Create link
- [ -z "$UNINSTALL" ] &&
- ln $DO_FORCE $LINK_TYPE ${DOTPATH}toybox $i ||
- rm $i 2>/dev/null
+ if [ -z "$UNINSTALL" ]
+ then
+ ln $DO_FORCE $LINK_TYPE ${DOTPATH}toybox $i || EXIT=1
+ else
+ rm -f $i || EXIT=1
+ fi
done
+
+exit $EXIT
set -o pipefail
source ./configure
-[ -z "$KCONFIG_CONFIG" ] && KCONFIG_CONFIG=".config"
+[ -z "$KCONFIG_CONFIG" ] && KCONFIG_CONFIG=.config
+[ -z "$OUTNAME" ] && OUTNAME=toybox
+UNSTRIPPED="generated/unstripped/$(basename "$OUTNAME")"
# Since each cc invocation is short, launch half again as many processes
# as we have processors so they don't exit faster than we can start them.
# 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..."
-mkdir -p generated
+mkdir -p generated/unstripped
if isnewer generated/Config.in toys
then
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
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'
# 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 &&
# LINK needs optlibs.dat, above
-LINK="$(echo $LDOPTIMIZE $LDFLAGS -o toybox_unstripped -Wl,--as-needed $(cat generated/optlibs.dat))"
+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
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
# 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
-for i in $FILES
+COUNT=0
+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))
# ratelimit to $CPUS many parallel jobs, detecting errors
- while true
+ for j in $PENDING
do
- PENDING="$(echo $PENDING $(jobs -rp) | tr ' ' '\n' | sort -u)"
- [ $(echo -n "$PENDING" | wc -l) -lt "$CPUS" ] && break;
+ [ "$COUNT" -lt "$CPUS" ] && break;
- wait $(echo "$PENDING" | head -n 1)
+ wait $j
DONE=$(($DONE+$?))
- PENDING="$(echo "$PENDING" | tail -n +2)"
+ COUNT=$(($COUNT-1))
+ PENDING="${PENDING## $j}"
done
[ $DONE -ne 0 ] && break
done
[ $DONE -ne 0 ] && exit 1
-do_loudly $BUILD $LFILES $LINK || exit 1
-if [ ! -z "$NOSTRIP" ] || ! do_loudly ${CROSS_COMPILE}strip toybox_unstripped -o toybox
+do_loudly $BUILD $LNKFILES $LINK || exit 1
+if [ ! -z "$NOSTRIP" ] ||
+ ! do_loudly ${CROSS_COMPILE}strip "$UNSTRIPPED" -o "$OUTNAME"
then
- echo "strip failed, using unstripped" && cp toybox_unstripped toybox ||
+ echo "strip failed, using unstripped" && cp "$UNSTRIPPED" "$OUTNAME" ||
exit 1
fi
# its output the way SUSv4 suggests it do so. While we're at it, make sure
# we don't have the "w" bit set so things like bzip2's "cp -f" install don't
# overwrite our binary through the symlink.
-do_loudly chmod 555 toybox || exit 1
+do_loudly chmod 555 "$OUTNAME" || exit 1
echo
for (;;) {
struct flag *flist, *aflist, *offlist;
- char *gaps, *mgaps, c;
+ char *mgaps = 0;
unsigned bit;
*command = *flags = *allflags = 0;
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);
}
// 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);
testing()
{
- NAME="$1"
+ NAME="$CMDNAME $1"
[ -z "$1" ] && NAME=$2
if [ $# -ne 5 ]
echo -ne "$3" > expected
echo -ne "$4" > input
- echo -ne "$5" | eval "$2" > actual
+ echo -ne "$5" | ${EVAL:-eval} "$2" > actual
RETVAL=$?
# Catch segfaults
[ $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"
if [ -n "$VERBOSE" ]
then
[ ! -z "$4" ] && echo "echo -ne \"$4\" > input"
- echo "echo -ne '$5' | $2"
- diff -au expected actual
+ echo "echo -ne '$5' |$EVAL $2"
+ echo "$DIFF"
[ "$VERBOSE" == fail ] && exit 1
fi
else
[ -n "$DEBUG" ] && set +x
- return $RETVAL
+ return 0
}
# Recursively grab an executable and all the libraries needed to run it.
exit 1
fi
- DEPENDS="$(sed -n 's/^[ \t]*depends on //;T;s/[!][A-Z0-9_]*//g;s/ *&& */|/g;p' $TOYFILE | grep -v SMACK | xargs | tr ' ' '|')"
+ # Enable stuff this command depends on
+ DEPENDS="$(sed -n "/^config *$i"'$/,/^$/{s/^[ \t]*depends on //;T;s/[!][A-Z0-9_]*//g;s/ *&& */|/g;p}' $TOYFILE | xargs | tr ' ' '|')"
NAME=$(echo $i | tr a-z- A-Z_)
-
make allnoconfig > /dev/null &&
sed -ri -e '/CONFIG_TOYBOX/d' \
-e "s/# (CONFIG_($NAME|${NAME}_.*${DEPENDS:+|$DEPENDS})) is not set/\1=y/" \
echo "# CONFIG_TOYBOX is not set" >> "$KCONFIG_CONFIG" &&
grep "CONFIG_TOYBOX_" .config >> "$KCONFIG_CONFIG" &&
- make &&
- mv -f toybox $PREFIX$i || exit 1
+ rm -f "$PREFIX$i" &&
+ OUTNAME="$PREFIX$i" scripts/make.sh || exit 1
done
#!/bin/bash
-[ -z "$TOPDIR" ] && TOPDIR="$(pwd)"
+TOPDIR="$PWD"
+FILES="$PWD"/tests/files
trap 'kill $(jobs -p) 2>/dev/null; exit 1' INT
then
for i in "$@"
do
+ CMDNAME="${i##*/}"
+ CMDNAME="${CMDNAME%.test}"
. "$TOPDIR"/tests/$i.test
done
else
for i in "$TOPDIR"/tests/*.test
do
- CMDNAME="$(echo "$i" | sed 's@.*/\(.*\)\.test@\1@')"
+ CMDNAME="${i##*/}"
+ CMDNAME="${CMDNAME%.test}"
if [ -h ../$CMDNAME ] || [ ! -z "$TEST_HOST" ]
then
cd .. && rm -rf testdir && mkdir testdir && cd testdir || exit 1
--- /dev/null
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "simple" "base64" "c2ltcGxlCg==\n" "" "simple\n"
+testing "file" "base64 input" "c2ltcGxlCg==\n" "simple\n" ""
+testing "simple -d" "base64 -d" "simple\n" "" "c2ltcGxlCg==\n"
+testing "simple -d" "base64 -d input" "simple\n" "c2ltcGxlCg==" ""
+testing "default wrap" "base64" \
+ "V2UndmUgcmVwbGFjZWQgdGhlIGRpbGl0aGl1bSB0aGV5IG5vcm1hbGx5IHVzZSB3aXRoIEZvbGdl\ncidzIENyeXN0YWxzLg==\n" \
+ "" "We've replaced the dilithium they normally use with Folger's Crystals."
+testing "multiline -d " "base64 -d" \
+ "We've replaced the dilithium they normally use with Folger's Crystals." "" \
+ "V2UndmUgcmVwbGFjZWQgdGhlIGRpbGl0aGl1bSB0aGV5IG5vcm1hbGx5IHVzZSB3aXRoIEZvbGdl\ncidzIENyeXN0YWxzLg==\n"
+
+testing "-w" "base64 -w 10" \
+ "TWFyY2hpbm\ncgdG8gdGhl\nIGJlYXQgb2\nYgYSBkaWZm\nZXJlbnQga2\nV0dGxlIG9m\nIGZpc2guCg\n==\n" \
+ "" "Marching to the beat of a different kettle of fish.\n"
+
+testing "-w0" "base64 -w0 input" \
+ "VmlraW5ncz8gVGhlcmUgYWluJ3Qgbm8gdmlraW5ncyBoZXJlLiBKdXN0IHVzIGhvbmVzdCBmYXJtZXJzLiBUaGUgdG93biB3YXMgYnVybmluZywgdGhlIHZpbGxhZ2VycyB3ZXJlIGRlYWQuIFRoZXkgZGlkbid0IG5lZWQgdGhvc2Ugc2hlZXAgYW55d2F5LiBUaGF0J3Mgb3VyIHN0b3J5IGFuZCB3ZSdyZSBzdGlja2luZyB0byBpdC4K" \
+ "Vikings? There ain't no vikings here. Just us honest farmers. The town was burning, the villagers were dead. They didn't need those sheep anyway. That's our story and we're sticking to it.\n" ""
#testing "name" "command" "result" "infile" "stdin"
# Removal of extra /'s
-testing "basename /-only" "basename ///////" "/\n" "" ""
-testing "basename trailing /" "basename a//////" "a\n" "" ""
-testing "basename combined" "basename /////a///b///c///d/////" "d\n" "" ""
+testing "/-only" "basename ///////" "/\n" "" ""
+testing "trailing /" "basename a//////" "a\n" "" ""
+testing "combined" "basename /////a///b///c///d/////" "d\n" "" ""
# Standard suffix behavior.
-testing "basename suffix" "basename a/b/c/d.suffix .suffix" "d\n" "" ""
+testing "suffix" "basename a/b/c/d.suffix .suffix" "d\n" "" ""
# A suffix cannot be the entire result.
-testing "basename suffix=result" "basename .txt .txt" ".txt\n" "" ""
+testing "suffix=result" "basename .txt .txt" ".txt\n" "" ""
# Deal with suffix appearing in the filename
-testing "basename reappearing suffix 1" "basename a.txt.txt .txt" "a.txt\n" "" ""
-testing "basename reappearing suffix 2" "basename a.txt.old .txt" "a.txt.old\n" "" ""
+testing "reappearing suffix 1" "basename a.txt.txt .txt" "a.txt\n" "" ""
+testing "reappearing suffix 2" "basename a.txt.old .txt" "a.txt.old\n" "" ""
# A suffix should be a real suffix, only a the end.
-testing "basename invalid suffix" "basename isthisasuffix? suffix" "isthisasuffix?\n" "" ""
+testing "invalid suffix" "basename isthisasuffix? suffix" "isthisasuffix?\n" "" ""
+
+# Zero-length suffix
+testing "zero-length suffix" "basename a/b/c ''" "c\n" "" ""
#testing "name" "command" "result" "infile" "stdin"
-BDIR="$TOPDIR/tests/blkid"
+BDIR="$FILES/blkid"
bzcat "$BDIR"/squashfs.bz2 > temp.img
-testing "blkid file" "blkid temp.img" 'temp.img: TYPE="squashfs"\n' "" ""
+testing "file" "blkid temp.img" 'temp.img: TYPE="squashfs"\n' "" ""
rm temp.img
-testing "blkid cramfs" 'bzcat "$BDIR"/cramfs.bz2 | blkid -' \
+testing "cramfs" 'bzcat "$BDIR"/cramfs.bz2 | blkid -' \
'-: LABEL="mycramfs" TYPE="cramfs"\n' "" ""
-testing "blkid ext2" 'bzcat "$BDIR"/ext2.bz2 | blkid -' \
+testing "ext2" 'bzcat "$BDIR"/ext2.bz2 | blkid -' \
'-: LABEL="myext2" UUID="e59093ba-4135-4fdb-bcc4-f20beae4dfaf" TYPE="ext2"\n' \
"" ""
-testing "blkid ext3" 'bzcat "$BDIR"/ext3.bz2 | blkid -' \
+testing "ext3" 'bzcat "$BDIR"/ext3.bz2 | blkid -' \
'-: LABEL="myext3" UUID="79d1c877-1a0f-4e7d-b21d-fc32ae3ef101" TYPE="ext3"\n' \
"" ""
-testing "blkid ext4" 'bzcat "$BDIR"/ext4.bz2 | blkid -' \
+testing "ext4" 'bzcat "$BDIR"/ext4.bz2 | blkid -' \
'-: LABEL="myext4" UUID="dc4b7c00-c0c0-4600-af7e-0335f09770fa" TYPE="ext4"\n' \
"" ""
-testing "blkid f2fs" 'bzcat "$BDIR"/f2fs.bz2 | blkid -' \
+testing "f2fs" 'bzcat "$BDIR"/f2fs.bz2 | blkid -' \
'-: LABEL="" UUID="b53d3619-c204-4c0b-8504-36363578491c" TYPE="f2fs"\n' \
"" ""
-testing "blkid msdos" 'bzcat "$BDIR"/msdos.bz2 | blkid -' \
- '-: LABEL="mymsdos " UUID="5108-1e6e" TYPE="vfat"\n' "" ""
-testing "blkid ntfs" 'bzcat "$BDIR"/ntfs.bz2 | blkid -' \
+testing "msdos" 'bzcat "$BDIR"/msdos.bz2 | blkid -' \
+ '-: LABEL="mymsdos" UUID="5108-1e6e" TYPE="vfat"\n' "" ""
+testing "ntfs" 'bzcat "$BDIR"/ntfs.bz2 | blkid -' \
'-: UUID="8585600838bfe16e" TYPE="ntfs"\n' "" ""
-testing "blkid reiserfs" 'bzcat "$BDIR"/reiser3.bz2 | blkid -' \
+testing "reiserfs" 'bzcat "$BDIR"/reiser3.bz2 | blkid -' \
'-: LABEL="myreiser" UUID="a5b99bec-45cc-41d7-986e-32f4b6fc28f2" TYPE="reiserfs"\n' \
"" ""
-testing "blkid squashfs" 'bzcat "$BDIR"/squashfs.bz2 | blkid -' \
+testing "squashfs" 'bzcat "$BDIR"/squashfs.bz2 | blkid -' \
'-: TYPE="squashfs"\n' "" ""
-testing "blkid vfat" 'bzcat "$BDIR"/vfat.bz2 | blkid -' \
- '-: LABEL="myvfat " UUID="1db9-5673" TYPE="vfat"\n' "" ""
-testing "blkid xfs" 'bzcat "$BDIR"/xfs.bz2 | blkid -' \
+testing "vfat" 'bzcat "$BDIR"/vfat.bz2 | blkid -' \
+ '-: LABEL="myvfat" UUID="1db9-5673" TYPE="vfat"\n' "" ""
+testing "xfs" 'bzcat "$BDIR"/xfs.bz2 | blkid -' \
'-: LABEL="XFS_test" UUID="d63a1dc3-27d5-4dd4-8b38-f4f97f495c6f" TYPE="xfs"\n' \
"" ""
-#testing "blkid minix" 'bzcat "$BDIR"/minix.bz2 | blkid -'
+#testing "minix" 'bzcat "$BDIR"/minix.bz2 | blkid -'
#adfs bfs btrfs cramfs jfs nilfs romfs
#vfat // fat32 fat12 fat16
#!/bin/bash
-# Copyright 2014 Divya Kothari <divya.s.kothari@gmail.com>
-# Copyright 2014 Naha Maggu <maggu.neha@gmail.com>
-
[ -f testing.sh ] && . testing.sh
#testing "name" "command" "result" "infile" "stdin"
-echo "hello" > file
-tar -cjf file.tar.bz2 file
-# Get system bzcat
-bzcatExe=`which bzcat`
-$bzcatExe file.tar.bz2 > bzcatOut
-testing "bzcat - decompresses a single file" "bzcat file.tar.bz2 > Tempfile && echo "yes"; diff Tempfile bzcatOut && echo "yes"; rm -rf file* bzcatOut Tempfile" "yes\nyes\n" "" ""
+testing "2 known files" \
+ 'bzcat "$FILES/blkid/"{minix,ntfs}.bz2 | sha1sum | '"awk '{print \$1}'" \
+ 'c0b7469c9660d6056a988ef8a7fe73925efc9266\n' '' ''
-#testing "name" "command" "result" "infile" "stdin"
-echo "hello" > file1
-echo "hi" > file2
-echo "Hi, Good morning !! I am a bzcat tester" > file3
-tar -cjf file1.tar.bz2 file1
-tar -cjf file2.tar.bz2 file2
-tar -cjf file3.tar.bz2 file3
-# Get system bzcat
-bzcatExe=`which bzcat`
-$bzcatExe file1.tar.bz2 file2.tar.bz2 file3.tar.bz2 > bzcatOut
-testing "bzcat - decompresses multiple files" "bzcat file1.tar.bz2 file2.tar.bz2 file3.tar.bz2 > Tempfile && echo "yes" ; diff Tempfile bzcatOut && echo "yes"; rm -rf file* bzcatOut Tempfile " "yes\nyes\n" "" ""
+testing "overflow" \
+ 'bzcat "$FILES/bzcat/overflow.bz2" >/dev/null 2>/dev/null ;
+ [ $? -ne 0 ] && echo good' "good\n" "" ""
+
+testing "badcrc" \
+ 'bzcat "$FILES/bzcat/badcrc.bz2" > /dev/null 2>/dev/null ;
+ [ $? -ne 0 ] && echo good' "good\n" "" ""
echo "one" > file1
echo "two" > file2
testing "cat" "cat && echo yes" "oneyes\n" "" "one"
-testing "cat -" "cat - && echo yes" "oneyes\n" "" "one"
-testing "cat file1 file2" "cat file1 file2" "one\ntwo\n" "" ""
-testing "cat - file" "cat - file1" "zero\none\n" "" "zero\n"
-testing "cat file -" "cat file1 -" "one\nzero\n" "" "zero\n"
+testing "-" "cat - && echo yes" "oneyes\n" "" "one"
+testing "file1 file2" "cat file1 file2" "one\ntwo\n" "" ""
+testing "- file" "cat - file1" "zero\none\n" "" "zero\n"
+testing "file -" "cat file1 -" "one\nzero\n" "" "zero\n"
-testing "cat file1 notfound file2" \
+testing "file1 notfound file2" \
"cat file1 notfound file2 2>stderr && echo ok ; cat stderr; rm stderr" \
"one\ntwo\ncat: notfound: No such file or directory\n" "" ""
FILE="$(readlink -f /proc/self/exe)"
-testing "cat file1" \
+testing "file1" \
'cat "$FILE" > file1 && cmp "$FILE" file1 && echo yes' \
"yes\n" "" ""
-testing "cat - file1" \
+testing "- file1" \
"cat - file1 | diff -a -U 0 - file1 | tail -n 1" \
"-hello\n" "" "hello\n"
-testing "cat > /dev/full" \
+testing "> /dev/full" \
"cat - > /dev/full 2>stderr && echo ok; cat stderr; rm stderr" \
"cat: xwrite: No space left on device\n" "" "zero\n"
--- /dev/null
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#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
+IN="cd testattr"
+OUT="cd .."
+_t="abcdefghijklmnopqrstuvwxyz"
+
+testing "[-/+]i FILE[write]" "$IN && echo "$_t" > testFile &&
+ chattr +i testFile && lsattr testFile && echo "$_t" > testFile;
+ chattr -i testFile; rm -rf testFile; $OUT " "----i-------- testFile\n" "" ""
+testing "[-/+]i FILE[re-write]" "$IN && echo "$_t" > testFile &&
+ chattr +i testFile && echo \"$_t\" > testFile || chattr -i testFile &&
+ echo \"$_t\" > testFile && lsattr testFile; rm -rf testFile; $OUT" \
+ "------------- testFile\n" "" ""
+testing "[-/+]i FILE[append]" "$IN && echo "$_t" > testFile &&
+ chattr +i testFile && echo \"$_t\" >> testFile || lsattr testFile &&
+ chattr -i testFile; rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
+testing "[-/+]i FILE[move]" "$IN && echo "$_t" > testFile &&
+ chattr +i testFile && mv testFile testFile1 || lsattr testFile &&
+ chattr -i testFile; rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
+testing "[-/+]i FILE[delete]" "$IN && echo "$_t" > testFile &&
+ chattr +i testFile && rm -f testFile || lsattr testFile &&
+ chattr -i testFile; rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
+testing "[-/+]i FILE[read]" "$IN && echo "$_t" > testFile &&
+ chattr +i testFile && cat testFile && lsattr testFile &&
+ chattr -i testFile; rm -rf testFile; $OUT" "$_t\n----i-------- testFile\n" "" ""
+testing "[-/+]a FILE[write]" "$IN && echo "$_t" > testFile &&
+ chattr +a testFile && echo $_t > testFile || lsattr testFile &&
+ chattr -a testFile; rm -rf testFile; $OUT" "-----a------- testFile\n" "" ""
+testing "[-/+]a FILE[re-write]" "$IN && echo "$_t" > testFile &&
+ chattr +a testFile && echo $_t > testFile || lsattr testFile &&
+ chattr -a testFile && echo $_t > testFile && cat testFile &&
+ lsattr testFile; rm -rf testFile;
+ $OUT" "-----a------- testFile\n$_t\n------------- testFile\n" "" ""
+testing "[-/+]a FILE[append]" "$IN && echo "$_t" > testFile &&
+ chattr +a testFile && echo $_t >> testFile && cat testFile &&
+ lsattr testFile && chattr -a testFile; rm -rf testFile; $OUT" \
+ "$_t\n$_t\n-----a------- testFile\n" "" ""
+testing "[-/+]a FILE[move]" "$IN && echo "$_t" > testFile &&
+ chattr +a testFile && mv testFile testFile1 || lsattr testFile &&
+ chattr -a testFile; rm -rf testFile; $OUT" "-----a------- testFile\n" "" ""
+testing "[-/+]a FILE[delete]" "$IN && echo "$_t" > testFile &&
+ chattr +a testFile && rm -f testFile || lsattr testFile &&
+ chattr -a testFile; rm -rf testFile; $OUT" "-----a------- testFile\n" "" ""
+testing "[-/+]a FILE[read]" "$IN && echo "$_t" > testFile &&
+ chattr +a testFile && cat testFile && lsattr testFile && chattr -a testFile;
+ rm -rf testFile; $OUT" "$_t\n-----a------- testFile\n" "" ""
+
+for attr in "A" "a" "c" "D" "d" "i" "j" "s" "S" "t" "T" "u"
+do
+ testing "[-/+]$attr FILE" "$IN && echo "$_t" > testFile &&
+ chattr +$attr testFile && cat testFile && chattr -$attr testFile &&
+ lsattr testFile; rm -rf testFile; $OUT" "$_t\n------------- testFile\n" "" ""
+done
+
+for attr in "A" "a" "c" "D" "d" "i" "j" "s" "S" "t" "T" "u"
+do
+ testing "-$attr FILE" "$IN && echo "$_t" > testFile && chattr -$attr testFile &&
+ cat testFile && lsattr testFile; rm -rf testFile; $OUT" "$_t\n------------- testFile\n" "" ""
+done
+
+testing "[-/+]AacDdijsStTu FILE" "$IN && echo "$_t" > testFile &&
+ chattr +AacDdijsStTu testFile && cat testFile && chattr -AacDdijsStTu testFile &&
+ lsattr testFile; rm -rf testFile; $OUT" "$_t\n------------- testFile\n" "" ""
+testing "[-/+]AacDdijsStTu(random) FILE" \
+ "$IN && echo "$_t" > testFile &&
+ chattr +AacDdijsStTu testFile && cat testFile && chattr -A testFile &&
+ chattr -a testFile && chattr -c testFile && chattr -D testFile &&
+ chattr -d testFile && chattr -i testFile && chattr -j testFile &&
+ chattr -s testFile && chattr -S testFile && chattr -t testFile &&
+ chattr -T testFile && chattr -u testFile && lsattr testFile &&
+ chattr -AacDdijsStTu testFile; rm -rf testFile; $OUT" \
+ "$_t\n------------- testFile\n" "" ""
+testing "[-/+]AacDdijsStTu FILE*" "$IN &&
+ echo "$_t" > testFile && echo "$_t" > testFile1 &&
+ echo "$_t" > testFile2 && echo "$_t" > testFile3 &&
+ echo "$_t" > testFile4 && echo "$_t" > testFile5 &&
+ echo "$_t" > testFile6 && echo "$_t" > testFile7 &&
+ echo "$_t" > testFile8 && echo "$_t" > testFile9 &&
+ echo "$_t" > testFile10 && echo "$_t" > testFile11 &&
+ chattr +AacDdijsStTu testFile* &&
+ cat testFile9 && chattr -AacDdijsStTu testFile* && lsattr testFile*; rm -rf testFile*; $OUT" \
+ "$_t\n------------- testFile\n------------- testFile1\n------------- testFile10\n------------- testFile11\n------------- testFile2\n------------- testFile3\n------------- testFile4\n------------- testFile5\n------------- testFile6\n------------- testFile7\n------------- testFile8\n------------- testFile9\n" "" ""
+testing "[-/+]AacDdijsStTu(random) FILE*" \
+ "$IN && echo "$_t" > testFile &&
+ chattr +AacDdijsStTu testFile* && cat testFile && chattr -A testFile* &&
+ chattr -a testFile* && chattr -c testFile* && chattr -D testFile* &&
+ chattr -d testFile* && chattr -i testFile* && chattr -j testFile* &&
+ chattr -s testFile* && chattr -S testFile* && chattr -t testFile* &&
+ chattr -T testFile* && chattr -u testFile* && lsattr testFile;
+ rm -rf testFile; $OUT" \
+ "$_t\n------------- testFile\n" "" ""
+testing "[-/+]i FILE[write]" \
+ "$IN && echo "$_t" > testFile &&
+ chattr +i testFile &&
+ echo \"$_t\" > testFile || lsattr testFile && chattr -i testFile;
+ rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
+testing "[-/+]A FILE[write]" \
+ "$IN && echo "$_t" > testFile && chattr +A testFile &&
+ echo \"$_t\" > testFile && lsattr testFile && chattr -A testFile;
+ rm -rf testFile; $OUT" "-------A----- testFile\n" "" ""
+testing "[-/+]s FILE[write]" \
+ "$IN && echo "$_t" > testFile && chattr +s testFile &&
+ echo \"$_t\" > testFile && lsattr testFile && chattr -s testFile
+ rm -rf testFile; $OUT" "s------------ testFile\n" "" ""
+testing "-v version FILE[write]" \
+ "$IN && echo "$_t" > testFile &&
+ chattr -v 1234 testFile && echo \"$_t\" > testFile &&
+ lsattr -v testFile; rm -rf testFile" \
+ " 1234 ------------- testFile\n" "" ""
+
+_a="-------A-----"
+testing "-R [-/+]a FILE" "$IN && touch aa && chattr -R +A aa && lsattr aa &&
+ chattr -R -A aa; rm -rf aa; $OUT" "$_a aa\n" "" ""
+testing "-R [-/+]a FILE.." "$IN && touch aa bb &&
+ chattr -R +A aa bb && lsattr aa bb &&
+ chattr -R -A aa bb; rm -rf aa bb; $OUT" "$_a aa\n$_a bb\n" "" ""
+
+# Clean up
+rm -rf testattr
#testing "name" "command" "result" "infile" "stdin"
# Basic smoketest
-testing "chgrp dir" "$IN chgrp root dir $OUT" \
+testing "dir" "$IN chgrp root dir $OUT" \
"root $GRP $GRP $GRP $GRP $GRP $GRP\n" "" ""
-testing "chgrp file" "$IN chgrp root dir/file $OUT" \
+testing "file" "$IN chgrp root dir/file $OUT" \
"$GRP $GRP $GRP root $GRP $GRP $GRP\n" "" ""
-testing "chgrp dir and file" "$IN chgrp root dir dir/file $OUT" \
+testing "dir and file" "$IN chgrp root dir dir/file $OUT" \
"root $GRP $GRP root $GRP $GRP $GRP\n" "" ""
# symlinks (affect target, not symlink)
-testing "chgrp symlink->file" "$IN chgrp root dir2/file $OUT" \
+testing "symlink->file" "$IN chgrp root dir2/file $OUT" \
"$GRP $GRP $GRP root $GRP $GRP $GRP\n" "" ""
-testing "chgrp symlink->dir" "$IN chgrp root dir2/dir $OUT" \
+testing "symlink->dir" "$IN chgrp root dir2/dir $OUT" \
"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
-testing "chgrp -h symlink->dir" "$IN chgrp -h root dir2/dir $OUT" \
+testing "-h symlink->dir" "$IN chgrp -h root dir2/dir $OUT" \
"$GRP $GRP $GRP $GRP $GRP root $GRP\n" "" ""
# What does -h do (affect symlink, not target)
-testing "chgrp -h symlink->file" "$IN chgrp -h root dir2/file $OUT" \
+testing "-h symlink->file" "$IN chgrp -h root dir2/file $OUT" \
"$GRP $GRP $GRP $GRP $GRP $GRP root\n" "" ""
-testing "chgrp -h symlink->dir" "$IN chgrp -h root dir2/dir $OUT" \
+testing "-h symlink->dir" "$IN chgrp -h root dir2/dir $OUT" \
"$GRP $GRP $GRP $GRP $GRP root $GRP\n" "" ""
# chgrp -R (note, -h is implied by -R)
-testing "chgrp -R dir" "$IN chgrp -R root dir $OUT" \
+testing "-R dir" "$IN chgrp -R root dir $OUT" \
"root $GRP root root root $GRP $GRP\n" "" ""
-testing "chgrp -R dir2" "$IN chgrp -R root dir2 $OUT" \
+testing "-R dir2" "$IN chgrp -R root dir2 $OUT" \
"$GRP root $GRP $GRP $GRP root root\n" "" ""
-testing "chgrp -R symlink->dir" "$IN chgrp -R root dir2/dir $OUT" \
+testing "-R symlink->dir" "$IN chgrp -R root dir2/dir $OUT" \
"$GRP $GRP $GRP $GRP $GRP root $GRP\n" "" ""
-testing "chgrp -R symlink->file" "$IN chgrp -R root dir2/file $OUT" \
+testing "-R symlink->file" "$IN chgrp -R root dir2/file $OUT" \
"$GRP $GRP $GRP $GRP $GRP $GRP root\n" "" ""
# chgrp -RP (same as -R by itself)
-testing "chgrp -RP dir2" "$IN chgrp -RP root dir2 $OUT" \
+testing "-RP dir2" "$IN chgrp -RP root dir2 $OUT" \
"$GRP root $GRP $GRP $GRP root root\n" "" ""
-testing "chgrp -RP symlink->dir" "$IN chgrp -RP root dir2/dir $OUT" \
+testing "-RP symlink->dir" "$IN chgrp -RP root dir2/dir $OUT" \
"$GRP $GRP $GRP $GRP $GRP root $GRP\n" "" ""
-testing "chgrp -RP symlink->file" "$IN chgrp -RP root dir2/file $OUT" \
+testing "-RP symlink->file" "$IN chgrp -RP root dir2/file $OUT" \
"$GRP $GRP $GRP $GRP $GRP $GRP root\n" "" ""
# chgrp -RH (change target but only recurse through symlink->dir on cmdline)
-testing "chgrp -RH dir2" "$IN chgrp -RH root dir2 $OUT" \
+testing "-RH dir2" "$IN chgrp -RH root dir2 $OUT" \
"$GRP root root root $GRP $GRP $GRP\n" "" ""
-testing "chgrp -RH symlink->dir" "$IN chgrp -RH root dir2/dir $OUT" \
+testing "-RH symlink->dir" "$IN chgrp -RH root dir2/dir $OUT" \
"$GRP $GRP root $GRP root $GRP $GRP\n" "" ""
-testing "chgrp -RH symlink->file" "$IN chgrp -RH root dir2/file $OUT" \
+testing "-RH symlink->file" "$IN chgrp -RH root dir2/file $OUT" \
"$GRP $GRP $GRP root $GRP $GRP $GRP\n" "" ""
# chgrp -RL (change target and always recurse through symlink->dir)
-testing "chgrp -RL dir2" "$IN chgrp -RL root dir2 $OUT" \
+testing "-RL dir2" "$IN chgrp -RL root dir2 $OUT" \
"$GRP root root root root $GRP $GRP\n" "" ""
-testing "chgrp -RL symlink->dir" "$IN chgrp -RL root dir2/dir $OUT" \
+testing "-RL symlink->dir" "$IN chgrp -RL root dir2/dir $OUT" \
"$GRP $GRP root $GRP root $GRP $GRP\n" "" ""
-testing "chgrp -RL symlink->file" "$IN chgrp -RL root dir2/file $OUT" \
+testing "-RL symlink->file" "$IN chgrp -RL root dir2/file $OUT" \
"$GRP $GRP $GRP root $GRP $GRP $GRP\n" "" ""
# -HLP are NOPs without -R
-testing "chgrp -H without -R" "$IN chgrp -H root dir2/dir $OUT" \
+testing "-H without -R" "$IN chgrp -H root dir2/dir $OUT" \
"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
-testing "chgrp -L without -R" "$IN chgrp -L root dir2/dir $OUT" \
+testing "-L without -R" "$IN chgrp -L root dir2/dir $OUT" \
"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
-testing "chgrp -P without -R" "$IN chgrp -P root dir2/dir $OUT" \
+testing "-P without -R" "$IN chgrp -P root dir2/dir $OUT" \
"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
rm -rf testdir
DASH=-
fi
DASHES=$(num2perm $u$g$o)
- testing "chmod $u$g$o $type" "chmod $u$g$o $type &&
+ testing "$u$g$o $type" "chmod $u$g$o $type &&
ls -ld $type | cut -d' ' -f 1 | cut -d. -f 1" "$DASH$DASHES\n" "" ""
done
done
done
rm -rf dir file && mkdir dir && touch file
-testing "chmod 750 dir 640 file" \
+testing "750 dir 640 file" \
"chmod 750 dir 640 file 2>/dev/null ||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-x---\n-rwxr-x---\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod 666 dir file" \
+testing "666 dir file" \
"chmod 666 dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drw-rw-rw-\n-rw-rw-rw-\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod 765 *" "chmod 765 * &&
+testing "765 *" "chmod 765 * &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxrw-r-x\n-rwxrw-r-x\n" "" ""
##### u,g,o,a=r,w,x
rm -rf dir file && mkdir dir && touch file
-testing "chmod u=r dir file" "chmod u=r dir file &&
+testing "u=r dir file" "chmod u=r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr--r-xr-x\n-r--r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod u=w dir file" "chmod u=w dir file &&
+testing "u=w dir file" "chmod u=w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-w-r-xr-x\n--w-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod u=x dir file" "chmod u=x dir file &&
+testing "u=x dir file" "chmod u=x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d--xr-xr-x\n---xr--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod u+r dir file" "chmod u+r dir file &&
+testing "u+r dir file" "chmod u+r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod u+w dir file" "chmod u+w dir file &&
+testing "u+w dir file" "chmod u+w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod u+x dir file" "chmod u+x dir file &&
+testing "u+x dir file" "chmod u+x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rwxr--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod u-r dir file" "chmod u-r dir file &&
+testing "u-r dir file" "chmod u-r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-wxr-xr-x\n--w-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod u-w dir file" "chmod u-w dir file &&
+testing "u-w dir file" "chmod u-w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr-xr-xr-x\n-r--r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod u-x dir file" "chmod u-x dir file &&
+testing "u-x dir file" "chmod u-x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drw-r-xr-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod g=r dir file" "chmod g=r dir file &&
+testing "g=r dir file" "chmod g=r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr--r-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod g=w dir file" "chmod g=w dir file &&
+testing "g=w dir file" "chmod g=w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwx-w-r-x\n-rw--w-r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod g=x dir file" "chmod g=x dir file &&
+testing "g=x dir file" "chmod g=x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwx--xr-x\n-rw---xr--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod g+r dir file" "chmod g+r dir file &&
+testing "g+r dir file" "chmod g+r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod g+w dir file" "chmod g+w dir file &&
+testing "g+w dir file" "chmod g+w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxrwxr-x\n-rw-rw-r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod g+x dir file" "chmod g+x dir file &&
+testing "g+x dir file" "chmod g+x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r-xr--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod g-r dir file" "chmod g-r dir file &&
+testing "g-r dir file" "chmod g-r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwx--xr-x\n-rw----r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod g-w dir file" "chmod g-w dir file &&
+testing "g-w dir file" "chmod g-w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod g-x dir file" "chmod g-x dir file &&
+testing "g-x dir file" "chmod g-x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr--r-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod o=r dir file" "chmod o=r dir file &&
+testing "o=r dir file" "chmod o=r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr--\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod o=w dir file" "chmod o=w dir file &&
+testing "o=w dir file" "chmod o=w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-x-w-\n-rw-r---w-\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod o=x dir file" "chmod o=x dir file &&
+testing "o=x dir file" "chmod o=x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-x--x\n-rw-r----x\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod o+r dir file" "chmod o+r dir file &&
+testing "o+r dir file" "chmod o+r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod o+w dir file" "chmod o+w dir file &&
+testing "o+w dir file" "chmod o+w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xrwx\n-rw-r--rw-\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod o+x dir file" "chmod o+x dir file &&
+testing "o+x dir file" "chmod o+x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r-x\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod o-r dir file" "chmod o-r dir file &&
+testing "o-r dir file" "chmod o-r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-x--x\n-rw-r-----\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod o-w dir file" "chmod o-w dir file &&
+testing "o-w dir file" "chmod o-w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod o-x dir file" "chmod o-x dir file &&
+testing "o-x dir file" "chmod o-x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr--\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod a=r dir file" "chmod a=r dir file &&
+testing "a=r dir file" "chmod a=r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr--r--r--\n-r--r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod a=w dir file" "chmod a=w dir file &&
+testing "a=w dir file" "chmod a=w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-w--w--w-\n--w--w--w-\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod a=x dir file" "chmod a=x dir file &&
+testing "a=x dir file" "chmod a=x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d--x--x--x\n---x--x--x\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod a+r dir file" "chmod a+r dir file &&
+testing "a+r dir file" "chmod a+r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod a+w dir file" "chmod a+w dir file &&
+testing "a+w dir file" "chmod a+w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxrwxrwx\n-rw-rw-rw-\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod a+x dir file" "chmod a+x dir file &&
+testing "a+x dir file" "chmod a+x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rwxr-xr-x\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod a-r dir file" "chmod a-r dir file &&
+testing "a-r dir file" "chmod a-r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-wx--x--x\n--w-------\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod a-w dir file" "chmod a-w dir file &&
+testing "a-w dir file" "chmod a-w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr-xr-xr-x\n-r--r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod a-x dir file" "chmod a-x dir file &&
+testing "a-x dir file" "chmod a-x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drw-r--r--\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod =r dir file" "chmod =r dir file &&
+testing "=r dir file" "chmod =r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr--r--r--\n-r--r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod =w dir file" "chmod =w dir file &&
+testing "=w dir file" "chmod =w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-w-------\n--w-------\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod =x dir file" "chmod =x dir file &&
+testing "=x dir file" "chmod =x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d--x--x--x\n---x--x--x\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod +r dir file" "chmod +r dir file &&
+testing "+r dir file" "chmod +r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod +w dir file" "chmod +w dir file &&
+testing "+w dir file" "chmod +w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod +x dir file" "chmod +x dir file &&
+testing "+x dir file" "chmod +x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rwxr-xr-x\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod -r dir file" "chmod -r dir file &&
+testing "-r dir file" "chmod -r dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-wx--x--x\n--w-------\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod -w dir file" "chmod -w dir file &&
+testing "-w dir file" "chmod -w dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr-xr-xr-x\n-r--r--r--\n" "" ""
rm -rf dir file && mkdir dir && touch file
-testing "chmod -x dir file" "chmod -x dir file &&
+testing "-x dir file" "chmod -x dir file &&
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drw-r--r--\n-rw-r--r--\n" "" ""
# Removing test files for cleanup purpose
#testing "name" "command" "result" "infile" "stdin"
# Basic smoketest
-testing "chown initial" "chown root:root $F $OUT" "root root\n" "" ""
-testing "chown usr:grp" "chown $USR:$GRP $F $OUT" "$USR $GRP\n" "" ""
-testing "chown root" "chown root $F $OUT" "root $GRP\n" "" ""
+testing "initial" "chown root:root $F $OUT" "root root\n" "" ""
+testing "usr:grp" "chown $USR:$GRP $F $OUT" "$USR $GRP\n" "" ""
+testing "root" "chown root $F $OUT" "root $GRP\n" "" ""
# TODO: can we test "owner:"?
-testing "chown :grp" "chown root:root $F && chown :$GRP $F $OUT" \
+testing ":grp" "chown root:root $F && chown :$GRP $F $OUT" \
"root $GRP\n" "" ""
-testing "chown :" "chown $USR:$GRP $F && chown : $F $OUT" \
+testing ":" "chown $USR:$GRP $F && chown : $F $OUT" \
"$USR $GRP\n" "" ""
rm -rf testdir
#testing "name" "command" "result" "infile" "stdin"
# Default behavior on stdin and on files.
-testing "cksum on stdin" "echo -n hello | cksum" "3287646509 5\n" "" ""
+testing "on stdin" "echo -n hello | cksum" "3287646509 5\n" "" ""
echo -n "hello" > tmpfile
-testing "cksum on file" "cksum tmpfile" "3287646509 5 tmpfile\n" "" ""
+testing "on file" "cksum tmpfile" "3287646509 5 tmpfile\n" "" ""
rm -f tmpfile
touch one two
-testing "cksum on multiple files" "cksum one two" "4294967295 0 one\n4294967295 0 two\n" "" ""
+testing "on multiple files" "cksum one two" "4294967295 0 one\n4294967295 0 two\n" "" ""
rm -f one two
# Check the length suppression, both calculate the CRC on 'abc' but the second
# option has length suppression on and has the length concatenated to 'abc'.
-testing "cksum on abc including length" "echo -n 'abc' | cksum" "1219131554 3\n" "" ""
-testing "cksum on abc excluding length" "echo -ne 'abc\x3' | cksum -N" "1219131554 4\n" "" ""
+testing "on abc including length" "echo -n 'abc' | cksum" "1219131554 3\n" "" ""
+testing "on abc excluding length" "echo -ne 'abc\x3' | cksum -N" "1219131554 4\n" "" ""
# cksum on no contents gives 0xffffffff (=4294967295)
-testing "cksum on no data post-inversion" "echo -n "" | cksum" "4294967295 0\n" "" ""
+testing "on no data post-inversion" "echo -n "" | cksum" "4294967295 0\n" "" ""
# If we do preinversion we will then get 0.
-testing "cksum on no data pre+post-inversion" "echo -n "" | cksum -P" "0 0\n" "" ""
+testing "on no data pre+post-inversion" "echo -n "" | cksum -P" "0 0\n" "" ""
# If we skip the post-inversion we also get 0
-testing "cksum on no data no inversion" "echo -n "" | cksum -I" "0 0\n" "" ""
+testing "on no data no inversion" "echo -n "" | cksum -I" "0 0\n" "" ""
# Two wrongs make a right.
-testing "cksum on no data pre-inversion" "echo -n "" | cksum -PI" "4294967295 0\n" "" ""
+testing "on no data pre-inversion" "echo -n "" | cksum -PI" "4294967295 0\n" "" ""
[ -f testing.sh ] && . testing.sh
-testing "cmp not enough arguments [fail]" "cmp input 2>/dev/null || echo yes" "yes\n" "foo" ""
-testing "cmp missing file1 [fail]" "cmp file1 input 2>/dev/null || echo yes" "yes\n" "foo" ""
+testing "not enough arguments [fail]" "cmp input 2>/dev/null || echo yes" "yes\n" "foo" ""
+testing "missing file1 [fail]" "cmp file1 input 2>/dev/null || echo yes" "yes\n" "foo" ""
#mkdir dir
-#testing "cmp directory [fail]" "cmp dir dir 2>/dev/null || echo yes" \
+#testing "directory [fail]" "cmp dir dir 2>/dev/null || echo yes" \
#"yes\n" "" ""
#rmdir dir
echo "ab
c" > input2
-testing "cmp identical files, stdout" "cmp input input2" "" "ab\nc\n" ""
-testing "cmp identical files, return code" "cmp input input2 && echo yes" "yes\n" "ab\nc\n" ""
+testing "identical files, stdout" "cmp input input2" "" "ab\nc\n" ""
+testing "identical files, return code" "cmp input input2 && echo yes" "yes\n" "ab\nc\n" ""
-testing "cmp EOF, stderr" "cmp input input2 2>&1" "cmp: EOF on input2\n" "ab\nc\nx" ""
-testing "cmp EOF, return code" "cmp input input2 2>/dev/null || echo yes" "yes\n" "ab\nc\nx" ""
+testing "EOF, stderr" "cmp input input2 2>&1" "cmp: EOF on input2\n" "ab\nc\nx" ""
+testing "EOF, return code" "cmp input input2 2>/dev/null || echo yes" "yes\n" "ab\nc\nx" ""
# The gnu/dammit version fails this because posix says "char" and they don't.
-testing "cmp diff, stdout" "cmp input input2" "input input2 differ: char 4, line 2\n" "ab\nx\nx" ""
-testing "cmp diff, return code" "cmp input input2 > /dev/null || echo yes" "yes\n" "ab\nx\nx" ""
+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 "cmp -s EOF, return code" "cmp -s input input2 || echo yes" "yes\n" "ab\nc\nx" ""
-testing "cmp -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 "cmp -l EOF, stderr" "cmp -l input input2 2>&1" "cmp: EOF on input2\n" "ab\nc\nx" ""
-testing "cmp -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 "-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 "cmp stdin and file" "cmp input -" "input - differ: char 4, line 2\n" "ab\nc\n" "ab\nx\n"
-#testing "cmp stdin and stdin" "cmp input -" "" "" "ab\nc\n"
+testing "stdin and file" "cmp input -" "input - differ: char 4, line 2\n" "ab\nc\n" "ab\nx\n"
+#testing "stdin and stdin" "cmp input -" "" "" "ab\nc\n"
#testing "name" "command" "result" "infile" "stdin"
-testing "cp not enough arguments [fail]" "cp one 2>/dev/null || echo yes" \
+testing "not enough arguments [fail]" "cp one 2>/dev/null || echo yes" \
"yes\n" "" ""
-testing "cp -missing source [fail]" "cp missing two 2>/dev/null || echo yes" \
+testing "-missing source [fail]" "cp missing two 2>/dev/null || echo yes" \
"yes\n" "" ""
-testing "cp file->file" "cp random two && cmp random two && echo yes" \
+testing "file->file" "cp random two && cmp random two && echo yes" \
"yes\n" "" ""
rm two
mkdir two
-testing "cp file->dir" "cp random two && cmp random two/random && echo yes" \
+testing "file->dir" "cp random two && cmp random two/random && echo yes" \
"yes\n" "" ""
rm two/random
-testing "cp file->dir/file" \
+testing "file->dir/file" \
"cp random two/random && cmp random two/random && echo yes" \
"yes\n" "" ""
-testing "cp -r dir->missing" \
+testing "-r dir->missing" \
"cp -r two three && cmp random three/random && echo yes" \
"yes\n" "" ""
touch walrus
-testing "cp -r dir->file [fail]" \
+testing "-r dir->file [fail]" \
"cp -r two walrus 2>/dev/null || echo yes" "yes\n" "" ""
touch two/three
-testing "cp -r dir hits file." \
+testing "-r dir hits file." \
"cp -r three two 2>/dev/null || echo yes" "yes\n" "" ""
rm -rf two three walrus
touch two
chmod 000 two
-testing "cp file->inaccessable [fail]" \
+testing "file->inaccessable [fail]" \
"cp random two 2>/dev/null || echo yes" "yes\n" "" ""
rm -f two
touch two
chmod 000 two
-testing "cp -f file->inaccessable" \
+testing "-f file->inaccessable" \
"cp -f random two && cmp random two && echo yes" "yes\n" "" ""
mkdir sub
chmod 000 sub
-testing "cp file->inaccessable_dir [fail]" \
+testing "file->inaccessable_dir [fail]" \
"cp random sub 2>/dev/null || echo yes" "yes\n" "" ""
rm two
rmdir sub
#mkdir dir
#touch file
-#testing "cp -rf dir file [fail]" "cp -rf dir file 2>/dev/null || echo yes" \
+#testing "-rf dir file [fail]" "cp -rf dir file 2>/dev/null || echo yes" \
# "yes\n" "" ""
#rm -rf dir file
touch one two
-testing "cp file1 file2 missing [fail]" \
+testing "file1 file2 missing [fail]" \
"cp one two missing 2>/dev/null || echo yes" "yes\n" "" ""
mkdir dir
-testing "cp dir file missing [fail]" \
+testing "dir file missing [fail]" \
"cp dir two missing 2>/dev/null || echo yes" "yes\n" "" ""
-testing "cp -rf dir file missing [fail]" \
+testing "-rf dir file missing [fail]" \
"cp dir two missing 2>/dev/null || echo yes" "yes\n" "" ""
-testing "cp file1 file2 file [fail]" \
+testing "file1 file2 file [fail]" \
"cp random one two 2>/dev/null || echo yes" "yes\n" "" ""
-testing "cp file1 file2 dir" \
+testing "file1 file2 dir" \
"cp random one dir && cmp random dir/random && cmp one dir/one && echo yes" \
"yes\n" "" ""
rm one two random
mkdir -p one/two/three/four
touch one/two/three/five
touch one/{six,seven,eight}
-testing "cp -r /abspath dest" \
+testing "-r /abspath dest" \
"cp -r \"$(readlink -f one)\" dir && diff -r one dir && echo yes" \
"yes\n" "" ""
-testing "cp -r dir again" "cp -r one/. dir && diff -r one dir && echo yes" \
+testing "-r dir again" "cp -r one/. dir && diff -r one dir && echo yes" \
"yes\n" "" ""
mkdir dir2
-testing "cp -r dir1/* dir2" \
+testing "-r dir1/* dir2" \
"cp -r one/* dir2 && diff -r one dir2 && echo yes" "yes\n" "" ""
rm -rf one dir dir2
# plus file sizes of at least 0-4.
touch a bb ccc dddd
-testing "cpio name padding" "cpio -o -H newc|cpio -it" "a\nbb\nccc\ndddd\n" "" "a\nbb\nccc\ndddd\n"
+testing "name padding" "cpio -o -H newc|cpio -it" "a\nbb\nccc\ndddd\n" "" "a\nbb\nccc\ndddd\n"
rm a bb ccc dddd
touch a
printf '1' >b
printf '22' >c
printf '333' >d
-testing "cpio file padding" "cpio -o -H newc|cpio -it" "a\nb\nc\nd\n" "" "a\nb\nc\nd\n"
+testing "file padding" "cpio -o -H newc|cpio -it" "a\nb\nc\nd\n" "" "a\nb\nc\nd\n"
rm a b c d
touch a
# the relevant bit should be here:
# 110*5 + 4*3 + 2 + 6*3 = 550 + 12 + 20 = 582
# files are padded to n*4, names are padded to 2 + n*4 due to the header length
-testing "cpio archive length" "cpio -o -H newc|dd ibs=2 skip=291 count=5 2>/dev/null" "TRAILER!!!" "" "a\nbb\nccc\ndddd\n"
-testing "cpio archive magic" "cpio -o -H newc|dd ibs=2 count=3 2>/dev/null" "070701" "" "a\n"
+testing "archive length" "cpio -o -H newc|dd ibs=2 skip=291 count=5 2>/dev/null" "TRAILER!!!" "" "a\nbb\nccc\ndddd\n"
+testing "archive magic" "cpio -o -H newc|dd ibs=2 count=3 2>/dev/null" "070701" "" "a\n"
# check name length (8 bytes before the empty "crc")
-testing "cpio name length" "cpio -o -H newc|dd ibs=2 skip=47 count=4 2>/dev/null" "00000002" "" "a\n"
+testing "name length" "cpio -o -H newc|dd ibs=2 skip=47 count=4 2>/dev/null" "00000002" "" "a\n"
rm a bb ccc dddd
# archive dangling symlinks and empty files even if we cannot open them
touch a; chmod a-rwx a; ln -s a/cant b
-testing "cpio archives unreadable empty files" "cpio -o -H newc|cpio -it" "a\nb\n" "" "a\nb\n"
+testing "archives unreadable empty files" "cpio -o -H newc|cpio -it" "a\nb\n" "" "a\nb\n"
chmod u+rw a; rm -f a b
alpha:beta:gamma:delta:epsilon:zeta:eta:teta:iota:kappa:lambda:mu
the quick brown fox jumps over the lazy dog" >abc.txt
-testing "cut with -c (a-b)" "cut -c 4-10 abc.txt" ":two:th\nha:beta\n quick \n" "" ""
-testing "cut with -f (a-)" "cut -d ':' -f 5- abc.txt" "five:six:seven\nepsilon:zeta:eta:teta:iota:kappa:lambda:mu\nthe quick brown fox jumps over the lazy dog\n" "" ""
+testing "with -c (a-b)" "cut -c 4-10 abc.txt" ":two:th\nha:beta\n quick \n" "" ""
+testing "with -f (a-)" "cut -d ':' -f 5- abc.txt" "five:six:seven\nepsilon:zeta:eta:teta:iota:kappa:lambda:mu\nthe quick brown fox jumps over the lazy dog\n" "" ""
-testing "cut with -f (a)" "cut -d ' ' -f 3 abc.txt" "one:two:three:four:five:six:seven\nalpha:beta:gamma:delta:epsilon:zeta:eta:teta:iota:kappa:lambda:mu\nbrown\n" "" ""
+testing "with -f (a)" "cut -d ' ' -f 3 abc.txt" "one:two:three:four:five:six:seven\nalpha:beta:gamma:delta:epsilon:zeta:eta:teta:iota:kappa:lambda:mu\nbrown\n" "" ""
-testing "cut with echo, -c (a-b)" "echo 'ref_categorie=test' | cut -c 1-15 " "ref_categorie=t\n" "" ""
-testing "cut with echo, -c (a)" "echo 'ref_categorie=test' | cut -c 14" "=\n" "" ""
+testing "with echo, -c (a-b)" "echo 'ref_categorie=test' | cut -c 1-15 " "ref_categorie=t\n" "" ""
+testing "with echo, -c (a)" "echo 'ref_categorie=test' | cut -c 14" "=\n" "" ""
# Modifying abc.txt data as per new testcase
echo "abcdefghijklmnopqrstuvwxyz" >abc.txt
-testing "cut with -c (a,b,c)" "cut -c 4,5,20 abc.txt" "det\n" "" ""
+testing "with -c (a,b,c)" "cut -c 4,5,20 abc.txt" "det\n" "" ""
-testing "cut with -b (a,b,c)" "cut -b 4,5,20 abc.txt" "det\n" "" ""
+testing "with -b (a,b,c)" "cut -b 4,5,20 abc.txt" "det\n" "" ""
# Modifying abc.txt data as per testcase
echo "406378:Sales:Itorre:Jan
636496:Research:Ancholie:Mel
396082:Sales:Jucacion:Ed" >abc.txt
-testing "cut with -d -f(:) -s" "cut -d: -f3 -s abc.txt" "Itorre\nNasium\nAncholie\nJucacion\n" "" ""
+testing "with -d -f(:) -s" "cut -d: -f3 -s abc.txt" "Itorre\nNasium\nAncholie\nJucacion\n" "" ""
-testing "cut with -d -f( ) -s" "cut -d' ' -f3 -s abc.txt && echo yes" "yes\n" "" ""
+testing "with -d -f( ) -s" "cut -d' ' -f3 -s abc.txt && echo yes" "yes\n" "" ""
-testing "cut with -d -f(a) -s" "cut -da -f3 -s abc.txt" "n\nsium:Jim\n\ncion:Ed\n" "" ""
+testing "with -d -f(a) -s" "cut -da -f3 -s abc.txt" "n\nsium:Jim\n\ncion:Ed\n" "" ""
-testing "cut with -d -f(a) -s -n" "cut -da -f3 -s -n abc.txt" "n\nsium:Jim\n\ncion:Ed\n" "" ""
+testing "with -d -f(a) -s -n" "cut -da -f3 -s -n abc.txt" "n\nsium:Jim\n\ncion:Ed\n" "" ""
# Removing abc.txt file for cleanup purpose
rm abc.txt
#testing "name" "command" "result" "infile" "stdin"
# Test Unix date parsing.
-testing "date -d @0" "TZ=UTC date -d @0 2>&1" "Thu Jan 1 00:00:00 GMT 1970\n" "" ""
-testing "date -d @0x123" "TZ=UTC date -d @0x123 2>&1" "date: bad date '@0x123'\n" "" ""
+testing "-d @0" "TZ=UTC date -d @0 2>&1" "Thu Jan 1 00:00:00 GMT 1970\n" "" ""
+testing "-d @0x123" "TZ=UTC date -d @0x123 2>&1" "date: bad date '@0x123'\n" "" ""
# Test basic date parsing.
# Note that toybox's -d format is not the same as coreutils'.
-testing "date -d 06021234" "TZ=UTC date -d 06021234 2>&1" "Sun Jun 2 12:34:00 UTC 1900\n" "" ""
-testing "date -d 060212341982" "TZ=UTC date -d 060212341982 2>&1" "Sun Jun 2 12:34:00 UTC 1982\n" "" ""
-testing "date -d 123" "TZ=UTC date -d 123 2>&1" "date: bad date '123'\n" "" ""
+testing "-d 06021234" "TZ=UTC date -d 06021234 2>&1" "Sun Jun 2 12:34:00 UTC 1900\n" "" ""
+testing "-d 060212341982" "TZ=UTC date -d 060212341982 2>&1" "Sun Jun 2 12:34:00 UTC 1982\n" "" ""
+testing "-d 123" "TZ=UTC date -d 123 2>&1" "date: bad date '123'\n" "" ""
# Test parsing 2- and 4-digit years.
-testing "date -d 1110143115.30" "TZ=UTC date -d 1110143115.30 2>&1" "Sun Nov 10 14:31:30 UTC 1915\n" "" ""
-testing "date -d 111014312015.30" "TZ=UTC date -d 111014312015.30 2>&1" "Sun Nov 10 14:31:30 UTC 2015\n" "" ""
+testing "-d 1110143115.30" "TZ=UTC date -d 1110143115.30 2>&1" "Sun Nov 10 14:31:30 UTC 1915\n" "" ""
+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 "date 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 "date 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" "" ""
#testing "name" "command" "result" "infile" "stdin"
-testing "dd if=(file)" "dd if=input $opt" "I WANT\n" "I WANT\n" ""
-testing "dd of=(file)" "dd of=file $opt && cat file" "I WANT\n" "" "I WANT\n"
-testing "dd if=file of=file" "dd if=input of=foo $opt && cat foo && rm -f foo" \
+# 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" \
"I WANT\n" "I WANT\n" ""
-testing "dd if=file | dd of=file" "dd if=input $opt | dd of=foo $opt &&
+testing "if=file | dd of=file" "dd if=input $opt | dd of=foo $opt &&
cat foo && rm -f foo" "I WANT\n" "I WANT\n" ""
-testing "dd (stdout)" "dd $opt" "I WANT\n" "" "I WANT\n"
-testing "dd sync,noerror" \
+testing "(stdout)" "dd $opt" "I WANT\n" "" "I WANT\n"
+testing "sync,noerror" \
"dd if=input of=outFile seek=8860 bs=1M conv=sync,noerror $opt &&
stat -c \"%s\" outFile && rm -f outFile" "9291431936\n" "I WANT\n" ""
-testing "dd if=file of=(null)" \
+testing "if=file of=(null)" \
"dd if=input of=/dev/null $opt && echo 'yes'" "yes\n" "I WANT\n" ""
-testing "dd with if of bs" \
+testing "with if of bs" \
"dd if=/dev/zero of=sda.txt bs=512 count=1 $opt &&
stat -c '%s' sda.txt && rm -f sda.txt" "512\n" "" ""
-testing "dd with if of ibs obs" \
+testing "with if of ibs obs" \
"dd if=/dev/zero of=sda.txt ibs=512 obs=256 count=1 $opt &&
stat -c '%s' sda.txt && rm -f sda.txt" "512\n" "" ""
-testing "dd with if of ibs obs count" \
+testing "with if of ibs obs count" \
"dd if=/dev/zero of=sda.txt ibs=512 obs=256 count=3 $opt &&
stat -c '%s' sda.txt && rm -f sda.txt" "1536\n" "" ""
ln -s input softlink
-testing "dd if=softlink" "dd if=softlink $opt" "I WANT\n" "I WANT\n" ""
+testing "if=softlink" "dd if=softlink $opt" "I WANT\n" "I WANT\n" ""
unlink softlink
ln -s file softlink
-testing "dd if=file of=softlink" "dd if=input of=softlink $opt &&
+testing "if=file of=softlink" "dd if=input of=softlink $opt &&
[ -f file -a -L softlink ] && cat softlink" "I WANT\n" "I WANT\n" ""
unlink softlink && rm -f file
-testing "dd if=file of=file (same file)" "dd if=input of=input $opt &&
+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 "dd with ibs obs bs" "dd ibs=2 obs=5 bs=9 $opt" "I WANT\n" "" "I WANT\n"
-testing "dd with ibs obs bs if" "dd ibs=2 obs=5 bs=9 if=input $opt" \
+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" \
"I WANT\n" "I WANT\n" ""
-testing "dd with ibs obs count" "dd ibs=1 obs=1 count=1 $opt" "I" "" "I WANT\n"
-testing "dd with ibs obs count if" "dd ibs=1 obs=1 count=3 if=input $opt" \
+testing "with ibs obs count" "dd ibs=1 obs=1 count=1 $opt" "I" "" "I WANT\n"
+testing "with ibs obs count if" "dd ibs=1 obs=1 count=3 if=input $opt" \
"I W" "I WANT\n" ""
-testing "dd with count" "dd count=1 $opt" "I WANT\n" "" "I WANT\n"
-testing "dd with count if" "dd count=1 if=input $opt" "I WANT\n" "I WANT\n" ""
-
-testing "dd with skip" "dd skip=0 $opt" "I WANT\n" "" "I WANT\n"
-testing "dd with skip if" "dd skip=0 if=input $opt" "I WANT\n" "I WANT\n" ""
+testing "with count" "dd count=1 $opt" "I WANT\n" "" "I WANT\n"
+testing "with count if" "dd count=1 if=input $opt" "I WANT\n" "I WANT\n" ""
-testing "dd with seek" "dd seek=0 $opt" "I WANT\n" "" "I WANT\n"
-testing "dd with seek if" "dd seek=0 if=input $opt" "I WANT\n" "I WANT\n" ""
+testing "with skip" "dd skip=0 $opt" "I WANT\n" "" "I WANT\n"
+testing "with skip if" "dd skip=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 "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" ""
# Testing only 'notrunc', 'noerror', 'fsync', 'sync'
-testing "dd conv=notrunc" "dd conv=notrunc $opt" "I WANT\n" "" "I WANT\n"
-testing "dd conv=notrunc with IF" "dd conv=notrunc if=input $opt" "I WANT\n" \
+testing "conv=notrunc" "dd conv=notrunc $opt" "I WANT\n" "" "I WANT\n"
+testing "conv=notrunc with IF" "dd conv=notrunc if=input $opt" "I WANT\n" \
"I WANT\n" ""
-testing "dd conv=noerror" "dd conv=noerror $opt" "I WANT\n" "" "I WANT\n"
-testing "dd conv=noerror with IF" "dd conv=noerror if=input $opt" "I WANT\n" \
+testing "conv=noerror" "dd conv=noerror $opt" "I WANT\n" "" "I WANT\n"
+testing "conv=noerror with IF" "dd conv=noerror if=input $opt" "I WANT\n" \
"I WANT\n" ""
-testing "dd conv=fsync" "dd conv=fsync $opt" "I WANT\n" "" "I WANT\n"
-testing "dd conv=fsync with IF" "dd conv=fsync if=input $opt" "I WANT\n" \
+testing "conv=fsync" "dd conv=fsync $opt" "I WANT\n" "" "I WANT\n"
+testing "conv=fsync with IF" "dd conv=fsync if=input $opt" "I WANT\n" \
"I WANT\n" ""
-testing "dd conv=sync" "dd conv=sync $opt | head -n 1" "I WANT\n" "" "I WANT\n"
-testing "dd conv=sync with IF" "dd conv=sync if=input $opt | head -n 1" "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" ""
--- /dev/null
+#!/bin/bash
+
+#testing "name" "command" "result" "infile" "stdin"
+
+seq 10 > left
+seq 11 > right
+
+expected='--- left
++++ right
+@@ -8,3 +8,4 @@
+ 8
+ 9
+ 10
++11
+'
+# Hm this only gives unified diffs?
+testing "simple" "diff left right" "$expected" "" ""
+
+
+expected='--- tree1/file
++++ tree2/file
+@@ -1 +1 @@
+-foo
++food
+'
+mkdir -p tree1 tree2
+echo foo > tree1/file
+echo food > tree2/file
+
+testing "simple" "diff -r tree1 tree2 |tee out" "$expected" "" ""
#testing "name" "command" "result" "infile" "stdin"
-testing "dirname /-only" "dirname ///////" "/\n" "" ""
-testing "dirname trailing /" "dirname a//////" ".\n" "" ""
-testing "dirname combined" "dirname /////a///b///c///d/////" "/////a///b///c\n" "" ""
-testing "dirname /a/" "dirname /////a///" "/\n" "" ""
+testing "/-only" "dirname ///////" "/\n" "" ""
+testing "trailing /" "dirname a//////" ".\n" "" ""
+testing "combined" "dirname /////a///b///c///d/////" "/////a///b///c\n" "" ""
+testing "/a/" "dirname /////a///" "/\n" "" ""
# while -k is the default on most Linux systems
mkdir -p du_test/test du_2/foo
-testing "du (no options)" "du -k du_test" "4\tdu_test/test\n8\tdu_test\n" "" ""
-testing "du -s" "du -k -s du_test" "8\tdu_test\n" "" ""
+testing "(no options)" "du -k du_test" "4\tdu_test/test\n8\tdu_test\n" "" ""
+testing "-s" "du -k -s du_test" "8\tdu_test\n" "" ""
ln -s ../du_2 du_test/xyz
# "du shall count the size of the symbolic link"
# The tests assume that like for most POSIX systems symbolic
# links are stored directly in the inode so that the
# allocated file space is zero.
-testing "du counts symlinks without following" "du -ks du_test" "8\tdu_test\n" "" ""
-testing "du -L follows symlinks" "du -ksL du_test" "16\tdu_test\n" "" ""
+testing "counts symlinks without following" "du -ks du_test" "8\tdu_test\n" "" ""
+testing "-L follows symlinks" "du -ksL du_test" "16\tdu_test\n" "" ""
ln -s . du_test/up
-testing "du -L avoid endless loop" "du -ksL du_test" "16\tdu_test\n" "" ""
+testing "-L avoid endless loop" "du -ksL du_test" "16\tdu_test\n" "" ""
rm du_test/up
# if -H and -L are specified, the last takes priority
-testing "du -HL follows symlinks" "du -ksHL du_test" "16\tdu_test\n" "" ""
-testing "du -H does not follow unspecified symlinks" "du -ksH du_test" "8\tdu_test\n" "" ""
-testing "du -LH does not follow unspecified symlinks" "du -ksLH du_test" "8\tdu_test\n" "" ""
-testing "du -H follows specified symlinks" "du -ksH du_test/xyz" "8\tdu_test/xyz\n" "" ""
+testing "-HL follows symlinks" "du -ksHL du_test" "16\tdu_test\n" "" ""
+testing "-H does not follow unspecified symlinks" "du -ksH du_test" "8\tdu_test\n" "" ""
+testing "-LH does not follow unspecified symlinks" "du -ksLH du_test" "8\tdu_test\n" "" ""
+testing "-H follows specified symlinks" "du -ksH du_test/xyz" "8\tdu_test/xyz\n" "" ""
rm -rf du_test du_2
#testing "name" "command" "result" "infile" "stdin"
testing "echo" "$CMD && echo yes" "\nyes\n" "" ""
-testing "echo 1 2 3" "$CMD one two three" "one two three\n" "" ""
-testing "echo with spaces" "$CMD 'one two three'" \
+testing "1 2 3" "$CMD one two three" "one two three\n" "" ""
+testing "with spaces" "$CMD 'one two three'" \
"one two three\n" "" ""
-testing "echo -n" "$CMD -n" "" "" ""
-testing "echo -n one" "$CMD -n one" "one" "" ""
-testing "echo one -n" "$CMD one -n" "one -n\n" "" ""
-testing "echo -en" "$CMD -en 'one\ntwo'" "one\ntwo" "" ""
-testing "echo --hello" "$CMD --hello" "--hello\n" "" ""
-testing "echo -e all" "$CMD -e '\a\b\c\f\n\r\t\v\\\0123'" \
+testing "-n" "$CMD -n" "" "" ""
+testing "-n one" "$CMD -n one" "one" "" ""
+testing "one -n" "$CMD one -n" "one -n\n" "" ""
+testing "-en" "$CMD -en 'one\ntwo'" "one\ntwo" "" ""
+testing "--hello" "$CMD --hello" "--hello\n" "" ""
+testing "-e all" "$CMD -e '\a\b\c\f\n\r\t\v\\\0123'" \
"\a\b\c\f\n\r\t\v\\\0123\n" "" ""
-testing "echo -nex hello" "$CMD -nex hello" "-nex hello\n" "" ""
+testing "-nex hello" "$CMD -nex hello" "-nex hello\n" "" ""
# Octal formatting tests
-testing "echo -e octal values" \
+testing "-e octal values" \
"$CMD -ne '\01234 \0060 \060 \0130\0131\0132 \077\012'" \
"S4 0 0 XYZ ?\n" "" ""
# Hexadecimal value tests
-testing "echo -e hexadecimal values" \
+testing "-e hexadecimal values" \
"$CMD -ne '\x534 \x30 \x58\x59\x5a \x3F\x0A'"\
"S4 0 XYZ ?\n" "" ""
-testing "echo -e \p" "$CMD -e '\\p'" "\\p\n" "" ""
+testing "-e \p" "$CMD -e '\\p'" "\\p\n" "" ""
# some basic tests
-testing "expand default" "expand input" " foo bar\n" "\tfoo\tbar\n" ""
-testing "expand default stdin" "expand" " foo bar\n" "" "\tfoo\tbar\n"
-testing "expand single" "expand -t 2 input" " foo bar\n" "\tfoo\tbar\n" ""
-testing "expand tablist" "expand -t 5,10,12 input" " foo bar foo\n" "\tfoo\tbar\tfoo\n" ""
-testing "expand backspace" "expand input" "foobarfoo\b\b bar\n" "foobarfoo\b\b\tbar\n" ""
+testing "default" "expand input" " foo bar\n" "\tfoo\tbar\n" ""
+testing "default stdin" "expand" " foo bar\n" "" "\tfoo\tbar\n"
+testing "single" "expand -t 2 input" " foo bar\n" "\tfoo\tbar\n" ""
+testing "tablist" "expand -t 5,10,12 input" " foo bar foo\n" "\tfoo\tbar\tfoo\n" ""
+testing "backspace" "expand input" "foobarfoo\b\b bar\n" "foobarfoo\b\b\tbar\n" ""
# advanced tests
BIGTAB=$BIGTAB$BIGTAB
TABSTOP=$[$TABSTOP*2]
done
-testing "expand long tab single" "expand -t $TABSTOP input" "${BIGTAB}foo\n" "\tfoo\n" ""
-testing "expand long tab tablist" "expand -t $TABSTOP,$[TABSTOP+5] input" \
+testing "long tab single" "expand -t $TABSTOP input" "${BIGTAB}foo\n" "\tfoo\n" ""
+testing "long tab tablist" "expand -t $TABSTOP,$[TABSTOP+5] input" \
"${BIGTAB}foo bar\n" "\tfoo\tbar\n" ""
-testing "expand multiline single" "expand -t 4 input" "foo \n bar\n" "foo\t\n\tbar\n" ""
-testing "expand multiline tablist" "expand -t 4,8 input" \
+testing "multiline single" "expand -t 4 input" "foo \n bar\n" "foo\t\n\tbar\n" ""
+testing "multiline tablist" "expand -t 4,8 input" \
"foo bar\n bar foo\n" "foo\t\tbar\n\tbar\tfoo\n" ""
POW=15
BIGLINE="foo "
EXPANDLINE="${BIGLINE} foo\n"
fi
BIGLINE="${BIGLINE}\tfoo\n"
-testing "expand long line single" "expand input" \
+testing "long line single" "expand input" \
"${EXPANDLINE}" "$BIGLINE" ""
[ -f testing.sh ] && . testing.sh
-testing "expr integer" "expr 5" "5\n" "" ""
-testing "expr integer negative" "expr -5" "-5\n" "" ""
-testing "expr string" "expr astring" "astring\n" "" ""
-testing "expr 1 + 3" "expr 1 + 3" "4\n" "" ""
-testing "expr 5 + 6 * 3" "expr 5 + 6 \* 3" "23\n" "" ""
-testing "expr ( 5 + 6 ) * 3" "expr \( 5 + 6 \) \* 3" "33\n" "" ""
-testing "expr * / same priority" "expr 4 \* 3 / 2" "6\n" "" ""
-testing "expr / * same priority" "expr 3 / 2 \* 4" "4\n" "" ""
-testing "expr & before |" "expr 0 \| 1 \& 0" "0\n" "" ""
-testing "expr | after &" "expr 1 \| 0 \& 0" "1\n" "" ""
-testing "expr | & same priority" "expr 0 \& 0 \| 1" "1\n" "" ""
-testing "expr % * same priority" "expr 3 % 2 \* 4" "4\n" "" ""
-testing "expr * % same priority" "expr 3 \* 2 % 4" "2\n" "" ""
-testing "expr = > same priority" "expr 0 = 2 \> 3" "0\n" "" ""
-testing "expr > = same priority" "expr 3 \> 2 = 1" "1\n" "" ""
-testing "expr string becomes integer" "expr ab21xx : '[^0-9]*\([0-9]*\)' + 3" \
+testing "integer" "expr 5" "5\n" "" ""
+testing "integer negative" "expr -5" "-5\n" "" ""
+testing "string" "expr astring" "astring\n" "" ""
+testing "addition" "expr 1 + 3" "4\n" "" ""
+testing "5 + 6 * 3" "expr 5 + 6 \* 3" "23\n" "" ""
+testing "( 5 + 6 ) * 3" "expr \( 5 + 6 \) \* 3" "33\n" "" ""
+testing ">" "expr 3 \> 2" "1\n" "" ""
+testing "* / same priority" "expr 4 \* 3 / 2" "6\n" "" ""
+testing "/ * same priority" "expr 3 / 2 \* 4" "4\n" "" ""
+testing "& before |" "expr 0 \| 1 \& 0" "0\n" "" ""
+testing "| after &" "expr 1 \| 0 \& 0" "1\n" "" ""
+testing "| & same priority" "expr 0 \& 0 \| 1" "1\n" "" ""
+testing "% * same priority" "expr 3 % 2 \* 4" "4\n" "" ""
+testing "* % same priority" "expr 3 \* 2 % 4" "2\n" "" ""
+testing "= > same priority" "expr 0 = 2 \> 3" "0\n" "" ""
+testing "> = same priority" "expr 3 \> 2 = 1" "1\n" "" ""
+
+testing "00 | 1" "expr 00 \| 1" "1\n" "" ""
+testing "-0 | 1" "expr -0 \| 2" "2\n" "" ""
+testing '"" | 1' 'expr "" \| 3' "3\n" "" ""
+testing "/ by zero" "expr 1 / 0 2>/dev/null; echo \$?" "2\n" "" ""
+testing "% by zero" "expr 1 % 0 2>/dev/null; echo \$?" "2\n" "" ""
+
+testing "regex position" "expr ab21xx : '[^0-9]*[0-9]*'" "4\n" "" ""
+testing "regex extraction" "expr ab21xx : '[^0-9]*\([0-9]*\).*'" "21\n" "" ""
+testing "regex no match" "expr ab21xx : x" "0\n" "" ""
+testing "long str" "expr abcdefghijklmnopqrstuvwxyz : '\(.*\)' = a" "0\n" "" ""
+
+# result of ':' regex match can subsequently be used for arithmetic
+testing "string becomes integer" "expr ab21xx : '[^0-9]*\([0-9]*\)' + 3" \
"24\n" "" ""
+
+testing "integer comparison" "expr -3 \< -2" "1\n" "" ""
+testing "string comparison" "expr -3 \< -2s" "0\n" "" ""
+testing "integer expression comparison" "expr 2 - 5 \< -2" "1\n" "" ""
+# result of arithmetic can subsequently be compared as a string
+testing "string expr comparison" "expr 2 - 5 \< -2s" "0\n" "" ""
+
+testing "parens around literal" "expr \( a \)" "a\n" "" ""
+
+testing "exit code when true" "expr a; echo \$?" "a\n0\n" "" ""
+testing "exit code when false" "expr 0; echo \$?" "0\n1\n" "" ""
+testing "exit code with syntax error" "expr \( 2>/dev/null; echo \$?" \
+ "2\n" "" ""
+testing "exit code when evaluating to 0" "expr -1 + 1; echo \$?" "0\n1\n" "" ""
+
+# BUG: segfaults because '3' is coerced to integer and regexc gets NULL
+testing "regex segfault" "expr 3 : '\(.\)'" "3\n" "" ""
+
+# syntax errors
+testing "no expression" "expr 2>/dev/null; echo \$?" "2\n" "" ""
+testing "empty ()" "expr \( \) 2>/dev/null; echo \$?" "2\n" "" ""
+testing "missing )" "expr \( 1 2>/dev/null; echo \$?" "2\n" "" ""
+testing "missing outer )" "expr \( 1 + \( 2 \* 3 \) 2>/dev/null; echo \$?" \
+ "2\n" "" ""
+testing "bad operator" "expr 1 @ 2 2>/dev/null; echo \$?" "2\n" "" ""
+testing "adjacent literals" "expr 1 2 2>/dev/null; echo \$?" "2\n" "" ""
+testing "non-integer argument" "expr 1 + a 2>/dev/null; echo \$?" "2\n" "" ""
#testing "name" "command" "result" "infile" "stdin"
-testing "factor -32" "factor -32" "-32: -1 2 2 2 2 2\n" "" ""
-testing "factor 0" "factor 0" "0: 0\n" "" ""
-testing "factor 1" "factor 1" "1: 1\n" "" ""
-testing "factor 2" "factor 2" "2: 2\n" "" ""
-testing "factor 3" "factor 3" "3: 3\n" "" ""
-testing "factor 4" "factor 4" "4: 2 2\n" "" ""
-testing "factor 10000000017" "factor 10000000017" \
+testing "-32" "factor -32" "-32: -1 2 2 2 2 2\n" "" ""
+testing "0" "factor 0" "0: 0\n" "" ""
+testing "1" "factor 1" "1: 1\n" "" ""
+testing "2" "factor 2" "2: 2\n" "" ""
+testing "3" "factor 3" "3: 3\n" "" ""
+testing "4" "factor 4" "4: 2 2\n" "" ""
+testing "10000000017" "factor 10000000017" \
"10000000017: 3 3 3 7 7 7 1079797\n" "" ""
-testing "factor 10000000018" "factor 10000000018" \
+testing "10000000018" "factor 10000000018" \
"10000000018: 2 131 521 73259\n" "" ""
-testing "factor 10000000019" "factor 10000000019" \
+testing "10000000019" "factor 10000000019" \
"10000000019: 10000000019\n" "" ""
-testing "factor 3 6 from stdin" "factor" "3: 3\n6: 2 3\n" "" "3 6"
-testing "factor stdin newline" "factor" "3: 3\n6: 2 3\n" "" "3\n6\n"
+testing "3 6 from stdin" "factor" "3: 3\n6: 2 3\n" "" "3 6"
+testing "stdin newline" "factor" "3: 3\n6: 2 3\n" "" "3\n6\n"
--- /dev/null
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+touch empty
+echo "#!/bin/bash" > bash.script
+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" "" ""
+testing "bash.script with spaces" "file bash.script2" "bash.script2: /bin/bash script\n" "" ""
+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
# Testing operators
-testing "find -type l -a -type d -o -type p" \
+testing "-type l -a -type d -o -type p" \
"find dir -type l -a -type d -o -type p" "dir/fifo\n" "" ""
-testing "find -type l -type d -o -type p" "find dir -type l -type d -o -type p" \
+testing "-type l -type d -o -type p" "find dir -type l -type d -o -type p" \
"dir/fifo\n" "" ""
-testing "find -type l -o -type d -a -type p" \
+testing "-type l -o -type d -a -type p" \
"find dir -type l -o -type d -a -type p" "dir/link\n" "" ""
-testing "find -type l -o -type d -type p" "find dir -type l -o -type d -type p" \
+testing "-type l -o -type d -type p" "find dir -type l -o -type d -type p" \
"dir/link\n" "" ""
-testing "find -type l ( -type d -o -type l )" \
+testing "-type l ( -type d -o -type l )" \
"find dir -type l \( -type d -o -type l \)" "dir/link\n" "" ""
-testing "find extra parentheses" \
+testing "extra parentheses" \
"find dir \( \( -type l \) \( -type d -o \( \( -type l \) \) \) \)" \
"dir/link\n" "" ""
-testing "find ( -type p -o -type d ) -type p" \
+testing "( -type p -o -type d ) -type p" \
"find dir \( -type p -o -type d \) -type p" "dir/fifo\n" "" ""
-testing "find -type l -o -type d -type p -o -type f" \
+testing "-type l -o -type d -type p -o -type f" \
"find dir -type l -o -type d -type p -o -type f | sort" \
"dir/file\ndir/link\n" "" ""
# Testing short-circuit evaluations
-testing "find -type f -a -print" \
+testing "-type f -a -print" \
"find dir -type f -a -print" "dir/file\n" "" ""
-testing "find -print -o -print" \
+testing "-print -o -print" \
"find dir -type f -a \( -print -o -print \)" "dir/file\n" "" ""
# these were erroring or segfaulting:
# Testing previous failures
-testing "find -type f -user -exec" \
+testing "-type f -user -exec" \
"find dir -type f -user $USER -exec ls {} \\;" "dir/file\n" "" ""
-testing "find -type l -newer -exec" \
+testing "-type l -newer -exec" \
"find dir -type l -newer dir/file -exec ls {} \\;" "dir/link\n" "" ""
-testing "find -perm (exact success)" \
+testing "-perm (exact success)" \
"find perm -type f -perm 0444" "perm/all-read-only\n" "" ""
-testing "find -perm (exact failure)" \
+testing "-perm (exact failure)" \
"find perm -type f -perm 0400" "" "" ""
-testing "find -perm (min success)" \
+testing "-perm (min success)" \
"find perm -type f -perm -0400" "perm/all-read-only\n" "" ""
-testing "find -perm (min failure)" \
+testing "-perm (min failure)" \
"find perm -type f -perm -0600" "" "" ""
-testing "find -perm (any success)" \
+testing "-perm (any success)" \
"find perm -type f -perm -0444" "perm/all-read-only\n" "" ""
-testing "find -perm (any failure)" \
+testing "-perm (any failure)" \
"find perm -type f -perm -0222" "" "" ""
# Still fails
-testing "find unterminated -exec {}" \
+testing "unterminated -exec {}" \
"find dir -type f -exec ls {} 2>/dev/null || echo bad" "bad\n" "" ""
-testing "find -exec {} +" \
+testing "-exec {} +" \
"find dir -type f -exec ls {} +" "dir/file\n" "" ""
# `find . -iname` was segfaulting
-testing "find -name file" \
+testing "-name file" \
"find dir -name file" "dir/file\n" "" ""
-testing "find -name FILE" \
+testing "-name FILE" \
"find dir -name FILE" "" "" ""
-testing "find -iname file" \
+testing "-iname file" \
"find dir -iname FILE" "dir/file\n" "" ""
-testing "find -iname FILE" \
+testing "-iname FILE" \
"find dir -iname FILE" "dir/file\n" "" ""
-testing "find -name (no arguments)" \
- "find dir -name 2>&1" "find: '-name' needs 1 arg\n" "" ""
-testing "find -iname (no arguments)" \
- "find dir -iname 2>&1" "find: '-iname' needs 1 arg\n" "" ""
+testing "-name (no arguments)" \
+ "find dir -name 2>&1 | grep -o '[-]name'" "-name\n" "" ""
+testing "-iname (no arguments)" \
+ "find dir -iname 2>&1 | grep -o '[-]iname'" "-iname\n" "" ""
+
+testing "" "find dir \( -iname file -o -iname missing \) -exec echo {} \;" \
+ "dir/file\n" "" ""
+
rm -rf dir
--- /dev/null
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+BDIR="$FILES/blkid"
+
+bzcat "$BDIR"/squashfs.bz2 > temp.img
+testing "file" "fstype temp.img" 'squashfs\n' "" ""
+rm temp.img
+
+for i in cramfs ext2 ext3 ext4 f2fs ntfs squashfs vfat xfs
+do
+ testing "$i" 'bzcat "$BDIR"/$i.bz2 | fstype -' "$i\n" "" ""
+done
+
+testing "msdos" 'bzcat "$BDIR"/msdos.bz2 | fstype -' 'vfat\n' "" ""
+testing "reiserfs" 'bzcat "$BDIR"/reiser3.bz2 | fstype -' 'reiserfs\n' "" ""
+
+#testing "blkid minix" 'bzcat "$BDIR"/minix.bz2 | blkid -'
+#adfs bfs btrfs cramfs jfs nilfs romfs
+#vfat // fat32 fat12 fat16
--- /dev/null
+#!/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
#testing "name" "command" "result" "infile" "stdin"
-testing "grep -c" "grep -c 123 input" "3\n" "123\ncount 123\n123\nfasdfasdf" ""
+testing "-c" "grep -c 123 input" "3\n" "123\ncount 123\n123\nfasdfasdf" ""
echo -e "this is test" > foo
echo -e "this is test2" > foo2
echo -e "this is foo3" > foo3
-testing "grep -l" "grep -l test foo foo2 foo3" "foo\nfoo2\n" "" ""
+testing "-l" "grep -l test foo foo2 foo3" "foo\nfoo2\n" "" ""
rm foo foo2 foo3
-testing "grep -q" "grep -q test input && echo yes" "yes\n" "this is a test\n" ""
-testing "grep -E" "grep -E '[0-9]' input" "1234123asdfas123123\n1\n" \
+testing "-q" "grep -q test input && echo yes" "yes\n" "this is a test\n" ""
+testing "-E" "grep -E '[0-9]' input" "1234123asdfas123123\n1\n" \
"1234123asdfas123123\nabc\n1\nabcde" ""
-testing "grep -e" "grep -e '[0-9]' input" "1234123asdfas123123\n1\n" \
+testing "-e" "grep -e '[0-9]' input" "1234123asdfas123123\n1\n" \
"1234123asdfas123123\nabc\n1\nabcde" ""
-testing "grep -e -e" "grep -e one -e two -e three input" \
+testing "-e -e" "grep -e one -e two -e three input" \
"two\ntwo\nthree\none\n" "two\ntwo\nthree\nand\none\n" ""
-testing "grep -F" "grep -F is input" "this is test\nthis is test2\n" \
+testing "-F" "grep -F is input" "this is test\nthis is test2\n" \
"this is test\nthis is test2\ntest case" ""
echo -e "this is test\nthis is test2\ntest case" > foo
echo -e "hello this is test" > foo2
echo -e "hi hello" > foo3
-testing "grep -H" "grep -H is foo foo2 foo3" "foo:this is test\nfoo:this is test2\nfoo2:hello this is test\n" "" ""
+testing "-H" "grep -H is foo foo2 foo3" "foo:this is test\nfoo:this is test2\nfoo2:hello this is test\n" "" ""
rm foo foo2 foo3
-testing "grep -b" "grep -b is input" "0:this is test\n13:this is test2\n" \
+testing "-b" "grep -b is input" "0:this is test\n13:this is test2\n" \
"this is test\nthis is test2\ntest case" ""
-testing "grep -i" "grep -i is input" "thisIs test\nthis is test2\n" \
+testing "-i" "grep -i is input" "thisIs test\nthis is test2\n" \
"thisIs test\nthis is test2\ntest case" ""
-testing "grep -n" "grep -n is input" "1:this is test\n2:this is test2\n" \
+testing "-n" "grep -n is input" "1:this is test\n2:this is test2\n" \
"this is test\nthis is test2\ntest case" ""
-testing "grep -o" "grep -o is input" "is\nis\nis\nis\n" \
+testing "-o" "grep -o is input" "is\nis\nis\nis\n" \
"this is test\nthis is test2\ntest case" ""
-testing "grep -s" "grep -hs hello asdf input 2>&1" "hello\n" "hello\n" ""
-testing "grep -v" "grep -v abc input" "1234123asdfas123123\n1ABa\n" \
+testing "-s" "grep -hs hello asdf input 2>&1" "hello\n" "hello\n" ""
+testing "-v" "grep -v abc input" "1234123asdfas123123\n1ABa\n" \
"1234123asdfas123123\n1ABabc\nabc\n1ABa\nabcde" ""
-testing "grep -w" "grep -w abc input" "abc\n123 abc\nabc 123\n123 abc 456\n" \
+testing "-w" "grep -w abc input" "abc\n123 abc\nabc 123\n123 abc 456\n" \
"1234123asdfas123123\n1ABabc\nabc\n1ABa\nabcde\n123 abc\nabc 123\n123 abc 456\n" ""
-testing "grep -x" "grep -x abc input" "abc\n" \
+testing "-x" "grep -x abc input" "abc\n" \
"aabcc\nabc\n" ""
-testing "grep -H (standard input)" "grep -H abc" "(standard input):abc\n" \
+testing "-H (standard input)" "grep -H abc" "(standard input):abc\n" \
"" "abc\n"
-testing "grep -l (standard input)" "grep -l abc" "(standard input)\n" \
+testing "-l (standard input)" "grep -l abc" "(standard input)\n" \
"" "abc\n"
-testing "grep -n two inputs" "grep -hn def - input" "2:def\n2:def\n" \
+testing "-n two inputs" "grep -hn def - input" "2:def\n2:def\n" \
"abc\ndef\n" "abc\ndef\n"
-testing "grep pattern with newline" "grep 'abc
+testing "pattern with newline" "grep 'abc
def' input" "aabcc\nddeff\n" \
"aaaa\naabcc\n\dddd\nddeff\nffff\n" ""
-testing "grep -lH" "grep -lH abc input" "input\n" "abc\n" ""
-testing "grep -cn" "grep -cn abc input" "1\n" "abc\n" ""
-testing "grep -cH" "grep -cH abc input" "input:1\n" "abc\n" ""
-testing "grep -qs" "grep -qs abc none input && echo yes" "yes\n" "abc\n" ""
-testing "grep -hl" "grep -hl abc input" "input\n" "abc\n" ""
-testing "grep -b stdin" "grep -b one" "0:one\n4:one\n8:one\n" "" "one\none\none\n"
-testing "grep -o overlap" "grep -bo aaa" "1:aaa\n" "" "baaaa\n"
+testing "-lH" "grep -lH abc input" "input\n" "abc\n" ""
+testing "-cn" "grep -cn abc input" "1\n" "abc\n" ""
+testing "-cH" "grep -cH abc input" "input:1\n" "abc\n" ""
+testing "-qs" "grep -qs abc none input && echo yes" "yes\n" "abc\n" ""
+testing "-hl" "grep -hl abc input" "input\n" "abc\n" ""
+testing "-b stdin" "grep -b one" "0:one\n4:one\n8:one\n" "" "one\none\none\n"
+testing "-o overlap" "grep -bo aaa" "1:aaa\n" "" "baaaa\n"
# nonobvious: -co counts lines, not matches
-testing "grep -co" "grep -co one input" "1\n" "one one one\n" ""
-testing "grep -nom" "grep -nom 2 one" "1:one\n1:one\n1:one\n2:one\n2:one\n" \
+testing "-co" "grep -co one input" "1\n" "one one one\n" ""
+testing "-nom" "grep -nom 2 one" "1:one\n1:one\n1:one\n2:one\n2:one\n" \
"" "one one one\none one\none"
-testing "grep -vo" "grep -vo one input" "two\nthree\n" "onetwoonethreeone\n" ""
-testing "grep no newline" "grep -h one input -" \
+testing "-vo" "grep -vo one input" "two\nthree\n" "onetwoonethreeone\n" ""
+testing "no newline" "grep -h one input -" \
"hello one\nthere one\n" "hello one" "there one"
-testing "grep -e multi" "grep -e one -ethree input" \
+testing "-e multi" "grep -e one -ethree input" \
"three\none\n" "three\ntwo\none\n" ""
# Suppress filenames for recursive test because dunno order they'd occur in
mkdir sub
echo -e "one\ntwo\nthree" > sub/one
echo -e "three\ntwo\none" > sub/two
-testing "grep -hr" "grep -hr one sub" "one\none\n" "" ""
-testing "grep -r file" "grep -r three sub/two" "three\n" "" ""
-testing "grep -r dir" "grep -r one sub | sort" "sub/one:one\nsub/two:one\n" \
+testing "-hr" "grep -hr one sub" "one\none\n" "" ""
+testing "-r file" "grep -r three sub/two" "three\n" "" ""
+testing "-r dir" "grep -r one sub | sort" "sub/one:one\nsub/two:one\n" \
"" ""
rm -rf sub
# -x exact match trumps -F's "empty string matches whole line" behavior
-testing "grep -Fx ''" "grep -Fx '' input" "" "one one one\n" ""
-testing "grep -F ''" "grep -F '' input" "one one one\n" "one one one\n" ""
-testing "grep -F -e blah -e ''" "grep -F -e blah -e '' input" "one one one\n" \
+testing "-Fx ''" "grep -Fx '' input" "" "one one one\n" ""
+testing "-F ''" "grep -F '' input" "one one one\n" "one one one\n" ""
+testing "-F -e blah -e ''" "grep -F -e blah -e '' input" "one one one\n" \
"one one one\n" ""
-testing "grep -e blah -e ''" "grep -e blah -e '' input" "one one one\n" \
+testing "-e blah -e ''" "grep -e blah -e '' input" "one one one\n" \
"one one one\n" ""
-testing "grep -w ''" "grep -w '' input" "" "one one one\n" ""
-testing "grep -w '' 2" "grep -w '' input" "one two\n" "one two\n" ""
-testing "grep -w \\1" "grep -wo '\\(x\\)\\1'" "xx\n" "" "xx"
-testing "grep -o ''" "grep -o '' input" "" "one one one\n" ""
-testing "grep backref" 'grep -e "a\(b\)" -e "b\(c\)\1"' "bcc\nab\n" \
+testing "-w ''" "grep -w '' input" "" "one one one\n" ""
+testing "-w '' 2" "grep -w '' input" "one two\n" "one two\n" ""
+testing "-w \\1" "grep -wo '\\(x\\)\\1'" "xx\n" "" "xx"
+testing "-o ''" "grep -o '' input" "" "one one one\n" ""
+testing "backref" 'grep -e "a\(b\)" -e "b\(c\)\1"' "bcc\nab\n" \
"" "bcc\nbcb\nab\n"
-testing "grep -A" "grep -A 2 yes" "yes\nno\nno\n--\nyes\nno\nno\nyes\nno\n" \
+testing "-A" "grep -A 2 yes" "yes\nno\nno\n--\nyes\nno\nno\nyes\nno\n" \
"" "yes\nno\nno\nno\nyes\nno\nno\nyes\nno"
-testing "grep -B" "grep -B 1 yes" "no\nyes\n--\nno\nyes\nno\nyes\n" \
+testing "-B" "grep -B 1 yes" "no\nyes\n--\nno\nyes\nno\nyes\n" \
"" "no\nno\nno\nyes\nno\nno\nyes\nno\nyes"
-testing "grep -C" "grep -C 1 yes" \
+testing "-C" "grep -C 1 yes" \
"yes\nno\n--\nno\nyes\nno\nno\nyes\nno\nyes\nno\n" \
"" "yes\nno\nno\nno\nyes\nno\nno\nyes\nno\nyes\nno\nno"
-testing "grep -HnC" "grep -HnC1 two" \
+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'
#testing "name" "command" "result" "infile" "stdin"
-testing "groupadd group_name (text)" "groupadd toyTestGroup &&
+testing "group_name (text)" "groupadd toyTestGroup &&
grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
echo 'yes'" "yes\n" "" ""
-testing "groupadd group_name (alphanumeric)" "groupadd toy1Test2Group3 &&
+testing "group_name (alphanumeric)" "groupadd toy1Test2Group3 &&
grep '^toy1Test2Group3:' /etc/group $arg && groupdel toy1Test2Group3 $arg &&
echo 'yes'" "yes\n" "" ""
-testing "groupadd group_name (numeric)" "groupadd 987654321 &&
+testing "group_name (numeric)" "groupadd 987654321 &&
grep '^987654321:' /etc/group $arg && groupdel 987654321 $arg &&
echo 'yes'" "yes\n" "" ""
-testing "groupadd group_name (with ./-)" "groupadd toy.1Test-2Group.3 &&
+testing "group_name (with ./-)" "groupadd toy.1Test-2Group.3 &&
grep '^toy.1Test-2Group.3:' /etc/group $arg &&
groupdel toy.1Test-2Group.3 $arg && echo 'yes'" "yes\n" "" ""
_s210=`echo $_s70$_s70$_s70`
-testing "groupadd group_name (long string)" "groupadd $_s210 &&
+testing "group_name (long string)" "groupadd $_s210 &&
grep '^$_s210:' /etc/group $arg && groupdel $_s210 $arg && echo 'yes'" \
"yes\n" "" ""
-testing "groupadd group_name with group_id" "groupadd -g 49999 toyTestGroup &&
+testing "group_name with group_id" "groupadd -g 49999 toyTestGroup &&
grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
echo 'yes'" "yes\n" "" ""
-testing "groupadd group_name with group_id (system_group)" \
+testing "group_name with group_id (system_group)" \
"groupadd -g 49999 -S toyTestGroup && grep '^toyTestGroup:' /etc/group $arg &&
groupdel toyTestGroup $arg && echo 'yes'" "yes\n" "" ""
-testing "groupadd group_name (system_group)" "groupadd -S toyTestGroup &&
+testing "group_name (system_group)" "groupadd -S toyTestGroup &&
grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
echo 'yes'" "yes\n" "" ""
-testing "groupadd group_name (add/del user)" "groupadd toyTestGroup &&
+testing "group_name (add/del user)" "groupadd toyTestGroup &&
grep '^toyTestGroup:' /etc/group $arg && groupadd $USER toyTestGroup &&
grep '^toyTestGroup:.*:.*:.*$USER.*' /etc/group $arg &&
groupdel $USER toyTestGroup $arg || groupdel toyTestGroup &&
echo "Testing to add single group multiple times after removing it..."
for each in {01..20}
do
- testing "groupadd group_name ($each)" "groupadd toyTestGroup &&
+ testing "group_name ($each)" "groupadd toyTestGroup &&
grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
echo 'yes'" "yes\n" "" ""
done
#testing "name" "command" "result" "infile" "stdin"
-testing "groupadd group_name (text)" "groupadd toyTestGroup &&
+testing "group_name (text)" "groupadd toyTestGroup &&
grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
echo 'yes'" "yes\n" "" ""
-testing "groupadd group_name (alphanumeric)" "groupadd toy1Test2Group3 &&
+testing "group_name (alphanumeric)" "groupadd toy1Test2Group3 &&
grep '^toy1Test2Group3:' /etc/group $arg && groupdel toy1Test2Group3 $arg &&
echo 'yes'" "yes\n" "" ""
-testing "groupadd group_name (numeric)" "groupadd 987654321 &&
+testing "group_name (numeric)" "groupadd 987654321 &&
grep '^987654321:' /etc/group $arg && groupdel 987654321 $arg &&
echo 'yes'" "yes\n" "" ""
-testing "groupadd group_name (with ./-)" "groupadd toy.1Test-2Group.3 &&
+testing "group_name (with ./-)" "groupadd toy.1Test-2Group.3 &&
grep '^toy.1Test-2Group.3:' /etc/group $arg &&
groupdel toy.1Test-2Group.3 $arg && echo 'yes'" "yes\n" "" ""
-testing "groupadd group_name with group_id" "groupadd -g 49999 toyTestGroup &&
+testing "group_name with group_id" "groupadd -g 49999 toyTestGroup &&
grep '^toyTestGroup:' /etc/group $arg && groupdel toyTestGroup $arg &&
echo 'yes'" "yes\n" "" ""
testing "head, stdin" "head -n 1 && echo yes" "one\nyes\n" "" "one\ntwo"
testing "head, stdin via -" "head -n 1 - && echo yes" "one\nyes\n" "" "one\ntwo"
testing "head, file" "head input -n 1 && echo yes" "one\nyes\n" "one\ntwo" ""
-testing "head -number" "head -2 input && echo yes" "one\ntwo\nyes\n" \
+testing "-number" "head -2 input && echo yes" "one\ntwo\nyes\n" \
"one\ntwo\nthree\nfour" ""
testing "head, default lines" "head" "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" "" "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12"
# New hostname
NewHostname="NewHostName.system"
-testing "Hostname - Get" "hostname" "$hostnameOut\n" "" ""
-testing "Hostname - Set, Get and then Reset" "hostname $NewHostname; hostname; hostname $hostnameOut; hostname" "$NewHostname\n$hostnameOut\n" "" ""
+testing "get" "hostname" "$hostnameOut\n" "" ""
+testing "set, Get and then Reset" "hostname $NewHostname; hostname; hostname $hostnameOut; hostname" "$NewHostname\n$hostnameOut\n" "" ""
# Test Description: Disable the dummy0 interface
# Results Expected: After calling ifconfig, no lines with dummy0 are displayed
-testing "ifconfig dummy0 down and if config /-only" \
+testing "dummy0 down and if config /-only" \
"ifconfig dummy0 down && ifconfig dummy0 | grep dummy | wc -l" \
"0\n" "" ""
# Test Description: Enable the dummy0 interface
# Results Expected: After calling ifconfig, one line with dummy0 is displayed
-testing "ifconfig dummy0 up" \
+testing "dummy0 up" \
"ifconfig dummy0 up && ifconfig dummy0 | grep dummy | wc -l" \
"1\n" "" ""
# Test Description: Set the ip address of the dummy0 interface
# Results Expected: After calling ifconfig dummy0, one line displays the ip
# address selected
-testing "ifconfig dummy0 10.240.240.240" \
+testing "dummy0 10.240.240.240" \
"ifconfig dummy0 10.240.240.240 && ifconfig dummy0 | grep 10\.240\.240\.240 | wc -l" \
"1\n" "" ""
# Test Description: Change the netmask to the interface
# Results Expected: After calling ifconfig dummy0, one line displays the
# netmask selected
-testing "ifconfig dummy0 netmask 255.255.240.0" \
+testing "dummy0 netmask 255.255.240.0" \
"ifconfig dummy0 netmask 255.255.240.0 && ifconfig dummy0 | grep 255\.255\.240\.0 | wc -l" \
"1\n" "" ""
# Test Description: Change the broadcast address to the interface
# Results Expected: After calling ifconfig dummy0, one line displays the
# broadcast address selected
-testing "ifconfig dummy0 broadcast 10.240.240.255" \
+testing "dummy0 broadcast 10.240.240.255" \
"ifconfig dummy0 broadcast 10.240.240.255 && ifconfig dummy0 | grep 10\.240\.240\.255 | wc -l" \
"1\n" "" ""
# Test Description: Revert to the default ip address
# Results Expected: After calling ifconfig dummy0, there are no lines
# displaying the ip address previously selected
-testing "ifconfig dummy0 default" \
+testing "dummy0 default" \
"ifconfig dummy0 default && ifconfig dummy0 | grep 10\.240\.240\.240 | wc -l" \
"0\n" "" ""
# Test Description: Change the Maximum transmission unit (MTU) of the interface
# Results Expected: After calling ifconfig dummy0, there is one line with the
# selected MTU
-testing "ifconfig dummy0 mtu 1269" \
+testing "dummy0 mtu 1269" \
"ifconfig dummy0 mtu 1269 && ifconfig dummy0 | grep 1269 | wc -l" \
"1\n" "" ""
# Test Description: Verify ifconfig add fails with such a small mtu
# Results Expected: There is one line of error message containing
# "No buffer space available"
-testing "ifconfig dummy0 add ::2 -- too small mtu" \
+testing "dummy0 add ::2 -- too small mtu" \
"ifconfig dummy0 add ::2 2>&1 | grep No\ buffer\ space\ available | wc -l" \
"1\n" "" ""
# Test Description: Change the Maximum transmission unit (MTU) of the interface
# Results Expected: After calling ifconfig dummy0, there is one line with the
# selected MTU
-testing "ifconfig dummy0 mtu 2000" \
+testing "dummy0 mtu 2000" \
"ifconfig dummy0 mtu 2000 && ifconfig dummy0 | grep 2000 | wc -l" \
"1\n" "" ""
# Test Description: Verify ifconfig add succeeds with a larger mtu
# Results Expected: after calling ifconfig dummy0, there is one line with the
# selected ip address
-testing "ifconfig dummy0 add ::2" \
+testing "dummy0 add ::2" \
"ifconfig dummy0 add ::2/126 && ifconfig dummy0 | grep \:\:2\/126 | wc -l" \
"1\n" "" ""
# Test Description: Verify ifconfig del removes the selected ip6 address
# Results Expected: after calling ifconfig dummy0, there are no lines with the
# selected ip address
-testing "ifconfig dummy0 del ::2" \
+testing "dummy0 del ::2" \
"ifconfig dummy0 del ::2/126 && ifconfig dummy0 | grep \:\:2 | wc -l" \
"0\n" "" ""
# preparation for the next test
# Results Expected: After calling ifconfig dummy0, there are no lines with the
# NOARP flag
-testing "ifconfig dummy0 arp down" \
+testing "dummy0 arp down" \
"ifconfig dummy0 arp down && ifconfig dummy0 | grep -i NOARP | wc -l" \
"0\n" "" ""
# Test Description: Call the pointtopoint option with no argument
# Results Expected: After calling ifconfig dummy0, there is one line with the
# NOARP and UP flags
-testing "ifconfig dummy0 pointtopoint" \
+testing "dummy0 pointtopoint" \
"ifconfig dummy0 pointtopoint && ifconfig dummy0 | grep -i NOARP | grep -i UP | wc -l" \
"1\n" "" ""
# Test Description: Test the pointtopoint option and set the ipaddress
# Results Expected: After calling ifconfig dummy0, there is one line with the
# word inet and the selected ip address
-testing "ifconfig dummy0 pointtopoint 127.0.0.2" \
+testing "dummy0 pointtopoint 127.0.0.2" \
"ifconfig dummy0 pointtopoint 127.0.0.2 && ifconfig dummy0 | grep -i inet | grep -i 127\.0\.0\.2 | wc -l" \
"1\n" "" ""
# Test Description: Enable allmulti mode on the interface
# Results Expected: After calling ifconfig dummy0, there is one line with the
# allmulti flag
-testing "ifconfig dummy0 allmulti" \
+testing "dummy0 allmulti" \
"ifconfig dummy0 allmulti && ifconfig dummy0 | grep -i allmulti | wc -l" "1\n" \
"" ""
# Test Description: Disable multicast mode the interface
# Results Expected: After calling ifconfig dummy0, there are no lines with the
# allmulti flag
-testing "ifconfig dummy0 -allmulti" \
+testing "dummy0 -allmulti" \
"ifconfig dummy0 -allmulti && ifconfig dummy0 | grep -i allmulti | wc -l" "0\n" \
"" ""
# Test Description: Disable NOARP mode on the interface
# Results Expected: After calling ifconfig dummy0, there are no lines with the
# NOARP flag
-testing "ifconfig dummy0 arp" \
+testing "dummy0 arp" \
"ifconfig dummy0 arp && ifconfig dummy0 | grep -i NOARP | wc -l" "0\n" \
"" ""
# Test Description: Enable NOARP mode on the interface
# Results Expected: After calling ifconfig dummy0, there is one line with the
# NOARP flag
-testing "ifconfig dummy0 -arp" \
+testing "dummy0 -arp" \
"ifconfig dummy0 -arp && ifconfig dummy0 | grep -i NOARP | wc -l" "1\n" \
"" ""
# Test Description: Enable multicast mode on the interface
# Results Expected: After calling ifconfig dummy0, there is one line with the
# multicast flag
-testing "ifconfig dummy0 multicast" \
+testing "dummy0 multicast" \
"ifconfig dummy0 multicast && ifconfig dummy0 | grep -i multicast | wc -l" \
"1\n" "" ""
# Test Description: Disable multicast mode the interface
# Results Expected: After calling ifconfig dummy0, there are no lines with the
# multicast flag
-testing "ifconfig dummy0 -multicast" \
+testing "dummy0 -multicast" \
"ifconfig dummy0 -multicast && ifconfig dummy0 | grep -i multicast | wc -l" \
"0\n" "" ""
# Test Description: Enable promiscuous mode the interface
# Results Expected: After calling ifconfig dummy0, there is one line with the
# promisc flag
-testing "ifconfig dummy0 promisc" \
+testing "dummy0 promisc" \
"ifconfig dummy0 promisc && ifconfig dummy0 | grep -i promisc | wc -l" "1\n" \
"" ""
# Disable promiscuous mode the interface
# Results Expected: After calling ifconfig dummy0, there are no lines with the
# promisc flag
-testing "ifconfig dummy0 -promisc" \
+testing "dummy0 -promisc" \
"ifconfig dummy0 -promisc && ifconfig dummy0 | grep -i promisc | wc -l" "0\n" \
"" ""
#testing "name" "command" "result" "infile" "stdin"
echo "" >foo
-testing "link fails on non-existent file" "link foo/foo baz || echo GOOD" "GOOD\n" "" ""
+testing "fails on non-existent file" "link foo/foo baz || echo GOOD" "GOOD\n" "" ""
rm -f foo bar
echo file1 > file
-testing "ln create_hardlink" "link file hlink && [ file -ef hlink ] &&
+testing "create_hardlink" "link file hlink && [ file -ef hlink ] &&
echo 'yes'; rm -rf hlink" "yes\n" "" ""
echo hlink1 > hlink
set +e
-testing "ln preserves_hardlinks" "link file hlink 2>/dev/null || echo 'yes'; rm -rf hlink" \
+testing "preserves_hardlinks" "link file hlink 2>/dev/null || echo 'yes'; rm -rf hlink" \
"yes\n" "" ""
echo file1 > file
-testing "ln create_hardlink_and_remove_sourcefile" "link file hlink &&
+testing "create_hardlink_and_remove_sourcefile" "link file hlink &&
[ file -ef hlink ] && rm -rf file && [ -f hlink ] && echo 'yes'; rm -f file hlink" \
"yes\n" "" ""
#set -x
echo file1 > file
-testing "ln create_hardlink" "ln file hlink && [ file -ef hlink ] &&
+testing "create_hardlink" "ln file hlink && [ file -ef hlink ] &&
echo 'yes'" "yes\n" "" ""
-testing "ln create_softlink" "ln -s file slink && [ -L slink ] &&
+testing "create_softlink" "ln -s file slink && [ -L slink ] &&
readlink slink" "file\n" "" ""
rm slink hlink
echo hlink1 > hlink
-testing "ln force_create_hardlink" "ln -f file hlink &&
+testing "force_create_hardlink" "ln -f file hlink &&
[ file -ef hlink ] && cat hlink 2>/dev/null" "file1\n" "" ""
echo slink1 > slink
-testing "ln force_create_softlink" "ln -f -s file slink &&
+testing "force_create_softlink" "ln -f -s file slink &&
[ -L slink ] && readlink slink" "file\n" "" ""
rm slink hlink
echo hlink1 > hlink
set +e
-testing "ln preserves_hardlinks" "ln file hlink 2>/dev/null || echo 'yes'" \
+testing "preserves_hardlinks" "ln file hlink 2>/dev/null || echo 'yes'" \
"yes\n" "" ""
echo slink1 > slink
set +e
-testing "ln preserves_softlinks" "ln -s file slink 2>/dev/null || echo 'yes'" \
+testing "preserves_softlinks" "ln -s file slink 2>/dev/null || echo 'yes'" \
"yes\n" "" ""
rm slink hlink
mkdir dir
-testing "ln multilevel_symbolic_links" "ln -s dir slink &&
+testing "multilevel_symbolic_links" "ln -s dir slink &&
ln -s file slink && [ -L slink -a -L slink/file ] &&
readlink slink && readlink slink/file" "dir\nfile\n" "" ""
rm slink
-testing "ln no_dereference" "ln -s dir slink &&
+testing "no_dereference" "ln -s dir slink &&
ln -n -s file slink 2>/dev/null || [ -L slink ] && readlink slink" \
"dir\n" "" ""
rm -rf file dir slink
touch file1 file2 && mkdir dir
-testing "ln create_multiple_hardlinks" "ln file* dir/ &&
+testing "create_multiple_hardlinks" "ln file* dir/ &&
[ file1 -ef dir/file1 -a file2 -ef dir/file2 ] && echo 'yes'" "yes\n" "" ""
rm -rf file* dir
touch file1 file2 && mkdir dir
-testing "ln create_multiple_softlinks" "ln -s file* dir/ &&
+testing "create_multiple_softlinks" "ln -s file* dir/ &&
[ -L dir/file1 -a -L dir/file2 ] && readlink dir/file1 &&
readlink dir/file2" "file1\nfile2\n" "" ""
rm -rf file* dir
echo file1 > file
-testing "ln create_softlink_and_remove_sourcefile" "ln -s file slink &&
+testing "create_softlink_and_remove_sourcefile" "ln -s file slink &&
[ -L slink ] && rm file && cat slink 2>/dev/null || echo 'yes' " \
"yes\n" "" ""
rm -f file slink
echo file1 > file
-testing "ln create_hardlink_and_remove_sourcefile" "ln file hlink &&
+testing "create_hardlink_and_remove_sourcefile" "ln file hlink &&
[ file -ef hlink ] && rm file && [ -f hlink ] && echo 'yes'" \
"yes\n" "" ""
rm -f file hlink
losetup -f
losetup -f -s
losetup -f file
-testing "cat" "cat && echo yes" "oneyes\n" "" "one"
-testing "cat -" "cat - && echo yes" "oneyes\n" "" "one"
-testing "cat file1 file2" "cat file1 file2" "one\ntwo\n" "" ""
-testing "cat - file" "cat - file1" "zero\none\n" "" "zero\n"
-testing "cat file -" "cat file1 -" "one\nzero\n" "" "zero\n"
-
-testing "cat file1 notfound file2" \
- "cat file1 notfound file2 2>stderr && echo ok ; cat stderr; rm stderr" \
- "one\ntwo\ncat: notfound: No such file or directory\n" "" ""
-
-testing "cat file1" \
- "cat /proc/self/exe > file1 && cmp /proc/self/exe file1 && echo yes" \
- "yes\n" "" ""
-
-testing "cat - file1" \
- "cat - file1 | diff -a -U 0 - file1 | tail -n 1" \
- "-hello\n" "" "hello\n"
-
-testing "cat > /dev/full" \
- "cat - > /dev/full 2>stderr && echo ok; cat stderr; rm stderr" \
- "cat: xwrite: No space left on device\n" "" "zero\n"
losetup -d
IN="cd lstest"
OUT="cd .. "
-testing "ls no argument" "$IN && ls; $OUT" "dir1\ndir2\nfile1.txt\nfile2.txt\n" "" ""
-testing "ls with wild char" "$IN && ls file*; $OUT" "file1.txt\nfile2.txt\n" "" ""
-testing "ls with wild char - long listing" "$IN && ls -1 file*; $OUT" "file1.txt\nfile2.txt\n" "" ""
-testing "ls with -p" "$IN && ls -p; $OUT" "dir1/\ndir2/\nfile1.txt\nfile2.txt\n" "" ""
-testing "ls with -a" "$IN && ls -a; $OUT" \
+testing "no argument" "$IN && ls; $OUT" "dir1\ndir2\nfile1.txt\nfile2.txt\n" "" ""
+testing "with wild char" "$IN && ls file*; $OUT" "file1.txt\nfile2.txt\n" "" ""
+testing "with wild char - long listing" "$IN && ls -1 file*; $OUT" "file1.txt\nfile2.txt\n" "" ""
+testing "with -p" "$IN && ls -p; $OUT" "dir1/\ndir2/\nfile1.txt\nfile2.txt\n" "" ""
+testing "with -a" "$IN && ls -a; $OUT" \
".\n..\ndir1\ndir2\nfile1.txt\nfile2.txt\n.hfile1\n" "" ""
-testing "ls with -A" "$IN && ls -A; $OUT" \
+testing "with -A" "$IN && ls -A; $OUT" \
"dir1\ndir2\nfile1.txt\nfile2.txt\n.hfile1\n" "" ""
-testing "ls with -d" "$IN && ls -d; $OUT" ".\n" "" ""
-testing "ls with wild char and -d *" "$IN && ls -d *; $OUT" "dir1\ndir2\nfile1.txt\nfile2.txt\n" "" ""
-testing "ls with -k" "$IN && ls -k; $OUT" "dir1\ndir2\nfile1.txt\nfile2.txt\n" "" ""
-testing "ls with -m" "$IN && ls -m; $OUT" "dir1, dir2, file1.txt, file2.txt\n" "" ""
-testing "ls with -F" "$IN && ls -F; $OUT" "dir1/\ndir2/\nfile1.txt\nfile2.txt\n" "" ""
-testing "ls with -dk *" "$IN && ls -dk *; $OUT" "dir1\ndir2\nfile1.txt\nfile2.txt\n" "" ""
+testing "with -d" "$IN && ls -d; $OUT" ".\n" "" ""
+testing "with wild char and -d *" "$IN && ls -d *; $OUT" "dir1\ndir2\nfile1.txt\nfile2.txt\n" "" ""
+testing "with -k" "$IN && ls -k; $OUT" "dir1\ndir2\nfile1.txt\nfile2.txt\n" "" ""
+testing "with -m" "$IN && ls -m; $OUT" "dir1, dir2, file1.txt, file2.txt\n" "" ""
+testing "with -F" "$IN && ls -F; $OUT" "dir1/\ndir2/\nfile1.txt\nfile2.txt\n" "" ""
+testing "with -dk *" "$IN && ls -dk *; $OUT" "dir1\ndir2\nfile1.txt\nfile2.txt\n" "" ""
ln -s file1.txt lstest/slink
-testing "ls softlink - long listing" "$IN && ls -l slink | awk '{ print \$NF }' ; $OUT" \
+testing "softlink - long listing" "$IN && ls -l slink | awk '{ print \$NF }' ; $OUT" \
"file1.txt\n" "" ""
rm -f lstest/slink
ln -s /dev/null/nosuchfile lstest/nosuchfile
-testing "ls with -d - broken softlink" "$IN && ls -d nosuchfile; $OUT" "nosuchfile\n" "" ""
+testing "with -d - broken softlink" "$IN && ls -d nosuchfile; $OUT" "nosuchfile\n" "" ""
rm -f lstest/nosuchfile
rm -rf lstest/* && mkdir -p lstest/dir1 && touch lstest/file1.txt
-testing "ls nested recursively" "$IN && ls -R; $OUT" \
+testing "nested recursively" "$IN && ls -R; $OUT" \
".:\ndir1\nfile1.txt\n\n./dir1:\n" "" ""
rm -rf lstest/* && touch lstest/file1.txt && INODE=`stat -c %i lstest/file1.txt`
-testing "ls with -i" "$IN && ls -i 2>/dev/null; $OUT" "$INODE file1.txt\n" "" ""
+testing "with -i" "$IN && ls -i 2>/dev/null; $OUT" "$INODE file1.txt\n" "" ""
unset INODE
# Removing test dir for cleanup purpose
#testing "name" "command" "result" "infile" "stdin"
-# chattr - Testcases
-
-mkdir testattr
-IN="cd testattr"
-OUT="cd .."
-_t="abcdefghijklmnopqrstuvwxyz"
-
-testing "chattr [-/+]i FILE[write]" "$IN && echo "$_t" > testFile &&
- chattr +i testFile && lsattr testFile && echo "$_t" > testFile;
- chattr -i testFile; rm -rf testFile; $OUT " "----i-------- testFile\n" "" ""
-testing "chattr [-/+]i FILE[re-write]" "$IN && echo "$_t" > testFile &&
- chattr +i testFile && echo \"$_t\" > testFile || chattr -i testFile &&
- echo \"$_t\" > testFile && lsattr testFile; rm -rf testFile; $OUT" \
- "------------- testFile\n" "" ""
-testing "chattr [-/+]i FILE[append]" "$IN && echo "$_t" > testFile &&
- chattr +i testFile && echo \"$_t\" >> testFile || lsattr testFile &&
- chattr -i testFile; rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
-testing "chattr [-/+]i FILE[move]" "$IN && echo "$_t" > testFile &&
- chattr +i testFile && mv testFile testFile1 || lsattr testFile &&
- chattr -i testFile; rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
-testing "chattr [-/+]i FILE[delete]" "$IN && echo "$_t" > testFile &&
- chattr +i testFile && rm -f testFile || lsattr testFile &&
- chattr -i testFile; rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
-testing "chattr [-/+]i FILE[read]" "$IN && echo "$_t" > testFile &&
- chattr +i testFile && cat testFile && lsattr testFile &&
- chattr -i testFile; rm -rf testFile; $OUT" "$_t\n----i-------- testFile\n" "" ""
-testing "chattr [-/+]a FILE[write]" "$IN && echo "$_t" > testFile &&
- chattr +a testFile && echo $_t > testFile || lsattr testFile &&
- chattr -a testFile; rm -rf testFile; $OUT" "-----a------- testFile\n" "" ""
-testing "chattr [-/+]a FILE[re-write]" "$IN && echo "$_t" > testFile &&
- chattr +a testFile && echo $_t > testFile || lsattr testFile &&
- chattr -a testFile && echo $_t > testFile && cat testFile &&
- lsattr testFile; rm -rf testFile;
- $OUT" "-----a------- testFile\n$_t\n------------- testFile\n" "" ""
-testing "chattr [-/+]a FILE[append]" "$IN && echo "$_t" > testFile &&
- chattr +a testFile && echo $_t >> testFile && cat testFile &&
- lsattr testFile && chattr -a testFile; rm -rf testFile; $OUT" \
- "$_t\n$_t\n-----a------- testFile\n" "" ""
-testing "chattr [-/+]a FILE[move]" "$IN && echo "$_t" > testFile &&
- chattr +a testFile && mv testFile testFile1 || lsattr testFile &&
- chattr -a testFile; rm -rf testFile; $OUT" "-----a------- testFile\n" "" ""
-testing "chattr [-/+]a FILE[delete]" "$IN && echo "$_t" > testFile &&
- chattr +a testFile && rm -f testFile || lsattr testFile &&
- chattr -a testFile; rm -rf testFile; $OUT" "-----a------- testFile\n" "" ""
-testing "chattr [-/+]a FILE[read]" "$IN && echo "$_t" > testFile &&
- chattr +a testFile && cat testFile && lsattr testFile && chattr -a testFile;
- rm -rf testFile; $OUT" "$_t\n-----a------- testFile\n" "" ""
-
-for attr in "A" "a" "c" "D" "d" "i" "j" "s" "S" "t" "T" "u"
-do
- testing "chattr [-/+]$attr FILE" "$IN && echo "$_t" > testFile &&
- chattr +$attr testFile && cat testFile && chattr -$attr testFile &&
- lsattr testFile; rm -rf testFile; $OUT" "$_t\n------------- testFile\n" "" ""
-done
-
-for attr in "A" "a" "c" "D" "d" "i" "j" "s" "S" "t" "T" "u"
-do
- testing "chattr -$attr FILE" "$IN && echo "$_t" > testFile && chattr -$attr testFile &&
- cat testFile && lsattr testFile; rm -rf testFile; $OUT" "$_t\n------------- testFile\n" "" ""
-done
-
-testing "chattr [-/+]AacDdijsStTu FILE" "$IN && echo "$_t" > testFile &&
- chattr +AacDdijsStTu testFile && cat testFile && chattr -AacDdijsStTu testFile &&
- lsattr testFile; rm -rf testFile; $OUT" "$_t\n------------- testFile\n" "" ""
-testing "chattr [-/+]AacDdijsStTu(random) FILE" \
- "$IN && echo "$_t" > testFile &&
- chattr +AacDdijsStTu testFile && cat testFile && chattr -A testFile &&
- chattr -a testFile && chattr -c testFile && chattr -D testFile &&
- chattr -d testFile && chattr -i testFile && chattr -j testFile &&
- chattr -s testFile && chattr -S testFile && chattr -t testFile &&
- chattr -T testFile && chattr -u testFile && lsattr testFile &&
- chattr -AacDdijsStTu testFile; rm -rf testFile; $OUT" \
- "$_t\n------------- testFile\n" "" ""
-testing "chattr [-/+]AacDdijsStTu FILE*" "$IN &&
- echo "$_t" > testFile && echo "$_t" > testFile1 &&
- echo "$_t" > testFile2 && echo "$_t" > testFile3 &&
- echo "$_t" > testFile4 && echo "$_t" > testFile5 &&
- echo "$_t" > testFile6 && echo "$_t" > testFile7 &&
- echo "$_t" > testFile8 && echo "$_t" > testFile9 &&
- echo "$_t" > testFile10 && echo "$_t" > testFile11 &&
- chattr +AacDdijsStTu testFile* &&
- cat testFile9 && chattr -AacDdijsStTu testFile* && lsattr testFile*; rm -rf testFile*; $OUT" \
- "$_t\n------------- testFile\n------------- testFile1\n------------- testFile10\n------------- testFile11\n------------- testFile2\n------------- testFile3\n------------- testFile4\n------------- testFile5\n------------- testFile6\n------------- testFile7\n------------- testFile8\n------------- testFile9\n" "" ""
-testing "chattr [-/+]AacDdijsStTu(random) FILE*" \
- "$IN && echo "$_t" > testFile &&
- chattr +AacDdijsStTu testFile* && cat testFile && chattr -A testFile* &&
- chattr -a testFile* && chattr -c testFile* && chattr -D testFile* &&
- chattr -d testFile* && chattr -i testFile* && chattr -j testFile* &&
- chattr -s testFile* && chattr -S testFile* && chattr -t testFile* &&
- chattr -T testFile* && chattr -u testFile* && lsattr testFile;
- rm -rf testFile; $OUT" \
- "$_t\n------------- testFile\n" "" ""
-testing "chattr [-/+]i FILE[write]" \
- "$IN && echo "$_t" > testFile &&
- chattr +i testFile &&
- echo \"$_t\" > testFile || lsattr testFile && chattr -i testFile;
- rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
-testing "chattr [-/+]A FILE[write]" \
- "$IN && echo "$_t" > testFile && chattr +A testFile &&
- echo \"$_t\" > testFile && lsattr testFile && chattr -A testFile;
- rm -rf testFile; $OUT" "-------A----- testFile\n" "" ""
-testing "chattr [-/+]s FILE[write]" \
- "$IN && echo "$_t" > testFile && chattr +s testFile &&
- echo \"$_t\" > testFile && lsattr testFile && chattr -s testFile
- rm -rf testFile; $OUT" "s------------ testFile\n" "" ""
-testing "chattr -v version FILE[write]" \
- "$IN && echo "$_t" > testFile &&
- chattr -v 1234 testFile && echo \"$_t\" > testFile &&
- lsattr -v testFile; rm -rf testFile" \
- " 1234 ------------- testFile\n" "" ""
-
-_a="-------A-----"
-testing "chattr -R [-/+]a FILE" "$IN && touch aa && chattr -R +A aa && lsattr aa &&
- chattr -R -A aa; rm -rf aa; $OUT" "$_a aa\n" "" ""
-testing "chattr -R [-/+]a FILE.." "$IN && touch aa bb &&
- chattr -R +A aa bb && lsattr aa bb &&
- chattr -R -A aa bb; rm -rf aa bb; $OUT" "$_a aa\n$_a bb\n" "" ""
-
-# Clean up
-rm -rf testattr
-
# lsattr - Testcases
mkdir dir && cd dir && touch file
chattr +A file &>/dev/null
_b="-------------"
_A="-------A-----"
-testing "lsattr file" "lsattr file" "$_A file\n" "" ""
-testing "lsattr file_path" "lsattr $_p/file" "$_A $_p/file\n" "" ""
-testing "lsattr -R file" "lsattr -R file" "$_A file\n" "" ""
-testing "lsattr -R file_path" "lsattr -R $_p/file" "$_A $_p/file\n" "" ""
-testing "lsattr -a file" "lsattr -a file" "$_A file\n" "" ""
-testing "lsattr -a file_path" "lsattr -a $_p/file" "$_A $_p/file\n" "" ""
-testing "lsattr -d ." "lsattr -d ." "$_b .\n" "" ""
-testing "lsattr -d dir_path" "lsattr -d $_p" "$_b $_p\n" "" ""
-testing "lsattr -d file" "lsattr -d file" "$_A file\n" "" ""
-testing "lsattr -d file_path" "lsattr -d $_p/file" "$_A $_p/file\n" "" ""
+testing "file" "lsattr file" "$_A file\n" "" ""
+testing "file_path" "lsattr $_p/file" "$_A $_p/file\n" "" ""
+testing "-R file" "lsattr -R file" "$_A file\n" "" ""
+testing "-R file_path" "lsattr -R $_p/file" "$_A $_p/file\n" "" ""
+testing "-a file" "lsattr -a file" "$_A file\n" "" ""
+testing "-a file_path" "lsattr -a $_p/file" "$_A $_p/file\n" "" ""
+testing "-d ." "lsattr -d ." "$_b .\n" "" ""
+testing "-d dir_path" "lsattr -d $_p" "$_b $_p\n" "" ""
+testing "-d file" "lsattr -d file" "$_A file\n" "" ""
+testing "-d file_path" "lsattr -d $_p/file" "$_A $_p/file\n" "" ""
sp_44=" "
-testing "lsattr -l file" "lsattr -l file" "file $sp_44 No_Atime\n" "" ""
+testing "-l file" "lsattr -l file" "file $sp_44 No_Atime\n" "" ""
_v="12345"
-testing "lsattr -v file" "chattr -v $_v * && lsattr -v file" \
+testing "-v file" "chattr -v $_v * && lsattr -v file" \
"$_v $_A file\n" "" ""
-testing "lsattr -v file_path" "chattr -v $_v * && lsattr -v $_p/file" \
+testing "-v file_path" "chattr -v $_v * && lsattr -v $_p/file" \
"$_v $_A $_p/file\n" "" ""
-testing "lsattr -Radlv file1 file2" "chattr -v $_v * &&
+testing "-Radlv file1 file2" "chattr -v $_v * &&
lsattr -Radlv file input" \
"$_v file $sp_44 No_Atime\n$_v input $sp_44 ---\n" "" ""
# These tests are from RFC 1321 appendix 5, reshuffled slightly to test
# varying argument numbers
-testing "md5sum ''" "md5sum" "d41d8cd98f00b204e9800998ecf8427e -\n" "" ""
-testing "md5sum infile" "md5sum input" \
+testing "''" "md5sum" "d41d8cd98f00b204e9800998ecf8427e -\n" "" ""
+testing "infile" "md5sum input" \
"0cc175b9c0f1b6a831c399e269772661 input\n" "a" ""
-testing "md5sum two files" "md5sum - input" \
+testing "two files" "md5sum - input" \
"900150983cd24fb0d6963f7d28e17f72 -\nf96b697d7cb7938d525a2f31aaf161d0 input\n" \
"message digest" "abc"
-testing "md5sum 4" "md5sum" "c3fcd3d76192e4007dfb496cca67e13b -\n" \
+testing "4" "md5sum" "c3fcd3d76192e4007dfb496cca67e13b -\n" \
"" "abcdefghijklmnopqrstuvwxyz"
-testing "md5sum 5" "md5sum" "d174ab98d277d9f5a5611c2c9f419d9f -\n" \
+testing "5" "md5sum" "d174ab98d277d9f5a5611c2c9f419d9f -\n" \
"" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
-testing "md5sum 6" "md5sum" "57edf4a22be3c955ac49da2e2107b67a -\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" "" ""
rmdir one
touch existing
-testing "mkdir existing" \
+testing "existing" \
"mkdir existing 2> /dev/null || [ -f existing ] && echo yes" "yes\n" "" ""
rm existing
-testing "mkdir one two" \
+testing "one two" \
"mkdir one two && [ -d one ] && [ -d two ] && echo yes" "yes\n" "" ""
rmdir one two
-testing "mkdir missing/one" \
+testing "missing/one" \
"mkdir missing/one 2> /dev/null || [ ! -d missing ] && echo yes" "yes\n" "" ""
-testing "mkdir -p" \
+testing "-p" \
"mkdir -p one/two/three && [ -d one/two/three ] && echo yes" "yes\n" "" ""
rm -rf one
mkdir existing
-testing "mkdir -p existing" "mkdir -p existing && echo yes" "yes\n" "" ""
+testing "-p existing" "mkdir -p existing && echo yes" "yes\n" "" ""
rmdir existing
umask 123
-testing "mkdir (default permissions)" \
+testing "(default permissions)" \
"mkdir one && stat -c %a one" "654\n" "" ""
rmdir one
-testing "mkdir -m 124" \
+testing "-m 124" \
"mkdir -m 124 one && stat -c %a one" "124\n" "" ""
rmdir one
umask 000
-testing "mkdir -p -m 653" \
+testing "-p -m 653" \
"mkdir -p -m 653 one/two && stat -c %a one && stat -c %a one/two" \
"777\n653\n" "" ""
rm -rf one
-testing "mkdir -p one/two/ (trailing slash)" \
+testing "-p one/two/ (trailing slash)" \
"mkdir -p one/two/ && [ -d one/two ] && echo yes" "yes\n" "" ""
rm -rf one
umask 022
-testing "mkdir -p -m 777 (022 umask)" \
+testing "-p -m 777 (022 umask)" \
"mkdir -p -m 777 one/two && stat -c %a one && stat -c %a one/two" \
"755\n777\n" "" ""
rm -rf one
umask 377
-testing "mkdir -p -m 777 (377 umask)" \
+testing "-p -m 777 (377 umask)" \
"mkdir -p -m 777 one/two && stat -c %a one && stat -c %a one/two" \
"700\n777\n" "" ""
umask 002
rm -rf one
-testing "mkdir -vp" "mkdir -vp walrus 2>&1" \
+testing "-vp" "mkdir -vp walrus 2>&1" \
"mkdir: created directory 'walrus'\n" "" ""
-testing "mkdir -vp exists" "mkdir -vp walrus 2>&1" \
+testing "-vp exists" "mkdir -vp walrus 2>&1" \
"" "" ""
rm -rf walrus
touch two
-testing "mkdir continue after fail" \
+testing "continue after fail" \
"mkdir -m 777 one two three 2>/dev/null || stat -c %a three" \
"777\n" "" ""
rm -rf one two three
rm one
touch existing
-testing "mkfifo existing" \
+testing "existing" \
"mkfifo existing 2> /dev/null || [ -f existing ] && echo yes" "yes\n" "" ""
rm existing
-testing "mkfifo one two" \
+testing "one two" \
"mkfifo one two && [ -p one ] && [ -p two ] && echo yes" "yes\n" "" ""
rm one two
umask 123
-testing "mkfifo (default permissions)" \
+testing "(default permissions)" \
"mkfifo one && stat -c %a one" "644\n" "" ""
rm one
umask 000
-testing "mkfifo -m 124" \
+testing "-m 124" \
"mkfifo -m 124 one && stat -c %a one" "124\n" "" ""
rm -f one
#We expect they have ne2k-pci as a module.
-testing "modinfo gets right number of fields" "modinfo ne2k-pci |cut -d: -f1 |grep -v ver|sort" "alias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nauthor\ndepends\ndescription\nfilename\nlicense\nparm\nparm\nparm\n" "" ""
-testing "modinfo treats - and _ as equivalent" "modinfo ne2k_pci |cut -d: -f1 |grep -v ver|sort" "alias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nauthor\ndepends\ndescription\nfilename\nlicense\nparm\nparm\nparm\n" "" ""
+testing "gets right number of fields" "modinfo ne2k-pci |cut -d: -f1 |grep -v ver|sort" "alias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nauthor\ndepends\ndescription\nfilename\nlicense\nparm\nparm\nparm\n" "" ""
+testing "treats - and _ as equivalent" "modinfo ne2k_pci |cut -d: -f1 |grep -v ver|sort" "alias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nalias\nauthor\ndepends\ndescription\nfilename\nlicense\nparm\nparm\nparm\n" "" ""
# Output of -F filename should be an absolute path to the module.
# Otherwise, initrd generating scripts will break.
-testing "modinfo -F filename gets absolute path" "[ -e `modinfo -F filename ne2k-pci` ] && echo ne2k-pci " "ne2k-pci\n" "" ""
+testing "-F filename gets absolute path" "[ -e `modinfo -F filename ne2k-pci` ] && echo ne2k-pci " "ne2k-pci\n" "" ""
-testing "modinfo supports multiple modules" "modinfo -F filename ne2k-pci 8390 | wc -l" "2\n" "" ""
+testing "supports multiple modules" "modinfo -F filename ne2k-pci 8390 | wc -l" "2\n" "" ""
-testing "modinfo does not output filename for bad module" "modinfo -F filename zxcvbnm__9753" "" "" ""
+testing "does not output filename for bad module" "modinfo -F filename zxcvbnm__9753" "" "" ""
--- /dev/null
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+cat >file1 <<EOF
+line1
+line2
+EOF
+
+testing "non-tty" "more file1 | cat -" "line1\nline2\n" "" ""
+
+rm file1
}
reCreateTmpFs
-testing "mount $root_fs /mnt" \
+testing "$root_fs /mnt" \
"mount $root_fs /mnt >/dev/null 2>&1 && mkdir /mnt/testDir &&
sleep 1 && umount /mnt && test -e /testDir && rmdir /testDir" "" "" ""
-testing "mount $tmp_b_fs /mnt" \
+testing "$tmp_b_fs /mnt" \
"mount $tmp_b_fs /mnt >/dev/null 2>&1 && mkdir /mnt/testDir &&
sleep 1 && umount /mnt && ! test -e /mnt/testDir" "" "" ""
reCreateTmpFs
chmod 444 /mnt
-testing "mount $root_fs /mnt (read_only dir)" \
+testing "$root_fs /mnt (read_only dir)" \
"mount $root_fs /mnt >/dev/null 2>&1 && mkdir /mnt/testDir &&
sleep 1 && umount /mnt && test -e /testDir && rmdir /testDir" "" "" ""
-testing "mount $tmp_b_fs /mnt (read_only dir)" \
+testing "$tmp_b_fs /mnt (read_only dir)" \
"mount $tmp_b_fs /mnt >/dev/null 2>&1 && mkdir /mnt/testDir &&
sleep 1 && umount /mnt && ! test -e /mnt/testDir" "" "" ""
reCreateTmpFs
chmod 755 /mnt
-testing "mount -w $root_fs /mnt (write_only mode)" \
+testing "-w $root_fs /mnt (write_only mode)" \
"mount -w $root_fs /mnt >/dev/null 2>&1 && mkdir /mnt/testDir &&
sleep 1 && umount /mnt && test -e /testDir && rmdir /testDir" "" "" ""
-testing "mount -w $tmp_b_fs /mnt (write_only mode)" \
+testing "-w $tmp_b_fs /mnt (write_only mode)" \
"mount -w $tmp_b_fs /mnt >/dev/null 2>&1 && mkdir /mnt/testDir &&
sleep 1 && umount /mnt && ! test -e /mnt/testDir" "" "" ""
reCreateTmpFs
-testing "mount -rw $tmp_b_fs /mnt (read_write mode)" \
+testing "-rw $tmp_b_fs /mnt (read_write mode)" \
'mount -rw $tmp_b_fs /mnt >/dev/null && mkdir /mnt/testDir && \
sleep 1 && ! test -e /mnt/testDir && umount /mnt' "" "" ""
reCreateTmpFs
-testing "mount $tmp_b_fs /mnt -t fs_type" \
+testing "$tmp_b_fs /mnt -t fs_type" \
"mount $tmp_b_fs /mnt -t $tmp_b_fs_type >/dev/null 2>&1 &&
mkdir /mnt/testDir && sleep 1 && umount /mnt &&
! test -e /mnt/testDir" "" "" ""
reCreateTmpFs
mkdir -p testDir1/testDir2 testDir
echo "abcdefghijklmnopqrstuvwxyz" > testDir1/testDir2/testFile
-testing "mount -o bind dir1 dir2" \
+testing "-o bind dir1 dir2" \
'mount -o bind testDir1 testDir >/dev/null 2>&1 && \
cat testDir/testDir2/testFile && sleep 1 && umount testDir' \
"abcdefghijklmnopqrstuvwxyz\n" "" ""
-testing "mount -o rbind dir1 dir2" \
+testing "-o rbind dir1 dir2" \
'mount -o rbind testDir1 testDir >/dev/null 2>&1 && \
cat testDir/testDir2/testFile && sleep 1 && umount testDir' \
"abcdefghijklmnopqrstuvwxyz\n" "" ""
-testing "mount -o loop $tmp_b_fs /mnt" \
+testing "-o loop $tmp_b_fs /mnt" \
"mount -o loop $tmp_b_fs /mnt >/dev/null 2>&1 && mkdir /mnt/testDirp &&
sleep 1 && umount -d /mnt && ! test -e /mnt/testDirp" "" "" ""
reCreateTmpFs
mkdir testDir2
-testing "mount -o move mount_1 mount_2" \
+testing "-o move mount_1 mount_2" \
"mount $tmp_b_fs testDir1 && mkdir testDir1/testDirr &&
mount -o move testDir1 testDir2 && test -r testDir2/testDirr &&
sleep 1 && umount testDir2" "" "" ""
reCreateTmpFs
-testing "mount -o rw $tmp_b_fs /mnt" \
+testing "-o rw $tmp_b_fs /mnt" \
"mount -o rw $tmp_b_fs /mnt >/dev/null 2>&1 && mkdir /mnt/testDir &&
sleep 1 && umount /mnt && ! test -e /mnt/testDir" "" "" ""
reCreateTmpFs
-testing "mount -o ro $tmp_b_fs /mnt" \
+testing "-o ro $tmp_b_fs /mnt" \
"mount -o ro $tmp_b_fs /mnt >/dev/null 2>&1 &&
mkdir /mnt/testDir 2>/dev/null || sleep 1 && umount /mnt" "" "" ""
reCreateTmpFs
-testing "mount -o ro,remount $tmp_b_fs /mnt" \
+testing "-o ro,remount $tmp_b_fs /mnt" \
"mount -o ro $tmp_b_fs /mnt >/dev/null 2>&1 &&
mkdir /mnt/testDir 2>/dev/null || sleep 1 && umount /mnt" "" "" ""
reCreateTmpFs
#!/bin/bash
+# TODO: needs root to mount tmpfs to test moving across filesystems.
+# check handling of chattr +i immutable bit
+# "touch two; chmod -w two; mv one two" shouldn't prompt to delete two if
+# one doesn't exist.
+
# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
#testing "name" "command" "result" "infile" "stdin"
touch file
-testing "Move old_file to new_file" "mv file file1 && [ ! -e file -a -f file1 ] &&
- echo 'yes'" "yes\n" "" ""
+testing "file to file" \
+ "mv file file1 && [ ! -e file -a -f file1 ] && echo yes" \
+ "yes\n" "" ""
rm -f file*
touch file
mkdir dir
-testing "Move file to a dir" "mv file dir && [ ! -e file -a -f dir/file ] &&
- echo 'yes'" "yes\n" "" ""
+testing "file to dir" \
+ "mv file dir && [ ! -e file -a -f dir/file ] && echo yes" \
+ "yes\n" "" ""
rm -rf file* dir*
mkdir dir
-testing "Move old_dir to new_dir" "mv dir dir1 && [ ! -e dir -a -d dir1 ] &&
- echo 'yes'" "yes\n" "" ""
+testing "dir to dir" \
+ "mv dir dir1 && [ ! -e dir -a -d dir1 ] && echo yes" \
+ "yes\n" "" ""
rm -rf dir*
mkdir dir1 dir2
touch file1 file2 dir1/file3
ln -s file1 link1
-testing "Move multiple files/dir to a dir" "mv file1 file2 link1 dir1 dir2 &&
- [ ! -e file1 -a ! -e file2 -a ! -e link1 -a ! -e dir1 ] &&
- [ -f dir2/file1 -a -f dir2/file2 -a -L dir2/link1 -a -d dir2/dir1 ] &&
- [ -f dir2/dir1/file3 ] && readlink dir2/link1" "file1\n" "" ""
+testing "multiple files/dirs to a dir" \
+ "mv file1 file2 link1 dir1 dir2 &&
+ [ ! -e file1 -a ! -e file2 -a ! -e link1 -a ! -e dir1 ] &&
+ [ -f dir2/file1 -a -f dir2/file2 -a -L dir2/link1 -a -d dir2/dir1 ] &&
+ [ -f dir2/dir1/file3 ] && readlink dir2/link1" \
+ "file1\n" "" ""
rm -rf file* link* dir*
-touch file1
-testing "Move a empty file to new_file" "mv file1 file2 &&
- [ ! -e file1 -a -f file2 ] && stat -c %s file2" "0\n" "" ""
-rm -rf file*
-
-mkdir dir1
-testing "Move enpty dir to new_dir" "mv dir1 dir2 &&
- [ ! -d dir1 -a -d dir2 ] && echo 'yes'" "yes\n" "" ""
-rm -rf dir*
-
dd if=/dev/zero of=file1 seek=10k count=1 >/dev/null 2>&1
-testing "Move file new_file (random file)" "mv file1 file2 &&
- [ ! -e file1 -a -f file2 ] && stat -c %s file2" "5243392\n" "" ""
+testing "random file to new file" \
+ "mv file1 file2 && [ ! -e file1 -a -f file2 ] && stat -c %s file2" \
+ "5243392\n" "" ""
rm -f file*
touch file1
ln -s file1 link1
-testing "Move link new_link (softlink)" "mv link1 link2 &&
- [ ! -e link1 -a -L link2 ] && readlink link2" "file1\n" "" ""
+testing "symlink to new symlink" \
+ "mv link1 link2 && [ ! -e link1 -a -L link2 ] && readlink link2" \
+ "file1\n" "" ""
unlink tLink2 &>/dev/null
rm -f file* link*
touch file1
ln file1 link1
-testing "Move link new_link (hardlink)" "mv link1 link2 &&
- [ ! -e link1 -a -f link2 -a file1 -ef link2 ] && echo 'yes'" "yes\n" "" ""
+testing "hard link to new hardlink" \
+ "mv link1 link2 && [ ! -e link1 -a -f link2 -a file1 -ef link2 ] && echo yes" \
+ "yes\n" "" ""
unlink link2 &>/dev/null
rm -f file* link*
touch file1
chmod a-r file1
-testing "Move file new_file (unreadable)" "mv file1 file2 &&
- [ ! -e file1 -a -f file2 ] && echo 'yes'" "yes\n" "" ""
+testing "file to unreadable file" \
+ "mv file1 file2 && [ ! -e file1 -a -f file2 ] && echo yes" \
+ "yes\n" "" ""
rm -f file*
touch file1
ln file1 link1
mkdir dir1
-testing "Move file link dir (hardlink)" "mv file1 link1 dir1 &&
- [ ! -e file1 -a ! -e link1 -a -f dir1/file1 -a -f dir1/link1 ] &&
- [ dir1/file1 -ef dir1/link1 ] && echo 'yes'" "yes\n" "" ""
+testing "file hardlink dir" \
+ "mv file1 link1 dir1 &&
+ [ ! -e file1 -a ! -e link1 -a -f dir1/file1 -a -f dir1/link1 ] &&
+ [ dir1/file1 -ef dir1/link1 ] && echo yes" \
+ "yes\n" "" ""
rm -rf file* link* dir*
mkdir -p dir1/dir2 dir3
touch dir1/dir2/file1 dir1/dir2/file2
-testing "Move dir1/dir2 dir3/new_dir" "mv dir1/dir2 dir3/dir4 &&
- [ ! -e dir1/dir2 -a -d dir3/dir4 -a -f dir3/dir4/file1 ] &&
- [ -f dir3/dir4/file2 ] && echo 'yes'" "yes\n" "" ""
+testing "dir to new dir" \
+ "mv dir1/dir2 dir3/new &&
+ [ ! -e dir1/dir2 -a -d dir3/new -a -f dir3/new/file1 ] &&
+ [ -f dir3/new/file2 ] && echo yes" \
+ "yes\n" "" ""
rm -rf file* dir*
mkdir dir1 dir2
-testing "Move dir new_dir (already exist)" "mv dir1 dir2 &&
- [ ! -e dir1 -a -d dir2/dir1 ] && echo 'yes'" "yes\n" "" ""
+testing "dir to existing dir" \
+ "mv dir1 dir2 && [ ! -e dir1 -a -d dir2/dir1 ] && echo yes" \
+ "yes\n" "" ""
rm -rf dir*
touch file1 file2
-testing "Move -f file new_file (exist)" "mv -f file1 file2 &&
- [ ! -e file1 -a -e file2 ] && echo 'yes'" "yes\n" "" ""
+chmod 400 file1 file2
+testing "force over unwritable" \
+ "mv -f file1 file2 && [ ! -e file1 -a -e file2 ] && echo yes" \
+ "yes\n" "" ""
+rm -f file*
+
+touch file1 file2
+testing "no clobber (dest exists)" \
+ "mv -n file1 file2 && [ -e file1 -a -e file2 ] && echo yes"\
+ "yes\n" "" ""
rm -f file*
+touch file1
+testing "no clobber (dest doesn't exist)" \
+ "mv -n file1 new-dest && [ ! -e file1 -a -e new-dest ] && echo yes"\
+ "yes\n" "" ""
+rm -f file*
+
+# If there is stdin, it prompts. If no stdin, it moves anyway and file2 won't
+# exist.
touch file1 file2
-testing "Move -n file new_file (exist)" "mv -n file1 file2 &&
- [ -e file1 -a -e file2 ] && echo 'yes'" "yes\n" "" ""
+chmod 400 file1 file2
+testing "mv over unwritable file: no stdin" \
+ "mv file2 file1 && [ -e file1 -a ! -e file2 ] && echo yes" \
+ "yes\n" "" ""
rm -f file*
touch file1 file2
chmod 400 file1 file2
-testing "Move file over unwritable file with no stdin" \
- "</dev/null mv file2 file1 && [ -e file -a ! -e file2 ] && echo 'yes'" \
- "yes\n" "" ""
+testing "mv over unwritable file: answered YES" \
+ "mv file2 file1 && [ -e file1 -a ! -e file2 ] && echo yes" \
+ "yes\n" "" "y\n"
+rm -f file*
+
+touch file1 file2
+chmod 400 file1 file2
+testing "mv over unwritable file: answered NO" \
+ "mv file2 file1 && [ -e file1 -a -e file2 ] && echo yes" \
+ "yes\n" "" "n\n"
+rm -f file*
+
+touch file1 file2
+testing "interactive: no stdin" \
+ "mv -i file2 file1 && [ -e file1 -a ! -e file2 ] && echo yes" \
+ "yes\n" "" ""
+rm -f file*
+
+touch file1 file2
+testing "interactive: answered YES" \
+ "mv -i file2 file1 && [ -e file1 -a ! -e file2 ] && echo yes" \
+ "yes\n" "" "y\n"
+rm -f file*
+
+touch file1 file2
+testing "interactive: answered NO" \
+ "mv -i file2 file1 && [ -e file1 -a -e file2 ] && echo yes" \
+ "yes\n" "" "n\n"
rm -f file*
testing "nl" "nl" " 1\tone\n 2\ttwo\n 3\tthree\n" \
"" "one\ntwo\nthree\n"
-testing "nl explicit defaults" "nl -nrn -b a" \
+testing "explicit defaults" "nl -nrn -b a" \
" 1\tone\n 2\ttwo\n 3\tthree\n" "" "one\ntwo\nthree\n"
# -n ln rn rz
-testing "nl -nln" "nl -nln" "1 \tone\n2 \ttwo\n3 \tthree\n" \
+testing "-nln" "nl -nln" "1 \tone\n2 \ttwo\n3 \tthree\n" \
"" "one\ntwo\nthree\n"
-testing "nl -nln -w" "nl -nln -w 8" \
+testing "-nln -w" "nl -nln -w 8" \
"1 \tone\n2 \ttwo\n3 \tthree\n" "" "one\ntwo\nthree\n"
-testing "nl -nrz" "nl -nrz" "000001\tone\n000002\ttwo\n000003\tthree\n" \
+testing "-nrz" "nl -nrz" "000001\tone\n000002\ttwo\n000003\tthree\n" \
"" "one\ntwo\nthree\n"
-testing "nl -nrz -w" "nl -w3 -nrz" "001\tone\n002\ttwo\n003\tthree\n" \
+testing "-nrz -w" "nl -w3 -nrz" "001\tone\n002\ttwo\n003\tthree\n" \
"" "one\ntwo\nthree\n"
# nl -w 3 -bpthe README
# Yeah. And I doubt utf8 fontmetrics are used either.
-testing "nl -b t" "nl -b t" " \n 1\tone\n \n 2\ttwo\n" \
+testing "-b t" "nl -b t" " \n 1\tone\n \n 2\ttwo\n" \
"" "\none\n\ntwo\n"
-testing "nl -b n" "nl -b n" " one\n two\n three\n" \
+testing "-b n" "nl -b n" " one\n two\n three\n" \
"" "one\ntwo\nthree\n"
-testing "nl -sook -b p" "nl -sook -bpoing" \
+testing "-sook -b p" "nl -sook -bpoing" \
" one\n 1ookboing\n 2ooksproingy\n" \
"" "one\nboing\nsproingy\n"
-testing "nl -v" "nl -v 42" " 42\tone\n 43\ttwo\n 44\tthree\n" \
+testing "-v" "nl -v 42" " 42\tone\n 43\ttwo\n 44\tthree\n" \
"" "one\ntwo\nthree\n"
-testing "nl -l" "nl -ba -l2 -w2 - input" \
+testing "-l" "nl -ba -l2 -w2 - input" \
" 1\tone\n \n 2\t\n 3\ttwo\n \n 4\t\n \n 5\tthree\n 6\tfour\n \n 7\t\n \n 8\tbang\n \n" \
"\n\nbang\n\n" "one\n\n\ntwo\n\n\n\nthree\nfour\n\n"
-testing "nl no space" "nl -w 1 -v 42" "42\tline\n" "" "line\n"
+testing "no space" "nl -w 1 -v 42" "42\tline\n" "" "line\n"
# Should test for -E but no other implementation seems to have it?
-#testing "nl -E" "nl -w2 -sx -Ebp'(one|two)'" " 1x" "one\nand\ntwo\n"
+#testing "-E" "nl -w2 -sx -Ebp'(one|two)'" " 1x" "one\nand\ntwo\n"
# Starting processes to test pgrep command
yes >/dev/null &
proc=$!
-echo "# Process created with id: $proc"
-sleep 1
+#echo "# Process created with id: $proc"
+sleep .1
session_id=0
proc_parent=`cat /proc/${proc}/stat | awk '{ print $4 }'`
-echo "# Parent Process id of $proc is $proc_parent"
+#echo "# Parent Process id of $proc is $proc_parent"
# Testcases for pgrep command
-testing "pgrep pattern" "pgrep yes" "$proc\n" "" ""
-testing "pgrep wildCardPattern" "pgrep ^y.*s$" "$proc\n" "" ""
-testing "pgrep -l pattern" "pgrep -l yes" "$proc yes\n" "" ""
-testing "pgrep -f pattern" "pgrep -f yes" "$proc\n" "" ""
-testing "pgrep -n pattern" "pgrep -n yes" "$proc\n" "" ""
-testing "pgrep -o pattern" "pgrep -o yes" "$proc\n" "" ""
-testing "pgrep -s" "pgrep -s $session_id yes" "$proc\n" "" ""
-testing "pgrep -P" "pgrep -P $proc_parent yes" "$proc\n" "" ""
+testing "pattern" "pgrep yes" "$proc\n" "" ""
+testing "wildCardPattern" "pgrep ^y.*s$" "$proc\n" "" ""
+testing "-l pattern" "pgrep -l yes" "$proc yes\n" "" ""
+testing "-f pattern" "pgrep -f yes" "$proc\n" "" ""
+testing "-n pattern" "pgrep -n yes" "$proc\n" "" ""
+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
-
-# Testcases for pkill command
-
-yes >/dev/null &
-sleep 1
-testing "pkill pattern" "pkill yes && sleep 1 && (pgrep yes || echo 'yes')" \
- "yes\n" "" ""
-killall yes >/dev/null 2>&1
-
-yes >/dev/null &
-yes print1 >/dev/null &
-yes print2 >/dev/null &
-sleep 1
-testing "pkill pattern (multiple)" "pkill yes && sleep 1 &&
- (pgrep yes || echo 'yes')" "yes\n" "" ""
-killall yes >/dev/null 2>&1
-
-yes >/dev/null &
-sleep 1
-testing "pkill -f pattern (one)" "pkill -f yes && sleep 1 &&
- (pgrep yes || echo 'yes')" "yes\n" "" ""
-killall yes >/dev/null 2>&1
-
-yes print1 >/dev/null &
-sleep 1
-testing "pkill -f pattern args" "pkill -f \"yes print1\" && sleep 1 &&
- (pgrep yes || echo 'yes')" "yes\n" "" ""
-killall yes >/dev/null 2>&1
-
-yes >/dev/null &
-yes print1 >/dev/null &
-yes print2 >/dev/null &
-sleep 1
-testing "pkill -f pattern (multiple)" "pkill -f yes && sleep 1 &&
- (pgrep yes || echo 'yes')" "yes\n" "" ""
-killall yes >/dev/null 2>&1
-
-yes >/dev/null &
-sleep 1
-testing "pkill -s 0 -f pattern (regexp)" "pkill -s 0 -f ye* && sleep 1 &&
- (pgrep yes || echo 'yes')" "yes\n" "" ""
-killall yes >/dev/null 2>&1
-
-yes >/dev/null &
-proc1=$!
-yes >/dev/null &
-proc2=$!
-sleep 1
-testing "pkill -n pattern" "pkill -n yes && sleep 1 && pgrep yes" \
- "$proc1\n" "" ""
-killall yes >/dev/null 2>&1
-
-yes >/dev/null &
-proc1=$!
-yes >/dev/null &
-proc2=$!
-sleep 1
-testing "pkill -o pattern" "pkill -o yes && sleep 1 && pgrep yes" \
- "$proc2\n" "" ""
-killall yes >/dev/null 2>&1
-
-yes >/dev/null &
-sleep 1
-testing "pkill -s (blank) pattern" "pkill -s '' yes && sleep 1 &&
- (pgrep yes || echo 'yes')" "yes\n" "" ""
-killall yes >/dev/null 2>&1
-
-yes >/dev/null &
-sleep 1
-testing "pkill -s 0 pattern" "pkill -s 0 yes && sleep 1 &&
- (pgrep yes || echo 'yes')" "yes\n" "" ""
-killall yes >/dev/null 2>&1
-
-yes >/dev/null &
-proc=$!
-proc_p=`cat /proc/${proc}/stat | awk '{ print $4 }'`
-sleep 1
-testing "pkill -P parent_prodId pattern" "pkill -P $proc_p yes && sleep 1 &&
- (pgrep yes || echo 'yes')" "yes\n" "" ""
-killall yes >/dev/null 2>&1
-
-yes >/dev/null &
-proc=$!
-proc_parent=`cat /proc/${proc}/stat | awk '{ print $4 }'`
-sleep 1
-testing "pkill -9 pattern" "pkill -9 yes && sleep 1 &&
- (pgrep yes || echo 'yes')" "yes\n" "" ""
-killall yes >/dev/null 2>&1
-
--- /dev/null
+#!/bin/bash
+
+# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
+# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
+
+#cleaning 'yes' processes
+killall yes >/dev/null 2>&1
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+# Testcases for pkill command
+
+yes >/dev/null &
+sleep 1
+testing "pattern" "pkill yes && sleep 1 && (pgrep yes || echo 'yes')" \
+ "yes\n" "" ""
+killall yes >/dev/null 2>&1
+
+yes >/dev/null &
+yes print1 >/dev/null &
+yes print2 >/dev/null &
+sleep 1
+testing "pattern (multiple)" "pkill yes && sleep 1 &&
+ (pgrep yes || echo 'yes')" "yes\n" "" ""
+killall yes >/dev/null 2>&1
+
+yes >/dev/null &
+sleep 1
+testing "-f pattern (one)" "pkill -f yes && sleep 1 &&
+ (pgrep yes || echo 'yes')" "yes\n" "" ""
+killall yes >/dev/null 2>&1
+
+yes print1 >/dev/null &
+sleep 1
+testing "-f pattern args" "pkill -f \"yes print1\" && sleep 1 &&
+ (pgrep yes || echo 'yes')" "yes\n" "" ""
+killall yes >/dev/null 2>&1
+
+yes >/dev/null &
+yes print1 >/dev/null &
+yes print2 >/dev/null &
+sleep 1
+testing "-f pattern (multiple)" "pkill -f yes && sleep 1 &&
+ (pgrep yes || echo 'yes')" "yes\n" "" ""
+killall yes >/dev/null 2>&1
+
+yes >/dev/null &
+sleep 1
+testing "-s 0 -f pattern (regexp)" "pkill -s 0 -f ye* && sleep 1 &&
+ (pgrep yes || echo 'yes')" "yes\n" "" ""
+killall yes >/dev/null 2>&1
+
+yes >/dev/null &
+proc1=$!
+yes >/dev/null &
+proc2=$!
+sleep 1
+testing "-n pattern" "pkill -n yes && sleep 1 && pgrep yes" \
+ "$proc1\n" "" ""
+killall yes >/dev/null 2>&1
+
+yes >/dev/null &
+proc1=$!
+sleep 1
+yes >/dev/null &
+proc2=$!
+sleep 1
+testing "-o pattern" "pkill -o yes && sleep 1 && pgrep yes" \
+ "$proc2\n" "" ""
+killall yes >/dev/null 2>&1
+
+yes >/dev/null &
+sleep 1
+testing "-s (blank) pattern" "pkill -s '' yes && sleep 1 &&
+ (pgrep yes || echo 'yes')" "yes\n" "" ""
+killall yes >/dev/null 2>&1
+
+yes >/dev/null &
+sleep 1
+testing "-s 0 pattern" "pkill -s 0 yes && sleep 1 &&
+ (pgrep yes || echo 'yes')" "yes\n" "" ""
+killall yes >/dev/null 2>&1
+
+yes >/dev/null &
+proc=$!
+proc_p=`cat /proc/${proc}/stat | awk '{ print $4 }'`
+sleep 1
+testing "-P parent_prodId pattern" "pkill -P $proc_p yes && sleep 1 &&
+ (pgrep yes || echo 'yes')" "yes\n" "" ""
+killall yes >/dev/null 2>&1
+
+yes >/dev/null &
+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" "" ""
+
# Disable shell builtin
PRINTF="$(which printf)"
-testing "printf text" "$PRINTF TEXT" "TEXT" "" ""
-testing "printf escapes" "$PRINTF 'one\ntwo\n\v\t\r\f\e\b\athree'" \
+testing "text" "$PRINTF TEXT" "TEXT" "" ""
+testing "escapes" "$PRINTF 'one\ntwo\n\v\t\r\f\e\b\athree'" \
"one\ntwo\n\v\t\r\f\e\b\athree" "" ""
-testing "printf %b escapes" "$PRINTF %b 'one\ntwo\n\v\t\r\f\e\b\athree'" \
+testing "%b escapes" "$PRINTF %b 'one\ntwo\n\v\t\r\f\e\b\athree'" \
"one\ntwo\n\v\t\r\f\e\b\athree" "" ""
-testing "printf null" "$PRINTF 'x\0y' | od -An -tx1" ' 78 00 79\n' "" ""
-testing "printf trailing slash" "$PRINTF 'abc\'" 'abc\' "" ""
-testing "printf octal" "$PRINTF ' \1\002\429\045x'" ' \001\002"9%x' "" ""
-testing "printf not octal" "$PRINTF '\9'" '\9' "" ""
-testing "printf hex" "$PRINTF 'A\x1b\x2B\x3Q\xa' | od -An -tx1" \
+testing "null" "$PRINTF 'x\0y' | od -An -tx1" ' 78 00 79\n' "" ""
+testing "trailing slash" "$PRINTF 'abc\'" 'abc\' "" ""
+testing "octal" "$PRINTF ' \1\002\429\045x'" ' \001\002"9%x' "" ""
+testing "not octal" "$PRINTF '\9'" '\9' "" ""
+testing "hex" "$PRINTF 'A\x1b\x2B\x3Q\xa' | od -An -tx1" \
' 41 1b 2b 03 51 0a\n' "" ""
-testing "printf %x" "$PRINTF '%x\n' 0x2a" "2a\n" "" ""
+testing "%x" "$PRINTF '%x\n' 0x2a" "2a\n" "" ""
-testing "printf %d 42" "$PRINTF %d 42" "42" "" ""
-testing "printf %d 0x2a" "$PRINTF %d 0x2a" "42" "" ""
-testing "printf %d 052" "$PRINTF %d 052" "42" "" ""
+testing "%d 42" "$PRINTF %d 42" "42" "" ""
+testing "%d 0x2a" "$PRINTF %d 0x2a" "42" "" ""
+testing "%d 052" "$PRINTF %d 052" "42" "" ""
-testing "printf %s width precision" \
+testing "%s width precision" \
"$PRINTF '%3s,%.3s,%10s,%10.3s' abcde fghij klmno pqrst" \
"abcde,fgh, klmno, pqr" "" ""
# posix: "The format operand shall be reused as often as necessary to satisfy
# the argument operands."
-testing "printf extra args" "$PRINTF 'abc%s!%ddef\n' X 42 ARG 36" \
+testing "extra args" "$PRINTF 'abc%s!%ddef\n' X 42 ARG 36" \
"abcX!42def\nabcARG!36def\n" "" ""
-testing "printf '%3c'" "$PRINTF '%3c' x" " x" "" ""
-testing "printf '%-3c'" "$PRINTF '%-3c' x" "x " "" ""
-testing "printf '%+d'" "$PRINTF '%+d' 5" "+5" "" ""
+testing "'%3c'" "$PRINTF '%3c' x" " x" "" ""
+testing "'%-3c'" "$PRINTF '%-3c' x" "x " "" ""
+testing "'%+d'" "$PRINTF '%+d' 5" "+5" "" ""
-testing "printf '%5d%4d' 1 21 321 4321 54321" \
+testing "'%5d%4d' 1 21 321 4321 54321" \
"$PRINTF '%5d%4d' 1 21 321 4321 54321" " 1 21 321432154321 0" "" ""
-testing "printf '%c %c' 78 79" "$PRINTF '%c %c' 78 79" "7 7" "" ""
-testing "printf '%d %d' 78 79" "$PRINTF '%d %d' 78 79" "78 79" "" ""
-testing "printf '%f %f' 78 79" "$PRINTF '%f %f' 78 79" \
+testing "'%c %c' 78 79" "$PRINTF '%c %c' 78 79" "7 7" "" ""
+testing "'%d %d' 78 79" "$PRINTF '%d %d' 78 79" "78 79" "" ""
+testing "'%f %f' 78 79" "$PRINTF '%f %f' 78 79" \
"78.000000 79.000000" "" ""
-testing "printf 'f f' 78 79" "$PRINTF 'f f' 78 79" "f f" "" ""
-testing "printf '%i %i' 78 79" "$PRINTF '%i %i' 78 79" "78 79" "" ""
-testing "printf '%o %o' 78 79" "$PRINTF '%o %o' 78 79" "116 117" "" ""
-testing "printf '%u %u' 78 79" "$PRINTF '%u %u' 78 79" "78 79" "" ""
-testing "printf '%u %u' -1 -2" "$PRINTF '%u %u' -1 -2" \
+testing "'f f' 78 79" "$PRINTF 'f f' 78 79" "f f" "" ""
+testing "'%i %i' 78 79" "$PRINTF '%i %i' 78 79" "78 79" "" ""
+testing "'%o %o' 78 79" "$PRINTF '%o %o' 78 79" "116 117" "" ""
+testing "'%u %u' 78 79" "$PRINTF '%u %u' 78 79" "78 79" "" ""
+testing "'%u %u' -1 -2" "$PRINTF '%u %u' -1 -2" \
"18446744073709551615 18446744073709551614" "" ""
-testing "printf '%x %X' 78 79" "$PRINTF '%x %X' 78 79" "4e 4F" "" ""
-testing "printf '%g %G' 78 79" "$PRINTF '%g %G' 78 79" "78 79" "" ""
-testing "printf '%s %s' 78 79" "$PRINTF '%s %s' 78 79" "78 79" "" ""
+testing "'%x %X' 78 79" "$PRINTF '%x %X' 78 79" "4e 4F" "" ""
+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 "printf %.s acts like %.0s" "$PRINTF %.s_ 1 2 3 4 5" "_____" "" ""
+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" \
+ "" ""
testing "pwd" "[ $(stat -c %i "$(pwd)") = $(stat -c %i .) ] && echo yes" \
"yes\n" "" ""
-testing "pwd -P" "[ $(stat -c %i "$(pwd -P)") = $(stat -c %i .) ] && echo yes" \
+testing "-P" "[ $(stat -c %i "$(pwd -P)") = $(stat -c %i .) ] && echo yes" \
"yes\n" "" ""
cd sym
testing "pwd" "[ $(stat -c %i "$(pwd)") = $(stat -c %i "$PWD") ] && echo yes" \
"yes\n" "" ""
-testing "pwd -P" "[ $(stat -c %i "$(pwd -P)") = $(stat -c %i "$PWD") ] || echo yes" \
+testing "-P" "[ $(stat -c %i "$(pwd -P)") = $(stat -c %i "$PWD") ] || echo yes" \
"yes\n" "" ""
cd ..
rm sym
export PWD=walrus
-testing "pwd (bad PWD)" "[ "$(pwd)" = "$(cd . ; pwd)" ] && echo yes" \
+testing "(bad PWD)" "[ "$(pwd)" = "$(cd . ; pwd)" ] && echo yes" \
"yes\n" "" ""
APWD="$(pwd -P)"
-testing "readlink missing" "readlink notfound || echo yes" "yes\n" "" ""
+testing "missing" "readlink notfound || echo yes" "yes\n" "" ""
# simple tests on a file
touch file
-testing "readlink file" "readlink file || echo yes" "yes\n" "" ""
-testing "readlink -f dir" "readlink -f ." "$APWD\n" "" ""
-testing "readlink -f missing" "readlink -f notfound" "$APWD/notfound\n" "" ""
+testing "file" "readlink file || echo yes" "yes\n" "" ""
+testing "-f dir" "readlink -f ." "$APWD\n" "" ""
+testing "-f missing" "readlink -f notfound" "$APWD/notfound\n" "" ""
ln -sf notfound link
-testing "readlink link" "readlink link" "notfound\n" "" ""
-testing "readlink link->missing" "readlink -f link" "$APWD/notfound\n" "" ""
+testing "link" "readlink link" "notfound\n" "" ""
+testing "link->missing" "readlink -f link" "$APWD/notfound\n" "" ""
ln -sf ../../ link
-testing "readlink stays relative" "readlink link" "../../\n" "" ""
+testing "stays relative" "readlink link" "../../\n" "" ""
rm link
ln -sf file link
-testing "readlink -f link->file" "readlink -f link" "$APWD/file\n" "" ""
+testing "-f link->file" "readlink -f link" "$APWD/file\n" "" ""
ln -sf . link
-testing "readlink -f link->dir" "readlink -f link" "$APWD\n" "" ""
+testing "-f link->dir" "readlink -f link" "$APWD\n" "" ""
ln -snf link link
-testing "readlink link->link (recursive)" "readlink link" "link\n" "" ""
-testing "readlink -f link->link (recursive)" \
+testing "link->link (recursive)" "readlink link" "link\n" "" ""
+testing "-f link->link (recursive)" \
"readlink -f link 2>/dev/null || echo yes" "yes\n" "" ""
-testing "readlink -q notlink" "readlink -q file || echo yes" "yes\n" "" ""
-testing "readlink -q link" "readlink -q link && echo yes" "yes\n" "" ""
-testing "readlink -q notfound" "readlink -q notfound || echo yes" "yes\n" "" ""
-testing "readlink -e found" "readlink -e file" "$APWD/file\n" "" ""
-testing "readlink -e notfound" \
+testing "-q notlink" "readlink -q file || echo yes" "yes\n" "" ""
+testing "-q link" "readlink -q link && echo yes" "yes\n" "" ""
+testing "-q notfound" "readlink -q notfound || echo yes" "yes\n" "" ""
+testing "-e found" "readlink -e file" "$APWD/file\n" "" ""
+testing "-e notfound" \
"readlink -e notfound 2>/dev/null || echo yes" "yes\n" "" ""
-testing "readlink -nf ." "readlink -nf ." "$APWD" "" ""
+testing "-nf ." "readlink -nf ." "$APWD" "" ""
mkdir sub &&
ln -s . here &&
ln -s ./sub dir &&
touch sub/bang || exit 1
-testing "readlink -f multi" "readlink -f dir/../here/dir/bang" \
+testing "-f multi" "readlink -f dir/../here/dir/bang" \
"$APWD/sub/bang\n" "" ""
-testing "readlink -f link/missing" "readlink -f dir/boing" \
+testing "-f link/missing" "readlink -f dir/boing" \
"$APWD/sub/boing\n" "" ""
-testing "readlink -f /dev/null/file" \
+testing "-f /dev/null/file" \
"readlink -f /dev/null/file 2>/dev/null || echo yes" "yes\n" "" ""
ln -sf / link || exit 1
-testing "readlink -f link->/" "readlink -e link/dev" "/dev\n" "" ""
-testing "readlink -f /dev/null/.." \
+testing "-f link->/" "readlink -e link/dev" "/dev\n" "" ""
+testing "-f /dev/null/.." \
"readlink -f link/null/.. 2>/dev/null || echo yes" "yes\n" "" ""
rm -f link && ln -sf link link || exit 1
-testing "readlink recurse" "readlink link" "link\n" "" ""
+testing "recurse" "readlink link" "link\n" "" ""
rm file link sub/bang dir here
rmdir sub
ln -s link1 link2
ln -s link2 link1
-testing "readlink follow recursive2" "readlink -f link1 || echo yes" \
+testing "follow recursive2" "readlink -f link1 || echo yes" \
"yes\n" "" ""
rm link1 link2
nice_val3=$((`fun_nice_val $proc3` + $n_v))
nice_val4=$((`fun_nice_val $proc4` + $n_v))
nice_val5=$((`fun_nice_val $proc5` + $n_v))
- testing "renice with -n=$n_v and with$n_o multiple_pids" \
+ testing "with -n=$n_v and with$n_o multiple_pids" \
"renice -n $n_v$n_o $proc1 $proc2 $proc3 $proc4 $proc5 &&
fun_nice_val $proc1 $proc2 $proc3 $proc4 $proc5" \
"$nice_val1\n$nice_val2\n$nice_val3\n$nice_val4\n$nice_val5\n" "" ""
nice_val3=$((`fun_nice_val $proc3` + $n_v))
nice_val4=$((`fun_nice_val $proc4` + $n_v))
nice_val5=$((`fun_nice_val $proc5` + $n_v))
- testing "renice with -n=$n_v and with$n_o multiple_pids (some invalid)" \
+ testing "with -n=$n_v and with$n_o multiple_pids (some invalid)" \
"renice -n $n_v$n_o $proc1 $proc2 88888 99999 $proc3 $proc4 $proc5 $arg ||
fun_nice_val $proc1 $proc2 $proc3 $proc4 $proc5" \
"$nice_val1\n$nice_val2\n$nice_val3\n$nice_val4\n$nice_val5\n" "" ""
echo -e "one" > file1
echo -e "two" > file2
testing "rev" "rev && echo yes" "orez\nyes\n" "" "zero\n"
-testing "rev -" "rev - && echo yes" "orez\nyes\n" "" "zero\n"
-testing "rev file1 file2" "rev file1 file2" "eno\nowt\n" "" ""
-testing "rev - file" "rev - file1" "orez\neno\n" "" "zero\n"
-testing "rev file -" "rev file1 -" "eno\norez\n" "" "zero\n"
-testing "rev no trailing newline" "rev -" "cba\nfed\n" "" "abc\ndef"
+testing "-" "rev - && echo yes" "orez\nyes\n" "" "zero\n"
+testing "file1 file2" "rev file1 file2" "eno\nowt\n" "" ""
+testing "- file" "rev - file1" "orez\neno\n" "" "zero\n"
+testing "file -" "rev file1 -" "eno\norez\n" "" "zero\n"
+testing "no trailing newline" "rev -" "cba\nfed\n" "" "abc\ndef"
-testing "rev file1 notfound file2" \
+testing "file1 notfound file2" \
"rev file1 notfound file2 2>stderr && echo ok ; cat stderr; rm stderr" \
"eno\nowt\nrev: notfound: No such file or directory\n" "" ""
-testing "rev different input sizes"\
+testing "different input sizes"\
"rev"\
"\n1\n21\n321\n4321\n54321\n4321\n321\n21\n1\n\n"\
"" "\n1\n12\n123\n1234\n12345\n1234\n123\n12\n1\n\n"
#testing "name" "command" "result" "infile" "stdin"
echo "abcdefghijklmnopqrstuvwxyz" > file.txt
-testing "Remove text-file" "rm file.txt && [ ! -e file.txt ] && echo 'yes'" "yes\n" "" ""
+testing "text-file" "rm file.txt && [ ! -e file.txt ] && echo 'yes'" "yes\n" "" ""
rm -f file*
mkdir dir
-testing "Remove empty directory" "rm -r dir && [ ! -d dir ] && echo 'yes'" "yes\n" "" ""
+testing "empty directory" "rm -r dir && [ ! -d dir ] && echo 'yes'" "yes\n" "" ""
rm -rf dir
echo "abcdefghijklmnopqrstuvwxyz" > file.txt && chmod 000 file.txt
-testing "Remove text file(mode 000)" "rm -f file.txt && [ ! -e file.txt ] && echo 'yes'" \
+testing "text file(mode 000)" "rm -f file.txt && [ ! -e file.txt ] && echo 'yes'" \
"yes\n" "" ""
rm -f file*
touch file1.txt file2.txt
mkdir dir1 dir2
-testing "rm -r (multiple files and dirs)" \
+testing "-r (multiple files and dirs)" \
"rm -r file1.txt file2.txt dir1 dir2 2>/dev/null &&
[ ! -e file1.txt -a ! -e file2.txt -a ! -d dir1 -a ! -d dir2 ] && echo 'yes'" \
"yes\n" "" ""
touch file1.txt file2.txt
mkdir dir1 dir2
-testing "rm -rf (present + missing files and dirs)" \
+testing "-rf (present + missing files and dirs)" \
"rm -rf file1.txt file2.txt file3.txt dir1 dir2 dir3 2>/dev/null &&
[ ! -e file1.txt -a ! -e file2.txt -a ! -d dir1 -a ! -d dir2 ] && echo 'yes'" \
"yes\n" "" ""
# testing with nested dirs.
mkdir -p dir1/dir2/dir3 dir1/dir2/dir4
touch dir1/file1.txt dir1/dir2/file2.txt dir1/dir2/dir3/file3.txt
-testing "rm -r nested_dir" "rm -r dir1/dir2/ 2>/dev/null &&
+testing "-r nested_dir" "rm -r dir1/dir2/ 2>/dev/null &&
[ -d dir1 -a -f dir1/file1.txt -a ! -d dir1/dir2 ] && echo 'yes'" \
"yes\n" "" ""
rm -rf dir*
testing "rmdir" "rmdir one && [ ! -d one ] && echo yes" "yes\n" "" ""
touch walrus
-testing "rmdir file" \
+testing "file" \
"rmdir walrus 2> /dev/null || [ -f walrus ] && echo yes" "yes\n" "" ""
mkdir one two
-testing "rmdir one two" \
+testing "one two" \
"rmdir one two 2> /dev/null && [ ! -d one ] && [ ! -d two ] && echo yes" \
"yes\n" "" ""
mkdir one two three
-testing "rmdir one missing two file three" \
+testing "one missing two file three" \
"rmdir one missing two walrus three 2> /dev/null || [ ! -d three ] && echo yes" \
"yes\n" "" ""
rm walrus
mkdir one
chmod 000 one
-testing "rmdir mode 000" "rmdir one && [ ! -d one ] && echo yes" "yes\n" "" ""
+testing "mode 000" "rmdir one && [ ! -d one ] && echo yes" "yes\n" "" ""
mkdir temp
touch temp/thing
-testing "rmdir non-empty" \
+testing "non-empty" \
"rmdir temp 2>/dev/null || [ -d temp ] && echo yes" "yes\n" "" ""
-testing "rmdir -p dir/file" \
+testing "-p dir/file" \
"rmdir -p temp/thing 2>/dev/null || [ -f temp/thing ] && echo yes" \
"yes\n" "" ""
mkdir -p temp/one/two/three
-testing "rmdir -p part of path" \
+testing "-p part of path" \
"rmdir -p temp/one/two/three 2>/dev/null || [ -d temp ] && [ ! -e temp/one ] && echo yes" \
"yes\n" "" ""
rm -rf temp
mkdir -p one/two/three
-testing "rmdir -p one/two/three" \
+testing "-p one/two/three" \
"rmdir -p one/two/three && [ ! -e one ] && echo yes" "yes\n" "" ""
mkdir -p one/two/three
-testing "rmdir -p one/two/three/" \
+testing "-p one/two/three/" \
"rmdir -p one/two/three/ && [ ! -e one ] && echo yes" "yes\n" "" ""
#mkdir -p one/two/three
#chmod 000 one/two/three one/two one
-#testing "rmdir -p one/two/three" \
+#testing "-p one/two/three" \
# "rmdir -p one/two/three && [ ! -e one ] && echo yes" "yes\n" "" ""
#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'
# 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 "sed aci" \
+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" "" \
"one\ntwo\nthree\nfour\n"
-testing "sed b loop" "sed ':woo;=;b woo' | head -n 5" '1\n1\n1\n1\n1\n' "" "X"
-testing "sed b skip" "sed -n '2b zap;d;:zap;p'" "two\n" "" "one\ntwo\nthree"
-testing "sed b end" "sed -n '2b;p'" "one\nthree" "" "one\ntwo\nthree"
-testing "sed c range" "sed '2,4c blah'" "one\nblah\nfive\nsix" "" \
+testing "b loop" "sed ':woo;=;b woo' | head -n 5" '1\n1\n1\n1\n1\n' "" "X"
+testing "b skip" "sed -n '2b zap;d;:zap;p'" "two\n" "" "one\ntwo\nthree"
+testing "b end" "sed -n '2b;p'" "one\nthree" "" "one\ntwo\nthree"
+testing "c range" "sed '2,4c blah'" "one\nblah\nfive\nsix" "" \
"one\ntwo\nthree\nfour\nfive\nsix"
-testing "sed c {range}" "sed -e '2,4{c blah' -e '}'" \
+testing "c {range}" "sed -e '2,4{c blah' -e '}'" \
"one\nblah\nblah\nblah\nfive\nsix" \
"" "one\ntwo\nthree\nfour\nfive\nsix"
-testing "sed c multiple continuation" \
+testing "c multiple continuation" \
"sed -e 'c\\' -e 'two\\' -e ''" "two\n\n" "" "hello"
-testing "sed D further processing depends on whether line is blank" \
+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' \
# all the s/// test
-testing "sed match empty line" "sed -e 's/^\$/@/'" "@\n" "" "\n"
+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 "sed delimiter in regex [char range] doesn't count" "sed -e 's/[/]//'" \
+testing "delimiter in regex [char range] doesn't count" "sed -e 's/[/]//'" \
"onetwo\n" "" 'one/two\n'
-testing "sed delete regex range start line after trigger" \
+testing "delete regex range start line after trigger" \
"sed -e '/one/,/three/{' -e 'i meep' -e '1D;}'" \
"meep\nmeep\ntwo\nmeep\nthree" "" "one\ntwo\nthree"
-testing "sed blank pattern repeats last pattern" \
+testing "blank pattern repeats last pattern" \
"sed -e '/^three/s//abc&def/'" \
"one two three\nabcthreedef four five\nfive six seven\n" "" \
"one two three\nthree four five\nfive six seven\n"
testing "" "sed -e '1a\' -e 'huh'" "meep\nhuh\n" "" "meep"
testing "" "sed -f input" "blah\nboom\n" '1a\\\nboom' 'blah'
+testing "" "sed -f - input" "blah\nboom\n" 'blah' '1a\\\nboom'
testing "" "sed '1a\
hello'" "merp\nhello\n" "" "merp"
testing "" "sed -e '/x/c\' -e 'y'" 'y\n' '' 'x\n'
testing "" "sed -e 's/a[([]*b/X/'" 'X' '' 'a[(b'
testing "" "sed 'y/a\\bc/de\f/'" "db\f" "" "abc"
-testing "sed [a-a] (for perl)" "sed '"'s/\([^a-zA-Z0-9.:_\-\/]\)/\\\1/g'"'" \
+testing "[a-a] (for perl)" "sed '"'s/\([^a-zA-Z0-9.:_\-\/]\)/\\\1/g'"'" \
'he\ llo' "" "he llo"
+# Debian bug https://bugs.debian.org/635570 added code to ensure a file
+# ends with a newline via "sed -e '$a\'". Apparently all a\ with no additional
+# pattern lines after it does (other than making posix throw up) is
+# flush the pending newline as _if_ it had added another line. *shrug* Ok?
+testing "trailing a\ (for debian)" "sed 'a\\'" "hello\n" "" "hello"
+
# You have to match the first line of a range in order to activate
# the range, numeric and ascii work the same way
-testing "sed skip start of range" "sed -e n -e '1,2s/b/c/'" "a\nb\n" "" "a\nb\n"
+testing "skip start of range" "sed -e n -e '1,2s/b/c/'" "a\nb\n" "" "a\nb\n"
#echo meep | sed/sed -e '1a\' -e 'huh'
#echo blah | sed/sed -f <(echo -e "1a\\\\\nboom")
#echo merp | sed/sed "1a\\
#hello"
-testing "sed bonus backslashes" \
+testing "bonus backslashes" \
"sed -e 'a \l \x\' -e \"\$(echo -e 'ab\\\nc')\"" \
"hello\nl x\nab\nc\n" "" "hello\n"
# -i with $ last line test
-
-
-exit $FAILCOUNT
#testing "name" "command" "result" "infile" "stdin"
-testing "seq (exit with error)" "seq 2> /dev/null || echo yes" "yes\n" "" ""
-testing "seq (exit with error)" "seq 1 2 3 4 2> /dev/null || echo yes" \
+testing "(exit with error)" "seq 2> /dev/null || echo yes" "yes\n" "" ""
+testing "(exit with error)" "seq 1 2 3 4 2> /dev/null || echo yes" \
"yes\n" "" ""
-testing "seq one argument" "seq 3" "1\n2\n3\n" "" ""
-testing "seq two arguments" "seq 5 7" "5\n6\n7\n" "" ""
-testing "seq two arguments reversed" "seq 7 5" "" "" ""
-testing "seq two arguments equal" "seq 3 3" "3\n" "" ""
-testing "seq two arguments equal, arbitrary negative step" "seq 1 -15 1" \
+testing "one argument" "seq 3" "1\n2\n3\n" "" ""
+testing "two arguments" "seq 5 7" "5\n6\n7\n" "" ""
+testing "two arguments reversed" "seq 7 5" "" "" ""
+testing "two arguments equal" "seq 3 3" "3\n" "" ""
+testing "two arguments equal, arbitrary negative step" "seq 1 -15 1" \
"1\n" "" ""
-testing "seq two arguments equal, arbitrary positive step" "seq 1 +15 1" \
+testing "two arguments equal, arbitrary positive step" "seq 1 +15 1" \
"1\n" "" ""
-testing "seq count up by 2" "seq 4 2 8" "4\n6\n8\n" "" ""
-testing "seq count down by 2" "seq 8 -2 4" "8\n6\n4\n" "" ""
-testing "seq count wrong way #1" "seq 4 -2 8" "" "" ""
-testing "seq count wrong way #2" "seq 8 2 4" "" "" ""
-testing "seq count by .3" "seq 3 .3 4" "3\n3.3\n3.6\n3.9\n" "" ""
-testing "seq count by -.9" "seq .7 -.9 -2.2" "0.7\n-0.2\n-1.1\n-2\n" "" ""
-testing "seq count by zero" "seq 4 0 8 | head -n 10" "" "" ""
-testing "seq separator -" "seq -s - 1 3" "1-2-3\n" "" ""
-testing "seq format string" 'seq -f %+01g -10 5 10' "-10\n-5\n+0\n+5\n+10\n" \
+testing "count up by 2" "seq 4 2 8" "4\n6\n8\n" "" ""
+testing "count down by 2" "seq 8 -2 4" "8\n6\n4\n" "" ""
+testing "count wrong way #1" "seq 4 -2 8" "" "" ""
+testing "count wrong way #2" "seq 8 2 4" "" "" ""
+testing "count by .3" "seq 3 .3 4" "3\n3.3\n3.6\n3.9\n" "" ""
+testing "count by -.9" "seq .7 -.9 -2.2" "0.7\n-0.2\n-1.1\n-2\n" "" ""
+testing "count by zero" "seq 4 0 8 | head -n 10" "" "" ""
+testing "separator -" "seq -s - 1 3" "1-2-3\n" "" ""
+testing "format string" 'seq -f %+01g -10 5 10' "-10\n-5\n+0\n+5\n+10\n" \
"" ""
-testing "seq separator and format string" "seq -f \%03g -s \; 5 -1 0" "005;004;003;002;001;000\n" "" ""
-testing "seq padding" "seq -s, -w -2 19 120" "-02,017,036,055,074,093,112\n" \
+testing "separator and format string" "seq -f \%03g -s \; 5 -1 0" "005;004;003;002;001;000\n" "" ""
+testing "padding" "seq -s, -w -2 19 120" "-02,017,036,055,074,093,112\n" \
"" ""
-testing "seq padding" "seq -s, -w -2 3 12" "-2,01,04,07,10\n" "" ""
-testing "seq padding" "seq -s, -w -2.2 3.3 12" "-2.2,01.1,04.4,07.7,11.0\n" \
+testing "padding" "seq -s, -w -2 3 12" "-2,01,04,07,10\n" "" ""
+testing "padding" "seq -s, -w -2.2 3.3 12" "-2.2,01.1,04.4,07.7,11.0\n" \
"" ""
# Test -f format filtering
for i in %f %e %g "boo %f yah" "% f" %-1.2f %+-f "%+ - f" %.2f %3.f "%'.2f" \
%%%f%%
do
- testing "seq filter -f \"$i\"" "seq -f \"$i\" 1 3 > /dev/null && echo yes" \
+ testing "filter -f \"$i\"" "seq -f \"$i\" 1 3 > /dev/null && echo yes" \
"yes\n" "" ""
done
# Test -f format filtering failures
for i in %d %s "" "boo %f %f yah" "%*f" %-1.2.3f '%2$f' %1-f "%1 f" \
%2..2f %%%f%%%
do
- testing "seq filter reject -f '$i'" \
+ testing "filter reject -f '$i'" \
"seq -f '$i' 1 3 2>/dev/null || echo no" "no\n" "" ""
done
--- /dev/null
+#!/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
--- /dev/null
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+shellit()
+{
+ EVAL="bash -c" testing "$2" "$1 printf %s $2" "$3" "$4" "$5"
+}
+
+# $'' expands special chars but doesn't do so inside double quotes.
+
+shellit "" "\$'a\\tb'" "a\tb" "" ""
+shellit "" "\"\$'a\\tb'\"" '$'"'"'a\\tb'"'" "" ""
+
+# $(( )) tests
+
+shellit 'x=1;' '$((-x))' '-1' '' ''
+shellit 'x=0;' '$((x++)); echo $x' '01\n' '' ''
+shellit 'x=0;' '$((++x))' '1' '' ''
+shellit 'x=0;' '$((~x))' '-1' '' ''
+shellit 'x=1;' '$((!x))' '0' '' ''
+shellit 'x=0;' '$((!x))' '1' '' ''
+shellit 'x=2;' '$((2*x))' '4' '' ''
+shellit 'x=9;' '$((x/4))' '2' '' ''
+shellit 'x=9;' '$((x%4))' '1' '' ''
+shellit 'x=4;' '$((x+2))' '6' '' ''
+shellit 'x=4;' '$((x-2))' '2' '' ''
+shellit 'x=4;' '$((1<<x))' '16' '' ''
+shellit 'x=4;' '$((x>>1))' '2' '' ''
+shellit '' '$((3**4))' '81' '' ''
+shellit '' '$((3<=4))' '1' '' ''
+shellit '' '$((3>=4))' '0' '' ''
+shellit '' '$((3<4))' '1' '' ''
+shellit '' '$((3>4))' '0' '' ''
+shellit '' '$((3==4))' '0' '' ''
+shellit '' '$((3!=4))' '1' '' ''
+shellit '' '$((6&4))' '4' '' ''
+shellit '' '$((4|2))' '6' '' ''
+shellit '' '$((6&&2))' '1' '' ''
+shellit '' '$((6||4))' '1' '' ''
+shellit '' '$((1?2:3))' '2' '' ''
+shellit 'x=2;' '$((x=3)); echo $x' '33\n' '' ''
+shellit 'x=2;' '$((x*=3)); echo $x' '66\n' '' ''
+shellit 'x=5;' '$((x/=2)); echo $x' '22\n' '' ''
+shellit 'x=9;' '$((x%=5)); echo $x' '44\n' '' ''
+shellit 'x=9;' '$((x-=3)); echo $x' '66\n' '' ''
+shellit 'x=3;' '$((x+=2)); echo $x' '55\n' '' ''
+shellit 'x=7;' '$((x&=13)); echo $x' '55\n' '' ''
+shellit 'x=5;' '$((x|=12)); echo $x' '1313\n' '' ''
+shellit 'x=5;' '$((x^=12)); echo $x' '99\n' '' ''
+shellit 'x=2;' '$((x<<=2)); echo $x' '88\n' '' ''
+shellit 'x=12;' '$((x>>=2)); echo $x' '33\n' '' ''
+shellit 'x=2;' '$((x++,5)); echo $x' '53\n' '' ''
# These tests are based on RFC3174 which were based on FIPS PUB 180-1
-testing "sha1sum TEST1" \
+testing "TEST1" \
"sha1sum" \
"a9993e364706816aba3e25717850c26c9cd0d89d -\n" \
"" "abc"
-testing "sha1sum TEST2" \
+testing "TEST2" \
"sha1sum" \
"84983e441c3bd26ebaae4aa1f95129e5e54670f1 -\n" \
"" "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
-testing "sha1sum TEST3" \
+testing "TEST3" \
'dd if=/dev/zero bs=1000 count=1000 2>/dev/null | tr \\0 a | sha1sum' \
"34aa973cd4c4daa4f61eeb2bdbad27316534016f -\n" \
"" ""
-testing "sha1sum TEST4" \
+testing "TEST4" \
'for i in `seq 1 10`; do echo -n 0123456701234567012345670123456701234567012345670123456701234567 ; done | sha1sum' \
"dea356a2cddd90c7a7ecedc5ebb563934f460452 -\n" \
"" ""
"a9993e364706816aba3e25717850c26c9cd0d89d -\n" \
"" "abc"
-testing "sha1sum -" \
+testing "-" \
"sha1sum -" \
"a9993e364706816aba3e25717850c26c9cd0d89d -\n" \
"" "abc"
-testing "sha1sum file" \
+testing "file" \
"sha1sum file1" \
"a9993e364706816aba3e25717850c26c9cd0d89d file1\n" \
"" ""
-testing "sha1sum file1 file2" \
+testing "file1 file2" \
"sha1sum file1 file2" \
"a9993e364706816aba3e25717850c26c9cd0d89d file1\n589c22335a381f122d129225f5c0ba3056ed5811 file2\n" \
"" ""
-testing "sha1sum file1 file2 -" \
+testing "file1 file2 -" \
"sha1sum file1 file2 -" \
"a9993e364706816aba3e25717850c26c9cd0d89d file1\n589c22335a381f122d129225f5c0ba3056ed5811 file2\na9993e364706816aba3e25717850c26c9cd0d89d -\n" \
"" "abc"
# The basic tests. These should work even with the small config.
testing "sort" "sort input" "a\nb\nc\n" "c\na\nb\n" ""
-testing "sort #2" "sort input" "010\n1\n3\n" "3\n1\n010\n" ""
-testing "sort stdin" "sort" "a\nb\nc\n" "" "b\na\nc\n"
-testing "sort numeric" "sort -n input" "1\n3\n010\n" "3\n1\n010\n" ""
-testing "sort reverse" "sort -r input" "wook\nwalrus\npoint\npabst\naargh\n" \
+testing "#2" "sort input" "010\n1\n3\n" "3\n1\n010\n" ""
+testing "stdin" "sort" "a\nb\nc\n" "" "b\na\nc\n"
+testing "numeric" "sort -n input" "1\n3\n010\n" "3\n1\n010\n" ""
+testing "reverse" "sort -r input" "wook\nwalrus\npoint\npabst\naargh\n" \
"point\nwook\npabst\naargh\nwalrus\n" ""
# These tests require the full option set.
# Sorting with keys
-testing "sort one key" "sort -k4,4 input" \
+testing "one key" "sort -k4,4 input" \
"999 3 0 algebra
egg 1 2 papyrus
7 3 42 soup
# at the whitespace), then the global fallback sort does an alpha sort on
# the whole string (starting at the beginning of the line).
-testing "sort key range with numeric option" "sort -k2,3n input" \
+testing "key range with numeric option" "sort -k2,3n input" \
"42 1 010 zoology
42 1 3 woot
egg 1 2 papyrus
# Numeric sort on field 2 (again, ignore field 3 because it's numeric),
# then do a _reversed_ alpha sort on the whole line as a tiebreaker.
-testing "sort key range with numeric option and global reverse" \
+testing "key range with numeric option and global reverse" \
"sort -k2,3n -r input" \
"egg 1 2 papyrus
42 1 3 woot
# Reversed numeric sort on field 2 (numeric ignores field 3), then
# break ties with alpha sort on whole line.
-testing "sort key range with multiple options" "sort -k2,3rn input" \
+testing "key range with multiple options" "sort -k2,3rn input" \
"7 3 42 soup
999 3 0 algebra
42 1 010 zoology
egg 1 2 papyrus
" "$data" ""
-testing "sort key doesn't strip leading blanks, disables fallback global sort" \
+testing "key doesn't strip leading blanks, disables fallback global sort" \
"sort -n -k2 -t ' '" " a \n 1 \n 2 \n" "" " 2 \n 1 \n a \n"
# Test case contributed by Joey Hess:
-testing "sort key edge case with -t" "sort -n -k4 -t/" \
+testing "key edge case with -t" "sort -n -k4 -t/" \
"/usr/lib/finish-install.d/1
/usr/lib/finish-install.d/4
/usr/lib/prebaseconfig.d/2
/usr/lib/prebaseconfig.d/6
"
-testing "sort -x" "sort -x" "010\na0\n 0c0\n" "" "a0\n010\n 0c0\n"
+testing "-x" "sort -x" "010\na0\n 0c0\n" "" "a0\n010\n 0c0\n"
# Test that -f applies to key or fallback independently
optional SORT_FLOAT
# not numbers < NaN < -infinity < numbers < +infinity
-testing "sort -g" "sort -g" \
+testing "-g" "sort -g" \
"bork\nNaN\n-inf\n0.4\n1.222\n01.37\n2.1\n+infinity\n" "" \
"01.37\n1.222\n2.1\n0.4\nNaN\nbork\n-inf\n+infinity\n"
testing "split" "seq 1 12345 | split && ls xa[a-z] | wc -l" "13\n" "" ""
rm xa[a-z]
-testing "split -" "seq 1 12345 | split - && ls xa[a-z] | wc -l" "13\n" "" ""
+testing "-" "seq 1 12345 | split - && ls xa[a-z] | wc -l" "13\n" "" ""
rm xa[a-z]
seq 1 12345 > file
-testing "split file" "split file && ls xa[a-z] | wc -l" "13\n" "" ""
+testing "file" "split file && ls xa[a-z] | wc -l" "13\n" "" ""
rm xa[a-z]
-testing "split -l" "split file -l 10k && wc -l xab" "2105 xab\n" "" ""
+testing "-l" "split file -l 10k && wc -l xab" "2105 xab\n" "" ""
rm xa[ab]
-testing "split suffix exhaustion" \
+testing "suffix exhaustion" \
"split file -l 10 -a 1 walrus 2>/dev/null || ls walrus* | wc -l" "26\n" "" ""
rm walrus*
-testing "split bytes" \
+testing "bytes" \
"toybox seq 1 20000 | split -b 100 -a 3 - whang && ls whang* | wc -l && wc -c whangbpw" "1089\n94 whangbpw\n" "" ""
-testing "split reassembly" \
+testing "reassembly" \
'diff -u <(ls whang* | sort | xargs cat) <(seq 1 20000) && echo yes' \
"yes\n" "" ""
echo -e "one-A\none-B" > file1
echo -e "two-A\ntwo-B" > file2
testing "tac" "tac && echo yes" "one-B\none-A\nyes\n" "" "one-A\none-B\n"
-testing "tac -" "tac - && echo yes" "one-B\none-A\nyes\n" "" "one-A\none-B\n"
-testing "tac file1 file2" "tac file1 file2" "one-B\none-A\ntwo-B\ntwo-A\n" "" ""
-testing "tac - file" "tac - file1" "zero-B\nzero-A\none-B\none-A\n" "" "zero-A\nzero-B\n"
-testing "tac file -" "tac file1 -" "one-B\none-A\nzero-B\nzero-A\n" "" "zero-A\nzero-B\n"
+testing "-" "tac - && echo yes" "one-B\none-A\nyes\n" "" "one-A\none-B\n"
+testing "file1 file2" "tac file1 file2" "one-B\none-A\ntwo-B\ntwo-A\n" "" ""
+testing "- file" "tac - file1" "zero-B\nzero-A\none-B\none-A\n" "" "zero-A\nzero-B\n"
+testing "file -" "tac file1 -" "one-B\none-A\nzero-B\nzero-A\n" "" "zero-A\nzero-B\n"
-testing "tac file1 notfound file2" \
+testing "file1 notfound file2" \
"tac file1 notfound file2 2>stderr && echo ok ; tac stderr; rm stderr" \
"one-B\none-A\ntwo-B\ntwo-A\ntac: notfound: No such file or directory\n" "" ""
-testing "tac no trailing newline" "tac -" "defabc\n" "" "abc\ndef"
+testing "no trailing newline" "tac -" "defabc\n" "" "abc\ndef"
# xputs used by tac does not propagate this error condition properly.
-#testing "tac > /dev/full" \
+#testing "> /dev/full" \
# "tac - > /dev/full 2>stderr && echo ok; cat stderr; rm stderr" \
# "tac: write: No space left on device\n" "" "zero\n"
BIGTEST="one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\neleven\n"
echo -ne "$BIGTEST" > file1
testing "tail" "tail && echo yes" "oneyes\n" "" "one"
-testing "tail file" "tail file1" \
+testing "file" "tail file1" \
"two\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\neleven\n" "" ""
-testing "tail -n in bounds" "tail -n 3 file1" "nine\nten\neleven\n" "" ""
-testing "tail -n out of bounds" "tail -n 999 file1" "$BIGTEST" "" ""
-testing "tail -n+ in bounds" "tail -n +3 file1" \
+testing "-n in bounds" "tail -n 3 file1" "nine\nten\neleven\n" "" ""
+testing "-n out of bounds" "tail -n 999 file1" "$BIGTEST" "" ""
+testing "-n+ in bounds" "tail -n +3 file1" \
"three\nfour\nfive\nsix\nseven\neight\nnine\nten\neleven\n" "" ""
-testing "tail -n+ outof bounds" "tail -n +999 file1" "" "" ""
-testing "tail -c in bounds" "tail -c 27 file1" \
+testing "-n+ outof bounds" "tail -n +999 file1" "" "" ""
+testing "-c in bounds" "tail -c 27 file1" \
"even\neight\nnine\nten\neleven\n" "" ""
-testing "tail -c out of bounds" "tail -c 999 file1" "$BIGTEST" "" ""
-testing "tail -c+ in bounds" "tail -c +27 file1" \
+testing "-c out of bounds" "tail -c 999 file1" "$BIGTEST" "" ""
+testing "-c+ in bounds" "tail -c +27 file1" \
"x\nseven\neight\nnine\nten\neleven\n" "" ""
-testing "tail -c+ out of bonds" "tail -c +999 file1" "" "" ""
+testing "-c+ out of bonds" "tail -c +999 file1" "" "" ""
+testing "-N" "tail -1 file1" "eleven\n" "" ""
rm file1
-testing "tail stdin no trailing newline" "tail -n 1 - " "c" "" "a\nb\nc"
-testing "tail file no trailing newline" "tail -n 1 input" "c" "a\nb\nc" ""
+testing "stdin no trailing newline" "tail -n 1 - " "c" "" "a\nb\nc"
+testing "file no trailing newline" "tail -n 1 input" "c" "a\nb\nc" ""
optional TAIL_SEEK
-testing "tail noseek -n in bounds" "tail -n 3" "nine\nten\neleven\n" \
+testing "noseek -n in bounds" "tail -n 3" "nine\nten\neleven\n" \
"" "$BIGTEST"
-testing "tail noseek -n out of bounds" "tail -n 999" "$BIGTEST" "" "$BIGTEST"
-testing "tail noseek -n+ in bounds" "tail -n +3" \
+testing "noseek -n out of bounds" "tail -n 999" "$BIGTEST" "" "$BIGTEST"
+testing "noseek -n+ in bounds" "tail -n +3" \
"three\nfour\nfive\nsix\nseven\neight\nnine\nten\neleven\n" "" \
"$BIGTEST"
-testing "tail noseek -n+ outof bounds" "tail -n +999" "" "" "$BIGTEST"
-testing "tail noseek -c in bounds" "tail -c 27" \
+testing "noseek -n+ outof bounds" "tail -n +999" "" "" "$BIGTEST"
+testing "noseek -c in bounds" "tail -c 27" \
"even\neight\nnine\nten\neleven\n" "" "$BIGTEST"
-testing "tail noseek -c out of bounds" "tail -c 999" "$BIGTEST" "" "$BIGTEST"
-testing "tail noseek -c+ in bounds" "tail -c +27" \
+testing "noseek -c out of bounds" "tail -c 999" "$BIGTEST" "" "$BIGTEST"
+testing "noseek -c+ in bounds" "tail -c +27" \
"x\nseven\neight\nnine\nten\neleven\n" "" "$BIGTEST"
-testing "tail noseek -c+ out of bonds" "tail -c +999" "" "" "$BIGTEST"
+testing "noseek -c+ out of bonds" "tail -c +999" "" "" "$BIGTEST"
makebigfile()
{
}
makebigfile > bigfile
-testing "tail -c 12345 -n 3 bigfile" "tail -c 12345 -n 3 bigfile | md5sum" \
+testing "-c 12345 -n 3 bigfile" "tail -c 12345 -n 3 bigfile | md5sum" \
"347bbdcbad8a313f4dc7bd558c5bfcb8 -\n" "" ""
-testing "tail -n 3 -c 12345 bigfile" "tail -n 3 -c 12345 bigfile | md5sum" \
+testing "-n 3 -c 12345 bigfile" "tail -n 3 -c 12345 bigfile | md5sum" \
"1698825a750288284ec3ba7d8a59f302 -\n" "" ""
+rm bigfile
+
+echo 111 > one
+testing "-f one" \
+ 'tail -f one & sleep .25 ; echo two >> one; sleep .25; echo three >> one; sleep .25; kill $! >/dev/null' \
+ "111\ntwo\nthree\n" "" ""
+rm one
+
+echo uno > one
+echo dos > two
+echo tres > three
+testing "-f one two three" \
+ 'tail -f one two three & sleep .25 ; echo more >> three ; echo also >> one; sleep .25; kill $! >/dev/null' \
+ "==> one <==\nuno\n\n==> two <==\ndos\n\n==> three <==\ntres\nmore\n\n==> one <==\nalso\n" "" ""
+rm one two three
#Creating dir
mkdir dir/dir1 -p
echo "This is testdata" > dir/dir1/file
-testing "tar tgz - compession, extraction and data validation" "tar -czf dir.tgz dir/ && [ -e dir.tgz ] && echo 'yes'; rm -rf dir; tar -xf dir.tgz && [ -f dir/dir1/file ] && cat dir/dir1/file; rm -rf dir.tgz" "yes\nThis is testdata\n" "" ""
+testing "tgz - compession, extraction and data validation" "tar -czf dir.tgz dir/ && [ -e dir.tgz ] && echo 'yes'; rm -rf dir; tar -xf dir.tgz && [ -f dir/dir1/file ] && cat dir/dir1/file; rm -rf dir.tgz" "yes\nThis is testdata\n" "" ""
#Creating dir
mkdir dir/dir1 -p
echo "This is testdata" > dir/dir1/file
-testing "tar tar.gz - compession, extraction and data validation" "tar -czf dir.tar.gz dir/ && [ -e dir.tar.gz ] && echo 'yes'; rm -rf dir; tar -xf dir.tar.gz && [ -f dir/dir1/file ] && cat dir/dir1/file; rm -rf dir.tar.gz" "yes\nThis is testdata\n" "" ""
+testing "tar.gz - compession, extraction and data validation" "tar -czf dir.tar.gz dir/ && [ -e dir.tar.gz ] && echo 'yes'; rm -rf dir; tar -xf dir.tar.gz && [ -f dir/dir1/file ] && cat dir/dir1/file; rm -rf dir.tar.gz" "yes\nThis is testdata\n" "" ""
#Creating dir
mkdir dir/dir1 -p
echo "This is testdata" > dir/dir1/file
-testing "tar verbose compression" "tar -cvzf dir.tgz dir/; rm -rf dir.tgz" "dir/\ndir/dir1/\ndir/dir1/file\n" "" ""
+testing "verbose compression" "tar -cvzf dir.tgz dir/; rm -rf dir.tgz" "dir/\ndir/dir1/\ndir/dir1/file\n" "" ""
rm -rf dir/
#creating test file
dd if=/dev/zero of=testFile ibs=4096 obs=4096 count=1000 2>/dev/null
-testing "tar - compession and extraction of a file" "tar -czf testFile.tgz testFile && [ -e testFile.tgz ] && echo 'yes'; rm -rf testFile; tar -xf testFile.tgz && [ -f testFile ] && echo 'yes'; rm -rf testFile.tgz" "yes\nyes\n" "" ""
+testing "- compession and extraction of a file" "tar -czf testFile.tgz testFile && [ -e testFile.tgz ] && echo 'yes'; rm -rf testFile; tar -xf testFile.tgz && [ -f testFile ] && echo 'yes'; rm -rf testFile.tgz" "yes\nyes\n" "" ""
#creating empty test file
touch testFile
-testing "tar - compession and extraction of a empty file" "tar -czf testFile.tgz testFile && [ -e testFile.tgz ] && echo 'yes'; rm -rf testFile; tar -xf testFile.tgz && [ -f testFile ] && echo 'yes'; rm -rf testFile.tgz" "yes\nyes\n" "" ""
+testing "- compession and extraction of a empty file" "tar -czf testFile.tgz testFile && [ -e testFile.tgz ] && echo 'yes'; rm -rf testFile; tar -xf testFile.tgz && [ -f testFile ] && echo 'yes'; rm -rf testFile.tgz" "yes\nyes\n" "" ""
#Creating dir
mkdir dir/dir1 -p
touch dir/dir1/file1 dir/dir1/file2 dir/dir1/file3 dir/dir1/file4
-testing "tar -t option" "tar -czf dir.tar.gz dir/; rm -rf dir; tar -tf dir.tar.gz | sort; rm -rf dir.tar.gz" "dir/\ndir/dir1/\ndir/dir1/file1\ndir/dir1/file2\ndir/dir1/file3\ndir/dir1/file4\n" "" ""
+testing "-t option" "tar -czf dir.tar.gz dir/; rm -rf dir; tar -tf dir.tar.gz | sort; rm -rf dir.tar.gz" "dir/\ndir/dir1/\ndir/dir1/file1\ndir/dir1/file2\ndir/dir1/file3\ndir/dir1/file4\n" "" ""
rm -rf dir/
#Creating nested directory
echo "This is testdata" > dir/dir1/file; echo "Dont exclude me" > dir/dir3/file1 ;
echo "Exclude me" > dir/dir3/file2 ; echo "YO" > dir/dir4/file1 ; echo "Hello" >dir/dir4/file2; echo "Dont" > dir/dir2/file1
echo -ne "dir/dir4\ndir/dir3/file2\n" > exclude_file
-testing "Creating tar with files excluded : -X" "tar -czf dir.tgz dir/ -X exclude_file ; rm -rf dir ; tar -tf dir.tgz | sort; rm -rf dir.tgz " "dir/\ndir/dir1/\ndir/dir1/file\ndir/dir2/\ndir/dir2/file1\ndir/dir3/\ndir/dir3/file1\n" "" ""
+testing "create with files excluded : -X" "tar -czf dir.tgz dir/ -X exclude_file ; rm -rf dir ; tar -tf dir.tgz | sort; rm -rf dir.tgz " "dir/\ndir/dir1/\ndir/dir1/file\ndir/dir2/\ndir/dir2/file1\ndir/dir3/\ndir/dir3/file1\n" "" ""
rm -rf exclude_file
#Creating nested directory
mkdir dir/dir1 -p ; mkdir dir/dir2 ; mkdir dir/dir3 ; mkdir dir/dir4
echo "This is testdata" > dir/dir1/file
echo "Dont exclude me" > dir/dir3/file1 ; echo "Exclude me" > dir/dir3/file2 ; echo "YO" > dir/dir4/file1 ; echo "Hello" >dir/dir4/file2; echo "Dont" > dir/dir2/file1
-testing "tar with pattern --exclude" "tar --exclude=dir/dir3/* -czf dir.tgz dir/ ; rm -rf dir ; tar -tf dir.tgz | sort; rm -rf dir.tgz " "dir/\ndir/dir1/\ndir/dir1/file\ndir/dir2/\ndir/dir2/file1\ndir/dir3/\ndir/dir4/\ndir/dir4/file1\ndir/dir4/file2\n" "" ""
+testing "with pattern --exclude" "tar --exclude=dir/dir3/* -czf dir.tgz dir/ ; rm -rf dir ; tar -tf dir.tgz | sort; rm -rf dir.tgz " "dir/\ndir/dir1/\ndir/dir1/file\ndir/dir2/\ndir/dir2/file1\ndir/dir3/\ndir/dir4/\ndir/dir4/file1\ndir/dir4/file2\n" "" ""
#Creating directory to be compressed
mkdir dir/dir1 -p
echo "This is testdata" > dir/dir1/file
mkdir temp
-testing "Extraction with -C Dir" "tar -czf dir.tgz dir/ ;rm -rf dir ;tar -xf dir.tgz -C temp/ ; [ -e temp/dir ] && echo 'yes' ; rm -rf dir dir.tgz" "yes\n" "" ""
+testing "extract with -C Dir" "tar -czf dir.tgz dir/ ;rm -rf dir ;tar -xf dir.tgz -C temp/ ; [ -e temp/dir ] && echo 'yes' ; rm -rf dir dir.tgz" "yes\n" "" ""
rm -rf temp
#Creating nested directory
echo "dir1/file" > dir/dir1/file ; echo "temp_dir/file" > temp_dir/file
echo "dir3/file1" > dir/dir3/file1 ; echo "dir3/file2" > dir/dir3/file2 ; echo "YO" > dir/dir4/file1 ; echo "Hello" >dir/dir4/file2; echo "dir2/file1" > dir/dir2/file1
echo "temp_dir/file" > exclude_file
-testing "Creating tar extra files/directory included : -T" "tar -czf dir.tgz dir/ -T exclude_file ; rm -rf dir ; tar -tf dir.tgz | sort; rm -rf dir.tgz " "dir/\ndir/dir1/\ndir/dir1/file\ndir/dir2/\ndir/dir2/file1\ndir/dir3/\ndir/dir3/file1\ndir/dir3/file2\ndir/dir4/\ndir/dir4/file1\ndir/dir4/file2\ntemp_dir/file\n" "" ""
+testing "create with extra files/directory included : -T" "tar -czf dir.tgz dir/ -T exclude_file ; rm -rf dir ; tar -tf dir.tgz | sort; rm -rf dir.tgz " "dir/\ndir/dir1/\ndir/dir1/file\ndir/dir2/\ndir/dir2/file1\ndir/dir3/\ndir/dir3/file1\ndir/dir3/file2\ndir/dir4/\ndir/dir4/file1\ndir/dir4/file2\ntemp_dir/file\n" "" ""
rm -rf exclude_file
rm -rf temp_dir
#Creating dir
mkdir dir/dir1 -p
echo "Inside dir/dir1" > dir/dir1/file ; echo "Hello Inside dir" > dir/file
-testing "Extraction on STDOUT : -O" " tar -czf dir.tgz dir/ ; rm -rf dir ; tar -xf dir.tgz -O ; [ -e 'Inside dir/dir1/\nHello Inside dir\n' ] && echo 'yes'; rm -rf dir.tgz " "" "" ""
+testing "extract to STDOUT : -O" " tar -czf dir.tgz dir/ ; rm -rf dir ; tar -xf dir.tgz -O ; [ -e 'Inside dir/dir1/\nHello Inside dir\n' ] && echo 'yes'; rm -rf dir.tgz " "" "" ""
#Creating short filename
f="filename_with_100_chars_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
echo "This is testdata" > $f
-testing "tar shortname filename" "tar -cf testFile.tar $f && [ -e testFile.tar ] && echo 'yes'; rm -f $f; tar -xf testFile.tar && [ -f $f ] && cat $f && strings testFile.tar | grep -o LongLink; rm -f testFile.tar; rm -f $f" "yes\nThis is testdata\n" "" ""
+testing "shortname filename" "tar -cf testFile.tar $f && [ -e testFile.tar ] && echo 'yes'; rm -f $f; tar -xf testFile.tar && [ -f $f ] && cat $f && strings testFile.tar | grep -o LongLink; rm -f testFile.tar; rm -f $f" "yes\nThis is testdata\n" "" ""
#Creating long filename
f="filename_with_101_chars_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
echo "This is testdata" > $f
-testing "tar longname filename" "tar -cf testFile.tar $f && [ -e testFile.tar ] && echo 'yes'; rm -f $f; tar -xf testFile.tar && [ -f $f ] && cat $f && strings testFile.tar | grep -o LongLink; rm -f testFile.tar; rm -f $f" "yes\nThis is testdata\nLongLink\n" "" ""
+testing "longname filename" "tar -cf testFile.tar $f && [ -e testFile.tar ] && echo 'yes'; rm -f $f; tar -xf testFile.tar && [ -f $f ] && cat $f && strings testFile.tar | grep -o LongLink; rm -f testFile.tar; rm -f $f" "yes\nThis is testdata\nLongLink\n" "" ""
#Creating long pathname
d="dirname_with_50_chars_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
f="filename_with_50_chars_xxxxxxxxxxxxxxxxxxxxxxxxxxx"
mkdir $d
echo "This is testdata" > $d/$f
-testing "tar longname pathname" "tar -cf testFile.tar $d/$f && [ -e testFile.tar ] && echo 'yes'; rm -rf $d; tar -xf testFile.tar && [ -f $d/$f ] && cat $d/$f && strings testFile.tar | grep -o LongLink; rm -f testFile.tar; rm -rf $d" "yes\nThis is testdata\nLongLink\n" "" ""
+testing "longname pathname" "tar -cf testFile.tar $d/$f && [ -e testFile.tar ] && echo 'yes'; rm -rf $d; tar -xf testFile.tar && [ -f $d/$f ] && cat $d/$f && strings testFile.tar | grep -o LongLink; rm -f testFile.tar; rm -rf $d" "yes\nThis is testdata\nLongLink\n" "" ""
printf "%s" $result
}
-testing "test -b" "type_test -b" "" "" ""
-testing "test -c" "type_test -c" "L" "" ""
-testing "test -d" "type_test -d" "d" "" ""
-testing "test -f" "type_test -f" "fs" "" ""
-testing "test -h" "type_test -h" "L" "" ""
-testing "test -L" "type_test -L" "L" "" ""
-testing "test -s" "type_test -s" "ds" "" ""
-testing "test -S" "type_test -S" "" "" ""
-testing "test -p" "type_test -p" "p" "" ""
-testing "test -e" "type_test -e" "dfLsp" "" ""
-testing "test ! -e" "type_test ! -e" "n" "" ""
+testing "-b" "type_test -b" "" "" ""
+testing "-c" "type_test -c" "L" "" ""
+testing "-d" "type_test -d" "d" "" ""
+testing "-f" "type_test -f" "fs" "" ""
+testing "-h" "type_test -h" "L" "" ""
+testing "-L" "type_test -L" "L" "" ""
+testing "-s" "type_test -s" "ds" "" ""
+testing "-S" "type_test -S" "" "" ""
+testing "-p" "type_test -p" "p" "" ""
+testing "-e" "type_test -e" "dfLsp" "" ""
+testing "! -e" "type_test ! -e" "n" "" ""
rm f L s p
rmdir d
# TODO: Test rwx gu t
testing "test" "test "" || test a && echo yes" "yes\n" "" ""
-testing "test -n" "test -n "" || test -n a && echo yes" "yes\n" "" ""
-testing "test -z" "test -n a || test -n "" && echo yes" "yes\n" "" ""
-testing "test a = b" "test a = b || test "" = "" && echo yes" "yes\n" "" ""
-testing "test a != b" "test "" != "" || test a = b && echo yes" "yes\n" "" ""
+testing "-n" "test -n "" || test -n a && echo yes" "yes\n" "" ""
+testing "-z" "test -n a || test -n "" && echo yes" "yes\n" "" ""
+testing "a = b" "test a = b || test "" = "" && echo yes" "yes\n" "" ""
+testing "a != b" "test "" != "" || test a = b && echo yes" "yes\n" "" ""
arith_test()
{
test -3 $1 -5 && echo g
}
-testing "test -eq" "arith_test -eq" "e\n" "" ""
-testing "test -ne" "arith_test -ne" "l\ng\n" "" ""
-testing "test -gt" "arith_test -gt" "g\n" "" ""
-testing "test -ge" "arith_test -ge" "e\ng\n" "" ""
-testing "test -lt" "arith_test -lt" "l\n" "" ""
-testing "test -le" "arith_test -le" "l\ne\n" "" ""
+testing "-eq" "arith_test -eq" "e\n" "" ""
+testing "-ne" "arith_test -ne" "l\ng\n" "" ""
+testing "-gt" "arith_test -gt" "g\n" "" ""
+testing "-ge" "arith_test -ge" "e\ng\n" "" ""
+testing "-lt" "arith_test -lt" "l\n" "" ""
+testing "-le" "arith_test -le" "l\ne\n" "" ""
# test ! = -o a
# test ! \( = -o a \)
#testing "name" "command" "result" "infile" "stdin"
-testing "human_readable l 1024" "test_human_readable 123456789" "118M\n" "" ""
-testing "human_readable l 1000" "test_human_readable -i 123456789" "123M\n" "" ""
-testing "human_readable s 1024" "test_human_readable 5675" "5.5K\n" "" ""
-testing "human_readable s 1000" "test_human_readable -i 5675" "5.6k\n" "" ""
+testing "l 1024" "test_human_readable 123456789" "118M\n" "" ""
+testing "l 1000" "test_human_readable -i 123456789" "123M\n" "" ""
+testing "s 1024" "test_human_readable 5675" "5.5K\n" "" ""
+testing "s 1000" "test_human_readable -i 5675" "5.6k\n" "" ""
# An example input where we give a better result than coreutils.
# 267350/1024=261.08. We say 261K and coreutils says 262K.
-testing "human_readable" "test_human_readable 267350" "261K\n" "" ""
+testing "test_human_readable" "test_human_readable 267350" "261K\n" "" ""
-testing "human_readable -b" "test_human_readable -b 123" "123B\n" "" ""
-testing "human_readable -b" "test_human_readable -b 123456789" "118M\n" "" ""
-testing "human_readable -s" "test_human_readable -s 123456789" "118 M\n" "" ""
-testing "human_readable -bs" "test_human_readable -bs 123456789" "118 M\n" "" ""
+testing "-b" "test_human_readable -b 123" "123B\n" "" ""
+testing "-b" "test_human_readable -b 123456789" "118M\n" "" ""
+testing "-s" "test_human_readable -s 123456789" "118 M\n" "" ""
+testing "-bs" "test_human_readable -bs 123456789" "118 M\n" "" ""
--- /dev/null
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "batch termination" "top -b -n1 | tail -c 1" "\n" "" ""
#testing "name" "command" "result" "infile" "stdin"
testing "touch" "touch walrus && [ -e walrus ] && echo yes" "yes\n" "" ""
-testing "touch 1 2 3" "touch one two three && rm one two three && echo yes" "yes\n" \
+testing "1 2 3" "touch one two three && rm one two three && echo yes" "yes\n" \
"" ""
-testing "touch -c" "touch -c walrus && [ -e walrus ] && echo yes" "yes\n" "" ""
-testing "touch -c missing" "touch -c warrus && [ ! -e warrus ] && echo yes" \
+testing "-c" "touch -c walrus && [ -e walrus ] && echo yes" "yes\n" "" ""
+testing "-c missing" "touch -c warrus && [ ! -e warrus ] && echo yes" \
"yes\n" "" ""
-testing "touch -d" \
+testing "-t" \
+ "touch -t 201201231234 walrus && date -r walrus +%Y%m%d-%H%M%S.%N" \
+ "20120123-123400.000000000\n" "" ""
+
+testing "-t seconds" \
+ "touch -t 201201231234.56 walrus && date -r walrus +%Y%m%d-%H%M%S.%N" \
+ "20120123-123456.000000000\n" "" ""
+
+testing "-t nanoseconds" \
+ "touch -t 201201231234.56123456789 walrus && date -r walrus +%Y%m%d-%H%M%S.%N" \
+ "20120123-123456.123456789\n" "" ""
+
+testing "-d" \
"touch -d 2009-02-13T23:31:30Z walrus && date -r walrus +%s" \
"1234567890\n" "" ""
-testing "touch -d nanoseconds" \
+testing "-d nanoseconds" \
"touch -d 2009-02-13T23:31:30.123456789Z walrus && date -r walrus +%s.%N" \
"1234567890.123456789\n" "" ""
-testing "touch -r" \
+testing "-r" \
"touch -r walrus walrus2 && date -r walrus2 +%s.%N" \
"1234567890.123456789\n" "" ""
-#testing "touch -a"
-#testing "touch -m"
-#testing "touch -am"
-#testing "touch -t"
+#testing "-a"
+#testing "-m"
+#testing "-am"
+#testing "-t"
rm walrus walrus2
#testing "name" "command" "result" "infile" "stdin"
SIZE='&& stat -c %s freep'
-testing "truncate 0" "truncate -s 0 freep $SIZE" "0\n" "" ""
-testing "truncate 12345" "truncate -s 12345 freep $SIZE" "12345\n" "" ""
-testing "truncate 1m" "truncate -s 1m freep $SIZE" "1048576\n" "" ""
-testing "truncate is sparse" "truncate -s 1g freep && stat -c %b freep" \
+testing "0" "truncate -s 0 freep $SIZE" "0\n" "" ""
+testing "12345" "truncate -s 12345 freep $SIZE" "12345\n" "" ""
+testing "1m" "truncate -s 1m freep $SIZE" "1048576\n" "" ""
+testing "is sparse" "truncate -s 1g freep && stat -c %b freep" \
"0\n" "" ""
-testing "truncate +" "truncate -s 1k freep && truncate -s +1k freep $SIZE" \
+testing "+" "truncate -s 1k freep && truncate -s +1k freep $SIZE" \
"2048\n" "" ""
-testing "truncate -" "truncate -s 4k freep && truncate -s -1k freep $SIZE" \
+testing "-" "truncate -s 4k freep && truncate -s -1k freep $SIZE" \
"3072\n" "" ""
-testing "truncate < hit" \
+testing "< hit" \
"truncate -s 5k freep && truncate -s \<4k freep $SIZE" "4096\n" "" ""
-testing "truncate < miss" \
+testing "< miss" \
"truncate -s 4k freep && truncate -s \<6k freep $SIZE" "4096\n" "" ""
-testing "truncate > hit" \
+testing "> hit" \
"truncate -s 3k freep && truncate -s \>4k freep $SIZE" "4096\n" "" ""
-testing "truncate > miss" \
+testing "> miss" \
"truncate -s 4k freep && truncate -s \>2k freep $SIZE" "4096\n" "" ""
-testing "truncate /" "truncate -s 7k freep && truncate -s /3k freep $SIZE" \
+testing "/" "truncate -s 7k freep && truncate -s /3k freep $SIZE" \
"6144\n" "" ""
-testing "truncate %" "truncate -s 7k freep && truncate -s %3k freep $SIZE" \
+testing "%" "truncate -s 7k freep && truncate -s %3k freep $SIZE" \
"9216\n" "" ""
pass=`echo -ne 'password\npassword\n'`
user="toyTestUser"
-testing "adduser user_name (text)" "useradd $user $arg ||
+testing "(text)" "useradd $user $arg ||
grep '^$user:' /etc/passwd $arg && [ -d /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
user="toy1Test2User3"
-testing "adduser user_name (alphanumeric)" "useradd $user $arg ||
+testing "(alphanumeric)" "useradd $user $arg ||
grep '^$user:' /etc/passwd $arg && [ -d /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
user="987654321"
-testing "adduser user_name (numeric)" "useradd $user $arg ||
+testing "(numeric)" "useradd $user $arg ||
grep '^$user:' /etc/passwd $arg && [ -d /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
user="toy.1Test-2User_3"
-testing "adduser user_name (with ./-/_)" "useradd $user $arg ||
+testing "(with ./-/_)" "useradd $user $arg ||
grep '^$user:' /etc/passwd $arg && [ -d /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
# 70 characters long string; hereafter, we will use it as per our need.
user="abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz123456789"
-testing "adduser user_name (long string)" "useradd $user $arg ||
+testing "(long string)" "useradd $user $arg ||
grep '^$user:' /etc/passwd $arg && [ -d /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
user="toyTestUser"
-testing "adduser user_name with dir" "useradd -h $PWD/dir $user $arg ||
+testing "dir" "useradd -h $PWD/dir $user $arg ||
grep '^$user:.*dir' /etc/passwd $arg && [ -d $PWD/dir ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
rm -rf $PWD/dir
gecos="aaa,bbb,ccc,ddd,eee"
-testing "adduser user_name with gecos" "useradd -g '$gecos' $user $arg ||
+testing "gecos" "useradd -g '$gecos' $user $arg ||
grep '^$user:.*$gecos' /etc/passwd $arg && [ -d /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
shl="/bin/sh"
-testing "adduser user_name with shell" "useradd -s $shl $user $arg ||
+testing "shell" "useradd -s $shl $user $arg ||
grep '^$user:.*$shl$' /etc/passwd $arg && [ -d /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
g_name="root"
g_id=`grep $g_name':.*:.*' /etc/group | cut -d : -f 3`
-testing "adduser user_name with group" "useradd -G $g_name $user $arg ||
+testing "group" "useradd -G $g_name $user $arg ||
grep '^$user:.*:.*:$g_id:.*' /etc/passwd $arg && [ -d /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
-testing "adduser user_name (system user)" "useradd -S $user $arg ||
+testing "(system user)" "useradd -S $user $arg ||
grep '^$user:.*:.*:.*' /etc/passwd $arg && [ ! -e /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
-testing "adduser user_name with -D" "useradd -D $user $arg ||
+testing "-D" "useradd -D $user $arg ||
grep '^$user:.*:.*:.*' /etc/passwd $arg && [ -d /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
-testing "adduser user_name with -H" "useradd -H $user $arg ||
+testing "-H" "useradd -H $user $arg ||
grep '^$user:.*:.*:.*' /etc/passwd $arg && [ ! -e /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
-testing "adduser user_name with dir and -H" "useradd -H -h $PWD/dir $user $arg ||
+testing "dir and -H" "useradd -H -h $PWD/dir $user $arg ||
grep '^$user:.*dir' /etc/passwd $arg && [ ! -e $PWD/dir ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
-testing "adduser user_name with user_id" "useradd -u 49999 $user $arg ||
+testing "-u" "useradd -u 49999 $user $arg ||
grep '^$user:x:49999:.*' /etc/passwd $arg && [ -d /home/$user ] &&
echo 'yes'" "yes\n" "" "$pass"
userdel -r $user $arg
#testing "name" "command" "result" "infile" "stdin"
-testing "uudecode uu empty file" "uudecode -o /dev/stdout && echo yes" \
+testing "uu empty file" "uudecode -o /dev/stdout && echo yes" \
"yes\n" "" "begin 744 test\n\`\nend\n"
-testing "uudecode uu 1-char" "uudecode -o /dev/stdout" "a" "" \
+testing "uu 1-char" "uudecode -o /dev/stdout" "a" "" \
"begin 744 test\n!80 \n\`\nend\n"
-testing "uudecode uu 2-char" "uudecode -o /dev/stdout" "ab" "" \
+testing "uu 2-char" "uudecode -o /dev/stdout" "ab" "" \
"begin 744 test\n\"86( \n\`\nend\n"
-testing "uudecode uu 3-char" "uudecode -o /dev/stdout" "abc" "" \
+testing "uu 3-char" "uudecode -o /dev/stdout" "abc" "" \
"begin 744 test\n#86)C\n\`\nend\n"
-testing "uudecode b64 empty file" "uudecode -o /dev/stdout && echo yes" \
+testing "b64 empty file" "uudecode -o /dev/stdout && echo yes" \
"yes\n" "" "begin-base64 744 test\n====\n"
-testing "uudecode b64 1-char" "uudecode -o /dev/stdout" "a" "" \
+testing "b64 1-char" "uudecode -o /dev/stdout" "a" "" \
"begin-base64 744 test\nYQ==\n====\n"
-testing "uudecode b64 2-char" "uudecode -o /dev/stdout" "ab" "" \
+testing "b64 2-char" "uudecode -o /dev/stdout" "ab" "" \
"begin-base64 744 test\nYWI=\n====\n"
-testing "uudecode b64 3-char" "uudecode -o /dev/stdout" "abc" "" \
+testing "b64 3-char" "uudecode -o /dev/stdout" "abc" "" \
"begin-base64 744 test\nYWJj\n====\n"
-testing "uudecode filename" "uudecode && echo -ne 'abc' | cmp uudecode-fn-test /dev/stdin && echo -ne yes && rm uudecode-fn-test" \
+testing "filename" "uudecode && echo -ne 'abc' | cmp uudecode-fn-test /dev/stdin && echo -ne yes && rm uudecode-fn-test" \
"yes" "" "begin-base64 744 uudecode-fn-test\nYWJj\n====\n"
#testing "name" "command" "result" "infile" "stdin"
-testing "uuencode not enough args [fail]" "uuencode 2>/dev/null" "" "" ""
+testing "not enough args [fail]" "uuencode 2>/dev/null" "" "" ""
-testing "uuencode uu empty file" "uuencode test" \
+testing "uu empty file" "uuencode test" \
"begin 744 test\nend\n" "" ""
-testing "uuencode uu 1-char" "uuencode test" \
+testing "uu 1-char" "uuencode test" \
"begin 744 test\n!80\`\`\nend\n" "" "a"
-testing "uuencode uu 2-char" "uuencode test" \
+testing "uu 2-char" "uuencode test" \
"begin 744 test\n\"86(\`\nend\n" "" "ab"
-testing "uuencode uu 3-char" "uuencode test" \
+testing "uu 3-char" "uuencode test" \
"begin 744 test\n#86)C\nend\n" "" "abc"
-testing "uuencode b64 empty file" "uuencode -m test" \
+testing "b64 empty file" "uuencode -m test" \
"begin-base64 744 test\n====\n" "" ""
-testing "uuencode b64 1-char" "uuencode -m test" \
+testing "b64 1-char" "uuencode -m test" \
"begin-base64 744 test\nYQ==\n====\n" "" "a"
-testing "uuencode b64 2-char" "uuencode -m test" \
+testing "b64 2-char" "uuencode -m test" \
"begin-base64 744 test\nYWI=\n====\n" "" "ab"
-testing "uuencode b64 3-char" "uuencode -m test" \
+testing "b64 3-char" "uuencode -m test" \
"begin-base64 744 test\nYWJj\n====\n" "" "abc"
EOF
testing "wc" "wc >/dev/null && echo yes" "yes\n" "" ""
-testing "wc empty file" "wc" "0 0 0\n" "" ""
-testing "wc standard input" "wc" "1 3 5\n" "" "a b\nc"
-testing "wc -c" "wc -c file1" "26 file1\n" "" ""
-testing "wc -l" "wc -l file1" "4 file1\n" "" ""
-testing "wc -w" "wc -w file1" "5 file1\n" "" ""
-testing "wc format" "wc file1" "4 5 26 file1\n" "" ""
-testing "wc 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
+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" "" ""
+NOSPACE=1 testing "format" "wc file1" " 4 5 26 file1\n" "" ""
+testing "multiple files" "wc input - file1" \
+ " 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
do
printf "ü" >> file1
done
-testing "wc -m" "wc -m file1" "8193 file1\n" "" ""
+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 "wc -m (invalid chars)" "wc -m file1" "8193 file1\n" "" ""
-testing "wc -mlw" "wc -mlw input" "1 2 11 input\n" "hello, 世界!\n" ""
+testing "-m (invalid chars)" "wc -m file1" "8193 file1\n" "" ""
+NOSPACE=1 testing "-mlw" "wc -mlw input" " 1 2 11 input\n" "hello, 世界!\n" ""
else
printf "skipping tests for wc -m"
#testing "name" "command" "result" "infile" "stdin"
testing "xargs" "xargs && echo yes" "hello\nyes\n" "" "hello"
-testing "xargs spaces" "xargs" \
+testing "spaces" "xargs" \
"one two three four\n" "" "one two\tthree \nfour\n\n"
-testing "xargs -n 0" "xargs -n 0 2>/dev/null || echo ok" "ok\n" \
+testing "-n 0" "xargs -n 0 2>/dev/null || echo ok" "ok\n" \
"" "one \ntwo\n three"
-testing "xargs -n 2" "xargs -n 2" "one two\nthree\n" "" "one \ntwo\n three"
-testing "xargs -n exact match" "xargs -n 3" "one two three\n" "" "one two three"
+testing "-n 2" "xargs -n 2" "one two\nthree\n" "" "one \ntwo\n three"
+testing "-n exact match" "xargs -n 3" "one two three\n" "" "one two three"
testing "xargs2" "xargs -n2" "one two\nthree four\nfive\n" "" \
"one two three four five"
-testing "xargs -s too long" "xargs -s 9 echo 2>/dev/null || echo ok" \
+testing "-s too long" "xargs -s 9 echo 2>/dev/null || echo ok" \
"one\ntwo\nok\n" "" "one two three"
-testing "xargs -s 13" "xargs -s 13 echo" "one two\nthree\n" "" "one \ntwo\n three"
-testing "xargs -s 12" "xargs -s 12 echo" "one\ntwo\nthree\n" "" "one \ntwo\n three"
+testing "-s 13" "xargs -s 13 echo" "one two\nthree\n" "" "one \ntwo\n three"
+testing "-s 12" "xargs -s 12 echo" "one\ntwo\nthree\n" "" "one \ntwo\n three"
touch one two three
-testing "xargs command -opt" "xargs -n2 ls -1" "one\ntwo\nthree\n" "" \
+testing "command -opt" "xargs -n2 ls -1" "one\ntwo\nthree\n" "" \
"one two three"
rm one two three
-exit
-
-testing "xargs -n exact match"
-testing "xargs -s exact match"
-testing "xargs -s 0"
-testing "xargs -s impossible"
+#testing "-n exact match"
+#testing "-s exact match"
+#testing "-s 0"
+#testing "-s impossible"
# xargs command_not_found - returns 127
# xargs false - returns 1
# Note that the xxd in vim-common on Ubuntu 14 uses %07x for the file offset.
-testing "xxd file1" "xxd file1" \
+testing "file1" "xxd file1" \
"00000000: 7468 6973 2069 7320 736f 6d65 2074 6578 this is some tex\n00000010: 740a t.\n" \
"" ""
-testing "xxd file1 -l" "xxd -l 2 file1" \
+testing "file1 -l" "xxd -l 2 file1" \
"00000000: 7468 th\n" \
"" ""
-testing "xxd file2" "xxd file2" "" "" ""
-testing "xxd -" "xxd -" \
+testing "file2" "xxd file2" "" "" ""
+testing "-" "xxd -" \
"00000000: 6865 6c6c 6f hello\n" "" "hello"
testing "xxd" "xxd" \
"00000000: 776f 726c 64 world\n" "" "world"
-testing "xxd -c 8 -g 4 file1" "xxd -c 8 -g 4 file1" \
+testing "-c 8 -g 4 file1" "xxd -c 8 -g 4 file1" \
"00000000: 74686973 20697320 this is \n00000008: 736f6d65 20746578 some tex\n00000010: 740a t.\n" "" ""
-testing "xxd -c 8 -g 3 file1" "xxd -c 8 -g 3 file1" \
+testing "-c 8 -g 3 file1" "xxd -c 8 -g 3 file1" \
"00000000: 746869 732069 7320 this is \n00000008: 736f6d 652074 6578 some tex\n00000010: 740a t.\n" "" ""
-testing "xxd -p" "xxd -p file1" "7468697320697320736f6d6520746578740a\n" "" ""
+testing "-p" "xxd -p file1" "7468697320697320736f6d6520746578740a\n" "" ""
-testing "xxd -r" "xxd file1 | xxd -r" "this is some text\n" "" ""
-testing "xxd -r -p" "xxd -p file1 | xxd -r -p" "this is some text\n" "" ""
+testing "-s" "xxd -s 13 file1" "0000000d: 7465 7874 0a text.\n" "" ""
-testing "xxd -r garbage" "echo '0000: 68 65 6c6c 6fxxxx' | xxd -r -" "hello" "" ""
+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" "" ""
+
+testing "-r garbage" "echo '0000: 68 65 6c6c 6fxxxx' | xxd -r -" "hello" "" ""
# -r will only read -c bytes (default 16) before skipping to the next line,
# ignoring the rest.
-testing "xxd -r long" \
+testing "-r long" \
"echo '0000: 40404040404040404040404040404040404040404040404040404040404040404040404040404040' | xxd -r -" \
"@@@@@@@@@@@@@@@@" "" ""
# -r -p ignores the usual -p 30-byte/line limit (or any limit set by -c) and
# will take as many bytes as you give it.
-testing "xxd -r -p long" \
+testing "-r -p long" \
"echo '40404040404040404040404040404040404040404040404040404040404040404040404040404040' | xxd -r -p -" \
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" "" ""
# Get system xzcat
xzcatExe=`which xzcat`
$xzcatExe file.xz > xzcatOut
-testing "xzcat - decompresses a single file" "xzcat file.xz > Tempfile && echo "yes"; diff Tempfile xzcatOut && echo "yes"; rm -rf file* xzcatOut Tempfile" "yes\nyes\n" "" ""
+testing "- decompresses a single file" "xzcat file.xz > Tempfile && echo "yes"; diff Tempfile xzcatOut && echo "yes"; rm -rf file* xzcatOut Tempfile" "yes\nyes\n" "" ""
#testing "name" "command" "result" "infile" "stdin"
echo "hello" > file1
# Get system xzcat
xzcatExe=`which xzcat`
$xzcatExe file1.xz file2.xz file3.xz > xzcatOut
-testing "xzcat - decompresses multiple files" "xzcat file1.xz file2.xz file3.xz > Tempfile && echo "yes" ; diff Tempfile xzcatOut && echo "yes"; rm -rf file* xzcatOut Tempfile " "yes\nyes\n" "" ""
+testing "- decompresses multiple files" "xzcat file1.xz file2.xz file3.xz > Tempfile && echo "yes" ; diff Tempfile xzcatOut && echo "yes"; rm -rf file* xzcatOut Tempfile " "yes\nyes\n" "" ""
# Get system zcat
zcatExe=`which zcat`
$zcatExe file.gz > zcatOut
-testing "zcat - decompresses a single file" "zcat file.gz > Tempfile && echo "yes"; diff Tempfile zcatOut && echo "yes"; rm -rf file* zcatOut Tempfile" "yes\nyes\n" "" ""
+testing "- decompresses a single file" "zcat file.gz > Tempfile && echo "yes"; diff Tempfile zcatOut && echo "yes"; rm -rf file* zcatOut Tempfile" "yes\nyes\n" "" ""
#testing "name" "command" "result" "infile" "stdin"
echo "hello" > file1
# Get system zcat
zcatExe=`which zcat`
$zcatExe file1.gz file2.gz file3.gz > zcatOut
-testing "zcat - decompresses multiple files" "zcat file1.gz file2.gz file3.gz > Tempfile && echo "yes" ; diff Tempfile zcatOut && echo "yes"; rm -rf file* zcatOut Tempfile " "yes\nyes\n" "" ""
+testing "- decompresses multiple files" "zcat file1.gz file2.gz file3.gz > Tempfile && echo "yes" ; diff Tempfile zcatOut && echo "yes"; rm -rf file* zcatOut Tempfile " "yes\nyes\n" "" ""
#include <wctype.h>
// LSB 4.1 headers
+#ifndef __APPLE__
#include <pty.h>
-#include <sys/ioctl.h>
#include <sys/statfs.h>
#include <sys/sysinfo.h>
+#endif
+#include <sys/ioctl.h>
#include "lib/lib.h"
#include "lib/lsm.h"
// This is at the end so toy_init() doesn't zero it.
jmp_buf *rebound; // longjmp here instead of exit when do_rebound set
+ struct arg_list *xexit; // atexit() functions for xexit(), set by sigatexit()
void *stacktop; // nested toy_exec() call count, or 0 if vforked
} toys;
}
// Needed to supress extraneous "Loaded property_contexts from" message
-int selinux_log_callback(int type, const char *fmt, ...) {
+static int selinux_log_callback_local(int type, const char *fmt, ...)
+{
va_list ap;
if (type == SELINUX_INFO) return 0;
if (toys.optflags & FLAG_Z) {
union selinux_callback cb;
- cb.func_log = selinux_log_callback;
+ cb.func_log = selinux_log_callback_local;
selinux_set_callback(SELINUX_CB_LOG, cb);
TT.handle = selinux_android_prop_context_handle();
if (!TT.handle) error_exit("unable to get selinux property context handle");
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);
}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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);
+}
/* skeleton.c - Example program to act as template for new commands.
+ * (Although really, half the time copying hello.c is easier.)
*
* Copyright 2014 Rob Landley <rob@landley.net>
*
// Command line options parsing is done for you by lib/args.c called
// from main.c using the optstring in the NEWTOY macros. Display results.
- if (toys.optflags) printf("flags=%x\n", toys.optflags);
+ if (toys.optflags) printf("flags=%llx\n", toys.optflags);
if (toys.optflags & FLAG_a) printf("Saw a\n");
if (toys.optflags & FLAG_b) printf("b=%s\n", TT.s.b_string);
if (toys.optflags & FLAG_c) printf("c=%ld\n", TT.s.c_number);
void skeleton_alias_main(void)
{
printf("Ran %s\n", toys.which->name);
- printf("flags=%x\n", toys.optflags);
+ printf("flags=%llx\n", toys.optflags);
// Note, this FLAG_b is a different bit position than the other FLAG_b,
// and fills out a different variable of a different type.
*
* 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"
*
* 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"
*
* 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"
*
* http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/hostname.html
-USE_HOSTNAME(NEWTOY(hostname, NULL, TOYFLAG_BIN))
+USE_HOSTNAME(NEWTOY(hostname, "bF:", TOYFLAG_BIN))
config HOSTNAME
bool "hostname"
default y
help
- usage: hostname [newname]
+ usage: hostname [-b] [-F FILENAME] [newname]
Get/Set the current hostname
+
+ -b Set hostname to 'localhost' if otherwise unset
+ -F Set hostname to contents of FILENAME
*/
#define FOR_hostname
#include "toys.h"
+GLOBALS(
+ char *fname;
+)
+
void hostname_main(void)
{
- const char *hostname = toys.optargs[0];
+ char *hostname = *toys.optargs;
+
+ if (TT.fname && (hostname = xreadfile(TT.fname, 0, 0))) {
+ if (!*chomp(hostname)) {
+ if (CFG_TOYBOX_FREE) free(hostname);
+ if (!(toys.optflags&FLAG_b)) error_exit("empty '%s'", TT.fname);
+ hostname = 0;
+ }
+ }
+
+ if (!hostname && (toys.optflags&FLAG_b))
+ if (gethostname(toybuf, sizeof(toybuf)-1) || !*toybuf)
+ hostname = "localhost";
+
if (hostname) {
if (sethostname(hostname, strlen(hostname)))
- perror_exit("set failed '%s'", hostname);
+ perror_exit("set '%s'", hostname);
} else {
- if (gethostname(toybuf, sizeof(toybuf))) perror_exit("get failed");
+ if (gethostname(toybuf, sizeof(toybuf)-1)) perror_exit("gethostname");
xputs(toybuf);
}
}
* 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;
}
}
+// 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);
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)
if (toys.optflags & FLAG_Z)
if (-1 == lsm_set_create(TT.arg_context))
perror_exit("-Z '%s' failed", TT.arg_context);
- if (mknod(*toys.optargs, mode|modes[type], makedev(major, minor)))
+ if (mknod(*toys.optargs, mode|modes[type], dev_makedev(major, minor)))
perror_exit_raw(*toys.optargs);
}
* See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/mount.html
* Note: -hV is bad spec, haven't implemented -FsLU yet
* no mtab (/proc/mounts does it) so -n is NOP.
+ * TODO mount -o loop,autoclear (linux git 96c5865559ce)
USE_MOUNT(NEWTOY(mount, "?O:afnrvwt:o*[-rw]", TOYFLAG_BIN|TOYFLAG_STAYROOT))
//USE_NFSMOUNT(NEWTOY(nfsmount, "?<2>2", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
bool "mount"
default y
help
- usage: mount [-afFrsvw] [-t TYPE] [-o OPTIONS...] [[DEVICE] DIR]
+ usage: mount [-afFrsvw] [-t TYPE] [-o OPTION,] [[DEVICE] DIR]
Mount new filesystem(s) on directories. With no arguments, display existing
mounts.
if (toys.optflags & FLAG_v)
printf("try '%s' type '%s' on '%s'\n", dev, type, dir);
for (;;) {
+ errno = 0;
rc = mount(dev, dir, type, flags, opts);
// Did we succeed, fail unrecoverably, or already try read-only?
- if (rc == 0 || (errno != EACCES && errno != EROFS) || (flags&MS_RDONLY))
+ if (!rc || (errno != EACCES && errno != EROFS) || (flags&MS_RDONLY))
break;
// If we haven't already tried it, use the BLKROSET ioctl to ensure
// that the underlying device isn't read-only.
if (-1 != (fd = open(dev, O_RDONLY))) {
rc = ioctl(fd, BLKROSET, &ro);
close(fd);
- if (rc == 0) continue;
+ if (!rc) continue;
}
}
fprintf(stderr, "'%s' is read-only\n", dev);
for (mm = remount ? remount : mtl; mm; mm = (remount ? mm->prev : mm->next))
{
- char *aopts = 0;
struct mtab_list *mmm = 0;
int aflags, noauto, len;
// user only counts from fstab, not opts.
if (!mmm) {
+ char *aopts = 0;
TT.okuser = comma_scan(mm->opts, "user", 1);
aflags = flag_opts(mm->opts, flags, &aopts);
aflags = flag_opts(opts, aflags, &aopts);
-
+ if (remount) {
+ // clear type and opts for remount
+ aflags |= MS_REMOUNT;
+ strcpy(mm->type, "none");
+ aopts = NULL;
+ }
mount_filesystem(mm->device, mm->dir, mm->type, aflags, aopts);
+ free(aopts);
+ if (!remount && errno == EINVAL) continue;
} // TODO else if (getuid()) error_msg("already there") ?
- free(aopts);
if (!(toys.optflags & FLAG_a)) break;
}
} else {
char *more = 0;
- mount_filesystem(dev, dir, TT.type, flag_opts(opts, flags, &more), more);
+ flags = flag_opts(opts, flags, &more);
+ mount_filesystem(dev, dir, TT.type, flags, more);
if (CFG_TOYBOX_FREE) free(more);
}
}
if (!s) error_exit("bad -f no %%f");
if (-1 == stridx("aAeEfFgG", *s) || (s = next_printf(s, 0))) {
// The @ is a byte offset, not utf8 chars. Waiting for somebody to complain.
- error_exit("bad -f '%s'@%ld", f, s-f+1);
+ error_exit("bad -f '%s'@%d", f, (int)(s-f+1));
}
}
--- /dev/null
+Networking
--- /dev/null
+/* 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;
+}
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;
--- /dev/null
+/* 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);
+}
*
* No standard
-USE_BASE64(NEWTOY(base64, "diw#<1[!dw]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_BASE64(NEWTOY(base64, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN))
config BASE64
bool "base64"
-d decode
-i ignore non-alphabetic characters
- -w wrap output at COLUMNS (default 76)
+ -w wrap output at COLUMNS (default 76 or 0 for no wrap)
*/
#define FOR_base64
GLOBALS(
long columns;
+
+ unsigned total;
)
+static void wraputchar(int c, int *x)
+{
+ putchar(c);
+ TT.total++;
+ if (TT.columns && ++*x == TT.columns) {
+ *x = 0;
+ xputc('\n');
+ };
+}
+
static void do_base64(int fd, char *name)
{
int out = 0, bits = 0, x = 0, i, len;
char *buf = toybuf+128;
+ TT.total = 0;
+
for (;;) {
+ // If no more data, flush buffer
if (!(len = xread(fd, buf, sizeof(toybuf)-128))) {
if (!(toys.optflags & FLAG_d)) {
- if (bits) {
- putchar(toybuf[out<<(6-bits)]);
- x++;
- }
- while (x++&3) putchar('=');
- if (x != 1) xputc('\n');
+ if (bits) wraputchar(toybuf[out<<(6-bits)], &x);
+ while (TT.total&3) wraputchar('=', &x);
+ if (x) xputc('\n');
}
return;
}
+
for (i=0; i<len; i++) {
if (toys.optflags & FLAG_d) {
if (buf[i] == '=') return;
out = (out<<8) + buf[i];
bits += 8;
while (bits >= 6) {
- putchar(toybuf[out >> (bits -= 6)]);
+ wraputchar(toybuf[out >> (bits -= 6)], &x);
out &= (1<<bits)-1;
- if (TT.columns == ++x) {
- xputc('\n');
- x = 0;
- }
}
}
}
void base64_main(void)
{
- if (!TT.columns) TT.columns = 76;
-
base64_init(toybuf);
loopfiles(toys.optargs, do_base64);
}
{"vfat", 0x31544146, 4, 54, 39+(4<<24), 11, 43} // fat1
};
+static const char *vfat_empty = " ";
+static const char *vfat_no_name = "NO NAME ";
+
+static int valid_label(int i, int off)
+{
+ int label_len = fstypes[i].label_len;
+ const char *label = toybuf + fstypes[i].label_off - off;
+
+ if (!strcmp(fstypes[i].name, "vfat")) {
+ if (!memcmp(label, vfat_empty, label_len))
+ return 0;
+ if (!memcmp(label, vfat_no_name, label_len))
+ return 0;
+ return 1;
+ }
+ return 1;
+}
+
static void do_blkid(int fd, char *name)
{
- int off, i, j;
+ int off, i, j, len;
char *type;
off = i = 0;
for (;;) {
- int pass = 0, len;
+ int pass = 0;
// Read next block of data
len = readall(fd, toybuf, sizeof(toybuf));
// distinguish ext2/3/4
type = fstypes[i].name;
- if (!i) {
+ if (!strcmp(type, "ext2")) {
if (toybuf[1116]&4) type = "ext3";
if (toybuf[1120]&64) type = "ext4";
}
// output for blkid
printf("%s:",name);
- if (fstypes[i].label_len)
- printf(" LABEL=\"%.*s\"", fstypes[i].label_len,
- toybuf+fstypes[i].label_off-off);
+ if (fstypes[i].label_len) {
+ char *s = toybuf+fstypes[i].label_off-off;;
+
+ len = fstypes[i].label_len;
+ if (!strcmp(type, "vfat")) {
+ while (len && s[len-1]==' ') len--;
+ if (strstart(&s, "NO NAME")) len=0;
+ }
+ if (len) printf(" LABEL=\"%.*s\"", len, s);
+ }
if (fstypes[i].uuid_off) {
int bits = 0x550, size = fstypes[i].uuid_off >> 24,
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++) {
static int read_huffman_data(struct bunzip_data *bd, struct bwdata *bw)
{
struct group_data *hufGroup;
- int hh, ii, jj, kk, runPos, dbufCount, symCount, selector, nextSym,
+ int ii, jj, kk, runPos, dbufCount, symCount, selector, nextSym,
*byteCount, *base, *limit;
- unsigned int *dbuf = bw->dbuf;
+ unsigned hh, *dbuf = bw->dbuf;
unsigned char uc;
// We've finished reading and digesting the block header. Now read this
literal used is the one at the head of the mtfSymbol array.) */
if (runPos) {
runPos = 0;
- if (dbufCount+hh > bd->dbufSize) return RETVAL_DATA_ERROR;
+ // Check for integer overflow
+ if (hh>bd->dbufSize || dbufCount+hh>bd->dbufSize)
+ return RETVAL_DATA_ERROR;
uc = bd->symToByte[bd->mtfSymbol[0]];
byteCount[uc] += hh;
unsigned int *dbuf = bw->dbuf;
int *byteCount = bw->byteCount;
- // Technically this part is preparation for the burrows-wheeler
- // transform, but it's quick and convenient to do here.
-
// Turn byteCount into cumulative occurrence counts of 0 to n-1.
jj = 0;
for (ii=0; ii<256; ii++) {
if (!(i = start_bunzip(&bd,src_fd, 0, 0))) {
i = write_bunzip_data(bd,bd->bwdata, dst_fd, 0, 0);
- if (i==RETVAL_LAST_BLOCK && bd->bwdata[0].headerCRC==bd->totalCRC) i = 0;
+ if (i==RETVAL_LAST_BLOCK) {
+ if (bd->bwdata[0].headerCRC==bd->totalCRC) i = 0;
+ else i = RETVAL_DATA_ERROR;
+ }
}
flush_bunzip_outbuf(bd, dst_fd);
static void factor(char *s)
{
- unsigned long l, ll;
+ unsigned long long l, ll;
for (;;) {
char *err = s;
+ int dash = 0;
while(isspace(*s)) s++;
+ if (*s=='-') dash = *s++;
if (!*s) return;
- l = strtoul(s, &s, 0);
+ l = strtoull(s, &s, 0);
if (*s && !isspace(*s)) {
error_msg("%s: not integer", err);
-
- return;
+ while (*s && !isspace(*s)) s++;
+ continue;
}
- printf("%lu:", l);
+ printf("-%llu:"+!dash, l);
// Negative numbers have -1 as a factor
- if (l < 0) {
- printf(" -1");
- l *= -1;
- }
+ if (dash) printf(" -1");
// Nothing below 4 has factors
if (l < 4) {
- printf(" %lu\n", l);
+ printf(" %llu\n", l);
continue;
}
l >>= 1;
}
- // test odd numbers.
+ // test odd numbers until square is > remainder or integer wrap.
for (ll=3; ;ll += 2) {
long lll = ll*ll;
if (lll>l || lll<ll) {
- if (l>1) printf(" %lu", l);
+ if (l>1) printf(" %llu", l);
break;
}
while (!(l%ll)) {
- printf(" %lu", ll);
+ printf(" %llu", ll);
l /= ll;
}
}
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);
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);
}
if (broiled==127) broiled = 32;
else broiled += 64;
}
- printf("%c", broiled);
+ printf("%c", (int)broiled);
tty_esc("0m");
- } else printf("%c", broiled);
+ } else printf("%c", (int)broiled);
}
return 1;
#include "toys.h"
#include <sys/syscall.h>
+#ifdef SYS_finit_module
#define finit_module(fd, opts, flags) syscall(SYS_finit_module, fd, opts, flags)
+#else
+#define finit_module(a, b, c) (errno = ENOSYS)
+#endif
#define init_module(mod, len, opts) syscall(SYS_init_module, mod, len, opts)
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;
// mount -o loop depends on found device being at the start of toybuf.
if (cfd != -1) {
if (0 <= (i = ioctl(cfd, 0x4C82))) // LOOP_CTL_GET_FREE
- sprintf(device = toybuf, "/dev/loop%d", i);
+ sprintf(device = toybuf, "/dev/block/loop%d", i);
close(cfd);
}
}
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);
{
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);
// 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);
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
perror_msg("line %d: file '%s' does not exist", line_no, ptr);
continue;
}
- } else if (mknod(ptr, mode, makedev(major, minor + i*incr))) {
+ } else if (mknod(ptr, mode, dev_makedev(major, minor + i*incr))) {
perror_msg("line %d: can't create node '%s'", line_no, ptr);
continue;
}
if (toys.optflags & FLAG_x) {
if (S_ISBLK(st1.st_mode)) {
- if (!quiet) printf("%u:%u\n", major(st1.st_rdev), minor(st1.st_rdev));
+ if (!quiet)
+ printf("%u:%u\n", dev_major(st1.st_rdev), dev_minor(st1.st_rdev));
return;
}
// absence of a spec I guess that's the expected behavior?
toys.exitval = !(st1.st_dev != st2.st_dev || st1.st_ino == st2.st_ino);
if (toys.optflags & FLAG_d)
- printf("%u:%u\n", major(st1.st_dev), minor(st1.st_dev));
+ printf("%u:%u\n", dev_major(st1.st_dev), dev_minor(st1.st_dev));
else if (!quiet)
printf("%s is %sa mountpoint\n", *toys.optargs, toys.exitval ? "not " : "");
}
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;
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);
}
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);
}
}
char *c;
for (;;) {
- int len, i;
+ unsigned len, i;
if (!(c = get_line(fd))) break;
- len = strlen(c) - 1;
- for (i = 0; i <= len/2; i++) {
+ len = strlen(c);
+ if (len--) for (i = 0; i <= len/2; i++) {
char tmp = c[i];
c[i] = c[len-i];
--- /dev/null
+/* 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);
+}
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.
* Copyright 2012 <warior.linux@gmail.com>
* Copyright 2013 <anand.sinha85@gmail.com>
-USE_STAT(NEWTOY(stat, "<1c:f", TOYFLAG_BIN))
+USE_STAT(NEWTOY(stat, "<1c:fLt", TOYFLAG_BIN))
config STAT
bool stat
default y
help
- usage: stat [-f] [-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
+ -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
%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
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
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)
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);
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);
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);
}
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);
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) {
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);
}
config UPTIME
bool "uptime"
default y
- depends on TOYBOX_UTMPX
help
usage: uptime
*
* 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.
-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;
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;
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
config BOOTCHARTD
bool "bootchartd"
default n
+ depends on TOYBOX_FORK
help
usage: bootchartd {start [PROG ARGS]}|stop|init
--- /dev/null
+/* 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);
+ }
+}
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);
config CRONTAB
bool "crontab"
default n
+ depends on TOYBOX_FORK
help
usage: crontab [-u user] FILE
[-u user] [-e | -l | -r]
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)) {
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);
}
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);
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);
}
* 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
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;
{ "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();
}
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;
long a, b, c, d, prev, suff;
};
-static struct dir {
+static struct dir_t {
char **list;
int nr_elm;
} dir[2];
struct candidate *prev, *next;
};
-static struct file {
+static struct file_t {
FILE *fp;
int len;
} file[2];
if (S_ISDIR(st[0].st_mode) && S_ISDIR(st[1].st_mode)) {
for (j = 0; j < 2; j++) {
- memset(&dir[j], 0, sizeof(dir));
- dirtree_handle_callback(dirtree_start(files[j], 1), list_dir);
+ memset(&dir[j], 0, sizeof(struct dir_t));
+ dirtree_flagread(files[j], DIRTREE_SYMFOLLOW, list_dir);
dir[j].nr_elm = TT.size; //size updated in list_dir
qsort(&(dir[j].list[1]), (TT.size - 1), sizeof(char*), cmp);
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);
/* expr.c - evaluate expression
*
+ * Copyright 2016 Google Inc.
* Copyright 2013 Daniel Verkamp <daniel@drv.nu>
*
* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/expr.html
*
* The web standard is incomplete (precedence grouping missing), see:
* http://permalink.gmane.org/gmane.comp.standards.posix.austin.general/10141
+ *
+ * eval_expr() uses the recursive "Precedence Climbing" algorithm:
+ *
+ * Clarke, Keith. "The top-down parsing of expressions." University of London.
+ * Queen Mary College. Department of Computer Science and Statistics, 1986.
+ *
+ * http://www.antlr.org/papers/Clarke-expr-parsing-1986.pdf
+ *
+ * Nice explanation and Python implementation:
+ * http://eli.thegreenplace.net/2012/08/02/parsing-expressions-by-precedence-climbing
USE_EXPR(NEWTOY(expr, NULL, TOYFLAG_USR|TOYFLAG_BIN))
#define FOR_expr
#include "toys.h"
-
GLOBALS(
- int argidx;
+ char **tok; // current token, not on the stack since recursive calls mutate it
+
+ char *refree;
)
-// Scalar value.
-// If s is NULL, the value is an integer (i).
-// If s is not NULL, the value is a string (s).
+// Scalar value. If s != NULL, it's a string, otherwise it's an int.
struct value {
char *s;
long long i;
};
-// check if v is the integer 0 or the empty string
-static int is_zero(struct value *v)
-{
- return v->s ? !*v->s : !v->i;
-}
-
-static char *num_to_str(long long num)
-{
- static char num_buf[21];
- snprintf(num_buf, sizeof(num_buf), "%lld", num);
- return num_buf;
-}
-
-static int cmp(struct value *lhs, struct value *rhs)
-{
- if (lhs->s || rhs->s) {
- // at least one operand is a string
- char *ls = lhs->s ? lhs->s : num_to_str(lhs->i);
- char *rs = rhs->s ? rhs->s : num_to_str(rhs->i);
- return strcmp(ls, rs);
- } else return lhs->i - rhs->i;
-}
-
-static void re(struct value *lhs, struct value *rhs)
-{
- regex_t rp;
- regmatch_t rm[2];
-
- xregcomp(&rp, rhs->s, 0);
- if (!regexec(&rp, lhs->s, 2, rm, 0) && rm[0].rm_so == 0) {
- if (rp.re_nsub > 0 && rm[1].rm_so >= 0)
- lhs->s = xmprintf("%.*s", rm[1].rm_eo - rm[1].rm_so, lhs->s+rm[1].rm_so);
- else {
- lhs->i = rm[0].rm_eo;
- lhs->s = 0;
- }
- } else {
- if (!rp.re_nsub) {
- lhs->i = 0;
- lhs->s = 0;
- } else lhs->s = "";
- }
-}
-
-static void mod(struct value *lhs, struct value *rhs)
-{
- if (lhs->s || rhs->s) error_exit("non-integer argument");
- if (is_zero(rhs)) error_exit("division by zero");
- lhs->i %= rhs->i;
-}
-
-static void divi(struct value *lhs, struct value *rhs)
-{
- if (lhs->s || rhs->s) error_exit("non-integer argument");
- if (is_zero(rhs)) error_exit("division by zero");
- lhs->i /= rhs->i;
-}
-
-static void mul(struct value *lhs, struct value *rhs)
-{
- if (lhs->s || rhs->s) error_exit("non-integer argument");
- lhs->i *= rhs->i;
-}
-
-static void sub(struct value *lhs, struct value *rhs)
-{
- if (lhs->s || rhs->s) error_exit("non-integer argument");
- lhs->i -= rhs->i;
-}
-
-static void add(struct value *lhs, struct value *rhs)
+// Get the value as a string.
+char *get_str(struct value *v)
{
- if (lhs->s || rhs->s) error_exit("non-integer argument");
- lhs->i += rhs->i;
+ if (v->s) return v->s;
+ else return xmprintf("%lld", v->i);
}
-static void ne(struct value *lhs, struct value *rhs)
+// Get the value as an integer and return 1, or return 0 on error.
+int get_int(struct value *v, long long *ret)
{
- lhs->i = cmp(lhs, rhs) != 0;
- lhs->s = NULL;
-}
+ if (v->s) {
+ char *endp;
-static void lte(struct value *lhs, struct value *rhs)
-{
- lhs->i = cmp(lhs, rhs) <= 0;
- lhs->s = NULL;
-}
+ *ret = strtoll(v->s, &endp, 10);
-static void lt(struct value *lhs, struct value *rhs)
-{
- lhs->i = cmp(lhs, rhs) < 0;
- lhs->s = NULL;
-}
+ if (*endp) return 0; // If endp points to NUL, all chars were converted
+ } else *ret = v->i;
-static void gte(struct value *lhs, struct value *rhs)
-{
- lhs->i = cmp(lhs, rhs) >= 0;
- lhs->s = NULL;
+ return 1;
}
-static void gt(struct value *lhs, struct value *rhs)
+// Preserve the invariant that v.s is NULL when the value is an integer.
+void assign_int(struct value *v, long long i)
{
- lhs->i = cmp(lhs, rhs) > 0;
- lhs->s = NULL;
+ v->i = i;
+ v->s = NULL;
}
-static void eq(struct value *lhs, struct value *rhs)
+// Check if v is 0 or the empty string.
+static int is_false(struct value *v)
{
- lhs->i = !cmp(lhs, rhs);
- lhs->s = NULL;
+ return get_int(v, &v->i) && !v->i;
}
-static void and(struct value *lhs, struct value *rhs)
+// 'ret' is filled with a string capture or int match position.
+static void re(char *target, char *pattern, struct value *ret)
{
- if (is_zero(lhs) || is_zero(rhs)) {
- lhs->i = 0;
- lhs->s = NULL;
+ regex_t pat;
+ regmatch_t m[2];
+
+ xregcomp(&pat, pattern, 0);
+ // must match at pos 0
+ if (!regexec(&pat, target, 2, m, 0) && !m[0].rm_so) {
+ // Return first parenthesized subexpression as string, or length of match
+ if (pat.re_nsub>0) {
+ ret->s = xmprintf("%.*s", m[1].rm_eo-m[1].rm_so, target+m[1].rm_so);
+ if (TT.refree) free(TT.refree);
+ TT.refree = ret->s;
+ } else assign_int(ret, m[0].rm_eo);
+ } else {
+ if (pat.re_nsub>0) ret->s = "";
+ else assign_int(ret, 0);
}
+ regfree(&pat);
}
-static void or(struct value *lhs, struct value *rhs)
-{
- if (is_zero(lhs)) *lhs = *rhs;
-}
+// 4 different signatures of operators. S = string, I = int, SI = string or
+// int.
+enum { SI_TO_SI = 1, SI_TO_I, I_TO_I, S_TO_SI };
-static void get_value(struct value *v)
-{
- char *endp, *arg;
-
- if (TT.argidx == toys.optc) {
- v->i = 0;
- v->s = ""; // signal end of expression
- return;
- }
+enum { OR = 1, AND, EQ, NE, GT, GTE, LT, LTE, ADD, SUB, MUL, DIVI, MOD, RE };
-// can't happen, the increment is after the == test
-// if (TT.argidx >= toys.optc) error_exit("syntax error");
+// operators grouped by precedence
+static struct op_def {
+ char *tok;
+ char prec, sig, op; // precedence, signature for type coercion, operator ID
+} OPS[] = {
+ // logical ops, precedence 1 and 2, signature SI_TO_SI
+ {"|", 1, SI_TO_SI, OR },
+ {"&", 2, SI_TO_SI, AND },
+ // comparison ops, precedence 3, signature SI_TO_I
+ {"=", 3, SI_TO_I, EQ }, {"==", 3, SI_TO_I, EQ }, {"!=", 3, SI_TO_I, NE },
+ {">", 3, SI_TO_I, GT }, {">=", 3, SI_TO_I, GTE },
+ {"<", 3, SI_TO_I, LT }, {"<=", 3, SI_TO_I, LTE },
+ // arithmetic ops, precedence 4 and 5, signature I_TO_I
+ {"+", 4, I_TO_I, ADD }, {"-", 4, I_TO_I, SUB },
+ {"*", 5, I_TO_I, MUL }, {"/", 5, I_TO_I, DIVI }, {"%", 5, I_TO_I, MOD },
+ // regex match, precedence 6, signature S_TO_SI
+ {":", 6, S_TO_SI, RE },
+ {NULL, 0, 0, 0}, // sentinel
+};
- arg = toys.optargs[TT.argidx++];
+void eval_op(struct op_def *o, struct value *ret, struct value *rhs)
+{
+ long long a, b, x = 0; // x = a OP b for ints.
+ char *s, *t; // string operands
+ int cmp;
- v->i = strtoll(arg, &endp, 10);
- v->s = *endp ? arg : NULL;
-}
+ switch (o->sig) {
-// check if v matches a token, and consume it if so
-static int match(struct value *v, char *tok)
-{
- if (v->s && !strcmp(v->s, tok)) {
- get_value(v);
- return 1;
+ case SI_TO_SI:
+ switch (o->op) {
+ case OR: if (is_false(ret)) *ret = *rhs; break;
+ case AND: if (is_false(ret) || is_false(rhs)) assign_int(ret, 0); break;
+ }
+ break;
+
+ case SI_TO_I:
+ if (get_int(ret, &a) && get_int(rhs, &b)) { // both are ints
+ cmp = a - b;
+ } else { // otherwise compare both as strings
+ cmp = strcmp(s = get_str(ret), t = get_str(rhs));
+ if (ret->s != s) free(s);
+ if (rhs->s != t) free(t);
+ }
+ switch (o->op) {
+ case EQ: x = cmp == 0; break;
+ case NE: x = cmp != 0; break;
+ case GT: x = cmp > 0; break;
+ case GTE: x = cmp >= 0; break;
+ case LT: x = cmp < 0; break;
+ case LTE: x = cmp <= 0; break;
+ }
+ assign_int(ret, x);
+ break;
+
+ case I_TO_I:
+ if (!get_int(ret, &a) || !get_int(rhs, &b))
+ error_exit("non-integer argument");
+ switch (o->op) {
+ case ADD: x = a + b; break;
+ case SUB: x = a - b; break;
+ case MUL: x = a * b; break;
+ case DIVI: if (b == 0) error_exit("division by zero"); x = a / b; break;
+ case MOD: if (b == 0) error_exit("division by zero"); x = a % b; break;
+ }
+ assign_int(ret, x);
+ break;
+
+ case S_TO_SI: // op == RE
+ s = get_str(ret);
+ cmp = ret->s!=s; // ret overwritten by re so check now
+ re(s, t = get_str(rhs), ret);
+ if (cmp) free(s);
+ if (rhs->s!=t) free(t);
+ break;
}
-
- return 0;
}
-// operators in order of increasing precedence
-static struct op {
- char *tok;
-
- // calculate "lhs op rhs" (e.g. lhs + rhs) and store result in lhs
- void (*calc)(struct value *lhs, struct value *rhs);
-} ops[] = {
- {"|", or }, {"&", and }, {"=", eq }, {"==", eq }, {">", gt },
- {">=", gte }, {"<", lt }, {"<=", lte }, {"!=", ne }, {"+", add },
- {"-", sub }, {"*", mul }, {"/", divi}, {"%", mod }, {":", re },
- {"(", NULL}, // special case - must be last
-};
-
-// "|,&,= ==> >=< <= !=,+-,*/%,:"
-
-static void parse_op(struct value *lhs, struct value *tok, struct op *op)
+// Evalute a compound expression using recursive "Precedence Climbing"
+// algorithm, setting 'ret'.
+static void eval_expr(struct value *ret, int min_prec)
{
- if (!op) op = ops;
-
- // special case parsing for parentheses
- if (*op->tok == '(') {
- if (match(tok, "(")) {
- parse_op(lhs, tok, 0);
- if (!match(tok, ")")) error_exit("syntax error"); // missing closing paren
- } else {
- // tok is a string or integer - return it and get the next token
- *lhs = *tok;
- get_value(tok);
+ if (!*TT.tok) error_exit("Unexpected end of input");
+
+ // Evaluate LHS atom, setting 'ret'.
+ if (!strcmp(*TT.tok, "(")) { // parenthesized expression
+ TT.tok++; // consume (
+
+ eval_expr(ret, 1); // We're inside ( ), so min_prec = 1
+ if (ret->s && !strcmp(ret->s, ")")) error_exit("empty ( )");
+ if (!*TT.tok) error_exit("Expected )");
+ if (strcmp(*TT.tok, ")")) error_exit("Expected ) but got %s", *TT.tok);
+ } else ret->s = *TT.tok; // simple literal, all values start as strings
+ TT.tok++;
+
+ // Evaluate RHS and apply operator until precedence is too low.
+ struct value rhs;
+ while (*TT.tok) {
+ struct op_def *o = OPS;
+
+ while (o->tok) { // Look up operator
+ if (!strcmp(*TT.tok, o->tok)) break;
+ o++;
}
+ if (!o->tok) break; // Not an operator (extra input will fail later)
+ if (o->prec < min_prec) break; // Precedence too low, pop a stack frame
+ TT.tok++;
- return;
- }
-
- parse_op(lhs, tok, op + 1);
- while (match(tok, op->tok)) {
- struct value rhs;
- parse_op(&rhs, tok, op + 1);
- if (rhs.s && !*rhs.s) error_exit("syntax error"); // premature end of expression
- op->calc(lhs, &rhs);
+ eval_expr(&rhs, o->prec + 1); // Evaluate RHS, with higher min precedence
+ eval_op(o, ret, &rhs); // Apply operator, setting 'ret'
}
}
void expr_main(void)
{
- struct value tok, ret = {0};
+ struct value ret = {0};
- toys.exitval = 2; // if exiting early, indicate invalid expression
-
- TT.argidx = 0;
-
- get_value(&tok); // warm up the parser with the initial value
- parse_op(&ret, &tok, 0);
-
- // final token should be end of expression
- if (!tok.s || *tok.s) error_exit("syntax error");
+ toys.exitval = 2; // if exiting early, indicate error
+ TT.tok = toys.optargs; // initialize global token
+ eval_expr(&ret, 1);
+ if (*TT.tok) error_exit("Unexpected extra input '%s'\n", *TT.tok);
if (ret.s) printf("%s\n", ret.s);
else printf("%lld\n", ret.i);
- exit(is_zero(&ret));
+ toys.exitval = is_false(&ret);
+
+ if (TT.refree) free(TT.refree);
}
toys.exitval = 0;
return;
} else {
- if (toys.optc != 1) help_exit(stdout);
+ if (toys.optc != 1) help_exit(0);
if (read_mbr(toys.optargs[0], 1)) return;
while (1) {
xputc('\n');
+++ /dev/null
-/* file.c - describe file type
- *
- * 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))
-
-config FILE
- bool "file"
- default n
- help
- usage: file [file...]
-
- Examine the given files and describe their content types.
-*/
-
-#define FOR_file
-#include "toys.h"
-
-GLOBALS(
- int max_name_len;
-)
-
-// 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)
-{
- int endian = toybuf[5], bits = toybuf[4], i, j;
- int64_t (*elf_int)(void *ptr, unsigned size) = peek_le;
- // Values from include/linux/elf-em.h (plus arch/*/include/asm/elf.h)
- // Names are linux/arch/ directory name
- struct {int val; char *name;} type[] = {{0x9026, "alpha"},
- {40, "arm"}, {183, "arm"}, {0x18ad, "avr32"}, {106, "blackfin"},
- {76, "cris"}, {0x5441, "frv"}, {46, "h8300"}, {50, "ia64"},//ia intel ftaghn
- {88, "m32r"}, {4, "m68k"}, {0xbaab, "microblaze"}, {8, "mips"},
- {10, "mips"}, {89, "mn10300"}, {15, "parisc"}, {22, "s390"},
- {135, "score"}, {42, "sh"}, {2, "sparc"}, {18, "sparc"}, {43, "sparc"},
- {187, "tile"}, {188, "tile"}, {191, "tile"}, {3, "x86"}, {6, "x86"},
- {62, "x86"}, {94, "xtensa"}, {0xabc7, "xtensa"}};
-
- xprintf("ELF ");
-
- // "64-bit"
- if (bits == 1) xprintf("32-bit ");
- else if (bits == 2) xprintf("64-bit ");
- else {
- xprintf("(bad class %d) ", bits);
- bits = 0;
- }
-
- // e_machine, ala "x86", from big table above
- j = elf_int(toybuf+18, 2);
- for (i = 0; i<ARRAY_LEN(type); i++) if (j==type[i].val) break;
- if (i<ARRAY_LEN(type)) xprintf("%s ", type[i].name);
- else xprintf("(unknown arch %d) ", j);
-
- // "LSB"
- if (endian == 1) xprintf("LSB ");
- else if (endian == 2) {
- xprintf("MSB ");
- elf_int = peek_be;
- } else {
- xprintf("(bad endian %d)\n", endian);
- endian = 0;
- }
-
- // ", executable"
- i = elf_int(toybuf+16, 2);
- if (i == 1) xprintf("relocatable");
- else if (i == 2) xprintf("executable");
- else if (i == 3) xprintf("shared object");
- else if (i == 4) xprintf("core dump");
- else xprintf("(bad type %d)", i);
-
- 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. (Not: 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 (!lib) printf(", static");
- else printf(", needs %d lib%s", lib, lib>1 ? "s" : "");
- munmap(map, phsize*phnum);
- }
- }
-
- // 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"
- xputc('\n');
-}
-
-static void do_regular_file(int fd, char *name)
-{
- char *s;
- int len = read(fd, s = toybuf, sizeof(toybuf)-256);
-
- if (len<0) perror_msg("%s", name);
-
- if (len>40 && strstart(&s, "\177ELF")) do_elf_file(fd);
- 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);
-
- xprintf("PNG image data");
-
- // The IHDR chunk comes first: https://www.w3.org/TR/PNG/#11IHDR
- s += 4;
- if (chunk_length == 13 && strstart(&s, "IHDR")) {
- // https://www.w3.org/TR/PNG/#6Colour-values
- char *c = 0, *colors[] = {"grayscale", 0, "color RGB", "indexed color",
- "grayscale with alpha", 0, "color RGBA"};
-
- if (s[9]<ARRAY_LEN(colors)) c = colors[s[9]];
- if (!c) c = "unknown";
-
- xprintf(", %d x %d, %d-bit/%s, %sinterlaced", (int)peek_be(s, 4),
- (int)peek_be(s+4, 4), s[8], c, s[12] ? "" : "non-");
- }
-
- xputc('\n');
-
- // https://www.w3.org/Graphics/GIF/spec-gif89a.txt
- } else if (len>16 && (strstart(&s, "GIF87a") || strstart(&s, "GIF89a")))
- xprintf("GIF image data, %d x %d\n",
- (int)peek_le(s, 2), (int)peek_le(s+8, 2));
-
- // TODO: parsing JPEG for width/height is harder than GIF or PNG.
- else if (len>32 && memcmp(toybuf, "\xff\xd8", 2) == 0)
- xprintf("JPEG image data\n");
-
- // https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
- else if (len>8 && strstart(&s, "\xca\xfe\xba\xbe"))
- xprintf("Java class file, version %d.%d\n",
- (int)peek_be(s+6, 2), (int)peek_be(s, 2));
-
- // TODO: cpio archive.
- // TODO: tar archive.
- // TODO: zip/jar/apk archive.
- else {
- char *what = 0;
- int i, bytes;
-
- // If shell script, report which interpreter
- if (len>3 && strstart(&s, "#!")) {
- for (what = s; (s-toybuf)<len && !isspace(*s); s++);
- strcpy(s, " script");
-
- // Distinguish ASCII text, UTF-8 text, or data
- } else for (i = 0; i<len; ++i) {
- if (!(isprint(toybuf[i]) || isspace(toybuf[i]))) {
- wchar_t wc;
- if ((bytes = mbrtowc(&wc, s+i, len-i, 0))>0 && wcwidth(wc)>=0) {
- i += bytes-1;
- if (!what) what = "UTF-8 text";
- } else {
- what = "data";
- break;
- }
- }
- }
- xputs(what ? what : "ASCII text");
- }
-}
-
-static void do_file(int fd, char *name)
-{
- struct stat sb;
- char *what = "unknown";
-
- xprintf("%s: %*s", name, (int)(TT.max_name_len - strlen(name)), "");
-
- if (!fstat(fd, &sb)) what = "cannot open";
- if (S_ISREG(sb.st_mode)) {
- if (sb.st_size == 0) what = "empty";
- else {
- do_regular_file(fd, name);
- return;
- }
- } 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_ISFIFO(sb.st_mode)) what = "fifo";
- else if (S_ISSOCK(sb.st_mode)) what = "socket";
- else if (S_ISLNK(sb.st_mode)) what = "symbolic link";
- xputs(what);
-}
-
-void file_main(void)
-{
- char **name;
-
- for (name = toys.optargs; *name; ++name) {
- int name_len = strlen(*name);
-
- if (name_len > TT.max_name_len) TT.max_name_len = name_len;
- }
-
- loopfiles(toys.optargs, do_file);
-}
--- /dev/null
+/* 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);
+}
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);
)
#include <resolv.h>
+#include "resolv_private.h"
#define PL_IP 1
#define PL_NAME 2
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..
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.
*
* Copyright 2015 The Android Open Source Project
-USE_LSOF(NEWTOY(lsof, "lp:t", TOYFLAG_USR|TOYFLAG_BIN))
+USE_LSOF(NEWTOY(lsof, "lp*t", TOYFLAG_USR|TOYFLAG_BIN))
config LSOF
bool "lsof"
#include "toys.h"
GLOBALS(
- char *pids;
+ struct arg_list *p;
struct stat *sought_files;
+ struct double_list *all_sockets;
struct double_list *files;
int last_shown_pid;
int shown_header;
// For output.
struct proc_info pi;
- char fd[8];
- char rw;
- char locks;
- char type[10];
- char device[32];
- char size_off[32];
- char node[32];
char* name;
+ char fd[8], rw, locks, type[10], device[32], size_off[32], node[32];
// For filtering.
dev_t st_dev;
ino_t st_ino;
};
-static int filter_matches(struct file_info *fi)
-{
- struct stat *sb = TT.sought_files;
-
- for (; sb != &(TT.sought_files[toys.optc]); ++sb) {
- if (sb->st_dev == fi->st_dev && sb->st_ino == fi->st_ino) return 1;
- }
- return 0;
-}
-
-static void print_header()
-{
- // TODO: llist_traverse to measure the columns first.
- char* names[] = {
- "COMMAND", "PID", "USER", "FD", "TYPE", "DEVICE", "SIZE/OFF", "NODE", "NAME"
- };
- printf("%-9s %5s %10.10s %4s %7s %18s %9s %10s %s\n", names[0], names[1],
- names[2], names[3], names[4], names[5], names[6], names[7], names[8]);
- TT.shown_header = 1;
-}
-
static void print_info(void *data)
{
struct file_info *fi = data;
- if (toys.optc && !filter_matches(fi)) return;
+ // Filter matches
+ if (toys.optc) {
+ int i;
+
+ for (i = 0; i<toys.optc; i++)
+ if (TT.sought_files[i].st_dev==fi->st_dev)
+ if (TT.sought_files[i].st_ino==fi->st_ino) break;
+
+ if (i==toys.optc) return;
+ }
if (toys.optflags&FLAG_t) {
if (fi->pi.pid != TT.last_shown_pid)
- printf("%d\n", (TT.last_shown_pid = fi->pi.pid));
+ printf("%d\n", TT.last_shown_pid = fi->pi.pid);
} else {
- if (!TT.shown_header) print_header();
+ if (!TT.shown_header) {
+ // TODO: llist_traverse to measure the columns first.
+ printf("%-9s %5s %10.10s %4s %7s %18s %9s %10s %s\n", "COMMAND", "PID",
+ "USER", "FD", "TYPE", "DEVICE", "SIZE/OFF", "NODE", "NAME");
+ TT.shown_header = 1;
+ }
+
printf("%-9s %5d %10.10s %4s%c%c %7s %18s %9s %10s %s\n",
fi->pi.cmd, fi->pi.pid, fi->pi.user,
fi->fd, fi->rw, fi->locks, fi->type, fi->device, fi->size_off,
fi->node, fi->name);
}
+}
- if (CFG_FREE) {
- free(((struct file_info *)data)->name);
- free(data);
- }
+static void free_info(void *data)
+{
+ free(((struct file_info *)data)->name);
+ free(data);
}
static void fill_flags(struct file_info *fi)
fclose(fp);
}
-static int scan_proc_net_file(char *path, int family, char type,
- void (*fn)(char *, int, char, struct file_info *, long),
- struct file_info *fi, long sought_inode)
+static void scan_proc_net_file(char *path, int family, char type,
+ void (*fn)(char *, int, char))
{
FILE *fp = fopen(path, "r");
char *line = NULL;
size_t line_length = 0;
- if (!fp) return 0;
+ if (!fp) return;
- if (!getline(&line, &line_length, fp)) return 0; // Skip header.
+ if (!getline(&line, &line_length, fp)) return; // Skip header.
while (getline(&line, &line_length, fp) > 0) {
- fn(line, family, type, fi, sought_inode);
- if (fi->name != 0) break;
+ fn(line, family, type);
}
free(line);
fclose(fp);
+}
- return fi->name != 0;
+static struct file_info *add_socket(ino_t inode, const char *type)
+{
+ struct file_info *fi = xzalloc(sizeof(struct file_info));
+
+ dlist_add_nomalloc(&TT.all_sockets, (struct double_list *)fi);
+ fi->st_ino = inode;
+ strcpy(fi->type, type);
+ return fi;
}
-static void match_unix(char *line, int af, char type, struct file_info *fi,
- long sought_inode)
+static void scan_unix(char *line, int af, char type)
{
long inode;
int path_pos;
- if (sscanf(line, "%*p: %*X %*X %*X %*X %*X %lu %n", &inode, &path_pos) >= 1 &&
- inode == sought_inode) {
+ if (sscanf(line, "%*p: %*X %*X %*X %*X %*X %lu %n", &inode, &path_pos) >= 1) {
+ struct file_info *fi = add_socket(inode, "unix");
char *name = chomp(line + path_pos);
- strcpy(fi->type, "unix");
fi->name = strdup(*name ? name : "socket");
}
}
-static void match_netlink(char *line, int af, char type, struct file_info *fi,
- long sought_inode)
+static void scan_netlink(char *line, int af, char type)
{
unsigned state;
long inode;
"ENCRYPTFS", "RDMA", "CRYPTO"
};
- if (sscanf(line, "%*p %u %*u %*x %*u %*u %*u %*u %*u %lu",
- &state, &inode) < 2 || inode != sought_inode) {
+ if (sscanf(line, "%*p %u %*u %*x %*u %*u %*u %*u %*u %lu", &state, &inode)
+ < 2) {
return;
}
- strcpy(fi->type, "netlink");
+ struct file_info *fi = add_socket(inode, "netlink");
fi->name =
strdup(state < ARRAY_LEN(netlink_states) ? netlink_states[state] : "?");
}
-static void match_ip(char *line, int af, char type, struct file_info *fi,
- long sought_inode)
+static void scan_ip(char *line, int af, char type)
{
char *tcp_states[] = {
"UNKNOWN", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1", "FIN_WAIT2",
&(remote.s6_addr32[2]), &(remote.s6_addr32[3]),
&remote_port, &state, &inode) == 12;
}
- if (!ok || inode != sought_inode) return;
+ if (!ok) return;
- strcpy(fi->type, af == 4 ? "IPv4" : "IPv6");
+ struct file_info *fi = add_socket(inode, af == 4 ? "IPv4" : "IPv6");
inet_ntop(af, &local, local_ip, sizeof(local_ip));
inet_ntop(af, &remote, remote_ip, sizeof(remote_ip));
if (type == 't') {
static int find_socket(struct file_info *fi, long inode)
{
- // TODO: other protocols (packet).
- return scan_proc_net_file("/proc/net/tcp", 4, 't', match_ip, fi, inode) ||
- scan_proc_net_file("/proc/net/tcp6", 6, 't', match_ip, fi, inode) ||
- scan_proc_net_file("/proc/net/udp", 4, 'u', match_ip, fi, inode) ||
- scan_proc_net_file("/proc/net/udp6", 6, 'u', match_ip, fi, inode) ||
- scan_proc_net_file("/proc/net/raw", 4, 'r', match_ip, fi, inode) ||
- scan_proc_net_file("/proc/net/raw6", 6, 'r', match_ip, fi, inode) ||
- scan_proc_net_file("/proc/net/unix", 0, 0, match_unix, fi, inode) ||
- scan_proc_net_file("/proc/net/netlink", 0, 0, match_netlink, fi, inode);
+ static int cached;
+ if (!cached) {
+ scan_proc_net_file("/proc/net/tcp", 4, 't', scan_ip);
+ scan_proc_net_file("/proc/net/tcp6", 6, 't', scan_ip);
+ scan_proc_net_file("/proc/net/udp", 4, 'u', scan_ip);
+ scan_proc_net_file("/proc/net/udp6", 6, 'u', scan_ip);
+ scan_proc_net_file("/proc/net/raw", 4, 'r', scan_ip);
+ scan_proc_net_file("/proc/net/raw6", 6, 'r', scan_ip);
+ scan_proc_net_file("/proc/net/unix", 0, 0, scan_unix);
+ scan_proc_net_file("/proc/net/netlink", 0, 0, scan_netlink);
+ cached = 1;
+ }
+ void* list = TT.all_sockets;
+
+ while (list) {
+ struct file_info *s = (struct file_info*) llist_pop(&list);
+
+ if (s->st_ino == inode) {
+ fi->name = s->name ? strdup(s->name) : NULL;
+ strcpy(fi->type, s->type);
+ return 1;
+ }
+ if (list == TT.all_sockets) break;
+ }
+
+ return 0;
}
-static void fill_stat(struct file_info *fi, const char* path)
+static void fill_stat(struct file_info *fi, const char *path)
{
struct stat sb;
long dev;
// 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))
fi->st_ino = sb.st_ino;
}
-struct file_info *new_file_info(struct proc_info *pi, const char* fd)
+struct file_info *new_file_info(struct proc_info *pi, const char *fd)
{
struct file_info *fi = xzalloc(sizeof(struct file_info));
return fi;
}
-static void visit_symlink(struct proc_info *pi, char* name, char* path)
+static void visit_symlink(struct proc_info *pi, char *name, char *path)
{
struct file_info *fi = new_file_info(pi, "");
static void lsof_pid(int pid)
{
struct proc_info pi;
- FILE *fp;
char *line;
struct stat sb;
- // Does this process even exist?
- snprintf(toybuf, sizeof(toybuf), "/proc/%d/stat", pid);
- fp = fopen(toybuf, "r");
- if (!fp) return;
+ // Skip nonexistent pids
+ sprintf(toybuf, "/proc/%d/stat", pid);
+ if (!(line = readfile(toybuf, toybuf, sizeof(toybuf)))) return;
// Get COMMAND.
strcpy(pi.cmd, "?");
- line = fgets(toybuf, sizeof(toybuf), fp);
- fclose(fp);
if (line) {
char *open_paren = strchr(toybuf, '(');
char *close_paren = strrchr(toybuf, ')');
visit_fds(&pi);
}
-static int scan_slash_proc(struct dirtree *node)
+static int scan_proc(struct dirtree *node)
{
int pid;
- if (!node->parent) return DIRTREE_RECURSE;
+ if (!node->parent) return DIRTREE_RECURSE|DIRTREE_SHUTUP;
if ((pid = atol(node->name))) lsof_pid(pid);
+
return 0;
}
void lsof_main(void)
{
+ struct arg_list *pp;
int i;
// lsof will only filter on paths it can stat (because it filters by inode).
TT.sought_files = xmalloc(toys.optc*sizeof(struct stat));
- for (i = 0; i < toys.optc; ++i) {
- xstat(toys.optargs[i], &(TT.sought_files[i]));
- }
+ for (i = 0; i<toys.optc; ++i) xstat(toys.optargs[i], TT.sought_files+i);
- if (toys.optflags&FLAG_p) {
- char *pid_str;
+ if (!TT.p) dirtree_read("/proc", scan_proc);
+ else for (pp = TT.p; pp; pp = pp->next) {
+ char *start, *end, *next = pp->arg;
int length, pid;
- while ((pid_str = comma_iterate(&TT.pids, &length))) {
- pid_str[length] = 0;
- if (!(pid = atoi(pid_str))) error_exit("bad pid '%s'", pid_str);
+ while ((start = comma_iterate(&next, &length))) {
+ pid = strtol(start, &end, 10);
+ if (pid<1 || (*end && *end!=','))
+ error_exit("bad -p '%.*s'", (int)(end-start), start);
lsof_pid(pid);
}
- } else dirtree_read("/proc", scan_slash_proc);
+ }
llist_traverse(TT.files, print_info);
+
+ if (CFG_TOYBOX_FREE) {
+ llist_traverse(TT.files, free_info);
+ llist_traverse(TT.all_sockets, free_info);
+ }
}
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;
if (strchr(device_name, '/'))
mkpathat(AT_FDCWD, toybuf, 0, 2);
- if (mknod(toybuf, mode | type, makedev(major, minor)) && errno != EEXIST)
+ if (mknod(toybuf, mode | type, dev_makedev(major, minor)) && errno != EEXIST)
perror_exit("mknod %s failed", toybuf);
if (!file) return NULL;
if (!mod) mod = xmalloc(MODNAME_LEN);
- from = basename_r(file);
+ from = getbasename(file);
for (i = 0; i < (MODNAME_LEN-1) && from[i] && from[i] != '.'; i++)
mod[i] = (from[i] == '-') ? '_' : from[i];
{
char *buf = NULL;
int len, res;
- int fd = xopen(modules, O_RDONLY);
+ int fd = xopenro(modules);
+
+ // TODO xreadfile()
len = fdlength(fd);
buf = xmalloc(len);
*
* Copyright 2013 Bilal Qureshi <bilal.jmi@gmail.com>
*
- * No Standard
+ * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/more.html
-USE_MORE(NEWTOY(more, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_MORE(NEWTOY(more, 0, TOYFLAG_USR|TOYFLAG_BIN))
config MORE
bool "more"
default n
help
- usage: more [FILE]...
+ usage: more [FILE...]
- View FILE (or stdin) one screenful at a time.
+ View FILE(s) (or stdin) one screenful at a time.
*/
#define FOR_more
static void signal_handler(int sig)
{
+ // Reset the terminal whether we were signalled or exited normally.
tcsetattr(TT.cin_fd, TCSANOW, &TT.inf);
+
+ if (sig == 0) _exit(0);
+
+ // We were actually signalled, so move to a new line and re-raise the signal.
xputc('\n');
signal(sig, SIG_DFL);
raise(sig);
static void do_cat_operation(int fd, char *name)
{
- char *buf = NULL;
-
if (toys.optc > 1) show_file_header(name);
- for (; (buf = get_line(fd)); free(buf)) printf("%s\n", buf);
+ xsendfile(fd, 1);
}
void more_main()
struct termios newf;
FILE *fp, *cin;
- if (!isatty(STDOUT_FILENO) || !(cin = fopen("/dev/tty", "r"))) {
+ if (!isatty(1) || !(cin = fopen("/dev/tty", "r"))) {
loopfiles(toys.optargs, do_cat_operation);
return;
}
}
putchar(ch);
- if (ch == '\t') col = (col | 0x7) + 1; else col++;
+ if (ch == '\t') col = (col | 0x7) + 1;
+ else col++;
if (col == cols) putchar(ch = '\n');
if (ch == '\n') {
col = 0;
+++ /dev/null
-/* 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 (!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, basename_r(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
-}
config OPENVT
bool "openvt"
default n
+ depends on TOYBOX_FORK
help
usage: openvt [-c N] [-sw] [command [command_options]]
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);
--- /dev/null
+/* resize.c - Set maximum terminal width and height
+ *
+ *
+
+USE_RESIZE(NEWTOY(resize, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_USR))
+
+config RESIZE
+ bool "resize"
+ default n
+ help
+ usage: resize
+
+ reset terminal to maximum width and height
+
+*/
+
+#define FOR_resize
+#include "toys.h"
+
+void resize_main(void)
+{
+ struct winsize w = { 0, 0, 0, 0 };
+ struct termios *old = (struct termios *)toybuf;
+ struct termios new;
+
+ tcgetattr(2, old);
+ memcpy(&new, old, sizeof(new));
+ new.c_cflag |= (CLOCAL | CREAD);
+ new.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+ tcsetattr(2, TCSANOW, &new);
+
+ // set cursor to 999,999, read back where it landed
+ fprintf(stderr, "\0337\033[r\033[999;999H\033[6n");
+ scanf("\033[%hu;%huR", &w.ws_row, &w.ws_col);
+ fprintf(stderr, "\0338");
+
+ ioctl(2, TIOCSWINSZ, &w);
+ tcsetattr(2, TCSANOW, old);
+}
*
* Things like the bash man page are good to read too.
*
+ * TODO: "make sh" doesn't work (nofork builtins need to be included)
+ * TODO: test that $PS1 color changes work without stupid \[ \] hack
+ * TODO: make fake pty wrapper for test infrastructure
* TODO: // Handle embedded NUL bytes in the command line.
+ * TODO: var=val command
+ * existing but considered builtins: false kill pwd true
+ * buitins: alias bg command fc fg getopts jobs newgrp read umask unalias wait
+ * "special" builtins: break continue : . eval exec export readonly return set
+ * shift times trap unset
+ * | & ; < > ( ) $ ` \ " ' <space> <tab> <newline>
+ * * ? [ # ~ = %
+ * ! { } case do done elif else esac fi for if in then until while
+ * [[ ]] function select
+ * $@ $* $# $? $- $$ $! $0
+ * ENV HOME IFS LANG LC_ALL LINENO PATH PPID PS1 PS2 PS4 PWD
+ * label:
+ * TODO: test exit from "trap EXIT" doesn't recurse
USE_SH(NEWTOY(cd, NULL, TOYFLAG_NOFORK))
USE_SH(NEWTOY(exit, NULL, TOYFLAG_NOFORK))
-c command line to execute
-i interactive mode (default when STDIN is a tty)
-config EXIT
- bool
- default n
- depends on SH
- help
- usage: exit [status]
-
- Exit shell. If no return value supplied on command line, use value
- of most recent command, or 0 if none.
-
config CD
bool
default n
-P Physical path: resolve symlinks in path.
-L Local path: .. trims directories off $PWD (default).
-*/
-
-/*
-This level of micromanagement is silly, it adds more complexity than it's
-worth. (Not just to the code, but decision fatigue configuring it.)
-
-That said, the following list is kept for the moment as a todo list of
-features I need to implement.
-
-config SH_PROFILE
- bool "Profile support"
- default n
- depends on SH_TTY
- help
- Read /etc/profile and ~/.profile when running interactively.
-
- Also enables the built-in command "source".
-
-config SH_JOBCTL
- bool "Job Control (fg, bg, jobs)"
- default n
- depends on SH_TTY
- help
- Add job control to toysh. This lets toysh handle CTRL-Z, and enables
- the built-in commands "fg", "bg", and "jobs".
-
- With pipe support, enable use of "&" to run background processes.
-
-config SH_FLOWCTL
- bool "Flow control (if, while, for, functions)"
- default n
- depends on SH
- help
- Add flow control to toysh. This enables the if/then/else/fi,
- while/do/done, and for/do/done constructs.
-
- With pipe support, this enables the ability to define functions
- using the "function name" or "name()" syntax, plus curly brackets
- "{ }" to group commands.
-
-config SH_QUOTES
- bool "Smarter argument parsing (quotes)"
- default n
- depends on SH
- help
- Add support for parsing "" and '' style quotes to the toysh command
- parser, with lets arguments have spaces in them.
-
-config SH_WILDCARDS
- bool "Wildcards ( ?*{,} )"
- default n
- depends on SH_QUOTES
- help
- Expand wildcards in argument names, ala "ls -l *.t?z" and
- "rm subdir/{one,two,three}.txt".
-
-config SH_PROCARGS
- bool "Executable arguments ( `` and $() )"
- default n
- depends on SH_QUOTES
- help
- Add support for executing arguments contianing $() and ``, using
- the output of the command as the new argument value(s).
-
- (Bash calls this "command substitution".)
-
-config SH_ENVVARS
- bool "Environment variable support"
- default n
- depends on SH_QUOTES
- help
- Substitute environment variable values for $VARNAME or ${VARNAME},
- and enable the built-in command "export".
-
-config SH_LOCALS
- bool "Local variables"
- default n
- depends on SH_ENVVARS
- help
- Support for local variables, fancy prompts ($PS1), the "set" command,
- and $?.
-
-config SH_ARRAYS
- bool "Array variables"
- default n
- depends on SH_LOCALS
- help
- Support for ${blah[blah]} style array variables.
-config SH_PIPES
- bool "Pipes and redirects ( | > >> < << & && | || () ; )"
+config EXIT
+ bool
default n
depends on SH
help
- Support multiple commands on the same command line. This includes
- | pipes, > >> < redirects, << here documents, || && conditional
- execution, () subshells, ; sequential execution, and (with job
- control) & background processes.
+ usage: exit [status]
-config SH_BUILTINS
- bool "Builtin commands"
- default n
- depends on SH
- help
- Adds the commands exec, fg, bg, help, jobs, pwd, export, source, set,
- unset, read, alias.
+ Exit shell. If no return value supplied on command line, use value
+ of most recent command, or 0 if none.
*/
#define FOR_sh
GLOBALS(
char *command;
-)
-// A single executable, its arguments, and other information we know about it.
-#define SH_FLAG_EXIT 1
-#define SH_FLAG_SUSPEND 2
-#define SH_FLAG_PIPE 4
-#define SH_FLAG_AND 8
-#define SH_FLAG_OR 16
-#define SH_FLAG_AMP 32
-#define SH_FLAG_SEMI 64
-#define SH_FLAG_PAREN 128
+ long lineno;
+)
// What we know about a single process.
struct command {
int cmdlinelen; // How long is cmdline?
};
+void cd_main(void)
+{
+ char *dest = *toys.optargs ? *toys.optargs : getenv("HOME");
+
+ xchdir(dest ? dest : "/");
+}
+
+void exit_main(void)
+{
+ exit(*toys.optargs ? atoi(*toys.optargs) : 0);
+}
+
// Parse one word from the command line, appending one or more argv[] entries
// to struct command. Handles environment variable substitution and
// substrings. Returns pointer to next used byte, or NULL if it
if (!cmd || !cmd->argc) return;
tl = toy_find(cmd->argv[0]);
+
// Is this command a builtin that should run in this process?
if (tl && (tl->flags & TOYFLAG_NOFORK)) {
struct toy_context temp;
}
}
-void cd_main(void)
+static void do_prompt(void)
{
- char *dest = *toys.optargs ? *toys.optargs : getenv("HOME");
+ char *prompt = getenv("PS1"), *s, c, cc;
- xchdir(dest ? dest : "/");
-}
+ if (!prompt) prompt = "\\$ ";
+ while (*prompt) {
+ c = *(prompt++);
-void exit_main(void)
-{
- exit(*toys.optargs ? atoi(*toys.optargs) : 0);
+ if (c=='!') {
+ if (*prompt=='!') prompt++;
+ else {
+ printf("%ld", TT.lineno);
+ continue;
+ }
+ } else if (c=='\\') {
+ cc = *(prompt++);
+ if (!cc) goto down;
+
+ // \nnn \dD{}hHjlstT@AuvVwW!#$
+ // Ignore bash's "nonprintable" hack; query our cursor position instead.
+ if (cc=='[' || cc==']') continue;
+ else if (cc=='$') putchar(getuid() ? '$' : '#');
+ else if (cc=='h' || cc=='H') {
+ *toybuf = 0;
+ gethostname(toybuf, sizeof(toybuf)-1);
+ if (cc=='h' && (s = strchr(toybuf, '.'))) *s = 0;
+ fputs(toybuf, stdout);
+ } else if (cc=='s') fputs(getbasename(*toys.argv), stdout);
+ else {
+ if (!(c = unescape(cc))) {
+ c = '\\';
+ prompt--;
+ }
+
+ goto down;
+ }
+ continue;
+ }
+down:
+ putchar(c);
+ }
}
void sh_main(void)
{
- FILE *f;
+ FILE *f = 0;
// Set up signal handlers and grab control of this tty.
if (isatty(0)) toys.optflags |= FLAG_i;
- f = *toys.optargs ? xfopen(*toys.optargs, "r") : NULL;
- if (TT.command) handle(TT.command);
+ if (*toys.optargs) f = xfopen(*toys.optargs, "r");
+ if (TT.command) handle(xstrdup(TT.command));
else {
size_t cmdlen = 0;
for (;;) {
- char *prompt = getenv("PS1"), *command = 0;
+ char *command = 0;
// TODO: parse escapes in prompt
- if (!f) printf("%s", prompt ? prompt : "$ ");
+ if (!f) do_prompt();
if (1 > getline(&command, &cmdlen, f ? f : stdin)) break;
handle(command);
free(command);
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);
else if (S_ISFIFO(st->st_mode)) hdr.type = '6';
else if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
hdr.type = (S_ISCHR(st->st_mode))?'3':'4';
- itoo(hdr.major, sizeof(hdr.major), major(st->st_rdev));
- itoo(hdr.minor, sizeof(hdr.minor), minor(st->st_rdev));
+ itoo(hdr.major, sizeof(hdr.major), dev_major(st->st_rdev));
+ itoo(hdr.minor, sizeof(hdr.minor), dev_minor(st->st_rdev));
} else {
error_msg("unknown file type '%o'", st->st_mode & S_IFMT);
return;
file_hdr->gname = xstrdup(tar.gname);
maj = otoi(tar.major, sizeof(tar.major));
min = otoi(tar.minor, sizeof(tar.minor));
- file_hdr->device = makedev(maj, min);
+ file_hdr->device = dev_makedev(maj, min);
if (tar.type <= '7') {
if (tar.link[0]) {
for (tmp = TT.inc; tmp; tmp = tmp->next) {
TT.handle = tar_hdl;
//recurse thru dir and add files to archive
- dirtree_handle_callback(dirtree_start(tmp->arg, toys.optflags & FLAG_h),
+ dirtree_flagread(tmp->arg, DIRTREE_SYMFOLLOW*!!(toys.optflags&FLAG_h),
add_to_tar);
}
memset(toybuf, 0, 1024);
config TCPSVD
bool "tcpsvd"
default n
+ depends on TOYBOX_FORK
help
usage: tcpsvd [-hEv] [-c N] [-C N[:MSG]] [-b N] [-u User] [-l Name] IP Port Prog
usage: udpsvd [-hEv] [-c N] [-u User] [-l Name] IP Port Prog
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);
- (t1.tv_sec * USEC + t1.tv_usec);
if (pfd[0].revents) {
- unsigned addrlen = sizeof(struct sockaddr_storage);
+ socklen_t addrlen = sizeof(struct sockaddr_storage);
int rcv_len, icmp_res = 0;
rcv_len = recvfrom(TT.recv_sock, toybuf, sizeof(toybuf),
--- /dev/null
+/* wget.c - Simple downloader to get the resource file in HTTP server
+ *
+ * Copyright 2016 Lipi C.H. Lee <lipisoft@gmail.com>
+ *
+
+USE_WGET(NEWTOY(wget, "f:", TOYFLAG_USR|TOYFLAG_BIN))
+
+config WGET
+ bool "wget"
+ default n
+ help
+ usage: wget -f filename URL
+ -f filename: specify the filename to be saved
+ URL: HTTP uniform resource location and only HTTP, not HTTPS
+
+ examples:
+ wget -f index.html http://www.example.com
+ wget -f sample.jpg http://www.example.com:8080/sample.jpg
+*/
+
+#define FOR_wget
+#include "toys.h"
+
+GLOBALS(
+ char *filename;
+)
+
+// extract hostname from url
+static unsigned get_hn(const char *url, char *hostname) {
+ unsigned i;
+
+ for (i = 0; url[i] != '\0' && url[i] != ':' && url[i] != '/'; i++) {
+ if(i >= 1024) error_exit("too long hostname in URL");
+ hostname[i] = url[i];
+ }
+ hostname[i] = '\0';
+
+ return i;
+}
+
+// extract port number
+static unsigned get_port(const char *url, char *port, unsigned url_i) {
+ unsigned i;
+
+ for (i = 0; url[i] != '\0' && url[i] != '/'; i++, url_i++) {
+ if('0' <= url[i] && url[i] <= '9') port[i] = url[i];
+ else error_exit("wrong decimal port number");
+ }
+ if(i <= 6) port[i] = '\0';
+ else error_exit("too long port number");
+
+ return url_i;
+}
+
+// get http infos in URL
+static void get_info(const char *url, char* hostname, char *port, char *path) {
+ unsigned i = 7, len;
+
+ if (strncmp(url, "http://", i)) error_exit("only HTTP support");
+ len = get_hn(url+i, hostname);
+ i += len;
+
+ // get port if exists
+ if (url[i] == ':') {
+ i++;
+ i = get_port(url+i, port, i);
+ } else strcpy(port, "80");
+
+ // get uri in URL
+ if (url[i] == '\0') strcpy(path, "/");
+ else if (url[i] == '/') {
+ if (strlen(url+i) < 1024) strcpy(path, url+i);
+ else error_exit("too long path in URL");
+ } else error_exit("wrong URL");
+}
+
+// connect to any IPv4 or IPv6 server
+static int conn_svr(const char *hostname, const char *port) {
+ struct addrinfo hints, *result, *rp;
+ int sock;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+ hints.ai_protocol = 0;
+
+ if ((errno = getaddrinfo(hostname, port, &hints, &result)))
+ error_exit("getaddrinfo: %s", gai_strerror(errno));
+
+ // try all address list(IPv4 or IPv6) until success
+ for (rp = result; rp; rp = rp->ai_next) {
+ if ((sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol))
+ == -1) {
+ perror_msg("socket error");
+ continue;
+ }
+ if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
+ break; // succeed in connecting to any server IP
+ else perror_msg("connect error");
+ close(sock);
+ }
+ freeaddrinfo(result);
+ if(!rp) error_exit("can't connect");
+
+ return sock;
+}
+
+// make HTTP request header field
+static void mk_fld(char *name, char *value) {
+ strcat(toybuf, name);
+ strcat(toybuf, ": ");
+ strcat(toybuf, value);
+ strcat(toybuf, "\r\n");
+}
+
+// get http response body starting address and its length
+static char *get_body(ssize_t len, ssize_t *body_len) {
+ int i;
+
+ for (i = 0; i < len-4; i++)
+ if (!strncmp(toybuf+i, "\r\n\r\n", 4)) break;
+
+ *body_len = len - i - 4;
+ return toybuf+i+4;
+}
+
+void wget_main(void)
+{
+ int sock;
+ FILE *fp;
+ ssize_t len, body_len;
+ char *body, *result, *rc, *r_str;
+ char ua[18] = "toybox wget/", ver[6], hostname[1024], port[6], path[1024];
+
+ // TODO extract filename to be saved from URL
+ if (!(toys.optflags & FLAG_f)) help_exit("no filename");
+ if (fopen(TT.filename, "r")) perror_exit("file already exists");
+
+ if(!toys.optargs[0]) help_exit("no URL");
+ get_info(toys.optargs[0], hostname, port, path);
+
+ sock = conn_svr(hostname, port);
+
+ // compose HTTP request
+ sprintf(toybuf, "GET %s HTTP/1.1\r\n", path);
+ mk_fld("Host", hostname);
+ strncpy(ver, TOYBOX_VERSION, 5);
+ strcat(ua, ver);
+ mk_fld("User-Agent", ua);
+ mk_fld("Connection", "close");
+ strcat(toybuf, "\r\n");
+
+ // send the HTTP request
+ len = strlen(toybuf);
+ if (write(sock, toybuf, len) != len) perror_exit("write error");
+
+ // read HTTP response
+ if ((len = read(sock, toybuf, 4096)) == -1) perror_exit("read error");
+ if (!strstr(toybuf, "\r\n\r\n")) error_exit("too long HTTP response");
+ body = get_body(len, &body_len);
+ result = strtok(toybuf, "\r");
+ strtok(result, " ");
+ rc = strtok(NULL, " ");
+ r_str = strtok(NULL, " ");
+
+ // HTTP res code check
+ // TODO handle HTTP 302 Found(Redirection)
+ if (strcmp(rc, "200")) error_exit("res: %s(%s)", rc, r_str);
+
+ if (!(fp = fopen(TT.filename, "w"))) perror_exit("fopen error");
+ if (fwrite(body, 1, body_len, fp) != body_len)
+ error_exit("fwrite error");
+ while ((len = read(sock, toybuf, 4096)) > 0)
+ if (fwrite(toybuf, 1, len, fp) != len)
+ error_exit("fwrite error");
+ if (fclose(fp) == EOF) perror_exit("fclose error");
+}
char *base = basename(*toys.optargs), *suffix = toys.optargs[1];
// chop off the suffix if provided
- if (suffix) {
+ if (suffix && *suffix) {
long bl = strlen(base), sl = strlen(suffix);
char *s = base + bl - sl;
*(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_handle_callback(dirtree_start(*s, toys.optflags&(FLAG_H|FLAG_L)),
- do_chgrp);;
+ dirtree_flagread(*s, DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)),
+ do_chgrp);
if (CFG_TOYBOX_FREE && ischown) free(own);
}
*
* 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"
return;
}
+ toys.exitval = 0;
+
for (;;) {
len1 = readall(TT.fd, toybuf, size);
len2 = readall(fd, buf2, size);
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;
}
}
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);
}
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]);
}
*
* Posix says "cp -Rf dir file" shouldn't delete file, but our -f does.
*
+ * Deviations from posix: -adlnrsvF, --preserve... about half the
+ * functionality in this cp isn't in posix. Posix is stuck in the 1970's.
+ *
* TODO: --preserve=links
* TODO: what's this _CP_mode system.posix_acl_ business? We chmod()?
// options shared between mv/cp must be in same order (right to left)
// for FLAG macros to work out right in shared infrastructure.
-USE_CP(NEWTOY(cp, "<2"USE_CP_PRESERVE("(preserve):;")"RHLPp"USE_CP_MORE("rdaslvnF(remove-destination)")"fi[-HLP"USE_CP_MORE("d")"]"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))
-USE_MV(NEWTOY(mv, "<2"USE_CP_MORE("vnF")"fi"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))
+USE_CP(NEWTOY(cp, "<2"USE_CP_PRESERVE("(preserve):;")"RHLPprdaslvnF(remove-destination)fi[-HLPd][-ni]", TOYFLAG_BIN))
+USE_MV(NEWTOY(mv, "<2vnF(remove-destination)fi[-ni]", TOYFLAG_BIN))
USE_INSTALL(NEWTOY(install, "<1cdDpsvm:o:g:", TOYFLAG_USR|TOYFLAG_BIN))
config CP
bool "cp"
default y
help
- usage: cp [-fipRHLP] SOURCE... DEST
+ usage: cp [-adlnrsvfipRHLP] SOURCE... DEST
Copy files from SOURCE to DEST. If more than one SOURCE, DEST must
be a directory.
-H Follow symlinks listed on command line
-L Follow all symlinks
-P Do not follow symlinks [default]
-
-config CP_MORE
- bool "cp -adlnrsv options"
- default y
- depends on CP
- help
- usage: cp [-adlnrsv]
-
-a same as -dpr
-d don't dereference symlinks
-l hard link instead of copy
config CP_PRESERVE
bool "cp --preserve support"
default y
- depends on CP_MORE
+ depends on CP
help
usage: cp [--preserve=motcxa]
config MV
bool "mv"
default y
- depends on CP
help
- usage: mv [-fi] SOURCE... DEST"
+ usage: mv [-fivn] SOURCE... DEST"
-f force copy by deleting destination file
-i interactive, prompt before overwriting existing DEST
-
-config MV_MORE
- bool
- default y
- depends on MV && CP_MORE
- help
- usage: mv [-vn]
-
-v verbose
-n no clobber (don't overwrite DEST)
config INSTALL
bool "install"
default y
- depends on CP && CP_MORE
help
usage: install [-dDpsv] [-o USER] [-g GROUP] [-m MODE] [SOURCE...] DEST
-v Verbose
*/
+#define FORCE_FLAGS
#define FOR_cp
#include "toys.h"
-#if CFG_CP_PRESERVE
-#include <sys/xattr.h>
-#endif
GLOBALS(
union {
return 0;
}
- // Handle -inv
+ // Handle -invF
if (!faccessat(cfd, catch, F_OK, 0) && !S_ISDIR(cst.st_mode)) {
char *s;
// 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;
rc = fchownat(cfd, catch, try->st.st_uid, try->st.st_gid,
AT_SYMLINK_NOFOLLOW);
else rc = fchown(fdout, try->st.st_uid, try->st.st_gid);
- if (rc) {
+ if (rc && !geteuid()) {
char *pp;
perror_msg("chown '%s'", pp = dirtree_path(try, 0));
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;
}
// Loop through sources
for (i=0; i<toys.optc; i++) {
- struct dirtree *new;
char *src = toys.optargs[i];
int rc = 1;
errno = EXDEV;
if (CFG_MV && toys.which->name[0] == 'm') {
- if (!(toys.optflags & FLAG_f)) {
+ int force = toys.optflags & FLAG_f, no_clobber = toys.optflags & FLAG_n;
+
+ if (!force || no_clobber) {
struct stat st;
+ int exists = !stat(TT.destname, &st);
- // Technically "is writeable" is more complicated (022 is not writeable
- // by the owner, just everybody _else_) but I don't care.
- if (!stat(TT.destname, &st)
- && ((toys.optflags & FLAG_i) || !(st.st_mode & 0222)))
- {
+ // Prompt if -i or file isn't writable. Technically "is writable" is
+ // more complicated (022 is not writeable by the owner, just everybody
+ // _else_) but I don't care.
+ if (exists && ((toys.optflags & FLAG_i) || !(st.st_mode & 0222))) {
fprintf(stderr, "%s: overwrite '%s'", toys.which->name, TT.destname);
if (!yesno(1)) rc = 0;
else unlink(TT.destname);
}
+ // if -n and dest exists, don't try to rename() or copy
+ if (exists && no_clobber) rc = 0;
}
-
if (rc) rc = rename(src, TT.destname);
}
- // Skip nonexistent sources
+ // Copy if we didn't mv, skipping nonexistent sources
if (rc) {
- if (errno!=EXDEV ||
- !(new = dirtree_start(src, toys.optflags&(FLAG_H|FLAG_L))))
+ if (errno!=EXDEV || dirtree_flagread(src, DIRTREE_SHUTUP+
+ DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)), TT.callback))
perror_msg("bad '%s'", src);
- else dirtree_handle_callback(new, TT.callback);
}
if (destdir) free(TT.destname);
}
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();
// Read header and name.
xreadall(afd, toybuf, 110);
+ if (memcmp(toybuf, "070701", 6)) error_exit("bad cpio magic");
tofree = name = strpad(afd, x8u(toybuf+94), 110);
if (!strcmp("TRAILER!!!", name)) {
if (CFG_TOYBOX_FREE) free(tofree);
close(fd);
}
} else if (!test)
- err = mknod(name, mode, makedev(x8u(toybuf+78), x8u(toybuf+86)));
+ err = mknod(name, mode, dev_makedev(x8u(toybuf+78), x8u(toybuf+86)));
// Set ownership and timestamp.
if (!test && !err) {
llen = sprintf(toybuf,
"070701%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
(int)st.st_ino, st.st_mode, st.st_uid, st.st_gid, (int)st.st_nlink,
- (int)st.st_mtime, (int)st.st_size, major(st.st_dev),
- minor(st.st_dev), major(st.st_rdev), minor(st.st_rdev), nlen, 0);
+ (int)st.st_mtime, (int)st.st_size, dev_major(st.st_dev),
+ dev_minor(st.st_dev), dev_major(st.st_rdev), dev_minor(st.st_rdev),
+ nlen, 0);
xwrite(afd, toybuf, llen);
xwrite(afd, name, nlen);
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);
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");
}
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;
}
// Loop over command line arguments, recursing through children
for (args = toys.optc ? toys.optargs : noargs; *args; args++)
- dirtree_handle_callback(dirtree_start(*args, toys.optflags&(FLAG_H|FLAG_L)),
+ dirtree_flagread(*args, DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)),
do_du);
if (toys.optflags & FLAG_c) print(TT.total*512, 0);
* 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))
*
* 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"
--- /dev/null
+/* file.c - describe file type
+ *
+ * Copyright 2016 The Android Open Source Project
+ *
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/file.html
+
+USE_FILE(NEWTOY(file, "<1hL[!hL]", TOYFLAG_USR|TOYFLAG_BIN))
+
+config FILE
+ bool "file"
+ default y
+ help
+ 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
+#include "toys.h"
+
+GLOBALS(
+ int max_name_len;
+)
+
+// 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, struct stat *sb)
+{
+ int endian = toybuf[5], bits = toybuf[4], i, j;
+ int64_t (*elf_int)(void *ptr, unsigned size) = peek_le;
+ // Values from include/linux/elf-em.h (plus arch/*/include/asm/elf.h)
+ // Names are linux/arch/ directory (sometimes before 32/64 bit merges)
+ struct {int val; char *name;} type[] = {{0x9026, "alpha"}, {93, "arc"},
+ {195, "arcv2"}, {40, "arm"}, {183, "arm64"}, {0x18ad, "avr32"},
+ {106, "blackfin"}, {140, "c6x"}, {23, "cell"}, {76, "cris"},
+ {0x5441, "frv"}, {46, "h8300"}, {164, "hexagon"}, {50, "ia64"},
+ {88, "m32r"}, {0x9041, "m32r"}, {4, "m68k"}, {174, "metag"},
+ {0xbaab, "microblaze"}, {8, "mips"}, {10, "mips-old"}, {89, "mn10300"},
+ {0xbeef, "mn10300-old"}, {113, "nios2"}, {92, "openrisc"},
+ {0x8472, "openrisc-old"}, {15, "parisc"}, {20, "ppc"}, {21, "ppc64"},
+ {22, "s390"}, {0xa390, "s390-old"}, {135, "score"}, {42, "sh"},
+ {2, "sparc"}, {18, "sparc8+"}, {43, "sparc9"}, {188, "tile"},
+ {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 ");
+
+ // executable (ELF says this is short but reality says byte, not MSB swapped)
+ i = toybuf[16];
+ if (i == 1) printf("relocatable");
+ else if (i == 2) printf("executable");
+ else if (i == 3) printf("shared object");
+ else if (i == 4) printf("core dump");
+ else printf("(bad type %d)", i);
+ printf(", ");
+
+ // "64-bit"
+ if (bits == 1) printf("32-bit ");
+ else if (bits == 2) printf("64-bit ");
+ else {
+ printf("(bad class %d) ", bits);
+ bits = 0;
+ }
+
+ // "LSB"
+ if (endian == 1) printf("LSB ");
+ else if (endian == 2) {
+ printf("MSB ");
+ elf_int = peek_be;
+ } else {
+ printf("(bad endian %d) \n", endian);
+ endian = 0;
+ }
+
+ // e_machine, ala "x86", from big table above
+ j = elf_int(toybuf+18, 2);
+ for (i = 0; i<ARRAY_LEN(type); i++) if (j==type[i].val) break;
+ if (i<ARRAY_LEN(type)) printf("%s", type[i].name);
+ else printf("(unknown arch %d)", j);
+
+ bits--;
+ // 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 (!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);
+
+ 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, struct stat *sb)
+{
+ char *s;
+ int len = read(fd, s = toybuf, sizeof(toybuf)-256);
+ int magic;
+
+ if (len<0) perror_msg("%s", name);
+
+ 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);
+
+ xprintf("PNG image data");
+
+ // The IHDR chunk comes first: https://www.w3.org/TR/PNG/#11IHDR
+ s += 4;
+ if (chunk_length == 13 && strstart(&s, "IHDR")) {
+ // https://www.w3.org/TR/PNG/#6Colour-values
+ char *c = 0, *colors[] = {"grayscale", 0, "color RGB", "indexed color",
+ "grayscale with alpha", 0, "color RGBA"};
+
+ if (s[9]<ARRAY_LEN(colors)) c = colors[s[9]];
+ if (!c) c = "unknown";
+
+ xprintf(", %d x %d, %d-bit/%s, %sinterlaced", (int)peek_be(s, 4),
+ (int)peek_be(s+4, 4), s[8], c, s[12] ? "" : "non-");
+ }
+
+ xputc('\n');
+
+ // https://www.w3.org/Graphics/GIF/spec-gif89a.txt
+ } else if (len>16 && (strstart(&s, "GIF87a") || strstart(&s, "GIF89a")))
+ xprintf("GIF image data, %d x %d\n",
+ (int)peek_le(s, 2), (int)peek_le(s+8, 2));
+
+ // TODO: parsing JPEG for width/height is harder than GIF or PNG.
+ else if (len>32 && memcmp(toybuf, "\xff\xd8", 2) == 0)
+ xprintf("JPEG image data\n");
+
+ // https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
+ else if (len>8 && strstart(&s, "\xca\xfe\xba\xbe"))
+ xprintf("Java class file, version %d.%d\n",
+ (int)peek_be(s+2, 2), (int)peek_be(s, 2));
+
+ // https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt
+ // the lengths for cpio are size of header + 9 bytes, since any valid
+ // cpio archive ends with a record for "TARGET!!!"
+ else if (len>85 && strstart(&s, "07070")) {
+ char *cpioformat = "unknown type";
+ if (toybuf[5] == '7') cpioformat = "pre-SVR4 or odc";
+ 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)) {
+ 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)) {
+ 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")) {
+ 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 {
+ char *what = 0;
+ int i, bytes;
+
+ // If shell script, report which interpreter
+ if (len>3 && strstart(&s, "#!")) {
+ // Whitespace is allowed between the #! and the interpreter
+ while (isspace(*s)) s++;
+ if (strstart(&s, "/usr/bin/env")) while (isspace(*s)) s++;
+ for (what = s; (s-toybuf)<len && !isspace(*s); s++);
+ strcpy(s, " script");
+
+ // Distinguish ASCII text, UTF-8 text, or data
+ } else for (i = 0; i<len; ++i) {
+ if (!(isprint(toybuf[i]) || isspace(toybuf[i]))) {
+ wchar_t wc;
+ if ((bytes = mbrtowc(&wc, s+i, len-i, 0))>0 && wcwidth(wc)>=0) {
+ i += bytes-1;
+ if (!what) what = "UTF-8 text";
+ } else {
+ what = "data";
+ break;
+ }
+ }
+ }
+ xputs(what ? what : "ASCII text");
+ }
+}
+
+void file_main(void)
+{
+ char **arg;
+
+ for (arg = toys.optargs; *arg; ++arg) {
+ int name_len = strlen(*arg);
+
+ if (name_len > TT.max_name_len) TT.max_name_len = name_len;
+ }
+
+ // Can't use loopfiles here because it doesn't call function when can't open
+ for (arg = toys.optargs; *arg; arg++) {
+ 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 (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);
+ continue;
+ }
+ } 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";
+ else if (S_ISLNK(sb.st_mode)) what = "symbolic link";
+ else what = "unknown";
+ }
+
+ xputs(what);
+ }
+}
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)) {
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;
// Handle path expansion and case flattening
if (new && s[i] == 'p') name = path = dirtree_path(new, 0);
if (i) {
- if (check || !new) {
- if (name) name = strlower(name);
- if (!new) {
- dlist_add(&TT.argdata, name);
- free(path);
- } else arg = ((struct double_list *)llist_pop(&argdata))->data;
- }
+ if ((check || !new) && name) name = strlower(name);
+ if (!new) dlist_add(&TT.argdata, name);
+ else arg = ((struct double_list *)llist_pop(&argdata))->data;
}
if (check) {
test = !fnmatch(arg, name, FNM_PATHNAME*(s[i] == 'p'));
- free(path);
if (i) free(name);
}
+ free(path);
} else if (!strcmp(s, "perm")) {
if (check) {
char *m = ss[1];
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;
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 {
// Loop through paths
for (i = 0; i < len; i++)
- dirtree_handle_callback(dirtree_start(ss[i], toys.optflags&(FLAG_H|FLAG_L)),
+ dirtree_flagread(ss[i], DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L)),
do_find);
execdir(0, 1);
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;
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);
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) {
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);
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) {
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);
}
else printf("%u", u);
if (done) {
xputc('\n');
- exit(0);
+ xexit();
}
}
}
if (toys.optflags&FLAG_G) {
xputc('\n');
- exit(0);
+ xexit();
}
}
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/ls.html
-USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")"ZgoACFHLRSacdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL]", TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")"ZgoACFHLRSabcdfhiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL][!qb]", TOYFLAG_BIN|TOYFLAG_LOCALE))
config LS
bool "ls"
list files
what to show:
- -a all files including .hidden -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
+ -a all files including .hidden -b escape nongraphic chars
+ -c use ctime for timestamps -d directory, not contents
+ -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)
- -g like -l but no owner -h human readable sizes
- -l long (show full details) -m comma separated
- -n like -l but numeric uid/gid -o like -l but no group
- -x columns (horizontal sort)
+ -1 list one file per line -C columns (sorted vertically)
+ -g like -l but no owner -h human readable sizes
+ -l long (show full details) -m comma separated
+ -n like -l but numeric uid/gid -o like -l but no group
+ -x columns (horizontal sort)
sorting (default is alphabetical):
- -f unsorted -r reverse -t timestamp -S size
+ -f unsorted -r reverse -t timestamp -S size
config LS_COLOR
bool "ls --color"
unsigned screen_width;
int nl_title;
- char uid_buf[12], gid_buf[12];
+ char *escmore;
)
-// Does two things: 1) Returns wcwidth(utf8) version of strlen,
-// 2) replaces unprintable characters input string with '?' wildcard char.
-int strwidth(char *s)
+// Callback from crunch_str to represent unprintable chars
+int crunch_qb(FILE *out, int cols, int wc)
{
- int total = 0, width, len;
- wchar_t c;
-
- if (!CFG_TOYBOX_I18N) {
- total = strlen(s);
- if (toys.optflags & FLAG_q) for (; *s; s++) if (!isprint(*s)) *s = '?';
- } else while (*s) {
- len = mbrtowc(&c, s, MB_CUR_MAX, 0);
- if (len < 1 || (width = wcwidth(c)) < 0) {
- total++;
- if (toys.optflags & FLAG_q) *s = '?';
- s++;
- } else {
- s += len;
- total += width;
+ unsigned len = 1;
+ char buf[32];
+
+ if (toys.optflags&FLAG_q) *buf = '?';
+ else {
+ if (wc<256) *buf = wc;
+ // scrute the inscrutable, eff the ineffable, print the unprintable
+ else len = wcrtomb(buf, wc, 0);
+ if (toys.optflags&FLAG_b) {
+ char *to = buf, *from = buf+24;
+ int i, j;
+
+ memcpy(from, to, 8);
+ for (i = 0; i<len; i++) {
+ *to++ = '\\';
+ if (strchr(TT.escmore, from[i])) *to++ = from[i];
+ else if (-1 != (j = stridx("\\\a\b\033\f\n\r\t\v", from[i])))
+ *to++ = "\\abefnrtv"[j];
+ else to += sprintf(to, "%03o", from[i]);
+ }
+ len = to-buf;
}
}
- return total;
+ if (cols<len) len = cols;
+ if (out) fwrite(buf, len, 1, out);
+
+ return len;
+}
+
+// Returns wcwidth(utf8) version of strlen with -qb escapes
+int strwidth(char *s)
+{
+ return crunch_str(&s, INT_MAX, 0, TT.escmore, crunch_qb);
}
+void qbstr(char *s, int width)
+{
+ draw_trim_esc(s, width, abs(width), TT.escmore, crunch_qb);
+}
+
static char endtype(struct stat *st)
{
mode_t mode = st->st_mode;
return 0;
}
-static char *getusername(uid_t uid)
-{
- struct passwd *pw = getpwuid(uid);
-
- sprintf(TT.uid_buf, "%u", (unsigned)uid);
- return pw ? pw->pw_name : TT.uid_buf;
-}
-
-static char *getgroupname(gid_t gid)
+static int numlen(long long ll)
{
- struct group *gr = getgrgid(gid);
-
- sprintf(TT.gid_buf, "%u", (unsigned)gid);
- return gr ? gr->gr_name : TT.gid_buf;
+ return snprintf(0, 0, "%llu", ll);
}
-static int numlen(long long ll)
+static int print_with_h(char *s, long long value, int units)
{
- 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
if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
// cheating slightly here: assuming minor is always 3 digits to avoid
// tracking another column
- len[5] = numlen(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);
+ len[5] = numlen(dev_major(st->st_rdev))+5;
+ } 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;
}
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;
char tmp[64];
if (-1 == dirfd) {
- strwidth(indir->name);
perror_msg_raw(indir->name);
return;
// 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.
- indir->dirfd = dup(dirfd);
- dirtree_recurse(indir, filter, DIRTREE_SYMFOLLOW*!!(flags&FLAG_L));
- }
+ // 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
}
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);
}
}
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]) {
memset(toybuf, ' ', 256);
width = 0;
for (ul = 0; ul<dtlen; ul++) {
+ int ii;
unsigned curcol, color = 0;
unsigned long next = next_column(ul, dtlen, columns, &curcol);
struct stat *st = &(sort[next]->st);
mode_t mode = st->st_mode;
- char et = endtype(st);
+ char et = endtype(st), *ss;
// Skip directories at the top of the tree when -d isn't set
if (S_ISDIR(mode) && !indir->parent && !(flags & FLAG_d)) continue;
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;
- char *ss;
// (long) is to coerce the st types into something we know we can print.
mode_to_string(mode, tmp);
// print user
if (!(flags&FLAG_g)) {
- if (flags&FLAG_n) sprintf(ss = tmp, "%u", (unsigned)st->st_uid);
- else strwidth(ss = getusername(st->st_uid));
- printf(" %-*s", (int)totals[3], ss);
+ putchar(' ');
+ ii = -totals[3];
+ if (flags&FLAG_n) printf("%*u", ii, (unsigned)st->st_uid);
+ else draw_trim_esc(getusername(st->st_uid), ii, abs(ii), TT.escmore,
+ crunch_qb);
}
// print group
if (!(flags&FLAG_o)) {
- if (flags&FLAG_n) sprintf(ss = tmp, "%u", (unsigned)st->st_gid);
- else strwidth(ss = getgroupname(st->st_gid));
- printf(" %-*s", (int)totals[4], ss);
+ putchar(' ');
+ ii = -totals[4];
+ if (flags&FLAG_n) printf("%*u", ii, (unsigned)st->st_gid);
+ else draw_trim_esc(getgroupname(st->st_gid), ii, abs(ii), TT.escmore,
+ crunch_qb);
}
if (flags & FLAG_Z)
// print major/minor, or size
if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
- printf("% *d,% 4d", totals[5]-4, major(st->st_rdev),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);
+ printf("% *d,% 4d", totals[5]-4, dev_major(st->st_rdev),
+ dev_minor(st->st_rdev));
+ 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);
if (color) printf("\033[%d;%dm", color>>8, color&255);
}
- if (flags & FLAG_q) {
- char *p;
- for (p=sort[next]->name; *p; p++) fputc(isprint(*p) ? *p : '?', stdout);
- } else xprintf("%s", sort[next]->name);
- if (color) xprintf("\033[0m");
+ ss = sort[next]->name;
+ crunch_str(&ss, INT_MAX, stdout, TT.escmore, crunch_qb);
+ if (color) printf("\033[0m");
if ((flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) && S_ISLNK(mode)) {
printf(" -> ");
// 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);
}
}
TT.screen_width = 80;
terminal_size(&TT.screen_width, NULL);
if (TT.screen_width<2) TT.screen_width = 2;
+ if (toys.optflags&FLAG_b) TT.escmore = " \\";
// Do we have an implied -1
if (!isatty(1)) {
if (toys.optflags & FLAG_d) toys.optflags &= ~FLAG_R;
// Iterate through command line arguments, collecting directories and files.
- // Non-absolute paths are relative to current directory.
- TT.files = dirtree_start(0, 0);
+ // Non-absolute paths are relative to current directory. Top of tree is
+ // a dummy node to collect command line arguments into pseudo-directory.
+ TT.files = dirtree_add_node(0, 0, 0);
TT.files->dirfd = AT_FDCWD;
for (s = *toys.optargs ? toys.optargs : noargs; *s; s++) {
- dt = dirtree_start(*s, !(toys.optflags&(FLAG_l|FLAG_d|FLAG_F)) ||
- (toys.optflags&(FLAG_L|FLAG_H)));
+ int sym = !(toys.optflags&(FLAG_l|FLAG_d|FLAG_F))
+ || (toys.optflags&(FLAG_L|FLAG_H));
+
+ dt = dirtree_add_node(0, *s, DIRTREE_SYMFOLLOW*sym);
// note: double_list->prev temporarirly goes in dirtree->parent
if (dt) dlist_add_nomalloc((void *)&TT.files->child, (void *)dt);
}
if (isatty(0)) {
close(0);
- open("/dev/null", O_RDONLY);
+ xopen_stdio("/dev/null", O_RDONLY);
}
xexec(toys.optargs);
}
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/od.html
-USE_OD(NEWTOY(od, "j#vN#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN))
+USE_OD(NEWTOY(od, "j#vw#<1=16N#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN))
config OD
bool "od"
default y
help
- usage: od [-bcdosxv] [-j #] [-N #] [-A doxn] [-t acdfoux[#]]
+ usage: od [-bcdosxv] [-j #] [-N #] [-w #] [-A doxn] [-t acdfoux[#]]
-A Address base (decimal, octal, hexdecimal, none)
-j Skip this many bytes of input
-N Stop dumping after this many bytes
- -t output type a(scii) c(har) d(ecimal) f(loat) o(ctal) u(nsigned) (he)x
+ -t Output type a(scii) c(har) d(ecimal) f(loat) o(ctal) u(nsigned) (he)x
plus optional size in bytes
aliases: -b=-t o1, -c=-t c, -d=-t u2, -o=-t o2, -s=-t d2, -x=-t x2
-v Don't collapse repeated lines together
+ -w Total line width in bytes (default 16).
*/
#define FOR_od
struct arg_list *output_base;
char *address_base;
long max_count;
+ long width;
long jump_bytes;
int address_idx;
unsigned types, leftover, star;
- char *buf;
- uint64_t bufs[4]; // force 64-bit alignment
+ char *buf; // Points to buffers[0] or buffers[1].
+ char *bufs[2]; // Used to detect duplicate lines.
off_t pos;
)
struct odtype *types = (struct odtype *)toybuf;
int i, j, len, pad;
- if (TT.leftover<16) memset(TT.buf+TT.leftover, 0, 16-TT.leftover);
+ if (TT.leftover<TT.width) memset(TT.buf+TT.leftover, 0, TT.width-TT.leftover);
// Handle duplciate lines as *
if (!(flags&FLAG_v) && TT.jump_bytes != TT.pos && TT.leftover
- && !memcmp(TT.bufs, TT.bufs + 2, 16))
+ && !memcmp(TT.bufs[0], TT.bufs[1], TT.width))
{
if (!TT.star) {
xputs("*");
}
// For each output type, print one line
-
for (i=0; i<TT.types; i++) {
for (j = 0; j<len;) {
int bytes = j;
xputc('\n');
}
- // buffer toggle for "same as last time" check.
- TT.buf = (char *)((TT.buf == (char *)TT.bufs) ? TT.bufs+2 : TT.bufs);
+ // Toggle buffer for "same as last time" check.
+ TT.buf = (TT.buf == TT.bufs[0]) ? TT.bufs[1] : TT.bufs[0];
}
// Loop through input files
for(;;) {
char *buf = TT.buf + TT.leftover;
- int len = 16 - TT.leftover;
+ int len = TT.width - TT.leftover;
if (toys.optflags & FLAG_N) {
if (!TT.max_count) break;
}
if (TT.max_count) TT.max_count -= len;
TT.leftover += len;
- if (TT.leftover < 16) break;
+ if (TT.leftover < TT.width) break;
od_outline();
}
{
struct arg_list *arg;
- TT.buf = (char *)TT.bufs;
+ TT.bufs[0] = xzalloc(TT.width);
+ TT.bufs[1] = xzalloc(TT.width);
+ TT.buf = TT.bufs[0];
if (!TT.address_base) TT.address_idx = 2;
else if (0>(TT.address_idx = stridx("ndox", *TT.address_base)))
if (TT.leftover) od_outline();
od_outline();
+
+ if (CFG_TOYBOX_FREE) {
+ free(TT.bufs[0]);
+ free(TT.bufs[1]);
+ }
}
* -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
GLOBALS(
char *infile;
long prefix;
+ char *dir;
struct double_list *current_hunk;
long oldline, oldlen, newline, newlen;
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;
}
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;
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;
}
}
// 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;
// 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 \)
// 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
// 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);
* 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*u*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" "k*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"
default y
help
- usage: ps [-AadeflnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]
+ usage: ps [-AadefLlnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]
List processes.
-P Parent PIDs (--ppid)
-s In session IDs
-t Attached to selected TTYs
+ -T Show threads
-u Owned by USERs
-U Owned by real USERs (before suid)
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
+ -O Add FIELDS to defaults
-Z Include LABEL
- Available -o FIELDs:
+ Command line -o fields:
- ADDR Instruction pointer ARGS Command line (argv[] -path)
- CMD COMM without -f, 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)
- PCPU Percentage of CPU time used PGID Process Group ID
+ 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
PRI Priority (higher is faster) PSR Processor last executed on
RGID Real (before sgid) group ID RGROUP Real (before sgid) group name
s session leader + foreground l multithreaded
STIME Start time of process in hh:mm (size :19 shows yyyy-mm-dd hh:mm:ss)
SZ Memory Size (4k pages needed to completely swap out process)
+ TCNT Thread count TID Thread ID
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 [-m] [ -d seconds ] [ -n iterations ]
+ usage: top [-H] [-k FIELD,] [-o FIELD,] [-s SORT]
Show process activity in real time.
+ -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]
bool
default y
help
- usage: COMMON [-bq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,] [-s SORT]
+ usage: * [-bq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]
-b Batch mode (no tty)
-d Delay SECONDS between each cycle (default 3)
-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)
-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
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;
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;
SLOT_rss2, /*Resident Set Size*/ SLOT_shr, // Shared memory
SLOT_rchar, /*All bytes read*/ SLOT_wchar, // All bytes written
SLOT_rbytes, /*Disk bytes read*/ SLOT_wbytes, // Disk bytes written
- SLOT_swap, /*Swap pages used*/
+ SLOT_swap, /*Swap pages used*/ SLOT_bits, // 32 or 64
+ SLOT_tid, /*Thread ID*/ SLOT_tcount, // Thread count
+ SLOT_pcy, /*Android sched policy*/
+
+ SLOT_count
};
// Data layout in toybuf
struct carveup {
- long long slot[55]; // data from /proc
- unsigned short offset[5]; // offset of fields in str[] (skip name, always 0)
+ long long slot[SLOT_count]; // data (see enum above)
+ unsigned short offset[6]; // offset of fields in str[] (skip name, always 0)
char state;
- char str[]; // name, tty, command, wchan, attr, cmdline
+ char str[]; // name, tty, command, wchan, attr, cmdline
};
// TODO: Android uses -30 for LABEL, but ideally it would auto-size.
// 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},
// Misc
{"STIME", 5, SLOT_starttime}, {"F", 1, 64|SLOT_flags}, {"S", -1, 64},
- {"STAT", -5, 64},
+ {"STAT", -5, 64}, {"PCY", 3, 64|SLOT_pcy},
);
// Return 0 to discard, nonzero to keep
// 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;
long long *slot = tb->slot, ll = (sl >= 0) ? slot[sl&63] : 0;
// numbers, mostly from /proc/$PID/stat
- if (which <= PS_CPU) {
+ if (which <= PS_BIT) {
char *fmt = "%lld";
if (which==PS_PRI) ll = 39-ll;
else if (which==PS_RSS) ll <<= 2;
else if (which==PS_VSZ) ll >>= 10;
else if (which==PS_PR && ll<-9) fmt="RT";
- else if (which==PS_RTPRIO && ll == 0) fmt="-";
+ else if ((which==PS_RTPRIO || which==PS_BIT) && ll == 0) fmt="-";
sprintf(out, fmt, ll);
// 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) 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;
}
out = out+strlen(out)-3-abs(field->len);
if (out<buf) out = buf;
- } else if (CFG_TOYBOX_DEBUG) error_exit("bad which %d", which);
+ } else if (which==PS_PCY) sprintf(out, "%.2s", get_sched_policy_name(ll));
+ else if (CFG_TOYBOX_DEBUG) error_exit("bad which %d", which);
return out;
}
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);
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;
// 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 (!(*slot = atol(new->name))) return 0;
+ 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;
// 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.
else s += j;
}
+ // Do we need to read "exe"?
+ if (TT.bits&_PS_BIT) {
+ off_t temp = 6;
+
+ sprintf(buf, "%lld/exe", *slot);
+ if (readfileat(fd, buf, buf, &temp) && !memcmp(buf, "\177ELF", 4)) {
+ if (buf[4] == 1) slot[SLOT_bits] = 32;
+ else if (buf[4] == 2) slot[SLOT_bits] = 64;
+ }
+ }
+
+ // Do we need Android scheduling policy?
+ if (TT.bits&_PS_PCY) get_sched_policy(*slot, (void *)&slot[SLOT_pcy]);
+
// Fetch string data while parentfd still available, appending to buf.
// (There's well over 3k of toybuf left. We could dynamically malloc, but
// 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;
len = sizeof(toybuf)-(buf-toybuf)-260-256*(ARRAY_LEN(fetch)-j);
sprintf(buf, "%lld/%s", *slot, fetch[j].name);
- // For cmdline we readlink instead of read contents
- if (j==3) {
- if ((len = readlinkat(fd, buf, buf, len))>0) buf[len] = 0;
- else *buf = 0;
+ // For exe we readlink instead of read contents
+ 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)
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.
if (i == 3) {
FILE *fp = fopen("/proc/tty/drivers", "r");
- int tty_major = 0, maj = major(rdev), min = minor(rdev);
+ int tty_major = 0, maj = dev_major(rdev), min = dev_minor(rdev);
if (fp) {
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;
}
}
// 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.
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)
- for (i=0; i<len; i++) {
+ // cmdline has a trailing NUL that we don't want to turn to space.
+ for (i=0; i<len-1; i++) {
char c = buf[i];
if (!c) {
} 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;
return DIRTREE_SAVE;
}
+static int get_threads(struct dirtree *new)
+{
+ struct dirtree *dt;
+ struct carveup *tb;
+ unsigned pid, kcount;
+
+ 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.
+ // Disable show_process at least until we can calculate tcount
+ kcount = TT.kcount;
+ 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
+ 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] = kcount;
+ }
+
+ // Save or display
+ 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;
+}
+
static char *parse_ko(void *data, char *type, int length)
{
struct strawberry *field;
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) {
return ret;
}
-static struct carveup **collate(int count, struct dirtree *dt,
- int (*sort)(void *a, void *b))
+static struct carveup **collate_leaves(struct carveup **tb, struct dirtree *dt)
{
- struct dirtree *temp;
- struct carveup **tbsort = xmalloc(count*sizeof(struct carveup *));
- int i;
-
- // descend into child list
- *tbsort = (void *)dt;
- dt = dt->child;
- free(*tbsort);
+ while (dt) {
+ struct dirtree *next = dt->next;
- // populate array
- for (i = 0; i < count; i++) {
- temp = dt->next;
- tbsort[i] = (void *)dt->extra;
+ if (dt->extra) *(tb++) = (void *)dt->extra;
+ if (dt->child) tb = collate_leaves(tb, dt->child);
free(dt);
- dt = temp;
+ dt = next;
}
+ return tb;
+}
+
+static struct carveup **collate(int count, struct dirtree *dt)
+{
+ struct carveup **tbsort = xmalloc(count*sizeof(struct carveup *));
+
+ collate_leaves(tbsort, dt);
+
return tbsort;
}
void ps_main(void)
{
struct dirtree *dt;
- char *s;
+ char *not_o;
int i;
if (toys.optflags&FLAG_w) TT.width = 99999;
comma_args(TT.ps.k, &TT.kfields, "bad -k", parse_ko);
dlist_terminate(TT.kfields);
- // Parse manual field selection, or default/-f/-l, plus -Z and -O
- if (toys.optflags&FLAG_Z) default_ko("LABEL", &TT.fields, 0, 0);
- if (toys.optflags&FLAG_f) s = "USER:8=UID,PID,PPID,C,STIME,TTY,TIME,CMD";
+ // 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,ARGS=CMD",
+ (toys.optflags&FLAG_T) ? "TCNT" : "C");
else if (toys.optflags&FLAG_l)
- s = "F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD";
+ not_o = "F,S,UID,%sPPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD";
else if (CFG_TOYBOX_ON_ANDROID)
- s = "USER,PID,PPID,VSIZE,RSS,WCHAN:10,ADDR:10=PC,S,NAME";
- else s = "PID,TTY,TIME,CMD";
- default_ko(s, &TT.fields, "bad -o", TT.ps.o);
+ not_o = "USER,%sPPID,VSIZE,RSS,WCHAN:10,ADDR:10=PC,S,NAME";
+ sprintf(toybuf, not_o, (toys.optflags & FLAG_T) ? "PID,TID," : "PID,");
+
+ // Init TT.fields. This only uses toybuf if TT.ps.o is NULL
+ if (toys.optflags&FLAG_Z) default_ko("LABEL", &TT.fields, 0, 0);
+ default_ko(toybuf, &TT.fields, "bad -o", TT.ps.o);
+
if (TT.ps.O) {
if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->prev;
comma_args(TT.ps.O, &TT.fields, "bad -O", parse_ko);
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--;
if (!(toys.optflags&FLAG_M)) printf("%.*s\n", TT.width, toybuf);
if (!(toys.optflags&(FLAG_k|FLAG_M))) TT.show_process = (void *)show_ps;
TT.match_process = ps_match_process;
- dt = dirtree_read("/proc", get_ps);
+ dt = dirtree_read("/proc",
+ ((toys.optflags&FLAG_T) || (TT.bits&(_PS_TID|_PS_TCNT)))
+ ? get_threads : get_ps);
if (toys.optflags&(FLAG_k|FLAG_M)) {
- struct carveup **tbsort = collate(TT.kcount, dt, ksort);
+ struct carveup **tbsort = collate(TT.kcount, dt);
if (toys.optflags&FLAG_M) {
for (i = 0; i<TT.kcount; i++) {
{
if (!line) return 0;
+ if (toys.optflags&FLAG_b) rev = 0;
+
printf("%s%*.*s%s\r\n", rev ? "\033[7m" : "",
(toys.optflags&FLAG_b) ? 0 : -TT.width, TT.width, toybuf,
rev ? "\033[0m" : "");
return line-1;
}
-// Get current time in miliseconds
-static long long militime(void)
+static long long millitime(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
-
return ts.tv_sec*1000+ts.tv_nsec/1000000;
}
plold = plist+(tock++&1);
plnew = plist+(tock&1);
- plnew->whence = militime();
- dt= dirtree_read("/proc", get_ps);
- plnew->tb = collate(plnew->count = TT.kcount, dt, ksort);
+ plnew->whence = millitime();
+ dt = dirtree_read("/proc",
+ ((toys.optflags&FLAG_H) || (TT.bits&(_PS_TID|_PS_TCNT)))
+ ? get_threads : get_ps);
+ plnew->tb = collate(plnew->count = TT.kcount, dt);
TT.kcount = 0;
if (readfile("/proc/stat", pos = toybuf, sizeof(toybuf))) {
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--;
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;
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]);
}
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;
lines = header_line(lines, 1);
}
- if (!recalc) printf("\033[%dH\033[J", 1+TT.height-lines);
+ if (!recalc && !(toys.optflags&FLAG_b))
+ printf("\033[%dH\033[J", 1+TT.height-lines);
recalc = 1;
for (i = 0; i<lines && i+topoff<mix.count; i++) {
- if (i) xputc('\n');
+ if (!(toys.optflags&FLAG_b) && i) xputc('\n');
show_ps(mix.tb[i+topoff]);
}
break;
}
- // Get current time in miliseconds
- now = militime();
+ now = millitime();
if (timeout<=now) timeout = new.whence+TT.top.d;
if (timeout<=now || timeout>now+TT.top.d) timeout = now+TT.top.d;
+ // In batch mode, we ignore the keyboard.
+ if (toys.optflags&FLAG_b) {
+ msleep(timeout-now);
+ // Make an obvious gap between datasets.
+ xputs("\n\n");
+ continue;
+ }
+
i = scan_key_getsize(scratch, timeout-now, &TT.width, &TT.height);
if (i==-1 || i==3 || toupper(i)=='Q') {
done++;
static void top_setup(char *defo, char *defk)
{
- int len;
-
- TT.time = militime();
TT.top.d *= 1000;
if (toys.optflags&FLAG_b) TT.width = TT.height = 99999;
else {
- xset_terminal(0, 1, 0);
+ TT.time = millitime();
+ set_terminal(0, 1, 0);
sigatexit(tty_sigreset);
xsignal(SIGWINCH, generic_signal);
printf("\033[?25l\033[0m");
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);
{
// 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);
}
static int iotop_filter(long long *oslot, long long *nslot, int milis)
{
if (!(toys.optflags&FLAG_a)) merge_deltas(oslot, nslot, milis);
- else oslot[SLOT_upticks] = ((militime()-TT.time)*TT.ticks)/1000;
+ else oslot[SLOT_upticks] = ((millitime()-TT.time)*TT.ticks)/1000;
return !(toys.optflags&FLAG_o)||oslot[SLOT_iobytes+!(toys.optflags&FLAG_A)];
}
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];
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) {
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();
*
* TODO: lines > 2G could wrap signed int length counters. Not just getline()
* but N and s///
+ * TODO: make y// handle unicode
+ * TODO: handle error return from emit(), error_msg/exit consistently
+ * What's the right thing to do for -i when write fails? Skip to next?
USE_SED(NEWTOY(sed, "(version)e*f*inEr[+Er]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
unsigned xx;
)
-struct step {
- struct step *next, *prev;
+// Linked list of parsed sed commands. Offset fields indicate location where
+// regex or string starts, ala offset+(char *)struct, because we remalloc()
+// these to expand them for multiline inputs, and pointers would have to be
+// individually adjusted.
+
+struct sedcmd {
+ struct sedcmd *next, *prev;
// Begin and end of each match
- long lmatch[2];
- int rmatch[2], arg1, arg2, w; // offsets because remalloc()
- unsigned not, hit, sflags;
+ long lmatch[2]; // line number of match
+ int rmatch[2]; // offset of regex struct for prefix matches (/abc/,/def/p)
+ int arg1, arg2, w; // offset of two arguments per command, plus s//w filename
+ unsigned not, hit;
+ unsigned sflags; // s///flag bits: i=1, g=2, p=4
char c; // action
};
int l, old = line[len];
if (TT.noeol && !writeall(TT.fdout, "\n", 1)) return 1;
+ TT.noeol = !eol;
if (eol) line[len++] = '\n';
if (!len) return 0;
- TT.noeol = len && !eol;
l = writeall(TT.fdout, line, len);
if (eol) line[len-1] = old;
if (l != len) {
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.
-static int ghostwheel(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)
}
// Apply pattern to line from input file
-static void walk_pattern(char **pline, long plen)
+static void process_line(char **pline, long plen)
{
struct append {
struct append *next, *prev;
} *append = 0;
char *line = TT.nextline;
long len = TT.nextlen;
- struct step *logrus;
+ struct sedcmd *command;
int eol = 0, tea = 0;
// Grab next line for deferred processing (EOF detection: we get a NULL
// The restart-1 is because we added one to make sure it wasn't NULL,
// otherwise N as last command would restart script
- logrus = TT.restart ? ((struct step *)TT.restart)-1 : (void *)TT.pattern;
+ command = TT.restart ? ((struct sedcmd *)TT.restart)-1 : (void *)TT.pattern;
TT.restart = 0;
- while (logrus) {
- char *str, c = logrus->c;
+ while (command) {
+ char *str, c = command->c;
// Have we got a line or regex matching range for this rule?
- if (*logrus->lmatch || *logrus->rmatch) {
+ if (*command->lmatch || *command->rmatch) {
int miss = 0;
long lm;
// In a match that might end?
- if (logrus->hit) {
- if (!(lm = logrus->lmatch[1])) {
- if (!logrus->rmatch[1]) logrus->hit = 0;
+ if (command->hit) {
+ if (!(lm = command->lmatch[1])) {
+ if (!command->rmatch[1]) command->hit = 0;
else {
- void *rm = get_regex(logrus, logrus->rmatch[1]);
+ void *rm = get_regex(command, command->rmatch[1]);
// regex match end includes matching line, so defer deactivation
- if (line && !ghostwheel(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) logrus->hit = 0;
+ } else if (lm > 0 && lm < TT.count) command->hit = 0;
// Start a new match?
} else {
- if (!(lm = *logrus->lmatch)) {
- void *rm = get_regex(logrus, *logrus->rmatch);
+ if (!(lm = *command->lmatch)) {
+ void *rm = get_regex(command, *command->rmatch);
- if (line && !ghostwheel(rm, line, len, 0, 0, 0)) logrus->hit++;
- } else if (lm == TT.count || (lm == -1 && !pline)) logrus->hit++;
+ if (line && !regexec0(rm, line, len, 0, 0, 0)) command->hit++;
+ } else if (lm == TT.count || (lm == -1 && !pline)) command->hit++;
- if (!logrus->lmatch[1] && !logrus->rmatch[1]) miss = 1;
+ if (!command->lmatch[1] && !command->rmatch[1]) miss = 1;
}
// Didn't match?
- lm = !(logrus->hit ^ logrus->not);
+ lm = !(command->hit ^ command->not);
// Deferred disable from regex end match
- if (miss || logrus->lmatch[1] == TT.count) logrus->hit = 0;
+ if (miss || command->lmatch[1] == TT.count) command->hit = 0;
if (lm) {
// Handle skipping curly bracket command group
int curly = 1;
while (curly) {
- logrus = logrus->next;
- if (logrus->c == '{') curly++;
- if (logrus->c == '}') curly--;
+ command = command->next;
+ if (command->c == '{') curly++;
+ if (command->c == '}') curly--;
}
}
- logrus = logrus->next;
+ command = command->next;
continue;
}
}
// A deleted line can still update line match state for later commands
if (!line) {
- logrus = logrus->next;
+ command = command->next;
continue;
}
if (c=='a' || c=='r') {
struct append *a = xzalloc(sizeof(struct append));
- a->str = logrus->arg1+(char *)logrus;
+ if (command->arg1) a->str = command->arg1+(char *)command;
a->file = c=='r';
dlist_add_nomalloc((void *)&append, (void *)a);
} else if (c=='b' || c=='t' || c=='T') {
if (c != 'b') tea = 0;
if (c=='b' || t^(c=='T')) {
- if (!logrus->arg1) break;
- str = logrus->arg1+(char *)logrus;
- for (logrus = (void *)TT.pattern; logrus; logrus = logrus->next)
- if (logrus->c == ':' && !strcmp(logrus->arg1+(char *)logrus, str))
+ if (!command->arg1) break;
+ str = command->arg1+(char *)command;
+ for (command = (void *)TT.pattern; command; command = command->next)
+ if (command->c == ':' && !strcmp(command->arg1+(char *)command, str))
break;
- if (!logrus) error_exit("no :%s", str);
+ if (!command) error_exit("no :%s", str);
}
} else if (c=='c') {
- str = logrus->arg1+(char *)logrus;
- if (!logrus->hit) emit(str, strlen(str), 1);
+ str = command->arg1+(char *)command;
+ if (!command->hit) emit(str, strlen(str), 1);
free(line);
line = 0;
continue;
line = 0;
} else {
line[len] = 0;
- logrus = (void *)TT.pattern;
+ command = (void *)TT.pattern;
}
continue;
} else if (c=='g') {
memcpy(TT.remember+TT.rememberlen, line, len);
TT.remember[TT.rememberlen += len] = 0;
} else if (c=='i') {
- str = logrus->arg1+(char *)logrus;
+ str = command->arg1+(char *)command;
emit(str, strlen(str), 1);
} else if (c=='l') {
int i, x, off;
toybuf[off++] = '$';
emit(toybuf, off, 1);
} else if (c=='n') {
- TT.restart = logrus->next+1;
+ TT.restart = command->next+1;
break;
} else if (c=='N') {
// Can't just grab next line because we could have multiple N and
// we need to actually read ahead to get N;$p EOF detection right.
if (pline) {
- TT.restart = logrus->next+1;
+ TT.restart = command->next+1;
extend_string(&line, TT.nextline, len, -TT.nextlen);
free(TT.nextline);
TT.nextline = line;
break;
} else if (c=='s') {
- char *rline = line, *new = logrus->arg2 + (char *)logrus, *swap, *rswap;
+ char *rline = line, *new = command->arg2 + (char *)command, *swap, *rswap;
regmatch_t *match = (void *)toybuf;
- regex_t *reg = get_regex(logrus, logrus->arg1);
+ regex_t *reg = get_regex(command, command->arg1);
int mflags = 0, count = 0, zmatch = 1, rlen = len, mlen, off, newlen;
// Find match in remaining line (up to remaining len)
- while (!ghostwheel(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
} else zmatch = 0;
// If we're replacing only a specific match, skip if this isn't it
- off = logrus->sflags>>3;
+ off = command->sflags>>3;
if (off && off != ++count) {
rline += match[0].rm_eo;
rlen -= match[0].rm_eo;
line = swap;
// Stop after first substitution unless we have flag g
- if (!(logrus->sflags & 2)) break;
+ if (!(command->sflags & 2)) break;
}
if (mflags) {
// flag p
- if (logrus->sflags & 4) emit(line, len, eol);
+ if (command->sflags & 4) emit(line, len, eol);
tea = 1;
- if (logrus->w) goto writenow;
+ if (command->w) goto writenow;
}
} else if (c=='w') {
int fd, noeol;
noeol = TT.noeol;
// We save filehandle and newline status before filename
- name = logrus->w + (char *)logrus;
+ name = command->w + (char *)command;
memcpy(&TT.fdout, name, 4);
name += 4;
TT.noeol = *(name++);
// write, then save/restore context
if (emit(line, len, eol))
- perror_exit("w '%s'", logrus->arg1+(char *)logrus);
+ perror_exit("w '%s'", command->arg1+(char *)command);
*(--name) = TT.noeol;
TT.noeol = noeol;
TT.fdout = fd;
TT.rememberlen = len;
len = swap;
} else if (c=='y') {
- char *from, *to = (char *)logrus;
+ char *from, *to = (char *)command;
int i, j;
- from = to+logrus->arg1;
- to += logrus->arg2;
+ from = to+command->arg1;
+ to += command->arg2;
for (i = 0; i < len; i++) {
j = stridx(from, line[i]);
emit(toybuf, strlen(toybuf), 1);
}
- logrus = logrus->next;
+ command = command->next;
}
if (line && !(toys.optflags & FLAG_n)) emit(line, len, eol);
done:
- free(line);
-
if (dlist_terminate(append)) while (append) {
struct append *a = append->next;
xsendfile(fd, TT.fdout);
close(fd);
}
- } else emit(append->str, strlen(append->str), 1);
+ } else if (append->str) emit(append->str, strlen(append->str), 1);
+ else emit(line, 0, 0);
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
char *tmp;
if (i) {
- struct step *primal;
+ struct sedcmd *command;
if (!fd && !strcmp(name, "-")) {
error_msg("-i on stdin");
}
TT.fdout = copy_tempfile(fd, name, &tmp);
TT.count = 0;
- for (primal = (void *)TT.pattern; primal; primal = primal->next)
- primal->hit = 0;
+ for (command = (void *)TT.pattern; command; command = command->next)
+ command->hit = 0;
}
- do_lines(fd, name, walk_pattern);
+ do_lines(fd, process_line);
if (i) {
- walk_pattern(0, 0);
+ process_line(0, 0);
replace_tempfile(-1, TT.fdout, &tmp);
TT.fdout = 1;
TT.nextline = 0;
{
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;
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 == '\\') {
return delim;
}
-// Translate primal pattern into walkable form.
-static void jewel_of_judgement(char **pline, long len)
+// Translate pattern strings into command structures. Each command structure
+// is a single allocation (which requires some math and remalloc at times).
+static void parse_pattern(char **pline, long len)
{
- struct step *corwin = (void *)TT.pattern;
+ struct sedcmd *command = (void *)TT.pattern;
char *line, *reg, c, *errstart;
int i;
line = errstart = pline ? *pline : "";
if (len && line[len-1]=='\n') line[--len] = 0;
- // Append additional line to pattern argument string?
- // We temporarily repurpose "hit" to indicate line continuations
- if (corwin && corwin->prev->hit) {
- if (!*pline) error_exit("unfinished %c", corwin->prev->c);;
+ // Append this line to previous multiline command? (hit indicates type.)
+ // During parsing "hit" stores data about line continuations, but in
+ // process_line() it means the match range attached to this command
+ // is active, so processing the continuation must zero it again.
+ if (command && command->prev->hit) {
// Remove half-finished entry from list so remalloc() doesn't confuse it
TT.pattern = TT.pattern->prev;
- corwin = dlist_pop(&TT.pattern);
- c = corwin->c;
- reg = (char *)corwin;
- reg += corwin->arg1 + strlen(reg + corwin->arg1);
-
- // Resume parsing for 'a' or 's' command
- if (corwin->hit < 256) goto resume_s;
+ command = dlist_pop(&TT.pattern);
+ c = command->c;
+ reg = (char *)command;
+ reg += command->arg1 + strlen(reg + command->arg1);
+
+ // Resume parsing for 'a' or 's' command. (Only two that can do this.)
+ // TODO: using 256 to indicate 'a' means our s/// delimiter can't be
+ // a unicode character.
+ if (command->hit < 256) goto resume_s;
else goto resume_a;
}
- // Loop through commands in line
+ // Loop through commands in this line.
- corwin = 0;
+ command = 0;
for (;;) {
- if (corwin) dlist_add_nomalloc(&TT.pattern, (void *)corwin);
+ if (command) dlist_add_nomalloc(&TT.pattern, (void *)command);
+ // If there's no more data on this line, return.
for (;;) {
while (isspace(*line) || *line == ';') line++;
if (*line == '#') while (*line && *line != '\n') line++;
}
if (!*line) return;
+ // We start by writing data into toybuf. Later we'll allocate the
+ // ex
+
errstart = line;
- memset(toybuf, 0, sizeof(struct step));
- corwin = (void *)toybuf;
- reg = toybuf + sizeof(struct step);
+ memset(toybuf, 0, sizeof(struct sedcmd));
+ command = (void *)toybuf;
+ reg = toybuf + sizeof(struct sedcmd);
// Parse address range (if any)
for (i = 0; i < 2; i++) {
if (*line == ',') line++;
else if (i) break;
- if (isdigit(*line)) corwin->lmatch[i] = strtol(line, &line, 0);
+ if (isdigit(*line)) command->lmatch[i] = strtol(line, &line, 0);
else if (*line == '$') {
- corwin->lmatch[i] = -1;
+ command->lmatch[i] = -1;
line++;
} else if (*line == '/' || *line == '\\') {
char *s = line;
- if (!(s = unescape_delimited_string(&line, 0))) goto brand;
- if (!*s) corwin->rmatch[i] = 0;
+ if (!(s = unescape_delimited_string(&line, 0))) goto error;
+ if (!*s) command->rmatch[i] = 0;
else {
xregcomp((void *)reg, s, (toys.optflags & FLAG_r)*REG_EXTENDED);
- corwin->rmatch[i] = reg-toybuf;
+ command->rmatch[i] = reg-toybuf;
reg += sizeof(regex_t);
}
free(s);
if (!*line) break;
while (*line == '!') {
- corwin->not = 1;
+ command->not = 1;
line++;
}
while (isspace(*line)) line++;
- c = corwin->c = *(line++);
+ c = command->c = *(line++);
if (strchr("}:", c) && i) break;
if (strchr("aiqr=", c) && i>1) break;
// Add step to pattern
- corwin = xmemdup(toybuf, reg-toybuf);
- reg = (reg-toybuf) + (char *)corwin;
+ command = xmemdup(toybuf, reg-toybuf);
+ reg = (reg-toybuf) + (char *)command;
// Parse arguments by command type
if (c == '{') TT.nextlen++;
else if (c == '}') {
if (!TT.nextlen--) break;
} else if (c == 's') {
- char *fiona, delim = 0;
+ char *end, delim = 0;
// s/pattern/replacement/flags
- // line continuations use arg1, so we fill out arg2 first (since the
- // regex part can't be multiple lines) and swap them back later.
+ // line continuations use arg1 (back at the start of the function),
+ // so let's fill out arg2 first (since the regex part can't be multiple
+ // lines) and swap them back later.
// get pattern (just record, we parse it later)
- corwin->arg2 = reg - (char *)corwin;
+ command->arg2 = reg - (char *)command;
if (!(TT.remember = unescape_delimited_string(&line, &delim)))
- goto brand;
+ goto error;
reg += sizeof(regex_t);
- corwin->arg1 = reg-(char *)corwin;
- corwin->hit = delim;
+ command->arg1 = reg-(char *)command;
+ command->hit = delim;
resume_s:
- // get replacement - don't replace escapes because \1 and \& need
+ // get replacement - don't replace escapes yet because \1 and \& need
// processing later, after we replace \\ with \ we can't tell \\1 from \1
- fiona = line;
- while (*fiona != corwin->hit) {
- if (!*fiona) goto brand;
- if (*fiona++ == '\\') {
- if (!*fiona || *fiona == '\n') {
- fiona[-1] = '\n';
+ end = line;
+ while (*end != command->hit) {
+ if (!*end) goto error;
+ if (*end++ == '\\') {
+ if (!*end || *end == '\n') {
+ end[-1] = '\n';
break;
}
- fiona++;
+ end++;
}
}
- reg = extend_string((void *)&corwin, line, reg-(char *)corwin,fiona-line);
- line = fiona;
+ reg = extend_string((void *)&command, line, reg-(char *)command,end-line);
+ line = end;
// line continuation? (note: '\n' can't be a valid delim).
- if (*line == corwin->hit) corwin->hit = 0;
+ if (*line == command->hit) command->hit = 0;
else {
if (!*line) continue;
reg--;
}
// swap arg1/arg2 so they're back in order arguments occur.
- i = corwin->arg1;
- corwin->arg1 = corwin->arg2;
- corwin->arg2 = i;
+ i = command->arg1;
+ command->arg1 = command->arg2;
+ command->arg2 = i;
// get flags
for (line++; *line; line++) {
if (isspace(*line) && *line != '\n') continue;
- if (0 <= (l = stridx("igp", *line))) corwin->sflags |= 1<<l;
- else if (!(corwin->sflags>>3) && 0<(l = strtol(line, &line, 10))) {
- corwin->sflags |= l << 3;
+ if (0 <= (l = stridx("igp", *line))) command->sflags |= 1<<l;
+ else if (!(command->sflags>>3) && 0<(l = strtol(line, &line, 10))) {
+ command->sflags |= l << 3;
line--;
} else break;
}
// We deferred actually parsing the regex until we had the s///i flag
// allocating the space was done by extend_string() above
- if (!*TT.remember) corwin->arg1 = 0;
- else xregcomp((void *)(corwin->arg1 + (char *)corwin), TT.remember,
- ((toys.optflags & FLAG_r)*REG_EXTENDED)|((corwin->sflags&1)*REG_ICASE));
+ if (!*TT.remember) command->arg1 = 0;
+ else xregcomp((void *)(command->arg1 + (char *)command), TT.remember,
+ ((toys.optflags & FLAG_r)*REG_EXTENDED)|((command->sflags&1)*REG_ICASE));
free(TT.remember);
TT.remember = 0;
if (*line == 'w') {
writenow:
while (isspace(*line)) line++;
- if (!*line) goto brand;
+ if (!*line) goto error;
for (cc = line; *cc; cc++) if (*cc == '\\' && cc[1] == ';') break;
delim = *cc;
*cc = 0;
fd = xcreate(line, O_WRONLY|O_CREAT|O_TRUNC, 0644);
*cc = delim;
- corwin->w = reg - (char *)corwin;
- corwin = xrealloc(corwin, corwin->w+(cc-line)+6);
- reg = corwin->w + (char *)corwin;
+ command->w = reg - (char *)command;
+ command = xrealloc(command, command->w+(cc-line)+6);
+ reg = command->w + (char *)command;
memcpy(reg, &fd, 4);
reg += 4;
char *s, delim = 0;
int len;
- if (!(s = unescape_delimited_string(&line, &delim))) goto brand;
- corwin->arg1 = reg-(char *)corwin;
+ if (!(s = unescape_delimited_string(&line, &delim))) goto error;
+ command->arg1 = reg-(char *)command;
len = strlen(s);
- reg = extend_string((void *)&corwin, s, reg-(char *)corwin, len);
+ reg = extend_string((void *)&command, s, reg-(char *)command, len);
free(s);
- corwin->arg2 = reg-(char *)corwin;
- if (!(s = unescape_delimited_string(&line, &delim))) goto brand;
- if (len != strlen(s)) goto brand;
- reg = extend_string((void *)&corwin, s, reg-(char*)corwin, len);
+ command->arg2 = reg-(char *)command;
+ if (!(s = unescape_delimited_string(&line, &delim))) goto error;
+ if (len != strlen(s)) goto error;
+ reg = extend_string((void *)&command, s, reg-(char*)command, len);
free(s);
} else if (strchr("abcirtTw:", c)) {
int end;
+ // trim leading spaces
while (isspace(*line) && *line != '\n') line++;
// Resume logic differs from 's' case because we don't add a newline
// unless it's after something, so we add it on return instead.
resume_a:
- corwin->hit = 0;
+ command->hit = 0;
- // Trim whitespace from "b ;" and ": blah " but only first space in "w x "
- if (!(end = strcspn(line, strchr("btT:", c) ? "; \t\r\n\v\f" : "\n"))) {
+ // btT: end with space or semicolon, aicrw continue to newline.
+ if (!(end = strcspn(line, strchr(":btT", c) ? "; \t\r\n\v\f" : "\n"))) {
+ // Argument's optional for btT
if (strchr("btT", c)) continue;
- else if (!corwin->arg1) break;
+ else if (!command->arg1) break;
}
// Extend allocation to include new string. We use offsets instead of
// pointers so realloc() moving stuff doesn't break things. Ok to write
// \n over NUL terminator because call to extend_string() adds it back.
- if (!corwin->arg1) corwin->arg1 = reg - (char*)corwin;
- else if (*(corwin->arg1+(char *)corwin)) *(reg++) = '\n';
- reg = extend_string((void *)&corwin, line, reg - (char *)corwin, end);
+ if (!command->arg1) command->arg1 = reg - (char*)command;
+ else if (*(command->arg1+(char *)command)) *(reg++) = '\n';
+ else if (!pline) {
+ command->arg1 = 0;
+ continue;
+ }
+ reg = extend_string((void *)&command, line, reg - (char *)command, end);
// Recopy data to remove escape sequences and handle line continuation.
if (strchr("aci", c)) {
line++;
goto resume_a;
}
- corwin->hit = 256;
+ command->hit = 256;
break;
}
if (!(reg[-1] = unescape(*line))) reg[-1] = *line;
} else if (!strchr("{dDgGhHlnNpPqx=", c)) break;
}
-brand:
- // Reminisce about chestnut trees.
+error:
error_exit("bad pattern '%s'@%ld (%c)", errstart, line-errstart+1L, *line);
}
void sed_main(void)
{
- struct arg_list *dworkin;
+ struct arg_list *al;
char **args = toys.optargs;
// Lie to autoconf when it asks stupid questions, so configure regexes
return;
}
- // Need a pattern. If no unicorns about, fight serpent and take its eye.
+ // Parse pattern into commands.
+
+ // If no -e or -f, first argument is the pattern.
if (!TT.e && !TT.f) {
if (!*toys.optargs) error_exit("no pattern");
(TT.e = xzalloc(sizeof(struct arg_list)))->arg = *(args++);
// Option parsing infrastructure can't interlace "-e blah -f blah -e blah"
// so handle all -e, then all -f. (At least the behavior's consistent.)
- for (dworkin = TT.e; dworkin; dworkin = dworkin->next)
- jewel_of_judgement(&dworkin->arg, strlen(dworkin->arg));
- for (dworkin = TT.f; dworkin; dworkin = dworkin->next)
- do_lines(xopen(dworkin->arg, O_RDONLY), dworkin->arg, jewel_of_judgement);
- jewel_of_judgement(0, 0);
+ 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(xopenro(al->arg), parse_pattern);
+ parse_pattern(0, 0);
dlist_terminate(TT.pattern);
if (TT.nextlen) error_exit("no }");
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)) walk_pattern(0, 0);
+ if (!(toys.optflags & FLAG_i)) process_line(0, 0);
// todo: need to close fd when done for TOYBOX_FREE?
}
* Copyright 2012 Timothy Elliott <tle@holymonkey.com>
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/tail.html
+ *
+ * Deviations from posix: -f waits for pipe/fifo on stdin (nonblock?).
USE_TAIL(NEWTOY(tail, "?fc-n-[-cn]", TOYFLAG_USR|TOYFLAG_BIN))
perror_msg("bad -f on '%s'", name);
}
- if (toys.optc > 1) {
- if (TT.file_no++) xputc('\n');
- xprintf("==> %s <==\n", name);
- }
+ if (TT.file_no++) xputc('\n');
+ if (toys.optc > 1) xprintf("==> %s <==\n", name);
// Are we measuring from the end of the file?
if (arg && *arg == '-' && arg[1]) {
TT.lines = atolx(*(args++));
toys.optc--;
+ } else {
+ // if nothing specified, default -n to -10
+ TT.lines = -10;
}
-
- // if nothing specified, default -n to -10
- TT.lines = -10;
}
// Allocate 2 ints per optarg for -f
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;
// 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;
if (s) break;
toybuf[1]='y';
}
+ tm.tm_sec = 0;
ts->tv_nsec = 0;
if (s && *s=='.' && sscanf(s, ".%2u%n", &(tm.tm_sec), &len) == 1) {
- sscanf(s += len, "%lu%n", &ts->tv_nsec, &len);
- len++;
+ if (sscanf(s += len, "%lu%n", &ts->tv_nsec, &len) == 1) {
+ s--;
+ len++;
+ } else len = 0;
} else len = 0;
}
if (len) {
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];
*
* 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"
config ULIMIT
bool "ulimit"
default y
+ depends on TOYBOX_PRLIMIT
help
usage: ulimit [-P PID] [-SHRacdefilmnpqrstuv] [LIMIT]
if (toys.optc) {
rlim_t val;
- if (tolower(**toys.optargs == 'i')) val = RLIM_INFINITY;
+ if (tolower(**toys.optargs) == 'u') val = RLIM_INFINITY;
else val = atolx_range(*toys.optargs, 0, LONG_MAX);
if (toys.optflags&FLAG_H) rr.rlim_max = val;
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);
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);
*
* 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"
#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:
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");
}
sight does not really help readability."</a> -
<a href=http://lkml.iu.edu/hypermail/linux/kernel/1407.1/00299.html>Pavel
Machek</a></li>
+<li>"Infrastructure in search of a user" is a bad thing, so don't put code
+in lib/ that doesn't already have at least two users. Don't preemptively
+factor stuff out, it's easy enough to rewrite it uin future if it needs
+to change. The "extreme programming" fad called this "You Ain't Gonna
+Need It" (while inexplicably screaming at cans of Mountain Dew, back in the
+90's). Here's <a href=https://lwn.net/Articles/683745/>Linus Torvalds' take</a>.</li>
</ul>
<hr>
I.E. "what to build", and "configure" describes the build and installation
environment, I.E. "how to build it".)</p>
+<p>By default "make install" puts files in /usr/toybox. Adding this to the
+$PATH is up to you. The environment variable $PREFIX can change the
+install location, ala "PREFIX=/usr/local/bin make install".</p>
+
+<p>If you need an unstripped (debug) version of any of these binaries,
+look in generated/unstripped.</p>
+
<p><h1><a name="running"><a href="#running">Running a command</a></h1></p>
<h2>main</h2>
the get_optargs() description in lib/args.c for details.</p>
</li>
-<li><b>char toybuf[4096]</b> - a common scratch space buffer so
-commands don't need to allocate their own. Any command is free to use this,
-and it should never be directly referenced by functions in lib/ (although
-commands are free to pass toybuf in to a library function as an argument).</li>
+<li><b>char toybuf[4096]</b> - a common scratch space buffer guaranteed
+to start zeroed, so commands don't need to allocate/initialize their own.
+Any command is free to use this, and it should never be directly referenced
+by functions in lib/ (although commands are free to pass toybuf in to a
+library function as an argument).</li>
+
+<li><b>char libbuf[4096]</b> - like toybuf, but for use by common code in
+lib/*.c. Commands should never directly reference libbuf, and library
+could should nnever directly reference toybuf.</li>
</ul>
<p>The following functions are defined in main.c:</p>
errors, to eliminate common error checking. This prints an error message
and the strerror() string for the errno encountered.</p>
-<p>You can intercept this exit by assigning a setjmp/longjmp buffer to
+<p>We replaced exit(), _exit(), and atexit() with xexit(), _xexit(), and
+sigatexit(). This gives _xexit() the option to siglongjmp(toys.rebound, 1)
+instead of exiting, lets xexit() report stdout flush failures to stderr
+and change the exit code to indicate error, lets our toys.exit function
+change happen for signal exit paths and lets us remove the functions
+after we've called them.</p>
+
+<p>You can intercept our exit by assigning a setjmp/longjmp buffer to
toys.rebound (set it back to zero to restore the default behavior).
If you do this, cleaning up resource leaks is your problem.</p>
<ul>
<li><b>void xstrncpy(char *dest, char *src, size_t size)</b></li>
-<li><b>void xexit(void)</b></li>
+<li><p><b><p>void _xexit(void)</b></p>
+<p>Calls siglongjmp(toys.rebound, 1), or else _exit(toys.exitval). This
+lets you ignore errors with the NO_EXIT() macro wrapper, or intercept
+them with WOULD_EXIT().</p>
+<li><b><p>void xexit(void)</b></p>
+<p>Calls toys.xexit functions (if any) and flushes stdout/stderr (reporting
+failure to write to stdout both to stderr and in the exit code), then
+calls _xexit().</p>
+</li>
<li><b>void *xmalloc(size_t size)</b></li>
<li><b>void *xzalloc(size_t size)</b></li>
<li><b>void *xrealloc(void *ptr, size_t size)</b></li>
<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>
</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>
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>
<p>These functions do not call chdir() or rely on PATH_MAX. Instead they
use openat() and friends, using one filehandle per directory level to
-recurseinto subdirectories. (I.E. they can descend 1000 directories deep
+recurse into subdirectories. (I.E. they can descend 1000 directories deep
if setrlimit(RLIMIT_NOFILE) allows enough open filehandles, and the default
in /proc/self/limits is generally 1024.)</p>
+<p>There are two main ways to use dirtree: 1) assemble a tree of nodes
+representing a snapshot of directory state and traverse them using the
+->next and ->child pointers, or 2) traverse the tree calling a callback
+function on each entry, and freeing its node afterwards. (You can also
+combine the two, using the callback as a filter to determine which nodes
+to keep.)</p>
+
<p>The basic dirtree functions are:</p>
<ul>
-<li><p><b>dirtree_read(char *path, int (*callback)(struct dirtree node))</b> -
-recursively read directories, either applying callback() or returning
-a tree of struct dirtree if callback is NULL.</p></li>
+<li><p><b>struct dirtree *dirtree_read(char *path, int (*callback)(struct
+dirtree node))</b> - recursively read files and directories, calling
+callback() on each, and returning a tree of saved nodes (if any).
+If path doesn't exist, returns DIRTREE_ABORTVAL. If callback is NULL,
+returns a single node at that path.</p>
+
+<li><p><b>dirtree_notdotdot(struct dirtree *new)</b> - standard callback
+which discards "." and ".." entries and returns DIRTREE_SAVE|DIRTREE_RECURSE
+for everything else. Used directly, this assembles a snapshot tree of
+the contents of this directory and its subdirectories
+to be processed after dirtree_read() returns (by traversing the
+struct dirtree's ->next and ->child pointers from the returned root node).</p>
<li><p><b>dirtree_path(struct dirtree *node, int *plen)</b> - malloc() a
string containing the path from the root of this tree to this node. If
of string.</p></li>
<li><p><b>dirtree_parentfd(struct dirtree *node)</b> - return fd of
-containing directory, for use with openat() and such.</p></li>
+directory containing this node, for use with openat() and such.</p></li>
</ul>
-<p>The <b>dirtree_read()</b> function takes two arguments, a starting path for
-the root of the tree, and a callback function. The callback takes a
-<b>struct dirtree *</b> (from lib/lib.h) as its argument. If the callback is
-NULL, the traversal uses a default callback (dirtree_notdotdot()) which
-recursively assembles a tree of struct dirtree nodes for all files under
-this directory and subdirectories (filtering out "." and ".." entries),
-after which dirtree_read() returns the pointer to the root node of this
-snapshot tree.</p>
+<p>The <b>dirtree_read()</b> function is the standard way to start
+directory traversal. It takes two arguments: a starting path for
+the root of the tree, and a callback function. The callback() is called
+on each directory entry, its argument is a fully populated
+<b>struct dirtree *</b> (from lib/lib.h) describing the node, and its
+return value tells the dirtree infrastructure what to do next.</p>
-<p>Otherwise the callback() is called on each entry in the directory,
-with struct dirtree * as its argument. This includes the initial
-node created by dirtree_read() at the top of the tree.</p>
+<p>(There's also a three argument version,
+<b>dirtree_flagread(char *path, int flags, int (*callback)(struct
+dirtree node))</b>, which lets you apply flags like DIRTREE_SYMFOLLOW and
+DIRTREE_SHUTUP to reading the top node, but this only affects the top node.
+Child nodes use the flags returned by callback().</p>
<p><b>struct dirtree</b></p>
st</b> entries describing a file, plus a <b>char *symlink</b>
which is NULL for non-symlinks.</p>
-<p>During a callback function, the <b>int data</b> field of directory nodes
-contains a dirfd (for use with the openat() family of functions). This is
-generally used by calling dirtree_parentfd() on the callback's node argument.
-For symlinks, data contains the length of the symlink string. On the second
-callback from DIRTREE_COMEAGAIN (depth-first traversal) data = -1 for
-all nodes (that's how you can tell it's the second callback).</p>
+<p>During a callback function, the <b>int dirfd</b> field of directory nodes
+contains a directory file descriptor (for use with the openat() family of
+functions). This isn't usually used directly, intstead call dirtree_parentfd()
+on the callback's node argument. The <b>char again</a> field is 0 for the
+first callback on a node, and 1 on the second callback (triggered by returning
+DIRTREE_COMEAGAIN on a directory, made after all children have been processed).
+</p>
<p>Users of this code may put anything they like into the <b>long extra</b>
field. For example, "cp" and "mv" use this to store a dirfd for the destination
<li><p><b>DIRTREE_RECURSE</b> - Examine directory contents. Ignored for
non-directory entries. The remaining flags only take effect when
recursing into the children of a directory.</p></li>
-<li><p><b>DIRTREE_COMEAGAIN</b> - Call the callback a second time after
-examining all directory contents, allowing depth-first traversal.
-On the second call, dirtree->data = -1.</p></li>
+<li><p><b>DIRTREE_COMEAGAIN</b> - Call the callback on this node a second time
+after examining all directory contents, allowing depth-first traversal.
+On the second call, dirtree->again is nonzero.</p></li>
<li><p><b>DIRTREE_SYMFOLLOW</b> - follow symlinks when populating children's
<b>struct stat st</b> (by feeding a nonzero value to the symfollow argument of
dirtree_add_node()), which means DIRTREE_RECURSE treats symlinks to
directories as directories. (Avoiding infinite recursion is the callback's
problem: the non-NULL dirtree->symlink can still distinguish between
-them.)</p></li>
+them. The "find" command follows ->parent up the tree to the root node
+each time, checking to make sure that stat's dev and inode pair don't
+match any ancestors.)</p></li>
</ul>
<p>Each struct dirtree contains three pointers (next, parent, and child)
so llist_free() works but its callback must descend into child nodes (freeing
a tree, not just a linked list), plus whatever the user stored in extra.</p>
-<p>The <b>dirtree_read</b>() function is a simple wrapper, calling <b>dirtree_add_node</b>()
+<p>The <b>dirtree_flagread</b>() function is a simple wrapper, calling <b>dirtree_add_node</b>()
to create a root node relative to the current directory, then calling
-<b>handle_callback</b>() on that node (which recurses as instructed by the callback
-return flags). Some commands (such as chgrp) bypass this wrapper, for example
-to control whether or not to follow symlinks to the root node; symlinks
+<b>dirtree_handle_callback</b>() on that node (which recurses as instructed by the callback
+return flags). The flags argument primarily lets you
+control whether or not to follow symlinks to the root node; symlinks
listed on the command line are often treated differently than symlinks
-encountered during recursive directory traversal).
+encountered during recursive directory traversal.
-<p>The ls command not only bypasses the wrapper, but never returns
+<p>The ls command not only bypasses this wrapper, but never returns
<b>DIRTREE_RECURSE</b> from the callback, instead calling <b>dirtree_recurse</b>() manually
from elsewhere in the program. This gives ls -lR manual control
of traversal order, which is neither depth first nor breadth first but
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
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>
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
<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>
--- /dev/null
+<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" -->
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
<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>
following commands:</p>
<blockquote><b>
-dd getevent iftop ioctl log
-nandread newfs_msdos ps prlimit
-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
<p>For reference, combining everything listed above, we get:</p>
<blockquote><b>
-dd getevent iftop init ioctl
-log logcat logwrapper nandread
-newfs_msdos ps prlimit reboot run-as
-sendevent start stop top
+dd getevent init
+logcat logwrapper
+newfs_msdos reboot run-as
</b></blockquote>
<p>We may eventually implement all of that, but for toybox 1.0 we need to
<p>This means toybox should implement (or finish implementing):</p>
<blockquote><b>
<span id=toolbox>
-dd getevent iftop ioctl log logcat logwrapper
-nandread newfs_msdos ps prlimit sendevent
-start stop top
+dd getevent logcat logwrapper newfs_msdos
</span>
</b></blockquote>
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>
+
+<blockquote><b>
+mtools genvfatfs mke2fs gene2fs
</b></blockquote>
<hr />